diff --git a/._Readme.md b/._Readme.md deleted file mode 100644 index 4a7c548..0000000 Binary files a/._Readme.md and /dev/null differ diff --git a/.github/workflows/EssentialsPlugins-builds-4-series-caller.yml b/.github/workflows/EssentialsPlugins-builds-4-series-caller.yml new file mode 100644 index 0000000..36588bd --- /dev/null +++ b/.github/workflows/EssentialsPlugins-builds-4-series-caller.yml @@ -0,0 +1,21 @@ +name: Build PepperDash Core + +on: + push: + branches: + - '**' + +jobs: + getVersion: + uses: PepperDash/workflow-templates/.github/workflows/essentialsplugins-getversion.yml@main + secrets: inherit + build-4Series: + uses: PepperDash/workflow-templates/.github/workflows/essentialsplugins-4Series-builds.yml@main + secrets: inherit + needs: getVersion + if: needs.getVersion.outputs.newVersion == 'true' + with: + newVersion: ${{ needs.getVersion.outputs.newVersion }} + version: ${{ needs.getVersion.outputs.version }} + tag: ${{ needs.getVersion.outputs.tag }} + channel: ${{ needs.getVersion.outputs.channel }} \ No newline at end of file diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml deleted file mode 100644 index 9f10395..0000000 --- a/.github/workflows/docker.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: Branch Build Using Docker - -on: - push: - branches: - - feature-2/* - - hotfix-2/* - - release-2/* - - development-2 - -env: - # solution path doesn't need slashes unless there it is multiple folders deep - # solution name does not include extension. .sln is assumed - SOLUTION_PATH: . - SOLUTION_FILE: PepperDash Core - # Do not edit this, we're just creating it here - VERSION: 0.0.0-buildtype-buildnumber - # Defaults to debug for build type - BUILD_TYPE: Debug - # Defaults to main as the release branch. Change as necessary - RELEASE_BRANCH: main -jobs: - Build_Project_4-Series: - runs-on: windows-latest - steps: - - uses: actions/checkout@v3 - # Fetch all tags - - name: Fetch tags - run: git fetch --tags - # Generate the appropriate version number - - name: Set Version Number - id: setVersion - shell: powershell - run: | - $latestVersion = [version]"2.0.0" - - $newVersion = [version]$latestVersion - $phase = "" - $newVersionString = "" - - switch -regex ($Env:GITHUB_REF) { - '^refs\/pull\/*.' { - $phase = 'beta'; - $newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER - } - '^refs\/heads\/feature-2\/*.' { - $phase = 'alpha' - $newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER - } - 'development-2' { - $phase = 'beta' - $newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER - } - } - echo "version=$newVersionString" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append - - name: Setup MS Build - uses: microsoft/setup-msbuild@v1.1 - - name: restore Nuget Packages - run: nuget restore .\$($Env:SOLUTION_FILE).sln - # Build the solutions in the docker image - - name: Build Solution - run: msbuild .\$($Env:SOLUTION_FILE).sln /p:Platform="Any CPU" /p:Configuration="Debug" /p:Version="${{ steps.setVersion.outputs.version }}" - - name: Create tag for non-rc builds - if: contains(steps.setVersion.outputs.version, 'alpha') - run: | - git tag ${{ steps.setVersion.outputs.version }} - git push --tags origin - # Create the release on the source repo - - name: Create Release - id: create_release - if: contains(steps.setVersion.outputs.version,'-rc-') || - contains(steps.setVersion.outputs.version,'-hotfix-') || - contains(steps.setVersion.outputs.version, 'beta') - uses: ncipollo/release-action@v1 - with: - artifacts: '**\*.clz' - generateReleaseNotes: true - prerelease: ${{contains('debug', env.BUILD_TYPE)}} - tag: ${{ steps.setVersion.outputs.version }} - - name: Publish to Nuget - run: | - nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }} - nuget setApiKey ${{ secrets.NUGET_API_KEY }} - nuget push ".\package\PepperDashCore.${{ steps.setVersion.outputs.version }}.nupkg" -Source github - nuget push ".\package\PepperDashCore.${{ steps.setVersion.outputs.version }}.nupkg" -Source https://api.nuget.org/v3/index.json \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml deleted file mode 100644 index 25d211b..0000000 --- a/.github/workflows/main.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Main Build using Docker - -on: - release: - types: - - created - branches: - - main-2 -env: - # solution path doesn't need slashes unless there it is multiple folders deep - # solution name does not include extension. .sln is assumed - SOLUTION_PATH: . - SOLUTION_FILE: Pepperdash Core - # Do not edit this, we're just creating it here - VERSION: 0.0.0-buildtype-buildnumber - # Defaults to debug for build type - BUILD_TYPE: Release - # Defaults to main as the release branch. Change as necessary - RELEASE_BRANCH: main -jobs: - Build_Project_4-Series: - runs-on: windows-latest - steps: - # First we checkout the source repo - - name: Checkout repo - uses: actions/checkout@v3 - # Generate the appropriate version number - - name: Set Version Number - shell: powershell - env: - TAG_NAME: ${{ github.event.release.tag_name }} - run: echo "VERSION=$($Env:TAG_NAME)" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append - - name: Setup MS-Build - uses: microsoft/setup-msbuild@v1 - - name: restore Nuget Packages - run: nuget restore .\$($Env:SOLUTION_FILE).sln - - name: Build Solution - run: msbuild .\$($Env:SOLUTION_FILE).sln /p:Platform="Any CPU" /p:Configuration="Release" /p:Version="${{ steps.setVersion.outputs.version }}" - - name: Update Existing Release - id: create_release - uses: ncipollo/release-action@v1 - with: - artifacts: '**\*.clz' - generateReleaseNotes: false - prerelease: false - tag: ${{ github.event.release.tag_name }} - - name: Add nuget.exe - uses: nuget/setup-nuget@v1 - - name: Publish to Nuget - run: | - nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }} - nuget setApiKey ${{ secrets.NUGET_API_KEY }} - nuget push ".\package\PepperDashCore.${{ github.event.release.tag_name }}.nupkg" -Source github - nuget push ".\package\PepperDashCore.${{ github.event.release.tag_name }}.nupkg" -Source https://api.nuget.org/v3/index.json diff --git a/.releaserc.json b/.releaserc.json new file mode 100644 index 0000000..416f7dc --- /dev/null +++ b/.releaserc.json @@ -0,0 +1,36 @@ +{ + "plugins": [ + [ + "@semantic-release/commit-analyzer", + { + "releaseRules": [ + { "scope": "force-patch", "release": "patch" }, + { "scope": "no-release", "release": false } + ] + } + ], + "@semantic-release/release-notes-generator", + ["@semantic-release/changelog", + { + "changelogFile": "CHANGELOG.md" + } + ], + [ + "@semantic-release/exec", + { + "verifyReleaseCmd": "echo \"newVersion=true\" >> $GITHUB_OUTPUT", + "publishCmd": "echo \"version=${nextRelease.version}\" >> $GITHUB_OUTPUT && echo \"tag=${nextRelease.gitTag}\" >> $GITHUB_OUTPUT && echo \"type=${nextRelease.type}\" >> $GITHUB_OUTPUT && echo \"channel=${nextRelease.channel}\" >> $GITHUB_OUTPUT" + } + ] + ], + "branches": [ + "main", + {"name": "development", "prerelease": "beta", "channel": "beta"}, + {"name": "release", "prerelease": "rc", "channel": "rc"}, + { + "name": "replace-me-feature-branch", + "prerelease": "replace-me-prerelease", + "channel": "replace-me-prerelease" + } + ] +} \ No newline at end of file diff --git a/PepperDash Core.sln b/PepperDash Core.sln deleted file mode 100644 index 9ce1b5d..0000000 --- a/PepperDash Core.sln +++ /dev/null @@ -1,25 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.1.32228.430 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash_Core", "src\Pepperdash Core\PepperDash_Core.csproj", "{85BC97D4-5564-4268-8F7B-1532E2DE0456}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {85BC97D4-5564-4268-8F7B-1532E2DE0456}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {85BC97D4-5564-4268-8F7B-1532E2DE0456}.Debug|Any CPU.Build.0 = Debug|Any CPU - {85BC97D4-5564-4268-8F7B-1532E2DE0456}.Release|Any CPU.ActiveCfg = Release|Any CPU - {85BC97D4-5564-4268-8F7B-1532E2DE0456}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {E4615FA3-8C8C-4DC0-897B-E85408B4E341} - EndGlobalSection -EndGlobal diff --git a/src/PepperDash Core.sln b/PepperDash.Core.4Series.sln similarity index 63% rename from src/PepperDash Core.sln rename to PepperDash.Core.4Series.sln index f38b242..2c47107 100644 --- a/src/PepperDash Core.sln +++ b/PepperDash.Core.4Series.sln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.1.32228.430 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PepperDash_Core", "Pepperdash Core\PepperDash_Core.csproj", "{66EB9188-E7AC-410D-AD59-931131DA7C2E}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash.Core.4Series", "src\PepperDash.Core.4Series.csproj", "{100ABA44-9471-4B18-8092-4D94D7D82223}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -11,10 +11,10 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {66EB9188-E7AC-410D-AD59-931131DA7C2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {66EB9188-E7AC-410D-AD59-931131DA7C2E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {66EB9188-E7AC-410D-AD59-931131DA7C2E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {66EB9188-E7AC-410D-AD59-931131DA7C2E}.Release|Any CPU.Build.0 = Release|Any CPU + {100ABA44-9471-4B18-8092-4D94D7D82223}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {100ABA44-9471-4B18-8092-4D94D7D82223}.Debug|Any CPU.Build.0 = Debug|Any CPU + {100ABA44-9471-4B18-8092-4D94D7D82223}.Release|Any CPU.ActiveCfg = Release|Any CPU + {100ABA44-9471-4B18-8092-4D94D7D82223}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/output/PepperDashCore.2.0.0-local.clz b/output/PepperDashCore.2.0.0-local.clz new file mode 100644 index 0000000..c4f7a62 Binary files /dev/null and b/output/PepperDashCore.2.0.0-local.clz differ diff --git a/src/Pepperdash Core/Comm/._GenericSshClient.cs b/src/Comm/._GenericSshClient.cs similarity index 100% rename from src/Pepperdash Core/Comm/._GenericSshClient.cs rename to src/Comm/._GenericSshClient.cs diff --git a/src/Pepperdash Core/Comm/._GenericTcpIpClient.cs b/src/Comm/._GenericTcpIpClient.cs similarity index 100% rename from src/Pepperdash Core/Comm/._GenericTcpIpClient.cs rename to src/Comm/._GenericTcpIpClient.cs diff --git a/src/Pepperdash Core/Comm/CommunicationGather.cs b/src/Comm/CommunicationGather.cs similarity index 100% rename from src/Pepperdash Core/Comm/CommunicationGather.cs rename to src/Comm/CommunicationGather.cs diff --git a/src/Pepperdash Core/Comm/CommunicationStreamDebugging.cs b/src/Comm/CommunicationStreamDebugging.cs similarity index 100% rename from src/Pepperdash Core/Comm/CommunicationStreamDebugging.cs rename to src/Comm/CommunicationStreamDebugging.cs diff --git a/src/Pepperdash Core/Comm/ControlPropertiesConfig.cs b/src/Comm/ControlPropertiesConfig.cs similarity index 100% rename from src/Pepperdash Core/Comm/ControlPropertiesConfig.cs rename to src/Comm/ControlPropertiesConfig.cs diff --git a/src/Pepperdash Core/Comm/DynamicTCPServer.cs b/src/Comm/DynamicTCPServer.cs similarity index 100% rename from src/Pepperdash Core/Comm/DynamicTCPServer.cs rename to src/Comm/DynamicTCPServer.cs diff --git a/src/Pepperdash Core/Comm/EventArgs.cs b/src/Comm/EventArgs.cs similarity index 100% rename from src/Pepperdash Core/Comm/EventArgs.cs rename to src/Comm/EventArgs.cs diff --git a/src/Pepperdash Core/Comm/FINISH CommStatic.cs b/src/Comm/FINISH CommStatic.cs similarity index 100% rename from src/Pepperdash Core/Comm/FINISH CommStatic.cs rename to src/Comm/FINISH CommStatic.cs diff --git a/src/Pepperdash Core/Comm/GenericHttpSseClient.cs b/src/Comm/GenericHttpSseClient.cs similarity index 100% rename from src/Pepperdash Core/Comm/GenericHttpSseClient.cs rename to src/Comm/GenericHttpSseClient.cs diff --git a/src/Pepperdash Core/Comm/GenericSecureTcpIpClient.cs b/src/Comm/GenericSecureTcpIpClient.cs similarity index 100% rename from src/Pepperdash Core/Comm/GenericSecureTcpIpClient.cs rename to src/Comm/GenericSecureTcpIpClient.cs diff --git a/src/Pepperdash Core/Comm/GenericSecureTcpIpClient_ForServer.cs b/src/Comm/GenericSecureTcpIpClient_ForServer.cs similarity index 100% rename from src/Pepperdash Core/Comm/GenericSecureTcpIpClient_ForServer.cs rename to src/Comm/GenericSecureTcpIpClient_ForServer.cs diff --git a/src/Pepperdash Core/Comm/GenericSecureTcpIpServer.cs b/src/Comm/GenericSecureTcpIpServer.cs similarity index 100% rename from src/Pepperdash Core/Comm/GenericSecureTcpIpServer.cs rename to src/Comm/GenericSecureTcpIpServer.cs diff --git a/src/Pepperdash Core/Comm/GenericSshClient.cs b/src/Comm/GenericSshClient.cs similarity index 58% rename from src/Pepperdash Core/Comm/GenericSshClient.cs rename to src/Comm/GenericSshClient.cs index 277b34c..ffe4e38 100644 --- a/src/Pepperdash Core/Comm/GenericSshClient.cs +++ b/src/Comm/GenericSshClient.cs @@ -1,10 +1,12 @@ using System; -using System.Linq; using System.Text; +using System.Threading; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronSockets; -using Crestron.SimplSharp.Ssh; -using Crestron.SimplSharp.Ssh.Common; +using Org.BouncyCastle.Utilities; +using PepperDash.Core.Logging; +using Renci.SshNet; +using Renci.SshNet.Common; namespace PepperDash.Core { @@ -133,7 +135,8 @@ namespace PepperDash.Core CTimer ReconnectTimer; //Lock object to prevent simulatneous connect/disconnect operations - private CCriticalSection connectLock = new CCriticalSection(); + //private CCriticalSection connectLock = new CCriticalSection(); + private SemaphoreSlim connectLock = new SemaphoreSlim(1); private bool DisconnectLogged = false; @@ -144,13 +147,31 @@ namespace PepperDash.Core base(key) { StreamDebugging = new CommunicationStreamDebugging(key); - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - Key = key; - Hostname = hostname; - Port = port; - Username = username; - Password = password; - AutoReconnectIntervalMs = 5000; + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + Key = key; + Hostname = hostname; + Port = port; + Username = username; + Password = password; + AutoReconnectIntervalMs = 5000; + + ReconnectTimer = new CTimer(o => + { + if (ConnectEnabled) + { + Connect(); + } + }, System.Threading.Timeout.Infinite); + } + + /// + /// S+ Constructor - Must set all properties before calling Connect + /// + public GenericSshClient() + : base(SPlusKey) + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + AutoReconnectIntervalMs = 5000; ReconnectTimer = new CTimer(o => { @@ -158,8 +179,8 @@ namespace PepperDash.Core { Connect(); } - }, Timeout.Infinite); - } + }, System.Threading.Timeout.Infinite); + } /// /// S+ Constructor - Must set all properties before calling Connect @@ -170,33 +191,16 @@ namespace PepperDash.Core CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; - ReconnectTimer = new CTimer(o => - { - if (ConnectEnabled) - { - Connect(); - } - }, Timeout.Infinite); - } - - /// - /// Just to help S+ set the key - /// - public void Initialize(string key) - { - Key = key; - } - - /// - /// Handles closing this up when the program shuts down - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) - { - if (programEventType == eProgramStatusEventType.Stopping) - { - if (Client != null) - { - Debug.Console(1, this, "Program stopping. Closing connection"); + /// + /// Handles closing this up when the program shuts down + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) + { + if (Client != null) + { + this.LogDebug("Program stopping. Closing connection"); Disconnect(); } } @@ -211,7 +215,7 @@ namespace PepperDash.Core if (string.IsNullOrEmpty(Hostname) || Port < 1 || Port > 65535 || Username == null || Password == null) { - Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Connect failed. Check hostname, port, username and password are set or not null"); + this.LogError("Connect failed. Check hostname, port, username and password are set or not null"); return; } @@ -219,25 +223,25 @@ namespace PepperDash.Core try { - connectLock.Enter(); + connectLock.Wait(); if (IsConnected) { - Debug.Console(1, this, "Connection already connected. Exiting Connect()"); + this.LogDebug("Connection already connected. Exiting Connect"); } else { - Debug.Console(1, this, "Attempting connect"); + this.LogDebug("Attempting connect"); // Cancel reconnect if running. - if (ReconnectTimer != null) - { - ReconnectTimer.Stop(); - } + if (ReconnectTimer != null) + { + ReconnectTimer.Stop(); + } // Cleanup the old client if it already exists if (Client != null) { - Debug.Console(1, this, "Cleaning up disconnected client"); + this.LogDebug("Cleaning up disconnected client"); KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY); } @@ -246,7 +250,7 @@ namespace PepperDash.Core kauth.AuthenticationPrompt += new EventHandler(kauth_AuthenticationPrompt); PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(Username, Password); - Debug.Console(1, this, "Creating new SshClient"); + this.LogDebug("Creating new SshClient"); ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth); Client = new SshClient(connectionInfo); Client.ErrorOccurred += Client_ErrorOccurred; @@ -263,7 +267,7 @@ namespace PepperDash.Core string str = TheStream.Read(); } TheStream.DataReceived += Stream_DataReceived; - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Connected"); + this.LogInformation("Connected"); ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED; DisconnectLogged = false; } @@ -273,35 +277,52 @@ namespace PepperDash.Core var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error; if (ie is SocketException) - Debug.Console(1, this, errorLogLevel, "'{0}' CONNECTION failure: Cannot reach host, ({1})", Key, ie.Message); - else if (ie is System.Net.Sockets.SocketException) - Debug.Console(1, this, errorLogLevel, "'{0}' Connection failure: Cannot reach host '{1}' on port {2}, ({3})", - Key, Hostname, Port, ie.GetType()); - else if (ie is SshAuthenticationException) { - Debug.Console(1, this, errorLogLevel, "Authentication failure for username '{0}', ({1})", + this.LogException(ie, "CONNECTION failure: Cannot reach host, ({1})", Key, ie.Message); + } + + if (ie is System.Net.Sockets.SocketException socketException) + { + this.LogException(ie, "'{0}' Connection failure: Cannot reach host '{1}' on port {2}, ({3})", + Key, Hostname, Port, ie.GetType()); + } + if (ie is SshAuthenticationException) + { + this.LogException(ie, "Authentication failure for username '{0}', ({1})", this, Username, ie.Message); } else - Debug.Console(1, this, errorLogLevel, "Error on connect:\r({0})", ie.Message); + this.LogException(ie, "Error on connect"); DisconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); if (AutoReconnect) { - Debug.Console(1, this, "Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); + this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); + ReconnectTimer.Reset(AutoReconnectIntervalMs); + } + } + catch(SshOperationTimeoutException ex) + { + this.LogWarning("Connection attempt timed out: {message}", ex.Message); + + DisconnectLogged = true; + KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); + if (AutoReconnect) + { + this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); ReconnectTimer.Reset(AutoReconnectIntervalMs); } } catch (Exception e) { var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error; - Debug.Console(1, this, errorLogLevel, "Unhandled exception on connect:\r({0})", e.Message); + this.LogException(e, "Unhandled exception on connect"); DisconnectLogged = true; KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); if (AutoReconnect) { - Debug.Console(1, this, "Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); + this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); ReconnectTimer.Reset(AutoReconnectIntervalMs); } } @@ -309,22 +330,22 @@ namespace PepperDash.Core } finally { - connectLock.Leave(); + connectLock.Release(); } } - /// - /// Disconnect the clients and put away it's resources. - /// - public void Disconnect() - { - ConnectEnabled = false; - // Stop trying reconnects, if we are - if (ReconnectTimer != null) - { - ReconnectTimer.Stop(); - // ReconnectTimer = null; - } + /// + /// Disconnect the clients and put away it's resources. + /// + public void Disconnect() + { + ConnectEnabled = false; + // Stop trying reconnects, if we are + if (ReconnectTimer != null) + { + ReconnectTimer.Stop(); + // ReconnectTimer = null; + } KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY); } @@ -345,40 +366,12 @@ namespace PepperDash.Core Client.Dispose(); Client = null; ClientStatus = status; - Debug.Console(1, this, "Disconnected"); + this.LogDebug("Disconnected"); } } catch (Exception ex) { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception in Kill Client:{0}", ex); - } - } - - /// - /// Anything to do with reestablishing connection on failures - /// - void HandleConnectionFailure() - { - KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); - - Debug.Console(1, this, "Client nulled due to connection failure. AutoReconnect: {0}, ConnectEnabled: {1}", AutoReconnect, ConnectEnabled); - if (AutoReconnect && ConnectEnabled) - { - Debug.Console(1, this, "Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); - if (ReconnectTimer == null) - { - ReconnectTimer = new CTimer(o => - { - Connect(); - }, AutoReconnectIntervalMs); - Debug.Console(1, this, "Attempting connection in {0} seconds", - (float)(AutoReconnectIntervalMs / 1000)); - } - else - { - Debug.Console(1, this, "{0} second reconnect cycle running", - (float)(AutoReconnectIntervalMs / 1000)); - } + this.LogException(ex,"Exception in Kill Client"); } } @@ -386,7 +379,7 @@ namespace PepperDash.Core /// Kills the stream /// void KillStream() - { + { try { if (TheStream != null) @@ -395,85 +388,84 @@ namespace PepperDash.Core TheStream.Close(); TheStream.Dispose(); TheStream = null; - Debug.Console(1, this, "Disconnected stream"); + this.LogDebug("Disconnected stream"); } } catch (Exception ex) { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception in Kill Stream:{0}", ex); + this.LogException(ex, "Exception in Kill Stream:{0}"); } - } + } - /// - /// Handles the keyboard interactive authentication, should it be required. - /// - void kauth_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e) - { - foreach (AuthenticationPrompt prompt in e.Prompts) - if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1) - prompt.Response = Password; - } - - /// - /// Handler for data receive on ShellStream. Passes data across to queue for line parsing. - /// - void Stream_DataReceived(object sender, Crestron.SimplSharp.Ssh.Common.ShellDataEventArgs e) - { + /// + /// Handles the keyboard interactive authentication, should it be required. + /// + void kauth_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e) + { + foreach (AuthenticationPrompt prompt in e.Prompts) + if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1) + prompt.Response = Password; + } + + /// + /// Handler for data receive on ShellStream. Passes data across to queue for line parsing. + /// + void Stream_DataReceived(object sender, ShellDataEventArgs e) + { if (((ShellStream)sender).Length <= 0L) { return; } - var response = ((ShellStream)sender).Read(); - - var bytesHandler = BytesReceived; - - if (bytesHandler != null) - { + 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); - } + if (StreamDebugging.RxStreamDebuggingIsEnabled) + { + this.LogInformation("Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length); + } bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); - } - - var textHandler = TextReceived; - if (textHandler != null) - { + } + + var textHandler = TextReceived; + if (textHandler != null) + { if (StreamDebugging.RxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Received: '{0}'", ComTextHelper.GetDebugText(response)); + this.LogInformation("Received: '{0}'", ComTextHelper.GetDebugText(response)); textHandler(this, new GenericCommMethodReceiveTextArgs(response)); } - - } + + } - /// - /// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange - /// event - /// - void Client_ErrorOccurred(object sender, Crestron.SimplSharp.Ssh.Common.ExceptionEventArgs e) - { + /// + /// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange + /// event + /// + void Client_ErrorOccurred(object sender, ExceptionEventArgs e) + { CrestronInvoke.BeginInvoke(o => { if (e.Exception is SshConnectionException || e.Exception is System.Net.Sockets.SocketException) - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Disconnected by remote"); + this.LogError("Disconnected by remote"); else - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Unhandled SSH client error: {0}", e.Exception); - + this.LogException(e.Exception, "Unhandled SSH client error"); try { - connectLock.Enter(); + connectLock.Wait(); KillClient(SocketStatus.SOCKET_STATUS_BROKEN_REMOTELY); } finally { - connectLock.Leave(); + connectLock.Release(); } if (AutoReconnect && ConnectEnabled) { - Debug.Console(1, this, "Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); + this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs); ReconnectTimer.Reset(AutoReconnectIntervalMs); } }); @@ -490,96 +482,87 @@ namespace PepperDash.Core #region IBasicCommunication Members - /// - /// Sends text to the server - /// - /// - 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)); + /// + /// Sends text to the server + /// + /// + public void SendText(string text) + { + try + { + if (Client != null && TheStream != null && IsConnected) + { + if (StreamDebugging.TxStreamDebuggingIsEnabled) + this.LogInformation( + "Sending {length} characters of text: '{text}'", + text.Length, + ComTextHelper.GetDebugText(text)); - TheStream.Write(text); - TheStream.Flush(); - } - else - { - Debug.Console(1, this, "Client is null or disconnected. Cannot Send Text"); - } - } - catch (ObjectDisposedException ex) + TheStream.Write(text); + TheStream.Flush(); + } + else + { + this.LogDebug("Client is null or disconnected. Cannot Send Text"); + } + } + catch (ObjectDisposedException ex) { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message); - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace); + this.LogException(ex, "ObjectDisposedException sending {message}", text); KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); ReconnectTimer.Reset(); - } - catch (Exception ex) - { - 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"); - } - } + } + catch (Exception ex) + { + this.LogException(ex, "Exception sending text: {message}", text); + } + } /// /// Sends Bytes to the server /// /// public void SendBytes(byte[] bytes) - { + { try { if (Client != null && TheStream != null && IsConnected) { if (StreamDebugging.TxStreamDebuggingIsEnabled) - Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + this.LogInformation("Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); TheStream.Write(bytes, 0, bytes.Length); TheStream.Flush(); } else { - Debug.Console(1, this, "Client is null or disconnected. Cannot Send Bytes"); + this.LogDebug("Client is null or disconnected. Cannot Send Bytes"); } } catch (ObjectDisposedException ex) { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message); - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace); + this.LogException(ex, "ObjectDisposedException sending {message}", ComTextHelper.GetEscapedText(bytes)); KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED); ReconnectTimer.Reset(); } catch (Exception ex) { - Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message); - Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace); + this.LogException(ex, "Exception sending {message}", ComTextHelper.GetEscapedText(bytes)); + } + } + #endregion - Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stream write failed"); - } - } +} - #endregion - } - - //***************************************************************************************************** - //***************************************************************************************************** - /// - /// Fired when connection changes - /// - public class SshConnectionChangeEventArgs : EventArgs - { +//***************************************************************************************************** +//***************************************************************************************************** +/// +/// Fired when connection changes +/// +public class SshConnectionChangeEventArgs : EventArgs + { /// /// Connection State /// diff --git a/src/Pepperdash Core/Comm/GenericTcpIpClient.cs b/src/Comm/GenericTcpIpClient.cs similarity index 99% rename from src/Pepperdash Core/Comm/GenericTcpIpClient.cs rename to src/Comm/GenericTcpIpClient.cs index e5f53b9..9529aa2 100644 --- a/src/Pepperdash Core/Comm/GenericTcpIpClient.cs +++ b/src/Comm/GenericTcpIpClient.cs @@ -219,7 +219,8 @@ namespace PepperDash.Core /// public GenericTcpIpClient() : base(SplusKey) - { + { + StreamDebugging = new CommunicationStreamDebugging(SplusKey); CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); AutoReconnectIntervalMs = 5000; BufferSize = 2000; diff --git a/src/Pepperdash Core/Comm/GenericTcpIpClient_ForServer.cs b/src/Comm/GenericTcpIpClient_ForServer.cs similarity index 100% rename from src/Pepperdash Core/Comm/GenericTcpIpClient_ForServer.cs rename to src/Comm/GenericTcpIpClient_ForServer.cs diff --git a/src/Pepperdash Core/Comm/GenericTcpIpServer.cs b/src/Comm/GenericTcpIpServer.cs similarity index 100% rename from src/Pepperdash Core/Comm/GenericTcpIpServer.cs rename to src/Comm/GenericTcpIpServer.cs diff --git a/src/Pepperdash Core/Comm/GenericUdpServer.cs b/src/Comm/GenericUdpServer.cs similarity index 100% rename from src/Pepperdash Core/Comm/GenericUdpServer.cs rename to src/Comm/GenericUdpServer.cs diff --git a/src/Pepperdash Core/Comm/QscCoreDoubleTcpIpClient.cs b/src/Comm/QscCoreDoubleTcpIpClient.cs similarity index 100% rename from src/Pepperdash Core/Comm/QscCoreDoubleTcpIpClient.cs rename to src/Comm/QscCoreDoubleTcpIpClient.cs diff --git a/src/Pepperdash Core/Comm/TcpClientConfigObject.cs b/src/Comm/TcpClientConfigObject.cs similarity index 100% rename from src/Pepperdash Core/Comm/TcpClientConfigObject.cs rename to src/Comm/TcpClientConfigObject.cs diff --git a/src/Pepperdash Core/Comm/TcpServerConfigObject.cs b/src/Comm/TcpServerConfigObject.cs similarity index 100% rename from src/Pepperdash Core/Comm/TcpServerConfigObject.cs rename to src/Comm/TcpServerConfigObject.cs diff --git a/src/Pepperdash Core/Comm/eControlMethods.cs b/src/Comm/eControlMethods.cs similarity index 100% rename from src/Pepperdash Core/Comm/eControlMethods.cs rename to src/Comm/eControlMethods.cs diff --git a/src/Pepperdash Core/CommunicationExtras.cs b/src/CommunicationExtras.cs similarity index 100% rename from src/Pepperdash Core/CommunicationExtras.cs rename to src/CommunicationExtras.cs diff --git a/src/Pepperdash Core/Config/PortalConfigReader.cs b/src/Config/PortalConfigReader.cs similarity index 100% rename from src/Pepperdash Core/Config/PortalConfigReader.cs rename to src/Config/PortalConfigReader.cs diff --git a/src/Pepperdash Core/Conversion/Convert.cs b/src/Conversion/Convert.cs similarity index 100% rename from src/Pepperdash Core/Conversion/Convert.cs rename to src/Conversion/Convert.cs diff --git a/src/Pepperdash Core/CoreInterfaces.cs b/src/CoreInterfaces.cs similarity index 100% rename from src/Pepperdash Core/CoreInterfaces.cs rename to src/CoreInterfaces.cs diff --git a/src/Pepperdash Core/Device.cs b/src/Device.cs similarity index 100% rename from src/Pepperdash Core/Device.cs rename to src/Device.cs diff --git a/src/Directory.build.props b/src/Directory.build.props new file mode 100644 index 0000000..196b6a0 --- /dev/null +++ b/src/Directory.build.props @@ -0,0 +1,19 @@ + + + 2.0.0-local + PepperDash Technologies + PepperDash Technologies + PepperDash Essentials + Copyright © 2025 + git + Crestron; 4series + ../output + True + LICENSE.md + README.md + + + + + + \ No newline at end of file diff --git a/src/Directory.build.targets b/src/Directory.build.targets new file mode 100644 index 0000000..0ef185c --- /dev/null +++ b/src/Directory.build.targets @@ -0,0 +1,43 @@ + + + + true + content; + + + true + content; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + doNotUse + + + + \ No newline at end of file diff --git a/src/EssentialsPlugins-builds-4-series-caller.yml b/src/EssentialsPlugins-builds-4-series-caller.yml new file mode 100644 index 0000000..c4b4d2c --- /dev/null +++ b/src/EssentialsPlugins-builds-4-series-caller.yml @@ -0,0 +1,21 @@ +name: Build Essentials Plugin + +on: + push: + branches: + - '**' + +jobs: + getVersion: + uses: PepperDash/workflow-templates/.github/workflows/essentialsplugins-getversion.yml@main + secrets: inherit + build-4Series: + uses: PepperDash/workflow-templates/.github/workflows/essentialsplugins-4Series-builds.yml@main + secrets: inherit + needs: getVersion + if: needs.getVersion.outputs.newVersion == 'true' + with: + newVersion: ${{ needs.getVersion.outputs.newVersion }} + version: ${{ needs.getVersion.outputs.version }} + tag: ${{ needs.getVersion.outputs.tag }} + channel: ${{ needs.getVersion.outputs.channel }} \ No newline at end of file diff --git a/src/Pepperdash Core/EthernetHelper.cs b/src/EthernetHelper.cs similarity index 100% rename from src/Pepperdash Core/EthernetHelper.cs rename to src/EthernetHelper.cs diff --git a/src/Pepperdash Core/EventArgs.cs b/src/EventArgs.cs similarity index 100% rename from src/Pepperdash Core/EventArgs.cs rename to src/EventArgs.cs diff --git a/src/Pepperdash Core/GenericRESTfulCommunications/Constants.cs b/src/GenericRESTfulCommunications/Constants.cs similarity index 100% rename from src/Pepperdash Core/GenericRESTfulCommunications/Constants.cs rename to src/GenericRESTfulCommunications/Constants.cs diff --git a/src/Pepperdash Core/GenericRESTfulCommunications/GenericRESTfulClient.cs b/src/GenericRESTfulCommunications/GenericRESTfulClient.cs similarity index 100% rename from src/Pepperdash Core/GenericRESTfulCommunications/GenericRESTfulClient.cs rename to src/GenericRESTfulCommunications/GenericRESTfulClient.cs diff --git a/src/Pepperdash Core/JsonStandardObjects/EventArgs and Constants.cs b/src/JsonStandardObjects/EventArgs and Constants.cs similarity index 100% rename from src/Pepperdash Core/JsonStandardObjects/EventArgs and Constants.cs rename to src/JsonStandardObjects/EventArgs and Constants.cs diff --git a/src/Pepperdash Core/JsonStandardObjects/JsonToSimplDevice.cs b/src/JsonStandardObjects/JsonToSimplDevice.cs similarity index 100% rename from src/Pepperdash Core/JsonStandardObjects/JsonToSimplDevice.cs rename to src/JsonStandardObjects/JsonToSimplDevice.cs diff --git a/src/Pepperdash Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs b/src/JsonStandardObjects/JsonToSimplDeviceConfig.cs similarity index 100% rename from src/Pepperdash Core/JsonStandardObjects/JsonToSimplDeviceConfig.cs rename to src/JsonStandardObjects/JsonToSimplDeviceConfig.cs diff --git a/src/Pepperdash Core/JsonToSimpl/Constants.cs b/src/JsonToSimpl/Constants.cs similarity index 100% rename from src/Pepperdash Core/JsonToSimpl/Constants.cs rename to src/JsonToSimpl/Constants.cs diff --git a/src/Pepperdash Core/JsonToSimpl/Global.cs b/src/JsonToSimpl/Global.cs similarity index 100% rename from src/Pepperdash Core/JsonToSimpl/Global.cs rename to src/JsonToSimpl/Global.cs diff --git a/src/Pepperdash Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs b/src/JsonToSimpl/JsonToSimplArrayLookupChild.cs similarity index 100% rename from src/Pepperdash Core/JsonToSimpl/JsonToSimplArrayLookupChild.cs rename to src/JsonToSimpl/JsonToSimplArrayLookupChild.cs diff --git a/src/Pepperdash Core/JsonToSimpl/JsonToSimplChildObjectBase.cs b/src/JsonToSimpl/JsonToSimplChildObjectBase.cs similarity index 100% rename from src/Pepperdash Core/JsonToSimpl/JsonToSimplChildObjectBase.cs rename to src/JsonToSimpl/JsonToSimplChildObjectBase.cs diff --git a/src/Pepperdash Core/JsonToSimpl/JsonToSimplFileMaster.cs b/src/JsonToSimpl/JsonToSimplFileMaster.cs similarity index 100% rename from src/Pepperdash Core/JsonToSimpl/JsonToSimplFileMaster.cs rename to src/JsonToSimpl/JsonToSimplFileMaster.cs diff --git a/src/Pepperdash Core/JsonToSimpl/JsonToSimplFixedPathObject.cs b/src/JsonToSimpl/JsonToSimplFixedPathObject.cs similarity index 100% rename from src/Pepperdash Core/JsonToSimpl/JsonToSimplFixedPathObject.cs rename to src/JsonToSimpl/JsonToSimplFixedPathObject.cs diff --git a/src/Pepperdash Core/JsonToSimpl/JsonToSimplGenericMaster.cs b/src/JsonToSimpl/JsonToSimplGenericMaster.cs similarity index 100% rename from src/Pepperdash Core/JsonToSimpl/JsonToSimplGenericMaster.cs rename to src/JsonToSimpl/JsonToSimplGenericMaster.cs diff --git a/src/Pepperdash Core/JsonToSimpl/JsonToSimplMaster.cs b/src/JsonToSimpl/JsonToSimplMaster.cs similarity index 92% rename from src/Pepperdash Core/JsonToSimpl/JsonToSimplMaster.cs rename to src/JsonToSimpl/JsonToSimplMaster.cs index d531d18..2f872e4 100644 --- a/src/Pepperdash Core/JsonToSimpl/JsonToSimplMaster.cs +++ b/src/JsonToSimpl/JsonToSimplMaster.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Collections.Generic; +using System.IO; using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json; @@ -159,7 +160,11 @@ namespace PepperDash.Core.JsonToSimpl /// public static JObject ParseObject(string json) { - using (var reader = new JsonTextReader(new StringReader(json))) + #if NET6_0 + using (var reader = new JsonTextReader(new System.IO.StringReader(json))) +#else + using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.StringReader(json))) +#endif { var startDepth = reader.Depth; var obj = JObject.Load(reader); @@ -176,7 +181,11 @@ namespace PepperDash.Core.JsonToSimpl /// public static JArray ParseArray(string json) { - using (var reader = new JsonTextReader(new StringReader(json))) + #if NET6_0 + using (var reader = new JsonTextReader(new System.IO.StringReader(json))) +#else + using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.StringReader(json))) +#endif { var startDepth = reader.Depth; var obj = JArray.Load(reader); diff --git a/src/Pepperdash Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs b/src/JsonToSimpl/JsonToSimplPortalFileMaster.cs similarity index 100% rename from src/Pepperdash Core/JsonToSimpl/JsonToSimplPortalFileMaster.cs rename to src/JsonToSimpl/JsonToSimplPortalFileMaster.cs diff --git a/src/Pepperdash Core/Logging/CrestronEnricher.cs b/src/Logging/CrestronEnricher.cs similarity index 100% rename from src/Pepperdash Core/Logging/CrestronEnricher.cs rename to src/Logging/CrestronEnricher.cs diff --git a/src/Pepperdash Core/Logging/Debug.cs b/src/Logging/Debug.cs similarity index 100% rename from src/Pepperdash Core/Logging/Debug.cs rename to src/Logging/Debug.cs diff --git a/src/Pepperdash Core/Logging/DebugConsoleSink.cs b/src/Logging/DebugConsoleSink.cs similarity index 100% rename from src/Pepperdash Core/Logging/DebugConsoleSink.cs rename to src/Logging/DebugConsoleSink.cs diff --git a/src/Pepperdash Core/Logging/DebugContext.cs b/src/Logging/DebugContext.cs similarity index 100% rename from src/Pepperdash Core/Logging/DebugContext.cs rename to src/Logging/DebugContext.cs diff --git a/src/Pepperdash Core/Logging/DebugCrestronLoggerSink.cs b/src/Logging/DebugCrestronLoggerSink.cs similarity index 100% rename from src/Pepperdash Core/Logging/DebugCrestronLoggerSink.cs rename to src/Logging/DebugCrestronLoggerSink.cs diff --git a/src/Pepperdash Core/Logging/DebugErrorLogSink.cs b/src/Logging/DebugErrorLogSink.cs similarity index 100% rename from src/Pepperdash Core/Logging/DebugErrorLogSink.cs rename to src/Logging/DebugErrorLogSink.cs diff --git a/src/Pepperdash Core/Logging/DebugExtensions.cs b/src/Logging/DebugExtensions.cs similarity index 86% rename from src/Pepperdash Core/Logging/DebugExtensions.cs rename to src/Logging/DebugExtensions.cs index e37e6d9..68e9868 100644 --- a/src/Pepperdash Core/Logging/DebugExtensions.cs +++ b/src/Logging/DebugExtensions.cs @@ -1,11 +1,16 @@ using Serilog; using Serilog.Events; +using System; using Log = PepperDash.Core.Debug; namespace PepperDash.Core.Logging { public static class DebugExtensions { + public static void LogException(this IKeyed device, Exception ex, string message, params object[] args) + { + Log.LogMessage(ex, message, device, args); + } public static void LogVerbose(this IKeyed device, string message, params object[] args) { Log.LogMessage(LogEventLevel.Verbose, device, message, args); diff --git a/src/Pepperdash Core/Logging/DebugMemory.cs b/src/Logging/DebugMemory.cs similarity index 100% rename from src/Pepperdash Core/Logging/DebugMemory.cs rename to src/Logging/DebugMemory.cs diff --git a/src/Pepperdash Core/Logging/DebugWebsocketSink.cs b/src/Logging/DebugWebsocketSink.cs similarity index 100% rename from src/Pepperdash Core/Logging/DebugWebsocketSink.cs rename to src/Logging/DebugWebsocketSink.cs diff --git a/src/Pepperdash Core/Network/DiscoveryThings.cs b/src/Network/DiscoveryThings.cs similarity index 100% rename from src/Pepperdash Core/Network/DiscoveryThings.cs rename to src/Network/DiscoveryThings.cs diff --git a/src/Pepperdash Core/PasswordManagement/Config.cs b/src/PasswordManagement/Config.cs similarity index 100% rename from src/Pepperdash Core/PasswordManagement/Config.cs rename to src/PasswordManagement/Config.cs diff --git a/src/Pepperdash Core/PasswordManagement/Constants.cs b/src/PasswordManagement/Constants.cs similarity index 100% rename from src/Pepperdash Core/PasswordManagement/Constants.cs rename to src/PasswordManagement/Constants.cs diff --git a/src/Pepperdash Core/PasswordManagement/OLD-ARRAY-Config.cs b/src/PasswordManagement/OLD-ARRAY-Config.cs similarity index 100% rename from src/Pepperdash Core/PasswordManagement/OLD-ARRAY-Config.cs rename to src/PasswordManagement/OLD-ARRAY-Config.cs diff --git a/src/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordClient.cs b/src/PasswordManagement/OLD-ARRAY-PasswordClient.cs similarity index 100% rename from src/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordClient.cs rename to src/PasswordManagement/OLD-ARRAY-PasswordClient.cs diff --git a/src/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordManager.cs b/src/PasswordManagement/OLD-ARRAY-PasswordManager.cs similarity index 100% rename from src/Pepperdash Core/PasswordManagement/OLD-ARRAY-PasswordManager.cs rename to src/PasswordManagement/OLD-ARRAY-PasswordManager.cs diff --git a/src/Pepperdash Core/PasswordManagement/PasswordClient.cs b/src/PasswordManagement/PasswordClient.cs similarity index 100% rename from src/Pepperdash Core/PasswordManagement/PasswordClient.cs rename to src/PasswordManagement/PasswordClient.cs diff --git a/src/Pepperdash Core/PasswordManagement/PasswordManager.cs b/src/PasswordManagement/PasswordManager.cs similarity index 100% rename from src/Pepperdash Core/PasswordManagement/PasswordManager.cs rename to src/PasswordManagement/PasswordManager.cs diff --git a/src/Pepperdash Core/PepperDash_Core.csproj b/src/PepperDash.Core.4Series.csproj similarity index 83% rename from src/Pepperdash Core/PepperDash_Core.csproj rename to src/PepperDash.Core.4Series.csproj index f00b2e3..bbc7f11 100644 --- a/src/Pepperdash Core/PepperDash_Core.csproj +++ b/src/PepperDash.Core.4Series.csproj @@ -2,7 +2,7 @@ PepperDash.Core PepperDashCore - net472;net6 + net472 true en bin\$(Configuration)\ @@ -12,11 +12,9 @@ PepperDash Technologies git https://github.com/PepperDash/PepperDashCore - crestron;4series; - 2.0.0-local - $(Version) - false - ../../package + crestron;4series; + false + $(Version) true @@ -41,15 +39,19 @@ - - + + + + + + diff --git a/src/Pepperdash Core/PepperDash_Core.projectinfo b/src/Pepperdash Core/PepperDash_Core.projectinfo deleted file mode 100644 index ded18d3..0000000 Binary files a/src/Pepperdash Core/PepperDash_Core.projectinfo and /dev/null differ diff --git a/src/Pepperdash Core/Web/RequestHandlers/DefaultRequestHandler.cs b/src/Pepperdash Core/Web/RequestHandlers/DefaultRequestHandler.cs deleted file mode 100644 index 57fa1de..0000000 --- a/src/Pepperdash Core/Web/RequestHandlers/DefaultRequestHandler.cs +++ /dev/null @@ -1,16 +0,0 @@ - -namespace PepperDash.Core.Web.RequestHandlers -{ - /// - /// Web API default request handler - /// - public class DefaultRequestHandler : WebApiBaseRequestHandler - { - /// - /// Constructor - /// - public DefaultRequestHandler() - : base(true) - { } - } -} diff --git a/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs b/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs deleted file mode 100644 index caa6a7c..0000000 --- a/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestHandler.cs +++ /dev/null @@ -1,165 +0,0 @@ -using System; -using System.Collections.Generic; -using Crestron.SimplSharp.WebScripting; - -namespace PepperDash.Core.Web.RequestHandlers -{ - /// - /// CWS Base Handler, implements IHttpCwsHandler - /// - public abstract class WebApiBaseRequestHandler : IHttpCwsHandler - { - private readonly Dictionary> _handlers; - protected readonly bool EnableCors; - - /// - /// Constructor - /// - protected WebApiBaseRequestHandler(bool enableCors) - { - EnableCors = enableCors; - - _handlers = new Dictionary> - { - {"CONNECT", HandleConnect}, - {"DELETE", HandleDelete}, - {"GET", HandleGet}, - {"HEAD", HandleHead}, - {"OPTIONS", HandleOptions}, - {"PATCH", HandlePatch}, - {"POST", HandlePost}, - {"PUT", HandlePut}, - {"TRACE", HandleTrace} - }; - } - - /// - /// Constructor - /// - protected WebApiBaseRequestHandler() - : this(false) - { - } - - /// - /// 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; - } - - 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 diff --git a/src/Pepperdash Core/Web/WebApiServer.cs b/src/Pepperdash Core/Web/WebApiServer.cs deleted file mode 100644 index 17c737a..0000000 --- a/src/Pepperdash Core/Web/WebApiServer.cs +++ /dev/null @@ -1,284 +0,0 @@ -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 -{ - /// - /// Web API server - /// - public class WebApiServer : IKeyName - { - 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; - private const uint DebugInfo = 1; - private const uint DebugVerbose = 2; - - private readonly CCriticalSection _serverLock = new CCriticalSection(); - private HttpCwsServer _server; - - /// - /// Web API server key - /// - public string Key { get; private set; } - - /// - /// Web API server name - /// - public string Name { get; private set; } - - /// - /// 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; } - - /// - /// 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 - /// - public WebApiServer() - : this(SplusKey, DefaultName, null) - { - } - - /// - /// Constructor - /// - /// - /// - public WebApiServer(string key, string basePath) - : this(key, DefaultName, basePath) - { - } - - /// - /// Constructor - /// - /// - /// - /// - public WebApiServer(string key, string name, string basePath) - { - Key = key; - Name = string.IsNullOrEmpty(name) ? DefaultName : name; - BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; - - if (_server == null) _server = new HttpCwsServer(BasePath); - - _server.setProcessName(Key); - _server.HttpRequestHandler = new DefaultRequestHandler(); - - CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; - CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; - } - - /// - /// Program status event handler - /// - /// - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) - { - if (programEventType != eProgramStatusEventType.Stopping) return; - - Debug.Console(DebugInfo, this, "Program stopping. stopping 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. Server is alreedy registered."); - return; - } - - 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; - } - - /// - /// 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); - } - - /// - /// Returns a list of the current routes - /// - public HttpCwsRouteCollection GetRouteCollection() - { - return _server.Routes; - } - - /// - /// Starts CWS instance - /// - public void Start() - { - try - { - _serverLock.Enter(); - - 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; - } - - IsRegistered = _server.Register(); - - Debug.Console(DebugInfo, this, "Starting server, registration {0}", IsRegistered ? "was successful" : "failed"); - } - 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, "Server is null or has already been stopped"); - return; - } - - IsRegistered = _server.Unregister() == false; - - Debug.Console(DebugInfo, this, "Stopping server, unregistration {0}", IsRegistered ? "failed" : "was successful"); - - _server.Dispose(); - _server = null; - } - catch (Exception ex) - { - 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, "Server Stop 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 - { - var j = JsonConvert.SerializeObject(args.Context, Formatting.Indented); - Debug.Console(DebugVerbose, this, "RecieveRequestEventHandler Context:\x0d\x0a{0}", j); - } - 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); - } - } - } -} \ No newline at end of file diff --git a/src/Pepperdash Core/lib/net35/PepperDash_Core.clz b/src/Pepperdash Core/lib/net35/PepperDash_Core.clz deleted file mode 100644 index 93e2b02..0000000 Binary files a/src/Pepperdash Core/lib/net35/PepperDash_Core.clz and /dev/null differ diff --git a/src/Pepperdash Core/lib/net35/PepperDash_Core.dll b/src/Pepperdash Core/lib/net35/PepperDash_Core.dll deleted file mode 100644 index 1b3d097..0000000 Binary files a/src/Pepperdash Core/lib/net35/PepperDash_Core.dll and /dev/null differ diff --git a/src/Pepperdash Core/Properties/ControlSystem.cfg b/src/Properties/ControlSystem.cfg similarity index 100% rename from src/Pepperdash Core/Properties/ControlSystem.cfg rename to src/Properties/ControlSystem.cfg diff --git a/src/Pepperdash Core/SystemInfo/EventArgs and Constants.cs b/src/SystemInfo/EventArgs and Constants.cs similarity index 100% rename from src/Pepperdash Core/SystemInfo/EventArgs and Constants.cs rename to src/SystemInfo/EventArgs and Constants.cs diff --git a/src/Pepperdash Core/SystemInfo/SystemInfoConfig.cs b/src/SystemInfo/SystemInfoConfig.cs similarity index 100% rename from src/Pepperdash Core/SystemInfo/SystemInfoConfig.cs rename to src/SystemInfo/SystemInfoConfig.cs diff --git a/src/Pepperdash Core/SystemInfo/SystemInfoToSimpl.cs b/src/SystemInfo/SystemInfoToSimpl.cs similarity index 100% rename from src/Pepperdash Core/SystemInfo/SystemInfoToSimpl.cs rename to src/SystemInfo/SystemInfoToSimpl.cs diff --git a/src/Pepperdash Core/Web/BouncyCertificate.cs b/src/Web/BouncyCertificate.cs similarity index 99% rename from src/Pepperdash Core/Web/BouncyCertificate.cs rename to src/Web/BouncyCertificate.cs index 67c129f..bf8b0f4 100644 --- a/src/Pepperdash Core/Web/BouncyCertificate.cs +++ b/src/Web/BouncyCertificate.cs @@ -9,7 +9,6 @@ using Org.BouncyCastle.Asn1.X509; using Org.BouncyCastle.Crypto; using Org.BouncyCastle.Crypto.Generators; using Org.BouncyCastle.Crypto.Prng; -using Org.BouncyCastle.Math; using Org.BouncyCastle.Pkcs; using Org.BouncyCastle.Security; using Org.BouncyCastle.Utilities; @@ -17,10 +16,7 @@ using Org.BouncyCastle.X509; using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2; using X509KeyStorageFlags = System.Security.Cryptography.X509Certificates.X509KeyStorageFlags; using X509ContentType = System.Security.Cryptography.X509Certificates.X509ContentType; -using System.Text; using Org.BouncyCastle.Crypto.Operators; -using System.Numerics; -using System.Security.Cryptography.X509Certificates; using BigInteger = Org.BouncyCastle.Math.BigInteger; using X509Certificate = Org.BouncyCastle.X509.X509Certificate; @@ -284,7 +280,7 @@ namespace PepperDash.Core // Now to convert the Bouncy Castle certificate to a .NET certificate. // See http://web.archive.org/web/20100504192226/http://www.fkollmann.de/v2/post/Creating-certificates-using-BouncyCastle.aspx // ...but, basically, we create a PKCS12 store (a .PFX file) in memory, and add the public and private key to that. - var store = new Pkcs12Store(); + var store = new Pkcs12StoreBuilder().Build(); // What Bouncy Castle calls "alias" is the same as what Windows terms the "friendly name". string friendlyName = certificate.SubjectDN.ToString(); diff --git a/src/Web/RequestHandlers/DefaultRequestHandler.cs b/src/Web/RequestHandlers/DefaultRequestHandler.cs new file mode 100644 index 0000000..ca19cf2 --- /dev/null +++ b/src/Web/RequestHandlers/DefaultRequestHandler.cs @@ -0,0 +1,17 @@ +using Crestron.SimplSharp.WebScripting; + +namespace PepperDash.Core.Web.RequestHandlers +{ + /// + /// Web API default request handler + /// + public class DefaultRequestHandler : WebApiBaseRequestHandler + { + /// + /// Constructor + /// + public DefaultRequestHandler() + : base(true) + { } + } +} \ No newline at end of file diff --git a/src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs b/src/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs similarity index 100% rename from src/Pepperdash Core/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs rename to src/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs diff --git a/src/Web/RequestHandlers/WebApiBaseRequestHandler.cs b/src/Web/RequestHandlers/WebApiBaseRequestHandler.cs new file mode 100644 index 0000000..99e4aa9 --- /dev/null +++ b/src/Web/RequestHandlers/WebApiBaseRequestHandler.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using Crestron.SimplSharp.WebScripting; + +namespace PepperDash.Core.Web.RequestHandlers +{ + /// + /// CWS Base Handler, implements IHttpCwsHandler + /// + public abstract class WebApiBaseRequestHandler : IHttpCwsHandler + { + private readonly Dictionary> _handlers; + protected readonly bool EnableCors; + + /// + /// Constructor + /// + protected WebApiBaseRequestHandler(bool enableCors) + { + EnableCors = enableCors; + + _handlers = new Dictionary> + { + {"CONNECT", HandleConnect}, + {"DELETE", HandleDelete}, + {"GET", HandleGet}, + {"HEAD", HandleHead}, + {"OPTIONS", HandleOptions}, + {"PATCH", HandlePatch}, + {"POST", HandlePost}, + {"PUT", HandlePut}, + {"TRACE", HandleTrace} + }; + } + + /// + /// Constructor + /// + protected WebApiBaseRequestHandler() + : this(false) + { + } + + /// + /// 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; + } + + 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 diff --git a/src/Web/WebApiServer.cs b/src/Web/WebApiServer.cs new file mode 100644 index 0000000..cf45b36 --- /dev/null +++ b/src/Web/WebApiServer.cs @@ -0,0 +1,284 @@ +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 +{ + /// + /// Web API server + /// + public class WebApiServer : IKeyName + { + 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; + private const uint DebugInfo = 1; + private const uint DebugVerbose = 2; + + private readonly CCriticalSection _serverLock = new CCriticalSection(); + private HttpCwsServer _server; + + /// + /// Web API server key + /// + public string Key { get; private set; } + + /// + /// Web API server name + /// + public string Name { get; private set; } + + /// + /// 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; } + + /// + /// 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 + /// + public WebApiServer() + : this(SplusKey, DefaultName, null) + { + } + + /// + /// Constructor + /// + /// + /// + public WebApiServer(string key, string basePath) + : this(key, DefaultName, basePath) + { + } + + /// + /// Constructor + /// + /// + /// + /// + public WebApiServer(string key, string name, string basePath) + { + Key = key; + Name = string.IsNullOrEmpty(name) ? DefaultName : name; + BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; + + if (_server == null) _server = new HttpCwsServer(BasePath); + + _server.setProcessName(Key); + _server.HttpRequestHandler = new DefaultRequestHandler(); + + CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; + CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; + } + + /// + /// Program status event handler + /// + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType != eProgramStatusEventType.Stopping) return; + + Debug.Console(DebugInfo, this, "Program stopping. stopping 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. Server is alreedy registered."); + return; + } + + 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; + } + + /// + /// 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); + } + + /// + /// Returns a list of the current routes + /// + public HttpCwsRouteCollection GetRouteCollection() + { + return _server.Routes; + } + + /// + /// Starts CWS instance + /// + public void Start() + { + try + { + _serverLock.Enter(); + + 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; + } + + IsRegistered = _server.Register(); + + Debug.Console(DebugInfo, this, "Starting server, registration {0}", IsRegistered ? "was successful" : "failed"); + } + 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, "Server is null or has already been stopped"); + return; + } + + IsRegistered = _server.Unregister() == false; + + Debug.Console(DebugInfo, this, "Stopping server, unregistration {0}", IsRegistered ? "failed" : "was successful"); + + _server.Dispose(); + _server = null; + } + catch (Exception ex) + { + 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, "Server Stop 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 + { + var j = JsonConvert.SerializeObject(args.Context, Formatting.Indented); + Debug.Console(DebugVerbose, this, "RecieveRequestEventHandler Context:\x0d\x0a{0}", j); + } + 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); + } + } + } +} \ No newline at end of file diff --git a/src/Pepperdash Core/WebApi/Presets/Preset.cs b/src/WebApi/Presets/Preset.cs similarity index 100% rename from src/Pepperdash Core/WebApi/Presets/Preset.cs rename to src/WebApi/Presets/Preset.cs diff --git a/src/Pepperdash Core/WebApi/Presets/User.cs b/src/WebApi/Presets/User.cs similarity index 100% rename from src/Pepperdash Core/WebApi/Presets/User.cs rename to src/WebApi/Presets/User.cs diff --git a/src/Pepperdash Core/WebApi/Presets/WebApiPasscodeClient.cs b/src/WebApi/Presets/WebApiPasscodeClient.cs similarity index 100% rename from src/Pepperdash Core/WebApi/Presets/WebApiPasscodeClient.cs rename to src/WebApi/Presets/WebApiPasscodeClient.cs diff --git a/src/Pepperdash Core/XSigUtility/Serialization/IXSigSerialization.cs b/src/XSigUtility/Serialization/IXSigSerialization.cs similarity index 100% rename from src/Pepperdash Core/XSigUtility/Serialization/IXSigSerialization.cs rename to src/XSigUtility/Serialization/IXSigSerialization.cs diff --git a/src/Pepperdash Core/XSigUtility/Serialization/XSigSerializationException.cs b/src/XSigUtility/Serialization/XSigSerializationException.cs similarity index 100% rename from src/Pepperdash Core/XSigUtility/Serialization/XSigSerializationException.cs rename to src/XSigUtility/Serialization/XSigSerializationException.cs diff --git a/src/Pepperdash Core/XSigUtility/Tokens/XSigAnalogToken.cs b/src/XSigUtility/Tokens/XSigAnalogToken.cs similarity index 100% rename from src/Pepperdash Core/XSigUtility/Tokens/XSigAnalogToken.cs rename to src/XSigUtility/Tokens/XSigAnalogToken.cs diff --git a/src/Pepperdash Core/XSigUtility/Tokens/XSigDigitalToken.cs b/src/XSigUtility/Tokens/XSigDigitalToken.cs similarity index 100% rename from src/Pepperdash Core/XSigUtility/Tokens/XSigDigitalToken.cs rename to src/XSigUtility/Tokens/XSigDigitalToken.cs diff --git a/src/Pepperdash Core/XSigUtility/Tokens/XSigSerialToken.cs b/src/XSigUtility/Tokens/XSigSerialToken.cs similarity index 100% rename from src/Pepperdash Core/XSigUtility/Tokens/XSigSerialToken.cs rename to src/XSigUtility/Tokens/XSigSerialToken.cs diff --git a/src/Pepperdash Core/XSigUtility/Tokens/XSigToken.cs b/src/XSigUtility/Tokens/XSigToken.cs similarity index 100% rename from src/Pepperdash Core/XSigUtility/Tokens/XSigToken.cs rename to src/XSigUtility/Tokens/XSigToken.cs diff --git a/src/Pepperdash Core/XSigUtility/Tokens/XSigTokenType.cs b/src/XSigUtility/Tokens/XSigTokenType.cs similarity index 100% rename from src/Pepperdash Core/XSigUtility/Tokens/XSigTokenType.cs rename to src/XSigUtility/Tokens/XSigTokenType.cs diff --git a/src/Pepperdash Core/XSigUtility/XSigHelpers.cs b/src/XSigUtility/XSigHelpers.cs similarity index 100% rename from src/Pepperdash Core/XSigUtility/XSigHelpers.cs rename to src/XSigUtility/XSigHelpers.cs diff --git a/src/Pepperdash Core/XSigUtility/XSigTokenStreamReader.cs b/src/XSigUtility/XSigTokenStreamReader.cs similarity index 100% rename from src/Pepperdash Core/XSigUtility/XSigTokenStreamReader.cs rename to src/XSigUtility/XSigTokenStreamReader.cs diff --git a/src/Pepperdash Core/XSigUtility/XSigTokenStreamWriter.cs b/src/XSigUtility/XSigTokenStreamWriter.cs similarity index 100% rename from src/Pepperdash Core/XSigUtility/XSigTokenStreamWriter.cs rename to src/XSigUtility/XSigTokenStreamWriter.cs