(_path);
+ _httpsServer.OnGet += HandleHttpGet;
+ Debug.LogInformation("Assigning Log Info");
+ _httpsServer.Log.Level = LogLevel.Trace;
+ _httpsServer.Log.Output = WriteWebSocketInternalLog;
+ Debug.LogInformation("Starting");
+
+ _httpsServer.Start();
+ Debug.LogInformation("Ready");
}
-
- ///
- /// StopServer method
- ///
- public void StopServer()
+ catch (Exception ex)
{
- Debug.Console(0, "Stopping Websocket Server");
- _httpsServer?.Stop();
-
+ Debug.LogError(ex, "WebSocket Failed to start {0}", ex.Message);
+ Debug.LogVerbose("Stack Trace:\r{0}", ex.StackTrace);
+ // Null out the server so callers can detect failure via IsRunning / Url null guards.
_httpsServer = null;
}
}
- public static class DebugWebsocketSinkExtensions
+ private void HandleHttpGet(object sender, HttpRequestEventArgs e)
{
- ///
- /// DebugWebsocketSink method
- ///
- public static LoggerConfiguration DebugWebsocketSink(
- this LoggerSinkConfiguration loggerConfiguration,
- ITextFormatter formatProvider = null)
+ var res = e.Response;
+ var body = System.Text.Encoding.UTF8.GetBytes(
+ "Certificate accepted.
You can close this tab and return to the application.
");
+ res.ContentType = "text/html";
+ res.ContentLength64 = body.Length;
+ res.Close(body, true);
+ }
+
+ ///
+ /// 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.LogInformation("Stopping Websocket Server");
+
+ try
{
- return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider));
+ if (_httpsServer == null || !_httpsServer.IsListening)
+ {
+ return;
+ }
+
+ // Prevent close-sequence internal websocket logs from re-entering the logging pipeline.
+ _httpsServer.Log.Output = (d, s) => { };
+
+ var serviceHost = _httpsServer.WebSocketServices[_path];
+
+ if (serviceHost == null)
+ {
+ _httpsServer.Stop();
+ _httpsServer = null;
+ return;
+ }
+
+ serviceHost.Sessions.Broadcast("Server is stopping");
+
+ foreach (var session in serviceHost.Sessions.Sessions)
+ {
+ if (session?.Context?.WebSocket != null && session.Context.WebSocket.IsAlive)
+ {
+ session.Context.WebSocket.Close(1001, "Server is stopping");
+ }
+ }
+
+ _httpsServer.Stop();
+
+ _httpsServer = null;
+
+ }
+ catch (Exception ex)
+ {
+ Debug.LogError(ex, "WebSocket Failed to stop gracefully {0}", ex.Message);
+ Debug.LogVerbose("Stack Trace\r\n{0}", ex.StackTrace);
+ }
+ }
+
+ private static void WriteWebSocketInternalLog(LogData data, string supplemental)
+ {
+ try
+ {
+ if (data == null)
+ {
+ return;
+ }
+
+ var message = string.IsNullOrWhiteSpace(data.Message) ? "" : data.Message;
+ var details = string.IsNullOrWhiteSpace(supplemental) ? string.Empty : string.Format(" | details: {0}", supplemental);
+
+ // Use direct console output to avoid recursive log sink calls.
+ CrestronConsole.PrintLine(string.Format("WS[{0}] {1} | message: {2}{3}", data.Level, data.Date, message, details));
+ }
+ catch
+ {
+ // Never throw from websocket log callback.
+ }
+ }
+
+}
+
+///
+/// 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)
+ {
+ return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider));
+ }
+}
+
+///
+/// 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
+ {
+ if (Context.WebSocket.IsAlive)
+ {
+ return DateTime.Now - _connectionTime;
+ }
+ else
+ {
+ return new TimeSpan(0);
+ }
}
}
///
- /// Represents a DebugClient
+ /// Initializes a new instance of the class.
///
- public class DebugClient : WebSocketBehavior
+ public DebugClient()
{
- private DateTime _connectionTime;
+ Debug.LogInformation("DebugClient Created");
+ }
- public TimeSpan ConnectedDuration
- {
- get
- {
- if (Context.WebSocket.IsAlive)
- {
- return DateTime.Now - _connectionTime;
- }
- else
- {
- return new TimeSpan(0);
- }
- }
- }
+ ///
+ protected override void OnOpen()
+ {
+ base.OnOpen();
- public DebugClient()
- {
- Debug.Console(0, "DebugClient Created");
- }
+ var url = Context.WebSocket.Url;
+ Debug.LogInformation("New WebSocket Connection from: {0}", url);
- protected override void OnOpen()
- {
- base.OnOpen();
+ _connectionTime = DateTime.Now;
+ }
- var url = Context.WebSocket.Url;
- Debug.Console(0, Debug.ErrorLogLevel.Notice, "New WebSocket Connection from: {0}", url);
+ ///
+ protected override void OnMessage(MessageEventArgs e)
+ {
+ base.OnMessage(e);
- _connectionTime = DateTime.Now;
- }
+ Debug.LogVerbose("WebSocket UiClient Message: {0}", e.Data);
+ }
- protected override void OnMessage(MessageEventArgs e)
- {
- base.OnMessage(e);
+ ///
+ protected override void OnClose(CloseEventArgs e)
+ {
+ base.OnClose(e);
- Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data);
- }
+ Debug.LogDebug("WebSocket UiClient Closing: {0} reason: {1}", e.Code, e.Reason);
+ }
- protected override void OnClose(CloseEventArgs e)
- {
- base.OnClose(e);
+ ///
+ protected override void OnError(WebSocketSharp.ErrorEventArgs e)
+ {
+ base.OnError(e);
- Debug.Console(0, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Closing: {0} reason: {1}", e.Code, e.Reason);
-
- }
-
- protected override void OnError(WebSocketSharp.ErrorEventArgs e)
- {
- base.OnError(e);
-
- Debug.Console(2, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Error: {0} message: {1}", e.Exception, e.Message);
- }
+ Debug.LogError(e.Exception, "WebSocket UiClient Error: {0} message: {1}", e.Exception, e.Message);
+ Debug.LogVerbose("Stack Trace:\r{0}", e.Exception.StackTrace);
}
}
diff --git a/src/PepperDash.Core/Network/DiscoveryThings.cs b/src/PepperDash.Core/Network/DiscoveryThings.cs
index 973c03a4..c01613b7 100644
--- a/src/PepperDash.Core/Network/DiscoveryThings.cs
+++ b/src/PepperDash.Core/Network/DiscoveryThings.cs
@@ -4,19 +4,17 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
-namespace PepperDash.Core
-{
+namespace PepperDash.Core;
+
+///
+/// Not in use
+///
+ public static class NetworkComm
+ {
///
/// Not in use
///
- public static class NetworkComm
- {
- ///
- /// Not in use
- ///
static NetworkComm()
{
}
- }
-
-}
\ No newline at end of file
+ }
\ No newline at end of file
diff --git a/src/PepperDash.Core/PasswordManagement/Config.cs b/src/PepperDash.Core/PasswordManagement/Config.cs
index 22aa4881..a5f071a4 100644
--- a/src/PepperDash.Core/PasswordManagement/Config.cs
+++ b/src/PepperDash.Core/PasswordManagement/Config.cs
@@ -4,8 +4,8 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
-namespace PepperDash.Core.PasswordManagement
-{
+namespace PepperDash.Core.PasswordManagement;
+
///
/// JSON password configuration
///
@@ -22,5 +22,4 @@ namespace PepperDash.Core.PasswordManagement
{
}
- }
-}
\ No newline at end of file
+ }
\ No newline at end of file
diff --git a/src/PepperDash.Core/PasswordManagement/Constants.cs b/src/PepperDash.Core/PasswordManagement/Constants.cs
index 65a1bf45..d4cf1e0b 100644
--- a/src/PepperDash.Core/PasswordManagement/Constants.cs
+++ b/src/PepperDash.Core/PasswordManagement/Constants.cs
@@ -4,8 +4,8 @@ using System.Linq;
using System.Text;
using Crestron.SimplSharp;
-namespace PepperDash.Core.PasswordManagement
-{
+namespace PepperDash.Core.PasswordManagement;
+
///
/// Constants
///
@@ -53,5 +53,4 @@ namespace PepperDash.Core.PasswordManagement
/// Generic string value change constant
///