/// <summary>
        /// Initializes an instance of the object.
        /// </summary>
        /// <param name="network">Specification of the network the node runs on - regtest/testnet/mainnet.</param>
        /// <param name="peer">Network peer the node is connected to, or will connect to.</param>
        /// <param name="client">Initialized TCP client, which may or may not be already connected.</param>
        /// <param name="clientId">Unique identifier of the connection.</param>
        /// <param name="processMessageAsync">Callback to be called when a new message arrives from the peer.</param>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        public NetworkPeerConnection(Network network, INetworkPeer peer, TcpClient client, int clientId, ProcessMessageAsync <IncomingMessage> processMessageAsync, IDateTimeProvider dateTimeProvider, ILoggerFactory loggerFactory)
        {
            this.loggerFactory = loggerFactory;
            this.logger        = this.loggerFactory.CreateLogger(this.GetType().FullName, $"[{clientId}-{peer.PeerEndPoint}] ");

            this.network          = network;
            this.dateTimeProvider = dateTimeProvider;

            this.peer = peer;
            this.setPeerStateOnShutdown = NetworkPeerState.Offline;
            this.tcpClient = client;
            this.Id        = clientId;

            this.stream           = this.tcpClient.Connected ? this.tcpClient.GetStream() : null;
            this.ShutdownComplete = new TaskCompletionSource <bool>();
            this.DisposeComplete  = new TaskCompletionSource <bool>();

            this.shutdownLock = new object();
            this.writeLock    = new AsyncLock();

            this.CancellationSource = new CancellationTokenSource();

            this.MessageProducer             = new MessageProducer <IncomingMessage>();
            this.messageListener             = new CallbackMessageListener <IncomingMessage>(processMessageAsync);
            this.messageProducerRegistration = this.MessageProducer.AddMessageListener(this.messageListener);
        }
        /// <summary>
        ///     Initializes an instance of the object.
        /// </summary>
        /// <param name="network">Specification of the network the node runs on - regtest/testnet/mainnet.</param>
        /// <param name="peer">Network peer the node is connected to, or will connect to.</param>
        /// <param name="client">Initialized TCP client, which may or may not be already connected.</param>
        /// <param name="clientId">Unique identifier of the connection.</param>
        /// <param name="processMessageAsync">Callback to be called when a new message arrives from the peer.</param>
        /// <param name="dateTimeProvider">Provider of time functions.</param>
        /// <param name="loggerFactory">Factory for creating loggers.</param>
        /// <param name="payloadProvider">A provider of network payload messages.</param>
        public NetworkPeerConnection(Network network, INetworkPeer peer, TcpClient client, int clientId,
                                     ProcessMessageAsync <IncomingMessage> processMessageAsync, IDateTimeProvider dateTimeProvider,
                                     ILoggerFactory loggerFactory, PayloadProvider payloadProvider, IAsyncProvider asyncProvider)
        {
            this.loggerFactory   = loggerFactory;
            this.payloadProvider = payloadProvider;
            this.asyncProvider   = Guard.NotNull(asyncProvider, nameof(asyncProvider));
            this.logger          = this.loggerFactory.CreateLogger(GetType().FullName, $"[{clientId}-{peer.PeerEndPoint}] ");

            this.network          = network;
            this.dateTimeProvider = dateTimeProvider;

            this.peer      = peer;
            this.tcpClient = client;
            this.Id        = clientId;

            this.stream = this.tcpClient.Connected ? this.tcpClient.GetStream() : null;

            this.writeLock = new AsyncLock();

            this.CancellationSource = new CancellationTokenSource();

            this.MessageProducer = new MessageProducer <IncomingMessage>();
            this.messageListener =
                new CallbackMessageListener <IncomingMessage>(asyncProvider, processMessageAsync, peer);
            this.messageProducerRegistration = this.MessageProducer.AddMessageListener(this.messageListener);
        }
Exemple #3
0
		/// <summary>
		/// <p>Performs a <see cref="Disconnect()"/> and uses the given <paramref name="timeout"/>
		/// to wait for the disconnect to complete.</p>
		/// <p>When a disconnect is sent to the server, the server also wakes up the long
		/// poll that may be outstanding, so that a connect reply message may arrive to
		/// the client later than the disconnect reply message.</p>
		/// <p>This method waits for the given <paramref name="timeout"/> for the disconnect reply, but also
		/// waits the same timeout for the last connect reply; in the worst case the
		/// maximum time waited will therefore be twice the given <paramref name="timeout"/> parameter.</p>
		/// <p>This method returns true if the disconnect reply message arrived within the
		/// given <paramref name="timeout"/> parameter, no matter if the connect reply message arrived or not.</p>
		/// </summary>
		/// <param name="timeout">The timeout to wait for the disconnect to complete.</param>
		/// <returns>True if the disconnect completed within the given timeout.</returns>
		public virtual bool Disconnect(int timeout)
		{
			BayeuxClientState currState = _bayeuxClientState;
			if (currState.IsDisconnected) return true;

			bool disconnected;
			using (ManualResetEvent latch = new ManualResetEvent(false))// TODO: CountdownEvent(1)
			{
				IMessageListener lastConnectListener
					= new CallbackMessageListener<ManualResetEvent>(WaitForNoneReconnection, latch);

				IClientSessionChannel ch = this.GetChannel(Channel.MetaConnect);
				if (ch != null) ch.AddListener(lastConnectListener);

				this.Disconnect();
				disconnected = this.WaitFor(timeout,
					BayeuxClientStates.Disconnected
					// TODO: | BayeuxClientStates.Disconnecting
					);

				// There is a possibility that we are in the window where the server
				// has returned the long poll and the client has not issued it again,
				// so wait for the timeout, but do not complain if the latch does not trigger.
				if (ch != null)
				{
					try
					{
						latch.WaitOne(timeout, false);// Wait(timeout)
					}
					catch (ThreadInterruptedException/*AbandonedMutexException*/)
					{
						Thread.CurrentThread.Interrupt();
					}
					finally
					{
						ch.RemoveListener(lastConnectListener);
					}
				}
			}

			currState = _bayeuxClientState;
			if (currState.IsDisconnected && currState.Transport != null)
				currState.Transport.Terminate();

			return disconnected;
		}