diff --git a/.DS_Store b/.DS_Store index 977dcfc..3cfbff4 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/src/.DS_Store b/src/.DS_Store index b64514e..7de8170 100644 Binary files a/src/.DS_Store and b/src/.DS_Store differ diff --git a/src/Pepperdash Core/.DS_Store b/src/Pepperdash Core/.DS_Store index de75050..bf662d8 100644 Binary files a/src/Pepperdash Core/.DS_Store and b/src/Pepperdash Core/.DS_Store differ diff --git a/src/Pepperdash Core/Logging/DebugWebsocketSink.cs b/src/Pepperdash Core/Logging/DebugWebsocketSink.cs index f24a585..e89940a 100644 --- a/src/Pepperdash Core/Logging/DebugWebsocketSink.cs +++ b/src/Pepperdash Core/Logging/DebugWebsocketSink.cs @@ -7,198 +7,104 @@ using Serilog; 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.Net.WebSockets; +using System.Threading; using System.IO; -using Org.BouncyCastle.Asn1.X509; using Serilog.Formatting; using Newtonsoft.Json.Linq; using Serilog.Formatting.Json; namespace PepperDash.Core { - public class DebugWebsocketSink : ILogEventSink + public class DebugWebsocketSink : ILogEventSink, IDisposable { - private HttpServer _httpsServer; - - private string _path = "/debug/join/"; - private const string _certificateName = "selfCres"; - private const string _certificatePassword = "cres12345"; + private readonly ITextFormatter _formatter; + private readonly List _clients; + private readonly object _lock = new object(); + private bool _disposed; - public int Port - { get - { - - if(_httpsServer == null) return 0; - return _httpsServer.Port; - } + public DebugWebsocketSink(ITextFormatter formatter) + { + _formatter = formatter ?? new JsonFormatter(); + _clients = new List(); } - public string Url + public void AddClient(WebSocket socket) { - get + lock (_lock) { - if (_httpsServer == null) return ""; - return $"wss://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{_httpsServer.Port}{_httpsServer.WebSocketServices[_path].Path}"; + _clients.Add(socket); } } - public bool IsRunning { get => _httpsServer?.IsListening ?? false; } - - - private readonly ITextFormatter _textFormatter; - - public DebugWebsocketSink(ITextFormatter formatProvider) + public void RemoveClient(WebSocket socket) { - - _textFormatter = formatProvider ?? new JsonFormatter(); - - if (!File.Exists($"\\user\\{_certificateName}.pfx")) - CreateCert(null); - - CrestronEnvironment.ProgramStatusEventHandler += type => + lock (_lock) { - if (type == eProgramStatusEventType.Stopping) - { - StopServer(); - } - }; - } - - private void CreateCert(string[] args) - { - try - { - //Debug.Console(0,"CreateCert Creating Utility"); - CrestronConsole.PrintLine("CreateCert Creating Utility"); - //var utility = new CertificateUtility(); - var utility = new BouncyCertificate(); - //Debug.Console(0, "CreateCert Calling CreateCert"); - CrestronConsole.PrintLine("CreateCert Calling CreateCert"); - //utility.CreateCert(); - var ipAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0); - var hostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0); - var domainName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0); - - //Debug.Console(0, "DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress); - CrestronConsole.PrintLine(string.Format("DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress)); - - var certificate = utility.CreateSelfSignedCertificate(string.Format("CN={0}.{1}", hostName, domainName), new[] { string.Format("{0}.{1}", hostName, domainName), ipAddress }, new[] { KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPClientAuth }); - //Crestron fails to let us do this...perhaps it should be done through their Dll's but haven't tested - //Debug.Print($"CreateCert Storing Certificate To My.LocalMachine"); - //utility.AddCertToStore(certificate, StoreName.My, StoreLocation.LocalMachine); - //Debug.Console(0, "CreateCert Saving Cert to \\user\\"); - CrestronConsole.PrintLine("CreateCert Saving Cert to \\user\\"); - utility.CertificatePassword = _certificatePassword; - utility.WriteCertificate(certificate, @"\user\", _certificateName); - //Debug.Console(0, "CreateCert Ending CreateCert"); - CrestronConsole.PrintLine("CreateCert Ending CreateCert"); - } - catch (Exception ex) - { - //Debug.Console(0, "WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace); - CrestronConsole.PrintLine(string.Format("WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace)); + _clients.Remove(socket); } } public void Emit(LogEvent logEvent) { - if (_httpsServer == null || !_httpsServer.IsListening) return; + if (logEvent == null || _disposed) return; - var sw = new StringWriter(); - _textFormatter.Format(logEvent, sw); + var writer = new StringWriter(); + _formatter.Format(logEvent, writer); + var json = writer.ToString(); + var buffer = Encoding.UTF8.GetBytes(json); - _httpsServer.WebSocketServices.Broadcast(sw.ToString()); - - } - - public void StartServerAndSetPort(int port) - { - Debug.Console(0, "Starting Websocket Server on port: {0}", port); - - - Start(port, $"\\user\\{_certificateName}.pfx", _certificatePassword); - } - - private void Start(int port, string certPath = "", string certPassword = "") - { - try + lock (_lock) { - _httpsServer = new HttpServer(port, true); - - - if (!string.IsNullOrWhiteSpace(certPath)) + foreach (var client in _clients.ToArray()) { - Debug.Console(0, "Assigning SSL Configuration"); - _httpsServer.SslConfiguration = new ServerSslConfiguration(new X509Certificate2(certPath, certPassword)) + try { - ClientCertificateRequired = false, - CheckCertificateRevocation = false, - EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls, - //this is just to test, you might want to actually validate - ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => + if (client.State == WebSocketState.Open) { - Debug.Console(0, "HTTPS ClientCerticateValidation Callback triggered"); - return true; + Task.Run(async () => + { + await client.SendAsync( + new ArraySegment(buffer), + WebSocketMessageType.Text, + true, + CancellationToken.None); + }); + } + else + { + RemoveClient(client); } - }; - } - Debug.Console(0, "Adding Debug Client Service"); - _httpsServer.AddWebSocketService(_path); - Debug.Console(0, "Assigning Log Info"); - _httpsServer.Log.Level = LogLevel.Trace; - _httpsServer.Log.Output = (d, s) => - { - uint level; - - switch(d.Level) - { - case WebSocketSharp.LogLevel.Fatal: - level = 3; - break; - case WebSocketSharp.LogLevel.Error: - level = 2; - break; - case WebSocketSharp.LogLevel.Warn: - level = 1; - break; - case WebSocketSharp.LogLevel.Info: - level = 0; - break; - case WebSocketSharp.LogLevel.Debug: - level = 4; - break; - case WebSocketSharp.LogLevel.Trace: - level = 5; - break; - default: - level = 4; - break; } - - Debug.Console(level, "{1} {0}\rCaller:{2}\rMessage:{3}\rs:{4}", d.Level.ToString(), d.Date.ToString(), d.Caller.ToString(), d.Message, s); - }; - Debug.Console(0, "Starting"); - - _httpsServer.Start(); - Debug.Console(0, "Ready"); - } - catch (Exception ex) - { - Debug.Console(0, "WebSocket Failed to start {0}", ex.Message); + catch (Exception) + { + RemoveClient(client); + } + } } } public void StopServer() { - Debug.Console(0, "Stopping Websocket Server"); - _httpsServer?.Stop(); + if (_disposed) return; + lock (_lock) + { + foreach (var client in _clients) + { + if (client.State == WebSocketState.Open) + { + client.Abort(); + } + } + _clients.Clear(); + } + } - _httpsServer = null; + public void Dispose() + { + if (_disposed) return; + _disposed = true; + StopServer(); } } @@ -211,61 +117,4 @@ namespace PepperDash.Core return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider)); } } - - public class DebugClient : WebSocketBehavior - { - private DateTime _connectionTime; - - public TimeSpan ConnectedDuration - { - get - { - if (Context.WebSocket.IsAlive) - { - return DateTime.Now - _connectionTime; - } - else - { - return new TimeSpan(0); - } - } - } - - public DebugClient() - { - Debug.Console(0, "DebugClient Created"); - } - - protected override void OnOpen() - { - base.OnOpen(); - - var url = Context.WebSocket.Url; - Debug.Console(0, Debug.ErrorLogLevel.Notice, "New WebSocket Connection from: {0}", url); - - _connectionTime = DateTime.Now; - } - - protected override void OnMessage(MessageEventArgs e) - { - base.OnMessage(e); - - Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data); - } - - protected override void OnClose(CloseEventArgs e) - { - base.OnClose(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); - } - } } diff --git a/src/Pepperdash Core/PepperDash_Core.csproj b/src/Pepperdash Core/PepperDash_Core.csproj index ae44062..8b3bcfe 100644 --- a/src/Pepperdash Core/PepperDash_Core.csproj +++ b/src/Pepperdash Core/PepperDash_Core.csproj @@ -41,7 +41,8 @@ - + +