private void StartChildConnections() { foreach (var childConnection in _connections) { childConnection.Start( receivedActionStreamAsync: (connection, networkStream, cancellationToken) => ServiceRef.CallAndWaitAsync(this, async() => await OnReceivedDataFromChildChannel(connection, networkStream, cancellationToken)), connectionStateChangedAction: (connection, fromState, toState) => ServiceRef.Call(this, () => OnChildChannelConnectionStateChanged(connection, fromState, toState))); } }
private async Task ReceiveLoopAsync(CancellationToken cancellationToken) { #pragma warning disable IDE0068 // Use recommended dispose pattern var refToThis = ServiceRef.Create <IConnection>(this); #pragma warning restore IDE0068 // Use recommended dispose pattern try { //if (_receiveLoopCancellationTokenSource != null) //{ // _receiveLoopCancellationTokenSource.Dispose(); // _receiveLoopCancellationTokenSource = null; //} //_receiveLoopCancellationTokenSource = new CancellationTokenSource(); _receiveLoopTaskIsRunningEvent.Set(); //var cancellationToken = _receiveLoopCancellationTokenSource.Token; while (true) { cancellationToken.ThrowIfCancellationRequested(); int messageLength = -1; if (_messageFramingEnabled) { await _receivingStream.ReadBufferedAsync(_messageSizeBuffer, cancellationToken).ConfigureAwait(false); messageLength = BitConverter.ToInt32(_messageSizeBuffer, 0); if (messageLength == 0) { continue; } cancellationToken.ThrowIfCancellationRequested(); } if (messageLength == -1) { if (_receivedActionStreamAsync != null) { //await ServiceRef.CallAndWaitAsync(this, () => // _receivedActionStreamAsync(refToThis, _receivingStream, cancellationToken)).ConfigureAwait(false); await _receivedActionStreamAsync(refToThis, _receivingStream, cancellationToken); } else { throw new InvalidOperationException("ReceiveActionStreamAsync must be specified to handle variable length messages"); } } else { if (_receivedActionStreamAsync != null) { #pragma warning disable IDE0067 // Dispose objects before losing scope var bufferedStream = new NetworkBufferedReadStream(_receivingStream, messageLength); #pragma warning restore IDE0067 // Dispose objects before losing scope await ServiceRef.CallAndWaitAsync(this, async() => await _receivedActionStreamAsync(refToThis, bufferedStream, cancellationToken).ConfigureAwait(false)).ConfigureAwait(false); await bufferedStream.FlushAsync().ConfigureAwait(false); } else { var messageBuffer = new byte[messageLength]; await _receivingStream.ReadBufferedAsync(messageBuffer, cancellationToken).ConfigureAwait(false); if (_receivedActionAsync != null) { await ServiceRef.CallAndWaitAsync(this, async() => await _receivedActionAsync(refToThis, messageBuffer, cancellationToken).ConfigureAwait(false)).ConfigureAwait(false); } else //if (_receivedAction != null) { ServiceRef.CallAndWait(this, () => _receivedAction(refToThis, messageBuffer)); } } } } } catch (OperationCanceledException) { System.Diagnostics.Debug.WriteLine($"{GetType()} ReceiveLoopAsync Cancelled"); } #if DEBUG catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"{GetType()}{Environment.NewLine}{ex}"); #else catch (Exception) { #endif //_receiveLoopCancellationTokenSource = null; ServiceRef.Call(this, () => { if (State == ConnectionState.Connected) { SetState(ConnectionTrigger.LinkError); } }); } finally { //_receiveLoopCancellationTokenSource = null; } }
//protected virtual async Task SetStateAsync(ConnectionTrigger connectionTrigger) //{ // var currentState = State; // var newState = State; // System.Diagnostics.Debug.WriteLine($"{GetType()} SetStateAsync({currentState}) -> {connectionTrigger}"); // switch (currentState) // { // case ConnectionState.Connecting: // { // if (connectionTrigger == ConnectionTrigger.Connected) // { // await RunConnection(); // newState = ConnectionState.Connected; // } // else throw new InvalidOperationException(); // } // break; // case ConnectionState.Disconnected: // { // throw new InvalidOperationException(); // } // case ConnectionState.Connected: // { // throw new InvalidOperationException(); // } // case ConnectionState.LinkError: // { // if (connectionTrigger == ConnectionTrigger.Connected) // { // await RunConnection(); // newState = ConnectionState.Connected; // } // } // break; // } // if (newState == currentState) // return; // State = newState; // System.Diagnostics.Debug.WriteLine($"{GetType()} SetState({currentState}) -> {connectionTrigger} -> {newState}"); // _connectionStateChangedAction?.Invoke(ServiceRef.Create<IConnection>(this), currentState, newState); //} //protected virtual void ConfigureStateMachine() //{ // _connectionStateMachine.Configure(ConnectionState.Disconnected) // .Permit(ConnectionTrigger.Connect, ConnectionState.Connecting) // .OnEntryFromAsync(ConnectionTrigger.Disconnect, async () => // { // await OnDisconnect().ConfigureAwait(false); // }); // _connectionStateMachine.Configure(ConnectionState.Connecting) // .Permit(ConnectionTrigger.Connected, ConnectionState.Connected) // .Permit(ConnectionTrigger.LinkError, ConnectionState.LinkError) // .Permit(ConnectionTrigger.Disconnect, ConnectionState.Disconnected) // .OnEntryAsync(async () => await ConnectAsyncCore().ConfigureAwait(false)) // .OnExitAsync(() => // { // _connectCancellationTokenSource?.Cancel(); // return Task.CompletedTask; // }) // .OnExit(() => _connectCancellationTokenSource?.Cancel()); // _connectionStateMachine.Configure(ConnectionState.Connected) // .Permit(ConnectionTrigger.Disconnect, ConnectionState.Disconnected) // .Permit(ConnectionTrigger.LinkError, ConnectionState.LinkError) // .OnEntryAsync(async () => // { // _receiveLoopTaskIsRunningEvent = new AsyncAutoResetEvent(); // _sendKeepAliveTaskIsRunningEvent = new AsyncAutoResetEvent(); // _receiveLoopTask = Task.Run(ReceiveLoopAsync); // if (_connectionSettings.KeepAliveMilliseconds > 0) // { // _sendKeepAliveLoopTask = Task.Run(() => SendKeepAliveLoopAsync()); // } // await _receiveLoopTaskIsRunningEvent.WaitAsync().ConfigureAwait(false); // if (_connectionSettings.KeepAliveMilliseconds > 0) // { // await _sendKeepAliveTaskIsRunningEvent.WaitAsync().ConfigureAwait(false); // } // _receiveLoopTaskIsRunningEvent = null; // _sendKeepAliveTaskIsRunningEvent = null; // }) // .OnExitAsync(() => // { // _receiveLoopCancellationTokenSource?.Cancel(); // _sendKeepAliveLoopCancellationTokenSource?.Cancel(); // _sendKeepAliveResetEvent?.Set(); // return Task.CompletedTask; // }); // _connectionStateMachine.Configure(ConnectionState.LinkError) // .Permit(ConnectionTrigger.Disconnect, ConnectionState.Disconnected) // .Permit(ConnectionTrigger.Connected, ConnectionState.Connected) // .Permit(ConnectionTrigger.Connect, ConnectionState.Connecting) // .OnEntryFromAsync(ConnectionTrigger.LinkError, async () => // { // await OnDisconnect().ConfigureAwait(false); // }); //} private async Task SendKeepAliveLoopAsync(AsyncAutoResetEvent sendKeepAliveResetEvent, CancellationToken cancellationToken) { try { //_sendKeepAliveResetEvent = new AsyncAutoResetEvent(false); //if (_sendKeepAliveLoopCancellationTokenSource != null) //{ // _sendKeepAliveLoopCancellationTokenSource.Dispose(); // _sendKeepAliveLoopCancellationTokenSource = null; //} //_sendKeepAliveLoopCancellationTokenSource = new CancellationTokenSource(); _sendKeepAliveTaskIsRunningEvent.Set(); if (_connectedStream.CanTimeout) { _connectedStream.ReadTimeout = _connectionSettings.KeepAliveMilliseconds * 2; } while (true) { cancellationToken.ThrowIfCancellationRequested(); if (!await sendKeepAliveResetEvent.WaitAsync(_connectionSettings.KeepAliveMilliseconds, cancellationToken).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); await ServiceRef.CallAndWaitAsync(this, async() => { if (State == ConnectionState.Connected && IsStreamConnected) { await _sendingStream.WriteAsync(_keepAlivePacket, 0, _keepAlivePacket.Length, cancellationToken).ConfigureAwait(false); } }).ConfigureAwait(false); } } } catch (OperationCanceledException) { System.Diagnostics.Debug.WriteLine($"{GetType()} SendKeepAliveLoop Cancelled"); } #if DEBUG catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); #else catch (Exception) { #endif //_sendKeepAliveLoopCancellationTokenSource = null; //_sendKeepAliveResetEvent = null; ServiceRef.Call(this, () => { if (State == ConnectionState.Connected) { //await _connectionStateMachine.FireAsync(ConnectionTrigger.LinkError).ConfigureAwait(false); SetState(ConnectionTrigger.LinkError); } }); } finally { //_sendKeepAliveLoopCancellationTokenSource = null; //_sendKeepAliveResetEvent = null; } }