/// <summary> /// Starts the send event loop and runs the receive loop in the background /// to listen for commands that are sent to the device /// </summary> /// <param name="token"></param> /// <returns></returns> public async Task StartAsync(CancellationToken token) { try { await InitializeAsync(); var loopTasks = new List <Task> { StartReceiveLoopAsync(token), StartSendLoopAsync(token) }; // Wait both the send and receive loops await Task.WhenAll(loopTasks.ToArray()); } catch (Exception ex) { Logger.LogError($"Exception raise while starting device {DeviceID}: {ex}"); } finally { // once the code makes it here the token has been canceled await Transport.CloseAsync(); } }
public async Task CleanupAsync() { await _transportListener.StopAsync(_cancellationToken); _serverTransport.CloseAsync(_cancellationToken); _clientTransport.CloseAsync(_cancellationToken); }
/// <summary> /// Receives an envelope from the buffer. /// </summary> private async Task <T> ReceiveFromBufferAsync <T>(ChannelReader <T> reader, IEnumerable <IChannelModule <T> > modules, CancellationToken cancellationToken) where T : Envelope, new() { if (_channelInformation.State < SessionState.Established) { throw new InvalidOperationException($"Cannot receive envelopes in the '{_channelInformation.State}' session state"); } try { T envelope; var modulesList = modules.ToList(); do { envelope = await reader.ReadAsync(cancellationToken).ConfigureAwait(false); foreach (var module in modulesList) { if (envelope == null) { break; } envelope = await module.OnReceivingAsync(envelope, cancellationToken); } } while (envelope == null); return(envelope); } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { throw; } catch (Exception ex) { // Closes the transport in case of any exception if (_transport.IsConnected) { using var cts = new CancellationTokenSource(_consumeTimeout ?? TimeSpan.FromSeconds(5)); try { await _transport.CloseAsync(cts.Token).ConfigureAwait(false); } catch (Exception ex2) { RaiseReceiverException(ex2); } } if (ex is ChannelClosedException && reader.Completion.IsCompleted) { throw new InvalidOperationException( "The channel listener task is complete and cannot receive envelopes", ex); } throw; } }
/// <summary> /// Sends the envelope to the specified target. /// </summary> private async Task SendToBufferAsync <T>(T envelope, IEnumerable <IChannelModule <T> > modules, CancellationToken cancellationToken) where T : Envelope, new() { if (envelope == null) { throw new ArgumentNullException(nameof(envelope)); } if (_channelInformation.State != SessionState.Established) { throw new InvalidOperationException( $"Cannot send a {typeof(T).Name} in the '{_channelInformation.State}' session state"); } if (!_transport.IsConnected) { throw new InvalidOperationException("The transport is not connected"); } try { if (_envelopeBuffer.Reader.Completion.IsCompleted) { throw new InvalidOperationException("The send buffer is complete", _envelopeBuffer.Reader.Completion.Exception?.GetBaseException()); } foreach (var module in modules.ToList()) { if (envelope == null) { break; } cancellationToken.ThrowIfCancellationRequested(); envelope = await module.OnSendingAsync(envelope, cancellationToken).ConfigureAwait(false); } await _envelopeBuffer.Writer.WriteAsync(envelope, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested) { throw; } catch when(_transport.IsConnected) { // Closes the transport in case of any exception using var cts = new CancellationTokenSource(_closeTimeout); try { await _transport.CloseAsync(cts.Token).ConfigureAwait(false); } catch (Exception ex) { RaiseSenderException(ex); } throw; } }
public async Task SendAsync_AfterServerDisconnect_ClientAutomaticallyReconnects() { ITransport clientTransport = null; ITransport serverTransport = null; ITransportListener transportListener = null; try { // Arrange transportListener = CreateTransportListener(ListenerUri, EnvelopeSerializer); await transportListener.StartAsync(CancellationToken); clientTransport = CreateClientTransport(EnvelopeSerializer); var serverTransportTask = transportListener.AcceptTransportAsync(CancellationToken); await clientTransport.OpenAsync(ListenerUri, CancellationToken); serverTransport = await serverTransportTask; await serverTransport.OpenAsync(ListenerUri, CancellationToken); var message = Dummy.CreateMessage(Dummy.CreateTextContent()); // Act await transportListener.StopAsync(CancellationToken); await serverTransport.CloseAsync(CancellationToken); transportListener = CreateTransportListener(ListenerUri, EnvelopeSerializer); await transportListener.StartAsync(CancellationToken); serverTransport = await transportListener.AcceptTransportAsync(CancellationToken); await serverTransport.OpenAsync(ListenerUri, CancellationToken); await clientTransport.SendAsync(message, CancellationToken); var actual = await serverTransport.ReceiveAsync(CancellationToken); // Assert var actualMessage = actual.ShouldBeOfType <Message>(); CompareMessages(message, actualMessage); } finally { (clientTransport as IDisposable)?.Dispose(); (serverTransport as IDisposable)?.Dispose(); (transportListener as IDisposable)?.Dispose(); } }
/// <summary> /// Starts the send event loop and runs the receive loop in the background /// to listen for commands that are sent to the device /// </summary> /// <param name="token"></param> /// <returns></returns> public async Task StartAsync(CancellationToken token) { Transport.Open(); var loopTasks = new List <Task> { StartReceiveLoopAsync(token), StartSendLoopAsync(token) }; // Wait both the send and receive loops await Task.WhenAll(loopTasks.ToArray()); // once the code makes it here the token has been canceled await Transport.CloseAsync(); }
public async Task TearDown() { _cts.Dispose(); using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(5))) { await Task.WhenAll( _serverTransport.CloseAsync(cts.Token), _clientTransport.CloseAsync(cts.Token)); await _transportListener.StopAsync(cts.Token); } _clientTransport.DisposeIfDisposable(); _serverTransport.DisposeIfDisposable(); _transportListener.DisposeIfDisposable(); // Set null to avoid issues with NUnit reusing the test class instance _clientTransport = null; _serverTransport = null; _transportListener = null; }
/// <summary> /// Starts the send event loop and runs the receive loop in the background /// to listen for commands that are sent to the device /// </summary> /// <param name="token"></param> /// <returns></returns> public async Task StartAsync(CancellationToken token) { try { Transport.Open(); var loopTasks = new List <Task> { StartReceiveLoopAsync(token), StartSendLoopAsync(token) }; // Wait both the send and receive loops await Task.WhenAll(loopTasks.ToArray()); // once the code makes it here the token has been canceled await Transport.CloseAsync(); } catch (Exception ex) { Logger.LogError("Unexpected Exception starting device: {0}", ex.ToString()); } }
public void Dispose() { _clientTransport.CloseAsync(CancellationToken.None); _serverTransport.CloseAsync(CancellationToken.None); _transportListener.StopAsync(_cancellationToken).Wait(); }
public Task CloseAsync(CancellationToken cancellationToken) { return(_transport.CloseAsync(cancellationToken).WithCancellation(cancellationToken)); }