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;
}
}
}