Listens on a streamingUri and processes the messages
Inheritance: IDisposable
        /// <summary>
        /// Returns a MessageStreamListener instance based on this instance's configuratino (timeout, bucket name etc.)
        ///
        /// When multiple listeners are requested with the exact same parameters (usually when multiple clients are instantiated from the same configuration),
        /// the same listener will be returned each time.
        /// </summary>
        /// <returns></returns>
        private MessageStreamListener GetPooledListener()
        {
            // create a unique key based on the parameters
            // to find out if we already have a listener attached to this sockIOPool
            var hcc = new HashCodeCombiner();

            hcc.Add(this.Timeout);
            hcc.Add(this.DeadTimeout);
            hcc.Add(this.RetryCount);
            hcc.Add(this.RetryTimeout.GetHashCode());
            hcc.Add(this.bucketName.GetHashCode());

            if (credential != null)
            {
                hcc.Add((this.credential.UserName ?? String.Empty).GetHashCode());
                hcc.Add((this.credential.Password ?? String.Empty).GetHashCode());
                hcc.Add((this.credential.Domain ?? String.Empty).GetHashCode());
            }

            for (var i = 0; i < this.poolUrls.Length; i++)
            {
                hcc.Add(this.poolUrls[i].GetHashCode());
            }

            var hash = hcc.CurrentHash;

            MessageStreamListener retval;

            lock (ListenerSync)
                if (listeners.TryGetValue(hash, out retval))
                {
                    listenerRefs[retval].RefCount++;
                    retval.Subscribe(this.HandleMessage);
                }
                else
                {
                    var name = this.bucketName;

                    // create a new listener for the sockIOPool urls
                    retval = new MessageStreamListener(poolUrls, (client, root) => ResolveBucketUri(client, root, name));

                    retval.Timeout      = this.Timeout;
                    retval.DeadTimeout  = this.DeadTimeout;
                    retval.Credentials  = this.credential;
                    retval.RetryCount   = this.RetryCount;
                    retval.RetryTimeout = this.RetryTimeout;

                    retval.Subscribe(this.HandleMessage);

                    listeners[hash]      = retval;
                    listenerRefs[retval] = new ListenerInfo {
                        RefCount = 1, HashKey = hash
                    };

                    retval.Start();
                }

            return(retval);
        }
		/// <summary>
		/// Starts listening for configuration data. This method blocks until the initial configuration is received. (Or until all sockIOPool urls fail.)
		/// </summary>
		public void Start()
		{
			var reset = this.mre = new ManualResetEvent(false);

			// subscribe to the config url
			this.listener = this.GetPooledListener();

			// this will be signaled by the config changed event handler
			reset.WaitOne();

			// set to null, then dispose, so RaiseConfigChanged will not 
			// fail at Set when the config changes while we're cleaning up here
			this.mre = null;
			((IDisposable)reset).Dispose();
		}
        /// <summary>
        /// Starts listening for configuration data. This method blocks until the initial configuration is received. (Or until all sockIOPool urls fail.)
        /// </summary>
        public void Start()
        {
            var reset = this.mre = new ManualResetEvent(false);

            // subscribe to the config url
            this.listener = this.GetPooledListener();

            // this will be signaled by the config changed event handler
            reset.WaitOne();

            // set to null, then dispose, so RaiseConfigChanged will not
            // fail at Set when the config changes while we're cleaning up here
            this.mre = null;
            ((IDisposable)reset).Dispose();
        }
        /// <summary>
        /// Unsubscibes from a pooled listener, and destrpys it if no additionals subscribers are present.
        /// </summary>
        /// <param name="listener"></param>
        private void ReleaseListener(MessageStreamListener listener)
        {
            lock (ListenerSync)
            {
                listener.Unsubscribe(this.HandleMessage);

                var info = listenerRefs[listener];
                if (info.RefCount == 1)
                {
                    listenerRefs.Remove(listener);
                    listeners.Remove(info.HashKey);

                    try { using (listener) listener.Stop(); }
                    catch { }
                }
                else
                {
                    info.RefCount--;
                }
            }
        }
		public void Stop()
		{
			this.ReleaseListener(this.listener);
			this.listener = null;
		}
		/// <summary>
		/// Returns a MessageStreamListener instance based on this instance's configuratino (timeout, bucket name etc.)
		/// 
		/// When multiple listeners are requested with the exact same parameters (usually when multiple clients are instantiated from the same configuration),
		/// the same listener will be returned each time.
		/// </summary>
		/// <returns></returns>
		private MessageStreamListener GetPooledListener()
		{
			// create a unique key based on the parameters
			// to find out if we already have a listener attached to this sockIOPool
			var hcc = new HashCodeCombiner();

			hcc.Add(this.Timeout);
			hcc.Add(this.DeadTimeout);
			hcc.Add(this.RetryCount);
			hcc.Add(this.RetryTimeout.GetHashCode());
			hcc.Add(this.bucketName.GetHashCode());

			if (credential != null)
			{
				hcc.Add((this.credential.UserName ?? String.Empty).GetHashCode());
				hcc.Add((this.credential.Password ?? String.Empty).GetHashCode());
				hcc.Add((this.credential.Domain ?? String.Empty).GetHashCode());
			}

			for (var i = 0; i < this.poolUrls.Length; i++)
				hcc.Add(this.poolUrls[i].GetHashCode());

			var hash = hcc.CurrentHash;

			MessageStreamListener retval;

			lock (ListenerSync)
				if (listeners.TryGetValue(hash, out retval))
				{
					listenerRefs[retval].RefCount++;
					retval.Subscribe(this.HandleMessage);
				}
				else
				{
					var name = this.bucketName;

					// create a new listener for the sockIOPool urls
					retval = new MessageStreamListener(poolUrls, (client, root) => ResolveBucketUri(client, root, name));

					retval.Timeout = this.Timeout;
					retval.DeadTimeout = this.DeadTimeout;
					retval.Credentials = this.credential;
					retval.RetryCount = this.RetryCount;
					retval.RetryTimeout = this.RetryTimeout;

					retval.Subscribe(this.HandleMessage);

					listeners[hash] = retval;
					listenerRefs[retval] = new ListenerInfo { RefCount = 1, HashKey = hash };

					retval.Start();
				}

			return retval;
		}
		/// <summary>
		/// Unsubscibes from a pooled listener, and destrpys it if no additionals subscribers are present.
		/// </summary>
		/// <param name="listener"></param>
		private void ReleaseListener(MessageStreamListener listener)
		{
			lock (ListenerSync)
			{
				listener.Unsubscribe(this.HandleMessage);

				var info = listenerRefs[listener];
				if (info.RefCount == 1)
				{
					listenerRefs.Remove(listener);
					listeners.Remove(info.HashKey);

					try { using (listener) listener.Stop(); }
					catch { }
				}
				else
				{
					info.RefCount--;
				}
			}
		}
 public void Stop()
 {
     this.ReleaseListener(this.listener);
     this.listener = null;
 }