/// <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); }
/// <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; }