/// <summary>
        /// Opens the <see cref="StreamingConnection"/> and listens for incoming requests, which will
        /// be assembled and sent to the provided <see cref="RequestHandler"/>.
        /// </summary>
        /// <param name="requestHandler"><see cref="RequestHandler"/> to which incoming requests will be sent.</param>
        /// <param name="cancellationToken"><see cref="CancellationToken"/> that signals the need to stop the connection.
        /// Once the token is cancelled, the connection will be gracefully shut down, finishing pending sends and receives.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public virtual async Task ListenAsync(RequestHandler requestHandler, CancellationToken cancellationToken = default)
        {
            if (requestHandler == null)
            {
                throw new ArgumentNullException(nameof(requestHandler));
            }

            var duplexPipePair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

            // Create transport and application
            _transport = CreateStreamingTransport(duplexPipePair.Application);
            var application = new TransportHandler(duplexPipePair.Transport, Logger);

            // Create session
            _session = new StreamingSession(requestHandler, application, Logger, cancellationToken);

            // Start transport and application
            var transportTask   = _transport.ConnectAsync(cancellationToken);
            var applicationTask = application.ListenAsync(cancellationToken);

            var tasks = new List <Task> {
                transportTask, applicationTask
            };

            // Signal that session is ready to be used
            _sessionInitializedTask.SetResult(true);

            // Let application and transport run
            await Task.WhenAll(tasks).ConfigureAwait(false);
        }
Example #2
0
        private async Task ListenImplAsync(Func <WebSocketTransport, Task> socketConnectFunc, RequestHandler requestHandler, CancellationToken cancellationToken = default(CancellationToken))
        {
            var duplexPipePair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

            // Create transport and application
            var transport   = new WebSocketTransport(duplexPipePair.Application, _logger);
            var application = new TransportHandler(duplexPipePair.Transport, _logger);

            // Create session
            _session = new StreamingSession(requestHandler, application, _logger, cancellationToken);

            // Start transport and application
            var transportTask   = socketConnectFunc(transport);
            var applicationTask = application.ListenAsync(cancellationToken);

            var tasks = new List <Task>()
            {
                transportTask, applicationTask
            };

            // Signal that session is ready to be used
            _sessionInitializedTask.SetResult(true);

            // Let application and transport run
            await Task.WhenAll(tasks).ConfigureAwait(false);
        }
Example #3
0
        internal async Task ConnectInternalAsync(Func <WebSocketTransport, Task> connectFunc, CancellationToken cancellationToken)
        {
            CheckDisposed();

            TimerAwaitable timer     = null;
            Task           timerTask = null;

            try
            {
                // Pipes
                _duplexPipePair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

                // Transport
                var transport = new WebSocketTransport(_duplexPipePair.Application, _logger);

                // Application
                _transportHandler = new TransportHandler(_duplexPipePair.Transport, _logger);

                // Session
                _session = new StreamingSession(_requestHandler, _transportHandler, _logger, cancellationToken);

                // Set up cancellation
                _disconnectCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

                // Start transport and application
                var transportTask   = connectFunc(transport);
                var applicationTask = _transportHandler.ListenAsync(_disconnectCts.Token);
                var combinedTask    = Task.WhenAll(transportTask, applicationTask);

                Log.ClientStarted(_logger, _url ?? string.Empty);

                // Periodic task: keep alive
                // Disposed with `timer.Stop()` in the finally block below
                if (_keepAlive.HasValue)
                {
                    timer     = new TimerAwaitable(_keepAlive.Value, _keepAlive.Value);
                    timerTask = TimerLoopAsync(timer);
                }

                // We are connected!
                IsConnected = true;

                // Block until transport or application ends.
                await combinedTask.ConfigureAwait(false);

                // Signal that we're done
                _disconnectCts.Cancel();
                Log.ClientTransportApplicationCompleted(_logger, _url);
            }
            finally
            {
                timer?.Stop();

                if (timerTask != null)
                {
                    await timerTask.ConfigureAwait(false);
                }
            }

            Log.ClientCompleted(_logger, _url ?? string.Empty);
        }