Пример #1
0
        public static async Task RunServerAsync(IConnectionListener listener, ConnectionDelegate connectionDelegate, CancellationToken cancellationToken = default)
        {
            ValueTask unbindTask = default;

            cancellationToken.Register(() =>
            {
                unbindTask = listener.UnbindAsync();
            });

            while (true)
            {
                var connection = await listener.AcceptAsync(cancellationToken);

                if (connection == null)
                {
                    break;
                }

                _ = Task.Run(async() =>
                {
                    try
                    {
                        await connectionDelegate(connection);
                    }
                    finally
                    {
                        await connection.DisposeAsync();
                    }
                });
            }

            await unbindTask;

            // TODO: Wait for opened connections to close

            await listener.DisposeAsync();
        }
Пример #2
0
 public ValueTask DisposeAsync()
 => _connectionListener.DisposeAsync();
Пример #3
0
 public override async Task StopAsync(CancellationToken cancellationToken)
 {
     await _connectionListener.DisposeAsync();
 }
Пример #4
0
        public async Task RunListenerAsync(IConnectionListener listener, ConnectionDelegate connectionDelegate, CancellationToken cancellationToken = default)
        {
            var unbindTask  = new TaskCompletionSource <object>();
            var connections = new ConcurrentDictionary <string, (ConnectionContext Connection, Task ExecutionTask)>();

            cancellationToken.Register(async() =>
            {
                try
                {
                    await listener.UnbindAsync();
                }
                finally
                {
                    unbindTask.TrySetResult(null);
                }
            });

            async Task ExecuteConnectionAsync(ConnectionContext connection)
            {
                await Task.Yield();

                try
                {
                    await connectionDelegate(connection);
                }
                catch (ConnectionAbortedException)
                {
                    // Don't let connection aborted exceptions out
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Unexpected exception from connection {ConnectionId}", connection.ConnectionId);
                }
                finally
                {
                    await connection.DisposeAsync();

                    // Remove the connection from tracking
                    connections.TryRemove(connection.ConnectionId, out _);
                }
            }

            while (true)
            {
                try
                {
                    var connection = await listener.AcceptAsync(cancellationToken);

                    if (connection == null)
                    {
                        // Null means we don't have anymore connections
                        break;
                    }

                    connections[connection.ConnectionId] = (connection, ExecuteConnectionAsync(connection));
                }
                catch (OperationCanceledException)
                {
                    // The accept loop was cancelled
                    break;
                }
            }

            // Wait for the listener to close, no new connections will be established
            await unbindTask.Task;

            // TODO: Give connections a chance to close gracefully

            var tasks = new List <Task>(connections.Count);

            // Abort all connections still in flight
            foreach (var pair in connections)
            {
                pair.Value.Connection.Abort();
                tasks.Add(pair.Value.ExecutionTask);
            }

            await Task.WhenAll(tasks);

            await listener.DisposeAsync();
        }