From 8c81517b98db6fcc7553b151ac097d95332910e9 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Mon, 12 Dec 2022 09:33:13 -0700 Subject: [PATCH 01/22] Revert "Feature/ssh dispose" --- Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs index 6998116..742ea03 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs @@ -298,7 +298,6 @@ namespace PepperDash.Core /// public void Disconnect() { - Debug.Console(2, "Disconnect Called"); ConnectEnabled = false; // Stop trying reconnects, if we are if (ReconnectTimer != null) @@ -316,13 +315,11 @@ namespace PepperDash.Core private void KillClient(SocketStatus status) { KillStream(); - IsConnecting = false; + if (Client != null) { - Client.ErrorOccurred -= Client_ErrorOccurred; + IsConnecting = false; Client.Disconnect(); - Client.Dispose(); - Client = null; ClientStatus = status; Debug.Console(1, this, "Disconnected"); From 1cbdc5aaef114abe000b4eb4dc8396f423713e28 Mon Sep 17 00:00:00 2001 From: jdevito Date: Tue, 17 Jan 2023 09:50:39 -0600 Subject: [PATCH 02/22] feat: added crestron web server (cws) generic base --- .../CrestronWebServer/GenericCwsBase.cs | 266 ++++++++++++++++++ .../RequestHandlerUnknown.cs | 16 ++ .../Pepperdash Core/PepperDash_Core.csproj | 6 + 3 files changed, 288 insertions(+) create mode 100644 Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs create mode 100644 Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs new file mode 100644 index 0000000..9446e6a --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs @@ -0,0 +1,266 @@ +using System; +using Crestron.SimplSharp; +using Crestron.SimplSharp.WebScripting; + +namespace PepperDash.Core +{ + public class GenericCwsBase : Device + { + private const string SplusKey = "Uninitialized CWS Server"; + private const string DefaultBasePath = "/api"; + + private const uint DebugTrace = 0; + private const uint DebugInfo = 1; + private const uint DebugVerbose = 2; + + private HttpCwsServer _server; + private readonly CCriticalSection _serverLock = new CCriticalSection(); + + /// + /// CWS base path, will default to "/api" if not set via initialize method + /// + public string BasePath { get; private set; } + + /// + /// Indicates CWS is registered with base path + /// + public bool IsRegistered { get; private set; } + + /// + /// Constructor for S+. Make sure to set necessary properties using init method + /// + public GenericCwsBase() + : base(SplusKey) + { + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; + CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; + } + + /// + /// Constructor + /// + /// + /// + public GenericCwsBase(string key, string basePath) + : base(key) + { + + BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + } + + /// + /// + /// + /// + /// + /// + public GenericCwsBase(string key, string name, string basePath) + : base(key, name) + { + + BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + } + + /// + /// Program status event handler + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType != eProgramStatusEventType.Stopping) + return; + + Debug.Console(DebugInfo, this, "Program stopping. Disabling Server"); + + Stop(); + } + + /// + /// Ethernet event handler + /// + /// + void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) + { + // Re-enable the server if the link comes back up and the status should be connected + if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp + && IsRegistered) + { + Debug.Console(DebugInfo, this, "Ethernet link up. Starting server"); + + Start(); + } + } + + /// + /// Initializes CWS class + /// + public void Initialize(string key, string basePath) + { + Key = key; + BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + } + + /// + /// Starts CWS instance + /// + public void Start() + { + try + { + _serverLock.Enter(); + + if (_server != null) + { + Debug.Console(DebugInfo, this, "Server has already been started"); + return; + } + + Debug.Console(DebugInfo, this, "Starting server"); + + _server = new HttpCwsServer(BasePath) + { + HttpRequestHandler = new RequestHandlerUnknown() + }; + + IsRegistered = _server.Register(); + } + catch (Exception ex) + { + Debug.Console(DebugInfo, this, "Start Exception Message: {0}", ex.Message); + Debug.Console(DebugVerbose, this, "Start Exception StackTrace: {0}", ex.StackTrace); + if (ex.InnerException != null) + Debug.Console(DebugVerbose, this, "Start Exception InnerException: {0}", ex.InnerException); + } + finally + { + _serverLock.Leave(); + } + } + + /// + /// Stop CWS instance + /// + public void Stop() + { + try + { + _serverLock.Enter(); + + if (_server == null) + { + Debug.Console(DebugInfo, this, "Servier has already been stopped"); + return; + } + + if (_server.Unregister()) + { + IsRegistered = false; + } + + Dispose(true); + } + catch (Exception ex) + { + Debug.Console(DebugInfo, this, "ServerStop Exception Message: {0}", ex.Message); + Debug.Console(DebugVerbose, this, "ServerStop Exception StackTrace: {0}", ex.StackTrace); + if (ex.InnerException != null) + Debug.Console(DebugVerbose, this, "ServerStop Exception InnerException: {0}", ex.InnerException); + } + finally + { + _serverLock.Leave(); + } + } + + /// + /// Received request handler + /// + /// + /// This is here for development and testing + /// + /// + /// + public void ReceivedRequestEventHandler(object sender, HttpCwsRequestEventArgs args) + { + try + { + // TODO [ ] Add logic for received requests + Debug.Console(DebugInfo, this, @"RecieveRequestEventHandler +Method: {0} +Path: {1} +PathInfo: {2} +PhysicalPath: {3} +ContentType: {4} +RawUrl: {5} +Url: {6} +UserAgent: {7} +UserHostAddress: {8} +UserHostName: {9}", + args.Context.Request.HttpMethod, + args.Context.Request.Path, + args.Context.Request.PathInfo, + args.Context.Request.PhysicalPath, + args.Context.Request.ContentType, + args.Context.Request.RawUrl, + args.Context.Request.Url, + args.Context.Request.UserAgent, + args.Context.Request.UserHostAddress, + args.Context.Request.UserHostName); + + } + catch (Exception ex) + { + Debug.Console(DebugInfo, this, "ReceivedRequestEventHandler Exception Message: {0}", ex.Message); + Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception StackTrace: {0}", ex.StackTrace); + if (ex.InnerException != null) + Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException); + } + } + + /// + /// Tracks if CWS is disposed + /// + public bool Disposed + { + get + { + return (_server == null); + } + } + + /// + /// Disposes CWS instance + /// + public void Dispose() + { + Dispose(true); + CrestronEnvironment.GC.SuppressFinalize(this); + } + + /// + /// Disposes CWS instance + /// + /// + protected void Dispose(bool disposing) + { + if (Disposed) + { + Debug.Console(DebugInfo, this, "Server has already been disposed"); + return; + } + + if (!disposing) return; + + if (_server != null) + { + _server.Dispose(); + _server = null; + } + } + + ~GenericCwsBase() + { + Dispose(true); + } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs new file mode 100644 index 0000000..5a2adac --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs @@ -0,0 +1,16 @@ +using Crestron.SimplSharp.WebScripting; + +namespace PepperDash.Core +{ + public class RequestHandlerUnknown : IHttpCwsHandler + { + public void ProcessRequest(HttpCwsContext context) + { + // TODO [ ] Modify unknown request handler + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.ContentType = "application/json"; + context.Response.Write(string.Format("{0} {1}", context.Request.HttpMethod, context.Request.RawUrl), true); + } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index 86ae71d..8e49d82 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -51,6 +51,10 @@ False ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll + + False + ..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCWSHelperInterface.dll + False ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll @@ -89,6 +93,8 @@ + + From e98aae2d89ffe2a4c833dd2407c1ca864f36a833 Mon Sep 17 00:00:00 2001 From: jdevito Date: Wed, 18 Jan 2023 13:30:27 -0600 Subject: [PATCH 03/22] fix: Added CwsBaseHandler, refactored CwsDefaultRequestHandler --- .../CrestronWebServer/CwsBaseHandler.cs | 149 ++++++++++++++++++ .../CwsDefaultRequestHandler.cs | 106 +++++++++++++ .../CrestronWebServer/GenericCwsBase.cs | 120 ++++++-------- .../RequestHandlerUnknown.cs | 16 -- .../Pepperdash Core/PepperDash_Core.csproj | 5 +- .../PepperDash_Core.csproj.DotSettings | 2 + 6 files changed, 309 insertions(+), 89 deletions(-) create mode 100644 Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs create mode 100644 Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs delete mode 100644 Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs create mode 100644 Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs new file mode 100644 index 0000000..f9e25bf --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; + +namespace PepperDash.Core +{ + /// + /// CWS Base Handler, implements IHttpCwsHandler + /// + public abstract class CwsBaseHandler : IHttpCwsHandler + { + private readonly Dictionary> _handlers; + + /// + /// Constructor + /// + protected CwsBaseHandler() + { + _handlers = new Dictionary> + { + {"CONNECT", HandleConnect}, + {"DELETE", HandleDelete}, + {"GET", HandleGet}, + {"HEAD", HandleHead}, + {"OPTIONS", HandleOptions}, + {"PATCH", HandlePatch}, + {"POST", HandlePost}, + {"PUT", HandlePut}, + {"TRACE", HandleTrace} + }; + } + + /// + /// Handles CONNECT method requests + /// + /// + protected virtual void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected virtual void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected virtual void HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected virtual void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected virtual void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected virtual void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected virtual void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected virtual void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected virtual void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Process request + /// + /// + public void ProcessRequest(HttpCwsContext context) + { + Action handler; + + if (!_handlers.TryGetValue(context.Request.HttpMethod, out handler)) + { + return; + } + + handler(context); + } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs new file mode 100644 index 0000000..3a91114 --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs @@ -0,0 +1,106 @@ +using Crestron.SimplSharp.WebScripting; + +namespace PepperDash.Core +{ + public class CwsDefaultRequestHandler : CwsBaseHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs index 9446e6a..0bfbb63 100644 --- a/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs +++ b/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs @@ -44,7 +44,6 @@ namespace PepperDash.Core public GenericCwsBase(string key, string basePath) : base(key) { - BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; } @@ -57,7 +56,6 @@ namespace PepperDash.Core public GenericCwsBase(string key, string name, string basePath) : base(key, name) { - BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; } @@ -67,8 +65,7 @@ namespace PepperDash.Core /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { - if (programEventType != eProgramStatusEventType.Stopping) - return; + if (programEventType != eProgramStatusEventType.Stopping) return; Debug.Console(DebugInfo, this, "Program stopping. Disabling Server"); @@ -82,13 +79,15 @@ namespace PepperDash.Core void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) { // Re-enable the server if the link comes back up and the status should be connected - if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp - && IsRegistered) + if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp && IsRegistered) { - Debug.Console(DebugInfo, this, "Ethernet link up. Starting server"); - - Start(); + Debug.Console(DebugInfo, this, "Ethernet link up. Server is alreedy registered."); + return; } + + Debug.Console(DebugInfo, this, "Ethernet link up. Starting server"); + + Start(); } /// @@ -97,7 +96,37 @@ namespace PepperDash.Core public void Initialize(string key, string basePath) { Key = key; - BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + } + + /// + /// Adds a route to CWS + /// + public void AddRoute(HttpCwsRoute route) + { + if (route == null) + { + Debug.Console(DebugInfo, this, "Failed to add route, route parameter is null"); + return; + } + + _server.Routes.Add(route); + + } + + /// + /// Removes a route from CWS + /// + /// + public void RemoveRoute(HttpCwsRoute route) + { + if (route == null) + { + Debug.Console(DebugInfo, this, "Failed to remote route, orute parameter is null"); + return; + } + + _server.Routes.Remove(route); } /// @@ -119,7 +148,7 @@ namespace PepperDash.Core _server = new HttpCwsServer(BasePath) { - HttpRequestHandler = new RequestHandlerUnknown() + HttpRequestHandler = new CwsDefaultRequestHandler() }; IsRegistered = _server.Register(); @@ -148,29 +177,26 @@ namespace PepperDash.Core if (_server == null) { - Debug.Console(DebugInfo, this, "Servier has already been stopped"); + Debug.Console(DebugInfo, this, "Server has already been stopped"); return; } - if (_server.Unregister()) - { - IsRegistered = false; - } - - Dispose(true); + IsRegistered = _server.Unregister() == false; + _server.Dispose(); + _server = null; } catch (Exception ex) { - Debug.Console(DebugInfo, this, "ServerStop Exception Message: {0}", ex.Message); - Debug.Console(DebugVerbose, this, "ServerStop Exception StackTrace: {0}", ex.StackTrace); + Debug.Console(DebugInfo, this, "Server Stop Exception Message: {0}", ex.Message); + Debug.Console(DebugVerbose, this, "Server Stop Exception StackTrace: {0}", ex.StackTrace); if (ex.InnerException != null) - Debug.Console(DebugVerbose, this, "ServerStop Exception InnerException: {0}", ex.InnerException); + Debug.Console(DebugVerbose, this, "Server Stop Exception InnerException: {0}", ex.InnerException); } finally { _serverLock.Leave(); } - } + } /// /// Received request handler @@ -184,7 +210,6 @@ namespace PepperDash.Core { try { - // TODO [ ] Add logic for received requests Debug.Console(DebugInfo, this, @"RecieveRequestEventHandler Method: {0} Path: {1} @@ -206,7 +231,6 @@ UserHostName: {9}", args.Context.Request.UserAgent, args.Context.Request.UserHostAddress, args.Context.Request.UserHostName); - } catch (Exception ex) { @@ -215,52 +239,6 @@ UserHostName: {9}", if (ex.InnerException != null) Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException); } - } - - /// - /// Tracks if CWS is disposed - /// - public bool Disposed - { - get - { - return (_server == null); - } - } - - /// - /// Disposes CWS instance - /// - public void Dispose() - { - Dispose(true); - CrestronEnvironment.GC.SuppressFinalize(this); - } - - /// - /// Disposes CWS instance - /// - /// - protected void Dispose(bool disposing) - { - if (Disposed) - { - Debug.Console(DebugInfo, this, "Server has already been disposed"); - return; - } - - if (!disposing) return; - - if (_server != null) - { - _server.Dispose(); - _server = null; - } - } - - ~GenericCwsBase() - { - Dispose(true); - } + } } } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs deleted file mode 100644 index 5a2adac..0000000 --- a/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Crestron.SimplSharp.WebScripting; - -namespace PepperDash.Core -{ - public class RequestHandlerUnknown : IHttpCwsHandler - { - public void ProcessRequest(HttpCwsContext context) - { - // TODO [ ] Modify unknown request handler - context.Response.StatusCode = 418; - context.Response.StatusDescription = "I'm a teapot"; - context.Response.ContentType = "application/json"; - context.Response.Write(string.Format("{0} {1}", context.Request.HttpMethod, context.Request.RawUrl), true); - } - } -} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index 8e49d82..55c4a20 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -7,7 +7,7 @@ {87E29B4C-569B-4368-A4ED-984AC1440C96} Library Properties - PepperDash_Core + PepperDash.Core PepperDash_Core {0B4745B0-194B-4BB6-8E21-E9057CA92500};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} WindowsCE @@ -93,8 +93,9 @@ + - + diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings new file mode 100644 index 0000000..8107a4f --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file From 78631be83021898148d8a7dd19584122f630878c Mon Sep 17 00:00:00 2001 From: jdevito Date: Wed, 18 Jan 2023 15:22:50 -0600 Subject: [PATCH 04/22] refactor: Changed CWS references to WebApi, re-organized Web folder --- .../Pepperdash Core/PepperDash_Core.csproj | 6 ++-- .../PepperDash_Core.csproj.DotSettings | 3 +- .../DefaultRequestRequestHandler.cs} | 4 +-- .../WebApiBaseRequestHandler.cs} | 7 ++-- .../GenericCwsBase.cs => Web/WebApiServer.cs} | 34 +++++++++++-------- 5 files changed, 30 insertions(+), 24 deletions(-) rename Pepperdash Core/Pepperdash Core/{CrestronWebServer/CwsDefaultRequestHandler.cs => Web/RequestHandlers/DefaultRequestRequestHandler.cs} (92%) rename Pepperdash Core/Pepperdash Core/{CrestronWebServer/CwsBaseHandler.cs => Web/RequestHandlers/WebApiBaseRequestHandler.cs} (92%) rename Pepperdash Core/Pepperdash Core/{CrestronWebServer/GenericCwsBase.cs => Web/WebApiServer.cs} (86%) diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index 55c4a20..b4785a2 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -93,9 +93,9 @@ - - - + + + diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings index 8107a4f..8e644b9 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings @@ -1,2 +1,3 @@  - True \ No newline at end of file + True + False \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs similarity index 92% rename from Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs rename to Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs index 3a91114..38dd6b3 100644 --- a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs @@ -1,8 +1,8 @@ using Crestron.SimplSharp.WebScripting; -namespace PepperDash.Core +namespace PepperDash.Core.Web.RequestHandlers { - public class CwsDefaultRequestHandler : CwsBaseHandler + public class DefaultRequestRequestHandler : WebApiBaseRequestHandler { /// /// Handles CONNECT method requests diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs similarity index 92% rename from Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs rename to Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs index f9e25bf..6d4b41c 100644 --- a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs @@ -1,21 +1,20 @@ using System; using System.Collections.Generic; using Crestron.SimplSharp.WebScripting; -using Newtonsoft.Json; -namespace PepperDash.Core +namespace PepperDash.Core.Web.RequestHandlers { /// /// CWS Base Handler, implements IHttpCwsHandler /// - public abstract class CwsBaseHandler : IHttpCwsHandler + public abstract class WebApiBaseRequestHandler : IHttpCwsHandler { private readonly Dictionary> _handlers; /// /// Constructor /// - protected CwsBaseHandler() + protected WebApiBaseRequestHandler() { _handlers = new Dictionary> { diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs similarity index 86% rename from Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs rename to Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs index 0bfbb63..6843e25 100644 --- a/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs +++ b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs @@ -1,12 +1,14 @@ using System; using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; +using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Core +namespace PepperDash.Core.Web { - public class GenericCwsBase : Device + public class WebApiServer : IKeyName { - private const string SplusKey = "Uninitialized CWS Server"; + private const string SplusKey = "Uninitialized Web API Server"; + private const string DefaultName = "Web API Server"; private const string DefaultBasePath = "/api"; private const uint DebugTrace = 0; @@ -16,6 +18,9 @@ namespace PepperDash.Core private HttpCwsServer _server; private readonly CCriticalSection _serverLock = new CCriticalSection(); + public string Key { get; private set; } + public string Name { get; private set; } + /// /// CWS base path, will default to "/api" if not set via initialize method /// @@ -29,11 +34,9 @@ namespace PepperDash.Core /// /// Constructor for S+. Make sure to set necessary properties using init method /// - public GenericCwsBase() - : base(SplusKey) - { - CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; + public WebApiServer() + : this(SplusKey, DefaultName, null) + { } /// @@ -41,10 +44,9 @@ namespace PepperDash.Core /// /// /// - public GenericCwsBase(string key, string basePath) - : base(key) + public WebApiServer(string key, string basePath) + : this(key, DefaultName, basePath) { - BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; } /// @@ -53,10 +55,14 @@ namespace PepperDash.Core /// /// /// - public GenericCwsBase(string key, string name, string basePath) - : base(key, name) + public WebApiServer(string key, string name, string basePath) { + Key = key; + Name = string.IsNullOrEmpty(name) ? DefaultName : name; BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; + CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; } /// @@ -148,7 +154,7 @@ namespace PepperDash.Core _server = new HttpCwsServer(BasePath) { - HttpRequestHandler = new CwsDefaultRequestHandler() + HttpRequestHandler = new DefaultRequestRequestHandler() }; IsRegistered = _server.Register(); From 897b1c86e15f65a7a68d1455d893516eabda052d Mon Sep 17 00:00:00 2001 From: jdevito Date: Tue, 24 Jan 2023 11:54:03 -0600 Subject: [PATCH 05/22] fix: rebased on latest development branch, added missing XML comments to resolve warnings in Web classes --- .../RequestHandlers/DefaultRequestRequestHandler.cs | 3 +++ Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs index 38dd6b3..e7545df 100644 --- a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs @@ -2,6 +2,9 @@ namespace PepperDash.Core.Web.RequestHandlers { + /// + /// Web API default request handler + /// public class DefaultRequestRequestHandler : WebApiBaseRequestHandler { /// diff --git a/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs index 6843e25..150e629 100644 --- a/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs +++ b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs @@ -5,6 +5,9 @@ using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Core.Web { + /// + /// Web API server + /// public class WebApiServer : IKeyName { private const string SplusKey = "Uninitialized Web API Server"; @@ -18,7 +21,14 @@ namespace PepperDash.Core.Web private HttpCwsServer _server; private readonly CCriticalSection _serverLock = new CCriticalSection(); + /// + /// Web API server key + /// public string Key { get; private set; } + + /// + /// Web API server name + /// public string Name { get; private set; } /// From 812b49eba41b26537c74c6430a50a27c866a0411 Mon Sep 17 00:00:00 2001 From: jdevito Date: Tue, 17 Jan 2023 09:50:39 -0600 Subject: [PATCH 06/22] feat: added crestron web server (cws) generic base --- .../CrestronWebServer/GenericCwsBase.cs | 266 ++++++++++++++++++ .../RequestHandlerUnknown.cs | 16 ++ .../Pepperdash Core/PepperDash_Core.csproj | 6 + 3 files changed, 288 insertions(+) create mode 100644 Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs create mode 100644 Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs new file mode 100644 index 0000000..9446e6a --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs @@ -0,0 +1,266 @@ +using System; +using Crestron.SimplSharp; +using Crestron.SimplSharp.WebScripting; + +namespace PepperDash.Core +{ + public class GenericCwsBase : Device + { + private const string SplusKey = "Uninitialized CWS Server"; + private const string DefaultBasePath = "/api"; + + private const uint DebugTrace = 0; + private const uint DebugInfo = 1; + private const uint DebugVerbose = 2; + + private HttpCwsServer _server; + private readonly CCriticalSection _serverLock = new CCriticalSection(); + + /// + /// CWS base path, will default to "/api" if not set via initialize method + /// + public string BasePath { get; private set; } + + /// + /// Indicates CWS is registered with base path + /// + public bool IsRegistered { get; private set; } + + /// + /// Constructor for S+. Make sure to set necessary properties using init method + /// + public GenericCwsBase() + : base(SplusKey) + { + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; + CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; + } + + /// + /// Constructor + /// + /// + /// + public GenericCwsBase(string key, string basePath) + : base(key) + { + + BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + } + + /// + /// + /// + /// + /// + /// + public GenericCwsBase(string key, string name, string basePath) + : base(key, name) + { + + BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + } + + /// + /// Program status event handler + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType != eProgramStatusEventType.Stopping) + return; + + Debug.Console(DebugInfo, this, "Program stopping. Disabling Server"); + + Stop(); + } + + /// + /// Ethernet event handler + /// + /// + void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) + { + // Re-enable the server if the link comes back up and the status should be connected + if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp + && IsRegistered) + { + Debug.Console(DebugInfo, this, "Ethernet link up. Starting server"); + + Start(); + } + } + + /// + /// Initializes CWS class + /// + public void Initialize(string key, string basePath) + { + Key = key; + BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + } + + /// + /// Starts CWS instance + /// + public void Start() + { + try + { + _serverLock.Enter(); + + if (_server != null) + { + Debug.Console(DebugInfo, this, "Server has already been started"); + return; + } + + Debug.Console(DebugInfo, this, "Starting server"); + + _server = new HttpCwsServer(BasePath) + { + HttpRequestHandler = new RequestHandlerUnknown() + }; + + IsRegistered = _server.Register(); + } + catch (Exception ex) + { + Debug.Console(DebugInfo, this, "Start Exception Message: {0}", ex.Message); + Debug.Console(DebugVerbose, this, "Start Exception StackTrace: {0}", ex.StackTrace); + if (ex.InnerException != null) + Debug.Console(DebugVerbose, this, "Start Exception InnerException: {0}", ex.InnerException); + } + finally + { + _serverLock.Leave(); + } + } + + /// + /// Stop CWS instance + /// + public void Stop() + { + try + { + _serverLock.Enter(); + + if (_server == null) + { + Debug.Console(DebugInfo, this, "Servier has already been stopped"); + return; + } + + if (_server.Unregister()) + { + IsRegistered = false; + } + + Dispose(true); + } + catch (Exception ex) + { + Debug.Console(DebugInfo, this, "ServerStop Exception Message: {0}", ex.Message); + Debug.Console(DebugVerbose, this, "ServerStop Exception StackTrace: {0}", ex.StackTrace); + if (ex.InnerException != null) + Debug.Console(DebugVerbose, this, "ServerStop Exception InnerException: {0}", ex.InnerException); + } + finally + { + _serverLock.Leave(); + } + } + + /// + /// Received request handler + /// + /// + /// This is here for development and testing + /// + /// + /// + public void ReceivedRequestEventHandler(object sender, HttpCwsRequestEventArgs args) + { + try + { + // TODO [ ] Add logic for received requests + Debug.Console(DebugInfo, this, @"RecieveRequestEventHandler +Method: {0} +Path: {1} +PathInfo: {2} +PhysicalPath: {3} +ContentType: {4} +RawUrl: {5} +Url: {6} +UserAgent: {7} +UserHostAddress: {8} +UserHostName: {9}", + args.Context.Request.HttpMethod, + args.Context.Request.Path, + args.Context.Request.PathInfo, + args.Context.Request.PhysicalPath, + args.Context.Request.ContentType, + args.Context.Request.RawUrl, + args.Context.Request.Url, + args.Context.Request.UserAgent, + args.Context.Request.UserHostAddress, + args.Context.Request.UserHostName); + + } + catch (Exception ex) + { + Debug.Console(DebugInfo, this, "ReceivedRequestEventHandler Exception Message: {0}", ex.Message); + Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception StackTrace: {0}", ex.StackTrace); + if (ex.InnerException != null) + Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException); + } + } + + /// + /// Tracks if CWS is disposed + /// + public bool Disposed + { + get + { + return (_server == null); + } + } + + /// + /// Disposes CWS instance + /// + public void Dispose() + { + Dispose(true); + CrestronEnvironment.GC.SuppressFinalize(this); + } + + /// + /// Disposes CWS instance + /// + /// + protected void Dispose(bool disposing) + { + if (Disposed) + { + Debug.Console(DebugInfo, this, "Server has already been disposed"); + return; + } + + if (!disposing) return; + + if (_server != null) + { + _server.Dispose(); + _server = null; + } + } + + ~GenericCwsBase() + { + Dispose(true); + } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs new file mode 100644 index 0000000..5a2adac --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs @@ -0,0 +1,16 @@ +using Crestron.SimplSharp.WebScripting; + +namespace PepperDash.Core +{ + public class RequestHandlerUnknown : IHttpCwsHandler + { + public void ProcessRequest(HttpCwsContext context) + { + // TODO [ ] Modify unknown request handler + context.Response.StatusCode = 418; + context.Response.StatusDescription = "I'm a teapot"; + context.Response.ContentType = "application/json"; + context.Response.Write(string.Format("{0} {1}", context.Request.HttpMethod, context.Request.RawUrl), true); + } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index 86ae71d..8e49d82 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -51,6 +51,10 @@ False ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll + + False + ..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCWSHelperInterface.dll + False ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll @@ -89,6 +93,8 @@ + + From 6221619400aba612fefb729d7bd44e1c4edf8ec2 Mon Sep 17 00:00:00 2001 From: jdevito Date: Wed, 18 Jan 2023 13:30:27 -0600 Subject: [PATCH 07/22] fix: Added CwsBaseHandler, refactored CwsDefaultRequestHandler --- .../CrestronWebServer/CwsBaseHandler.cs | 149 ++++++++++++++++++ .../CwsDefaultRequestHandler.cs | 106 +++++++++++++ .../CrestronWebServer/GenericCwsBase.cs | 120 ++++++-------- .../RequestHandlerUnknown.cs | 16 -- .../Pepperdash Core/PepperDash_Core.csproj | 5 +- .../PepperDash_Core.csproj.DotSettings | 2 + 6 files changed, 309 insertions(+), 89 deletions(-) create mode 100644 Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs create mode 100644 Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs delete mode 100644 Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs create mode 100644 Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs new file mode 100644 index 0000000..f9e25bf --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs @@ -0,0 +1,149 @@ +using System; +using System.Collections.Generic; +using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; + +namespace PepperDash.Core +{ + /// + /// CWS Base Handler, implements IHttpCwsHandler + /// + public abstract class CwsBaseHandler : IHttpCwsHandler + { + private readonly Dictionary> _handlers; + + /// + /// Constructor + /// + protected CwsBaseHandler() + { + _handlers = new Dictionary> + { + {"CONNECT", HandleConnect}, + {"DELETE", HandleDelete}, + {"GET", HandleGet}, + {"HEAD", HandleHead}, + {"OPTIONS", HandleOptions}, + {"PATCH", HandlePatch}, + {"POST", HandlePost}, + {"PUT", HandlePut}, + {"TRACE", HandleTrace} + }; + } + + /// + /// Handles CONNECT method requests + /// + /// + protected virtual void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected virtual void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected virtual void HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected virtual void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected virtual void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected virtual void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected virtual void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected virtual void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected virtual void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Process request + /// + /// + public void ProcessRequest(HttpCwsContext context) + { + Action handler; + + if (!_handlers.TryGetValue(context.Request.HttpMethod, out handler)) + { + return; + } + + handler(context); + } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs new file mode 100644 index 0000000..3a91114 --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs @@ -0,0 +1,106 @@ +using Crestron.SimplSharp.WebScripting; + +namespace PepperDash.Core +{ + public class CwsDefaultRequestHandler : CwsBaseHandler + { + /// + /// Handles CONNECT method requests + /// + /// + protected override void HandleConnect(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles DELETE method requests + /// + /// + protected override void HandleDelete(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles GET method requests + /// + /// + protected override void HandleGet(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles HEAD method requests + /// + /// + protected override void HandleHead(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles OPTIONS method requests + /// + /// + protected override void HandleOptions(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PATCH method requests + /// + /// + protected override void HandlePatch(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles POST method requests + /// + /// + protected override void HandlePost(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles PUT method requests + /// + /// + protected override void HandlePut(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + + /// + /// Handles TRACE method requests + /// + /// + protected override void HandleTrace(HttpCwsContext context) + { + context.Response.StatusCode = 501; + context.Response.StatusDescription = "Not Implemented"; + context.Response.End(); + } + } +} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs index 9446e6a..0bfbb63 100644 --- a/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs +++ b/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs @@ -44,7 +44,6 @@ namespace PepperDash.Core public GenericCwsBase(string key, string basePath) : base(key) { - BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; } @@ -57,7 +56,6 @@ namespace PepperDash.Core public GenericCwsBase(string key, string name, string basePath) : base(key, name) { - BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; } @@ -67,8 +65,7 @@ namespace PepperDash.Core /// void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) { - if (programEventType != eProgramStatusEventType.Stopping) - return; + if (programEventType != eProgramStatusEventType.Stopping) return; Debug.Console(DebugInfo, this, "Program stopping. Disabling Server"); @@ -82,13 +79,15 @@ namespace PepperDash.Core void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) { // Re-enable the server if the link comes back up and the status should be connected - if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp - && IsRegistered) + if (ethernetEventArgs.EthernetEventType == eEthernetEventType.LinkUp && IsRegistered) { - Debug.Console(DebugInfo, this, "Ethernet link up. Starting server"); - - Start(); + Debug.Console(DebugInfo, this, "Ethernet link up. Server is alreedy registered."); + return; } + + Debug.Console(DebugInfo, this, "Ethernet link up. Starting server"); + + Start(); } /// @@ -97,7 +96,37 @@ namespace PepperDash.Core public void Initialize(string key, string basePath) { Key = key; - BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + } + + /// + /// Adds a route to CWS + /// + public void AddRoute(HttpCwsRoute route) + { + if (route == null) + { + Debug.Console(DebugInfo, this, "Failed to add route, route parameter is null"); + return; + } + + _server.Routes.Add(route); + + } + + /// + /// Removes a route from CWS + /// + /// + public void RemoveRoute(HttpCwsRoute route) + { + if (route == null) + { + Debug.Console(DebugInfo, this, "Failed to remote route, orute parameter is null"); + return; + } + + _server.Routes.Remove(route); } /// @@ -119,7 +148,7 @@ namespace PepperDash.Core _server = new HttpCwsServer(BasePath) { - HttpRequestHandler = new RequestHandlerUnknown() + HttpRequestHandler = new CwsDefaultRequestHandler() }; IsRegistered = _server.Register(); @@ -148,29 +177,26 @@ namespace PepperDash.Core if (_server == null) { - Debug.Console(DebugInfo, this, "Servier has already been stopped"); + Debug.Console(DebugInfo, this, "Server has already been stopped"); return; } - if (_server.Unregister()) - { - IsRegistered = false; - } - - Dispose(true); + IsRegistered = _server.Unregister() == false; + _server.Dispose(); + _server = null; } catch (Exception ex) { - Debug.Console(DebugInfo, this, "ServerStop Exception Message: {0}", ex.Message); - Debug.Console(DebugVerbose, this, "ServerStop Exception StackTrace: {0}", ex.StackTrace); + Debug.Console(DebugInfo, this, "Server Stop Exception Message: {0}", ex.Message); + Debug.Console(DebugVerbose, this, "Server Stop Exception StackTrace: {0}", ex.StackTrace); if (ex.InnerException != null) - Debug.Console(DebugVerbose, this, "ServerStop Exception InnerException: {0}", ex.InnerException); + Debug.Console(DebugVerbose, this, "Server Stop Exception InnerException: {0}", ex.InnerException); } finally { _serverLock.Leave(); } - } + } /// /// Received request handler @@ -184,7 +210,6 @@ namespace PepperDash.Core { try { - // TODO [ ] Add logic for received requests Debug.Console(DebugInfo, this, @"RecieveRequestEventHandler Method: {0} Path: {1} @@ -206,7 +231,6 @@ UserHostName: {9}", args.Context.Request.UserAgent, args.Context.Request.UserHostAddress, args.Context.Request.UserHostName); - } catch (Exception ex) { @@ -215,52 +239,6 @@ UserHostName: {9}", if (ex.InnerException != null) Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException); } - } - - /// - /// Tracks if CWS is disposed - /// - public bool Disposed - { - get - { - return (_server == null); - } - } - - /// - /// Disposes CWS instance - /// - public void Dispose() - { - Dispose(true); - CrestronEnvironment.GC.SuppressFinalize(this); - } - - /// - /// Disposes CWS instance - /// - /// - protected void Dispose(bool disposing) - { - if (Disposed) - { - Debug.Console(DebugInfo, this, "Server has already been disposed"); - return; - } - - if (!disposing) return; - - if (_server != null) - { - _server.Dispose(); - _server = null; - } - } - - ~GenericCwsBase() - { - Dispose(true); - } + } } } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs b/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs deleted file mode 100644 index 5a2adac..0000000 --- a/Pepperdash Core/Pepperdash Core/CrestronWebServer/RequestHandlerUnknown.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Crestron.SimplSharp.WebScripting; - -namespace PepperDash.Core -{ - public class RequestHandlerUnknown : IHttpCwsHandler - { - public void ProcessRequest(HttpCwsContext context) - { - // TODO [ ] Modify unknown request handler - context.Response.StatusCode = 418; - context.Response.StatusDescription = "I'm a teapot"; - context.Response.ContentType = "application/json"; - context.Response.Write(string.Format("{0} {1}", context.Request.HttpMethod, context.Request.RawUrl), true); - } - } -} \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index 8e49d82..55c4a20 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -7,7 +7,7 @@ {87E29B4C-569B-4368-A4ED-984AC1440C96} Library Properties - PepperDash_Core + PepperDash.Core PepperDash_Core {0B4745B0-194B-4BB6-8E21-E9057CA92500};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} WindowsCE @@ -93,8 +93,9 @@ + - + diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings new file mode 100644 index 0000000..8107a4f --- /dev/null +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings @@ -0,0 +1,2 @@ + + True \ No newline at end of file From a56f66230a0b4918bb3df84f069abe107cd253c6 Mon Sep 17 00:00:00 2001 From: jdevito Date: Wed, 18 Jan 2023 15:22:50 -0600 Subject: [PATCH 08/22] refactor: Changed CWS references to WebApi, re-organized Web folder --- .../Pepperdash Core/PepperDash_Core.csproj | 6 ++-- .../PepperDash_Core.csproj.DotSettings | 3 +- .../DefaultRequestRequestHandler.cs} | 4 +-- .../WebApiBaseRequestHandler.cs} | 7 ++-- .../GenericCwsBase.cs => Web/WebApiServer.cs} | 34 +++++++++++-------- 5 files changed, 30 insertions(+), 24 deletions(-) rename Pepperdash Core/Pepperdash Core/{CrestronWebServer/CwsDefaultRequestHandler.cs => Web/RequestHandlers/DefaultRequestRequestHandler.cs} (92%) rename Pepperdash Core/Pepperdash Core/{CrestronWebServer/CwsBaseHandler.cs => Web/RequestHandlers/WebApiBaseRequestHandler.cs} (92%) rename Pepperdash Core/Pepperdash Core/{CrestronWebServer/GenericCwsBase.cs => Web/WebApiServer.cs} (86%) diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index 55c4a20..b4785a2 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -93,9 +93,9 @@ - - - + + + diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings index 8107a4f..8e644b9 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj.DotSettings @@ -1,2 +1,3 @@  - True \ No newline at end of file + True + False \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs similarity index 92% rename from Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs rename to Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs index 3a91114..38dd6b3 100644 --- a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsDefaultRequestHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs @@ -1,8 +1,8 @@ using Crestron.SimplSharp.WebScripting; -namespace PepperDash.Core +namespace PepperDash.Core.Web.RequestHandlers { - public class CwsDefaultRequestHandler : CwsBaseHandler + public class DefaultRequestRequestHandler : WebApiBaseRequestHandler { /// /// Handles CONNECT method requests diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs similarity index 92% rename from Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs rename to Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs index f9e25bf..6d4b41c 100644 --- a/Pepperdash Core/Pepperdash Core/CrestronWebServer/CwsBaseHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs @@ -1,21 +1,20 @@ using System; using System.Collections.Generic; using Crestron.SimplSharp.WebScripting; -using Newtonsoft.Json; -namespace PepperDash.Core +namespace PepperDash.Core.Web.RequestHandlers { /// /// CWS Base Handler, implements IHttpCwsHandler /// - public abstract class CwsBaseHandler : IHttpCwsHandler + public abstract class WebApiBaseRequestHandler : IHttpCwsHandler { private readonly Dictionary> _handlers; /// /// Constructor /// - protected CwsBaseHandler() + protected WebApiBaseRequestHandler() { _handlers = new Dictionary> { diff --git a/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs similarity index 86% rename from Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs rename to Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs index 0bfbb63..6843e25 100644 --- a/Pepperdash Core/Pepperdash Core/CrestronWebServer/GenericCwsBase.cs +++ b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs @@ -1,12 +1,14 @@ using System; using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; +using PepperDash.Core.Web.RequestHandlers; -namespace PepperDash.Core +namespace PepperDash.Core.Web { - public class GenericCwsBase : Device + public class WebApiServer : IKeyName { - private const string SplusKey = "Uninitialized CWS Server"; + private const string SplusKey = "Uninitialized Web API Server"; + private const string DefaultName = "Web API Server"; private const string DefaultBasePath = "/api"; private const uint DebugTrace = 0; @@ -16,6 +18,9 @@ namespace PepperDash.Core private HttpCwsServer _server; private readonly CCriticalSection _serverLock = new CCriticalSection(); + public string Key { get; private set; } + public string Name { get; private set; } + /// /// CWS base path, will default to "/api" if not set via initialize method /// @@ -29,11 +34,9 @@ namespace PepperDash.Core /// /// Constructor for S+. Make sure to set necessary properties using init method /// - public GenericCwsBase() - : base(SplusKey) - { - CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; + public WebApiServer() + : this(SplusKey, DefaultName, null) + { } /// @@ -41,10 +44,9 @@ namespace PepperDash.Core /// /// /// - public GenericCwsBase(string key, string basePath) - : base(key) + public WebApiServer(string key, string basePath) + : this(key, DefaultName, basePath) { - BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; } /// @@ -53,10 +55,14 @@ namespace PepperDash.Core /// /// /// - public GenericCwsBase(string key, string name, string basePath) - : base(key, name) + public WebApiServer(string key, string name, string basePath) { + Key = key; + Name = string.IsNullOrEmpty(name) ? DefaultName : name; BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; + CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; } /// @@ -148,7 +154,7 @@ namespace PepperDash.Core _server = new HttpCwsServer(BasePath) { - HttpRequestHandler = new CwsDefaultRequestHandler() + HttpRequestHandler = new DefaultRequestRequestHandler() }; IsRegistered = _server.Register(); From 5e03ce51c055f82b392455dc1ef15e98f2c83ba4 Mon Sep 17 00:00:00 2001 From: jdevito Date: Tue, 24 Jan 2023 11:54:03 -0600 Subject: [PATCH 09/22] fix: rebased on latest development branch, added missing XML comments to resolve warnings in Web classes --- .../RequestHandlers/DefaultRequestRequestHandler.cs | 3 +++ Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs index 38dd6b3..e7545df 100644 --- a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs @@ -2,6 +2,9 @@ namespace PepperDash.Core.Web.RequestHandlers { + /// + /// Web API default request handler + /// public class DefaultRequestRequestHandler : WebApiBaseRequestHandler { /// diff --git a/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs index 6843e25..150e629 100644 --- a/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs +++ b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs @@ -5,6 +5,9 @@ using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Core.Web { + /// + /// Web API server + /// public class WebApiServer : IKeyName { private const string SplusKey = "Uninitialized Web API Server"; @@ -18,7 +21,14 @@ namespace PepperDash.Core.Web private HttpCwsServer _server; private readonly CCriticalSection _serverLock = new CCriticalSection(); + /// + /// Web API server key + /// public string Key { get; private set; } + + /// + /// Web API server name + /// public string Name { get; private set; } /// From ba930dafaf96ce59d76de9d6b15aa297e69b56e9 Mon Sep 17 00:00:00 2001 From: jdevito Date: Thu, 26 Jan 2023 11:52:31 -0600 Subject: [PATCH 10/22] fix: moved instantiation of server to resolve null ref exception --- .../Pepperdash Core/Web/WebApiServer.cs | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs index 150e629..a3a30c0 100644 --- a/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs +++ b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs @@ -46,7 +46,7 @@ namespace PepperDash.Core.Web /// public WebApiServer() : this(SplusKey, DefaultName, null) - { + { } /// @@ -71,6 +71,8 @@ namespace PepperDash.Core.Web Name = string.IsNullOrEmpty(name) ? DefaultName : name; BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + if (_server == null) _server = new HttpCwsServer(BasePath); + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; } @@ -112,7 +114,7 @@ namespace PepperDash.Core.Web public void Initialize(string key, string basePath) { Key = key; - BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; } /// @@ -127,7 +129,7 @@ namespace PepperDash.Core.Web } _server.Routes.Add(route); - + } /// @@ -154,18 +156,19 @@ namespace PepperDash.Core.Web { _serverLock.Enter(); - if (_server != null) + if (_server == null) + { + Debug.Console(DebugInfo, this, "Server is null, unable to start"); + return; + } + + if (IsRegistered) { Debug.Console(DebugInfo, this, "Server has already been started"); return; } - Debug.Console(DebugInfo, this, "Starting server"); - - _server = new HttpCwsServer(BasePath) - { - HttpRequestHandler = new DefaultRequestRequestHandler() - }; + Debug.Console(DebugInfo, this, "Starting server"); IsRegistered = _server.Register(); } @@ -193,13 +196,13 @@ namespace PepperDash.Core.Web if (_server == null) { - Debug.Console(DebugInfo, this, "Server has already been stopped"); + Debug.Console(DebugInfo, this, "Server is null or has already been stopped"); return; } IsRegistered = _server.Unregister() == false; _server.Dispose(); - _server = null; + _server = null; } catch (Exception ex) { @@ -212,7 +215,7 @@ namespace PepperDash.Core.Web { _serverLock.Leave(); } - } + } /// /// Received request handler @@ -255,6 +258,6 @@ UserHostName: {9}", if (ex.InnerException != null) Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException); } - } + } } } \ No newline at end of file From 627a39e63ad42c28bfea835cfd0cd003cf97d3da Mon Sep 17 00:00:00 2001 From: jdevito Date: Mon, 30 Jan 2023 16:25:23 -0600 Subject: [PATCH 11/22] fix: added GetRouteCollection method, additional refactoring to resolve use of base class --- .../DefaultRequestRequestHandler.cs | 2 +- .../Pepperdash Core/Web/WebApiServer.cs | 75 ++++++++++++------- 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs index e7545df..9db866e 100644 --- a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs @@ -14,7 +14,7 @@ namespace PepperDash.Core.Web.RequestHandlers protected override void HandleConnect(HttpCwsContext context) { context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; + context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } diff --git a/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs index a3a30c0..43efb5b 100644 --- a/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs +++ b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs @@ -1,6 +1,10 @@ using System; +using System.Collections.Generic; +using System.Linq; using Crestron.SimplSharp; using Crestron.SimplSharp.WebScripting; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using PepperDash.Core.Web.RequestHandlers; namespace PepperDash.Core.Web @@ -18,8 +22,8 @@ namespace PepperDash.Core.Web private const uint DebugInfo = 1; private const uint DebugVerbose = 2; - private HttpCwsServer _server; private readonly CCriticalSection _serverLock = new CCriticalSection(); + private HttpCwsServer _server; /// /// Web API server key @@ -41,6 +45,28 @@ namespace PepperDash.Core.Web /// public bool IsRegistered { get; private set; } + /// + /// Http request handler + /// + //public IHttpCwsHandler HttpRequestHandler + //{ + // get { return _server.HttpRequestHandler; } + // set + // { + // if (_server == null) return; + // _server.HttpRequestHandler = value; + // } + //} + + /// + /// Received request event handler + /// + //public event EventHandler ReceivedRequestEvent + //{ + // add { _server.ReceivedRequestEvent += new HttpCwsRequestEventHandler(value); } + // remove { _server.ReceivedRequestEvent -= new HttpCwsRequestEventHandler(value); } + //} + /// /// Constructor for S+. Make sure to set necessary properties using init method /// @@ -60,12 +86,12 @@ namespace PepperDash.Core.Web } /// - /// + /// Constructor /// /// /// /// - public WebApiServer(string key, string name, string basePath) + public WebApiServer(string key, string name, string basePath) { Key = key; Name = string.IsNullOrEmpty(name) ? DefaultName : name; @@ -73,6 +99,9 @@ namespace PepperDash.Core.Web if (_server == null) _server = new HttpCwsServer(BasePath); + _server.setProcessName(Key); + _server.HttpRequestHandler = new DefaultRequestRequestHandler(); + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; } @@ -85,7 +114,7 @@ namespace PepperDash.Core.Web { if (programEventType != eProgramStatusEventType.Stopping) return; - Debug.Console(DebugInfo, this, "Program stopping. Disabling Server"); + Debug.Console(DebugInfo, this, "Program stopping. stopping server"); Stop(); } @@ -147,6 +176,14 @@ namespace PepperDash.Core.Web _server.Routes.Remove(route); } + /// + /// Returns a list of the current routes + /// + public HttpCwsRouteCollection GetRouteCollection() + { + return _server.Routes; + } + /// /// Starts CWS instance /// @@ -168,9 +205,9 @@ namespace PepperDash.Core.Web return; } - Debug.Console(DebugInfo, this, "Starting server"); - IsRegistered = _server.Register(); + + Debug.Console(DebugInfo, this, "Starting server, registration {0}", IsRegistered ? "was successful" : "failed"); } catch (Exception ex) { @@ -201,6 +238,9 @@ namespace PepperDash.Core.Web } IsRegistered = _server.Unregister() == false; + + Debug.Console(DebugInfo, this, "Stopping server, unregistration {0}", IsRegistered ? "failed" : "was successful"); + _server.Dispose(); _server = null; } @@ -229,27 +269,8 @@ namespace PepperDash.Core.Web { try { - Debug.Console(DebugInfo, this, @"RecieveRequestEventHandler -Method: {0} -Path: {1} -PathInfo: {2} -PhysicalPath: {3} -ContentType: {4} -RawUrl: {5} -Url: {6} -UserAgent: {7} -UserHostAddress: {8} -UserHostName: {9}", - args.Context.Request.HttpMethod, - args.Context.Request.Path, - args.Context.Request.PathInfo, - args.Context.Request.PhysicalPath, - args.Context.Request.ContentType, - args.Context.Request.RawUrl, - args.Context.Request.Url, - args.Context.Request.UserAgent, - args.Context.Request.UserHostAddress, - args.Context.Request.UserHostName); + var j = JsonConvert.SerializeObject(args.Context, Formatting.Indented); + Debug.Console(DebugVerbose, this, "RecieveRequestEventHandler Context:\x0d\x0a{0}", j); } catch (Exception ex) { From 56bfbb4bf96fadb58f12d0db2429b4551256ff5d Mon Sep 17 00:00:00 2001 From: jta Date: Tue, 31 Jan 2023 10:37:30 -0500 Subject: [PATCH 12/22] feature: add workflow to push to project --- .github/workflows/add-issues-to-project.yml | 37 +++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/add-issues-to-project.yml diff --git a/.github/workflows/add-issues-to-project.yml b/.github/workflows/add-issues-to-project.yml new file mode 100644 index 0000000..8811c0c --- /dev/null +++ b/.github/workflows/add-issues-to-project.yml @@ -0,0 +1,37 @@ +name: Add bugs to bugs project + +on: + issues: + types: + - opened + - labeled + +jobs: + check-secret: + runs-on: ubuntu-latest + outputs: + my-key: ${{ steps.my-key.outputs.defined }} + steps: + - id: my-key + if: "${{ env.MY_KEY != '' }}" + run: echo "::set-output name=defined::true" + env: + MY_KEY: ${{ secrets.PROJECT_URL }} + throw-error: + name: Check + runs-on: ubuntu-latest + needs: [check-secret] + if: needs.check-secret.outputs.my-key != 'true' + steps: + - run: echo "The Project URL Repo Secret is empty" + add-to-project: + name: Add issue to project + runs-on: ubuntu-latest + needs: [check-secret] + if: needs.check-secret.outputs.my-key == 'true' + steps: + - uses: actions/add-to-project@main + with: + project-url: ${{ secrets.PROJECT_URL }} + github-token: ${{ secrets.GH_PROJECTS_PASSWORD }} + From 71349e67a383562f3e28d99fe704e923420b08f8 Mon Sep 17 00:00:00 2001 From: jdevito Date: Mon, 6 Feb 2023 19:47:45 -0600 Subject: [PATCH 13/22] fix: remove default handler overrides --- .../Pepperdash Core/PepperDash_Core.csproj | 2 +- .../DefaultRequestRequestHandler.cs | 101 +----------------- 2 files changed, 2 insertions(+), 101 deletions(-) diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index b4785a2..510d978 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -93,9 +93,9 @@ + - diff --git a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs index 9db866e..e052eb3 100644 --- a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs @@ -6,104 +6,5 @@ namespace PepperDash.Core.Web.RequestHandlers /// Web API default request handler /// public class DefaultRequestRequestHandler : WebApiBaseRequestHandler - { - /// - /// Handles CONNECT method requests - /// - /// - protected override void HandleConnect(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles DELETE method requests - /// - /// - protected override void HandleDelete(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles GET method requests - /// - /// - protected override void HandleGet(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles HEAD method requests - /// - /// - protected override void HandleHead(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles OPTIONS method requests - /// - /// - protected override void HandleOptions(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles PATCH method requests - /// - /// - protected override void HandlePatch(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles POST method requests - /// - /// - protected override void HandlePost(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles PUT method requests - /// - /// - protected override void HandlePut(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - - /// - /// Handles TRACE method requests - /// - /// - protected override void HandleTrace(HttpCwsContext context) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; - context.Response.End(); - } - } + {} } \ No newline at end of file From 8f47762409e38be535c43a22459e3be57419c2a8 Mon Sep 17 00:00:00 2001 From: jdevito Date: Mon, 20 Feb 2023 15:27:02 -0600 Subject: [PATCH 14/22] fix: add CORS headers to all responses Added EnableCors field,used to enable CORS support. Enabled CORS in default request handler for all requests. --- .../DefaultRequestRequestHandler.cs | 9 ++++++- .../WebApiBaseRequestHandler.cs | 26 ++++++++++++++++--- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs index e052eb3..a2ea2c0 100644 --- a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs @@ -6,5 +6,12 @@ namespace PepperDash.Core.Web.RequestHandlers /// Web API default request handler /// public class DefaultRequestRequestHandler : WebApiBaseRequestHandler - {} + { + /// + /// Constructor + /// + public DefaultRequestRequestHandler() + : base(true) + { } + } } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs index 6d4b41c..22d9d23 100644 --- a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs @@ -14,8 +14,10 @@ namespace PepperDash.Core.Web.RequestHandlers /// /// Constructor /// - protected WebApiBaseRequestHandler() + protected WebApiBaseRequestHandler(bool enableCors) { + EnableCors = enableCors; + _handlers = new Dictionary> { {"CONNECT", HandleConnect}, @@ -30,6 +32,16 @@ namespace PepperDash.Core.Web.RequestHandlers }; } + /// + /// Constructor + /// + protected WebApiBaseRequestHandler() + : this(false) + { + } + + protected readonly bool EnableCors; + /// /// Handles CONNECT method requests /// @@ -37,7 +49,7 @@ namespace PepperDash.Core.Web.RequestHandlers protected virtual void HandleConnect(HttpCwsContext context) { context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; + context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } @@ -48,7 +60,7 @@ namespace PepperDash.Core.Web.RequestHandlers protected virtual void HandleDelete(HttpCwsContext context) { context.Response.StatusCode = 501; - context.Response.StatusDescription = "Not Implemented"; + context.Response.StatusDescription = "Not Implemented"; context.Response.End(); } @@ -142,7 +154,13 @@ namespace PepperDash.Core.Web.RequestHandlers return; } + if (EnableCors) + { + context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); + context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); + } + handler(context); - } + } } } \ No newline at end of file From ca648e6107ea39a322441cb21e141ebe6e473474 Mon Sep 17 00:00:00 2001 From: jdevito Date: Mon, 20 Feb 2023 16:01:32 -0600 Subject: [PATCH 15/22] fix: refactored default request handler to remove redundant reference --- Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj | 2 +- ...aultRequestRequestHandler.cs => DefaultRequestHandler.cs} | 4 ++-- .../Web/RequestHandlers/WebApiBaseRequestHandler.cs | 5 ++--- Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) rename Pepperdash Core/Pepperdash Core/Web/RequestHandlers/{DefaultRequestRequestHandler.cs => DefaultRequestHandler.cs} (65%) diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index 510d978..ec6346d 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -93,7 +93,7 @@ - + diff --git a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestHandler.cs similarity index 65% rename from Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs rename to Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestHandler.cs index a2ea2c0..93cfae0 100644 --- a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestRequestHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/DefaultRequestHandler.cs @@ -5,12 +5,12 @@ namespace PepperDash.Core.Web.RequestHandlers /// /// Web API default request handler /// - public class DefaultRequestRequestHandler : WebApiBaseRequestHandler + public class DefaultRequestHandler : WebApiBaseRequestHandler { /// /// Constructor /// - public DefaultRequestRequestHandler() + public DefaultRequestHandler() : base(true) { } } diff --git a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs index 22d9d23..a73abd1 100644 --- a/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs +++ b/Pepperdash Core/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs @@ -10,6 +10,7 @@ namespace PepperDash.Core.Web.RequestHandlers public abstract class WebApiBaseRequestHandler : IHttpCwsHandler { private readonly Dictionary> _handlers; + protected readonly bool EnableCors; /// /// Constructor @@ -38,9 +39,7 @@ namespace PepperDash.Core.Web.RequestHandlers protected WebApiBaseRequestHandler() : this(false) { - } - - protected readonly bool EnableCors; + } /// /// Handles CONNECT method requests diff --git a/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs index 43efb5b..f2f8464 100644 --- a/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs +++ b/Pepperdash Core/Pepperdash Core/Web/WebApiServer.cs @@ -100,7 +100,7 @@ namespace PepperDash.Core.Web if (_server == null) _server = new HttpCwsServer(BasePath); _server.setProcessName(Key); - _server.HttpRequestHandler = new DefaultRequestRequestHandler(); + _server.HttpRequestHandler = new DefaultRequestHandler(); CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; From 9b56db1cb8b0aa4b9e848077ac9a752013bee9cc Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Wed, 1 Mar 2023 09:35:31 -0700 Subject: [PATCH 16/22] fix: remove isConnecting reference --- Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs | 3 +-- Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs index 4c93278..f9a6ef6 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs @@ -331,8 +331,7 @@ namespace PepperDash.Core KillStream(); if (Client != null) - { - IsConnecting = false; + { Client.Disconnect(); Client = null; ClientStatus = status; diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index ec6346d..ec00542 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -53,7 +53,7 @@ False - ..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCWSHelperInterface.dll + ..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCWSHelperInterface.dll False From 70b09fb6b8ec0eedfdcfc702225f08667f84bfc5 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Fri, 7 Apr 2023 10:13:03 -0600 Subject: [PATCH 17/22] fix: add null check for SSH reconnect timer --- Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs index f9a6ef6..0728cfc 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs @@ -229,7 +229,10 @@ namespace PepperDash.Core Debug.Console(1, this, "Attempting connect"); // Cancel reconnect if running. - ReconnectTimer.Stop(); + if (ReconnectTimer != null) + { + ReconnectTimer.Stop(); + } // Cleanup the old client if it already exists if (Client != null) From f5803fe7c14d1ed0f9bc4ae0f9c138a09ddcfb39 Mon Sep 17 00:00:00 2001 From: Andrew Welker Date: Tue, 15 Aug 2023 09:44:01 -0600 Subject: [PATCH 18/22] chore: trigger build with new Crestron DBs From 751d157f07b9c136d10d1974c848429e1bba65aa Mon Sep 17 00:00:00 2001 From: Nick Genovese Date: Wed, 16 Aug 2023 10:08:06 -0400 Subject: [PATCH 19/22] fix: handles an object disposed ex - the SSH Stream is occasionally disposed, when this happens we catch and recreate the client - removed the line where we set the Timer to null at disconnect, as there is no other place that the timer gets recreated - added try/catch w/ logging in the KillClient method for safety's sake --- .../Pepperdash Core/Comm/GenericSshClient.cs | 112 ++++++++++++------ 1 file changed, 74 insertions(+), 38 deletions(-) diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs index 0728cfc..26da1ef 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs @@ -249,8 +249,6 @@ namespace PepperDash.Core Debug.Console(1, this, "Creating new SshClient"); ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth); Client = new SshClient(connectionInfo); - - Client.ErrorOccurred -= Client_ErrorOccurred; Client.ErrorOccurred += Client_ErrorOccurred; //Attempt to connect @@ -320,7 +318,7 @@ namespace PepperDash.Core if (ReconnectTimer != null) { ReconnectTimer.Stop(); - ReconnectTimer = null; + // ReconnectTimer = null; } KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY); @@ -333,12 +331,21 @@ namespace PepperDash.Core { KillStream(); - if (Client != null) - { - Client.Disconnect(); - Client = null; - ClientStatus = status; - Debug.Console(1, this, "Disconnected"); + try + { + if (Client != null) + { + Client.ErrorOccurred -= Client_ErrorOccurred; + Client.Disconnect(); + Client.Dispose(); + Client = null; + ClientStatus = status; + Debug.Console(1, this, "Disconnected"); + } + } + catch (Exception ex) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception in Kill Client:{0}", ex); } } @@ -375,14 +382,21 @@ namespace PepperDash.Core /// void KillStream() { - if (TheStream != null) - { - TheStream.DataReceived -= Stream_DataReceived; - TheStream.Close(); - TheStream.Dispose(); - TheStream = null; - Debug.Console(1, this, "Disconnected stream"); - } + try + { + if (TheStream != null) + { + TheStream.DataReceived -= Stream_DataReceived; + TheStream.Close(); + TheStream.Dispose(); + TheStream = null; + Debug.Console(1, this, "Disconnected stream"); + } + } + catch (Exception ex) + { + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception in Kill Stream:{0}", ex); + } } /// @@ -473,28 +487,39 @@ namespace PepperDash.Core /// public void SendText(string text) { - try - { - if (Client != null && TheStream != null && IsConnected) - { - if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Sending {0} characters of text: '{1}'", text.Length, ComTextHelper.GetDebugText(text)); + try + { + if (Client != null && TheStream != null && IsConnected) + { + if (StreamDebugging.TxStreamDebuggingIsEnabled) + Debug.Console(0, + this, + "Sending {0} characters of text: '{1}'", + text.Length, + ComTextHelper.GetDebugText(text)); - TheStream.Write(text); - TheStream.Flush(); + TheStream.Write(text); + TheStream.Flush(); + } + else + { + Debug.Console(1, this, "Client is null or disconnected. Cannot Send Text"); + } + } + catch (ObjectDisposedException ex) + { + Debug.Console(0, this, "Exception: {0}", ex.Message); + Debug.Console(0, this, "Stack Trace: {0}", ex.StackTrace); - } - else - { - Debug.Console(1, this, "Client is null or disconnected. Cannot Send Text"); - } - } + KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); + ReconnectTimer.Reset(); + } catch (Exception ex) { - Debug.Console(0, "Exception: {0}", ex.Message); - Debug.Console(0, "Stack Trace: {0}", ex.StackTrace); + Debug.Console(0, this, "Exception: {0}", ex.Message); + Debug.Console(0, this, "Stack Trace: {0}", ex.StackTrace); - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stream write failed. Disconnected, closing"); + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stream write failed"); } } @@ -518,10 +543,21 @@ namespace PepperDash.Core { Debug.Console(1, this, "Client is null or disconnected. Cannot Send Bytes"); } - } - catch - { - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stream write failed. Disconnected, closing"); + } + catch (ObjectDisposedException ex) + { + Debug.Console(0, this, "Exception: {0}", ex.Message); + Debug.Console(0, this, "Stack Trace: {0}", ex.StackTrace); + + KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); + ReconnectTimer.Reset(); + } + catch (Exception ex) + { + Debug.Console(0, this, "Exception: {0}", ex.Message); + Debug.Console(0, this, "Stack Trace: {0}", ex.StackTrace); + + Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stream write failed"); } } From 4f482460614db1c9d5ad209f901eb98714e6d0fb Mon Sep 17 00:00:00 2001 From: Nick Genovese Date: Wed, 23 Aug 2023 14:01:13 -0400 Subject: [PATCH 20/22] fix: cleaned up some debug - in both 'send' methods, print and log the ex message at level 0 - in both 'send' methods, print and log the stack trace at level 1 --- .../Pepperdash Core/Comm/GenericSshClient.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs index 26da1ef..e13c284 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs @@ -508,16 +508,16 @@ namespace PepperDash.Core } catch (ObjectDisposedException ex) { - Debug.Console(0, this, "Exception: {0}", ex.Message); - Debug.Console(0, this, "Stack Trace: {0}", ex.StackTrace); + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace); KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); ReconnectTimer.Reset(); } catch (Exception ex) { - Debug.Console(0, this, "Exception: {0}", ex.Message); - Debug.Console(0, this, "Stack Trace: {0}", ex.StackTrace); + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace); Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stream write failed"); } @@ -546,16 +546,16 @@ namespace PepperDash.Core } catch (ObjectDisposedException ex) { - Debug.Console(0, this, "Exception: {0}", ex.Message); - Debug.Console(0, this, "Stack Trace: {0}", ex.StackTrace); + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace); KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); ReconnectTimer.Reset(); } catch (Exception ex) { - Debug.Console(0, this, "Exception: {0}", ex.Message); - Debug.Console(0, this, "Stack Trace: {0}", ex.StackTrace); + Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message); + Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace); Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stream write failed"); } From 86acb09782e46362982477b9712b3bc4f8f50b70 Mon Sep 17 00:00:00 2001 From: Nick Genovese Date: Thu, 24 Aug 2023 12:36:21 -0400 Subject: [PATCH 21/22] fix: StreamDebugging in default constructor - creates a StreamDebugging class with the default s+ key - this shouldn't matter since in a simpl windows env you can't use console commands anyhow --- Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs index 8cfaad2..024221f 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs @@ -220,7 +220,8 @@ namespace PepperDash.Core /// public GenericTcpIpClient() : base(SplusKey) - { + { + StreamDebugging = new CommunicationStreamDebugging(SplusKey); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; BufferSize = 2000; From 63f6bb9cf2c10c8f765dde9dc85c2972f29bf697 Mon Sep 17 00:00:00 2001 From: jtalborough Date: Mon, 26 Feb 2024 12:58:42 -0500 Subject: [PATCH 22/22] fix: refactor the ssh handeler to use ShellStream.Read() --- .../Pepperdash Core/Comm/GenericSshClient.cs | 51 +++++++++++-------- .../Comm/GenericTcpIpClient.cs | 2 +- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs index e13c284..f27a104 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs @@ -257,6 +257,11 @@ namespace PepperDash.Core { Client.Connect(); TheStream = Client.CreateShellStream("PDTShell", 100, 80, 100, 200, 65534); + if (TheStream.DataAvailable) + { + // empty the buffer if there is data + string str = TheStream.Read(); + } TheStream.DataReceived += Stream_DataReceived; Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Connected"); ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED; @@ -414,29 +419,33 @@ namespace PepperDash.Core /// void Stream_DataReceived(object sender, Crestron.SimplSharp.Ssh.Common.ShellDataEventArgs e) { - var bytes = e.Data; - if (bytes.Length > 0) + if (((ShellStream)sender).Length <= 0L) + { + return; + } + var response = ((ShellStream)sender).Read(); + + var bytesHandler = BytesReceived; + + if (bytesHandler != null) + { + var bytes = Encoding.UTF8.GetBytes(response); + if (StreamDebugging.RxStreamDebuggingIsEnabled) + { + Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); + } + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + } + + var textHandler = TextReceived; + if (textHandler != null) { - var bytesHandler = BytesReceived; - if (bytesHandler != null) - { - if (StreamDebugging.RxStreamDebuggingIsEnabled) - { - Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); - } - bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); - } - - var textHandler = TextReceived; - if (textHandler != null) - { - var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - if (StreamDebugging.RxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Received: '{0}'", ComTextHelper.GetDebugText(str)); + if (StreamDebugging.RxStreamDebuggingIsEnabled) + Debug.Console(0, this, "Received: '{0}'", ComTextHelper.GetDebugText(response)); - textHandler(this, new GenericCommMethodReceiveTextArgs(str)); - } - } + textHandler(this, new GenericCommMethodReceiveTextArgs(response)); + } + } diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs index 024221f..1094fe3 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs @@ -564,4 +564,4 @@ namespace PepperDash.Core } -} +}