using System; using System.Collections.Generic; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Server_Dashboard_Socket { /// /// Generic Channel class that handles the connection and message sending / receiving /// Inherits IDisposable to correctly cut the connection to the server /// /// The Protocol type, either JsonMessageProtocol or XmlMessageProtocol /// The message type, either JObject or XDocument public abstract class SocketChannel : IDisposable where TProtocol : Protocol, new() { protected bool isDisposable = false; private NetworkStream networkStream; private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); private readonly TProtocol protocol = new TProtocol(); private Func messageCallback; /// /// Attaches the socket to a network stream that owns the socket /// if the network stream goes down it takes the socket with it! /// /// A Socket public void Attach(Socket socket) { networkStream = new NetworkStream(socket, true); _ = Task.Run(ReceiveLoop, cancellationTokenSource.Token); } /// /// Takes a function with a message and sets the private member to the functions value /// /// public void OnMessage(Func callbackHandler) => messageCallback = callbackHandler; /// /// Makes sure to close the socket /// public void Close() { cancellationTokenSource.Cancel(); networkStream?.Close(); } /// /// Sends the message async /// /// Anything as message, e.g. object or string /// The message /// public async Task SendAsync(T message) => await protocol.SendAsync(networkStream, message).ConfigureAwait(false); /// /// Checks for received messages /// /// received message protected virtual async Task ReceiveLoop() { while (!cancellationTokenSource.Token.IsCancellationRequested) { var msg = await protocol.ReceiveAsync(networkStream).ConfigureAwait(false); await messageCallback(msg).ConfigureAwait(false); } } /// /// Deconstructor sets Dispose to false /// ~SocketChannel() => Dispose(false); /// /// Sets dispose to true /// public void Dispose() => Dispose(true); /// /// Disposes open sockets /// /// Is it currently disposing stuff? protected void Dispose(bool isDisposing) { //If its not disposable if (!isDisposable) { //Set disposable to true isDisposable = true; //Close the socket Close(); //If its closed, dispose it networkStream?.Dispose(); //Wait with the garbage collection until the disposing is done if (isDisposing) GC.SuppressFinalize(this); } } } }