using System; using System.Threading.Tasks; using Impostor.Api.Net.Messages; using Serilog; namespace Impostor.Hazel { /// /// Base class for all connection listeners. /// /// /// /// ConnectionListeners are server side objects that listen for clients and create matching server side connections /// for each client in a similar way to TCP does. These connections should be ready for communication immediately. /// /// /// Each time a client connects the event will be invoked to alert all subscribers to /// the new connection. A disconnected event is then present on the that is passed to the /// subscribers. /// /// /// public abstract class ConnectionListener : IAsyncDisposable { private static readonly ILogger Logger = Log.ForContext(); /// /// Invoked when a new client connects. /// /// /// /// NewConnection is invoked each time a client connects to the listener. The /// contains the new for communication with this /// client. /// /// /// Hazel may or may not store connections so it is your responsibility to keep track and properly Dispose of /// connections to your server. /// /// /// /// /// /// public Func NewConnection; /// /// Makes this connection listener begin listening for connections. /// /// /// /// This instructs the listener to begin listening for new clients connecting to the server. When a new client /// connects the event will be invoked containing the connection to the new client. /// /// /// To stop listening you should call . /// /// /// /// /// public abstract Task StartAsync(); /// /// Invokes the NewConnection event with the supplied connection. /// /// The user sent bytes that were received as part of the handshake. /// The connection to pass in the arguments. /// /// Implementers should call this to invoke the event before data is received so that /// subscribers do not miss any data that may have been sent immediately after connecting. /// internal async Task InvokeNewConnection(IMessageReader msg, Connection connection) { // Make a copy to avoid race condition between null check and invocation var handler = NewConnection; if (handler != null) { try { await handler(new NewConnectionEventArgs(msg, connection)); } catch (Exception e) { Logger.Error(e, "Accepting connection failed"); await connection.Disconnect("Accepting connection failed"); } } } /// /// Call to dispose of the connection listener. /// public virtual ValueTask DisposeAsync() { this.NewConnection = null; return ValueTask.CompletedTask; } } }