diff --git a/src/PepperDash.Core/CoreInterfaces.cs b/src/PepperDash.Core/CoreInterfaces.cs index 6e0b639e..b142c69a 100644 --- a/src/PepperDash.Core/CoreInterfaces.cs +++ b/src/PepperDash.Core/CoreInterfaces.cs @@ -13,8 +13,8 @@ namespace PepperDash.Core /// public interface IKeyed { - /// - /// Unique Key + /// + /// Gets the unique key associated with the object. /// [JsonProperty("key")] string Key { get; } @@ -25,8 +25,8 @@ namespace PepperDash.Core /// public interface IKeyName : IKeyed { - /// - /// Isn't it obvious :) + /// + /// Gets the name associated with the current object. /// [JsonProperty("name")] string Name { get; } diff --git a/src/PepperDash.Core/Logging/DebugWebsocketSink.cs b/src/PepperDash.Core/Logging/DebugWebsocketSink.cs index b22757b1..5941fc56 100644 --- a/src/PepperDash.Core/Logging/DebugWebsocketSink.cs +++ b/src/PepperDash.Core/Logging/DebugWebsocketSink.cs @@ -1,27 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using Crestron.SimplSharp; +using Org.BouncyCastle.Asn1.X509; using Serilog; +using Serilog.Configuration; using Serilog.Core; using Serilog.Events; -using Serilog.Configuration; -using WebSocketSharp.Server; -using Crestron.SimplSharp; -using WebSocketSharp; -using System.Security.Authentication; -using WebSocketSharp.Net; -using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2; -using System.IO; -using Org.BouncyCastle.Asn1.X509; using Serilog.Formatting; -using Newtonsoft.Json.Linq; using Serilog.Formatting.Json; +using System; +using System.IO; +using System.Security.Authentication; +using WebSocketSharp; +using WebSocketSharp.Server; +using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2; namespace PepperDash.Core { - public class DebugWebsocketSink : ILogEventSink + /// + /// Provides a WebSocket-based logging sink for debugging purposes, allowing log events to be broadcast to connected + /// WebSocket clients. + /// + /// This class implements the interface and is designed to send + /// formatted log events to WebSocket clients connected to a secure WebSocket server. The server is hosted locally + /// and uses a self-signed certificate for SSL/TLS encryption. + public class DebugWebsocketSink : ILogEventSink, IKeyed { private HttpServer _httpsServer; @@ -29,6 +30,9 @@ namespace PepperDash.Core private const string _certificateName = "selfCres"; private const string _certificatePassword = "cres12345"; + /// + /// Gets the port number on which the HTTPS server is currently running. + /// public int Port { get { @@ -38,6 +42,11 @@ namespace PepperDash.Core } } + /// + /// Gets the WebSocket URL for the current server instance. + /// + /// The URL is dynamically constructed based on the server's current IP address, port, + /// and WebSocket path. public string Url { get @@ -47,18 +56,31 @@ namespace PepperDash.Core } } - public bool IsRunning { get => _httpsServer?.IsListening ?? false; } - + /// + /// Gets a value indicating whether the HTTPS server is currently listening for incoming connections. + /// + public bool IsRunning { get => _httpsServer?.IsListening ?? false; } + + /// + public string Key => "DebugWebsocketSink"; private readonly ITextFormatter _textFormatter; + /// + /// Initializes a new instance of the class with the specified text formatter. + /// + /// This constructor initializes the WebSocket sink and ensures that a certificate is + /// available for secure communication. If the required certificate does not exist, it will be created + /// automatically. Additionally, the sink is configured to stop the server when the program is + /// stopping. + /// The text formatter used to format log messages. If null, a default JSON formatter is used. public DebugWebsocketSink(ITextFormatter formatProvider) { _textFormatter = formatProvider ?? new JsonFormatter(); if (!File.Exists($"\\user\\{_certificateName}.pfx")) - CreateCert(null); + CreateCert(); CrestronEnvironment.ProgramStatusEventHandler += type => { @@ -69,7 +91,7 @@ namespace PepperDash.Core }; } - private void CreateCert(string[] args) + private static void CreateCert() { try { @@ -105,6 +127,13 @@ namespace PepperDash.Core } } + /// + /// Sends a log event to all connected WebSocket clients. + /// + /// The log event is formatted using the configured text formatter and then broadcasted + /// to all clients connected to the WebSocket server. If the WebSocket server is not initialized or not + /// listening, the method exits without performing any action. + /// The log event to be formatted and broadcasted. Cannot be null. public void Emit(LogEvent logEvent) { if (_httpsServer == null || !_httpsServer.IsListening) return; @@ -112,10 +141,16 @@ namespace PepperDash.Core var sw = new StringWriter(); _textFormatter.Format(logEvent, sw); - _httpsServer.WebSocketServices.Broadcast(sw.ToString()); - + _httpsServer.WebSocketServices[_path].Sessions.Broadcast(sw.ToString()); } + /// + /// Starts the WebSocket server on the specified port and configures it with the appropriate certificate. + /// + /// This method initializes the WebSocket server and binds it to the specified port. It + /// also applies the server's certificate for secure communication. Ensure that the port is not already in use + /// and that the certificate file is accessible. + /// The port number on which the WebSocket server will listen. Must be a valid, non-negative port number. public void StartServerAndSetPort(int port) { Debug.Console(0, "Starting Websocket Server on port: {0}", port); @@ -128,24 +163,22 @@ namespace PepperDash.Core { try { - _httpsServer = new HttpServer(port, true); - + _httpsServer = new HttpServer(port, true); if (!string.IsNullOrWhiteSpace(certPath)) { Debug.Console(0, "Assigning SSL Configuration"); - _httpsServer.SslConfiguration = new ServerSslConfiguration(new X509Certificate2(certPath, certPassword)) - { - ClientCertificateRequired = false, - CheckCertificateRevocation = false, - EnabledSslProtocols = SslProtocols.Tls12, - //this is just to test, you might want to actually validate - ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => + + _httpsServer.SslConfiguration.ServerCertificate = new X509Certificate2(certPath, certPassword); + _httpsServer.SslConfiguration.ClientCertificateRequired = false; + _httpsServer.SslConfiguration.CheckCertificateRevocation = false; + _httpsServer.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12; + //this is just to test, you might want to actually validate + _httpsServer.SslConfiguration.ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => { Debug.Console(0, "HTTPS ClientCerticateValidation Callback triggered"); return true; - } - }; + }; } Debug.Console(0, "Adding Debug Client Service"); _httpsServer.AddWebSocketService(_path); @@ -193,6 +226,11 @@ namespace PepperDash.Core } } + /// + /// Stops the WebSocket server if it is currently running. + /// + /// This method halts the WebSocket server and releases any associated resources. After + /// calling this method, the server will no longer accept or process incoming connections. public void StopServer() { Debug.Console(0, "Stopping Websocket Server"); @@ -202,8 +240,21 @@ namespace PepperDash.Core } } + /// + /// Configures the logger to write log events to a debug WebSocket sink. + /// + /// This extension method allows you to direct log events to a WebSocket sink for debugging + /// purposes. public static class DebugWebsocketSinkExtensions { + /// + /// Configures a logger to write log events to a debug WebSocket sink. + /// + /// This method adds a sink that writes log events to a WebSocket for debugging purposes. + /// It is typically used during development to stream log events in real-time. + /// The logger sink configuration to apply the WebSocket sink to. + /// An optional text formatter to format the log events. If not provided, a default formatter will be used. + /// A object that can be used to further configure the logger. public static LoggerConfiguration DebugWebsocketSink( this LoggerSinkConfiguration loggerConfiguration, ITextFormatter formatProvider = null) @@ -212,10 +263,20 @@ namespace PepperDash.Core } } + /// + /// Represents a WebSocket client for debugging purposes, providing connection lifecycle management and message + /// handling functionality. + /// + /// The class extends to handle + /// WebSocket connections, including events for opening, closing, receiving messages, and errors. It tracks the + /// duration of the connection and logs relevant events for debugging. public class DebugClient : WebSocketBehavior { private DateTime _connectionTime; + /// + /// Gets the duration of time the WebSocket connection has been active. + /// public TimeSpan ConnectedDuration { get @@ -231,11 +292,17 @@ namespace PepperDash.Core } } + /// + /// Initializes a new instance of the class. + /// + /// This constructor creates a new instance and logs its + /// creation using the method with a debug level of 0. public DebugClient() { Debug.Console(0, "DebugClient Created"); } + /// protected override void OnOpen() { base.OnOpen(); @@ -246,6 +313,7 @@ namespace PepperDash.Core _connectionTime = DateTime.Now; } + /// protected override void OnMessage(MessageEventArgs e) { base.OnMessage(e); @@ -253,6 +321,7 @@ namespace PepperDash.Core Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data); } + /// protected override void OnClose(CloseEventArgs e) { base.OnClose(e); @@ -261,6 +330,7 @@ namespace PepperDash.Core } + /// protected override void OnError(WebSocketSharp.ErrorEventArgs e) { base.OnError(e);