Merge pull request #188 from PepperDash/release

Release PD Core 2.0.0
This commit is contained in:
Andrew Welker 2025-03-06 09:52:56 -06:00 committed by GitHub
commit ab61b2673a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
105 changed files with 12503 additions and 13387 deletions

Binary file not shown.

View file

@ -1,45 +0,0 @@
$latestVersions = $(git tag --merged origin/main)
$latestVersion = [version]"0.0.0"
Foreach ($version in $latestVersions) {
Write-Host $version
try {
if (([version]$version) -ge $latestVersion) {
$latestVersion = $version
Write-Host "Setting latest version to: $latestVersion"
}
}
catch {
Write-Host "Unable to convert $($version). Skipping"
continue;
}
}
$newVersion = [version]$latestVersion
$phase = ""
$newVersionString = ""
switch -regex ($Env:GITHUB_REF) {
'^refs\/heads\/main*.' {
$newVersionString = "{0}.{1}.{2}" -f $newVersion.Major, $newVersion.Minor, $newVersion.Build
}
'^refs\/heads\/feature\/*.' {
$phase = 'alpha'
$newVersionString = "{0}.{1}.{2}-{3}-{4}" -f $newVersion.Major, $newVersion.Minor, ($newVersion.Build + 1), $phase, $Env:GITHUB_RUN_NUMBER
}
'^refs\/heads\/release\/*.' {
$splitRef = $Env:GITHUB_REF -split "/"
$version = [version]($splitRef[-1] -replace "v", "")
$phase = 'rc'
$newVersionString = "{0}.{1}.{2}-{3}-{4}" -f $version.Major, $version.Minor, $version.Build, $phase, $Env:GITHUB_RUN_NUMBER
}
'^refs\/heads\/development*.' {
$phase = 'beta'
$newVersionString = "{0}.{1}.{2}-{3}-{4}" -f $newVersion.Major, $newVersion.Minor, ($newVersion.Build + 1), $phase, $Env:GITHUB_RUN_NUMBER
}
'^refs\/heads\/hotfix\/*.' {
$phase = 'hotfix'
$newVersionString = "{0}.{1}.{2}-{3}-{4}" -f $newVersion.Major, $newVersion.Minor, ($newVersion.Build + 1), $phase, $Env:GITHUB_RUN_NUMBER
}
}
Write-Output $newVersionString

View file

@ -1,40 +0,0 @@
function Update-SourceVersion {
Param ([string]$Version)
#$fullVersion = $Version
$baseVersion = [regex]::Match($Version, "(\d+.\d+.\d+).*").captures.groups[1].value
$NewAssemblyVersion = AssemblyVersion(" + $baseVersion + .*")
Write-Output "AssemblyVersion = $NewAssemblyVersion"
$NewAssemblyInformationalVersion = AssemblyInformationalVersion(" + $Version + ")
Write-Output "AssemblyInformationalVersion = $NewAssemblyInformationalVersion"
foreach ($o in $input) {
Write-output $o.FullName
$TmpFile = $o.FullName + .tmp
get-content $o.FullName |
ForEach-Object {
$_ -replace AssemblyVersion\(".*"\), $NewAssemblyVersion } |
ForEach-Object {
$_ -replace AssemblyInformationalVersion\(".*"\), $NewAssemblyInformationalVersion
} > $TmpFile
move-item $TmpFile $o.FullName -force
}
}
function Update-AllAssemblyInfoFiles ( $version ) {
foreach ($file in AssemblyInfo.cs, AssemblyInfo.vb ) {
get-childitem -Path $Env:GITHUB_WORKSPACE -recurse | Where-Object { $_.Name -eq $file } | Update-SourceVersion $version ;
}
}
# validate arguments
$r = [System.Text.RegularExpressions.Regex]::Match($args[0], "\d+\.\d+\.\d+.*");
if ($r.Success) {
Write-Output "Updating Assembly Version to $args ...";
Update-AllAssemblyInfoFiles $args[0];
}
else {
Write-Output ;
Write-Output Error: Input version does not match x.y.z format!
Write-Output ;
Write-Output "Unable to apply version to AssemblyInfo.cs files";
}

View file

@ -1,42 +0,0 @@
# Uncomment these for local testing
# $Env:GITHUB_WORKSPACE = "C:\Working Directories\PD\essentials"
# $Env:SOLUTION_FILE = "PepperDashEssentials"
# $Env:VERSION = "0.0.0-buildType-test"
# Sets the root directory for the operation
$destination = "$($Env:GITHUB_HOME)\output"
New-Item -ItemType Directory -Force -Path ($destination)
Get-ChildItem ($destination)
$exclusions = @(git submodule foreach --quiet 'echo $name')
$exclusions += "Newtonsoft.Json.Compact.dll"
# Trying to get any .json schema files (not currently working)
# Gets any files with the listed extensions.
Get-ChildItem -recurse -Path "$($Env:GITHUB_WORKSPACE)" -include "*.clz", "*.cpz", "*.cplz", "*.json", "*.nuspec" | ForEach-Object {
$allowed = $true;
# Exclude any files in submodules
foreach ($exclude in $exclusions) {
if ((Split-Path $_.FullName -Parent).contains("$($exclude)")) {
$allowed = $false;
break;
}
}
if ($allowed) {
Write-Host "allowing $($_)"
$_;
}
} | Copy-Item -Destination ($destination) -Force
Write-Host "Getting matching files..."
# Get any files from the output folder that match the following extensions
Get-ChildItem -Path $destination | Where-Object { (($_.Extension -eq ".clz") -or ($_.Extension -eq ".cpz") -or ($_.Extension -eq ".cplz")) } | ForEach-Object {
# Replace the extensions with dll or xml and create an array
$filenames = @($($_ -replace "cpz|clz|cplz", "dll"), $($_ -replace "cpz|clz|cplz", "xml"))
Write-Host "Filenames:"
Write-Host $filenames
if ($filenames.length -gt 0) {
# Attempt to get the files and return them to the output directory
Get-ChildItem -Recurse -Path "$($Env:GITHUB_WORKSPACE)" -include $filenames | Copy-Item -Destination ($destination) -Force
}
}
Compress-Archive -Path $destination -DestinationPath "$($Env:GITHUB_WORKSPACE)\$($Env:SOLUTION_FILE)-$($Env:VERSION).zip" -Force
Write-Host "Output Contents post Zip"
Get-ChildItem -Path $destination

View file

@ -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 }}

View file

@ -1,154 +0,0 @@
name: Branch Build Using Docker
on:
push:
branches:
- feature/*
- hotfix/*
- release/*
- development
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: Pepperdash Core
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:
runs-on: windows-2019
steps:
# First we checkout the source repo
- name: Checkout repo
uses: actions/checkout@v2
with:
fetch-depth: 0
# And any submodules
- name: Checkout submodules
shell: bash
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
# Fetch all tags
- name: Fetch tags
run: git fetch --tags
# Generate the appropriate version number
- name: Set Version Number
shell: powershell
run: |
$version = ./.github/scripts/GenerateVersionNumber.ps1
echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
# Use the version number to set the version of the assemblies
- name: Update AssemblyInfo.cs
shell: powershell
run: |
Write-Output ${{ env.VERSION }}
./.github/scripts/UpdateAssemblyVersion.ps1 ${{ env.VERSION }}
# Login to Docker
- name: Login to Docker
uses: azure/docker-login@v1
with:
username: ${{ secrets.dockerhub_user }}
password: ${{ secrets.dockerhub_password }}
# Build the solutions in the docker image
- name: Build Solution
shell: powershell
run: |
Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_PATH)\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)"
- name: Zip Build Output
shell: powershell
run: ./.github/scripts/ZipBuildOutput.ps1
# Write the version to a file to be consumed by the push jobs
- name: Write Version
run: Write-Output "$($Env:VERSION)" | Out-File -FilePath "$($Env:GITHUB_HOME)\output\version.txt"
# Upload the build output as an artifact
- name: Upload Build Output
uses: actions/upload-artifact@v1
with:
name: Build
path: ./${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip
# Upload the Version file as an artifact
- name: Upload version.txt
uses: actions/upload-artifact@v1
with:
name: Version
path: ${{env.GITHUB_HOME}}\output\version.txt
# Create the release on the source repo
- name: Create tag for non-rc builds
if: contains(env.VERSION, 'alpha') || contains(env.VERSION, 'beta')
run: |
git tag $($Env:VERSION)
git push --tags origin
- name: Create Release
id: create_release
# using contributor's version to allow for pointing at the right commit
if: contains(env.VERSION,'-rc-') || contains(env.VERSION,'-hotfix-')
uses: fleskesvor/create-release@feature/support-target-commitish
with:
tag_name: ${{ env.VERSION }}
release_name: ${{ env.VERSION }}
prerelease: ${{contains('debug', env.BUILD_TYPE)}}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Upload the build package to the release
- name: Upload Release Package
if: contains(env.VERSION,'-rc-') || contains(env.VERSION,'-hotfix-')
id: upload_release
uses: actions/upload-release-asset@v1
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip
asset_name: ${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip
asset_content_type: application/zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN}}
Push_Nuget_Package:
needs: Build_Project
runs-on: windows-latest
steps:
- name: Download Build Version Info
uses: actions/download-artifact@v1
with:
name: Version
- name: Set Version Number
shell: powershell
run: |
Get-ChildItem "./Version"
$version = Get-Content -Path ./Version/version.txt
Write-Host "Version: $version"
echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Remove-Item -Path ./Version/version.txt
Remove-Item -Path ./Version
- name: Download Build output
uses: actions/download-artifact@v1
with:
name: Build
path: ./
- name: Unzip Build file
run: |
Get-ChildItem .\*.zip | Expand-Archive -DestinationPath .\
Remove-Item -Path .\*.zip
- name: Copy Files to root & delete output directory
run: |
Remove-Item -Path .\* -Include @("*.cpz","*.md","*.cplz","*.json","*.dll","*.clz")
Get-ChildItem -Path .\output\* | Copy-Item -Destination .\
Remove-Item -Path .\output -Recurse
- name: Add nuget.exe
uses: nuget/setup-nuget@v1
- name: Add Github Packages source
run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }}
- name: Add nuget.org API Key
run: nuget setApiKey ${{ secrets.NUGET_API_KEY }}
- name: Create nuget package
run: nuget pack "./PepperDash_Core.nuspec" -version ${{ env.VERSION }}
- name: Publish nuget package to Github registry
run: nuget push **/*.nupkg -source github
- name: Publish nuget package to nuget.org
run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json

View file

@ -1,129 +0,0 @@
name: Main Build using Docker
on:
release:
types:
- created
branches:
- main
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: Pepperdash Core
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:
runs-on: windows-2019
steps:
# First we checkout the source repo
- name: Checkout repo
uses: actions/checkout@v2
# And any submodules
- name: Checkout submodules
shell: bash
run: |
git config --global url."https://github.com/".insteadOf "git@github.com:"
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
# 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_ENV -Encoding utf8 -Append
# Use the version number to set the version of the assemblies
- name: Update AssemblyInfo.cs
shell: powershell
run: |
Write-Output ${{ env.VERSION }}
./.github/scripts/UpdateAssemblyVersion.ps1 ${{ env.VERSION }}
# Login to Docker
- name: Login to Docker
uses: azure/docker-login@v1
with:
username: ${{ secrets.dockerhub_user }}
password: ${{ secrets.dockerhub_password }}
# Build the solutions in the docker image
- name: Build Solution
shell: powershell
run: |
Invoke-Expression "docker run --rm --mount type=bind,source=""$($Env:GITHUB_WORKSPACE)"",target=""c:/project"" pepperdash/sspbuilder c:\cihelpers\vsidebuild.exe -Solution ""c:\project\$($Env:SOLUTION_PATH)\$($Env:SOLUTION_FILE).sln"" -BuildSolutionConfiguration $($ENV:BUILD_TYPE)"
# Zip up the output files as needed
- name: Zip Build Output
shell: powershell
run: ./.github/scripts/ZipBuildOutput.ps1
# Write the version to a file to be consumed by the push jobs
- name: Write Version
run: Write-Output "$($Env:VERSION)" | Out-File -FilePath "$($Env:GITHUB_HOME)\output\version.txt"
- name: Upload Build Output
uses: actions/upload-artifact@v1
with:
name: Build
path: ./${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip
# Upload the Version file as an artifact
- name: Upload version.txt
uses: actions/upload-artifact@v1
with:
name: Version
path: ${{env.GITHUB_HOME}}\output\version.txt
# Upload the build package to the release
- name: Upload Release Package
id: upload_release
uses: actions/upload-release-asset@v1
with:
upload_url: ${{ github.event.release.upload_url }}
asset_path: ./${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip
asset_name: ${{ env.SOLUTION_FILE}}-${{ env.VERSION}}.zip
asset_content_type: application/zip
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Push_Nuget_Package:
needs: Build_Project
runs-on: windows-latest
steps:
- name: Download Build Version Info
uses: actions/download-artifact@v1
with:
name: Version
- name: Set Version Number
shell: powershell
run: |
Get-ChildItem "./Version"
$version = Get-Content -Path ./Version/version.txt
Write-Host "Version: $version"
echo "VERSION=$version" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Remove-Item -Path ./Version/version.txt
Remove-Item -Path ./Version
- name: Download Build output
uses: actions/download-artifact@v1
with:
name: Build
path: ./
- name: Unzip Build file
run: |
Get-ChildItem .\*.zip | Expand-Archive -DestinationPath .\
Remove-Item -Path .\*.zip
- name: Copy Files to root & delete output directory
run: |
Remove-Item -Path .\* -Include @("*.cpz","*.md","*.cplz","*.json","*.dll","*.clz")
Get-ChildItem -Path .\output\* | Copy-Item -Destination .\
Remove-Item -Path .\output -Recurse
- name: Add nuget.exe
uses: nuget/setup-nuget@v1
- name: Add Github Packages source
run: nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username Pepperdash -password ${{ secrets.GITHUB_TOKEN }}
- name: Add nuget.org API Key
run: nuget setApiKey ${{ secrets.NUGET_API_KEY }}
- name: Create nuget package
run: nuget pack "./PepperDash_Core.nuspec" -version ${{ env.VERSION }}
- name: Publish nuget package to Github registry
run: nuget push **/*.nupkg -source github
- name: Publish nuget package to nuget.org
run: nuget push **/*.nupkg -Source https://api.nuget.org/v3/index.json

412
.gitignore vendored
View file

@ -1,25 +1,401 @@
#ignore thumbnails created by windows ## Ignore Visual Studio temporary files, build results, and
Thumbs.db ## files generated by popular Visual Studio add-ons.
#Ignore files build by Visual Studio ##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user *.user
*.aps *.userosscache
*.pch *.sln.docstates
*.vspscc
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c *_i.c
*_p.c *_p.c
*.ncb *_h.h
*.suo
*.bak
*.cache
*.ilk *.ilk
*.log *.meta
[Bb]in/ *.obj
[Dd]ebug*/ *.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr *.sbr
obj/ *.tlb
[Rr]elease*/ *.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/ _ReSharper*/
SIMPLSharpLogs/ *.[Rr]e[Ss]harper
*.projectinfo *.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg *.nupkg
lib/ # NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml
*.projectinfo
output/

36
.releaserc.json Normal file
View file

@ -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"
}
]
}

View file

@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.1.32228.430
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash.Core.4Series", "src\PepperDash.Core.4Series.csproj", "{100ABA44-9471-4B18-8092-4D94D7D82223}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{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
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E4615FA3-8C8C-4DC0-897B-E85408B4E341}
EndGlobalSection
EndGlobal

View file

@ -1,19 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash_Core", "Pepperdash Core\PepperDash_Core.csproj", "{87E29B4C-569B-4368-A4ED-984AC1440C96}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{87E29B4C-569B-4368-A4ED-984AC1440C96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{87E29B4C-569B-4368-A4ED-984AC1440C96}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87E29B4C-569B-4368-A4ED-984AC1440C96}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87E29B4C-569B-4368-A4ED-984AC1440C96}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -1,19 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PepperDash_Core", "Pepperdash Core\PepperDash_Core.csproj", "{87E29B4C-569B-4368-A4ED-984AC1440C96}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{87E29B4C-569B-4368-A4ED-984AC1440C96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{87E29B4C-569B-4368-A4ED-984AC1440C96}.Debug|Any CPU.Build.0 = Debug|Any CPU
{87E29B4C-569B-4368-A4ED-984AC1440C96}.Release|Any CPU.ActiveCfg = Release|Any CPU
{87E29B4C-569B-4368-A4ED-984AC1440C96}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View file

@ -1,684 +0,0 @@
/*PepperDash Technology Corp.
JAG
Copyright: 2017
------------------------------------
***Notice of Ownership and Copyright***
The material in which this notice appears is the property of PepperDash Technology Corporation,
which claims copyright under the laws of the United States of America in the entire body of material
and in all parts thereof, regardless of the use to which it is being put. Any use, in whole or in part,
of this material by another party without the express written permission of PepperDash Technology Corporation is prohibited.
PepperDash Technology Corporation reserves all rights under applicable laws.
------------------------------------ */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets;
using PepperDash.Core;
namespace DynamicTCP
{
public class DynamicTCPServer : Device
{
#region Events
/// <summary>
/// Event for Receiving text
/// </summary>
public event EventHandler<CopyCoreForSimplpGenericCommMethodReceiveTextArgs> TextReceived;
/// <summary>
/// Event for client connection socket status change
/// </summary>
public event EventHandler<DynamicTCPSocketStatusChangeEventArgs> ClientConnectionChange;
/// <summary>
/// Event for Server State Change
/// </summary>
public event EventHandler<DynamicTCPServerStateChangedEventArgs> ServerStateChange;
#endregion
#region Properties/Variables
/// <summary>
/// Secure or unsecure TCP server. Defaults to Unsecure or standard TCP server without SSL
/// </summary>
public bool Secure { get; set; }
/// <summary>
/// S+ Helper for Secure bool. Parameter in SIMPL+ so there is no get, one way set from simpl+ Param to property in func main of SIMPL+
/// </summary>
public ushort USecure
{
set
{
if (value == 1)
Secure = true;
else if (value == 0)
Secure = false;
}
}
/// <summary>
/// Text representation of the Socket Status enum values for the server
/// </summary>
public string Status
{
get
{
if (Secure ? SecureServer != null : UnsecureServer != null)
return Secure ? SecureServer.State.ToString() : UnsecureServer.State.ToString();
else
return "";
}
}
/// <summary>
/// Bool showing if socket is connected
/// </summary>
public bool IsConnected
{
get
{
return (Secure ? SecureServer != null : UnsecureServer != null) &&
(Secure ? SecureServer.State == ServerState.SERVER_CONNECTED : UnsecureServer.State == ServerState.SERVER_CONNECTED);
}
}
/// <summary>
/// S+ helper for IsConnected
/// </summary>
public ushort UIsConnected
{
get { return (ushort)(IsConnected ? 1 : 0); }
}
/// <summary>
/// Bool showing if socket is connected
/// </summary>
public bool IsListening
{
get { return (Secure ? SecureServer != null : UnsecureServer != null) &&
(Secure ? SecureServer.State == ServerState.SERVER_LISTENING : UnsecureServer.State == ServerState.SERVER_LISTENING); }
}
/// <summary>
/// S+ helper for IsConnected
/// </summary>
public ushort UIsListening
{
get { return (ushort)(IsListening ? 1 : 0); }
}
public ushort MaxClients { get; set; } // should be set by parameter in SIMPL+ in the MAIN method, Should not ever need to be configurable
/// <summary>
/// Number of clients currently connected.
/// </summary>
public ushort NumberOfClientsConnected
{
get
{
if (Secure ? SecureServer != null : UnsecureServer != null)
return Secure ? (ushort)SecureServer.NumberOfClientsConnected : (ushort)UnsecureServer.NumberOfClientsConnected;
return 0;
}
}
/// <summary>
/// Port Server should listen on
/// </summary>
public int Port { get; set; }
/// <summary>
/// S+ helper for Port
/// </summary>
public ushort UPort
{
get { return Convert.ToUInt16(Port); }
set { Port = Convert.ToInt32(value); }
}
/// <summary>
/// Bool to show whether the server requires a preshared key. Must be set the same in the client, and if true shared keys must be identical on server/client
/// </summary>
public bool SharedKeyRequired { get; set; }
/// <summary>
/// S+ helper for requires shared key bool
/// </summary>
public ushort USharedKeyRequired
{
set
{
if (value == 1)
SharedKeyRequired = true;
else
SharedKeyRequired = false;
}
}
/// <summary>
/// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module.
/// If SharedKey changes while server is listening or clients are connected, disconnect and stop listening will be called
/// </summary>
public string SharedKey { get; set; }
/// <summary>
/// Heartbeat Required bool sets whether server disconnects client if heartbeat is not received
/// </summary>
public bool HeartbeatRequired { get; set; }
/// <summary>
/// S+ Helper for Heartbeat Required
/// </summary>
public ushort UHeartbeatRequired
{
set
{
if (value == 1)
HeartbeatRequired = true;
else
HeartbeatRequired = false;
}
}
/// <summary>
/// Milliseconds before server expects another heartbeat. Set by property HeartbeatRequiredIntervalInSeconds which is driven from S+
/// </summary>
public int HeartbeatRequiredIntervalMs { get; set; }
/// <summary>
/// Simpl+ Heartbeat Analog value in seconds
/// </summary>
public ushort HeartbeatRequiredIntervalInSeconds { set { HeartbeatRequiredIntervalMs = (value * 1000); } }
/// <summary>
/// String to Match for heartbeat. If null or empty any string will reset heartbeat timer
/// </summary>
public string HeartbeatStringToMatch { get; set; }
//private timers for Heartbeats per client
Dictionary<uint, CTimer> HeartbeatTimerDictionary = new Dictionary<uint, CTimer>();
//flags to show the secure server is waiting for client at index to send the shared key
List<uint> WaitingForSharedKey = new List<uint>();
//Store the connected client indexes
List<uint> ConnectedClientsIndexes = new List<uint>();
/// <summary>
/// Defaults to 2000
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// Private flag to note that the server has stopped intentionally
/// </summary>
private bool ServerStopped { get; set; }
//Servers
SecureTCPServer SecureServer;
TCPServer UnsecureServer;
#endregion
#region Constructors
/// <summary>
/// constructor
/// </summary>
public DynamicTCPServer()
: base("Uninitialized Dynamic TCP Server")
{
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
BufferSize = 2000;
Secure = false;
}
#endregion
#region Methods - Server Actions
/// <summary>
/// Initialize Key for device using client name from SIMPL+. Called on Listen from SIMPL+
/// </summary>
/// <param name="key"></param>
public void Initialize(string key)
{
Key = key;
}
/// <summary>
/// Start listening on the specified port
/// </summary>
public void Listen()
{
try
{
if (Port < 1 || Port > 65535)
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': Invalid port", Key);
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': Invalid port", Key));
return;
}
if (string.IsNullOrEmpty(SharedKey) && SharedKeyRequired)
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': No Shared Key set", Key);
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': No Shared Key set", Key));
return;
}
if (IsListening)
return;
if (Secure)
{
SecureServer = new SecureTCPServer(Port, MaxClients);
SecureServer.SocketStatusChange += new SecureTCPServerSocketStatusChangeEventHandler(SecureServer_SocketStatusChange);
ServerStopped = false;
SecureServer.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback);
onServerStateChange();
Debug.Console(2, "Secure Server Status: {0}, Socket Status: {1}\r\n", SecureServer.State.ToString(), SecureServer.ServerSocketStatus);
}
else
{
UnsecureServer = new TCPServer(Port, MaxClients);
UnsecureServer.SocketStatusChange += new TCPServerSocketStatusChangeEventHandler(UnsecureServer_SocketStatusChange);
ServerStopped = false;
UnsecureServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback);
onServerStateChange();
Debug.Console(2, "Unsecure Server Status: {0}, Socket Status: {1}\r\n", UnsecureServer.State.ToString(), UnsecureServer.ServerSocketStatus);
}
}
catch (Exception ex)
{
ErrorLog.Error("Error with Dynamic Server: {0}", ex.ToString());
}
}
/// <summary>
/// Stop Listeneing
/// </summary>
public void StopListening()
{
Debug.Console(2, "Stopping Listener");
if (SecureServer != null)
SecureServer.Stop();
if (UnsecureServer != null)
UnsecureServer.Stop();
ServerStopped = true;
onServerStateChange();
}
/// <summary>
/// Disconnect All Clients
/// </summary>
public void DisconnectAllClients()
{
Debug.Console(2, "Disconnecting All Clients");
if (SecureServer != null)
SecureServer.DisconnectAll();
if (UnsecureServer != null)
UnsecureServer.DisconnectAll();
onConnectionChange();
onServerStateChange(); //State shows both listening and connected
}
/// <summary>
/// Broadcast text from server to all connected clients
/// </summary>
/// <param name="text"></param>
public void BroadcastText(string text)
{
if (ConnectedClientsIndexes.Count > 0)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes(text);
if (Secure)
foreach (uint i in ConnectedClientsIndexes)
SecureServer.SendDataAsync(i, b, b.Length, SecureSendDataAsyncCallback);
else
foreach (uint i in ConnectedClientsIndexes)
UnsecureServer.SendDataAsync(i, b, b.Length, UnsecureSendDataAsyncCallback);
}
}
/// <summary>
/// Not sure this is useful in library, maybe Pro??
/// </summary>
/// <param name="text"></param>
/// <param name="clientIndex"></param>
public void SendTextToClient(string text, uint clientIndex)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes(text);
if (Secure)
SecureServer.SendDataAsync(clientIndex, b, b.Length, SecureSendDataAsyncCallback);
else
UnsecureServer.SendDataAsync(clientIndex, b, b.Length, UnsecureSendDataAsyncCallback);
}
//private method to check heartbeat requirements and start or reset timer
void checkHeartbeat(uint clientIndex, string received)
{
if (HeartbeatRequired)
{
if (!string.IsNullOrEmpty(HeartbeatStringToMatch))
{
if (received == HeartbeatStringToMatch)
{
if (HeartbeatTimerDictionary.ContainsKey(clientIndex))
HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs);
else
{
CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs);
HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer);
}
}
}
else
{
if (HeartbeatTimerDictionary.ContainsKey(clientIndex))
HeartbeatTimerDictionary[clientIndex].Reset(HeartbeatRequiredIntervalMs);
else
{
CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs);
HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer);
}
}
}
}
#endregion
#region Methods - HeartbeatTimer Callback
void HeartbeatTimer_CallbackFunction(object o)
{
uint clientIndex = (uint)o;
string address = Secure ? SecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex) :
UnsecureServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex);
ErrorLog.Error("Heartbeat not received for Client at IP: {0}, DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE", address);
Debug.Console(2, "Heartbeat not received for Client at IP: {0}, DISCONNECTING BECAUSE HEARTBEAT REQUIRED IS TRUE", address);
SendTextToClient("Heartbeat not received by server, closing connection", clientIndex);
if (Secure)
SecureServer.Disconnect(clientIndex);
else
UnsecureServer.Disconnect(clientIndex);
HeartbeatTimerDictionary.Remove(clientIndex);
}
#endregion
#region Methods - Socket Status Changed Callbacks
/// <summary>
/// Secure Server Socket Status Changed Callback
/// </summary>
/// <param name="mySecureTCPServer"></param>
/// <param name="clientIndex"></param>
/// <param name="serverSocketStatus"></param>
void SecureServer_SocketStatusChange(SecureTCPServer server, uint clientIndex, SocketStatus serverSocketStatus)
{
Debug.Console(2, "Client at {0} ServerSocketStatus {1}",
server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), serverSocketStatus.ToString());
if (server.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
{
if (SharedKeyRequired && !WaitingForSharedKey.Contains(clientIndex))
WaitingForSharedKey.Add(clientIndex);
if (!ConnectedClientsIndexes.Contains(clientIndex))
ConnectedClientsIndexes.Add(clientIndex);
}
else
{
if (ConnectedClientsIndexes.Contains(clientIndex))
ConnectedClientsIndexes.Remove(clientIndex);
if (HeartbeatRequired && HeartbeatTimerDictionary.ContainsKey(clientIndex))
HeartbeatTimerDictionary.Remove(clientIndex);
}
if(SecureServer.ServerSocketStatus.ToString() != Status)
onConnectionChange();
}
/// <summary>
/// TCP Server (Unsecure) Socket Status Change Callback
/// </summary>
/// <param name="mySecureTCPServer"></param>
/// <param name="clientIndex"></param>
/// <param name="serverSocketStatus"></param>
void UnsecureServer_SocketStatusChange(TCPServer server, uint clientIndex, SocketStatus serverSocketStatus)
{
Debug.Console(2, "Client at {0} ServerSocketStatus {1}",
server.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), serverSocketStatus.ToString());
if (server.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
{
if (SharedKeyRequired && !WaitingForSharedKey.Contains(clientIndex))
WaitingForSharedKey.Add(clientIndex);
if (!ConnectedClientsIndexes.Contains(clientIndex))
ConnectedClientsIndexes.Add(clientIndex);
}
else
{
if (ConnectedClientsIndexes.Contains(clientIndex))
ConnectedClientsIndexes.Remove(clientIndex);
if (HeartbeatRequired && HeartbeatTimerDictionary.ContainsKey(clientIndex))
HeartbeatTimerDictionary.Remove(clientIndex);
}
if (UnsecureServer.ServerSocketStatus.ToString() != Status)
onConnectionChange();
}
#endregion
#region Methods Connected Callbacks
/// <summary>
/// Secure TCP Client Connected to Secure Server Callback
/// </summary>
/// <param name="mySecureTCPServer"></param>
/// <param name="clientIndex"></param>
void SecureConnectCallback(SecureTCPServer mySecureTCPServer, uint clientIndex)
{
if (mySecureTCPServer.ClientConnected(clientIndex))
{
if (SharedKeyRequired)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes(SharedKey + "\n");
mySecureTCPServer.SendDataAsync(clientIndex, b, b.Length, SecureSendDataAsyncCallback);
Debug.Console(2, "Sent Shared Key to client at {0}", mySecureTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex));
}
if (HeartbeatRequired)
{
CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs);
HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer);
}
mySecureTCPServer.ReceiveDataAsync(clientIndex, SecureReceivedDataAsyncCallback);
if (mySecureTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped)
mySecureTCPServer.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback);
}
}
/// <summary>
/// Unsecure TCP Client Connected to Unsecure Server Callback
/// </summary>
/// <param name="myTCPServer"></param>
/// <param name="clientIndex"></param>
void UnsecureConnectCallback(TCPServer myTCPServer, uint clientIndex)
{
if (myTCPServer.ClientConnected(clientIndex))
{
if (SharedKeyRequired)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes(SharedKey + "\n");
myTCPServer.SendDataAsync(clientIndex, b, b.Length, UnsecureSendDataAsyncCallback);
Debug.Console(2, "Sent Shared Key to client at {0}", myTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex));
}
if (HeartbeatRequired)
{
CTimer HeartbeatTimer = new CTimer(HeartbeatTimer_CallbackFunction, clientIndex, HeartbeatRequiredIntervalMs);
HeartbeatTimerDictionary.Add(clientIndex, HeartbeatTimer);
}
myTCPServer.ReceiveDataAsync(clientIndex, UnsecureReceivedDataAsyncCallback);
if (myTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped)
myTCPServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback);
}
if (myTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped)
myTCPServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback);
}
#endregion
#region Methods - Send/Receive Callbacks
/// <summary>
/// Secure Send Data Async Callback
/// </summary>
/// <param name="mySecureTCPServer"></param>
/// <param name="clientIndex"></param>
/// <param name="numberOfBytesSent"></param>
void SecureSendDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesSent)
{
//Seems there is nothing to do here
}
/// <summary>
/// Unsecure Send Data Asyc Callback
/// </summary>
/// <param name="myTCPServer"></param>
/// <param name="clientIndex"></param>
/// <param name="numberOfBytesSent"></param>
void UnsecureSendDataAsyncCallback(TCPServer myTCPServer, uint clientIndex, int numberOfBytesSent)
{
//Seems there is nothing to do here
}
/// <summary>
/// Secure Received Data Async Callback
/// </summary>
/// <param name="mySecureTCPServer"></param>
/// <param name="clientIndex"></param>
/// <param name="numberOfBytesReceived"></param>
void SecureReceivedDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesReceived)
{
if (numberOfBytesReceived > 0)
{
string received = "Nothing";
byte[] bytes = mySecureTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex);
received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived);
if (WaitingForSharedKey.Contains(clientIndex))
{
received = received.Replace("\r", "");
received = received.Replace("\n", "");
if (received != SharedKey)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting");
Debug.Console(2, "Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
ErrorLog.Error("Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
mySecureTCPServer.SendDataAsync(clientIndex, b, b.Length, null);
mySecureTCPServer.Disconnect(clientIndex);
}
if (mySecureTCPServer.NumberOfClientsConnected > 0)
mySecureTCPServer.ReceiveDataAsync(SecureReceivedDataAsyncCallback);
WaitingForSharedKey.Remove(clientIndex);
byte[] skResponse = Encoding.GetEncoding(28591).GetBytes("Shared Key Match, Connected and ready for communication");
mySecureTCPServer.SendDataAsync(clientIndex, skResponse, skResponse.Length, null);
mySecureTCPServer.ReceiveDataAsync(SecureReceivedDataAsyncCallback);
}
else
{
mySecureTCPServer.ReceiveDataAsync(SecureReceivedDataAsyncCallback);
Debug.Console(2, "Secure Server Listening on Port: {0}, client IP: {1}, NumberOfBytesReceived: {2}, Received: {3}\r\n",
mySecureTCPServer.PortNumber, mySecureTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), numberOfBytesReceived, received);
onTextReceived(received);
}
checkHeartbeat(clientIndex, received);
}
if (mySecureTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
mySecureTCPServer.ReceiveDataAsync(clientIndex, SecureReceivedDataAsyncCallback);
}
/// <summary>
/// Unsecure Received Data Async Callback
/// </summary>
/// <param name="myTCPServer"></param>
/// <param name="clientIndex"></param>
/// <param name="numberOfBytesReceived"></param>
void UnsecureReceivedDataAsyncCallback(TCPServer myTCPServer, uint clientIndex, int numberOfBytesReceived)
{
if (numberOfBytesReceived > 0)
{
string received = "Nothing";
byte[] bytes = myTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex);
received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived);
if (WaitingForSharedKey.Contains(clientIndex))
{
received = received.Replace("\r", "");
received = received.Replace("\n", "");
if (received != SharedKey)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting");
Debug.Console(2, "Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
ErrorLog.Error("Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
myTCPServer.SendDataAsync(clientIndex, b, b.Length, null);
myTCPServer.Disconnect(clientIndex);
}
if (myTCPServer.NumberOfClientsConnected > 0)
myTCPServer.ReceiveDataAsync(UnsecureReceivedDataAsyncCallback);
WaitingForSharedKey.Remove(clientIndex);
byte[] skResponse = Encoding.GetEncoding(28591).GetBytes("Shared Key Match, Connected and ready for communication");
myTCPServer.SendDataAsync(clientIndex, skResponse, skResponse.Length, null);
myTCPServer.ReceiveDataAsync(UnsecureReceivedDataAsyncCallback);
}
else
{
myTCPServer.ReceiveDataAsync(UnsecureReceivedDataAsyncCallback);
Debug.Console(2, "Secure Server Listening on Port: {0}, client IP: {1}, NumberOfBytesReceived: {2}, Received: {3}\r\n",
myTCPServer.PortNumber, myTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), numberOfBytesReceived, received);
onTextReceived(received);
}
checkHeartbeat(clientIndex, received);
}
if (myTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
myTCPServer.ReceiveDataAsync(clientIndex, UnsecureReceivedDataAsyncCallback);
}
#endregion
#region Methods - EventHelpers/Callbacks
//Private Helper method to call the Connection Change Event
void onConnectionChange()
{
var handler = ClientConnectionChange;
if (handler != null)
{
if (Secure)
handler(this, new DynamicTCPSocketStatusChangeEventArgs(SecureServer, Secure));
else
handler(this, new DynamicTCPSocketStatusChangeEventArgs(UnsecureServer, Secure));
}
}
//Private Helper Method to call the Text Received Event
void onTextReceived(string text)
{
var handler = TextReceived;
if (handler != null)
handler(this, new CopyCoreForSimplpGenericCommMethodReceiveTextArgs(text));
}
//Private Helper Method to call the Server State Change Event
void onServerStateChange()
{
var handler = ServerStateChange;
if(handler != null)
{
if(Secure)
handler(this, new DynamicTCPServerStateChangedEventArgs(SecureServer, Secure));
else
handler(this, new DynamicTCPServerStateChangedEventArgs(UnsecureServer, Secure));
}
}
//Private Event Handler method to handle the closing of connections when the program stops
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType == eProgramStatusEventType.Stopping)
{
Debug.Console(1, this, "Program stopping. Closing server");
DisconnectAllClients();
StopListening();
}
}
#endregion
}
}

View file

@ -1,104 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core
{
/// <summary>
/// Background class that manages debug features for sockets
/// </summary>
public static class CommStatic
{
static List<ISocketStatus> Sockets = new List<ISocketStatus>();
/// <summary>
/// Sets up the backing class. Adds console commands for S#Pro programs
/// </summary>
static CommStatic()
{
if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro)
{
CrestronConsole.AddNewConsoleCommand(SocketCommand, "socket", "socket commands: list, send, connect, disco",
ConsoleAccessLevelEnum.AccessOperator);
}
}
static void SocketCommand(string s)
{
// 0 1 2
//socket command number/key/all param
//socket list
//socket send 4 ver -v\n
if (string.IsNullOrEmpty(s))
return;
var tokens = s.Split(' ');
if (tokens.Length == 0)
return;
var command = tokens[0].ToLower();
if(command == "connect")
{
}
else if(command == "disco")
{
}
else if(command =="list")
{
CrestronConsole.ConsoleCommandResponse("{0} sockets", Sockets.Count);
if(Sockets.Count == 0)
return;
// get the longest key name, for formatting
var longestLength = Sockets.Aggregate("",
(max, cur) => max.Length > cur.Key.Length ? max : cur.Key).Length;
for(int i = 0; i < Sockets.Count; i++)
{
var sock = Sockets[i];
CrestronConsole.ConsoleCommandResponse("{0} {1} {2} {3}",
i, sock.Key, GetSocketType(sock), sock.ClientStatus);
}
}
else if(command == "send")
{
}
}
/// <summary>
/// Helper for socket list, to show types
/// </summary>
static string GetSocketType(ISocketStatus sock)
{
if (sock is GenericSshClient)
return "SSH";
else if (sock is GenericTcpIpClient)
return "TCP-IP";
else
return "?";
}
/// <summary>
///
/// </summary>
/// <param name="socket"></param>
public static void AddSocket(ISocketStatus socket)
{
if(!Sockets.Contains(socket))
Sockets.Add(socket);
}
/// <summary>
///
/// </summary>
/// <param name="socket"></param>
public static void RemoveSocket(ISocketStatus socket)
{
if (Sockets.Contains(socket))
Sockets.Remove(socket);
}
}
}

View file

@ -1,314 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Net.Http;
namespace PepperDash.Core
{
/// <summary>
/// Client for communicating with an HTTP Server Side Event pattern
/// </summary>
public class GenericHttpSseClient : ICommunicationReceiver
{
/// <summary>
/// Notifies when bytes have been received
/// </summary>
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
/// <summary>
/// Notifies when text has been received
/// </summary>
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
/// <summary>
/// Indicates connection status
/// </summary>
public bool IsConnected
{
get;
private set;
}
/// <summary>
/// Unique identifier for the instance
/// </summary>
public string Key
{
get;
private set;
}
/// <summary>
/// Name for the instance
/// </summary>
public string Name
{
get;
private set;
}
/// <summary>
/// URL of the server
/// </summary>
public string Url { get; set; }
HttpClient Client;
HttpClientRequest Request;
/// <summary>
/// Constructor
/// </summary>
/// <param name="key"></param>
/// <param name="name"></param>
public GenericHttpSseClient(string key, string name)
{
Key = key;
Name = name;
}
/// <summary>
/// Connects to the server. Requires Url to be set first.
/// </summary>
public void Connect()
{
InitiateConnection(Url);
}
/// <summary>
/// Disconnects from the server
/// </summary>
public void Disconnect()
{
CloseConnection(null);
}
/// <summary>
/// Initiates connection to the server
/// </summary>
/// <param name="url"></param>
public void InitiateConnection(string url)
{
CrestronInvoke.BeginInvoke(o =>
{
try
{
if(string.IsNullOrEmpty(url))
{
Debug.Console(0, this, "Error connecting to Server. No URL specified");
return;
}
Client = new HttpClient();
Request = new HttpClientRequest();
Client.Verbose = true;
Client.KeepAlive = true;
Request.Url.Parse(url);
Request.RequestType = RequestType.Get;
Request.Header.SetHeaderValue("Accept", "text/event-stream");
// In order to get a handle on the response stream, we have to get
// the request stream first. Boo
Client.BeginGetRequestStream(GetRequestStreamCallback, Request, null);
CrestronConsole.PrintLine("Request made!");
}
catch (Exception e)
{
ErrorLog.Notice("Exception occured in AsyncWebPostHttps(): " + e.ToString());
}
});
}
/// <summary>
/// Closes the connection to the server
/// </summary>
/// <param name="s"></param>
public void CloseConnection(string s)
{
if (Client != null)
{
Client.Abort();
IsConnected = false;
Debug.Console(1, this, "Client Disconnected");
}
}
private void GetRequestStreamCallback(HttpClientRequest request, HTTP_CALLBACK_ERROR error, object status)
{
try
{
// End the the async request operation and return the data stream
Stream requestStream = request.ThisClient.EndGetRequestStream(request, null);
// If this were something other than a GET we could write to the stream here
// Closing makes the request happen
requestStream.Close();
// Get a handle on the response stream.
request.ThisClient.BeginGetResponseStream(GetResponseStreamCallback, request, status);
}
catch (Exception e)
{
ErrorLog.Notice("Exception occured in GetSecureRequestStreamCallback(): " + e.ToString());
}
}
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="error"></param>
/// <param name="status"></param>
private void GetResponseStreamCallback(HttpClientRequest request, HTTP_CALLBACK_ERROR error, object status)
{
try
{
// This closes up the GetResponseStream async
var response = request.ThisClient.EndGetResponseStream(request);
response.DataConnection.OnBytesReceived += new EventHandler(DataConnection_OnBytesReceived);
IsConnected = true;
Debug.Console(1, this, "Client Disconnected");
Stream streamResponse = response.ContentStream;
// Object containing various states to be passed back to async callback below
RequestState asyncState = new RequestState();
asyncState.Request = request;
asyncState.Response = response;
asyncState.StreamResponse = streamResponse;
asyncState.HttpClient = request.ThisClient;
// This processes the ongoing data stream
Crestron.SimplSharp.CrestronIO.IAsyncResult asyncResult = null;
do
{
asyncResult = streamResponse.BeginRead(asyncState.BufferRead, 0, RequestState.BUFFER_SIZE,
new Crestron.SimplSharp.CrestronIO.AsyncCallback(ReadCallBack), asyncState);
}
while (asyncResult.CompletedSynchronously && !asyncState.Done);
//Console.WriteLine("\r\nExit Response Callback\r\n");
}
catch (Exception e)
{
ErrorLog.Notice("Exception occured in GetSecureRequestStreamCallback(): " + e.ToString());
}
}
void DataConnection_OnBytesReceived(object sender, EventArgs e)
{
Debug.Console(1, this, "DataConnection OnBytesReceived Fired");
}
private void ReadCallBack(Crestron.SimplSharp.CrestronIO.IAsyncResult asyncResult)
{
//we are getting back everything here, so cast the state from the call
RequestState requestState = asyncResult.AsyncState as RequestState;
Stream responseStream = requestState.StreamResponse;
int read = responseStream.EndRead(asyncResult);
// Read the HTML page and then print it to the console.
if (read > 0)
{
var bytes = requestState.BufferRead;
var bytesHandler = BytesReceived;
if (bytesHandler != null)
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
var textHandler = TextReceived;
if (textHandler != null)
{
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
}
//requestState.RequestData.Append(Encoding.ASCII.GetString(requestState.BufferRead, 0, read));
//CrestronConsole.PrintLine(requestState.RequestData.ToString());
//clear the byte array buffer used.
Array.Clear(requestState.BufferRead, 0, requestState.BufferRead.Length);
if (asyncResult.CompletedSynchronously)
{
return;
}
Crestron.SimplSharp.CrestronIO.IAsyncResult asynchronousResult;
do
{
asynchronousResult = responseStream.BeginRead(requestState.BufferRead, 0, RequestState.BUFFER_SIZE,
new Crestron.SimplSharp.CrestronIO.AsyncCallback(ReadCallBack), requestState);
}
while (asynchronousResult.CompletedSynchronously && !requestState.Done);
}
else
{
requestState.Done = true;
}
}
}
/// <summary>
/// Stores the state of the request
/// </summary>
public class RequestState
{
/// <summary>
///
/// </summary>
public const int BUFFER_SIZE = 10000;
/// <summary>
///
/// </summary>
public byte[] BufferRead;
/// <summary>
///
/// </summary>
public HttpClient HttpClient;
/// <summary>
///
/// </summary>
public HttpClientRequest Request;
/// <summary>
///
/// </summary>
public HttpClientResponse Response;
/// <summary>
///
/// </summary>
public Stream StreamResponse;
/// <summary>
///
/// </summary>
public bool Done;
/// <summary>
/// Constructor
/// </summary>
public RequestState()
{
BufferRead = new byte[BUFFER_SIZE];
HttpClient = null;
Request = null;
Response = null;
StreamResponse = null;
Done = false;
}
}
/// <summary>
/// Waithandle for main thread.
/// </summary>
public class StreamAsyncTest
{
/// <summary>
///
/// </summary>
public CEvent wait_for_response = new CEvent(true, false);
}
}

View file

@ -1,351 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core
{
/// <summary>
/// Allows for two simultaneous TCP clients to connect to a redundant pair of QSC Core DSPs and manages
/// </summary>
public class QscCoreDoubleTcpIpClient : IKeyed
{
/// <summary>
/// Key to uniquely identify the instance of the class
/// </summary>
public string Key { get; private set; }
/// <summary>
/// Fires when a bool value changes to notify the S+ module
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Fires when a ushort value changes to notify the S+ module
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UshortChange;
/// <summary>
/// Fires when a string value changes to notify the S+ module
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// The client for the master DSP unit
/// </summary>
public GenericTcpIpClient MasterClient { get; private set; }
/// <summary>
/// The client for the slave DSP unit
/// </summary>
public GenericTcpIpClient SlaveClient { get; private set; }
string Username;
string Password;
string LineEnding;
CommunicationGather MasterGather;
CommunicationGather SlaveGather;
bool IsPolling;
int PollingIntervalSeconds;
CTimer PollTimer;
bool SlaveIsActive;
/// <summary>
/// Default constuctor for S+
/// </summary>
public QscCoreDoubleTcpIpClient()
{
MasterClient = new GenericTcpIpClient("temp-master");
MasterClient.AutoReconnect = true;
MasterClient.AutoReconnectIntervalMs = 2000;
SlaveClient = new GenericTcpIpClient("temp-slave");
SlaveClient.AutoReconnect = true;
SlaveClient.AutoReconnectIntervalMs = 2000;
}
/// <summary>
/// Connects to both DSP units
/// </summary>
/// <param name="key"></param>
/// <param name="masterAddress"></param>
/// <param name="masterPort"></param>
/// <param name="slaveAddress"></param>
/// <param name="slavePort"></param>
/// <param name="username"></param>
/// <param name="password"></param>
/// <param name="pollingIntervalSeconds"></param>
/// <param name="lineEnding"></param>
public void Connect(string key, string masterAddress, int masterPort,
string slaveAddress, int slavePort, string username, string password,
int pollingIntervalSeconds, string lineEnding)
{
Key = key;
PollingIntervalSeconds = pollingIntervalSeconds;
Username = username;
Password = password;
LineEnding = lineEnding;
MasterClient.Initialize(key + "-master");
SlaveClient.Initialize(key + "-slave");
MasterClient.Hostname = masterAddress;
MasterClient.Port = masterPort;
if (MasterClient != null)
{
MasterClient.Disconnect();
}
if (SlaveClient != null)
{
SlaveClient.Disconnect();
}
if (MasterGather == null)
{
MasterGather = new CommunicationGather(MasterClient, lineEnding);
MasterGather.IncludeDelimiter = true;
}
MasterGather.LineReceived -= MasterGather_LineReceived;
MasterGather.LineReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(MasterGather_LineReceived);
MasterClient.ConnectionChange -= MasterClient_SocketStatusChange;
MasterClient.ConnectionChange += MasterClient_SocketStatusChange;
SlaveClient.Hostname = slaveAddress;
SlaveClient.Port = slavePort;
if (SlaveGather == null)
{
SlaveGather = new CommunicationGather(SlaveClient, lineEnding);
SlaveGather.IncludeDelimiter = true;
}
SlaveGather.LineReceived -= MasterGather_LineReceived;
SlaveGather.LineReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(SlaveGather_LineReceived);
SlaveClient.ConnectionChange -= SlaveClient_SocketStatusChange;
SlaveClient.ConnectionChange += SlaveClient_SocketStatusChange;
MasterClient.Connect();
SlaveClient.Connect();
}
/// <summary>
///
/// </summary>
public void Disconnect()
{
if (MasterClient != null)
{
MasterGather.LineReceived -= MasterGather_LineReceived;
MasterClient.Disconnect();
}
if (SlaveClient != null)
{
SlaveGather.LineReceived -= SlaveGather_LineReceived;
SlaveClient.Disconnect();
}
if (PollTimer != null)
{
IsPolling = false;
PollTimer.Stop();
PollTimer = null;
}
}
/// <summary>
/// Does not include line feed
/// </summary>
public void SendText(string s)
{
if (SlaveIsActive)
{
if (SlaveClient != null)
{
Debug.Console(2, this, "Sending to Slave: {0}", s);
SlaveClient.SendText(s);
}
}
else
{
if (MasterClient != null)
{
Debug.Console(2, this, "Sending to Master: {0}", s);
MasterClient.SendText(s);
}
}
}
void MasterClient_SocketStatusChange(object sender, GenericSocketStatusChageEventArgs args)
{
OnUshortChange((ushort)args.Client.ClientStatus, MasterClientStatusId);
if (args.Client.IsConnected)
{
MasterGather.LineReceived += MasterGather_LineReceived;
StartPolling();
}
else
MasterGather.LineReceived -= MasterGather_LineReceived;
}
void SlaveClient_SocketStatusChange(object sender, GenericSocketStatusChageEventArgs args)
{
OnUshortChange((ushort)args.Client.ClientStatus, SlaveClientStatusId);
if (args.Client.IsConnected)
{
SlaveGather.LineReceived += SlaveGather_LineReceived;
StartPolling();
}
else
SlaveGather.LineReceived -= SlaveGather_LineReceived;
}
void MasterGather_LineReceived(object sender, GenericCommMethodReceiveTextArgs e)
{
if (e.Text.Contains("login_required"))
{
MasterClient.SendText(string.Format("login {0} {1} \x0d\x0a", Username, Password));
}
else if (e.Text.Contains("login_success"))
{
// START THE POLLING, YO!
}
else if (e.Text.StartsWith("sr"))
{
// example response "sr "MyDesign" "NIEC2bxnVZ6a" 1 1"
var split = e.Text.Trim().Split(' ');
if (split[split.Length - 1] == "1")
{
SlaveIsActive = false;
OnBoolChange(false, SlaveIsActiveId);
OnBoolChange(true, MasterIsActiveId);
}
}
if (!SlaveIsActive)
OnStringChange(e.Text, LineReceivedId);
}
void SlaveGather_LineReceived(object sender, GenericCommMethodReceiveTextArgs e)
{
if (e.Text.Contains("login_required"))
{
SlaveClient.SendText(string.Format("login {0} {1} \x0d\x0a", Username, Password));
}
else if (e.Text.Contains("login_success"))
{
// START THE POLLING, YO!
}
else if (e.Text.StartsWith("sr"))
{
var split = e.Text.Trim().Split(' ');
if (split[split.Length - 1] == "1")
{
SlaveIsActive = true;
OnBoolChange(true, SlaveIsActiveId);
OnBoolChange(false, MasterIsActiveId);
}
}
if (SlaveIsActive)
OnStringChange(e.Text, LineReceivedId);
}
void StartPolling()
{
if (!IsPolling)
{
IsPolling = true;
Poll();
if (PollTimer != null)
PollTimer.Stop();
PollTimer = new CTimer(o => Poll(), null, PollingIntervalSeconds * 1000, PollingIntervalSeconds * 1000);
}
}
void Poll()
{
if (MasterClient != null && MasterClient.IsConnected)
{
Debug.Console(2, this, "Polling Master.");
MasterClient.SendText("sg\x0d\x0a");
}
if (SlaveClient != null && SlaveClient.IsConnected)
{
Debug.Console(2, this, "Polling Slave.");
SlaveClient.SendText("sg\x0d\x0a");
}
}
// login NAME PIN ---> login_success, login_failed
// status get
// sg --> sr DESIGN_NAME DESIGN_ID IS_PRIMARY IS_ACTIVE
// CRLF
void OnBoolChange(bool state, ushort type)
{
var handler = BoolChange;
if (handler != null)
handler(this, new BoolChangeEventArgs(state, type));
}
void OnUshortChange(ushort state, ushort type)
{
var handler = UshortChange;
if (handler != null)
handler(this, new UshrtChangeEventArgs(state, type));
}
void OnStringChange(string value, ushort type)
{
var handler = StringChange;
if (handler != null)
handler(this, new StringChangeEventArgs(value, type));
}
/// <summary>
///
/// </summary>
public const ushort MasterIsActiveId = 3;
/// <summary>
///
/// </summary>
public const ushort SlaveIsActiveId = 4;
/// <summary>
///
/// </summary>
public const ushort MainModuleInitiailzeId = 5;
/// <summary>
///
/// </summary>
public const ushort MasterClientStatusId = 101;
/// <summary>
///
/// </summary>
public const ushort SlaveClientStatusId = 102;
/// <summary>
///
/// </summary>
public const ushort LineReceivedId = 201;
}
}

View file

@ -1,20 +0,0 @@
//using System;
////using System.IO;
//using System.Collections.Generic;
//using System.Linq;
//using System.Text;
//using Crestron.SimplSharp;
//using Crestron.SimplSharp.CrestronIO;
//using Newtonsoft.Json;
//using Newtonsoft.Json.Linq;
//namespace PepperDash.Core.JsonToSimpl
//{
// public class JsonToSimplFixedPathObject : JsonToSimplChildObjectBase
// {
// public JsonToSimplFixedPathObject()
// {
// }
// }
//}

View file

@ -1,149 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement
{
// Example JSON password array configuration object
//{
// "global":{
// "passwords":[
// {
// "key": "Password01",
// "name": "Technician Password",
// "enabled": true,
// "password": "1988"
// }
// ]
// }
//}
/// <summary>
/// JSON password array configuration object
/// </summary>
//public class PasswordConfig
//{
// /// <summary>
// /// Key used to search for object in JSON array
// /// </summary>
// public string key { get; set; }
// /// <summary>
// /// Friendly name of password object
// /// </summary>
// public string name { get; set; }
// /// <summary>
// /// Password object enabled
// /// </summary>
// public bool enabled { get; set; }
// /// <summary>
// ///
// /// </summary>
// public ushort simplEnabled
// {
// get { return (ushort)(enabled ? 1 : 0); }
// set { enabled = Convert.ToBoolean(value); }
// }
// /// <summary>
// /// Password object configured password
// /// </summary>
// public string password { get; set; }
// /// <summary>
// /// Password type
// /// </summary>
// private int type { get; set; }
// /// <summary>
// /// Password Type for S+
// /// </summary>
// public ushort simplType
// {
// get { return Convert.ToUInt16(type); }
// set { type = value; }
// }
// /// <summary>
// /// Password path
// /// **FUTURE** implementation of saving passwords recieved from Fusion or other external sources back to config
// /// </summary>
// public string path { get; set; }
// /// <summary>
// /// Constructor
// /// </summary>
// public PasswordConfig()
// {
// simplEnabled = 0;
// simplType = 0;
// }
//}
// Example JSON password collections configuration object
//{
// "global": {
// "passwords": {
// "1": {
// "name": "Technician Password",
// "password": "2468"
// },
// "2": {
// "name": "System Password",
// "password": "123456"
// },
// "3": {
// "name": "Master Password",
// "password": "abc123"
// },
// "5": {
// "name": "Backdoor Password",
// "password": "1988"
// },
// "10": {
// "name": "Backdoor Password",
// "password": "1988"
// }
// }
// }
//}
/// <summary>
/// JSON password array configuration object
/// </summary>
public class PasswordConfig
{
/// <summary>
/// Password object configured password
/// </summary>
public string password { get; set; }
/// <summary>
/// Constructor
/// </summary>
public PasswordConfig()
{
}
}
/// <summary>
/// Global JSON object
/// </summary>
//public class GlobalConfig
//{
// //public List<PasswordConfig> passwords { get; set; }
// public Dictionary<uint, PasswordConfig> passwords { get; set; }
// /// <summary>
// /// Constructor
// /// </summary>
// public GlobalConfig()
// {
// }
//}
/// <summary>
/// Root JSON object
/// </summary>
//public class RootObject
//{
// public GlobalConfig global { get; set; }
//}
}

View file

@ -1,207 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement
{
public class PasswordClient
{
/// <summary>
/// Password Client
/// </summary>
public PasswordConfig Client { get; set; }
/// <summary>
/// Used to build the password entered by the user
/// </summary>
public string PasswordToValidate { get; set; }
/// <summary>
/// Boolean event
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Ushort event
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary>
/// String event
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// Constructor
/// </summary>
public PasswordClient()
{
}
/// <summary>
/// Initialize method
/// </summary>
/// <param name="key"></param>
public void Initialize(string key)
{
OnBoolChange(false, 0, PasswordManagementConstants.BoolEvaluatedChange);
Client = new PasswordConfig();
PasswordToValidate = "";
// there has to be a better way to get the index of the current index of password
ushort i = 0;
foreach (var password in PasswordManager.Passwords)
{
i++;
OnUshrtChange((ushort)password.Key, (ushort)password.Key, PasswordManagementConstants.PasswordKey);
}
OnBoolChange(true, 0, PasswordManagementConstants.BoolEvaluatedChange);
}
/// <summary>
/// Retrieves password by key
/// </summary>
/// <param name="key"></param>
//public void GetPasswordByKey(string key)
//{
// if (string.IsNullOrEmpty(key))
// {
// Debug.Console(1, "PassowrdClient.GetPasswordByKey failed:\rKey {0} is null or empty", key);
// return;
// }
// PasswordConfig password = PasswordManager.Passwords.FirstOrDefault(p => p.key.Equals(key));
// if (password == null)
// {
// OnUshrtChange(0, 0, PasswordManagementConstants.SelectedPasswordLength);
// return;
// }
// Client = password;
// OnUshrtChange((ushort)Client.password.Length, 0, PasswordManagementConstants.SelectedPasswordLength);
// OnStringChange(Client.key, 0, PasswordManagementConstants.PasswordKeySelected);
//}
/// <summary>
/// Retrieve password by index
/// </summary>
/// <param name="index"></param>
public void GetPasswordByIndex(ushort key)
{
PasswordConfig pw = PasswordManager.Passwords[key];
if (pw == null)
{
OnUshrtChange(0, 0, PasswordManagementConstants.SelectedPasswordLength);
return;
}
Client = pw;
OnUshrtChange((ushort)Client.password.Length, 0, PasswordManagementConstants.SelectedPasswordLength);
OnUshrtChange(key, 0, PasswordManagementConstants.PasswordKeySelected);
}
/// <summary>
/// Password validation method
/// </summary>
/// <param name="password"></param>
public void ValidatePassword(string password)
{
if (string.IsNullOrEmpty(password))
return;
if (string.Equals(Client.password, password))
{
OnBoolChange(true, 0, PasswordManagementConstants.PasswordIsValid);
}
else
{
OnBoolChange(true, 0, PasswordManagementConstants.PasswordIsInvalid);
}
OnBoolChange(false, 0, PasswordManagementConstants.PasswordIsValid);
OnBoolChange(false, 0, PasswordManagementConstants.PasswordIsInvalid);
ClearPassword();
}
/// <summary>
/// Builds the user entered passwrod string, will attempt to validate the user entered
/// password against the selected password when the length of the 2 are equal
/// </summary>
/// <param name="data"></param>
public void BuildPassword(string data)
{
PasswordToValidate = String.Concat(PasswordToValidate, data);
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedChange);
if (PasswordToValidate.Length == Client.password.Length)
ValidatePassword(PasswordToValidate);
}
/// <summary>
/// Clears the user entered password and resets the LEDs
/// </summary>
public void ClearPassword()
{
PasswordToValidate = "";
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedChange);
for(var i = 1; i <= Client.password.Length; i++)
OnBoolChange(false, (ushort)i, PasswordManagementConstants.PasswordLedChange);
}
/// <summary>
/// Protected boolean change event handler
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnBoolChange(bool state, ushort index, ushort type)
{
var handler = BoolChange;
if (handler != null)
{
var args = new BoolChangeEventArgs(state, type);
args.Index = index;
BoolChange(this, args);
}
}
/// <summary>
/// Protected ushort change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnUshrtChange(ushort value, ushort index, ushort type)
{
var handler = UshrtChange;
if (handler != null)
{
var args = new UshrtChangeEventArgs(value, type);
args.Index = index;
UshrtChange(this, args);
}
}
/// <summary>
/// Protected string change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnStringChange(string value, ushort index, ushort type)
{
var handler = StringChange;
if (handler != null)
{
var args = new StringChangeEventArgs(value, type);
args.Index = index;
StringChange(this, args);
}
}
}
}

View file

@ -1,233 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Crestron.SimplSharp;
using PepperDash.Core.JsonToSimpl;
using PepperDash.Core.JsonStandardObjects;
namespace PepperDash.Core.PasswordManagement
{
public class PasswordManager
{
/// <summary>
/// List of passwords configured
/// </summary>
public static Dictionary<uint, PasswordConfig> Passwords = new Dictionary<uint, PasswordConfig>();
private Dictionary<uint, PasswordConfig> TempPasswords = new Dictionary<uint, PasswordConfig>();
CTimer UpdateTimer;
public long UpdateTimerElapsedMs = 5000;
/// <summary>
/// Boolean event
/// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary>
/// Ushort event
/// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary>
/// String event
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// Constructor
/// </summary>
public PasswordManager()
{
Passwords.Clear();
}
/// <summary>
/// Initialize method
/// </summary>
/// <param name="key"></param>
/// <param name="uniqueId"></param>
//public void Initialize(string uniqueId, string key)
//{
// OnBoolChange(false, 0, PasswordManagementConstants.BoolEvaluatedChange);
// try
// {
// if(string.IsNullOrEmpty(uniqueId) || string.IsNullOrEmpty(key))
// {
// Debug.Console(1, "PasswordManager.Initialize({0}, {1}) null or empty parameters", uniqueId, key);
// return;
// }
// JsonToSimplMaster master = J2SGlobal.GetMasterByFile(uniqueId);
// if(master == null)
// {
// Debug.Console(1, "PassowrdManager.Initialize failed:\rCould not find JSON file with uniqueID {0}", uniqueId);
// return;
// }
// var global = master.JsonObject.ToObject<RootObject>().global;
// var passwords = global.passwords;
// if(passwords == null)
// {
// Debug.Console(1, "PasswordManager.Initialize failed:\rCould not find password object");
// return;
// }
// foreach(var password in passwords)
// {
// if (password != null)
// {
// var index = passwords.IndexOf(password);
// password.path = string.Format("global.passwords[{0}]", index);
// Debug.Console(1, "PasswordManager.Initialize: {0}, {1}, {2}, {3}, {4}, {5}", password.key, password.name, password.simplEnabled, password.simplType, password.password, password.path);
// //AddPassword(password);
// OnStringChange(password.path, (ushort)index, PasswordManagementConstants.FullPathToPassword);
// OnStringChange(password.key, (ushort)index, PasswordManagementConstants.PasswordKey);
// }
// }
// OnUshrtChange(Convert.ToUInt16(Passwords.Count), 0, PasswordManagementConstants.PasswordListCount);
// }
// catch(Exception e)
// {
// var msg = string.Format("PasswordManager.Initialize({0}, {1}) failed:\r{2}", uniqueId, key, e.Message);
// CrestronConsole.PrintLine(msg);
// ErrorLog.Error(msg);
// }
// finally
// {
// OnBoolChange(true, 0, PasswordManagementConstants.BoolEvaluatedChange);
// }
//}
/// <summary>
/// Adds password to the list
/// </summary>
/// <param name="password"></param>
//private void AddPassword(PasswordConfig password)
//{
// if (password == null)
// return;
// var item = Passwords.FirstOrDefault(i => i.key.Equals(password.key));
// if (item != null)
// Passwords.Remove(item);
// Passwords.Add(password);
// Passwords.Sort((x, y) => string.Compare(x.key, y.key));
//}
/// <summary>
/// Removes password from the list
/// </summary>
/// <param name="password"></param>
//private void RemovePassword(PasswordConfig password)
//{
// if (password == null)
// return;
// var item = Passwords.FirstOrDefault(i => i.key.Equals(password.key));
// if (item != null)
// Passwords.Remove(item);
//}
/// <summary>
/// Updates password stored in the dictonary
/// </summary>
/// <param name="uniqueId"></param>
/// <param name="key"></param>
/// <param name="password"></param>
public void UpdatePassword(ushort key, string password)
{
if (string.IsNullOrEmpty(password))
return;
var pw = TempPasswords[key];
if (pw == null)
{
pw = new PasswordConfig();
}
pw.password = password;
if (UpdateTimer == null)
{
// (o) => SavePasswords removes the need to create a callback method that takes in an object
UpdateTimer = new CTimer((o) => StorePassword(), UpdateTimerElapsedMs);
}
else
{
UpdateTimer.Reset();
}
}
/// <summary>
/// Stores the updated passwords in TempPassword in the Passwords dictionary
/// </summary>
private void StorePassword()
{
UpdateTimer.Stop();
foreach (var tempPw in TempPasswords)
{
Passwords[tempPw.Key] = tempPw.Value;
}
TempPasswords.Clear();
}
/// <summary>
/// Protected boolean change event handler
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnBoolChange(bool state, ushort index, ushort type)
{
var handler = BoolChange;
if (handler != null)
{
var args = new BoolChangeEventArgs(state, type);
args.Index = index;
BoolChange(this, args);
}
}
/// <summary>
/// Protected ushort change event handler
/// </summary>
/// <param name="state"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnUshrtChange(ushort value, ushort index, ushort type)
{
var handler = UshrtChange;
if (handler != null)
{
var args = new UshrtChangeEventArgs(value, type);
args.Index = index;
UshrtChange(this, args);
}
}
/// <summary>
/// Protected string change event handler
/// </summary>
/// <param name="value"></param>
/// <param name="index"></param>
/// <param name="type"></param>
protected void OnStringChange(string value, ushort index, ushort type)
{
var handler = StringChange;
if (handler != null)
{
var args = new StringChangeEventArgs(value, type);
args.Index = index;
StringChange(this, args);
}
}
}
}

View file

@ -1,156 +0,0 @@
<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{87E29B4C-569B-4368-A4ED-984AC1440C96}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>PepperDash.Core</RootNamespace>
<AssemblyName>PepperDash_Core</AssemblyName>
<ProjectTypeGuids>{0B4745B0-194B-4BB6-8E21-E9057CA92500};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<PlatformFamilyName>WindowsCE</PlatformFamilyName>
<PlatformID>E2BECB1F-8C8C-41ba-B736-9BE7D946A398</PlatformID>
<OSVersion>5.0</OSVersion>
<DeployDirSuffix>SmartDeviceProject1</DeployDirSuffix>
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
<NativePlatformName>Windows CE</NativePlatformName>
<FormFactorID>
</FormFactorID>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<DocumentationFile>bin\PepperDash_Core.xml</DocumentationFile>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AllowedReferenceRelatedFileExtensions>.allowedReferenceRelatedFileExtensions</AllowedReferenceRelatedFileExtensions>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<FileAlignment>512</FileAlignment>
<NoStdLib>true</NoStdLib>
<NoConfig>true</NoConfig>
<DocumentationFile>bin\PepperDash_Core.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="mscorlib" />
<Reference Include="SimplSharpCustomAttributesInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpCWSHelperInterface, Version=2.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCWSHelperInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpHelperInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll</HintPath>
</Reference>
<Reference Include="SimplSharpNewtonsoft, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpNewtonsoft.dll</HintPath>
</Reference>
<Reference Include="SimplSharpReflectionInterface, Version=1.0.5583.25238, Culture=neutral, PublicKeyToken=1099c178b3b54c3b, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpReflectionInterface.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
</ItemGroup>
<ItemGroup>
<Compile Include="CommunicationExtras.cs" />
<Compile Include="Comm\CommunicationStreamDebugging.cs" />
<Compile Include="Comm\ControlPropertiesConfig.cs" />
<Compile Include="Comm\GenericSecureTcpIpClient.cs" />
<Compile Include="Comm\GenericTcpIpClient_ForServer.cs" />
<Compile Include="Comm\GenericHttpSseClient.cs" />
<Compile Include="Comm\GenericSecureTcpIpServer.cs" />
<Compile Include="Comm\GenericSecureTcpIpClient_ForServer.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Comm\eControlMethods.cs" />
<Compile Include="Comm\FINISH CommStatic.cs" />
<Compile Include="Comm\CommunicationGather.cs" />
<Compile Include="Comm\EventArgs.cs" />
<Compile Include="Comm\GenericSshClient.cs" />
<Compile Include="Comm\GenericUdpServer.cs" />
<Compile Include="Comm\QscCoreDoubleTcpIpClient.cs" />
<Compile Include="Comm\TcpClientConfigObject.cs" />
<Compile Include="Comm\TcpServerConfigObject.cs" />
<Compile Include="Config\PortalConfigReader.cs" />
<Compile Include="CoreInterfaces.cs" />
<Compile Include="Web\RequestHandlers\DefaultRequestHandler.cs" />
<Compile Include="Web\RequestHandlers\WebApiBaseRequestHandler.cs" />
<Compile Include="Web\WebApiServer.cs" />
<Compile Include="EventArgs.cs" />
<Compile Include="GenericRESTfulCommunications\Constants.cs" />
<Compile Include="GenericRESTfulCommunications\GenericRESTfulClient.cs" />
<Compile Include="JsonStandardObjects\EventArgs and Constants.cs" />
<Compile Include="JsonStandardObjects\JsonToSimplDeviceConfig.cs" />
<Compile Include="JsonStandardObjects\JsonToSimplDevice.cs" />
<Compile Include="JsonToSimpl\JsonToSimplPortalFileMaster.cs" />
<Compile Include="Logging\Debug.cs" />
<Compile Include="Logging\DebugContext.cs" />
<Compile Include="Logging\DebugMemory.cs" />
<Compile Include="Device.cs" />
<Compile Include="Comm\GenericTcpIpServer.cs" />
<Compile Include="EthernetHelper.cs" />
<Compile Include="Comm\GenericTcpIpClient.cs" />
<Compile Include="JsonToSimpl\Constants.cs" />
<Compile Include="JsonToSimpl\Global.cs" />
<Compile Include="JsonToSimpl\JsonToSimplArrayLookupChild.cs" />
<Compile Include="JsonToSimpl\JsonToSimplChildObjectBase.cs" />
<Compile Include="JsonToSimpl\JsonToSimplFileMaster.cs" />
<Compile Include="JsonToSimpl\JsonToSimplFixedPathObject.cs" />
<Compile Include="JsonToSimpl\REMOVE JsonToSimplFixedPathObject.cs" />
<Compile Include="JsonToSimpl\JsonToSimplGenericMaster.cs" />
<Compile Include="JsonToSimpl\JsonToSimplMaster.cs" />
<Compile Include="Network\DiscoveryThings.cs" />
<Compile Include="PasswordManagement\Config.cs" />
<Compile Include="PasswordManagement\Constants.cs" />
<Compile Include="PasswordManagement\PasswordClient.cs" />
<Compile Include="PasswordManagement\PasswordManager.cs" />
<Compile Include="SystemInfo\EventArgs and Constants.cs" />
<Compile Include="SystemInfo\SystemInfoConfig.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SystemInfo\SystemInfoToSimpl.cs" />
<Compile Include="WebApi\Presets\Preset.cs" />
<Compile Include="WebApi\Presets\User.cs" />
<Compile Include="WebApi\Presets\WebApiPasscodeClient.cs" />
<Compile Include="XSigUtility\Serialization\IXSigSerialization.cs" />
<Compile Include="XSigUtility\Serialization\XSigSerializationException.cs" />
<Compile Include="XSigUtility\Tokens\XSigAnalogToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigDigitalToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigSerialToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigToken.cs" />
<Compile Include="XSigUtility\Tokens\XSigTokenType.cs" />
<Compile Include="XSigUtility\XSigHelpers.cs" />
<Compile Include="XSigUtility\XSigTokenStreamReader.cs" />
<Compile Include="XSigUtility\XSigTokenStreamWriter.cs" />
<None Include="Properties\ControlSystem.cfg" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CompactFramework.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
</VisualStudio>
</ProjectExtensions>
<PropertyGroup>
<PostBuildEvent>rem S# preparation will execute after these operations</PostBuildEvent>
<PreBuildEvent>del "$(TargetDir)PepperDash_Core.*" /q
</PreBuildEvent>
</PropertyGroup>
</Project>

View file

@ -1,3 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=CrestronWebServer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=Web/@EntryIndexedValue">False</s:Boolean></wpf:ResourceDictionary>

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package >
<metadata>
<id>PepperDashCore</id>
<version>1.0.37</version>
<title>PepperDash Core</title>
<authors>PepperDash Technologies</authors>
<owners>pepperdash</owners>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="expression">MIT</license>
<projectUrl>https://github.com/PepperDash/PepperDashCore</projectUrl>
<copyright>Copyright 2020</copyright>
<description>PepperDash Core is an open source Crestron SIMPL# library that can be used in SIMPL# Pro applications such as Essentials or as a standalone library with SIMPL+ wrappers to expose functionality in SIMPL Windows programs.</description>
<tags>crestron 3series 4series</tags>
<repository type="git" url="https://github.com/PepperDash/PepperDashCore"/>
</metadata>
<files>
<file src="**" target="lib\net35"/>
<file src="**" target="lib\net47"/>
</files>
</package>

View file

@ -1,7 +0,0 @@
[assembly: System.Reflection.AssemblyTitle("Pepperdash_Core")]
[assembly: System.Reflection.AssemblyCompany("PepperDash Technology Corp")]
[assembly: System.Reflection.AssemblyProduct("Pepperdash_Core")]
[assembly: System.Reflection.AssemblyCopyright("Copyright © PepperDash 2019")]
[assembly: System.Reflection.AssemblyVersion("1.0.0.*")]
[assembly: System.Reflection.AssemblyInformationalVersion("0.0.0-buildType-buildNumber")]
[assembly: Crestron.SimplSharp.Reflection.AssemblyInformationalVersion("0.0.0-buildType-buildNumber")]

View file

@ -1,11 +0,0 @@
using System.Reflection;
[assembly: AssemblyTitle("Pepperdash_Core")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Pepperdash_Core")]
[assembly: AssemblyCopyright("Copyright © PepperDash 2016")]
<<<<<<< HEAD
[assembly: AssemblyVersion("1.0.2.*")]
=======
[assembly: AssemblyVersion("1.0.3.*")]
>>>>>>> e16c2cbee87c631bf84ad9634bfbc25bbec78a31

View file

@ -1,36 +0,0 @@
function Update-SourceVersion
{
Param ([string]$Version)
$NewVersion = AssemblyVersion(" + $Version + .*");
foreach ($o in $input)
{
Write-output $o.FullName
$TmpFile = $o.FullName + .tmp
get-content $o.FullName |
%{$_ -replace AssemblyVersion\("(\d+\.\d+\.\d+)\.\*"\), $NewVersion } > $TmpFile
move-item $TmpFile $o.FullName -force
}
}
function Update-AllAssemblyInfoFiles ( $version )
{
foreach ($file in AssemblyInfo.cs, AssemblyInfo.vb )
{
get-childitem -recurse |? {$_.Name -eq $file} | Update-SourceVersion $version ;
}
}
# validate arguments
$r= [System.Text.RegularExpressions.Regex]::Match($args[0], "^\d+\.\d+\.\d+$");
if ($r.Success)
{
echo "Updating Assembly Version...";
Update-AllAssemblyInfoFiles $args[0];
}
else
{
echo ;
echo Error: Input version does not match x.y.z format!
echo ;
echo "Unable to apply version to AssemblyInfo.cs files";
}

View file

@ -1,179 +1,179 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using PepperDash.Core; using PepperDash.Core;
namespace PepperDash.Core namespace PepperDash.Core
{ {
/// <summary> /// <summary>
/// Defines the string event handler for line events on the gather /// Defines the string event handler for line events on the gather
/// </summary> /// </summary>
/// <param name="text"></param> /// <param name="text"></param>
public delegate void LineReceivedHandler(string text); public delegate void LineReceivedHandler(string text);
/// <summary> /// <summary>
/// Attaches to IBasicCommunication as a text gather /// Attaches to IBasicCommunication as a text gather
/// </summary> /// </summary>
public class CommunicationGather public class CommunicationGather
{ {
/// <summary> /// <summary>
/// Event that fires when a line is received from the IBasicCommunication source. /// Event that fires when a line is received from the IBasicCommunication source.
/// The event merely contains the text, not an EventArgs type class. /// The event merely contains the text, not an EventArgs type class.
/// </summary> /// </summary>
public event EventHandler<GenericCommMethodReceiveTextArgs> LineReceived; public event EventHandler<GenericCommMethodReceiveTextArgs> LineReceived;
/// <summary> /// <summary>
/// The communication port that this gathers on /// The communication port that this gathers on
/// </summary> /// </summary>
public ICommunicationReceiver Port { get; private set; } public ICommunicationReceiver Port { get; private set; }
/// <summary> /// <summary>
/// Default false. If true, the delimiter will be included in the line output /// Default false. If true, the delimiter will be included in the line output
/// events /// events
/// </summary> /// </summary>
public bool IncludeDelimiter { get; set; } public bool IncludeDelimiter { get; set; }
/// <summary> /// <summary>
/// For receive buffer /// For receive buffer
/// </summary> /// </summary>
StringBuilder ReceiveBuffer = new StringBuilder(); StringBuilder ReceiveBuffer = new StringBuilder();
/// <summary> /// <summary>
/// Delimiter, like it says! /// Delimiter, like it says!
/// </summary> /// </summary>
char Delimiter; char Delimiter;
string[] StringDelimiters; string[] StringDelimiters;
/// <summary> /// <summary>
/// Constructor for using a char delimiter /// Constructor for using a char delimiter
/// </summary> /// </summary>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="delimiter"></param> /// <param name="delimiter"></param>
public CommunicationGather(ICommunicationReceiver port, char delimiter) public CommunicationGather(ICommunicationReceiver port, char delimiter)
{ {
Port = port; Port = port;
Delimiter = delimiter; Delimiter = delimiter;
port.TextReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(Port_TextReceived); port.TextReceived += new EventHandler<GenericCommMethodReceiveTextArgs>(Port_TextReceived);
} }
/// <summary> /// <summary>
/// Constructor for using a single string delimiter /// Constructor for using a single string delimiter
/// </summary> /// </summary>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="delimiter"></param> /// <param name="delimiter"></param>
public CommunicationGather(ICommunicationReceiver port, string delimiter) public CommunicationGather(ICommunicationReceiver port, string delimiter)
:this(port, new string[] { delimiter} ) :this(port, new string[] { delimiter} )
{ {
} }
/// <summary> /// <summary>
/// Constructor for using an array of string delimiters /// Constructor for using an array of string delimiters
/// </summary> /// </summary>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="delimiters"></param> /// <param name="delimiters"></param>
public CommunicationGather(ICommunicationReceiver port, string[] delimiters) public CommunicationGather(ICommunicationReceiver port, string[] delimiters)
{ {
Port = port; Port = port;
StringDelimiters = delimiters; StringDelimiters = delimiters;
port.TextReceived += Port_TextReceivedStringDelimiter; port.TextReceived += Port_TextReceivedStringDelimiter;
} }
/// <summary> /// <summary>
/// Disconnects this gather from the Port's TextReceived event. This will not fire LineReceived /// Disconnects this gather from the Port's TextReceived event. This will not fire LineReceived
/// after the this call. /// after the this call.
/// </summary> /// </summary>
public void Stop() public void Stop()
{ {
Port.TextReceived -= Port_TextReceived; Port.TextReceived -= Port_TextReceived;
Port.TextReceived -= Port_TextReceivedStringDelimiter; Port.TextReceived -= Port_TextReceivedStringDelimiter;
} }
/// <summary> /// <summary>
/// Handler for raw data coming from port /// Handler for raw data coming from port
/// </summary> /// </summary>
void Port_TextReceived(object sender, GenericCommMethodReceiveTextArgs args) void Port_TextReceived(object sender, GenericCommMethodReceiveTextArgs args)
{ {
var handler = LineReceived; var handler = LineReceived;
if (handler != null) if (handler != null)
{ {
ReceiveBuffer.Append(args.Text); ReceiveBuffer.Append(args.Text);
var str = ReceiveBuffer.ToString(); var str = ReceiveBuffer.ToString();
var lines = str.Split(Delimiter); var lines = str.Split(Delimiter);
if (lines.Length > 0) if (lines.Length > 0)
{ {
for (int i = 0; i < lines.Length - 1; i++) for (int i = 0; i < lines.Length - 1; i++)
{ {
string strToSend = null; string strToSend = null;
if (IncludeDelimiter) if (IncludeDelimiter)
strToSend = lines[i] + Delimiter; strToSend = lines[i] + Delimiter;
else else
strToSend = lines[i]; strToSend = lines[i];
handler(this, new GenericCommMethodReceiveTextArgs(strToSend)); handler(this, new GenericCommMethodReceiveTextArgs(strToSend));
} }
ReceiveBuffer = new StringBuilder(lines[lines.Length - 1]); ReceiveBuffer = new StringBuilder(lines[lines.Length - 1]);
} }
} }
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="args"></param> /// <param name="args"></param>
void Port_TextReceivedStringDelimiter(object sender, GenericCommMethodReceiveTextArgs args) void Port_TextReceivedStringDelimiter(object sender, GenericCommMethodReceiveTextArgs args)
{ {
var handler = LineReceived; var handler = LineReceived;
if (handler != null) if (handler != null)
{ {
// Receive buffer should either be empty or not contain the delimiter // Receive buffer should either be empty or not contain the delimiter
// If the line does not have a delimiter, append the // If the line does not have a delimiter, append the
ReceiveBuffer.Append(args.Text); ReceiveBuffer.Append(args.Text);
var str = ReceiveBuffer.ToString(); var str = ReceiveBuffer.ToString();
// Case: Receiving DEVICE get version\x0d\0x0a+OK "value":"1234"\x0d\x0a // Case: Receiving DEVICE get version\x0d\0x0a+OK "value":"1234"\x0d\x0a
// RX: DEV // RX: DEV
// Split: (1) "DEV" // Split: (1) "DEV"
// RX: I // RX: I
// Split: (1) "DEVI" // Split: (1) "DEVI"
// RX: CE get version // RX: CE get version
// Split: (1) "DEVICE get version" // Split: (1) "DEVICE get version"
// RX: \x0d\x0a+OK "value":"1234"\x0d\x0a // RX: \x0d\x0a+OK "value":"1234"\x0d\x0a
// Split: (2) DEVICE get version, +OK "value":"1234" // Split: (2) DEVICE get version, +OK "value":"1234"
// Iterate the delimiters and fire an event for any matching delimiter // Iterate the delimiters and fire an event for any matching delimiter
foreach (var delimiter in StringDelimiters) foreach (var delimiter in StringDelimiters)
{ {
var lines = Regex.Split(str, delimiter); var lines = Regex.Split(str, delimiter);
if (lines.Length == 1) if (lines.Length == 1)
continue; continue;
for (int i = 0; i < lines.Length - 1; i++) for (int i = 0; i < lines.Length - 1; i++)
{ {
string strToSend = null; string strToSend = null;
if (IncludeDelimiter) if (IncludeDelimiter)
strToSend = lines[i] + delimiter; strToSend = lines[i] + delimiter;
else else
strToSend = lines[i]; strToSend = lines[i];
handler(this, new GenericCommMethodReceiveTextArgs(strToSend, delimiter)); handler(this, new GenericCommMethodReceiveTextArgs(strToSend, delimiter));
} }
ReceiveBuffer = new StringBuilder(lines[lines.Length - 1]); ReceiveBuffer = new StringBuilder(lines[lines.Length - 1]);
} }
} }
} }
/// <summary> /// <summary>
/// Deconstructor. Disconnects from port TextReceived events. /// Deconstructor. Disconnects from port TextReceived events.
/// </summary> /// </summary>
~CommunicationGather() ~CommunicationGather()
{ {
Stop(); Stop();
} }
} }
} }

View file

@ -1,9 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace PepperDash.Core namespace PepperDash.Core
{ {
@ -15,38 +13,44 @@ namespace PepperDash.Core
/// <summary> /// <summary>
/// The method of control /// The method of control
/// </summary> /// </summary>
[JsonProperty("method")]
[JsonConverter(typeof(StringEnumConverter))]
public eControlMethod Method { get; set; } public eControlMethod Method { get; set; }
/// <summary> /// <summary>
/// The key of the device that contains the control port /// The key of the device that contains the control port
/// </summary> /// </summary>
[JsonProperty("controlPortDevKey", NullValueHandling = NullValueHandling.Ignore)]
public string ControlPortDevKey { get; set; } public string ControlPortDevKey { get; set; }
/// <summary> /// <summary>
/// The number of the control port on the device specified by ControlPortDevKey /// The number of the control port on the device specified by ControlPortDevKey
/// </summary> /// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value [JsonProperty("controlPortNumber", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value
public uint ControlPortNumber { get; set; } public uint? ControlPortNumber { get; set; }
/// <summary> /// <summary>
/// The name of the control port on the device specified by ControlPortDevKey /// The name of the control port on the device specified by ControlPortDevKey
/// </summary> /// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value [JsonProperty("controlPortName", NullValueHandling = NullValueHandling.Ignore)] // In case "null" is present in config on this value
public string ControlPortName { get; set; } public string ControlPortName { get; set; }
/// <summary> /// <summary>
/// Properties for ethernet based communications /// Properties for ethernet based communications
/// </summary> /// </summary>
[JsonProperty("tcpSshProperties", NullValueHandling = NullValueHandling.Ignore)]
public TcpSshPropertiesConfig TcpSshProperties { get; set; } public TcpSshPropertiesConfig TcpSshProperties { get; set; }
/// <summary> /// <summary>
/// The filename and path for the IR file /// The filename and path for the IR file
/// </summary> /// </summary>
[JsonProperty("irFile", NullValueHandling = NullValueHandling.Ignore)]
public string IrFile { get; set; } public string IrFile { get; set; }
/// <summary> /// <summary>
/// The IpId of a Crestron device /// The IpId of a Crestron device
/// </summary> /// </summary>
[JsonProperty("ipId", NullValueHandling = NullValueHandling.Ignore)]
public string IpId { get; set; } public string IpId { get; set; }
/// <summary> /// <summary>
@ -58,29 +62,32 @@ namespace PepperDash.Core
/// <summary> /// <summary>
/// Char indicating end of line /// Char indicating end of line
/// </summary> /// </summary>
[JsonProperty("endOfLineChar", NullValueHandling = NullValueHandling.Ignore)]
public char EndOfLineChar { get; set; } public char EndOfLineChar { get; set; }
/// <summary> /// <summary>
/// Defaults to Environment.NewLine; /// Defaults to Environment.NewLine;
/// </summary> /// </summary>
[JsonProperty("endOfLineString", NullValueHandling = NullValueHandling.Ignore)]
public string EndOfLineString { get; set; } public string EndOfLineString { get; set; }
/// <summary> /// <summary>
/// Indicates /// Indicates
/// </summary> /// </summary>
[JsonProperty("deviceReadyResponsePattern", NullValueHandling = NullValueHandling.Ignore)]
public string DeviceReadyResponsePattern { get; set; } public string DeviceReadyResponsePattern { get; set; }
/// <summary> /// <summary>
/// Used when communcating to programs running in VC-4 /// Used when communcating to programs running in VC-4
/// </summary> /// </summary>
[JsonProperty("roomId", NullValueHandling = NullValueHandling.Ignore)]
public string RoomId { get; set; } public string RoomId { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ControlPropertiesConfig() public ControlPropertiesConfig()
{ {
EndOfLineString = CrestronEnvironment.NewLine;
} }
} }
} }

View file

@ -1,251 +1,251 @@
/*PepperDash Technology Corp. /*PepperDash Technology Corp.
Copyright: 2017 Copyright: 2017
------------------------------------ ------------------------------------
***Notice of Ownership and Copyright*** ***Notice of Ownership and Copyright***
The material in which this notice appears is the property of PepperDash Technology Corporation, The material in which this notice appears is the property of PepperDash Technology Corporation,
which claims copyright under the laws of the United States of America in the entire body of material which claims copyright under the laws of the United States of America in the entire body of material
and in all parts thereof, regardless of the use to which it is being put. Any use, in whole or in part, and in all parts thereof, regardless of the use to which it is being put. Any use, in whole or in part,
of this material by another party without the express written permission of PepperDash Technology Corporation is prohibited. of this material by another party without the express written permission of PepperDash Technology Corporation is prohibited.
PepperDash Technology Corporation reserves all rights under applicable laws. PepperDash Technology Corporation reserves all rights under applicable laws.
------------------------------------ */ ------------------------------------ */
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
namespace PepperDash.Core namespace PepperDash.Core
{ {
/// <summary> /// <summary>
/// Delegate for notifying of socket status changes /// Delegate for notifying of socket status changes
/// </summary> /// </summary>
/// <param name="client"></param> /// <param name="client"></param>
public delegate void GenericSocketStatusChangeEventDelegate(ISocketStatus client); public delegate void GenericSocketStatusChangeEventDelegate(ISocketStatus client);
/// <summary> /// <summary>
/// EventArgs class for socket status changes /// EventArgs class for socket status changes
/// </summary> /// </summary>
public class GenericSocketStatusChageEventArgs : EventArgs public class GenericSocketStatusChageEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ISocketStatus Client { get; private set; } public ISocketStatus Client { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="client"></param> /// <param name="client"></param>
public GenericSocketStatusChageEventArgs(ISocketStatus client) public GenericSocketStatusChageEventArgs(ISocketStatus client)
{ {
Client = client; Client = client;
} }
/// <summary> /// <summary>
/// S+ Constructor /// S+ Constructor
/// </summary> /// </summary>
public GenericSocketStatusChageEventArgs() { } public GenericSocketStatusChageEventArgs() { }
} }
/// <summary> /// <summary>
/// Delegate for notifying of TCP Server state changes /// Delegate for notifying of TCP Server state changes
/// </summary> /// </summary>
/// <param name="state"></param> /// <param name="state"></param>
public delegate void GenericTcpServerStateChangedEventDelegate(ServerState state); public delegate void GenericTcpServerStateChangedEventDelegate(ServerState state);
/// <summary> /// <summary>
/// EventArgs class for TCP Server state changes /// EventArgs class for TCP Server state changes
/// </summary> /// </summary>
public class GenericTcpServerStateChangedEventArgs : EventArgs public class GenericTcpServerStateChangedEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ServerState State { get; private set; } public ServerState State { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="state"></param> /// <param name="state"></param>
public GenericTcpServerStateChangedEventArgs(ServerState state) public GenericTcpServerStateChangedEventArgs(ServerState state)
{ {
State = state; State = state;
} }
/// <summary> /// <summary>
/// S+ Constructor /// S+ Constructor
/// </summary> /// </summary>
public GenericTcpServerStateChangedEventArgs() { } public GenericTcpServerStateChangedEventArgs() { }
} }
/// <summary> /// <summary>
/// Delegate for TCP Server socket status changes /// Delegate for TCP Server socket status changes
/// </summary> /// </summary>
/// <param name="socket"></param> /// <param name="socket"></param>
/// <param name="clientIndex"></param> /// <param name="clientIndex"></param>
/// <param name="clientStatus"></param> /// <param name="clientStatus"></param>
public delegate void GenericTcpServerSocketStatusChangeEventDelegate(object socket, uint clientIndex, SocketStatus clientStatus); public delegate void GenericTcpServerSocketStatusChangeEventDelegate(object socket, uint clientIndex, SocketStatus clientStatus);
/// <summary> /// <summary>
/// EventArgs for TCP server socket status changes /// EventArgs for TCP server socket status changes
/// </summary> /// </summary>
public class GenericTcpServerSocketStatusChangeEventArgs : EventArgs public class GenericTcpServerSocketStatusChangeEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public object Socket { get; private set; } public object Socket { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public uint ReceivedFromClientIndex { get; private set; } public uint ReceivedFromClientIndex { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public SocketStatus ClientStatus { get; set; } public SocketStatus ClientStatus { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="socket"></param> /// <param name="socket"></param>
/// <param name="clientStatus"></param> /// <param name="clientStatus"></param>
public GenericTcpServerSocketStatusChangeEventArgs(object socket, SocketStatus clientStatus) public GenericTcpServerSocketStatusChangeEventArgs(object socket, SocketStatus clientStatus)
{ {
Socket = socket; Socket = socket;
ClientStatus = clientStatus; ClientStatus = clientStatus;
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="socket"></param> /// <param name="socket"></param>
/// <param name="clientIndex"></param> /// <param name="clientIndex"></param>
/// <param name="clientStatus"></param> /// <param name="clientStatus"></param>
public GenericTcpServerSocketStatusChangeEventArgs(object socket, uint clientIndex, SocketStatus clientStatus) public GenericTcpServerSocketStatusChangeEventArgs(object socket, uint clientIndex, SocketStatus clientStatus)
{ {
Socket = socket; Socket = socket;
ReceivedFromClientIndex = clientIndex; ReceivedFromClientIndex = clientIndex;
ClientStatus = clientStatus; ClientStatus = clientStatus;
} }
/// <summary> /// <summary>
/// S+ Constructor /// S+ Constructor
/// </summary> /// </summary>
public GenericTcpServerSocketStatusChangeEventArgs() { } public GenericTcpServerSocketStatusChangeEventArgs() { }
} }
/// <summary> /// <summary>
/// EventArgs for TCP server com method receive text /// EventArgs for TCP server com method receive text
/// </summary> /// </summary>
public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs public class GenericTcpServerCommMethodReceiveTextArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public uint ReceivedFromClientIndex { get; private set; } public uint ReceivedFromClientIndex { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort ReceivedFromClientIndexShort public ushort ReceivedFromClientIndexShort
{ {
get get
{ {
return (ushort)ReceivedFromClientIndex; return (ushort)ReceivedFromClientIndex;
} }
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Text { get; private set; } public string Text { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="text"></param> /// <param name="text"></param>
public GenericTcpServerCommMethodReceiveTextArgs(string text) public GenericTcpServerCommMethodReceiveTextArgs(string text)
{ {
Text = text; Text = text;
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="text"></param> /// <param name="text"></param>
/// <param name="clientIndex"></param> /// <param name="clientIndex"></param>
public GenericTcpServerCommMethodReceiveTextArgs(string text, uint clientIndex) public GenericTcpServerCommMethodReceiveTextArgs(string text, uint clientIndex)
{ {
Text = text; Text = text;
ReceivedFromClientIndex = clientIndex; ReceivedFromClientIndex = clientIndex;
} }
/// <summary> /// <summary>
/// S+ Constructor /// S+ Constructor
/// </summary> /// </summary>
public GenericTcpServerCommMethodReceiveTextArgs() { } public GenericTcpServerCommMethodReceiveTextArgs() { }
} }
/// <summary> /// <summary>
/// EventArgs for TCP server client ready for communication /// EventArgs for TCP server client ready for communication
/// </summary> /// </summary>
public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs public class GenericTcpServerClientReadyForcommunicationsEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public bool IsReady; public bool IsReady;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="isReady"></param> /// <param name="isReady"></param>
public GenericTcpServerClientReadyForcommunicationsEventArgs(bool isReady) public GenericTcpServerClientReadyForcommunicationsEventArgs(bool isReady)
{ {
IsReady = isReady; IsReady = isReady;
} }
/// <summary> /// <summary>
/// S+ Constructor /// S+ Constructor
/// </summary> /// </summary>
public GenericTcpServerClientReadyForcommunicationsEventArgs() { } public GenericTcpServerClientReadyForcommunicationsEventArgs() { }
} }
/// <summary> /// <summary>
/// EventArgs for UDP connected /// EventArgs for UDP connected
/// </summary> /// </summary>
public class GenericUdpConnectedEventArgs : EventArgs public class GenericUdpConnectedEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort UConnected; public ushort UConnected;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public bool Connected; public bool Connected;
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public GenericUdpConnectedEventArgs() { } public GenericUdpConnectedEventArgs() { }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="uconnected"></param> /// <param name="uconnected"></param>
public GenericUdpConnectedEventArgs(ushort uconnected) public GenericUdpConnectedEventArgs(ushort uconnected)
{ {
UConnected = uconnected; UConnected = uconnected;
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="connected"></param> /// <param name="connected"></param>
public GenericUdpConnectedEventArgs(bool connected) public GenericUdpConnectedEventArgs(bool connected)
{ {
Connected = connected; Connected = connected;
} }
} }
} }

View file

@ -1,17 +1,11 @@
using System; 
using System.Collections.Generic; using System;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PepperDash.Core namespace PepperDash.Core
{ {

View file

@ -1,60 +1,60 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core namespace PepperDash.Core
{ {
/// <summary> /// <summary>
/// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities /// Tcp Server Config object with properties for a tcp server with shared key and heartbeat capabilities
/// </summary> /// </summary>
public class TcpServerConfigObject public class TcpServerConfigObject
{ {
/// <summary> /// <summary>
/// Uique key /// Uique key
/// </summary> /// </summary>
public string Key { get; set; } public string Key { get; set; }
/// <summary> /// <summary>
/// Max Clients that the server will allow to connect. /// Max Clients that the server will allow to connect.
/// </summary> /// </summary>
public ushort MaxClients { get; set; } public ushort MaxClients { get; set; }
/// <summary> /// <summary>
/// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic /// Bool value for secure. Currently not implemented in TCP sockets as they are not dynamic
/// </summary> /// </summary>
public bool Secure { get; set; } public bool Secure { get; set; }
/// <summary> /// <summary>
/// Port for the server to listen on /// Port for the server to listen on
/// </summary> /// </summary>
public int Port { get; set; } public int Port { get; set; }
/// <summary> /// <summary>
/// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client /// Require a shared key that both server and client negotiate. If negotiation fails server disconnects the client
/// </summary> /// </summary>
public bool SharedKeyRequired { get; set; } public bool SharedKeyRequired { get; set; }
/// <summary> /// <summary>
/// The shared key that must match on the server and client /// The shared key that must match on the server and client
/// </summary> /// </summary>
public string SharedKey { get; set; } public string SharedKey { get; set; }
/// <summary> /// <summary>
/// Require a heartbeat on the client/server connection that will cause the server/client to disconnect if the heartbeat is not received. /// Require a heartbeat on the client/server connection that will cause the server/client to disconnect if the heartbeat is not received.
/// heartbeats do not raise received events. /// heartbeats do not raise received events.
/// </summary> /// </summary>
public bool HeartbeatRequired { get; set; } public bool HeartbeatRequired { get; set; }
/// <summary> /// <summary>
/// The interval in seconds for the heartbeat from the client. If not received client is disconnected /// The interval in seconds for the heartbeat from the client. If not received client is disconnected
/// </summary> /// </summary>
public ushort HeartbeatRequiredIntervalInSeconds { get; set; } public ushort HeartbeatRequiredIntervalInSeconds { get; set; }
/// <summary> /// <summary>
/// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided. /// HeartbeatString that will be checked against the message received. defaults to heartbeat if no string is provided.
/// </summary> /// </summary>
public string HeartbeatStringToMatch { get; set; } public string HeartbeatStringToMatch { get; set; }
/// <summary> /// <summary>
/// Client buffer size. See Crestron help. defaults to 2000 if not greater than 2000 /// Client buffer size. See Crestron help. defaults to 2000 if not greater than 2000
/// </summary> /// </summary>
public int BufferSize { get; set; } public int BufferSize { get; set; }
/// <summary> /// <summary>
/// Receive Queue size must be greater than 20 or defaults to 20 /// Receive Queue size must be greater than 20 or defaults to 20
/// </summary> /// </summary>
public int ReceiveQueueSize { get; set; } public int ReceiveQueueSize { get; set; }
} }
} }

View file

@ -1,242 +1,247 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets; using Crestron.SimplSharp.CrestronSockets;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PepperDash.Core
namespace PepperDash.Core {
{ /// <summary>
/// <summary> /// An incoming communication stream
/// An incoming communication stream /// </summary>
/// </summary> public interface ICommunicationReceiver : IKeyed
public interface ICommunicationReceiver : IKeyed {
{ /// <summary>
/// <summary> /// Notifies of bytes received
/// Notifies of bytes received /// </summary>
/// </summary> event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived; /// <summary>
/// <summary> /// Notifies of text received
/// Notifies of text received /// </summary>
/// </summary> event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
/// <summary>
/// <summary> /// Indicates connection status
/// Indicates connection status /// </summary>
/// </summary> [JsonProperty("isConnected")]
bool IsConnected { get; } bool IsConnected { get; }
/// <summary> /// <summary>
/// Connect to the device /// Connect to the device
/// </summary> /// </summary>
void Connect(); void Connect();
/// <summary> /// <summary>
/// Disconnect from the device /// Disconnect from the device
/// </summary> /// </summary>
void Disconnect(); void Disconnect();
} }
/// <summary> /// <summary>
/// Represents a device that uses basic connection /// Represents a device that uses basic connection
/// </summary> /// </summary>
public interface IBasicCommunication : ICommunicationReceiver public interface IBasicCommunication : ICommunicationReceiver
{ {
/// <summary> /// <summary>
/// Send text to the device /// Send text to the device
/// </summary> /// </summary>
/// <param name="text"></param> /// <param name="text"></param>
void SendText(string text); void SendText(string text);
/// <summary> /// <summary>
/// Send bytes to the device /// Send bytes to the device
/// </summary> /// </summary>
/// <param name="bytes"></param> /// <param name="bytes"></param>
void SendBytes(byte[] bytes); void SendBytes(byte[] bytes);
} }
/// <summary> /// <summary>
/// Represents a device that implements IBasicCommunication and IStreamDebugging /// Represents a device that implements IBasicCommunication and IStreamDebugging
/// </summary> /// </summary>
public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging public interface IBasicCommunicationWithStreamDebugging : IBasicCommunication, IStreamDebugging
{ {
} }
/// <summary> /// <summary>
/// Represents a device with stream debugging capablities /// Represents a device with stream debugging capablities
/// </summary> /// </summary>
public interface IStreamDebugging public interface IStreamDebugging
{ {
/// <summary> /// <summary>
/// Object to enable stream debugging /// Object to enable stream debugging
/// </summary> /// </summary>
CommunicationStreamDebugging StreamDebugging { get; } [JsonProperty("streamDebugging")]
} CommunicationStreamDebugging StreamDebugging { get; }
}
/// <summary>
/// For IBasicCommunication classes that have SocketStatus. GenericSshClient, /// <summary>
/// GenericTcpIpClient /// For IBasicCommunication classes that have SocketStatus. GenericSshClient,
/// </summary> /// GenericTcpIpClient
public interface ISocketStatus : IBasicCommunication /// </summary>
{ public interface ISocketStatus : IBasicCommunication
/// <summary> {
/// Notifies of socket status changes /// <summary>
/// </summary> /// Notifies of socket status changes
event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange; /// </summary>
event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
/// <summary>
/// The current socket status of the client /// <summary>
/// </summary> /// The current socket status of the client
SocketStatus ClientStatus { get; } /// </summary>
} [JsonProperty("clientStatus")]
[JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]
/// <summary> SocketStatus ClientStatus { get; }
/// Describes a device that implements ISocketStatus and IStreamDebugging }
/// </summary>
public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging /// <summary>
{ /// Describes a device that implements ISocketStatus and IStreamDebugging
/// </summary>
} public interface ISocketStatusWithStreamDebugging : ISocketStatus, IStreamDebugging
{
/// <summary>
/// Describes a device that can automatically attempt to reconnect }
/// </summary>
public interface IAutoReconnect /// <summary>
{ /// Describes a device that can automatically attempt to reconnect
/// <summary> /// </summary>
/// Enable automatic recconnect public interface IAutoReconnect
/// </summary> {
bool AutoReconnect { get; set; } /// <summary>
/// <summary> /// Enable automatic recconnect
/// Interval in ms to attempt automatic recconnections /// </summary>
/// </summary> [JsonProperty("autoReconnect")]
int AutoReconnectIntervalMs { get; set; } bool AutoReconnect { get; set; }
} /// <summary>
/// Interval in ms to attempt automatic recconnections
/// <summary> /// </summary>
/// [JsonProperty("autoReconnectIntervalMs")]
/// </summary> int AutoReconnectIntervalMs { get; set; }
public enum eGenericCommMethodStatusChangeType }
{
/// <summary> /// <summary>
/// Connected ///
/// </summary> /// </summary>
Connected, public enum eGenericCommMethodStatusChangeType
/// <summary> {
/// Disconnected /// <summary>
/// </summary> /// Connected
Disconnected /// </summary>
} Connected,
/// <summary>
/// <summary> /// Disconnected
/// This delegate defines handler for IBasicCommunication status changes /// </summary>
/// </summary> Disconnected
/// <param name="comm">Device firing the status change</param> }
/// <param name="status"></param>
public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status); /// <summary>
/// This delegate defines handler for IBasicCommunication status changes
/// <summary> /// </summary>
/// /// <param name="comm">Device firing the status change</param>
/// </summary> /// <param name="status"></param>
public class GenericCommMethodReceiveBytesArgs : EventArgs public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status);
{
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public byte[] Bytes { get; private set; } public class GenericCommMethodReceiveBytesArgs : EventArgs
{
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="bytes"></param> public byte[] Bytes { get; private set; }
public GenericCommMethodReceiveBytesArgs(byte[] bytes)
{ /// <summary>
Bytes = bytes; ///
} /// </summary>
/// <param name="bytes"></param>
/// <summary> public GenericCommMethodReceiveBytesArgs(byte[] bytes)
/// S+ Constructor {
/// </summary> Bytes = bytes;
public GenericCommMethodReceiveBytesArgs() { } }
}
/// <summary>
/// <summary> /// S+ Constructor
/// /// </summary>
/// </summary> public GenericCommMethodReceiveBytesArgs() { }
public class GenericCommMethodReceiveTextArgs : EventArgs }
{
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Text { get; private set; } public class GenericCommMethodReceiveTextArgs : EventArgs
/// <summary> {
/// /// <summary>
/// </summary> ///
public string Delimiter { get; private set; } /// </summary>
/// <summary> public string Text { get; private set; }
/// /// <summary>
/// </summary> ///
/// <param name="text"></param> /// </summary>
public GenericCommMethodReceiveTextArgs(string text) public string Delimiter { get; private set; }
{ /// <summary>
Text = text; ///
} /// </summary>
/// <param name="text"></param>
/// <summary> public GenericCommMethodReceiveTextArgs(string text)
/// {
/// </summary> Text = text;
/// <param name="text"></param> }
/// <param name="delimiter"></param>
public GenericCommMethodReceiveTextArgs(string text, string delimiter) /// <summary>
:this(text) ///
{ /// </summary>
Delimiter = delimiter; /// <param name="text"></param>
} /// <param name="delimiter"></param>
public GenericCommMethodReceiveTextArgs(string text, string delimiter)
/// <summary> :this(text)
/// S+ Constructor {
/// </summary> Delimiter = delimiter;
public GenericCommMethodReceiveTextArgs() { } }
}
/// <summary>
/// S+ Constructor
/// </summary>
/// <summary> public GenericCommMethodReceiveTextArgs() { }
/// }
/// </summary>
public class ComTextHelper
{
/// <summary> /// <summary>
/// Gets escaped text for a byte array ///
/// </summary> /// </summary>
/// <param name="bytes"></param> public class ComTextHelper
/// <returns></returns> {
public static string GetEscapedText(byte[] bytes) /// <summary>
{ /// Gets escaped text for a byte array
return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); /// </summary>
} /// <param name="bytes"></param>
/// <returns></returns>
/// <summary> public static string GetEscapedText(byte[] bytes)
/// Gets escaped text for a string {
/// </summary> return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
/// <param name="text"></param> }
/// <returns></returns>
public static string GetEscapedText(string text) /// <summary>
{ /// Gets escaped text for a string
var bytes = Encoding.GetEncoding(28591).GetBytes(text); /// </summary>
return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); /// <param name="text"></param>
} /// <returns></returns>
public static string GetEscapedText(string text)
/// <summary> {
/// Gets debug text for a string var bytes = Encoding.GetEncoding(28591).GetBytes(text);
/// </summary> return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray());
/// <param name="text"></param> }
/// <returns></returns>
public static string GetDebugText(string text) /// <summary>
{ /// Gets debug text for a string
return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value)); /// </summary>
} /// <param name="text"></param>
} /// <returns></returns>
public static string GetDebugText(string text)
{
return Regex.Replace(text, @"[^\u0020-\u007E]", a => GetEscapedText(a.Value));
}
}
} }

View file

@ -1,13 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using PepperDash.Core; using PepperDash.Core;
namespace PepperDash.Core.Config namespace PepperDash.Core.Config
@ -83,7 +79,7 @@ namespace PepperDash.Core.Config
merged.Add("info", template["info"]); merged.Add("info", template["info"]);
merged.Add("devices", MergeArraysOnTopLevelProperty(template["devices"] as JArray, merged.Add("devices", MergeArraysOnTopLevelProperty(template["devices"] as JArray,
system["devices"] as JArray, "uid", "devices")); system["devices"] as JArray, "key", "devices"));
if (system["rooms"] == null) if (system["rooms"] == null)
merged.Add("rooms", template["rooms"]); merged.Add("rooms", template["rooms"]);
@ -102,9 +98,22 @@ namespace PepperDash.Core.Config
merged.Add("destinationLists", merged.Add("destinationLists",
Merge(template["destinationLists"], system["destinationLists"], "destinationLists")); Merge(template["destinationLists"], system["destinationLists"], "destinationLists"));
// Template tie lines take precedence. Config tool doesn't do them at system
// level anyway... if (system["cameraLists"] == null)
if (template["tieLines"] != null) merged.Add("cameraLists", template["cameraLists"]);
else
merged.Add("cameraLists", Merge(template["cameraLists"], system["cameraLists"], "cameraLists"));
if (system["audioControlPointLists"] == null)
merged.Add("audioControlPointLists", template["audioControlPointLists"]);
else
merged.Add("audioControlPointLists",
Merge(template["audioControlPointLists"], system["audioControlPointLists"], "audioControlPointLists"));
// Template tie lines take precedence. Config tool doesn't do them at system
// level anyway...
if (template["tieLines"] != null)
merged.Add("tieLines", template["tieLines"]); merged.Add("tieLines", template["tieLines"]);
else if (system["tieLines"] != null) else if (system["tieLines"] != null)
merged.Add("tieLines", system["tieLines"]); merged.Add("tieLines", system["tieLines"]);
@ -121,7 +130,7 @@ namespace PepperDash.Core.Config
else else
merged.Add("global", template["global"]); merged.Add("global", template["global"]);
Debug.Console(2, "MERGED CONFIG RESULT: \x0d\x0a{0}", merged); //Debug.Console(2, "MERGED CONFIG RESULT: \x0d\x0a{0}", merged);
return merged; return merged;
} }

View file

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Newtonsoft.Json;
using Serilog;
namespace PepperDash.Core namespace PepperDash.Core
{ {
@ -14,17 +16,20 @@ namespace PepperDash.Core
/// <summary> /// <summary>
/// Unique Key /// Unique Key
/// </summary> /// </summary>
[JsonProperty("key")]
string Key { get; } string Key { get; }
} }
/// <summary> /// <summary>
/// Named Keyed device interface. Forces the devie to have a Unique Key and a name. /// Named Keyed device interface. Forces the device to have a Unique Key and a name.
/// </summary> /// </summary>
public interface IKeyName : IKeyed public interface IKeyName : IKeyed
{ {
/// <summary> /// <summary>
/// Isn't it obvious :) /// Isn't it obvious :)
/// </summary> /// </summary>
[JsonProperty("name")]
string Name { get; } string Name { get; }
} }
} }

View file

@ -1,162 +1,179 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using Serilog.Events;
namespace PepperDash.Core namespace PepperDash.Core
{ {
//********************************************************************************************************* //*********************************************************************************************************
/// <summary> /// <summary>
/// The core event and status-bearing class that most if not all device and connectors can derive from. /// The core event and status-bearing class that most if not all device and connectors can derive from.
/// </summary> /// </summary>
public class Device : IKeyName public class Device : IKeyName
{ {
/// <summary>
/// Unique Key /// <summary>
/// </summary> /// Unique Key
public string Key { get; protected set; } /// </summary>
/// <summary> public string Key { get; protected set; }
/// Name of the devie /// <summary>
/// </summary> /// Name of the devie
public string Name { get; protected set; } /// </summary>
/// <summary> public string Name { get; protected set; }
/// /// <summary>
/// </summary> ///
public bool Enabled { get; protected set; } /// </summary>
public bool Enabled { get; protected set; }
///// <summary>
///// A place to store reference to the original config object, if any. These values should ///// <summary>
///// NOT be used as properties on the device as they are all publicly-settable values. ///// A place to store reference to the original config object, if any. These values should
///// </summary> ///// NOT be used as properties on the device as they are all publicly-settable values.
//public DeviceConfig Config { get; private set; } ///// </summary>
///// <summary> //public DeviceConfig Config { get; private set; }
///// Helper method to check if Config exists ///// <summary>
///// </summary> ///// Helper method to check if Config exists
//public bool HasConfig { get { return Config != null; } } ///// </summary>
//public bool HasConfig { get { return Config != null; } }
List<Action> _PreActivationActions;
List<Action> _PostActivationActions; List<Action> _PreActivationActions;
List<Action> _PostActivationActions;
/// <summary>
/// /// <summary>
/// </summary> ///
public static Device DefaultDevice { get { return _DefaultDevice; } } /// </summary>
static Device _DefaultDevice = new Device("Default", "Default"); public static Device DefaultDevice { get { return _DefaultDevice; } }
static Device _DefaultDevice = new Device("Default", "Default");
/// <summary>
/// Base constructor for all Devices. /// <summary>
/// </summary> /// Base constructor for all Devices.
/// <param name="key"></param> /// </summary>
public Device(string key) /// <param name="key"></param>
{ public Device(string key)
Key = key; {
if (key.Contains('.')) Debug.Console(0, this, "WARNING: Device name's should not include '.'"); Key = key;
Name = ""; if (key.Contains(".")) Debug.LogMessage(LogEventLevel.Information, "WARNING: Device key should not include '.'", this);
Name = "";
} }
/// <summary> /// <summary>
/// Constructor with key and name /// Constructor with key and name
/// </summary> /// </summary>
/// <param name="key"></param> /// <param name="key"></param>
/// <param name="name"></param> /// <param name="name"></param>
public Device(string key, string name) : this(key) public Device(string key, string name) : this(key)
{ {
Name = name; Name = name;
} }
//public Device(DeviceConfig config) //public Device(DeviceConfig config)
// : this(config.Key, config.Name) // : this(config.Key, config.Name)
//{ //{
// Config = config; // Config = config;
//} //}
/// <summary> /// <summary>
/// Adds a pre activation action /// Adds a pre activation action
/// </summary> /// </summary>
/// <param name="act"></param> /// <param name="act"></param>
public void AddPreActivationAction(Action act) public void AddPreActivationAction(Action act)
{ {
if (_PreActivationActions == null) if (_PreActivationActions == null)
_PreActivationActions = new List<Action>(); _PreActivationActions = new List<Action>();
_PreActivationActions.Add(act); _PreActivationActions.Add(act);
} }
/// <summary> /// <summary>
/// Adds a post activation action /// Adds a post activation action
/// </summary> /// </summary>
/// <param name="act"></param> /// <param name="act"></param>
public void AddPostActivationAction(Action act) public void AddPostActivationAction(Action act)
{ {
if (_PostActivationActions == null) if (_PostActivationActions == null)
_PostActivationActions = new List<Action>(); _PostActivationActions = new List<Action>();
_PostActivationActions.Add(act); _PostActivationActions.Add(act);
} }
/// <summary> /// <summary>
/// Executes the preactivation actions /// Executes the preactivation actions
/// </summary> /// </summary>
public void PreActivate() public void PreActivate()
{ {
if (_PreActivationActions != null) if (_PreActivationActions != null)
_PreActivationActions.ForEach(a => a.Invoke()); _PreActivationActions.ForEach(a => {
} try
{
/// <summary> a.Invoke();
/// Gets this device ready to be used in the system. Runs any added pre-activation items, and } catch (Exception e)
/// all post-activation at end. Classes needing additional logic to {
/// run should override CustomActivate() Debug.LogMessage(e, "Error in PreActivationAction: " + e.Message, this);
/// </summary> }
public bool Activate() });
{ }
//if (_PreActivationActions != null)
// _PreActivationActions.ForEach(a => a.Invoke()); /// <summary>
var result = CustomActivate(); /// Gets this device ready to be used in the system. Runs any added pre-activation items, and
//if(result && _PostActivationActions != null) /// all post-activation at end. Classes needing additional logic to
// _PostActivationActions.ForEach(a => a.Invoke()); /// run should override CustomActivate()
return result; /// </summary>
} public bool Activate()
{
/// <summary> //if (_PreActivationActions != null)
/// Executes the postactivation actions // _PreActivationActions.ForEach(a => a.Invoke());
/// </summary> var result = CustomActivate();
public void PostActivate() //if(result && _PostActivationActions != null)
{ // _PostActivationActions.ForEach(a => a.Invoke());
if (_PostActivationActions != null) return result;
_PostActivationActions.ForEach(a => a.Invoke()); }
}
/// <summary>
/// <summary> /// Executes the postactivation actions
/// Called in between Pre and PostActivationActions when Activate() is called. /// </summary>
/// Override to provide addtitional setup when calling activation. Overriding classes public void PostActivate()
/// do not need to call base.CustomActivate() {
/// </summary> if (_PostActivationActions != null)
/// <returns>true if device activated successfully.</returns> _PostActivationActions.ForEach(a => {
public virtual bool CustomActivate() { return true; } try
{
/// <summary> a.Invoke();
/// Call to deactivate device - unlink events, etc. Overriding classes do not }
/// need to call base.Deactivate() catch (Exception e)
/// </summary> {
/// <returns></returns> Debug.LogMessage(e, "Error in PostActivationAction: " + e.Message, this);
public virtual bool Deactivate() { return true; } }
});
/// <summary> }
/// Call this method to start communications with a device. Overriding classes do not need to call base.Initialize()
/// </summary> /// <summary>
public virtual void Initialize() /// Called in between Pre and PostActivationActions when Activate() is called.
{ /// Override to provide addtitional setup when calling activation. Overriding classes
} /// do not need to call base.CustomActivate()
/// </summary>
/// <summary> /// <returns>true if device activated successfully.</returns>
/// Helper method to check object for bool value false and fire an Action method public virtual bool CustomActivate() { return true; }
/// </summary>
/// <param name="o">Should be of type bool, others will be ignored</param> /// <summary>
/// <param name="a">Action to be run when o is false</param> /// Call to deactivate device - unlink events, etc. Overriding classes do not
public void OnFalse(object o, Action a) /// need to call base.Deactivate()
{ /// </summary>
if (o is bool && !(bool)o) a(); /// <returns></returns>
} public virtual bool Deactivate() { return true; }
} /// <summary>
/// Call this method to start communications with a device. Overriding classes do not need to call base.Initialize()
/// </summary>
public virtual void Initialize()
{
}
/// <summary>
/// Helper method to check object for bool value false and fire an Action method
/// </summary>
/// <param name="o">Should be of type bool, others will be ignored</param>
/// <param name="a">Action to be run when o is false</param>
public void OnFalse(object o, Action a)
{
if (o is bool && !(bool)o) a();
}
}
} }

19
src/Directory.build.props Normal file
View file

@ -0,0 +1,19 @@
<Project>
<PropertyGroup>
<Version>2.0.0-local</Version>
<Authors>PepperDash Technologies</Authors>
<Company>PepperDash Technologies</Company>
<Product>PepperDash Essentials</Product>
<Copyright>Copyright © 2025</Copyright>
<RepositoryType>git</RepositoryType>
<PackageTags>Crestron; 4series</PackageTags>
<PackageOutputPath>../output</PackageOutputPath>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<PackageLicenseFile>LICENSE.md</PackageLicenseFile>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<ItemGroup>
<None Include="..\LICENSE.md" Pack="true" PackagePath=""/>
<None Include="..\README.md" Pack="true" PackagePath=""/>
</ItemGroup>
</Project>

View file

@ -0,0 +1,43 @@
<Project>
<ItemGroup>
<None Include="$(TargetDir)\$(TargetName).$(Version).cpz" Condition="$(ProjectType) == 'Program'">
<Pack>true</Pack>
<PackagePath>content;</PackagePath>
</None>
<None Include="$(PackageOutputPath)\$(TargetName).$(Version).cplz" Condition="$(ProjectType) == 'ProgramLibrary'">
<Pack>true</Pack>
<PackagePath>content;</PackagePath>
</None>
</ItemGroup>
<Target Name="Create CPLZ" AfterTargets="Build; Rebuild" Condition="$(ProjectType) == 'ProgramLibrary'">
<Message Text="Creating CPLZ"></Message>
<MakeDir Directories="$(PackageOutputPath)" Condition="!Exists($(PackageOutputPath))"></MakeDir>
<ZipDirectory SourceDirectory="$(TargetDir)" DestinationFile="$(PackageOutputPath)\$(TargetName).$(Version).cplz" Overwrite="true"/>
</Target>
<Target Name="Clean CPLZ" AfterTargets="AfterClean" Condition="$(ProjectType) == 'ProgramLibrary'">
<Delete Files="$(PackageOutputPath)\$(TargetName).$(Version).cplz"/>
</Target>
<Target Name="Copy CPZ" AfterTargets="SimplSharpPostProcess" Condition="$(ProjectType) == 'Program'">
<Message Text="Copying CPZ"></Message>
<Move SourceFiles="$(TargetDir)\$(TargetName).cpz" DestinationFiles="$(TargetDir)\$(TargetName).$(Version).cpz"/>
<Copy SourceFiles="$(TargetDir)\$(TargetName).$(Version).cpz" DestinationFiles="$(PackageOutputPath)\$(TargetName).$(Version).cpz"/>
</Target>
<Target Name="Clean CPZ" AfterTargets="AfterClean" Condition="$(ProjectType) == 'Program'">
<Delete Files="$(PackageOutputPath)\$(TargetName).$(Version).cpz"/>
</Target>
<Target Name="Copy CLZ" AfterTargets="SimplSharpPostProcess">
<Message Text="Copying CLZ"></Message>
<Move SourceFiles="$(TargetDir)\$(TargetName).clz" DestinationFiles="$(TargetDir)\$(TargetName).$(Version).clz"/>
<Copy SourceFiles="$(TargetDir)\$(TargetName).$(Version).clz" DestinationFiles="$(PackageOutputPath)\$(TargetName).$(Version).clz"/>
</Target>
<Target Name="Clean CLZ" AfterTargets="AfterClean">
<Delete Files="$(PackageOutputPath)\$(TargetName).$(Version).clz"/>
</Target>
<Target Name="SimplSharpNewtonsoft" BeforeTargets="FindReferenceAssembliesForReferences;ResolveReferences">
<ItemGroup>
<ReferencePath Condition="'%(FileName)' == 'Newtonsoft.Json.Compact'">
<Aliases>doNotUse</Aliases>
</ReferencePath>
</ItemGroup>
</Target>
</Project>

View file

@ -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 }}

View file

@ -1,9 +1,4 @@
using System; using Crestron.SimplSharp;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace PepperDash.Core namespace PepperDash.Core

View file

@ -1,172 +1,172 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core namespace PepperDash.Core
{ {
/// <summary> /// <summary>
/// Bool change event args /// Bool change event args
/// </summary> /// </summary>
public class BoolChangeEventArgs : EventArgs public class BoolChangeEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// Boolean state property /// Boolean state property
/// </summary> /// </summary>
public bool State { get; set; } public bool State { get; set; }
/// <summary> /// <summary>
/// Boolean ushort value property /// Boolean ushort value property
/// </summary> /// </summary>
public ushort IntValue { get { return (ushort)(State ? 1 : 0); } } public ushort IntValue { get { return (ushort)(State ? 1 : 0); } }
/// <summary> /// <summary>
/// Boolean change event args type /// Boolean change event args type
/// </summary> /// </summary>
public ushort Type { get; set; } public ushort Type { get; set; }
/// <summary> /// <summary>
/// Boolean change event args index /// Boolean change event args index
/// </summary> /// </summary>
public ushort Index { get; set; } public ushort Index { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public BoolChangeEventArgs() public BoolChangeEventArgs()
{ {
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="state"></param> /// <param name="state"></param>
/// <param name="type"></param> /// <param name="type"></param>
public BoolChangeEventArgs(bool state, ushort type) public BoolChangeEventArgs(bool state, ushort type)
{ {
State = state; State = state;
Type = type; Type = type;
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="state"></param> /// <param name="state"></param>
/// <param name="type"></param> /// <param name="type"></param>
/// <param name="index"></param> /// <param name="index"></param>
public BoolChangeEventArgs(bool state, ushort type, ushort index) public BoolChangeEventArgs(bool state, ushort type, ushort index)
{ {
State = state; State = state;
Type = type; Type = type;
Index = index; Index = index;
} }
} }
/// <summary> /// <summary>
/// Ushort change event args /// Ushort change event args
/// </summary> /// </summary>
public class UshrtChangeEventArgs : EventArgs public class UshrtChangeEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// Ushort change event args integer value /// Ushort change event args integer value
/// </summary> /// </summary>
public ushort IntValue { get; set; } public ushort IntValue { get; set; }
/// <summary> /// <summary>
/// Ushort change event args type /// Ushort change event args type
/// </summary> /// </summary>
public ushort Type { get; set; } public ushort Type { get; set; }
/// <summary> /// <summary>
/// Ushort change event args index /// Ushort change event args index
/// </summary> /// </summary>
public ushort Index { get; set; } public ushort Index { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public UshrtChangeEventArgs() public UshrtChangeEventArgs()
{ {
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="intValue"></param> /// <param name="intValue"></param>
/// <param name="type"></param> /// <param name="type"></param>
public UshrtChangeEventArgs(ushort intValue, ushort type) public UshrtChangeEventArgs(ushort intValue, ushort type)
{ {
IntValue = intValue; IntValue = intValue;
Type = type; Type = type;
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="intValue"></param> /// <param name="intValue"></param>
/// <param name="type"></param> /// <param name="type"></param>
/// <param name="index"></param> /// <param name="index"></param>
public UshrtChangeEventArgs(ushort intValue, ushort type, ushort index) public UshrtChangeEventArgs(ushort intValue, ushort type, ushort index)
{ {
IntValue = intValue; IntValue = intValue;
Type = type; Type = type;
Index = index; Index = index;
} }
} }
/// <summary> /// <summary>
/// String change event args /// String change event args
/// </summary> /// </summary>
public class StringChangeEventArgs : EventArgs public class StringChangeEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// String change event args value /// String change event args value
/// </summary> /// </summary>
public string StringValue { get; set; } public string StringValue { get; set; }
/// <summary> /// <summary>
/// String change event args type /// String change event args type
/// </summary> /// </summary>
public ushort Type { get; set; } public ushort Type { get; set; }
/// <summary> /// <summary>
/// string change event args index /// string change event args index
/// </summary> /// </summary>
public ushort Index { get; set; } public ushort Index { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public StringChangeEventArgs() public StringChangeEventArgs()
{ {
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="stringValue"></param> /// <param name="stringValue"></param>
/// <param name="type"></param> /// <param name="type"></param>
public StringChangeEventArgs(string stringValue, ushort type) public StringChangeEventArgs(string stringValue, ushort type)
{ {
StringValue = stringValue; StringValue = stringValue;
Type = type; Type = type;
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="stringValue"></param> /// <param name="stringValue"></param>
/// <param name="type"></param> /// <param name="type"></param>
/// <param name="index"></param> /// <param name="index"></param>
public StringChangeEventArgs(string stringValue, ushort type, ushort index) public StringChangeEventArgs(string stringValue, ushort type, ushort index)
{ {
StringValue = stringValue; StringValue = stringValue;
Type = type; Type = type;
Index = index; Index = index;
} }
} }
} }

View file

@ -1,39 +1,39 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.GenericRESTfulCommunications namespace PepperDash.Core.GenericRESTfulCommunications
{ {
/// <summary> /// <summary>
/// Constants /// Constants
/// </summary> /// </summary>
public class GenericRESTfulConstants public class GenericRESTfulConstants
{ {
/// <summary> /// <summary>
/// Generic boolean change /// Generic boolean change
/// </summary> /// </summary>
public const ushort BoolValueChange = 1; public const ushort BoolValueChange = 1;
/// <summary> /// <summary>
/// Generic Ushort change /// Generic Ushort change
/// </summary> /// </summary>
public const ushort UshrtValueChange = 101; public const ushort UshrtValueChange = 101;
/// <summary> /// <summary>
/// Response Code Ushort change /// Response Code Ushort change
/// </summary> /// </summary>
public const ushort ResponseCodeChange = 102; public const ushort ResponseCodeChange = 102;
/// <summary> /// <summary>
/// Generic String chagne /// Generic String chagne
/// </summary> /// </summary>
public const ushort StringValueChange = 201; public const ushort StringValueChange = 201;
/// <summary> /// <summary>
/// Response string change /// Response string change
/// </summary> /// </summary>
public const ushort ResponseStringChange = 202; public const ushort ResponseStringChange = 202;
/// <summary> /// <summary>
/// Error string change /// Error string change
/// </summary> /// </summary>
public const ushort ErrorStringChange = 203; public const ushort ErrorStringChange = 203;
} }
} }

View file

@ -1,256 +1,256 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharp.Net.Http;
using Crestron.SimplSharp.Net.Https; using Crestron.SimplSharp.Net.Https;
namespace PepperDash.Core.GenericRESTfulCommunications namespace PepperDash.Core.GenericRESTfulCommunications
{ {
/// <summary> /// <summary>
/// Generic RESTful communication class /// Generic RESTful communication class
/// </summary> /// </summary>
public class GenericRESTfulClient public class GenericRESTfulClient
{ {
/// <summary> /// <summary>
/// Boolean event handler /// Boolean event handler
/// </summary> /// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange; public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary> /// <summary>
/// Ushort event handler /// Ushort event handler
/// </summary> /// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange; public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary> /// <summary>
/// String event handler /// String event handler
/// </summary> /// </summary>
public event EventHandler<StringChangeEventArgs> StringChange; public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public GenericRESTfulClient() public GenericRESTfulClient()
{ {
} }
/// <summary> /// <summary>
/// Generic RESTful submit request /// Generic RESTful submit request
/// </summary> /// </summary>
/// <param name="url"></param> /// <param name="url"></param>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="requestType"></param> /// <param name="requestType"></param>
/// <param name="username"></param> /// <param name="username"></param>
/// <param name="password"></param> /// <param name="password"></param>
/// <param name="contentType"></param> /// <param name="contentType"></param>
public void SubmitRequest(string url, ushort port, ushort requestType, string contentType, string username, string password) public void SubmitRequest(string url, ushort port, ushort requestType, string contentType, string username, string password)
{ {
if (url.StartsWith("https:", StringComparison.OrdinalIgnoreCase)) if (url.StartsWith("https:", StringComparison.OrdinalIgnoreCase))
{ {
SubmitRequestHttps(url, port, requestType, contentType, username, password); SubmitRequestHttps(url, port, requestType, contentType, username, password);
} }
else if (url.StartsWith("http:", StringComparison.OrdinalIgnoreCase)) else if (url.StartsWith("http:", StringComparison.OrdinalIgnoreCase))
{ {
SubmitRequestHttp(url, port, requestType, contentType, username, password); SubmitRequestHttp(url, port, requestType, contentType, username, password);
} }
else else
{ {
OnStringChange(string.Format("Invalid URL {0}", url), 0, GenericRESTfulConstants.ErrorStringChange); OnStringChange(string.Format("Invalid URL {0}", url), 0, GenericRESTfulConstants.ErrorStringChange);
} }
} }
/// <summary> /// <summary>
/// Private HTTP submit request /// Private HTTP submit request
/// </summary> /// </summary>
/// <param name="url"></param> /// <param name="url"></param>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="requestType"></param> /// <param name="requestType"></param>
/// <param name="contentType"></param> /// <param name="contentType"></param>
/// <param name="username"></param> /// <param name="username"></param>
/// <param name="password"></param> /// <param name="password"></param>
private void SubmitRequestHttp(string url, ushort port, ushort requestType, string contentType, string username, string password) private void SubmitRequestHttp(string url, ushort port, ushort requestType, string contentType, string username, string password)
{ {
try try
{ {
HttpClient client = new HttpClient(); HttpClient client = new HttpClient();
HttpClientRequest request = new HttpClientRequest(); HttpClientRequest request = new HttpClientRequest();
HttpClientResponse response; HttpClientResponse response;
client.KeepAlive = false; client.KeepAlive = false;
if(port >= 1 || port <= 65535) if(port >= 1 || port <= 65535)
client.Port = port; client.Port = port;
else else
client.Port = 80; client.Port = 80;
var authorization = ""; var authorization = "";
if (!string.IsNullOrEmpty(username)) if (!string.IsNullOrEmpty(username))
authorization = EncodeBase64(username, password); authorization = EncodeBase64(username, password);
if (!string.IsNullOrEmpty(authorization)) if (!string.IsNullOrEmpty(authorization))
request.Header.SetHeaderValue("Authorization", authorization); request.Header.SetHeaderValue("Authorization", authorization);
if (!string.IsNullOrEmpty(contentType)) if (!string.IsNullOrEmpty(contentType))
request.Header.ContentType = contentType; request.Header.ContentType = contentType;
request.Url.Parse(url); request.Url.Parse(url);
request.RequestType = (Crestron.SimplSharp.Net.Http.RequestType)requestType; request.RequestType = (Crestron.SimplSharp.Net.Http.RequestType)requestType;
response = client.Dispatch(request); response = client.Dispatch(request);
CrestronConsole.PrintLine(string.Format("SubmitRequestHttp Response[{0}]: {1}", response.Code, response.ContentString.ToString())); CrestronConsole.PrintLine(string.Format("SubmitRequestHttp Response[{0}]: {1}", response.Code, response.ContentString.ToString()));
if (!string.IsNullOrEmpty(response.ContentString.ToString())) if (!string.IsNullOrEmpty(response.ContentString.ToString()))
OnStringChange(response.ContentString.ToString(), 0, GenericRESTfulConstants.ResponseStringChange); OnStringChange(response.ContentString.ToString(), 0, GenericRESTfulConstants.ResponseStringChange);
if (response.Code > 0) if (response.Code > 0)
OnUshrtChange((ushort)response.Code, 0, GenericRESTfulConstants.ResponseCodeChange); OnUshrtChange((ushort)response.Code, 0, GenericRESTfulConstants.ResponseCodeChange);
} }
catch (Exception e) catch (Exception e)
{ {
//var msg = string.Format("SubmitRequestHttp({0}, {1}, {2}) failed:{3}", url, port, requestType, e.Message); //var msg = string.Format("SubmitRequestHttp({0}, {1}, {2}) failed:{3}", url, port, requestType, e.Message);
//CrestronConsole.PrintLine(msg); //CrestronConsole.PrintLine(msg);
//ErrorLog.Error(msg); //ErrorLog.Error(msg);
CrestronConsole.PrintLine(e.Message); CrestronConsole.PrintLine(e.Message);
OnStringChange(e.Message, 0, GenericRESTfulConstants.ErrorStringChange); OnStringChange(e.Message, 0, GenericRESTfulConstants.ErrorStringChange);
} }
} }
/// <summary> /// <summary>
/// Private HTTPS submit request /// Private HTTPS submit request
/// </summary> /// </summary>
/// <param name="url"></param> /// <param name="url"></param>
/// <param name="port"></param> /// <param name="port"></param>
/// <param name="requestType"></param> /// <param name="requestType"></param>
/// <param name="contentType"></param> /// <param name="contentType"></param>
/// <param name="username"></param> /// <param name="username"></param>
/// <param name="password"></param> /// <param name="password"></param>
private void SubmitRequestHttps(string url, ushort port, ushort requestType, string contentType, string username, string password) private void SubmitRequestHttps(string url, ushort port, ushort requestType, string contentType, string username, string password)
{ {
try try
{ {
HttpsClient client = new HttpsClient(); HttpsClient client = new HttpsClient();
HttpsClientRequest request = new HttpsClientRequest(); HttpsClientRequest request = new HttpsClientRequest();
HttpsClientResponse response; HttpsClientResponse response;
client.KeepAlive = false; client.KeepAlive = false;
client.HostVerification = false; client.HostVerification = false;
client.PeerVerification = false; client.PeerVerification = false;
var authorization = ""; var authorization = "";
if (!string.IsNullOrEmpty(username)) if (!string.IsNullOrEmpty(username))
authorization = EncodeBase64(username, password); authorization = EncodeBase64(username, password);
if (!string.IsNullOrEmpty(authorization)) if (!string.IsNullOrEmpty(authorization))
request.Header.SetHeaderValue("Authorization", authorization); request.Header.SetHeaderValue("Authorization", authorization);
if (!string.IsNullOrEmpty(contentType)) if (!string.IsNullOrEmpty(contentType))
request.Header.ContentType = contentType; request.Header.ContentType = contentType;
request.Url.Parse(url); request.Url.Parse(url);
request.RequestType = (Crestron.SimplSharp.Net.Https.RequestType)requestType; request.RequestType = (Crestron.SimplSharp.Net.Https.RequestType)requestType;
response = client.Dispatch(request); response = client.Dispatch(request);
CrestronConsole.PrintLine(string.Format("SubmitRequestHttp Response[{0}]: {1}", response.Code, response.ContentString.ToString())); CrestronConsole.PrintLine(string.Format("SubmitRequestHttp Response[{0}]: {1}", response.Code, response.ContentString.ToString()));
if(!string.IsNullOrEmpty(response.ContentString.ToString())) if(!string.IsNullOrEmpty(response.ContentString.ToString()))
OnStringChange(response.ContentString.ToString(), 0, GenericRESTfulConstants.ResponseStringChange); OnStringChange(response.ContentString.ToString(), 0, GenericRESTfulConstants.ResponseStringChange);
if(response.Code > 0) if(response.Code > 0)
OnUshrtChange((ushort)response.Code, 0, GenericRESTfulConstants.ResponseCodeChange); OnUshrtChange((ushort)response.Code, 0, GenericRESTfulConstants.ResponseCodeChange);
} }
catch (Exception e) catch (Exception e)
{ {
//var msg = string.Format("SubmitRequestHttps({0}, {1}, {2}, {3}, {4}) failed:{5}", url, port, requestType, username, password, e.Message); //var msg = string.Format("SubmitRequestHttps({0}, {1}, {2}, {3}, {4}) failed:{5}", url, port, requestType, username, password, e.Message);
//CrestronConsole.PrintLine(msg); //CrestronConsole.PrintLine(msg);
//ErrorLog.Error(msg); //ErrorLog.Error(msg);
CrestronConsole.PrintLine(e.Message); CrestronConsole.PrintLine(e.Message);
OnStringChange(e.Message, 0, GenericRESTfulConstants.ErrorStringChange); OnStringChange(e.Message, 0, GenericRESTfulConstants.ErrorStringChange);
} }
} }
/// <summary> /// <summary>
/// Private method to encode username and password to Base64 string /// Private method to encode username and password to Base64 string
/// </summary> /// </summary>
/// <param name="username"></param> /// <param name="username"></param>
/// <param name="password"></param> /// <param name="password"></param>
/// <returns>authorization</returns> /// <returns>authorization</returns>
private string EncodeBase64(string username, string password) private string EncodeBase64(string username, string password)
{ {
var authorization = ""; var authorization = "";
try try
{ {
if (!string.IsNullOrEmpty(username)) if (!string.IsNullOrEmpty(username))
{ {
string base64String = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(string.Format("{0}:{1}", username, password))); string base64String = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(string.Format("{0}:{1}", username, password)));
authorization = string.Format("Basic {0}", base64String); authorization = string.Format("Basic {0}", base64String);
} }
} }
catch (Exception e) catch (Exception e)
{ {
var msg = string.Format("EncodeBase64({0}, {1}) failed:\r{2}", username, password, e); var msg = string.Format("EncodeBase64({0}, {1}) failed:\r{2}", username, password, e);
CrestronConsole.PrintLine(msg); CrestronConsole.PrintLine(msg);
ErrorLog.Error(msg); ErrorLog.Error(msg);
return "" ; return "" ;
} }
return authorization; return authorization;
} }
/// <summary> /// <summary>
/// Protected method to handle boolean change events /// Protected method to handle boolean change events
/// </summary> /// </summary>
/// <param name="state"></param> /// <param name="state"></param>
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="type"></param> /// <param name="type"></param>
protected void OnBoolChange(bool state, ushort index, ushort type) protected void OnBoolChange(bool state, ushort index, ushort type)
{ {
var handler = BoolChange; var handler = BoolChange;
if (handler != null) if (handler != null)
{ {
var args = new BoolChangeEventArgs(state, type); var args = new BoolChangeEventArgs(state, type);
args.Index = index; args.Index = index;
BoolChange(this, args); BoolChange(this, args);
} }
} }
/// <summary> /// <summary>
/// Protected mehtod to handle ushort change events /// Protected mehtod to handle ushort change events
/// </summary> /// </summary>
/// <param name="value"></param> /// <param name="value"></param>
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="type"></param> /// <param name="type"></param>
protected void OnUshrtChange(ushort value, ushort index, ushort type) protected void OnUshrtChange(ushort value, ushort index, ushort type)
{ {
var handler = UshrtChange; var handler = UshrtChange;
if (handler != null) if (handler != null)
{ {
var args = new UshrtChangeEventArgs(value, type); var args = new UshrtChangeEventArgs(value, type);
args.Index = index; args.Index = index;
UshrtChange(this, args); UshrtChange(this, args);
} }
} }
/// <summary> /// <summary>
/// Protected method to handle string change events /// Protected method to handle string change events
/// </summary> /// </summary>
/// <param name="value"></param> /// <param name="value"></param>
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="type"></param> /// <param name="type"></param>
protected void OnStringChange(string value, ushort index, ushort type) protected void OnStringChange(string value, ushort index, ushort type)
{ {
var handler = StringChange; var handler = StringChange;
if (handler != null) if (handler != null)
{ {
var args = new StringChangeEventArgs(value, type); var args = new StringChangeEventArgs(value, type);
args.Index = index; args.Index = index;
StringChange(this, args); StringChange(this, args);
} }
} }
} }
} }

View file

@ -1,77 +1,77 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.JsonStandardObjects namespace PepperDash.Core.JsonStandardObjects
{ {
/// <summary> /// <summary>
/// Constants for simpl modules /// Constants for simpl modules
/// </summary> /// </summary>
public class JsonStandardDeviceConstants public class JsonStandardDeviceConstants
{ {
/// <summary> /// <summary>
/// Json object evaluated constant /// Json object evaluated constant
/// </summary> /// </summary>
public const ushort JsonObjectEvaluated = 2; public const ushort JsonObjectEvaluated = 2;
/// <summary> /// <summary>
/// Json object changed constant /// Json object changed constant
/// </summary> /// </summary>
public const ushort JsonObjectChanged = 104; public const ushort JsonObjectChanged = 104;
} }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public class DeviceChangeEventArgs : EventArgs public class DeviceChangeEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// Device change event args object /// Device change event args object
/// </summary> /// </summary>
public DeviceConfig Device { get; set; } public DeviceConfig Device { get; set; }
/// <summary> /// <summary>
/// Device change event args type /// Device change event args type
/// </summary> /// </summary>
public ushort Type { get; set; } public ushort Type { get; set; }
/// <summary> /// <summary>
/// Device change event args index /// Device change event args index
/// </summary> /// </summary>
public ushort Index { get; set; } public ushort Index { get; set; }
/// <summary> /// <summary>
/// Default constructor /// Default constructor
/// </summary> /// </summary>
public DeviceChangeEventArgs() public DeviceChangeEventArgs()
{ {
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="device"></param> /// <param name="device"></param>
/// <param name="type"></param> /// <param name="type"></param>
public DeviceChangeEventArgs(DeviceConfig device, ushort type) public DeviceChangeEventArgs(DeviceConfig device, ushort type)
{ {
Device = device; Device = device;
Type = type; Type = type;
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="device"></param> /// <param name="device"></param>
/// <param name="type"></param> /// <param name="type"></param>
/// <param name="index"></param> /// <param name="index"></param>
public DeviceChangeEventArgs(DeviceConfig device, ushort type, ushort index) public DeviceChangeEventArgs(DeviceConfig device, ushort type, ushort index)
{ {
Device = device; Device = device;
Type = type; Type = type;
Index = index; Index = index;
} }
} }
} }

View file

@ -1,186 +1,182 @@
using System; using System;
using System.Collections.Generic; using System.Linq;
using System.Linq; using Crestron.SimplSharp;
using System.Text; using PepperDash.Core.JsonToSimpl;
using Crestron.SimplSharp;
using Newtonsoft.Json; namespace PepperDash.Core.JsonStandardObjects
using Newtonsoft.Json.Linq; {
using PepperDash.Core.JsonToSimpl; /// <summary>
/// Device class
namespace PepperDash.Core.JsonStandardObjects /// </summary>
{ public class DeviceConfig
/// <summary> {
/// Device class /// <summary>
/// </summary> /// JSON config key property
public class DeviceConfig /// </summary>
{ public string key { get; set; }
/// <summary> /// <summary>
/// JSON config key property /// JSON config name property
/// </summary> /// </summary>
public string key { get; set; } public string name { get; set; }
/// <summary> /// <summary>
/// JSON config name property /// JSON config type property
/// </summary> /// </summary>
public string name { get; set; } public string type { get; set; }
/// <summary> /// <summary>
/// JSON config type property /// JSON config properties
/// </summary> /// </summary>
public string type { get; set; } public PropertiesConfig properties { get; set; }
/// <summary>
/// JSON config properties /// <summary>
/// </summary> /// Bool change event handler
public PropertiesConfig properties { get; set; } /// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary> /// <summary>
/// Bool change event handler /// Ushort change event handler
/// </summary> /// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange; public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary> /// <summary>
/// Ushort change event handler /// String change event handler
/// </summary> /// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange; public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary> /// <summary>
/// String change event handler /// Object change event handler
/// </summary> /// </summary>
public event EventHandler<StringChangeEventArgs> StringChange; public event EventHandler<DeviceChangeEventArgs> DeviceChange;
/// <summary>
/// Object change event handler /// <summary>
/// </summary> /// Constructor
public event EventHandler<DeviceChangeEventArgs> DeviceChange; /// </summary>
public DeviceConfig()
/// <summary> {
/// Constructor properties = new PropertiesConfig();
/// </summary> }
public DeviceConfig()
{ /// <summary>
properties = new PropertiesConfig(); /// Initialize method
} /// </summary>
/// <param name="uniqueID"></param>
/// <summary> /// <param name="deviceKey"></param>
/// Initialize method public void Initialize(string uniqueID, string deviceKey)
/// </summary> {
/// <param name="uniqueID"></param> // S+ set EvaluateFb low
/// <param name="deviceKey"></param> OnBoolChange(false, 0, JsonStandardDeviceConstants.JsonObjectEvaluated);
public void Initialize(string uniqueID, string deviceKey) // validate parameters
{ if (string.IsNullOrEmpty(uniqueID) || string.IsNullOrEmpty(deviceKey))
// S+ set EvaluateFb low {
OnBoolChange(false, 0, JsonStandardDeviceConstants.JsonObjectEvaluated); Debug.Console(1, "UniqueID ({0} or key ({1} is null or empty", uniqueID, deviceKey);
// validate parameters // S+ set EvaluteFb high
if (string.IsNullOrEmpty(uniqueID) || string.IsNullOrEmpty(deviceKey)) OnBoolChange(true, 0, JsonStandardDeviceConstants.JsonObjectEvaluated);
{ return;
Debug.Console(1, "UniqueID ({0} or key ({1} is null or empty", uniqueID, deviceKey); }
// S+ set EvaluteFb high
OnBoolChange(true, 0, JsonStandardDeviceConstants.JsonObjectEvaluated); key = deviceKey;
return;
} try
{
key = deviceKey; // get the file using the unique ID
JsonToSimplMaster jsonMaster = J2SGlobal.GetMasterByFile(uniqueID);
try if (jsonMaster == null)
{ {
// get the file using the unique ID Debug.Console(1, "Could not find JSON file with uniqueID {0}", uniqueID);
JsonToSimplMaster jsonMaster = J2SGlobal.GetMasterByFile(uniqueID); return;
if (jsonMaster == null) }
{
Debug.Console(1, "Could not find JSON file with uniqueID {0}", uniqueID); // get the device configuration using the key
return; var devices = jsonMaster.JsonObject.ToObject<RootObject>().devices;
} var device = devices.FirstOrDefault(d => d.key.Equals(key));
if (device == null)
// get the device configuration using the key {
var devices = jsonMaster.JsonObject.ToObject<RootObject>().devices; Debug.Console(1, "Could not find device with key {0}", key);
var device = devices.FirstOrDefault(d => d.key.Equals(key)); return;
if (device == null) }
{ OnObjectChange(device, 0, JsonStandardDeviceConstants.JsonObjectChanged);
Debug.Console(1, "Could not find device with key {0}", key);
return; var index = devices.IndexOf(device);
} OnStringChange(string.Format("devices[{0}]", index), 0, JsonToSimplConstants.FullPathToArrayChange);
OnObjectChange(device, 0, JsonStandardDeviceConstants.JsonObjectChanged); }
catch (Exception e)
var index = devices.IndexOf(device); {
OnStringChange(string.Format("devices[{0}]", index), 0, JsonToSimplConstants.FullPathToArrayChange); var msg = string.Format("Device {0} lookup failed:\r{1}", key, e);
} CrestronConsole.PrintLine(msg);
catch (Exception e) ErrorLog.Error(msg);
{ }
var msg = string.Format("Device {0} lookup failed:\r{1}", key, e); finally
CrestronConsole.PrintLine(msg); {
ErrorLog.Error(msg); // S+ set EvaluteFb high
} OnBoolChange(true, 0, JsonStandardDeviceConstants.JsonObjectEvaluated);
finally }
{ }
// S+ set EvaluteFb high
OnBoolChange(true, 0, JsonStandardDeviceConstants.JsonObjectEvaluated); #region EventHandler Helpers
}
} /// <summary>
/// BoolChange event handler helper
#region EventHandler Helpers /// </summary>
/// <param name="state"></param>
/// <summary> /// <param name="index"></param>
/// BoolChange event handler helper /// <param name="type"></param>
/// </summary> protected void OnBoolChange(bool state, ushort index, ushort type)
/// <param name="state"></param> {
/// <param name="index"></param> var handler = BoolChange;
/// <param name="type"></param> if (handler != null)
protected void OnBoolChange(bool state, ushort index, ushort type) {
{ var args = new BoolChangeEventArgs(state, type);
var handler = BoolChange; args.Index = index;
if (handler != null) BoolChange(this, args);
{ }
var args = new BoolChangeEventArgs(state, type); }
args.Index = index;
BoolChange(this, args); /// <summary>
} /// UshrtChange event handler helper
} /// </summary>
/// <param name="state"></param>
/// <summary> /// <param name="index"></param>
/// UshrtChange event handler helper /// <param name="type"></param>
/// </summary> protected void OnUshrtChange(ushort state, ushort index, ushort type)
/// <param name="state"></param> {
/// <param name="index"></param> var handler = UshrtChange;
/// <param name="type"></param> if (handler != null)
protected void OnUshrtChange(ushort state, ushort index, ushort type) {
{ var args = new UshrtChangeEventArgs(state, type);
var handler = UshrtChange; args.Index = index;
if (handler != null) UshrtChange(this, args);
{ }
var args = new UshrtChangeEventArgs(state, type); }
args.Index = index;
UshrtChange(this, args); /// <summary>
} /// StringChange event handler helper
} /// </summary>
/// <param name="value"></param>
/// <summary> /// <param name="index"></param>
/// StringChange event handler helper /// <param name="type"></param>
/// </summary> protected void OnStringChange(string value, ushort index, ushort type)
/// <param name="value"></param> {
/// <param name="index"></param> var handler = StringChange;
/// <param name="type"></param> if (handler != null)
protected void OnStringChange(string value, ushort index, ushort type) {
{ var args = new StringChangeEventArgs(value, type);
var handler = StringChange; args.Index = index;
if (handler != null) StringChange(this, args);
{ }
var args = new StringChangeEventArgs(value, type); }
args.Index = index;
StringChange(this, args); /// <summary>
} /// ObjectChange event handler helper
} /// </summary>
/// <param name="device"></param>
/// <summary> /// <param name="index"></param>
/// ObjectChange event handler helper /// <param name="type"></param>
/// </summary> protected void OnObjectChange(DeviceConfig device, ushort index, ushort type)
/// <param name="device"></param> {
/// <param name="index"></param> if (DeviceChange != null)
/// <param name="type"></param> {
protected void OnObjectChange(DeviceConfig device, ushort index, ushort type) var args = new DeviceChangeEventArgs(device, type);
{ args.Index = index;
if (DeviceChange != null) DeviceChange(this, args);
{ }
var args = new DeviceChangeEventArgs(device, type); }
args.Index = index;
DeviceChange(this, args); #endregion EventHandler Helpers
} }
}
#endregion EventHandler Helpers
}
} }

View file

@ -1,257 +1,257 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.JsonStandardObjects namespace PepperDash.Core.JsonStandardObjects
{ {
/* /*
Convert JSON snippt to C#: http://json2csharp.com/# Convert JSON snippt to C#: http://json2csharp.com/#
JSON Snippet: JSON Snippet:
{ {
"devices": [ "devices": [
{ {
"key": "deviceKey", "key": "deviceKey",
"name": "deviceName", "name": "deviceName",
"type": "deviceType", "type": "deviceType",
"properties": { "properties": {
"deviceId": 1, "deviceId": 1,
"enabled": true, "enabled": true,
"control": { "control": {
"method": "methodName", "method": "methodName",
"controlPortDevKey": "deviceControlPortDevKey", "controlPortDevKey": "deviceControlPortDevKey",
"controlPortNumber": 1, "controlPortNumber": 1,
"comParams": { "comParams": {
"baudRate": 9600, "baudRate": 9600,
"dataBits": 8, "dataBits": 8,
"stopBits": 1, "stopBits": 1,
"parity": "None", "parity": "None",
"protocol": "RS232", "protocol": "RS232",
"hardwareHandshake": "None", "hardwareHandshake": "None",
"softwareHandshake": "None", "softwareHandshake": "None",
"pacing": 0 "pacing": 0
}, },
"tcpSshProperties": { "tcpSshProperties": {
"address": "172.22.1.101", "address": "172.22.1.101",
"port": 23, "port": 23,
"username": "user01", "username": "user01",
"password": "password01", "password": "password01",
"autoReconnect": false, "autoReconnect": false,
"autoReconnectIntervalMs": 10000 "autoReconnectIntervalMs": 10000
} }
} }
} }
} }
] ]
} }
*/ */
/// <summary> /// <summary>
/// Device communication parameter class /// Device communication parameter class
/// </summary> /// </summary>
public class ComParamsConfig public class ComParamsConfig
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int baudRate { get; set; } public int baudRate { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int dataBits { get; set; } public int dataBits { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int stopBits { get; set; } public int stopBits { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string parity { get; set; } public string parity { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string protocol { get; set; } public string protocol { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string hardwareHandshake { get; set; } public string hardwareHandshake { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string softwareHandshake { get; set; } public string softwareHandshake { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int pacing { get; set; } public int pacing { get; set; }
// convert properties for simpl // convert properties for simpl
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort simplBaudRate { get { return Convert.ToUInt16(baudRate); } } public ushort simplBaudRate { get { return Convert.ToUInt16(baudRate); } }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort simplDataBits { get { return Convert.ToUInt16(dataBits); } } public ushort simplDataBits { get { return Convert.ToUInt16(dataBits); } }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort simplStopBits { get { return Convert.ToUInt16(stopBits); } } public ushort simplStopBits { get { return Convert.ToUInt16(stopBits); } }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort simplPacing { get { return Convert.ToUInt16(pacing); } } public ushort simplPacing { get { return Convert.ToUInt16(pacing); } }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ComParamsConfig() public ComParamsConfig()
{ {
} }
} }
/// <summary> /// <summary>
/// Device TCP/SSH properties class /// Device TCP/SSH properties class
/// </summary> /// </summary>
public class TcpSshPropertiesConfig public class TcpSshPropertiesConfig
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string address { get; set; } public string address { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int port { get; set; } public int port { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string username { get; set; } public string username { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string password { get; set; } public string password { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public bool autoReconnect { get; set; } public bool autoReconnect { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int autoReconnectIntervalMs { get; set; } public int autoReconnectIntervalMs { get; set; }
// convert properties for simpl // convert properties for simpl
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort simplPort { get { return Convert.ToUInt16(port); } } public ushort simplPort { get { return Convert.ToUInt16(port); } }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort simplAutoReconnect { get { return (ushort)(autoReconnect ? 1 : 0); } } public ushort simplAutoReconnect { get { return (ushort)(autoReconnect ? 1 : 0); } }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort simplAutoReconnectIntervalMs { get { return Convert.ToUInt16(autoReconnectIntervalMs); } } public ushort simplAutoReconnectIntervalMs { get { return Convert.ToUInt16(autoReconnectIntervalMs); } }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public TcpSshPropertiesConfig() public TcpSshPropertiesConfig()
{ {
} }
} }
/// <summary> /// <summary>
/// Device control class /// Device control class
/// </summary> /// </summary>
public class ControlConfig public class ControlConfig
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string method { get; set; } public string method { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string controlPortDevKey { get; set; } public string controlPortDevKey { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int controlPortNumber { get; set; } public int controlPortNumber { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ComParamsConfig comParams { get; set; } public ComParamsConfig comParams { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public TcpSshPropertiesConfig tcpSshProperties { get; set; } public TcpSshPropertiesConfig tcpSshProperties { get; set; }
// convert properties for simpl // convert properties for simpl
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort simplControlPortNumber { get { return Convert.ToUInt16(controlPortNumber); } } public ushort simplControlPortNumber { get { return Convert.ToUInt16(controlPortNumber); } }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ControlConfig() public ControlConfig()
{ {
comParams = new ComParamsConfig(); comParams = new ComParamsConfig();
tcpSshProperties = new TcpSshPropertiesConfig(); tcpSshProperties = new TcpSshPropertiesConfig();
} }
} }
/// <summary> /// <summary>
/// Device properties class /// Device properties class
/// </summary> /// </summary>
public class PropertiesConfig public class PropertiesConfig
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public int deviceId { get; set; } public int deviceId { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public bool enabled { get; set; } public bool enabled { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ControlConfig control { get; set; } public ControlConfig control { get; set; }
// convert properties for simpl // convert properties for simpl
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort simplDeviceId { get { return Convert.ToUInt16(deviceId); } } public ushort simplDeviceId { get { return Convert.ToUInt16(deviceId); } }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort simplEnabled { get { return (ushort)(enabled ? 1 : 0); } } public ushort simplEnabled { get { return (ushort)(enabled ? 1 : 0); } }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public PropertiesConfig() public PropertiesConfig()
{ {
control = new ControlConfig(); control = new ControlConfig();
} }
} }
/// <summary> /// <summary>
/// Root device class /// Root device class
/// </summary> /// </summary>
public class RootObject public class RootObject
{ {
/// <summary> /// <summary>
/// The collection of devices /// The collection of devices
/// </summary> /// </summary>
public List<DeviceConfig> devices { get; set; } public List<DeviceConfig> devices { get; set; }
} }
} }

View file

@ -1,143 +1,143 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl
{ {
/// <summary> /// <summary>
/// Constants for Simpl modules /// Constants for Simpl modules
/// </summary> /// </summary>
public class JsonToSimplConstants public class JsonToSimplConstants
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort BoolValueChange = 1; public const ushort BoolValueChange = 1;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort JsonIsValidBoolChange = 2; public const ushort JsonIsValidBoolChange = 2;
/// <summary> /// <summary>
/// Reports the if the device is 3-series compatible /// Reports the if the device is 3-series compatible
/// </summary> /// </summary>
public const ushort ProgramCompatibility3SeriesChange = 3; public const ushort ProgramCompatibility3SeriesChange = 3;
/// <summary> /// <summary>
/// Reports the if the device is 4-series compatible /// Reports the if the device is 4-series compatible
/// </summary> /// </summary>
public const ushort ProgramCompatibility4SeriesChange = 4; public const ushort ProgramCompatibility4SeriesChange = 4;
/// <summary> /// <summary>
/// Reports the device platform enum value /// Reports the device platform enum value
/// </summary> /// </summary>
public const ushort DevicePlatformValueChange = 5; public const ushort DevicePlatformValueChange = 5;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort UshortValueChange = 101; public const ushort UshortValueChange = 101;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort StringValueChange = 201; public const ushort StringValueChange = 201;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort FullPathToArrayChange = 202; public const ushort FullPathToArrayChange = 202;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort ActualFilePathChange = 203; public const ushort ActualFilePathChange = 203;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort FilenameResolvedChange = 204; public const ushort FilenameResolvedChange = 204;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort FilePathResolvedChange = 205; public const ushort FilePathResolvedChange = 205;
/// <summary> /// <summary>
/// Reports the root directory change /// Reports the root directory change
/// </summary> /// </summary>
public const ushort RootDirectoryChange = 206; public const ushort RootDirectoryChange = 206;
/// <summary> /// <summary>
/// Reports the room ID change /// Reports the room ID change
/// </summary> /// </summary>
public const ushort RoomIdChange = 207; public const ushort RoomIdChange = 207;
/// <summary> /// <summary>
/// Reports the room name change /// Reports the room name change
/// </summary> /// </summary>
public const ushort RoomNameChange = 208; public const ushort RoomNameChange = 208;
} }
/// <summary> /// <summary>
/// S+ values delegate /// S+ values delegate
/// </summary> /// </summary>
public delegate void SPlusValuesDelegate(); public delegate void SPlusValuesDelegate();
/// <summary> /// <summary>
/// S+ values wrapper /// S+ values wrapper
/// </summary> /// </summary>
public class SPlusValueWrapper public class SPlusValueWrapper
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public SPlusType ValueType { get; private set; } public SPlusType ValueType { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort Index { get; private set; } public ushort Index { get; private set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort BoolUShortValue { get; set; } public ushort BoolUShortValue { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string StringValue { get; set; } public string StringValue { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public SPlusValueWrapper() {} public SPlusValueWrapper() {}
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
/// <param name="type"></param> /// <param name="type"></param>
/// <param name="index"></param> /// <param name="index"></param>
public SPlusValueWrapper(SPlusType type, ushort index) public SPlusValueWrapper(SPlusType type, ushort index)
{ {
ValueType = type; ValueType = type;
Index = index; Index = index;
} }
} }
/// <summary> /// <summary>
/// S+ types enum /// S+ types enum
/// </summary> /// </summary>
public enum SPlusType public enum SPlusType
{ {
/// <summary> /// <summary>
/// Digital /// Digital
/// </summary> /// </summary>
Digital, Digital,
/// <summary> /// <summary>
/// Analog /// Analog
/// </summary> /// </summary>
Analog, Analog,
/// <summary> /// <summary>
/// String /// String
/// </summary> /// </summary>
String String
} }
} }

View file

@ -1,165 +1,161 @@
using System; using System;
using System.Collections.Generic; using System.Linq;
using System.Linq; using Newtonsoft.Json.Linq;
using System.Text;
using Crestron.SimplSharp; namespace PepperDash.Core.JsonToSimpl
using Newtonsoft.Json; {
using Newtonsoft.Json.Linq; /// <summary>
/// Used to interact with an array of values with the S+ modules
namespace PepperDash.Core.JsonToSimpl /// </summary>
{ public class JsonToSimplArrayLookupChild : JsonToSimplChildObjectBase
/// <summary> {
/// Used to interact with an array of values with the S+ modules /// <summary>
/// </summary> ///
public class JsonToSimplArrayLookupChild : JsonToSimplChildObjectBase /// </summary>
{ public string SearchPropertyName { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string SearchPropertyName { get; set; } public string SearchPropertyValue { get; set; }
/// <summary>
/// int ArrayIndex;
/// </summary>
public string SearchPropertyValue { get; set; } /// <summary>
/// For gt2.4.1 array lookups
int ArrayIndex; /// </summary>
/// <param name="file"></param>
/// <summary> /// <param name="key"></param>
/// For gt2.4.1 array lookups /// <param name="pathPrefix"></param>
/// </summary> /// <param name="pathSuffix"></param>
/// <param name="file"></param> /// <param name="searchPropertyName"></param>
/// <param name="key"></param> /// <param name="searchPropertyValue"></param>
/// <param name="pathPrefix"></param> public void Initialize(string file, string key, string pathPrefix, string pathSuffix,
/// <param name="pathSuffix"></param> string searchPropertyName, string searchPropertyValue)
/// <param name="searchPropertyName"></param> {
/// <param name="searchPropertyValue"></param> base.Initialize(file, key, pathPrefix, pathSuffix);
public void Initialize(string file, string key, string pathPrefix, string pathSuffix, SearchPropertyName = searchPropertyName;
string searchPropertyName, string searchPropertyValue) SearchPropertyValue = searchPropertyValue;
{ }
base.Initialize(file, key, pathPrefix, pathSuffix);
SearchPropertyName = searchPropertyName;
SearchPropertyValue = searchPropertyValue; /// <summary>
} /// For newer >=2.4.1 array lookups.
/// </summary>
/// <param name="file"></param>
/// <summary> /// <param name="key"></param>
/// For newer >=2.4.1 array lookups. /// <param name="pathPrefix"></param>
/// </summary> /// <param name="pathAppend"></param>
/// <param name="file"></param> /// <param name="pathSuffix"></param>
/// <param name="key"></param> /// <param name="searchPropertyName"></param>
/// <param name="pathPrefix"></param> /// <param name="searchPropertyValue"></param>
/// <param name="pathAppend"></param> public void InitializeWithAppend(string file, string key, string pathPrefix, string pathAppend,
/// <param name="pathSuffix"></param> string pathSuffix, string searchPropertyName, string searchPropertyValue)
/// <param name="searchPropertyName"></param> {
/// <param name="searchPropertyValue"></param> string pathPrefixWithAppend = (pathPrefix != null ? pathPrefix : "") + GetPathAppend(pathAppend);
public void InitializeWithAppend(string file, string key, string pathPrefix, string pathAppend, base.Initialize(file, key, pathPrefixWithAppend, pathSuffix);
string pathSuffix, string searchPropertyName, string searchPropertyValue)
{ SearchPropertyName = searchPropertyName;
string pathPrefixWithAppend = (pathPrefix != null ? pathPrefix : "") + GetPathAppend(pathAppend); SearchPropertyValue = searchPropertyValue;
base.Initialize(file, key, pathPrefixWithAppend, pathSuffix); }
SearchPropertyName = searchPropertyName;
SearchPropertyValue = searchPropertyValue;
} //PathPrefix+ArrayName+[x]+path+PathSuffix
/// <summary>
///
/// </summary>
//PathPrefix+ArrayName+[x]+path+PathSuffix /// <param name="path"></param>
/// <summary> /// <returns></returns>
/// protected override string GetFullPath(string path)
/// </summary> {
/// <param name="path"></param> return string.Format("{0}[{1}].{2}{3}",
/// <returns></returns> PathPrefix == null ? "" : PathPrefix,
protected override string GetFullPath(string path) ArrayIndex,
{ path,
return string.Format("{0}[{1}].{2}{3}", PathSuffix == null ? "" : PathSuffix);
PathPrefix == null ? "" : PathPrefix, }
ArrayIndex,
path, /// <summary>
PathSuffix == null ? "" : PathSuffix); /// Process all values
} /// </summary>
public override void ProcessAll()
/// <summary> {
/// Process all values if (FindInArray())
/// </summary> base.ProcessAll();
public override void ProcessAll() }
{
if (FindInArray()) /// <summary>
base.ProcessAll(); /// Provides the path append for GetFullPath
} /// </summary>
/// <returns></returns>
/// <summary> string GetPathAppend(string a)
/// Provides the path append for GetFullPath {
/// </summary> if (string.IsNullOrEmpty(a))
/// <returns></returns> {
string GetPathAppend(string a) return "";
{ }
if (string.IsNullOrEmpty(a)) if (a.StartsWith("."))
{ {
return ""; return a;
} }
if (a.StartsWith(".")) else
{ {
return a; return "." + a;
} }
else }
{
return "." + a; /// <summary>
} ///
} /// </summary>
/// <returns></returns>
/// <summary> bool FindInArray()
/// {
/// </summary> if (Master == null)
/// <returns></returns> throw new InvalidOperationException("Cannot do operations before master is linked");
bool FindInArray() if (Master.JsonObject == null)
{ throw new InvalidOperationException("Cannot do operations before master JSON has read");
if (Master == null) if (PathPrefix == null)
throw new InvalidOperationException("Cannot do operations before master is linked"); throw new InvalidOperationException("Cannot do operations before PathPrefix is set");
if (Master.JsonObject == null)
throw new InvalidOperationException("Cannot do operations before master JSON has read");
if (PathPrefix == null) var token = Master.JsonObject.SelectToken(PathPrefix);
throw new InvalidOperationException("Cannot do operations before PathPrefix is set"); if (token is JArray)
{
var array = token as JArray;
var token = Master.JsonObject.SelectToken(PathPrefix); try
if (token is JArray) {
{ var item = array.FirstOrDefault(o =>
var array = token as JArray; {
try var prop = o[SearchPropertyName];
{ return prop != null && prop.Value<string>()
var item = array.FirstOrDefault(o => .Equals(SearchPropertyValue, StringComparison.OrdinalIgnoreCase);
{ });
var prop = o[SearchPropertyName]; if (item == null)
return prop != null && prop.Value<string>() {
.Equals(SearchPropertyValue, StringComparison.OrdinalIgnoreCase); Debug.Console(1, "JSON Child[{0}] Array '{1}' '{2}={3}' not found: ", Key,
}); PathPrefix, SearchPropertyName, SearchPropertyValue);
if (item == null) this.LinkedToObject = false;
{ return false;
Debug.Console(1, "JSON Child[{0}] Array '{1}' '{2}={3}' not found: ", Key, }
PathPrefix, SearchPropertyName, SearchPropertyValue);
this.LinkedToObject = false; this.LinkedToObject = true;
return false; ArrayIndex = array.IndexOf(item);
} OnStringChange(string.Format("{0}[{1}]", PathPrefix, ArrayIndex), 0, JsonToSimplConstants.FullPathToArrayChange);
Debug.Console(1, "JSON Child[{0}] Found array match at index {1}", Key, ArrayIndex);
this.LinkedToObject = true; return true;
ArrayIndex = array.IndexOf(item); }
OnStringChange(string.Format("{0}[{1}]", PathPrefix, ArrayIndex), 0, JsonToSimplConstants.FullPathToArrayChange); catch (Exception e)
Debug.Console(1, "JSON Child[{0}] Found array match at index {1}", Key, ArrayIndex); {
return true; Debug.Console(1, "JSON Child[{0}] Array '{1}' lookup error: '{2}={3}'\r{4}", Key,
} PathPrefix, SearchPropertyName, SearchPropertyValue, e);
catch (Exception e) }
{ }
Debug.Console(1, "JSON Child[{0}] Array '{1}' lookup error: '{2}={3}'\r{4}", Key, else
PathPrefix, SearchPropertyName, SearchPropertyValue, e); {
} Debug.Console(1, "JSON Child[{0}] Path '{1}' is not an array", Key, PathPrefix);
} }
else
{ return false;
Debug.Console(1, "JSON Child[{0}] Path '{1}' is not an array", Key, PathPrefix); }
} }
return false;
}
}
} }

View file

@ -1,407 +1,404 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using Newtonsoft.Json.Linq;
using Crestron.SimplSharp;
using Newtonsoft.Json; namespace PepperDash.Core.JsonToSimpl
using Newtonsoft.Json.Linq; {
/// <summary>
namespace PepperDash.Core.JsonToSimpl /// Base class for JSON objects
{ /// </summary>
/// <summary> public abstract class JsonToSimplChildObjectBase : IKeyed
/// Base class for JSON objects {
/// </summary> /// <summary>
public abstract class JsonToSimplChildObjectBase : IKeyed /// Notifies of bool change
{ /// </summary>
/// <summary> public event EventHandler<BoolChangeEventArgs> BoolChange;
/// Notifies of bool change /// <summary>
/// </summary> /// Notifies of ushort change
public event EventHandler<BoolChangeEventArgs> BoolChange; /// </summary>
/// <summary> public event EventHandler<UshrtChangeEventArgs> UShortChange;
/// Notifies of ushort change /// <summary>
/// </summary> /// Notifies of string change
public event EventHandler<UshrtChangeEventArgs> UShortChange; /// </summary>
/// <summary> public event EventHandler<StringChangeEventArgs> StringChange;
/// Notifies of string change
/// </summary> /// <summary>
public event EventHandler<StringChangeEventArgs> StringChange; /// Delegate to get all values
/// </summary>
/// <summary> public SPlusValuesDelegate GetAllValuesDelegate { get; set; }
/// Delegate to get all values
/// </summary> /// <summary>
public SPlusValuesDelegate GetAllValuesDelegate { get; set; } /// Use a callback to reduce task switch/threading
/// </summary>
/// <summary> public SPlusValuesDelegate SetAllPathsDelegate { get; set; }
/// Use a callback to reduce task switch/threading
/// </summary> /// <summary>
public SPlusValuesDelegate SetAllPathsDelegate { get; set; } /// Unique identifier for instance
/// </summary>
/// <summary> public string Key { get; protected set; }
/// Unique identifier for instance
/// </summary> /// <summary>
public string Key { get; protected set; } /// This will be prepended to all paths to allow path swapping or for more organized
/// sub-paths
/// <summary> /// </summary>
/// This will be prepended to all paths to allow path swapping or for more organized public string PathPrefix { get; protected set; }
/// sub-paths
/// </summary> /// <summary>
public string PathPrefix { get; protected set; } /// This is added to the end of all paths
/// </summary>
/// <summary> public string PathSuffix { get; protected set; }
/// This is added to the end of all paths
/// </summary> /// <summary>
public string PathSuffix { get; protected set; } /// Indicates if the instance is linked to an object
/// </summary>
/// <summary> public bool LinkedToObject { get; protected set; }
/// Indicates if the instance is linked to an object
/// </summary> /// <summary>
public bool LinkedToObject { get; protected set; } /// Reference to Master instance
/// </summary>
/// <summary> protected JsonToSimplMaster Master;
/// Reference to Master instance
/// </summary> /// <summary>
protected JsonToSimplMaster Master; /// Paths to boolean values in JSON structure
/// </summary>
/// <summary> protected Dictionary<ushort, string> BoolPaths = new Dictionary<ushort, string>();
/// Paths to boolean values in JSON structure /// <summary>
/// </summary> /// Paths to numeric values in JSON structure
protected Dictionary<ushort, string> BoolPaths = new Dictionary<ushort, string>(); /// </summary>
/// <summary> protected Dictionary<ushort, string> UshortPaths = new Dictionary<ushort, string>();
/// Paths to numeric values in JSON structure /// <summary>
/// </summary> /// Paths to string values in JSON structure
protected Dictionary<ushort, string> UshortPaths = new Dictionary<ushort, string>(); /// </summary>
/// <summary> protected Dictionary<ushort, string> StringPaths = new Dictionary<ushort, string>();
/// Paths to string values in JSON structure
/// </summary> /// <summary>
protected Dictionary<ushort, string> StringPaths = new Dictionary<ushort, string>(); /// Call this before doing anything else
/// </summary>
/// <summary> /// <param name="masterUniqueId"></param>
/// Call this before doing anything else /// <param name="key"></param>
/// </summary> /// <param name="pathPrefix"></param>
/// <param name="masterUniqueId"></param> /// <param name="pathSuffix"></param>
/// <param name="key"></param> public void Initialize(string masterUniqueId, string key, string pathPrefix, string pathSuffix)
/// <param name="pathPrefix"></param> {
/// <param name="pathSuffix"></param> Key = key;
public void Initialize(string masterUniqueId, string key, string pathPrefix, string pathSuffix) PathPrefix = pathPrefix;
{ PathSuffix = pathSuffix;
Key = key;
PathPrefix = pathPrefix; Master = J2SGlobal.GetMasterByFile(masterUniqueId);
PathSuffix = pathSuffix; if (Master != null)
Master.AddChild(this);
Master = J2SGlobal.GetMasterByFile(masterUniqueId); else
if (Master != null) Debug.Console(1, "JSON Child [{0}] cannot link to master {1}", key, masterUniqueId);
Master.AddChild(this); }
else
Debug.Console(1, "JSON Child [{0}] cannot link to master {1}", key, masterUniqueId); /// <summary>
} /// Sets the path prefix for the object
/// </summary>
/// <summary> /// <param name="pathPrefix"></param>
/// Sets the path prefix for the object public void SetPathPrefix(string pathPrefix)
/// </summary> {
/// <param name="pathPrefix"></param> PathPrefix = pathPrefix;
public void SetPathPrefix(string pathPrefix) }
{ /// <summary>
PathPrefix = pathPrefix; /// Set the JPath to evaluate for a given bool out index.
} /// </summary>
/// <summary> public void SetBoolPath(ushort index, string path)
/// Set the JPath to evaluate for a given bool out index. {
/// </summary> Debug.Console(1, "JSON Child[{0}] SetBoolPath {1}={2}", Key, index, path);
public void SetBoolPath(ushort index, string path) if (path == null || path.Trim() == string.Empty) return;
{ BoolPaths[index] = path;
Debug.Console(1, "JSON Child[{0}] SetBoolPath {1}={2}", Key, index, path); }
if (path == null || path.Trim() == string.Empty) return;
BoolPaths[index] = path; /// <summary>
} /// Set the JPath for a ushort out index.
/// </summary>
/// <summary> public void SetUshortPath(ushort index, string path)
/// Set the JPath for a ushort out index. {
/// </summary> Debug.Console(1, "JSON Child[{0}] SetUshortPath {1}={2}", Key, index, path);
public void SetUshortPath(ushort index, string path) if (path == null || path.Trim() == string.Empty) return;
{ UshortPaths[index] = path;
Debug.Console(1, "JSON Child[{0}] SetUshortPath {1}={2}", Key, index, path); }
if (path == null || path.Trim() == string.Empty) return;
UshortPaths[index] = path; /// <summary>
} /// Set the JPath for a string output index.
/// </summary>
/// <summary> public void SetStringPath(ushort index, string path)
/// Set the JPath for a string output index. {
/// </summary> Debug.Console(1, "JSON Child[{0}] SetStringPath {1}={2}", Key, index, path);
public void SetStringPath(ushort index, string path) if (path == null || path.Trim() == string.Empty) return;
{ StringPaths[index] = path;
Debug.Console(1, "JSON Child[{0}] SetStringPath {1}={2}", Key, index, path); }
if (path == null || path.Trim() == string.Empty) return;
StringPaths[index] = path; /// <summary>
} /// Evalutates all outputs with defined paths. called by S+ when paths are ready to process
/// and by Master when file is read.
/// <summary> /// </summary>
/// Evalutates all outputs with defined paths. called by S+ when paths are ready to process public virtual void ProcessAll()
/// and by Master when file is read. {
/// </summary> if (!LinkedToObject)
public virtual void ProcessAll() {
{ Debug.Console(1, this, "Not linked to object in file. Skipping");
if (!LinkedToObject) return;
{ }
Debug.Console(1, this, "Not linked to object in file. Skipping");
return; if (SetAllPathsDelegate == null)
} {
Debug.Console(1, this, "No SetAllPathsDelegate set. Ignoring ProcessAll");
if (SetAllPathsDelegate == null) return;
{ }
Debug.Console(1, this, "No SetAllPathsDelegate set. Ignoring ProcessAll"); SetAllPathsDelegate();
return; foreach (var kvp in BoolPaths)
} ProcessBoolPath(kvp.Key);
SetAllPathsDelegate(); foreach (var kvp in UshortPaths)
foreach (var kvp in BoolPaths) ProcessUshortPath(kvp.Key);
ProcessBoolPath(kvp.Key); foreach (var kvp in StringPaths)
foreach (var kvp in UshortPaths) ProcessStringPath(kvp.Key);
ProcessUshortPath(kvp.Key); }
foreach (var kvp in StringPaths)
ProcessStringPath(kvp.Key); /// <summary>
} /// Processes a bool property, converting to bool, firing off a BoolChange event
/// </summary>
/// <summary> void ProcessBoolPath(ushort index)
/// Processes a bool property, converting to bool, firing off a BoolChange event {
/// </summary> string response;
void ProcessBoolPath(ushort index) if (Process(BoolPaths[index], out response))
{ OnBoolChange(response.Equals("true", StringComparison.OrdinalIgnoreCase),
string response; index, JsonToSimplConstants.BoolValueChange);
if (Process(BoolPaths[index], out response)) else { }
OnBoolChange(response.Equals("true", StringComparison.OrdinalIgnoreCase), // OnBoolChange(false, index, JsonToSimplConstants.BoolValueChange);
index, JsonToSimplConstants.BoolValueChange); }
else { }
// OnBoolChange(false, index, JsonToSimplConstants.BoolValueChange); // Processes the path to a ushort, converting to ushort if able, twos complement if necessary, firing off UshrtChange event
} void ProcessUshortPath(ushort index) {
string response;
// Processes the path to a ushort, converting to ushort if able, twos complement if necessary, firing off UshrtChange event if (Process(UshortPaths[index], out response)) {
void ProcessUshortPath(ushort index) { ushort val;
string response; try { val = Convert.ToInt32(response) < 0 ? (ushort)(Convert.ToInt16(response) + 65536) : Convert.ToUInt16(response); }
if (Process(UshortPaths[index], out response)) { catch { val = 0; }
ushort val;
try { val = Convert.ToInt32(response) < 0 ? (ushort)(Convert.ToInt16(response) + 65536) : Convert.ToUInt16(response); } OnUShortChange(val, index, JsonToSimplConstants.UshortValueChange);
catch { val = 0; } }
else { }
OnUShortChange(val, index, JsonToSimplConstants.UshortValueChange); // OnUShortChange(0, index, JsonToSimplConstants.UshortValueChange);
} }
else { }
// OnUShortChange(0, index, JsonToSimplConstants.UshortValueChange); // Processes the path to a string property and fires of a StringChange event.
} void ProcessStringPath(ushort index)
{
// Processes the path to a string property and fires of a StringChange event. string response;
void ProcessStringPath(ushort index) if (Process(StringPaths[index], out response))
{ OnStringChange(response, index, JsonToSimplConstants.StringValueChange);
string response; else { }
if (Process(StringPaths[index], out response)) // OnStringChange("", index, JsonToSimplConstants.StringValueChange);
OnStringChange(response, index, JsonToSimplConstants.StringValueChange); }
else { }
// OnStringChange("", index, JsonToSimplConstants.StringValueChange); /// <summary>
} /// Processes the given path.
/// </summary>
/// <summary> /// <param name="path">JPath formatted path to the desired property</param>
/// Processes the given path. /// <param name="response">The string value of the property, or a default value if it
/// </summary> /// doesn't exist</param>
/// <param name="path">JPath formatted path to the desired property</param> /// <returns> This will return false in the case that EvaulateAllOnJsonChange
/// <param name="response">The string value of the property, or a default value if it /// is false and the path does not evaluate to a property in the incoming JSON. </returns>
/// doesn't exist</param> bool Process(string path, out string response)
/// <returns> This will return false in the case that EvaulateAllOnJsonChange {
/// is false and the path does not evaluate to a property in the incoming JSON. </returns> path = GetFullPath(path);
bool Process(string path, out string response) Debug.Console(1, "JSON Child[{0}] Processing {1}", Key, path);
{ response = "";
path = GetFullPath(path); if (Master == null)
Debug.Console(1, "JSON Child[{0}] Processing {1}", Key, path); {
response = ""; Debug.Console(1, "JSONChild[{0}] cannot process without Master attached", Key);
if (Master == null) return false;
{ }
Debug.Console(1, "JSONChild[{0}] cannot process without Master attached", Key);
return false; if (Master.JsonObject != null && path != string.Empty)
} {
bool isCount = false;
if (Master.JsonObject != null && path != string.Empty) path = path.Trim();
{ if (path.EndsWith(".Count"))
bool isCount = false; {
path = path.Trim(); path = path.Remove(path.Length - 6, 6);
if (path.EndsWith(".Count")) isCount = true;
{ }
path = path.Remove(path.Length - 6, 6); try // Catch a strange cast error on a bad path
isCount = true; {
} var t = Master.JsonObject.SelectToken(path);
try // Catch a strange cast error on a bad path if (t != null)
{ {
var t = Master.JsonObject.SelectToken(path); // return the count of children objects - if any
if (t != null) if (isCount)
{ response = (t.HasValues ? t.Children().Count() : 0).ToString();
// return the count of children objects - if any else
if (isCount) response = t.Value<string>();
response = (t.HasValues ? t.Children().Count() : 0).ToString(); Debug.Console(1, " ='{0}'", response);
else return true;
response = t.Value<string>(); }
Debug.Console(1, " ='{0}'", response); }
return true; catch
} {
} response = "";
catch }
{ }
response = ""; // If the path isn't found, return this to determine whether to pass out the non-value or not.
} return false;
} }
// If the path isn't found, return this to determine whether to pass out the non-value or not.
return false;
} //************************************************************************************************
// Save-related functions
//************************************************************************************************
// Save-related functions /// <summary>
/// Called from Master to read inputs and update their values in master JObject
/// Callback should hit one of the following four methods
/// <summary> /// </summary>
/// Called from Master to read inputs and update their values in master JObject public void UpdateInputsForMaster()
/// Callback should hit one of the following four methods {
/// </summary> if (!LinkedToObject)
public void UpdateInputsForMaster() {
{ Debug.Console(1, this, "Not linked to object in file. Skipping");
if (!LinkedToObject) return;
{ }
Debug.Console(1, this, "Not linked to object in file. Skipping");
return; if (SetAllPathsDelegate == null)
} {
Debug.Console(1, this, "No SetAllPathsDelegate set. Ignoring UpdateInputsForMaster");
if (SetAllPathsDelegate == null) return;
{ }
Debug.Console(1, this, "No SetAllPathsDelegate set. Ignoring UpdateInputsForMaster"); SetAllPathsDelegate();
return; var del = GetAllValuesDelegate;
} if (del != null)
SetAllPathsDelegate(); GetAllValuesDelegate();
var del = GetAllValuesDelegate; }
if (del != null)
GetAllValuesDelegate(); /// <summary>
} ///
/// </summary>
/// <summary> /// <param name="key"></param>
/// /// <param name="theValue"></param>
/// </summary> public void USetBoolValue(ushort key, ushort theValue)
/// <param name="key"></param> {
/// <param name="theValue"></param> SetBoolValue(key, theValue == 1);
public void USetBoolValue(ushort key, ushort theValue) }
{
SetBoolValue(key, theValue == 1); /// <summary>
} ///
/// </summary>
/// <summary> /// <param name="key"></param>
/// /// <param name="theValue"></param>
/// </summary> public void SetBoolValue(ushort key, bool theValue)
/// <param name="key"></param> {
/// <param name="theValue"></param> if (BoolPaths.ContainsKey(key))
public void SetBoolValue(ushort key, bool theValue) SetValueOnMaster(BoolPaths[key], new JValue(theValue));
{ }
if (BoolPaths.ContainsKey(key))
SetValueOnMaster(BoolPaths[key], new JValue(theValue)); /// <summary>
} ///
/// </summary>
/// <summary> /// <param name="key"></param>
/// /// <param name="theValue"></param>
/// </summary> public void SetUShortValue(ushort key, ushort theValue)
/// <param name="key"></param> {
/// <param name="theValue"></param> if (UshortPaths.ContainsKey(key))
public void SetUShortValue(ushort key, ushort theValue) SetValueOnMaster(UshortPaths[key], new JValue(theValue));
{ }
if (UshortPaths.ContainsKey(key))
SetValueOnMaster(UshortPaths[key], new JValue(theValue)); /// <summary>
} ///
/// </summary>
/// <summary> /// <param name="key"></param>
/// /// <param name="theValue"></param>
/// </summary> public void SetStringValue(ushort key, string theValue)
/// <param name="key"></param> {
/// <param name="theValue"></param> if (StringPaths.ContainsKey(key))
public void SetStringValue(ushort key, string theValue) SetValueOnMaster(StringPaths[key], new JValue(theValue));
{ }
if (StringPaths.ContainsKey(key))
SetValueOnMaster(StringPaths[key], new JValue(theValue)); /// <summary>
} ///
/// </summary>
/// <summary> /// <param name="keyPath"></param>
/// /// <param name="valueToSave"></param>
/// </summary> public void SetValueOnMaster(string keyPath, JValue valueToSave)
/// <param name="keyPath"></param> {
/// <param name="valueToSave"></param> var path = GetFullPath(keyPath);
public void SetValueOnMaster(string keyPath, JValue valueToSave) try
{ {
var path = GetFullPath(keyPath); Debug.Console(1, "JSON Child[{0}] Queueing value on master {1}='{2}'", Key, path, valueToSave);
try
{ //var token = Master.JsonObject.SelectToken(path);
Debug.Console(1, "JSON Child[{0}] Queueing value on master {1}='{2}'", Key, path, valueToSave); //if (token != null) // The path exists in the file
Master.AddUnsavedValue(path, valueToSave);
//var token = Master.JsonObject.SelectToken(path); }
//if (token != null) // The path exists in the file catch (Exception e)
Master.AddUnsavedValue(path, valueToSave); {
} Debug.Console(1, "JSON Child[{0}] Failed setting value for path '{1}'\r{2}", Key, path, e);
catch (Exception e) }
{ }
Debug.Console(1, "JSON Child[{0}] Failed setting value for path '{1}'\r{2}", Key, path, e);
} /// <summary>
} /// Called during Process(...) to get the path to a given property. By default,
/// returns PathPrefix+path+PathSuffix. Override to change the way path is built.
/// <summary> /// </summary>
/// Called during Process(...) to get the path to a given property. By default, protected virtual string GetFullPath(string path)
/// returns PathPrefix+path+PathSuffix. Override to change the way path is built. {
/// </summary> return (PathPrefix != null ? PathPrefix : "") +
protected virtual string GetFullPath(string path) path + (PathSuffix != null ? PathSuffix : "");
{ }
return (PathPrefix != null ? PathPrefix : "") +
path + (PathSuffix != null ? PathSuffix : ""); // Helpers for events
} //******************************************************************************************
/// <summary>
// Helpers for events /// Event helper
//****************************************************************************************** /// </summary>
/// <summary> /// <param name="state"></param>
/// Event helper /// <param name="index"></param>
/// </summary> /// <param name="type"></param>
/// <param name="state"></param> protected void OnBoolChange(bool state, ushort index, ushort type)
/// <param name="index"></param> {
/// <param name="type"></param> var handler = BoolChange;
protected void OnBoolChange(bool state, ushort index, ushort type) if (handler != null)
{ {
var handler = BoolChange; var args = new BoolChangeEventArgs(state, type);
if (handler != null) args.Index = index;
{ BoolChange(this, args);
var args = new BoolChangeEventArgs(state, type); }
args.Index = index; }
BoolChange(this, args);
} //******************************************************************************************
} /// <summary>
/// Event helper
//****************************************************************************************** /// </summary>
/// <summary> /// <param name="state"></param>
/// Event helper /// <param name="index"></param>
/// </summary> /// <param name="type"></param>
/// <param name="state"></param> protected void OnUShortChange(ushort state, ushort index, ushort type)
/// <param name="index"></param> {
/// <param name="type"></param> var handler = UShortChange;
protected void OnUShortChange(ushort state, ushort index, ushort type) if (handler != null)
{ {
var handler = UShortChange; var args = new UshrtChangeEventArgs(state, type);
if (handler != null) args.Index = index;
{ UShortChange(this, args);
var args = new UshrtChangeEventArgs(state, type); }
args.Index = index; }
UShortChange(this, args);
} /// <summary>
} /// Event helper
/// </summary>
/// <summary> /// <param name="value"></param>
/// Event helper /// <param name="index"></param>
/// </summary> /// <param name="type"></param>
/// <param name="value"></param> protected void OnStringChange(string value, ushort index, ushort type)
/// <param name="index"></param> {
/// <param name="type"></param> var handler = StringChange;
protected void OnStringChange(string value, ushort index, ushort type) if (handler != null)
{ {
var handler = StringChange; var args = new StringChangeEventArgs(value, type);
if (handler != null) args.Index = index;
{ StringChange(this, args);
var args = new StringChangeEventArgs(value, type); }
args.Index = index; }
StringChange(this, args); }
}
}
}
} }

View file

@ -1,291 +1,289 @@
using System; using System;
//using System.IO; using System.Collections.Generic;
using System.Collections.Generic; using System.Linq;
using System.Linq; using System.Text;
using System.Text; using System.Text.RegularExpressions;
using System.Text.RegularExpressions; using Crestron.SimplSharp;
using Crestron.SimplSharp; using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.CrestronIO; using Newtonsoft.Json.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq; namespace PepperDash.Core.JsonToSimpl
{
namespace PepperDash.Core.JsonToSimpl /// <summary>
{ /// Represents a JSON file that can be read and written to
/// <summary> /// </summary>
/// Represents a JSON file that can be read and written to public class JsonToSimplFileMaster : JsonToSimplMaster
/// </summary> {
public class JsonToSimplFileMaster : JsonToSimplMaster /// <summary>
{ /// Sets the filepath as well as registers this with the Global.Masters list
/// <summary> /// </summary>
/// Sets the filepath as well as registers this with the Global.Masters list public string Filepath { get; private set; }
/// </summary>
public string Filepath { get; private set; } /// <summary>
/// Filepath to the actual file that will be read (Portal or local)
/// <summary> /// </summary>
/// Filepath to the actual file that will be read (Portal or local) public string ActualFilePath { get; private set; }
/// </summary>
public string ActualFilePath { get; private set; } /// <summary>
///
/// <summary> /// </summary>
/// public string Filename { get; private set; }
/// </summary> /// <summary>
public string Filename { get; private set; } ///
/// <summary> /// </summary>
/// public string FilePathName { get; private set; }
/// </summary>
public string FilePathName { get; private set; } /*****************************************************************************************/
/** Privates **/
/*****************************************************************************************/
/** Privates **/
// The JSON file in JObject form
// For gathering the incoming data
// The JSON file in JObject form object StringBuilderLock = new object();
// For gathering the incoming data // To prevent multiple same-file access
object StringBuilderLock = new object(); static object FileLock = new object();
// To prevent multiple same-file access
static object FileLock = new object(); /*****************************************************************************************/
/*****************************************************************************************/ /// <summary>
/// SIMPL+ default constructor.
/// <summary> /// </summary>
/// SIMPL+ default constructor. public JsonToSimplFileMaster()
/// </summary> {
public JsonToSimplFileMaster() }
{
} /// <summary>
/// Read, evaluate and udpate status
/// <summary> /// </summary>
/// Read, evaluate and udpate status public void EvaluateFile(string filepath)
/// </summary> {
public void EvaluateFile(string filepath) try
{ {
try OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange);
{
OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange); var dirSeparator = Path.DirectorySeparatorChar;
var dirSeparatorAlt = Path.AltDirectorySeparatorChar;
var dirSeparator = Path.DirectorySeparatorChar;
var dirSeparatorAlt = Path.AltDirectorySeparatorChar; var series = CrestronEnvironment.ProgramCompatibility;
var series = CrestronEnvironment.ProgramCompatibility; var is3Series = (eCrestronSeries.Series3 == (series & eCrestronSeries.Series3));
OnBoolChange(is3Series, 0,
var is3Series = (eCrestronSeries.Series3 == (series & eCrestronSeries.Series3)); JsonToSimplConstants.ProgramCompatibility3SeriesChange);
OnBoolChange(is3Series, 0,
JsonToSimplConstants.ProgramCompatibility3SeriesChange); var is4Series = (eCrestronSeries.Series4 == (series & eCrestronSeries.Series4));
OnBoolChange(is4Series, 0,
var is4Series = (eCrestronSeries.Series4 == (series & eCrestronSeries.Series4)); JsonToSimplConstants.ProgramCompatibility4SeriesChange);
OnBoolChange(is4Series, 0,
JsonToSimplConstants.ProgramCompatibility4SeriesChange); var isServer = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server;
OnBoolChange(isServer, 0,
var isServer = CrestronEnvironment.DevicePlatform == eDevicePlatform.Server; JsonToSimplConstants.DevicePlatformValueChange);
OnBoolChange(isServer, 0,
JsonToSimplConstants.DevicePlatformValueChange); // get the roomID
var roomId = Crestron.SimplSharp.InitialParametersClass.RoomId;
// get the roomID if (!string.IsNullOrEmpty(roomId))
var roomId = Crestron.SimplSharp.InitialParametersClass.RoomId; {
if (!string.IsNullOrEmpty(roomId)) OnStringChange(roomId, 0, JsonToSimplConstants.RoomIdChange);
{ }
OnStringChange(roomId, 0, JsonToSimplConstants.RoomIdChange);
} // get the roomName
var roomName = Crestron.SimplSharp.InitialParametersClass.RoomName;
// get the roomName if (!string.IsNullOrEmpty(roomName))
var roomName = Crestron.SimplSharp.InitialParametersClass.RoomName; {
if (!string.IsNullOrEmpty(roomName)) OnStringChange(roomName, 0, JsonToSimplConstants.RoomNameChange);
{ }
OnStringChange(roomName, 0, JsonToSimplConstants.RoomNameChange);
} var rootDirectory = Directory.GetApplicationRootDirectory();
OnStringChange(rootDirectory, 0, JsonToSimplConstants.RootDirectoryChange);
var rootDirectory = Directory.GetApplicationRootDirectory();
OnStringChange(rootDirectory, 0, JsonToSimplConstants.RootDirectoryChange); var splusPath = string.Empty;
if (Regex.IsMatch(filepath, @"user", RegexOptions.IgnoreCase))
var splusPath = string.Empty; {
if (Regex.IsMatch(filepath, @"user", RegexOptions.IgnoreCase)) if (is4Series)
{ splusPath = Regex.Replace(filepath, "user", "user", RegexOptions.IgnoreCase);
if (is4Series) else if (isServer)
splusPath = Regex.Replace(filepath, "user", "user", RegexOptions.IgnoreCase); splusPath = Regex.Replace(filepath, "user", "User", RegexOptions.IgnoreCase);
else if (isServer) else
splusPath = Regex.Replace(filepath, "user", "User", RegexOptions.IgnoreCase); splusPath = filepath;
else }
splusPath = filepath;
} filepath = splusPath.Replace(dirSeparatorAlt, dirSeparator);
filepath = splusPath.Replace(dirSeparatorAlt, dirSeparator); Filepath = string.Format("{1}{0}{2}", dirSeparator, rootDirectory,
filepath.TrimStart(dirSeparator, dirSeparatorAlt));
Filepath = string.Format("{1}{0}{2}", dirSeparator, rootDirectory,
filepath.TrimStart(dirSeparator, dirSeparatorAlt)); OnStringChange(string.Format("Attempting to evaluate {0}", Filepath), 0, JsonToSimplConstants.StringValueChange);
OnStringChange(string.Format("Attempting to evaluate {0}", Filepath), 0, JsonToSimplConstants.StringValueChange); if (string.IsNullOrEmpty(Filepath))
{
if (string.IsNullOrEmpty(Filepath)) OnStringChange(string.Format("Cannot evaluate file. JSON file path not set"), 0, JsonToSimplConstants.StringValueChange);
{ CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set");
OnStringChange(string.Format("Cannot evaluate file. JSON file path not set"), 0, JsonToSimplConstants.StringValueChange); return;
CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set"); }
return;
} // get file directory and name to search
var fileDirectory = Path.GetDirectoryName(Filepath);
// get file directory and name to search var fileName = Path.GetFileName(Filepath);
var fileDirectory = Path.GetDirectoryName(Filepath);
var fileName = Path.GetFileName(Filepath); OnStringChange(string.Format("Checking '{0}' for '{1}'", fileDirectory, fileName), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "Checking '{0}' for '{1}'", fileDirectory, fileName);
OnStringChange(string.Format("Checking '{0}' for '{1}'", fileDirectory, fileName), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "Checking '{0}' for '{1}'", fileDirectory, fileName); if (Directory.Exists(fileDirectory))
{
if (Directory.Exists(fileDirectory)) // get the directory info
{ var directoryInfo = new DirectoryInfo(fileDirectory);
// get the directory info
var directoryInfo = new DirectoryInfo(fileDirectory); // get the file to be read
var actualFile = directoryInfo.GetFiles(fileName).FirstOrDefault();
// get the file to be read if (actualFile == null)
var actualFile = directoryInfo.GetFiles(fileName).FirstOrDefault(); {
if (actualFile == null) var msg = string.Format("JSON file not found: {0}", Filepath);
{ OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange);
var msg = string.Format("JSON file not found: {0}", Filepath); CrestronConsole.PrintLine(msg);
OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange); ErrorLog.Error(msg);
CrestronConsole.PrintLine(msg); return;
ErrorLog.Error(msg); }
return;
} // \xSE\xR\PDT000-Template_Main_Config-Combined_DSP_v00.02.json
// \USER\PDT000-Template_Main_Config-Combined_DSP_v00.02.json
// \xSE\xR\PDT000-Template_Main_Config-Combined_DSP_v00.02.json ActualFilePath = actualFile.FullName;
// \USER\PDT000-Template_Main_Config-Combined_DSP_v00.02.json OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange);
ActualFilePath = actualFile.FullName; OnStringChange(string.Format("Actual JSON file is {0}", ActualFilePath), 0, JsonToSimplConstants.StringValueChange);
OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); Debug.Console(1, "Actual JSON file is {0}", ActualFilePath);
OnStringChange(string.Format("Actual JSON file is {0}", ActualFilePath), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "Actual JSON file is {0}", ActualFilePath); Filename = actualFile.Name;
OnStringChange(Filename, 0, JsonToSimplConstants.FilenameResolvedChange);
Filename = actualFile.Name; OnStringChange(string.Format("JSON Filename is {0}", Filename), 0, JsonToSimplConstants.StringValueChange);
OnStringChange(Filename, 0, JsonToSimplConstants.FilenameResolvedChange); Debug.Console(1, "JSON Filename is {0}", Filename);
OnStringChange(string.Format("JSON Filename is {0}", Filename), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "JSON Filename is {0}", Filename);
FilePathName = string.Format(@"{0}{1}", actualFile.DirectoryName, dirSeparator);
OnStringChange(string.Format(@"{0}", actualFile.DirectoryName), 0, JsonToSimplConstants.FilePathResolvedChange);
FilePathName = string.Format(@"{0}{1}", actualFile.DirectoryName, dirSeparator); OnStringChange(string.Format(@"JSON File Path is {0}", actualFile.DirectoryName), 0, JsonToSimplConstants.StringValueChange);
OnStringChange(string.Format(@"{0}", actualFile.DirectoryName), 0, JsonToSimplConstants.FilePathResolvedChange); Debug.Console(1, "JSON File Path is {0}", FilePathName);
OnStringChange(string.Format(@"JSON File Path is {0}", actualFile.DirectoryName), 0, JsonToSimplConstants.StringValueChange);
Debug.Console(1, "JSON File Path is {0}", FilePathName); var json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII);
var json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII); JsonObject = JObject.Parse(json);
foreach (var child in Children)
JsonObject = JObject.Parse(json); child.ProcessAll();
foreach (var child in Children)
child.ProcessAll(); OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange);
}
OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange); else
} {
else OnStringChange(string.Format("'{0}' not found", fileDirectory), 0, JsonToSimplConstants.StringValueChange);
{ Debug.Console(1, "'{0}' not found", fileDirectory);
OnStringChange(string.Format("'{0}' not found", fileDirectory), 0, JsonToSimplConstants.StringValueChange); }
Debug.Console(1, "'{0}' not found", fileDirectory); }
} catch (Exception e)
} {
catch (Exception e) var msg = string.Format("EvaluateFile Exception: Message\r{0}", e.Message);
{ OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange);
var msg = string.Format("EvaluateFile Exception: Message\r{0}", e.Message); CrestronConsole.PrintLine(msg);
OnStringChange(msg, 0, JsonToSimplConstants.StringValueChange); ErrorLog.Error(msg);
CrestronConsole.PrintLine(msg);
ErrorLog.Error(msg); var stackTrace = string.Format("EvaluateFile: Stack Trace\r{0}", e.StackTrace);
OnStringChange(stackTrace, 0, JsonToSimplConstants.StringValueChange);
var stackTrace = string.Format("EvaluateFile: Stack Trace\r{0}", e.StackTrace); CrestronConsole.PrintLine(stackTrace);
OnStringChange(stackTrace, 0, JsonToSimplConstants.StringValueChange); ErrorLog.Error(stackTrace);
CrestronConsole.PrintLine(stackTrace); }
ErrorLog.Error(stackTrace); }
}
}
/// <summary>
/// Sets the debug level
/// <summary> /// </summary>
/// Sets the debug level /// <param name="level"></param>
/// </summary> public void setDebugLevel(uint level)
/// <param name="level"></param> {
public void setDebugLevel(int level) Debug.SetDebugLevel(level);
{ }
Debug.SetDebugLevel(level);
} /// <summary>
/// Saves the values to the file
/// <summary> /// </summary>
/// Saves the values to the file public override void Save()
/// </summary> {
public override void Save() // this code is duplicated in the other masters!!!!!!!!!!!!!
{ UnsavedValues = new Dictionary<string, JValue>();
// this code is duplicated in the other masters!!!!!!!!!!!!! // Make each child update their values into master object
UnsavedValues = new Dictionary<string, JValue>(); foreach (var child in Children)
// Make each child update their values into master object {
foreach (var child in Children) Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key);
{ child.UpdateInputsForMaster();
Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key); }
child.UpdateInputsForMaster();
} if (UnsavedValues == null || UnsavedValues.Count == 0)
{
if (UnsavedValues == null || UnsavedValues.Count == 0) Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID);
{ return;
Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID); }
return; lock (FileLock)
} {
lock (FileLock) Debug.Console(1, "Saving");
{ foreach (var path in UnsavedValues.Keys)
Debug.Console(1, "Saving"); {
foreach (var path in UnsavedValues.Keys) var tokenToReplace = JsonObject.SelectToken(path);
{ if (tokenToReplace != null)
var tokenToReplace = JsonObject.SelectToken(path); {// It's found
if (tokenToReplace != null) tokenToReplace.Replace(UnsavedValues[path]);
{// It's found Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path);
tokenToReplace.Replace(UnsavedValues[path]); }
Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path); else // No token. Let's make one
} {
else // No token. Let's make one //http://stackoverflow.com/questions/17455052/how-to-set-the-value-of-a-json-path-using-json-net
{ Debug.Console(1, "JSON Master[{0}] Cannot write value onto missing property: '{1}'", UniqueID, path);
//http://stackoverflow.com/questions/17455052/how-to-set-the-value-of-a-json-path-using-json-net
Debug.Console(1, "JSON Master[{0}] Cannot write value onto missing property: '{1}'", UniqueID, path); // JContainer jpart = JsonObject;
// // walk down the path and find where it goes
// JContainer jpart = JsonObject; //#warning Does not handle arrays.
// // walk down the path and find where it goes // foreach (var part in path.Split('.'))
//#warning Does not handle arrays. // {
// foreach (var part in path.Split('.'))
// { // var openPos = part.IndexOf('[');
// if (openPos > -1)
// var openPos = part.IndexOf('['); // {
// if (openPos > -1) // openPos++; // move to number
// { // var closePos = part.IndexOf(']');
// openPos++; // move to number // var arrayName = part.Substring(0, openPos - 1); // get the name
// var closePos = part.IndexOf(']'); // var index = Convert.ToInt32(part.Substring(openPos, closePos - openPos));
// var arrayName = part.Substring(0, openPos - 1); // get the name
// var index = Convert.ToInt32(part.Substring(openPos, closePos - openPos)); // // Check if the array itself exists and add the item if so
// if (jpart[arrayName] != null)
// // Check if the array itself exists and add the item if so // {
// if (jpart[arrayName] != null) // var arrayObj = jpart[arrayName] as JArray;
// { // var item = arrayObj[index];
// var arrayObj = jpart[arrayName] as JArray; // if (item == null)
// var item = arrayObj[index]; // arrayObj.Add(new JObject());
// if (item == null) // }
// arrayObj.Add(new JObject());
// } // Debug.Console(0, "IGNORING MISSING ARRAY VALUE FOR NOW");
// continue;
// Debug.Console(0, "IGNORING MISSING ARRAY VALUE FOR NOW"); // }
// continue; // // Build the
// } // if (jpart[part] == null)
// // Build the // jpart.Add(new JProperty(part, new JObject()));
// if (jpart[part] == null) // jpart = jpart[part] as JContainer;
// jpart.Add(new JProperty(part, new JObject())); // }
// jpart = jpart[part] as JContainer; // jpart.Replace(UnsavedValues[path]);
// } }
// jpart.Replace(UnsavedValues[path]); }
} using (StreamWriter sw = new StreamWriter(ActualFilePath))
} {
using (StreamWriter sw = new StreamWriter(ActualFilePath)) try
{ {
try sw.Write(JsonObject.ToString());
{ sw.Flush();
sw.Write(JsonObject.ToString()); }
sw.Flush(); catch (Exception e)
} {
catch (Exception e) string err = string.Format("Error writing JSON file:\r{0}", e);
{ Debug.Console(0, err);
string err = string.Format("Error writing JSON file:\r{0}", e); ErrorLog.Warn(err);
Debug.Console(0, err); return;
ErrorLog.Warn(err); }
return; }
} }
} }
} }
} }
}
}

View file

@ -1,12 +1,4 @@
using System; 
//using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace PepperDash.Core.JsonToSimpl namespace PepperDash.Core.JsonToSimpl
{ {

View file

@ -1,8 +1,6 @@
using System; using System;
//using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.IO;
using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json; using Newtonsoft.Json;
@ -162,7 +160,11 @@ namespace PepperDash.Core.JsonToSimpl
/// <returns></returns> /// <returns></returns>
public static JObject ParseObject(string json) public static JObject ParseObject(string json)
{ {
using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.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 startDepth = reader.Depth;
var obj = JObject.Load(reader); var obj = JObject.Load(reader);
@ -179,7 +181,11 @@ namespace PepperDash.Core.JsonToSimpl
/// <returns></returns> /// <returns></returns>
public static JArray ParseArray(string json) public static JArray ParseArray(string json)
{ {
using (var reader = new JsonTextReader(new Crestron.SimplSharp.CrestronIO.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 startDepth = reader.Depth;
var obj = JArray.Load(reader); var obj = JArray.Load(reader);

View file

@ -1,195 +1,191 @@
using System; using System;
//using System.IO; using System.Collections.Generic;
using System.Collections.Generic; using System.Linq;
using System.Linq; using Crestron.SimplSharp;
using System.Text; using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp; using Newtonsoft.Json.Linq;
using Crestron.SimplSharp.CrestronIO; using PepperDash.Core.Config;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq; namespace PepperDash.Core.JsonToSimpl
{
using PepperDash.Core.Config; /// <summary>
/// Portal File Master
namespace PepperDash.Core.JsonToSimpl /// </summary>
{ public class JsonToSimplPortalFileMaster : JsonToSimplMaster
/// <summary> {
/// Portal File Master /// <summary>
/// </summary> /// Sets the filepath as well as registers this with the Global.Masters list
public class JsonToSimplPortalFileMaster : JsonToSimplMaster /// </summary>
{ public string PortalFilepath { get; private set; }
/// <summary>
/// Sets the filepath as well as registers this with the Global.Masters list /// <summary>
/// </summary> /// File path of the actual file being read (Portal or local)
public string PortalFilepath { get; private set; } /// </summary>
public string ActualFilePath { get; private set; }
/// <summary>
/// File path of the actual file being read (Portal or local) /*****************************************************************************************/
/// </summary> /** Privates **/
public string ActualFilePath { get; private set; }
// To prevent multiple same-file access
/*****************************************************************************************/ object StringBuilderLock = new object();
/** Privates **/ static object FileLock = new object();
// To prevent multiple same-file access /*****************************************************************************************/
object StringBuilderLock = new object();
static object FileLock = new object(); /// <summary>
/// SIMPL+ default constructor.
/*****************************************************************************************/ /// </summary>
public JsonToSimplPortalFileMaster()
/// <summary> {
/// SIMPL+ default constructor. }
/// </summary>
public JsonToSimplPortalFileMaster() /// <summary>
{ /// Read, evaluate and udpate status
} /// </summary>
public void EvaluateFile(string portalFilepath)
/// <summary> {
/// Read, evaluate and udpate status PortalFilepath = portalFilepath;
/// </summary>
public void EvaluateFile(string portalFilepath) OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange);
{ if (string.IsNullOrEmpty(PortalFilepath))
PortalFilepath = portalFilepath; {
CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set");
OnBoolChange(false, 0, JsonToSimplConstants.JsonIsValidBoolChange); return;
if (string.IsNullOrEmpty(PortalFilepath)) }
{
CrestronConsole.PrintLine("Cannot evaluate file. JSON file path not set"); // Resolve possible wildcarded filename
return;
} // If the portal file is xyz.json, then
// the file we want to check for first will be called xyz.local.json
// Resolve possible wildcarded filename var localFilepath = Path.ChangeExtension(PortalFilepath, "local.json");
Debug.Console(0, this, "Checking for local file {0}", localFilepath);
// If the portal file is xyz.json, then var actualLocalFile = GetActualFileInfoFromPath(localFilepath);
// the file we want to check for first will be called xyz.local.json
var localFilepath = Path.ChangeExtension(PortalFilepath, "local.json"); if (actualLocalFile != null)
Debug.Console(0, this, "Checking for local file {0}", localFilepath); {
var actualLocalFile = GetActualFileInfoFromPath(localFilepath); ActualFilePath = actualLocalFile.FullName;
OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange);
if (actualLocalFile != null) }
{ // If the local file does not exist, then read the portal file xyz.json
ActualFilePath = actualLocalFile.FullName; // and create the local.
OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); else
} {
// If the local file does not exist, then read the portal file xyz.json Debug.Console(1, this, "Local JSON file not found {0}\rLoading portal JSON file", localFilepath);
// and create the local. var actualPortalFile = GetActualFileInfoFromPath(portalFilepath);
else if (actualPortalFile != null)
{ {
Debug.Console(1, this, "Local JSON file not found {0}\rLoading portal JSON file", localFilepath); var newLocalPath = Path.ChangeExtension(actualPortalFile.FullName, "local.json");
var actualPortalFile = GetActualFileInfoFromPath(portalFilepath); // got the portal file, hand off to the merge / save method
if (actualPortalFile != null) PortalConfigReader.ReadAndMergeFileIfNecessary(actualPortalFile.FullName, newLocalPath);
{ ActualFilePath = newLocalPath;
var newLocalPath = Path.ChangeExtension(actualPortalFile.FullName, "local.json"); OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange);
// got the portal file, hand off to the merge / save method }
PortalConfigReader.ReadAndMergeFileIfNecessary(actualPortalFile.FullName, newLocalPath); else
ActualFilePath = newLocalPath; {
OnStringChange(ActualFilePath, 0, JsonToSimplConstants.ActualFilePathChange); var msg = string.Format("Portal JSON file not found: {0}", PortalFilepath);
} Debug.Console(1, this, msg);
else ErrorLog.Error(msg);
{ return;
var msg = string.Format("Portal JSON file not found: {0}", PortalFilepath); }
Debug.Console(1, this, msg); }
ErrorLog.Error(msg);
return; // At this point we should have a local file. Do it.
} Debug.Console(1, "Reading local JSON file {0}", ActualFilePath);
}
string json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII);
// At this point we should have a local file. Do it.
Debug.Console(1, "Reading local JSON file {0}", ActualFilePath); try
{
string json = File.ReadToEnd(ActualFilePath, System.Text.Encoding.ASCII); JsonObject = JObject.Parse(json);
foreach (var child in Children)
try child.ProcessAll();
{ OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange);
JsonObject = JObject.Parse(json); }
foreach (var child in Children) catch (Exception e)
child.ProcessAll(); {
OnBoolChange(true, 0, JsonToSimplConstants.JsonIsValidBoolChange); var msg = string.Format("JSON parsing failed:\r{0}", e);
} CrestronConsole.PrintLine(msg);
catch (Exception e) ErrorLog.Error(msg);
{ return;
var msg = string.Format("JSON parsing failed:\r{0}", e); }
CrestronConsole.PrintLine(msg); }
ErrorLog.Error(msg);
return; /// <summary>
} /// Returns the FileInfo object for a given path, with possible wildcards
} /// </summary>
/// <param name="path"></param>
/// <summary> /// <returns></returns>
/// Returns the FileInfo object for a given path, with possible wildcards FileInfo GetActualFileInfoFromPath(string path)
/// </summary> {
/// <param name="path"></param> var dir = Path.GetDirectoryName(path);
/// <returns></returns> var localFilename = Path.GetFileName(path);
FileInfo GetActualFileInfoFromPath(string path) var directory = new DirectoryInfo(dir);
{ // search the directory for the file w/ wildcards
var dir = Path.GetDirectoryName(path); return directory.GetFiles(localFilename).FirstOrDefault();
var localFilename = Path.GetFileName(path); }
var directory = new DirectoryInfo(dir);
// search the directory for the file w/ wildcards /// <summary>
return directory.GetFiles(localFilename).FirstOrDefault(); ///
} /// </summary>
/// <param name="level"></param>
/// <summary> public void setDebugLevel(uint level)
/// {
/// </summary> Debug.SetDebugLevel(level);
/// <param name="level"></param> }
public void setDebugLevel(int level)
{ /// <summary>
Debug.SetDebugLevel(level); ///
} /// </summary>
public override void Save()
/// <summary> {
/// // this code is duplicated in the other masters!!!!!!!!!!!!!
/// </summary> UnsavedValues = new Dictionary<string, JValue>();
public override void Save() // Make each child update their values into master object
{ foreach (var child in Children)
// this code is duplicated in the other masters!!!!!!!!!!!!! {
UnsavedValues = new Dictionary<string, JValue>(); Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key);
// Make each child update their values into master object child.UpdateInputsForMaster();
foreach (var child in Children) }
{
Debug.Console(1, "Master [{0}] checking child [{1}] for updates to save", UniqueID, child.Key); if (UnsavedValues == null || UnsavedValues.Count == 0)
child.UpdateInputsForMaster(); {
} Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID);
return;
if (UnsavedValues == null || UnsavedValues.Count == 0) }
{ lock (FileLock)
Debug.Console(1, "Master [{0}] No updated values to save. Skipping", UniqueID); {
return; Debug.Console(1, "Saving");
} foreach (var path in UnsavedValues.Keys)
lock (FileLock) {
{ var tokenToReplace = JsonObject.SelectToken(path);
Debug.Console(1, "Saving"); if (tokenToReplace != null)
foreach (var path in UnsavedValues.Keys) {// It's found
{ tokenToReplace.Replace(UnsavedValues[path]);
var tokenToReplace = JsonObject.SelectToken(path); Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path);
if (tokenToReplace != null) }
{// It's found else // No token. Let's make one
tokenToReplace.Replace(UnsavedValues[path]); {
Debug.Console(1, "JSON Master[{0}] Updating '{1}'", UniqueID, path); //http://stackoverflow.com/questions/17455052/how-to-set-the-value-of-a-json-path-using-json-net
} Debug.Console(1, "JSON Master[{0}] Cannot write value onto missing property: '{1}'", UniqueID, path);
else // No token. Let's make one
{ }
//http://stackoverflow.com/questions/17455052/how-to-set-the-value-of-a-json-path-using-json-net }
Debug.Console(1, "JSON Master[{0}] Cannot write value onto missing property: '{1}'", UniqueID, path); using (StreamWriter sw = new StreamWriter(ActualFilePath))
{
} try
} {
using (StreamWriter sw = new StreamWriter(ActualFilePath)) sw.Write(JsonObject.ToString());
{ sw.Flush();
try }
{ catch (Exception e)
sw.Write(JsonObject.ToString()); {
sw.Flush(); string err = string.Format("Error writing JSON file:\r{0}", e);
} Debug.Console(0, err);
catch (Exception e) ErrorLog.Warn(err);
{ return;
string err = string.Format("Error writing JSON file:\r{0}", e); }
Debug.Console(0, err); }
ErrorLog.Warn(err); }
return; }
} }
} }
}
}
}
}

View file

@ -0,0 +1,37 @@
using Crestron.SimplSharp;
using Serilog.Core;
using Serilog.Events;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Core.Logging
{
public class CrestronEnricher : ILogEventEnricher
{
static readonly string _appName;
static CrestronEnricher()
{
switch (CrestronEnvironment.DevicePlatform)
{
case eDevicePlatform.Appliance:
_appName = $"App {InitialParametersClass.ApplicationNumber}";
break;
case eDevicePlatform.Server:
_appName = $"{InitialParametersClass.RoomId}";
break;
}
}
public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory)
{
var property = propertyFactory.CreateProperty("App", _appName);
logEvent.AddOrUpdateProperty(property);
}
}
}

View file

@ -0,0 +1,55 @@
using Crestron.SimplSharp;
using Serilog.Configuration;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Formatting.Json;
using System.IO;
using System.Text;
namespace PepperDash.Core
{
public class DebugConsoleSink : ILogEventSink
{
private readonly ITextFormatter _textFormatter;
public void Emit(LogEvent logEvent)
{
if (!Debug.IsRunningOnAppliance) return;
/*string message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}]{logEvent.RenderMessage()}";
if(logEvent.Properties.TryGetValue("Key",out var value) && value is ScalarValue sv && sv.Value is string rawValue)
{
message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue,3}]: {logEvent.RenderMessage()}";
}*/
var buffer = new StringWriter(new StringBuilder(256));
_textFormatter.Format(logEvent, buffer);
var message = buffer.ToString();
CrestronConsole.PrintLine(message);
}
public DebugConsoleSink(ITextFormatter formatProvider )
{
_textFormatter = formatProvider ?? new JsonFormatter();
}
}
public static class DebugConsoleSinkExtensions
{
public static LoggerConfiguration DebugConsoleSink(
this LoggerSinkConfiguration loggerConfiguration,
ITextFormatter formatProvider = null)
{
return loggerConfiguration.Sink(new DebugConsoleSink(formatProvider));
}
}
}

View file

@ -1,12 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronDataStore;
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
using Newtonsoft.Json; using Newtonsoft.Json;
using PepperDash.Core.DebugThings;
namespace PepperDash.Core namespace PepperDash.Core
@ -101,7 +98,7 @@ namespace PepperDash.Core
{ {
if (string.IsNullOrEmpty(levelString.Trim())) if (string.IsNullOrEmpty(levelString.Trim()))
{ {
CrestronConsole.PrintLine("AppDebug level = {0}", SaveData.Level); CrestronConsole.ConsoleCommandResponse("AppDebug level = {0}", SaveData.Level);
return; return;
} }

View file

@ -0,0 +1,29 @@
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronLogger;
using Serilog.Core;
using Serilog.Events;
namespace PepperDash.Core.Logging
{
public class DebugCrestronLoggerSink : ILogEventSink
{
public void Emit(LogEvent logEvent)
{
if (!Debug.IsRunningOnAppliance) return;
string message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}]{logEvent.RenderMessage()}";
if (logEvent.Properties.TryGetValue("Key", out var value) && value is ScalarValue sv && sv.Value is string rawValue)
{
message = $"[{logEvent.Timestamp}][{logEvent.Level}][App {InitialParametersClass.ApplicationNumber}][{rawValue}]: {logEvent.RenderMessage()}";
}
CrestronLogger.WriteToLog(message, (uint)logEvent.Level);
}
public DebugCrestronLoggerSink()
{
CrestronLogger.Initialize(1, LoggerModeEnum.RM);
}
}
}

View file

@ -0,0 +1,65 @@
using Crestron.SimplSharp;
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace PepperDash.Core.Logging
{
public class DebugErrorLogSink : ILogEventSink
{
private ITextFormatter _formatter;
private Dictionary<LogEventLevel, Action<string>> _errorLogMap = new Dictionary<LogEventLevel, Action<string>>
{
{ LogEventLevel.Verbose, (msg) => ErrorLog.Notice(msg) },
{LogEventLevel.Debug, (msg) => ErrorLog.Notice(msg) },
{LogEventLevel.Information, (msg) => ErrorLog.Notice(msg) },
{LogEventLevel.Warning, (msg) => ErrorLog.Warn(msg) },
{LogEventLevel.Error, (msg) => ErrorLog.Error(msg) },
{LogEventLevel.Fatal, (msg) => ErrorLog.Error(msg) }
};
public void Emit(LogEvent logEvent)
{
string message;
if (_formatter == null)
{
var programId = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance
? $"App {InitialParametersClass.ApplicationNumber}"
: $"Room {InitialParametersClass.RoomId}";
message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}]{logEvent.RenderMessage()}";
if (logEvent.Properties.TryGetValue("Key", out var value) && value is ScalarValue sv && sv.Value is string rawValue)
{
message = $"[{logEvent.Timestamp}][{logEvent.Level}][{programId}][{rawValue}]: {logEvent.RenderMessage()}";
}
} else
{
var buffer = new StringWriter(new StringBuilder(256));
_formatter.Format(logEvent, buffer);
message = buffer.ToString();
}
if(!_errorLogMap.TryGetValue(logEvent.Level, out var handler))
{
return;
}
handler(message);
}
public DebugErrorLogSink(ITextFormatter formatter = null)
{
_formatter = formatter;
}
}
}

View file

@ -0,0 +1,44 @@
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);
}
public static void LogDebug(this IKeyed device, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Debug, device, message, args);
}
public static void LogInformation(this IKeyed device, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Information, device, message, args);
}
public static void LogWarning(this IKeyed device, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Warning, device, message, args);
}
public static void LogError(this IKeyed device, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Error, device, message, args);
}
public static void LogFatal(this IKeyed device, string message, params object[] args)
{
Log.LogMessage(LogEventLevel.Fatal, device, message, args);
}
}
}

View file

@ -1,9 +1,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace PepperDash.Core.DebugThings namespace PepperDash.Core.Logging
{ {
/// <summary> /// <summary>
/// Class to persist current Debug settings across program restarts /// Class to persist current Debug settings across program restarts

View file

@ -0,0 +1,271 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Configuration;
using WebSocketSharp.Server;
using Crestron.SimplSharp;
using WebSocketSharp;
using System.Security.Authentication;
using WebSocketSharp.Net;
using X509Certificate2 = System.Security.Cryptography.X509Certificates.X509Certificate2;
using System.IO;
using Org.BouncyCastle.Asn1.X509;
using Serilog.Formatting;
using Newtonsoft.Json.Linq;
using Serilog.Formatting.Json;
namespace PepperDash.Core
{
public class DebugWebsocketSink : ILogEventSink
{
private HttpServer _httpsServer;
private string _path = "/debug/join/";
private const string _certificateName = "selfCres";
private const string _certificatePassword = "cres12345";
public int Port
{ get
{
if(_httpsServer == null) return 0;
return _httpsServer.Port;
}
}
public string Url
{
get
{
if (_httpsServer == null) return "";
return $"wss://{CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0)}:{_httpsServer.Port}{_httpsServer.WebSocketServices[_path].Path}";
}
}
public bool IsRunning { get => _httpsServer?.IsListening ?? false; }
private readonly ITextFormatter _textFormatter;
public DebugWebsocketSink(ITextFormatter formatProvider)
{
_textFormatter = formatProvider ?? new JsonFormatter();
if (!File.Exists($"\\user\\{_certificateName}.pfx"))
CreateCert(null);
CrestronEnvironment.ProgramStatusEventHandler += type =>
{
if (type == eProgramStatusEventType.Stopping)
{
StopServer();
}
};
}
private void CreateCert(string[] args)
{
try
{
//Debug.Console(0,"CreateCert Creating Utility");
CrestronConsole.PrintLine("CreateCert Creating Utility");
//var utility = new CertificateUtility();
var utility = new BouncyCertificate();
//Debug.Console(0, "CreateCert Calling CreateCert");
CrestronConsole.PrintLine("CreateCert Calling CreateCert");
//utility.CreateCert();
var ipAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, 0);
var hostName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, 0);
var domainName = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, 0);
//Debug.Console(0, "DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress);
CrestronConsole.PrintLine(string.Format("DomainName: {0} | HostName: {1} | {1}.{0}@{2}", domainName, hostName, ipAddress));
var certificate = utility.CreateSelfSignedCertificate(string.Format("CN={0}.{1}", hostName, domainName), new[] { string.Format("{0}.{1}", hostName, domainName), ipAddress }, new[] { KeyPurposeID.IdKPServerAuth, KeyPurposeID.IdKPClientAuth });
//Crestron fails to let us do this...perhaps it should be done through their Dll's but haven't tested
//Debug.Print($"CreateCert Storing Certificate To My.LocalMachine");
//utility.AddCertToStore(certificate, StoreName.My, StoreLocation.LocalMachine);
//Debug.Console(0, "CreateCert Saving Cert to \\user\\");
CrestronConsole.PrintLine("CreateCert Saving Cert to \\user\\");
utility.CertificatePassword = _certificatePassword;
utility.WriteCertificate(certificate, @"\user\", _certificateName);
//Debug.Console(0, "CreateCert Ending CreateCert");
CrestronConsole.PrintLine("CreateCert Ending CreateCert");
}
catch (Exception ex)
{
//Debug.Console(0, "WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace);
CrestronConsole.PrintLine(string.Format("WSS CreateCert Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace));
}
}
public void Emit(LogEvent logEvent)
{
if (_httpsServer == null || !_httpsServer.IsListening) return;
var sw = new StringWriter();
_textFormatter.Format(logEvent, sw);
_httpsServer.WebSocketServices.Broadcast(sw.ToString());
}
public void StartServerAndSetPort(int port)
{
Debug.Console(0, "Starting Websocket Server on port: {0}", port);
Start(port, $"\\user\\{_certificateName}.pfx", _certificatePassword);
}
private void Start(int port, string certPath = "", string certPassword = "")
{
try
{
_httpsServer = new HttpServer(port, true);
if (!string.IsNullOrWhiteSpace(certPath))
{
Debug.Console(0, "Assigning SSL Configuration");
_httpsServer.SslConfiguration = new ServerSslConfiguration(new X509Certificate2(certPath, certPassword))
{
ClientCertificateRequired = false,
CheckCertificateRevocation = false,
EnabledSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls,
//this is just to test, you might want to actually validate
ClientCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) =>
{
Debug.Console(0, "HTTPS ClientCerticateValidation Callback triggered");
return true;
}
};
}
Debug.Console(0, "Adding Debug Client Service");
_httpsServer.AddWebSocketService<DebugClient>(_path);
Debug.Console(0, "Assigning Log Info");
_httpsServer.Log.Level = LogLevel.Trace;
_httpsServer.Log.Output = (d, s) =>
{
uint level;
switch(d.Level)
{
case WebSocketSharp.LogLevel.Fatal:
level = 3;
break;
case WebSocketSharp.LogLevel.Error:
level = 2;
break;
case WebSocketSharp.LogLevel.Warn:
level = 1;
break;
case WebSocketSharp.LogLevel.Info:
level = 0;
break;
case WebSocketSharp.LogLevel.Debug:
level = 4;
break;
case WebSocketSharp.LogLevel.Trace:
level = 5;
break;
default:
level = 4;
break;
}
Debug.Console(level, "{1} {0}\rCaller:{2}\rMessage:{3}\rs:{4}", d.Level.ToString(), d.Date.ToString(), d.Caller.ToString(), d.Message, s);
};
Debug.Console(0, "Starting");
_httpsServer.Start();
Debug.Console(0, "Ready");
}
catch (Exception ex)
{
Debug.Console(0, "WebSocket Failed to start {0}", ex.Message);
}
}
public void StopServer()
{
Debug.Console(0, "Stopping Websocket Server");
_httpsServer?.Stop();
_httpsServer = null;
}
}
public static class DebugWebsocketSinkExtensions
{
public static LoggerConfiguration DebugWebsocketSink(
this LoggerSinkConfiguration loggerConfiguration,
ITextFormatter formatProvider = null)
{
return loggerConfiguration.Sink(new DebugWebsocketSink(formatProvider));
}
}
public class DebugClient : WebSocketBehavior
{
private DateTime _connectionTime;
public TimeSpan ConnectedDuration
{
get
{
if (Context.WebSocket.IsAlive)
{
return DateTime.Now - _connectionTime;
}
else
{
return new TimeSpan(0);
}
}
}
public DebugClient()
{
Debug.Console(0, "DebugClient Created");
}
protected override void OnOpen()
{
base.OnOpen();
var url = Context.WebSocket.Url;
Debug.Console(0, Debug.ErrorLogLevel.Notice, "New WebSocket Connection from: {0}", url);
_connectionTime = DateTime.Now;
}
protected override void OnMessage(MessageEventArgs e)
{
base.OnMessage(e);
Debug.Console(0, "WebSocket UiClient Message: {0}", e.Data);
}
protected override void OnClose(CloseEventArgs e)
{
base.OnClose(e);
Debug.Console(0, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Closing: {0} reason: {1}", e.Code, e.Reason);
}
protected override void OnError(WebSocketSharp.ErrorEventArgs e)
{
base.OnError(e);
Debug.Console(2, Debug.ErrorLogLevel.Notice, "WebSocket UiClient Error: {0} message: {1}", e.Exception, e.Message);
}
}
}

View file

@ -1,26 +1,26 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement namespace PepperDash.Core.PasswordManagement
{ {
/// <summary> /// <summary>
/// JSON password configuration /// JSON password configuration
/// </summary> /// </summary>
public class PasswordConfig public class PasswordConfig
{ {
/// <summary> /// <summary>
/// Password object configured password /// Password object configured password
/// </summary> /// </summary>
public string password { get; set; } public string password { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public PasswordConfig() public PasswordConfig()
{ {
} }
} }
} }

View file

@ -1,57 +1,57 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.PasswordManagement namespace PepperDash.Core.PasswordManagement
{ {
/// <summary> /// <summary>
/// Constants /// Constants
/// </summary> /// </summary>
public class PasswordManagementConstants public class PasswordManagementConstants
{ {
/// <summary> /// <summary>
/// Generic boolean value change constant /// Generic boolean value change constant
/// </summary> /// </summary>
public const ushort BoolValueChange = 1; public const ushort BoolValueChange = 1;
/// <summary> /// <summary>
/// Evaluated boolean change constant /// Evaluated boolean change constant
/// </summary> /// </summary>
public const ushort PasswordInitializedChange = 2; public const ushort PasswordInitializedChange = 2;
/// <summary> /// <summary>
/// Update busy change const /// Update busy change const
/// </summary> /// </summary>
public const ushort PasswordUpdateBusyChange = 3; public const ushort PasswordUpdateBusyChange = 3;
/// <summary> /// <summary>
/// Password is valid change constant /// Password is valid change constant
/// </summary> /// </summary>
public const ushort PasswordValidationChange = 4; public const ushort PasswordValidationChange = 4;
/// <summary> /// <summary>
/// Password LED change constant /// Password LED change constant
/// </summary> /// </summary>
public const ushort PasswordLedFeedbackChange = 5; public const ushort PasswordLedFeedbackChange = 5;
/// <summary> /// <summary>
/// Generic ushort value change constant /// Generic ushort value change constant
/// </summary> /// </summary>
public const ushort UshrtValueChange = 101; public const ushort UshrtValueChange = 101;
/// <summary> /// <summary>
/// Password count /// Password count
/// </summary> /// </summary>
public const ushort PasswordManagerCountChange = 102; public const ushort PasswordManagerCountChange = 102;
/// <summary> /// <summary>
/// Password selecte index change constant /// Password selecte index change constant
/// </summary> /// </summary>
public const ushort PasswordSelectIndexChange = 103; public const ushort PasswordSelectIndexChange = 103;
/// <summary> /// <summary>
/// Password length /// Password length
/// </summary> /// </summary>
public const ushort PasswordLengthChange = 104; public const ushort PasswordLengthChange = 104;
/// <summary> /// <summary>
/// Generic string value change constant /// Generic string value change constant
/// </summary> /// </summary>
public const ushort StringValueChange = 201; public const ushort StringValueChange = 201;
} }
} }

View file

@ -1,191 +1,187 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; namespace PepperDash.Core.PasswordManagement
using System.Text; {
using Crestron.SimplSharp; /// <summary>
/// A class to allow user interaction with the PasswordManager
namespace PepperDash.Core.PasswordManagement /// </summary>
{ public class PasswordClient
/// <summary> {
/// A class to allow user interaction with the PasswordManager /// <summary>
/// </summary> /// Password selected
public class PasswordClient /// </summary>
{ public string Password { get; set; }
/// <summary> /// <summary>
/// Password selected /// Password selected key
/// </summary> /// </summary>
public string Password { get; set; } public ushort Key { get; set; }
/// <summary> /// <summary>
/// Password selected key /// Used to build the password entered by the user
/// </summary> /// </summary>
public ushort Key { get; set; } public string PasswordToValidate { get; set; }
/// <summary>
/// Used to build the password entered by the user /// <summary>
/// </summary> /// Boolean event
public string PasswordToValidate { get; set; } /// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary> /// <summary>
/// Boolean event /// Ushort event
/// </summary> /// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange; public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// <summary> /// <summary>
/// Ushort event /// String event
/// </summary> /// </summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange; public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary>
/// String event /// <summary>
/// </summary> /// Constructor
public event EventHandler<StringChangeEventArgs> StringChange; /// </summary>
public PasswordClient()
/// <summary> {
/// Constructor PasswordManager.PasswordChange += new EventHandler<StringChangeEventArgs>(PasswordManager_PasswordChange);
/// </summary> }
public PasswordClient()
{ /// <summary>
PasswordManager.PasswordChange += new EventHandler<StringChangeEventArgs>(PasswordManager_PasswordChange); /// Initialize method
} /// </summary>
public void Initialize()
/// <summary> {
/// Initialize method OnBoolChange(false, 0, PasswordManagementConstants.PasswordInitializedChange);
/// </summary>
public void Initialize() Password = "";
{ PasswordToValidate = "";
OnBoolChange(false, 0, PasswordManagementConstants.PasswordInitializedChange);
OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange);
Password = ""; OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange);
PasswordToValidate = ""; }
OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); /// <summary>
OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange); /// Retrieve password by index
} /// </summary>
/// <param name="key"></param>
/// <summary> public void GetPasswordByIndex(ushort key)
/// Retrieve password by index {
/// </summary> OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange);
/// <param name="key"></param>
public void GetPasswordByIndex(ushort key) Key = key;
{
OnUshrtChange((ushort)PasswordManager.Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); var pw = PasswordManager.Passwords[Key];
if (pw == null)
Key = key; {
OnUshrtChange(0, 0, PasswordManagementConstants.PasswordLengthChange);
var pw = PasswordManager.Passwords[Key]; return;
if (pw == null) }
{
OnUshrtChange(0, 0, PasswordManagementConstants.PasswordLengthChange); Password = pw;
return; OnUshrtChange((ushort)Password.Length, 0, PasswordManagementConstants.PasswordLengthChange);
} OnUshrtChange(key, 0, PasswordManagementConstants.PasswordSelectIndexChange);
}
Password = pw;
OnUshrtChange((ushort)Password.Length, 0, PasswordManagementConstants.PasswordLengthChange); /// <summary>
OnUshrtChange(key, 0, PasswordManagementConstants.PasswordSelectIndexChange); /// Password validation method
} /// </summary>
/// <param name="password"></param>
/// <summary> public void ValidatePassword(string password)
/// Password validation method {
/// </summary> if (string.IsNullOrEmpty(password))
/// <param name="password"></param> return;
public void ValidatePassword(string password)
{ if (string.Equals(Password, password))
if (string.IsNullOrEmpty(password)) OnBoolChange(true, 0, PasswordManagementConstants.PasswordValidationChange);
return; else
OnBoolChange(false, 0, PasswordManagementConstants.PasswordValidationChange);
if (string.Equals(Password, password))
OnBoolChange(true, 0, PasswordManagementConstants.PasswordValidationChange); ClearPassword();
else }
OnBoolChange(false, 0, PasswordManagementConstants.PasswordValidationChange);
/// <summary>
ClearPassword(); /// Builds the user entered passwrod string, will attempt to validate the user entered
} /// password against the selected password when the length of the 2 are equal
/// </summary>
/// <summary> /// <param name="data"></param>
/// Builds the user entered passwrod string, will attempt to validate the user entered public void BuildPassword(string data)
/// password against the selected password when the length of the 2 are equal {
/// </summary> PasswordToValidate = String.Concat(PasswordToValidate, data);
/// <param name="data"></param> OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange);
public void BuildPassword(string data)
{ if (PasswordToValidate.Length == Password.Length)
PasswordToValidate = String.Concat(PasswordToValidate, data); ValidatePassword(PasswordToValidate);
OnBoolChange(true, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange); }
if (PasswordToValidate.Length == Password.Length) /// <summary>
ValidatePassword(PasswordToValidate); /// Clears the user entered password and resets the LEDs
} /// </summary>
public void ClearPassword()
/// <summary> {
/// Clears the user entered password and resets the LEDs PasswordToValidate = "";
/// </summary> OnBoolChange(false, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange);
public void ClearPassword() }
{
PasswordToValidate = ""; /// <summary>
OnBoolChange(false, (ushort)PasswordToValidate.Length, PasswordManagementConstants.PasswordLedFeedbackChange); /// Protected boolean change event handler
} /// </summary>
/// <param name="state"></param>
/// <summary> /// <param name="index"></param>
/// Protected boolean change event handler /// <param name="type"></param>
/// </summary> protected void OnBoolChange(bool state, ushort index, ushort type)
/// <param name="state"></param> {
/// <param name="index"></param> var handler = BoolChange;
/// <param name="type"></param> if (handler != null)
protected void OnBoolChange(bool state, ushort index, ushort type) {
{ var args = new BoolChangeEventArgs(state, type);
var handler = BoolChange; args.Index = index;
if (handler != null) BoolChange(this, args);
{ }
var args = new BoolChangeEventArgs(state, type); }
args.Index = index;
BoolChange(this, args); /// <summary>
} /// Protected ushort change event handler
} /// </summary>
/// <param name="value"></param>
/// <summary> /// <param name="index"></param>
/// Protected ushort change event handler /// <param name="type"></param>
/// </summary> protected void OnUshrtChange(ushort value, ushort index, ushort type)
/// <param name="value"></param> {
/// <param name="index"></param> var handler = UshrtChange;
/// <param name="type"></param> if (handler != null)
protected void OnUshrtChange(ushort value, ushort index, ushort type) {
{ var args = new UshrtChangeEventArgs(value, type);
var handler = UshrtChange; args.Index = index;
if (handler != null) UshrtChange(this, args);
{ }
var args = new UshrtChangeEventArgs(value, type); }
args.Index = index;
UshrtChange(this, args); /// <summary>
} /// Protected string change event handler
} /// </summary>
/// <param name="value"></param>
/// <summary> /// <param name="index"></param>
/// Protected string change event handler /// <param name="type"></param>
/// </summary> protected void OnStringChange(string value, ushort index, ushort type)
/// <param name="value"></param> {
/// <param name="index"></param> var handler = StringChange;
/// <param name="type"></param> if (handler != null)
protected void OnStringChange(string value, ushort index, ushort type) {
{ var args = new StringChangeEventArgs(value, type);
var handler = StringChange; args.Index = index;
if (handler != null) StringChange(this, args);
{ }
var args = new StringChangeEventArgs(value, type); }
args.Index = index;
StringChange(this, args); /// <summary>
} /// If password changes while selected change event will be notifed and update the client
} /// </summary>
/// <param name="sender"></param>
/// <summary> /// <param name="args"></param>
/// If password changes while selected change event will be notifed and update the client protected void PasswordManager_PasswordChange(object sender, StringChangeEventArgs args)
/// </summary> {
/// <param name="sender"></param> //throw new NotImplementedException();
/// <param name="args"></param> if (Key == args.Index)
protected void PasswordManager_PasswordChange(object sender, StringChangeEventArgs args) {
{ //PasswordSelectedKey = args.Index;
//throw new NotImplementedException(); //PasswordSelected = args.StringValue;
if (Key == args.Index) GetPasswordByIndex(args.Index);
{ }
//PasswordSelectedKey = args.Index; }
//PasswordSelected = args.StringValue; }
GetPasswordByIndex(args.Index);
}
}
}
} }

View file

@ -1,247 +1,241 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using Crestron.SimplSharp;
using System.Text;
using Newtonsoft.Json; namespace PepperDash.Core.PasswordManagement
using Newtonsoft.Json.Linq; {
using Crestron.SimplSharp; /// <summary>
using PepperDash.Core.JsonToSimpl; /// Allows passwords to be stored and managed
using PepperDash.Core.JsonStandardObjects; /// </summary>
public class PasswordManager
namespace PepperDash.Core.PasswordManagement {
{ /// <summary>
/// <summary> /// Public dictionary of known passwords
/// Allows passwords to be stored and managed /// </summary>
/// </summary> public static Dictionary<uint, string> Passwords = new Dictionary<uint, string>();
public class PasswordManager /// <summary>
{ /// Private dictionary, used when passwords are updated
/// <summary> /// </summary>
/// Public dictionary of known passwords private Dictionary<uint, string> _passwords = new Dictionary<uint, string>();
/// </summary>
public static Dictionary<uint, string> Passwords = new Dictionary<uint, string>(); /// <summary>
/// <summary> /// Timer used to wait until password changes have stopped before updating the dictionary
/// Private dictionary, used when passwords are updated /// </summary>
/// </summary> CTimer PasswordTimer;
private Dictionary<uint, string> _passwords = new Dictionary<uint, string>(); /// <summary>
/// Timer length
/// <summary> /// </summary>
/// Timer used to wait until password changes have stopped before updating the dictionary public long PasswordTimerElapsedMs = 5000;
/// </summary>
CTimer PasswordTimer; /// <summary>
/// <summary> /// Boolean event
/// Timer length /// </summary>
/// </summary> public event EventHandler<BoolChangeEventArgs> BoolChange;
public long PasswordTimerElapsedMs = 5000; /// <summary>
/// Ushort event
/// <summary> /// </summary>
/// Boolean event public event EventHandler<UshrtChangeEventArgs> UshrtChange;
/// </summary> /// <summary>
public event EventHandler<BoolChangeEventArgs> BoolChange; /// String event
/// <summary> /// </summary>
/// Ushort event public event EventHandler<StringChangeEventArgs> StringChange;
/// </summary> /// <summary>
public event EventHandler<UshrtChangeEventArgs> UshrtChange; /// Event to notify clients of an updated password at the specified index (uint)
/// <summary> /// </summary>
/// String event public static event EventHandler<StringChangeEventArgs> PasswordChange;
/// </summary>
public event EventHandler<StringChangeEventArgs> StringChange; /// <summary>
/// <summary> /// Constructor
/// Event to notify clients of an updated password at the specified index (uint) /// </summary>
/// </summary> public PasswordManager()
public static event EventHandler<StringChangeEventArgs> PasswordChange; {
/// <summary> }
/// Constructor
/// </summary> /// <summary>
public PasswordManager() /// Initialize password manager
{ /// </summary>
public void Initialize()
} {
if (Passwords == null)
/// <summary> Passwords = new Dictionary<uint, string>();
/// Initialize password manager
/// </summary> if (_passwords == null)
public void Initialize() _passwords = new Dictionary<uint, string>();
{
if (Passwords == null) OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange);
Passwords = new Dictionary<uint, string>(); }
if (_passwords == null) /// <summary>
_passwords = new Dictionary<uint, string>(); /// Updates password stored in the dictonary
/// </summary>
OnBoolChange(true, 0, PasswordManagementConstants.PasswordInitializedChange); /// <param name="key"></param>
} /// <param name="password"></param>
public void UpdatePassword(ushort key, string password)
/// <summary> {
/// Updates password stored in the dictonary // validate the parameters
/// </summary> if (key > 0 && string.IsNullOrEmpty(password))
/// <param name="key"></param> {
/// <param name="password"></param> Debug.Console(1, string.Format("PasswordManager.UpdatePassword: key [{0}] or password are not valid", key, password));
public void UpdatePassword(ushort key, string password) return;
{ }
// validate the parameters
if (key > 0 && string.IsNullOrEmpty(password)) try
{ {
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: key [{0}] or password are not valid", key, password)); // if key exists, update the value
return; if(_passwords.ContainsKey(key))
} _passwords[key] = password;
// else add the key & value
try else
{ _passwords.Add(key, password);
// if key exists, update the value
if(_passwords.ContainsKey(key)) Debug.Console(1, string.Format("PasswordManager.UpdatePassword: _password[{0}] = {1}", key, _passwords[key]));
_passwords[key] = password;
// else add the key & value if (PasswordTimer == null)
else {
_passwords.Add(key, password); PasswordTimer = new CTimer((o) => PasswordTimerElapsed(), PasswordTimerElapsedMs);
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started"));
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: _password[{0}] = {1}", key, _passwords[key])); OnBoolChange(true, 0, PasswordManagementConstants.PasswordUpdateBusyChange);
}
if (PasswordTimer == null) else
{ {
PasswordTimer = new CTimer((o) => PasswordTimerElapsed(), PasswordTimerElapsedMs); PasswordTimer.Reset(PasswordTimerElapsedMs);
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Started")); Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Reset"));
OnBoolChange(true, 0, PasswordManagementConstants.PasswordUpdateBusyChange); }
} }
else catch (Exception e)
{ {
PasswordTimer.Reset(PasswordTimerElapsedMs); var msg = string.Format("PasswordManager.UpdatePassword key-value[{0}, {1}] failed:\r{2}", key, password, e);
Debug.Console(1, string.Format("PasswordManager.UpdatePassword: CTimer Reset")); Debug.Console(1, msg);
} }
} }
catch (Exception e)
{ /// <summary>
var msg = string.Format("PasswordManager.UpdatePassword key-value[{0}, {1}] failed:\r{2}", key, password, e); /// CTimer callback function
Debug.Console(1, msg); /// </summary>
} private void PasswordTimerElapsed()
} {
try
/// <summary> {
/// CTimer callback function PasswordTimer.Stop();
/// </summary> Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: CTimer Stopped"));
private void PasswordTimerElapsed() OnBoolChange(false, 0, PasswordManagementConstants.PasswordUpdateBusyChange);
{ foreach (var pw in _passwords)
try {
{ // if key exists, continue
PasswordTimer.Stop(); if (Passwords.ContainsKey(pw.Key))
Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: CTimer Stopped")); {
OnBoolChange(false, 0, PasswordManagementConstants.PasswordUpdateBusyChange); Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: pw.key[{0}] = {1}", pw.Key, pw.Value));
foreach (var pw in _passwords) if (Passwords[pw.Key] != _passwords[pw.Key])
{ {
// if key exists, continue Passwords[pw.Key] = _passwords[pw.Key];
if (Passwords.ContainsKey(pw.Key)) Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: Updated Password[{0} = {1}", pw.Key, Passwords[pw.Key]));
{ OnPasswordChange(Passwords[pw.Key], (ushort)pw.Key, PasswordManagementConstants.StringValueChange);
Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: pw.key[{0}] = {1}", pw.Key, pw.Value)); }
if (Passwords[pw.Key] != _passwords[pw.Key]) }
{ // else add the key & value
Passwords[pw.Key] = _passwords[pw.Key]; else
Debug.Console(1, string.Format("PasswordManager.PasswordTimerElapsed: Updated Password[{0} = {1}", pw.Key, Passwords[pw.Key])); {
OnPasswordChange(Passwords[pw.Key], (ushort)pw.Key, PasswordManagementConstants.StringValueChange); Passwords.Add(pw.Key, pw.Value);
} }
} }
// else add the key & value OnUshrtChange((ushort)Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange);
else }
{ catch (Exception e)
Passwords.Add(pw.Key, pw.Value); {
} var msg = string.Format("PasswordManager.PasswordTimerElapsed failed:\r{0}", e);
} Debug.Console(1, msg);
OnUshrtChange((ushort)Passwords.Count, 0, PasswordManagementConstants.PasswordManagerCountChange); }
} }
catch (Exception e)
{ /// <summary>
var msg = string.Format("PasswordManager.PasswordTimerElapsed failed:\r{0}", e); /// Method to change the default timer value, (default 5000ms/5s)
Debug.Console(1, msg); /// </summary>
} /// <param name="time"></param>
} public void PasswordTimerMs(ushort time)
{
/// <summary> PasswordTimerElapsedMs = Convert.ToInt64(time);
/// Method to change the default timer value, (default 5000ms/5s) }
/// </summary>
/// <param name="time"></param> /// <summary>
public void PasswordTimerMs(ushort time) /// Helper method for debugging to see what passwords are in the lists
{ /// </summary>
PasswordTimerElapsedMs = Convert.ToInt64(time); public void ListPasswords()
} {
Debug.Console(0, "PasswordManager.ListPasswords:\r");
/// <summary> foreach (var pw in Passwords)
/// Helper method for debugging to see what passwords are in the lists Debug.Console(0, "Passwords[{0}]: {1}\r", pw.Key, pw.Value);
/// </summary> Debug.Console(0, "\n");
public void ListPasswords() foreach (var pw in _passwords)
{ Debug.Console(0, "_passwords[{0}]: {1}\r", pw.Key, pw.Value);
Debug.Console(0, "PasswordManager.ListPasswords:\r"); }
foreach (var pw in Passwords)
Debug.Console(0, "Passwords[{0}]: {1}\r", pw.Key, pw.Value); /// <summary>
Debug.Console(0, "\n"); /// Protected boolean change event handler
foreach (var pw in _passwords) /// </summary>
Debug.Console(0, "_passwords[{0}]: {1}\r", pw.Key, pw.Value); /// <param name="state"></param>
} /// <param name="index"></param>
/// <param name="type"></param>
/// <summary> protected void OnBoolChange(bool state, ushort index, ushort type)
/// Protected boolean change event handler {
/// </summary> var handler = BoolChange;
/// <param name="state"></param> if (handler != null)
/// <param name="index"></param> {
/// <param name="type"></param> var args = new BoolChangeEventArgs(state, type);
protected void OnBoolChange(bool state, ushort index, ushort type) args.Index = index;
{ BoolChange(this, args);
var handler = BoolChange; }
if (handler != null) }
{
var args = new BoolChangeEventArgs(state, type); /// <summary>
args.Index = index; /// Protected ushort change event handler
BoolChange(this, args); /// </summary>
} /// <param name="value"></param>
} /// <param name="index"></param>
/// <param name="type"></param>
/// <summary> protected void OnUshrtChange(ushort value, ushort index, ushort type)
/// Protected ushort change event handler {
/// </summary> var handler = UshrtChange;
/// <param name="value"></param> if (handler != null)
/// <param name="index"></param> {
/// <param name="type"></param> var args = new UshrtChangeEventArgs(value, type);
protected void OnUshrtChange(ushort value, ushort index, ushort type) args.Index = index;
{ UshrtChange(this, args);
var handler = UshrtChange; }
if (handler != null) }
{
var args = new UshrtChangeEventArgs(value, type); /// <summary>
args.Index = index; /// Protected string change event handler
UshrtChange(this, args); /// </summary>
} /// <param name="value"></param>
} /// <param name="index"></param>
/// <param name="type"></param>
/// <summary> protected void OnStringChange(string value, ushort index, ushort type)
/// Protected string change event handler {
/// </summary> var handler = StringChange;
/// <param name="value"></param> if (handler != null)
/// <param name="index"></param> {
/// <param name="type"></param> var args = new StringChangeEventArgs(value, type);
protected void OnStringChange(string value, ushort index, ushort type) args.Index = index;
{ StringChange(this, args);
var handler = StringChange; }
if (handler != null) }
{
var args = new StringChangeEventArgs(value, type); /// <summary>
args.Index = index; /// Protected password change event handler
StringChange(this, args); /// </summary>
} /// <param name="value"></param>
} /// <param name="index"></param>
/// <param name="type"></param>
/// <summary> protected void OnPasswordChange(string value, ushort index, ushort type)
/// Protected password change event handler {
/// </summary> var handler = PasswordChange;
/// <param name="value"></param> if (handler != null)
/// <param name="index"></param> {
/// <param name="type"></param> var args = new StringChangeEventArgs(value, type);
protected void OnPasswordChange(string value, ushort index, ushort type) args.Index = index;
{ PasswordChange(this, args);
var handler = PasswordChange; }
if (handler != null) }
{ }
var args = new StringChangeEventArgs(value, type);
args.Index = index;
PasswordChange(this, args);
}
}
}
} }

View file

@ -0,0 +1,63 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RootNamespace>PepperDash.Core</RootNamespace>
<AssemblyName>PepperDashCore</AssemblyName>
<TargetFramework>net472</TargetFramework>
<Deterministic>true</Deterministic>
<NeutralLanguage>en</NeutralLanguage>
<OutputPath>bin\$(Configuration)\</OutputPath>
<SignAssembly>False</SignAssembly>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>PepperDash Core</Title>
<Company>PepperDash Technologies</Company>
<RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/PepperDash/PepperDashCore</RepositoryUrl>
<PackageTags>crestron;4series;</PackageTags>
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
<InformationalVersion>$(Version)</InformationalVersion>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugType>full</DebugType>
<DefineConstants>TRACE;DEBUG;SERIES4</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<DocumentationFile>bin\4Series\$(Configuration)\PepperDashCore.xml</DocumentationFile>
</PropertyGroup>
<ItemGroup>
<Compile Remove="lib\**" />
<Compile Remove="Properties\**" />
<EmbeddedResource Remove="lib\**" />
<EmbeddedResource Remove="Properties\**" />
<None Remove="lib\**" />
<None Remove="Properties\**" />
</ItemGroup>
<ItemGroup>
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BouncyCastle.Cryptography" Version="2.4.0" />
<PackageReference Include="Crestron.SimplSharp.SDK.Library" Version="2.21.90" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Expressions" Version="4.0.0" />
<PackageReference Include="Serilog.Formatting.Compact" Version="2.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="SSH.NET" Version="2024.2.0" />
<PackageReference Include="WebSocketSharp" Version="1.0.3-rc11" />
</ItemGroup>
<ItemGroup Condition="'$(TargetFramework)' == 'net6'">
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Comm\._GenericSshClient.cs" />
<Compile Remove="Comm\._GenericTcpIpClient.cs" />
<Compile Remove="Comm\DynamicTCPServer.cs" />
<Compile Remove="PasswordManagement\OLD-ARRAY-Config.cs" />
<Compile Remove="PasswordManagement\OLD-ARRAY-PasswordClient.cs" />
<Compile Remove="PasswordManagement\OLD-ARRAY-PasswordManager.cs" />
</ItemGroup>
</Project>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ControlSystem> <ControlSystem>
<Name>MC3 SSH</Name> <Name>MC3 SSH</Name>
<Address>ssh 10.0.0.15</Address> <Address>ssh 10.0.0.15</Address>
<ProgramSlot>Program01</ProgramSlot> <ProgramSlot>Program01</ProgramSlot>
<Storage>Internal Flash</Storage> <Storage>Internal Flash</Storage>
</ControlSystem> </ControlSystem>

View file

@ -1,264 +1,264 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.SystemInfo namespace PepperDash.Core.SystemInfo
{ {
/// <summary> /// <summary>
/// Constants /// Constants
/// </summary> /// </summary>
public class SystemInfoConstants public class SystemInfoConstants
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort BoolValueChange = 1; public const ushort BoolValueChange = 1;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort CompleteBoolChange = 2; public const ushort CompleteBoolChange = 2;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort BusyBoolChange = 3; public const ushort BusyBoolChange = 3;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort UshortValueChange = 101; public const ushort UshortValueChange = 101;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort StringValueChange = 201; public const ushort StringValueChange = 201;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort ConsoleResponseChange = 202; public const ushort ConsoleResponseChange = 202;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort ProcessorUptimeChange = 203; public const ushort ProcessorUptimeChange = 203;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort ProgramUptimeChange = 204; public const ushort ProgramUptimeChange = 204;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort ObjectChange = 301; public const ushort ObjectChange = 301;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort ProcessorConfigChange = 302; public const ushort ProcessorConfigChange = 302;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort EthernetConfigChange = 303; public const ushort EthernetConfigChange = 303;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort ControlSubnetConfigChange = 304; public const ushort ControlSubnetConfigChange = 304;
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public const ushort ProgramConfigChange = 305; public const ushort ProgramConfigChange = 305;
} }
/// <summary> /// <summary>
/// Processor Change Event Args Class /// Processor Change Event Args Class
/// </summary> /// </summary>
public class ProcessorChangeEventArgs : EventArgs public class ProcessorChangeEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ProcessorInfo Processor { get; set; } public ProcessorInfo Processor { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort Type { get; set; } public ushort Type { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort Index { get; set; } public ushort Index { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ProcessorChangeEventArgs() public ProcessorChangeEventArgs()
{ {
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
public ProcessorChangeEventArgs(ProcessorInfo processor, ushort type) public ProcessorChangeEventArgs(ProcessorInfo processor, ushort type)
{ {
Processor = processor; Processor = processor;
Type = type; Type = type;
} }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ProcessorChangeEventArgs(ProcessorInfo processor, ushort type, ushort index) public ProcessorChangeEventArgs(ProcessorInfo processor, ushort type, ushort index)
{ {
Processor = processor; Processor = processor;
Type = type; Type = type;
Index = index; Index = index;
} }
} }
/// <summary> /// <summary>
/// Ethernet Change Event Args Class /// Ethernet Change Event Args Class
/// </summary> /// </summary>
public class EthernetChangeEventArgs : EventArgs public class EthernetChangeEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public EthernetInfo Adapter { get; set; } public EthernetInfo Adapter { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort Type { get; set; } public ushort Type { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort Index { get; set; } public ushort Index { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public EthernetChangeEventArgs() public EthernetChangeEventArgs()
{ {
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="ethernet"></param> /// <param name="ethernet"></param>
/// <param name="type"></param> /// <param name="type"></param>
public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type) public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type)
{ {
Adapter = ethernet; Adapter = ethernet;
Type = type; Type = type;
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="ethernet"></param> /// <param name="ethernet"></param>
/// <param name="type"></param> /// <param name="type"></param>
/// <param name="index"></param> /// <param name="index"></param>
public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type, ushort index) public EthernetChangeEventArgs(EthernetInfo ethernet, ushort type, ushort index)
{ {
Adapter = ethernet; Adapter = ethernet;
Type = type; Type = type;
Index = index; Index = index;
} }
} }
/// <summary> /// <summary>
/// Control Subnet Chage Event Args Class /// Control Subnet Chage Event Args Class
/// </summary> /// </summary>
public class ControlSubnetChangeEventArgs : EventArgs public class ControlSubnetChangeEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ControlSubnetInfo Adapter { get; set; } public ControlSubnetInfo Adapter { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort Type { get; set; } public ushort Type { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort Index { get; set; } public ushort Index { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ControlSubnetChangeEventArgs() public ControlSubnetChangeEventArgs()
{ {
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
public ControlSubnetChangeEventArgs(ControlSubnetInfo controlSubnet, ushort type) public ControlSubnetChangeEventArgs(ControlSubnetInfo controlSubnet, ushort type)
{ {
Adapter = controlSubnet; Adapter = controlSubnet;
Type = type; Type = type;
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
public ControlSubnetChangeEventArgs(ControlSubnetInfo controlSubnet, ushort type, ushort index) public ControlSubnetChangeEventArgs(ControlSubnetInfo controlSubnet, ushort type, ushort index)
{ {
Adapter = controlSubnet; Adapter = controlSubnet;
Type = type; Type = type;
Index = index; Index = index;
} }
} }
/// <summary> /// <summary>
/// Program Change Event Args Class /// Program Change Event Args Class
/// </summary> /// </summary>
public class ProgramChangeEventArgs : EventArgs public class ProgramChangeEventArgs : EventArgs
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ProgramInfo Program { get; set; } public ProgramInfo Program { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort Type { get; set; } public ushort Type { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort Index { get; set; } public ushort Index { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ProgramChangeEventArgs() public ProgramChangeEventArgs()
{ {
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="program"></param> /// <param name="program"></param>
/// <param name="type"></param> /// <param name="type"></param>
public ProgramChangeEventArgs(ProgramInfo program, ushort type) public ProgramChangeEventArgs(ProgramInfo program, ushort type)
{ {
Program = program; Program = program;
Type = type; Type = type;
} }
/// <summary> /// <summary>
/// Constructor overload /// Constructor overload
/// </summary> /// </summary>
/// <param name="program"></param> /// <param name="program"></param>
/// <param name="type"></param> /// <param name="type"></param>
/// <param name="index"></param> /// <param name="index"></param>
public ProgramChangeEventArgs(ProgramInfo program, ushort type, ushort index) public ProgramChangeEventArgs(ProgramInfo program, ushort type, ushort index)
{ {
Program = program; Program = program;
Type = type; Type = type;
Index = index; Index = index;
} }
} }
} }

View file

@ -1,204 +1,204 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.SystemInfo namespace PepperDash.Core.SystemInfo
{ {
/// <summary> /// <summary>
/// Processor info class /// Processor info class
/// </summary> /// </summary>
public class ProcessorInfo public class ProcessorInfo
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Model { get; set; } public string Model { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string SerialNumber { get; set; } public string SerialNumber { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Firmware { get; set; } public string Firmware { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string FirmwareDate { get; set; } public string FirmwareDate { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string OsVersion { get; set; } public string OsVersion { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string RuntimeEnvironment { get; set; } public string RuntimeEnvironment { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string DevicePlatform { get; set; } public string DevicePlatform { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string ModuleDirectory { get; set; } public string ModuleDirectory { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string LocalTimeZone { get; set; } public string LocalTimeZone { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string ProgramIdTag { get; set; } public string ProgramIdTag { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ProcessorInfo() public ProcessorInfo()
{ {
} }
} }
/// <summary> /// <summary>
/// Ethernet info class /// Ethernet info class
/// </summary> /// </summary>
public class EthernetInfo public class EthernetInfo
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort DhcpIsOn { get; set; } public ushort DhcpIsOn { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Hostname { get; set; } public string Hostname { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string MacAddress { get; set; } public string MacAddress { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string IpAddress { get; set; } public string IpAddress { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Subnet { get; set; } public string Subnet { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Gateway { get; set; } public string Gateway { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Dns1 { get; set; } public string Dns1 { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Dns2 { get; set; } public string Dns2 { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Dns3 { get; set; } public string Dns3 { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Domain { get; set; } public string Domain { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public EthernetInfo() public EthernetInfo()
{ {
} }
} }
/// <summary> /// <summary>
/// Control subnet info class /// Control subnet info class
/// </summary> /// </summary>
public class ControlSubnetInfo public class ControlSubnetInfo
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort Enabled { get; set; } public ushort Enabled { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public ushort IsInAutomaticMode { get; set; } public ushort IsInAutomaticMode { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string MacAddress { get; set; } public string MacAddress { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string IpAddress { get; set; } public string IpAddress { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Subnet { get; set; } public string Subnet { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string RouterPrefix { get; set; } public string RouterPrefix { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ControlSubnetInfo() public ControlSubnetInfo()
{ {
} }
} }
/// <summary> /// <summary>
/// Program info class /// Program info class
/// </summary> /// </summary>
public class ProgramInfo public class ProgramInfo
{ {
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Name { get; set; } public string Name { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Header { get; set; } public string Header { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string System { get; set; } public string System { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string ProgramIdTag { get; set; } public string ProgramIdTag { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string CompileTime { get; set; } public string CompileTime { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Database { get; set; } public string Database { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Environment { get; set; } public string Environment { get; set; }
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
public string Programmer { get; set; } public string Programmer { get; set; }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public ProgramInfo() public ProgramInfo()
{ {
} }
} }
} }

View file

@ -1,462 +1,462 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using Crestron.SimplSharp; using Crestron.SimplSharp;
namespace PepperDash.Core.SystemInfo namespace PepperDash.Core.SystemInfo
{ {
/// <summary> /// <summary>
/// System Info class /// System Info class
/// </summary> /// </summary>
public class SystemInfoToSimpl public class SystemInfoToSimpl
{ {
/// <summary> /// <summary>
/// Notifies of bool change /// Notifies of bool change
/// </summary> /// </summary>
public event EventHandler<BoolChangeEventArgs> BoolChange; public event EventHandler<BoolChangeEventArgs> BoolChange;
/// <summary> /// <summary>
/// Notifies of string change /// Notifies of string change
/// </summary> /// </summary>
public event EventHandler<StringChangeEventArgs> StringChange; public event EventHandler<StringChangeEventArgs> StringChange;
/// <summary> /// <summary>
/// Notifies of processor change /// Notifies of processor change
/// </summary> /// </summary>
public event EventHandler<ProcessorChangeEventArgs> ProcessorChange; public event EventHandler<ProcessorChangeEventArgs> ProcessorChange;
/// <summary> /// <summary>
/// Notifies of ethernet change /// Notifies of ethernet change
/// </summary> /// </summary>
public event EventHandler<EthernetChangeEventArgs> EthernetChange; public event EventHandler<EthernetChangeEventArgs> EthernetChange;
/// <summary> /// <summary>
/// Notifies of control subnet change /// Notifies of control subnet change
/// </summary> /// </summary>
public event EventHandler<ControlSubnetChangeEventArgs> ControlSubnetChange; public event EventHandler<ControlSubnetChangeEventArgs> ControlSubnetChange;
/// <summary> /// <summary>
/// Notifies of program change /// Notifies of program change
/// </summary> /// </summary>
public event EventHandler<ProgramChangeEventArgs> ProgramChange; public event EventHandler<ProgramChangeEventArgs> ProgramChange;
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public SystemInfoToSimpl() public SystemInfoToSimpl()
{ {
} }
/// <summary> /// <summary>
/// Gets the current processor info /// Gets the current processor info
/// </summary> /// </summary>
public void GetProcessorInfo() public void GetProcessorInfo()
{ {
OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange); OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange);
try try
{ {
var processor = new ProcessorInfo(); var processor = new ProcessorInfo();
processor.Model = InitialParametersClass.ControllerPromptName; processor.Model = InitialParametersClass.ControllerPromptName;
processor.SerialNumber = CrestronEnvironment.SystemInfo.SerialNumber; processor.SerialNumber = CrestronEnvironment.SystemInfo.SerialNumber;
processor.ModuleDirectory = InitialParametersClass.ProgramDirectory.ToString(); processor.ModuleDirectory = InitialParametersClass.ProgramDirectory.ToString();
processor.ProgramIdTag = InitialParametersClass.ProgramIDTag; processor.ProgramIdTag = InitialParametersClass.ProgramIDTag;
processor.DevicePlatform = CrestronEnvironment.DevicePlatform.ToString(); processor.DevicePlatform = CrestronEnvironment.DevicePlatform.ToString();
processor.OsVersion = CrestronEnvironment.OSVersion.Version.ToString(); processor.OsVersion = CrestronEnvironment.OSVersion.Version.ToString();
processor.RuntimeEnvironment = CrestronEnvironment.RuntimeEnvironment.ToString(); processor.RuntimeEnvironment = CrestronEnvironment.RuntimeEnvironment.ToString();
processor.LocalTimeZone = CrestronEnvironment.GetTimeZone().Offset; processor.LocalTimeZone = CrestronEnvironment.GetTimeZone().Offset;
// Does not return firmware version matching a "ver" command // Does not return firmware version matching a "ver" command
// returns the "ver -v" 'CAB' version // returns the "ver -v" 'CAB' version
// example return ver -v: // example return ver -v:
// RMC3 Cntrl Eng [v1.503.3568.25373 (Oct 09 2018), #4001E302] @E-00107f4420f0 // RMC3 Cntrl Eng [v1.503.3568.25373 (Oct 09 2018), #4001E302] @E-00107f4420f0
// Build: 14:05:46 Oct 09 2018 (3568.25373) // Build: 14:05:46 Oct 09 2018 (3568.25373)
// Cab: 1.503.0070 // Cab: 1.503.0070
// Applications: 1.0.6855.21351 // Applications: 1.0.6855.21351
// Updater: 1.4.24 // Updater: 1.4.24
// Bootloader: 1.22.00 // Bootloader: 1.22.00
// RMC3-SetupProgram: 1.003.0011 // RMC3-SetupProgram: 1.003.0011
// IOPVersion: FPGA [v09] slot:7 // IOPVersion: FPGA [v09] slot:7
// PUF: Unknown // PUF: Unknown
//Firmware = CrestronEnvironment.OSVersion.Firmware; //Firmware = CrestronEnvironment.OSVersion.Firmware;
//Firmware = InitialParametersClass.FirmwareVersion; //Firmware = InitialParametersClass.FirmwareVersion;
// Use below logic to get actual firmware ver, not the 'CAB' returned by the above // Use below logic to get actual firmware ver, not the 'CAB' returned by the above
// matches console return of a "ver" and on SystemInfo page // matches console return of a "ver" and on SystemInfo page
// example return ver: // example return ver:
// RMC3 Cntrl Eng [v1.503.3568.25373 (Oct 09 2018), #4001E302] @E-00107f4420f0 // RMC3 Cntrl Eng [v1.503.3568.25373 (Oct 09 2018), #4001E302] @E-00107f4420f0
var response = ""; var response = "";
CrestronConsole.SendControlSystemCommand("ver", ref response); CrestronConsole.SendControlSystemCommand("ver", ref response);
processor.Firmware = ParseConsoleResponse(response, "Cntrl Eng", "[", "("); processor.Firmware = ParseConsoleResponse(response, "Cntrl Eng", "[", "(");
processor.FirmwareDate = ParseConsoleResponse(response, "Cntrl Eng", "(", ")"); processor.FirmwareDate = ParseConsoleResponse(response, "Cntrl Eng", "(", ")");
OnProcessorChange(processor, 0, SystemInfoConstants.ProcessorConfigChange); OnProcessorChange(processor, 0, SystemInfoConstants.ProcessorConfigChange);
} }
catch (Exception e) catch (Exception e)
{ {
var msg = string.Format("GetProcessorInfo failed: {0}", e.Message); var msg = string.Format("GetProcessorInfo failed: {0}", e.Message);
CrestronConsole.PrintLine(msg); CrestronConsole.PrintLine(msg);
//ErrorLog.Error(msg); //ErrorLog.Error(msg);
} }
OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange); OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange);
} }
/// <summary> /// <summary>
/// Gets the current ethernet info /// Gets the current ethernet info
/// </summary> /// </summary>
public void GetEthernetInfo() public void GetEthernetInfo()
{ {
OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange); OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange);
var adapter = new EthernetInfo(); var adapter = new EthernetInfo();
try try
{ {
// get lan adapter id // get lan adapter id
var adapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter); var adapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetLANAdapter);
// get lan adapter info // get lan adapter info
var dhcpState = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, adapterId); var dhcpState = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_DHCP_STATE, adapterId);
if (!string.IsNullOrEmpty(dhcpState)) if (!string.IsNullOrEmpty(dhcpState))
adapter.DhcpIsOn = (ushort)(dhcpState.ToLower().Contains("on") ? 1 : 0); adapter.DhcpIsOn = (ushort)(dhcpState.ToLower().Contains("on") ? 1 : 0);
adapter.Hostname = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterId); adapter.Hostname = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_HOSTNAME, adapterId);
adapter.MacAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterId); adapter.MacAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterId);
adapter.IpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterId); adapter.IpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterId);
adapter.Subnet = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterId); adapter.Subnet = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterId);
adapter.Gateway = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterId); adapter.Gateway = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_ROUTER, adapterId);
adapter.Domain = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, adapterId); adapter.Domain = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DOMAIN_NAME, adapterId);
// returns comma seperate list of dns servers with trailing comma // returns comma seperate list of dns servers with trailing comma
// example return: "8.8.8.8 (DHCP),8.8.4.4 (DHCP)," // example return: "8.8.8.8 (DHCP),8.8.4.4 (DHCP),"
string dns = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, adapterId); string dns = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_DNS_SERVER, adapterId);
if (dns.Contains(",")) if (dns.Contains(","))
{ {
string[] dnsList = dns.Split(','); string[] dnsList = dns.Split(',');
for (var i = 0; i < dnsList.Length; i++) for (var i = 0; i < dnsList.Length; i++)
{ {
if(i == 0) if(i == 0)
adapter.Dns1 = !string.IsNullOrEmpty(dnsList[0]) ? dnsList[0] : "0.0.0.0"; adapter.Dns1 = !string.IsNullOrEmpty(dnsList[0]) ? dnsList[0] : "0.0.0.0";
if(i == 1) if(i == 1)
adapter.Dns2 = !string.IsNullOrEmpty(dnsList[1]) ? dnsList[1] : "0.0.0.0"; adapter.Dns2 = !string.IsNullOrEmpty(dnsList[1]) ? dnsList[1] : "0.0.0.0";
if(i == 2) if(i == 2)
adapter.Dns3 = !string.IsNullOrEmpty(dnsList[2]) ? dnsList[2] : "0.0.0.0"; adapter.Dns3 = !string.IsNullOrEmpty(dnsList[2]) ? dnsList[2] : "0.0.0.0";
} }
} }
else else
{ {
adapter.Dns1 = !string.IsNullOrEmpty(dns) ? dns : "0.0.0.0"; adapter.Dns1 = !string.IsNullOrEmpty(dns) ? dns : "0.0.0.0";
adapter.Dns2 = "0.0.0.0"; adapter.Dns2 = "0.0.0.0";
adapter.Dns3 = "0.0.0.0"; adapter.Dns3 = "0.0.0.0";
} }
OnEthernetInfoChange(adapter, 0, SystemInfoConstants.EthernetConfigChange); OnEthernetInfoChange(adapter, 0, SystemInfoConstants.EthernetConfigChange);
} }
catch (Exception e) catch (Exception e)
{ {
var msg = string.Format("GetEthernetInfo failed: {0}", e.Message); var msg = string.Format("GetEthernetInfo failed: {0}", e.Message);
CrestronConsole.PrintLine(msg); CrestronConsole.PrintLine(msg);
//ErrorLog.Error(msg); //ErrorLog.Error(msg);
} }
OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange); OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange);
} }
/// <summary> /// <summary>
/// Gets the current control subnet info /// Gets the current control subnet info
/// </summary> /// </summary>
public void GetControlSubnetInfo() public void GetControlSubnetInfo()
{ {
OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange); OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange);
var adapter = new ControlSubnetInfo(); var adapter = new ControlSubnetInfo();
try try
{ {
// get cs adapter id // get cs adapter id
var adapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter); var adapterId = CrestronEthernetHelper.GetAdapterdIdForSpecifiedAdapterType(EthernetAdapterType.EthernetCSAdapter);
if (!adapterId.Equals(EthernetAdapterType.EthernetUnknownAdapter)) if (!adapterId.Equals(EthernetAdapterType.EthernetUnknownAdapter))
{ {
adapter.Enabled = 1; adapter.Enabled = 1;
adapter.IsInAutomaticMode = (ushort)(CrestronEthernetHelper.IsControlSubnetInAutomaticMode ? 1 : 0); adapter.IsInAutomaticMode = (ushort)(CrestronEthernetHelper.IsControlSubnetInAutomaticMode ? 1 : 0);
adapter.MacAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterId); adapter.MacAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_MAC_ADDRESS, adapterId);
adapter.IpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterId); adapter.IpAddress = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_ADDRESS, adapterId);
adapter.Subnet = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterId); adapter.Subnet = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CURRENT_IP_MASK, adapterId);
adapter.RouterPrefix = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CONTROL_SUBNET_ROUTER_PREFIX, adapterId); adapter.RouterPrefix = CrestronEthernetHelper.GetEthernetParameter(CrestronEthernetHelper.ETHERNET_PARAMETER_TO_GET.GET_CONTROL_SUBNET_ROUTER_PREFIX, adapterId);
} }
} }
catch (Exception e) catch (Exception e)
{ {
adapter.Enabled = 0; adapter.Enabled = 0;
adapter.IsInAutomaticMode = 0; adapter.IsInAutomaticMode = 0;
adapter.MacAddress = "NA"; adapter.MacAddress = "NA";
adapter.IpAddress = "NA"; adapter.IpAddress = "NA";
adapter.Subnet = "NA"; adapter.Subnet = "NA";
adapter.RouterPrefix = "NA"; adapter.RouterPrefix = "NA";
var msg = string.Format("GetControlSubnetInfo failed: {0}", e.Message); var msg = string.Format("GetControlSubnetInfo failed: {0}", e.Message);
CrestronConsole.PrintLine(msg); CrestronConsole.PrintLine(msg);
//ErrorLog.Error(msg); //ErrorLog.Error(msg);
} }
OnControlSubnetInfoChange(adapter, 0, SystemInfoConstants.ControlSubnetConfigChange); OnControlSubnetInfoChange(adapter, 0, SystemInfoConstants.ControlSubnetConfigChange);
OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange); OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange);
} }
/// <summary> /// <summary>
/// Gets the program info by index /// Gets the program info by index
/// </summary> /// </summary>
/// <param name="index"></param> /// <param name="index"></param>
public void GetProgramInfoByIndex(ushort index) public void GetProgramInfoByIndex(ushort index)
{ {
if (index < 1 || index > 10) if (index < 1 || index > 10)
return; return;
OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange); OnBoolChange(true, 0, SystemInfoConstants.BusyBoolChange);
var program = new ProgramInfo(); var program = new ProgramInfo();
try try
{ {
var response = ""; var response = "";
CrestronConsole.SendControlSystemCommand(string.Format("progcomments:{0}", index), ref response); CrestronConsole.SendControlSystemCommand(string.Format("progcomments:{0}", index), ref response);
// no program loaded or running // no program loaded or running
if (response.Contains("Bad or Incomplete Command")) if (response.Contains("Bad or Incomplete Command"))
{ {
program.Name = ""; program.Name = "";
program.System = ""; program.System = "";
program.Programmer = ""; program.Programmer = "";
program.CompileTime = ""; program.CompileTime = "";
program.Database = ""; program.Database = "";
program.Environment = ""; program.Environment = "";
} }
else else
{ {
// SIMPL returns // SIMPL returns
program.Name = ParseConsoleResponse(response, "Program File", ":", "\x0D"); program.Name = ParseConsoleResponse(response, "Program File", ":", "\x0D");
program.System = ParseConsoleResponse(response, "System Name", ":", "\x0D"); program.System = ParseConsoleResponse(response, "System Name", ":", "\x0D");
program.ProgramIdTag = ParseConsoleResponse(response, "Friendly Name", ":", "\x0D"); program.ProgramIdTag = ParseConsoleResponse(response, "Friendly Name", ":", "\x0D");
program.Programmer = ParseConsoleResponse(response, "Programmer", ":", "\x0D"); program.Programmer = ParseConsoleResponse(response, "Programmer", ":", "\x0D");
program.CompileTime = ParseConsoleResponse(response, "Compiled On", ":", "\x0D"); program.CompileTime = ParseConsoleResponse(response, "Compiled On", ":", "\x0D");
program.Database = ParseConsoleResponse(response, "CrestronDB", ":", "\x0D"); program.Database = ParseConsoleResponse(response, "CrestronDB", ":", "\x0D");
program.Environment = ParseConsoleResponse(response, "Source Env", ":", "\x0D"); program.Environment = ParseConsoleResponse(response, "Source Env", ":", "\x0D");
// S# returns // S# returns
if (program.System.Length == 0) if (program.System.Length == 0)
program.System = ParseConsoleResponse(response, "Application Name", ":", "\x0D"); program.System = ParseConsoleResponse(response, "Application Name", ":", "\x0D");
if (program.Database.Length == 0) if (program.Database.Length == 0)
program.Database = ParseConsoleResponse(response, "PlugInVersion", ":", "\x0D"); program.Database = ParseConsoleResponse(response, "PlugInVersion", ":", "\x0D");
if (program.Environment.Length == 0) if (program.Environment.Length == 0)
program.Environment = ParseConsoleResponse(response, "Program Tool", ":", "\x0D"); program.Environment = ParseConsoleResponse(response, "Program Tool", ":", "\x0D");
} }
OnProgramChange(program, index, SystemInfoConstants.ProgramConfigChange); OnProgramChange(program, index, SystemInfoConstants.ProgramConfigChange);
} }
catch (Exception e) catch (Exception e)
{ {
var msg = string.Format("GetProgramInfoByIndex failed: {0}", e.Message); var msg = string.Format("GetProgramInfoByIndex failed: {0}", e.Message);
CrestronConsole.PrintLine(msg); CrestronConsole.PrintLine(msg);
//ErrorLog.Error(msg); //ErrorLog.Error(msg);
} }
OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange); OnBoolChange(false, 0, SystemInfoConstants.BusyBoolChange);
} }
/// <summary> /// <summary>
/// Gets the processor uptime and passes it to S+ /// Gets the processor uptime and passes it to S+
/// </summary> /// </summary>
public void RefreshProcessorUptime() public void RefreshProcessorUptime()
{ {
try try
{ {
string response = ""; string response = "";
CrestronConsole.SendControlSystemCommand("uptime", ref response); CrestronConsole.SendControlSystemCommand("uptime", ref response);
var uptime = ParseConsoleResponse(response, "running for", "running for", "\x0D"); var uptime = ParseConsoleResponse(response, "running for", "running for", "\x0D");
OnStringChange(uptime, 0, SystemInfoConstants.ProcessorUptimeChange); OnStringChange(uptime, 0, SystemInfoConstants.ProcessorUptimeChange);
} }
catch (Exception e) catch (Exception e)
{ {
var msg = string.Format("RefreshProcessorUptime failed:\r{0}", e.Message); var msg = string.Format("RefreshProcessorUptime failed:\r{0}", e.Message);
CrestronConsole.PrintLine(msg); CrestronConsole.PrintLine(msg);
//ErrorLog.Error(msg); //ErrorLog.Error(msg);
} }
} }
/// <summary> /// <summary>
/// Gets the program uptime, by index, and passes it to S+ /// Gets the program uptime, by index, and passes it to S+
/// </summary> /// </summary>
/// <param name="index"></param> /// <param name="index"></param>
public void RefreshProgramUptimeByIndex(int index) public void RefreshProgramUptimeByIndex(int index)
{ {
try try
{ {
string response = ""; string response = "";
CrestronConsole.SendControlSystemCommand(string.Format("proguptime:{0}", index), ref response); CrestronConsole.SendControlSystemCommand(string.Format("proguptime:{0}", index), ref response);
string uptime = ParseConsoleResponse(response, "running for", "running for", "\x0D"); string uptime = ParseConsoleResponse(response, "running for", "running for", "\x0D");
OnStringChange(uptime, (ushort)index, SystemInfoConstants.ProgramUptimeChange); OnStringChange(uptime, (ushort)index, SystemInfoConstants.ProgramUptimeChange);
} }
catch (Exception e) catch (Exception e)
{ {
var msg = string.Format("RefreshProgramUptimebyIndex({0}) failed:\r{1}", index, e.Message); var msg = string.Format("RefreshProgramUptimebyIndex({0}) failed:\r{1}", index, e.Message);
CrestronConsole.PrintLine(msg); CrestronConsole.PrintLine(msg);
//ErrorLog.Error(msg); //ErrorLog.Error(msg);
} }
} }
/// <summary> /// <summary>
/// Sends command to console, passes response back using string change event /// Sends command to console, passes response back using string change event
/// </summary> /// </summary>
/// <param name="cmd"></param> /// <param name="cmd"></param>
public void SendConsoleCommand(string cmd) public void SendConsoleCommand(string cmd)
{ {
if (string.IsNullOrEmpty(cmd)) if (string.IsNullOrEmpty(cmd))
return; return;
string response = ""; string response = "";
CrestronConsole.SendControlSystemCommand(cmd, ref response); CrestronConsole.SendControlSystemCommand(cmd, ref response);
if (!string.IsNullOrEmpty(response)) if (!string.IsNullOrEmpty(response))
{ {
if (response.EndsWith("\x0D\\x0A")) if (response.EndsWith("\x0D\\x0A"))
response.Trim('\n'); response.Trim('\n');
OnStringChange(response, 0, SystemInfoConstants.ConsoleResponseChange); OnStringChange(response, 0, SystemInfoConstants.ConsoleResponseChange);
} }
} }
/// <summary> /// <summary>
/// private method to parse console messages /// private method to parse console messages
/// </summary> /// </summary>
/// <param name="data"></param> /// <param name="data"></param>
/// <param name="line"></param> /// <param name="line"></param>
/// <param name="dataStart"></param> /// <param name="dataStart"></param>
/// <param name="dataEnd"></param> /// <param name="dataEnd"></param>
/// <returns></returns> /// <returns></returns>
private string ParseConsoleResponse(string data, string line, string dataStart, string dataEnd) private string ParseConsoleResponse(string data, string line, string dataStart, string dataEnd)
{ {
var response = ""; var response = "";
if (string.IsNullOrEmpty(data) || string.IsNullOrEmpty(line) || string.IsNullOrEmpty(dataStart) || string.IsNullOrEmpty(dataEnd)) if (string.IsNullOrEmpty(data) || string.IsNullOrEmpty(line) || string.IsNullOrEmpty(dataStart) || string.IsNullOrEmpty(dataEnd))
return response; return response;
try try
{ {
var linePos = data.IndexOf(line); var linePos = data.IndexOf(line);
var startPos = data.IndexOf(dataStart, linePos) + dataStart.Length; var startPos = data.IndexOf(dataStart, linePos) + dataStart.Length;
var endPos = data.IndexOf(dataEnd, startPos); var endPos = data.IndexOf(dataEnd, startPos);
response = data.Substring(startPos, endPos - startPos).Trim(); response = data.Substring(startPos, endPos - startPos).Trim();
} }
catch (Exception e) catch (Exception e)
{ {
var msg = string.Format("ParseConsoleResponse failed: {0}", e.Message); var msg = string.Format("ParseConsoleResponse failed: {0}", e.Message);
CrestronConsole.PrintLine(msg); CrestronConsole.PrintLine(msg);
//ErrorLog.Error(msg); //ErrorLog.Error(msg);
} }
return response; return response;
} }
/// <summary> /// <summary>
/// Protected boolean change event handler /// Protected boolean change event handler
/// </summary> /// </summary>
/// <param name="state"></param> /// <param name="state"></param>
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="type"></param> /// <param name="type"></param>
protected void OnBoolChange(bool state, ushort index, ushort type) protected void OnBoolChange(bool state, ushort index, ushort type)
{ {
var handler = BoolChange; var handler = BoolChange;
if (handler != null) if (handler != null)
{ {
var args = new BoolChangeEventArgs(state, type); var args = new BoolChangeEventArgs(state, type);
args.Index = index; args.Index = index;
BoolChange(this, args); BoolChange(this, args);
} }
} }
/// <summary> /// <summary>
/// Protected string change event handler /// Protected string change event handler
/// </summary> /// </summary>
/// <param name="value"></param> /// <param name="value"></param>
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="type"></param> /// <param name="type"></param>
protected void OnStringChange(string value, ushort index, ushort type) protected void OnStringChange(string value, ushort index, ushort type)
{ {
var handler = StringChange; var handler = StringChange;
if (handler != null) if (handler != null)
{ {
var args = new StringChangeEventArgs(value, type); var args = new StringChangeEventArgs(value, type);
args.Index = index; args.Index = index;
StringChange(this, args); StringChange(this, args);
} }
} }
/// <summary> /// <summary>
/// Protected processor config change event handler /// Protected processor config change event handler
/// </summary> /// </summary>
/// <param name="processor"></param> /// <param name="processor"></param>
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="type"></param> /// <param name="type"></param>
protected void OnProcessorChange(ProcessorInfo processor, ushort index, ushort type) protected void OnProcessorChange(ProcessorInfo processor, ushort index, ushort type)
{ {
var handler = ProcessorChange; var handler = ProcessorChange;
if (handler != null) if (handler != null)
{ {
var args = new ProcessorChangeEventArgs(processor, type); var args = new ProcessorChangeEventArgs(processor, type);
args.Index = index; args.Index = index;
ProcessorChange(this, args); ProcessorChange(this, args);
} }
} }
/// <summary> /// <summary>
/// Ethernet change event handler /// Ethernet change event handler
/// </summary> /// </summary>
/// <param name="ethernet"></param> /// <param name="ethernet"></param>
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="type"></param> /// <param name="type"></param>
protected void OnEthernetInfoChange(EthernetInfo ethernet, ushort index, ushort type) protected void OnEthernetInfoChange(EthernetInfo ethernet, ushort index, ushort type)
{ {
var handler = EthernetChange; var handler = EthernetChange;
if (handler != null) if (handler != null)
{ {
var args = new EthernetChangeEventArgs(ethernet, type); var args = new EthernetChangeEventArgs(ethernet, type);
args.Index = index; args.Index = index;
EthernetChange(this, args); EthernetChange(this, args);
} }
} }
/// <summary> /// <summary>
/// Control Subnet change event handler /// Control Subnet change event handler
/// </summary> /// </summary>
/// <param name="ethernet"></param> /// <param name="ethernet"></param>
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="type"></param> /// <param name="type"></param>
protected void OnControlSubnetInfoChange(ControlSubnetInfo ethernet, ushort index, ushort type) protected void OnControlSubnetInfoChange(ControlSubnetInfo ethernet, ushort index, ushort type)
{ {
var handler = ControlSubnetChange; var handler = ControlSubnetChange;
if (handler != null) if (handler != null)
{ {
var args = new ControlSubnetChangeEventArgs(ethernet, type); var args = new ControlSubnetChangeEventArgs(ethernet, type);
args.Index = index; args.Index = index;
ControlSubnetChange(this, args); ControlSubnetChange(this, args);
} }
} }
/// <summary> /// <summary>
/// Program change event handler /// Program change event handler
/// </summary> /// </summary>
/// <param name="program"></param> /// <param name="program"></param>
/// <param name="index"></param> /// <param name="index"></param>
/// <param name="type"></param> /// <param name="type"></param>
protected void OnProgramChange(ProgramInfo program, ushort index, ushort type) protected void OnProgramChange(ProgramInfo program, ushort index, ushort type)
{ {
var handler = ProgramChange; var handler = ProgramChange;
if (handler != null) if (handler != null)
{ {
var args = new ProgramChangeEventArgs(program, type); var args = new ProgramChangeEventArgs(program, type);
args.Index = index; args.Index = index;
ProgramChange(this, args); ProgramChange(this, args);
} }
} }
} }
} }

View file

@ -0,0 +1,356 @@
using Crestron.SimplSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Utilities;
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 Org.BouncyCastle.Crypto.Operators;
using BigInteger = Org.BouncyCastle.Math.BigInteger;
using X509Certificate = Org.BouncyCastle.X509.X509Certificate;
namespace PepperDash.Core
{
/// <summary>
/// Taken From https://github.com/rlipscombe/bouncy-castle-csharp/
/// </summary>
internal class BouncyCertificate
{
public string CertificatePassword { get; set; } = "password";
public X509Certificate2 LoadCertificate(string issuerFileName, string password)
{
// We need to pass 'Exportable', otherwise we can't get the private key.
var issuerCertificate = new X509Certificate2(issuerFileName, password, X509KeyStorageFlags.Exportable);
return issuerCertificate;
}
public X509Certificate2 IssueCertificate(string subjectName, X509Certificate2 issuerCertificate, string[] subjectAlternativeNames, KeyPurposeID[] usages)
{
// It's self-signed, so these are the same.
var issuerName = issuerCertificate.Subject;
var random = GetSecureRandom();
var subjectKeyPair = GenerateKeyPair(random, 2048);
var issuerKeyPair = DotNetUtilities.GetKeyPair(issuerCertificate.PrivateKey);
var serialNumber = GenerateSerialNumber(random);
var issuerSerialNumber = new BigInteger(issuerCertificate.GetSerialNumber());
const bool isCertificateAuthority = false;
var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber,
subjectAlternativeNames, issuerName, issuerKeyPair,
issuerSerialNumber, isCertificateAuthority,
usages);
return ConvertCertificate(certificate, subjectKeyPair, random);
}
public X509Certificate2 CreateCertificateAuthorityCertificate(string subjectName, string[] subjectAlternativeNames, KeyPurposeID[] usages)
{
// It's self-signed, so these are the same.
var issuerName = subjectName;
var random = GetSecureRandom();
var subjectKeyPair = GenerateKeyPair(random, 2048);
// It's self-signed, so these are the same.
var issuerKeyPair = subjectKeyPair;
var serialNumber = GenerateSerialNumber(random);
var issuerSerialNumber = serialNumber; // Self-signed, so it's the same serial number.
const bool isCertificateAuthority = true;
var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber,
subjectAlternativeNames, issuerName, issuerKeyPair,
issuerSerialNumber, isCertificateAuthority,
usages);
return ConvertCertificate(certificate, subjectKeyPair, random);
}
public X509Certificate2 CreateSelfSignedCertificate(string subjectName, string[] subjectAlternativeNames, KeyPurposeID[] usages)
{
// It's self-signed, so these are the same.
var issuerName = subjectName;
var random = GetSecureRandom();
var subjectKeyPair = GenerateKeyPair(random, 2048);
// It's self-signed, so these are the same.
var issuerKeyPair = subjectKeyPair;
var serialNumber = GenerateSerialNumber(random);
var issuerSerialNumber = serialNumber; // Self-signed, so it's the same serial number.
const bool isCertificateAuthority = false;
var certificate = GenerateCertificate(random, subjectName, subjectKeyPair, serialNumber,
subjectAlternativeNames, issuerName, issuerKeyPair,
issuerSerialNumber, isCertificateAuthority,
usages);
return ConvertCertificate(certificate, subjectKeyPair, random);
}
private SecureRandom GetSecureRandom()
{
// Since we're on Windows, we'll use the CryptoAPI one (on the assumption
// that it might have access to better sources of entropy than the built-in
// Bouncy Castle ones):
var randomGenerator = new CryptoApiRandomGenerator();
var random = new SecureRandom(randomGenerator);
return random;
}
private X509Certificate GenerateCertificate(SecureRandom random,
string subjectName,
AsymmetricCipherKeyPair subjectKeyPair,
BigInteger subjectSerialNumber,
string[] subjectAlternativeNames,
string issuerName,
AsymmetricCipherKeyPair issuerKeyPair,
BigInteger issuerSerialNumber,
bool isCertificateAuthority,
KeyPurposeID[] usages)
{
var certificateGenerator = new X509V3CertificateGenerator();
certificateGenerator.SetSerialNumber(subjectSerialNumber);
var issuerDN = new X509Name(issuerName);
certificateGenerator.SetIssuerDN(issuerDN);
// Note: The subject can be omitted if you specify a subject alternative name (SAN).
var subjectDN = new X509Name(subjectName);
certificateGenerator.SetSubjectDN(subjectDN);
// Our certificate needs valid from/to values.
var notBefore = DateTime.UtcNow.Date;
var notAfter = notBefore.AddYears(2);
certificateGenerator.SetNotBefore(notBefore);
certificateGenerator.SetNotAfter(notAfter);
// The subject's public key goes in the certificate.
certificateGenerator.SetPublicKey(subjectKeyPair.Public);
AddAuthorityKeyIdentifier(certificateGenerator, issuerDN, issuerKeyPair, issuerSerialNumber);
AddSubjectKeyIdentifier(certificateGenerator, subjectKeyPair);
//AddBasicConstraints(certificateGenerator, isCertificateAuthority);
if (usages != null && usages.Any())
AddExtendedKeyUsage(certificateGenerator, usages);
if (subjectAlternativeNames != null && subjectAlternativeNames.Any())
AddSubjectAlternativeNames(certificateGenerator, subjectAlternativeNames);
// Set the signature algorithm. This is used to generate the thumbprint which is then signed
// with the issuer's private key. We'll use SHA-256, which is (currently) considered fairly strong.
const string signatureAlgorithm = "SHA256WithRSA";
// The certificate is signed with the issuer's private key.
ISignatureFactory signatureFactory = new Asn1SignatureFactory(signatureAlgorithm, issuerKeyPair.Private, random);
var certificate = certificateGenerator.Generate(signatureFactory);
return certificate;
}
/// <summary>
/// The certificate needs a serial number. This is used for revocation,
/// and usually should be an incrementing index (which makes it easier to revoke a range of certificates).
/// Since we don't have anywhere to store the incrementing index, we can just use a random number.
/// </summary>
/// <param name="random"></param>
/// <returns></returns>
private BigInteger GenerateSerialNumber(SecureRandom random)
{
var serialNumber =
BigIntegers.CreateRandomInRange(
BigInteger.One, BigInteger.ValueOf(Int64.MaxValue), random);
return serialNumber;
}
/// <summary>
/// Generate a key pair.
/// </summary>
/// <param name="random">The random number generator.</param>
/// <param name="strength">The key length in bits. For RSA, 2048 bits should be considered the minimum acceptable these days.</param>
/// <returns></returns>
private AsymmetricCipherKeyPair GenerateKeyPair(SecureRandom random, int strength)
{
var keyGenerationParameters = new KeyGenerationParameters(random, strength);
var keyPairGenerator = new RsaKeyPairGenerator();
keyPairGenerator.Init(keyGenerationParameters);
var subjectKeyPair = keyPairGenerator.GenerateKeyPair();
return subjectKeyPair;
}
/// <summary>
/// Add the Authority Key Identifier. According to http://www.alvestrand.no/objectid/2.5.29.35.html, this
/// identifies the public key to be used to verify the signature on this certificate.
/// In a certificate chain, this corresponds to the "Subject Key Identifier" on the *issuer* certificate.
/// The Bouncy Castle documentation, at http://www.bouncycastle.org/wiki/display/JA1/X.509+Public+Key+Certificate+and+Certification+Request+Generation,
/// shows how to create this from the issuing certificate. Since we're creating a self-signed certificate, we have to do this slightly differently.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="issuerDN"></param>
/// <param name="issuerKeyPair"></param>
/// <param name="issuerSerialNumber"></param>
private void AddAuthorityKeyIdentifier(X509V3CertificateGenerator certificateGenerator,
X509Name issuerDN,
AsymmetricCipherKeyPair issuerKeyPair,
BigInteger issuerSerialNumber)
{
var authorityKeyIdentifierExtension =
new AuthorityKeyIdentifier(
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(issuerKeyPair.Public),
new GeneralNames(new GeneralName(issuerDN)),
issuerSerialNumber);
certificateGenerator.AddExtension(
X509Extensions.AuthorityKeyIdentifier.Id, false, authorityKeyIdentifierExtension);
}
/// <summary>
/// Add the "Subject Alternative Names" extension. Note that you have to repeat
/// the value from the "Subject Name" property.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="subjectAlternativeNames"></param>
private void AddSubjectAlternativeNames(X509V3CertificateGenerator certificateGenerator,
IEnumerable<string> subjectAlternativeNames)
{
var subjectAlternativeNamesExtension =
new DerSequence(
subjectAlternativeNames.Select(name => new GeneralName(GeneralName.DnsName, name))
.ToArray<Asn1Encodable>());
certificateGenerator.AddExtension(
X509Extensions.SubjectAlternativeName.Id, false, subjectAlternativeNamesExtension);
}
/// <summary>
/// Add the "Extended Key Usage" extension, specifying (for example) "server authentication".
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="usages"></param>
private void AddExtendedKeyUsage(X509V3CertificateGenerator certificateGenerator, KeyPurposeID[] usages)
{
certificateGenerator.AddExtension(
X509Extensions.ExtendedKeyUsage.Id, false, new ExtendedKeyUsage(usages));
}
/// <summary>
/// Add the "Basic Constraints" extension.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="isCertificateAuthority"></param>
private void AddBasicConstraints(X509V3CertificateGenerator certificateGenerator,
bool isCertificateAuthority)
{
certificateGenerator.AddExtension(
X509Extensions.BasicConstraints.Id, true, new BasicConstraints(isCertificateAuthority));
}
/// <summary>
/// Add the Subject Key Identifier.
/// </summary>
/// <param name="certificateGenerator"></param>
/// <param name="subjectKeyPair"></param>
private void AddSubjectKeyIdentifier(X509V3CertificateGenerator certificateGenerator,
AsymmetricCipherKeyPair subjectKeyPair)
{
var subjectKeyIdentifierExtension =
new SubjectKeyIdentifier(
SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(subjectKeyPair.Public));
certificateGenerator.AddExtension(
X509Extensions.SubjectKeyIdentifier.Id, false, subjectKeyIdentifierExtension);
}
private X509Certificate2 ConvertCertificate(X509Certificate certificate,
AsymmetricCipherKeyPair subjectKeyPair,
SecureRandom random)
{
// 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 Pkcs12StoreBuilder().Build();
// What Bouncy Castle calls "alias" is the same as what Windows terms the "friendly name".
string friendlyName = certificate.SubjectDN.ToString();
// Add the certificate.
var certificateEntry = new X509CertificateEntry(certificate);
store.SetCertificateEntry(friendlyName, certificateEntry);
// Add the private key.
store.SetKeyEntry(friendlyName, new AsymmetricKeyEntry(subjectKeyPair.Private), new[] { certificateEntry });
// Convert it to an X509Certificate2 object by saving/loading it from a MemoryStream.
// It needs a password. Since we'll remove this later, it doesn't particularly matter what we use.
var stream = new MemoryStream();
store.Save(stream, CertificatePassword.ToCharArray(), random);
var convertedCertificate =
new X509Certificate2(stream.ToArray(),
CertificatePassword,
X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
return convertedCertificate;
}
public void WriteCertificate(X509Certificate2 certificate, string outputDirectory, string certName)
{
// This password is the one attached to the PFX file. Use 'null' for no password.
// Create PFX (PKCS #12) with private key
try
{
var pfx = certificate.Export(X509ContentType.Pfx, CertificatePassword);
File.WriteAllBytes(string.Format("{0}.pfx", Path.Combine(outputDirectory, certName)), pfx);
}
catch (Exception ex)
{
CrestronConsole.PrintLine(string.Format("Failed to write x509 cert pfx\r\n{0}", ex.Message));
}
// Create Base 64 encoded CER (public key only)
using (var writer = new StreamWriter($"{Path.Combine(outputDirectory, certName)}.cer", false))
{
try
{
var contents = string.Format("-----BEGIN CERTIFICATE-----\r\n{0}\r\n-----END CERTIFICATE-----", Convert.ToBase64String(certificate.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
writer.Write(contents);
}
catch (Exception ex)
{
CrestronConsole.PrintLine(string.Format("Failed to write x509 cert cer\r\n{0}", ex.Message));
}
}
}
public bool AddCertToStore(X509Certificate2 cert, System.Security.Cryptography.X509Certificates.StoreName st, System.Security.Cryptography.X509Certificates.StoreLocation sl)
{
bool bRet = false;
try
{
var store = new System.Security.Cryptography.X509Certificates.X509Store(st, sl);
store.Open(System.Security.Cryptography.X509Certificates.OpenFlags.ReadWrite);
store.Add(cert);
store.Close();
bRet = true;
}
catch (Exception ex)
{
CrestronConsole.PrintLine(string.Format("AddCertToStore Failed\r\n{0}\r\n{1}", ex.Message, ex.StackTrace));
}
return bRet;
}
}
}

View file

@ -1,17 +1,17 @@
using Crestron.SimplSharp.WebScripting; using Crestron.SimplSharp.WebScripting;
namespace PepperDash.Core.Web.RequestHandlers namespace PepperDash.Core.Web.RequestHandlers
{ {
/// <summary> /// <summary>
/// Web API default request handler /// Web API default request handler
/// </summary> /// </summary>
public class DefaultRequestHandler : WebApiBaseRequestHandler public class DefaultRequestHandler : WebApiBaseRequestHandler
{ {
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
public DefaultRequestHandler() public DefaultRequestHandler()
: base(true) : base(true)
{ } { }
} }
} }

View file

@ -0,0 +1,163 @@
using Crestron.SimplSharp.WebScripting;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace PepperDash.Core.Web.RequestHandlers
{
public abstract class WebApiBaseRequestAsyncHandler:IHttpCwsHandler
{
private readonly Dictionary<string, Func<HttpCwsContext, Task>> _handlers;
protected readonly bool EnableCors;
/// <summary>
/// Constructor
/// </summary>
protected WebApiBaseRequestAsyncHandler(bool enableCors)
{
EnableCors = enableCors;
_handlers = new Dictionary<string, Func<HttpCwsContext, Task>>
{
{"CONNECT", HandleConnect},
{"DELETE", HandleDelete},
{"GET", HandleGet},
{"HEAD", HandleHead},
{"OPTIONS", HandleOptions},
{"PATCH", HandlePatch},
{"POST", HandlePost},
{"PUT", HandlePut},
{"TRACE", HandleTrace}
};
}
/// <summary>
/// Constructor
/// </summary>
protected WebApiBaseRequestAsyncHandler()
: this(false)
{
}
/// <summary>
/// Handles CONNECT method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleConnect(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles DELETE method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleDelete(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles GET method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleGet(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles HEAD method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleHead(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles OPTIONS method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleOptions(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles PATCH method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandlePatch(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles POST method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandlePost(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles PUT method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandlePut(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Handles TRACE method requests
/// </summary>
/// <param name="context"></param>
protected virtual async Task HandleTrace(HttpCwsContext context)
{
context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented";
context.Response.End();
}
/// <summary>
/// Process request
/// </summary>
/// <param name="context"></param>
public void ProcessRequest(HttpCwsContext context)
{
if (!_handlers.TryGetValue(context.Request.HttpMethod, out Func<HttpCwsContext, Task> handler))
{
return;
}
if (EnableCors)
{
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
}
var handlerTask = handler(context);
handlerTask.GetAwaiter().GetResult();
}
}
}

View file

@ -1,165 +1,165 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Crestron.SimplSharp.WebScripting; using Crestron.SimplSharp.WebScripting;
namespace PepperDash.Core.Web.RequestHandlers namespace PepperDash.Core.Web.RequestHandlers
{ {
/// <summary> /// <summary>
/// CWS Base Handler, implements IHttpCwsHandler /// CWS Base Handler, implements IHttpCwsHandler
/// </summary> /// </summary>
public abstract class WebApiBaseRequestHandler : IHttpCwsHandler public abstract class WebApiBaseRequestHandler : IHttpCwsHandler
{ {
private readonly Dictionary<string, Action<HttpCwsContext>> _handlers; private readonly Dictionary<string, Action<HttpCwsContext>> _handlers;
protected readonly bool EnableCors; protected readonly bool EnableCors;
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
protected WebApiBaseRequestHandler(bool enableCors) protected WebApiBaseRequestHandler(bool enableCors)
{ {
EnableCors = enableCors; EnableCors = enableCors;
_handlers = new Dictionary<string, Action<HttpCwsContext>> _handlers = new Dictionary<string, Action<HttpCwsContext>>
{ {
{"CONNECT", HandleConnect}, {"CONNECT", HandleConnect},
{"DELETE", HandleDelete}, {"DELETE", HandleDelete},
{"GET", HandleGet}, {"GET", HandleGet},
{"HEAD", HandleHead}, {"HEAD", HandleHead},
{"OPTIONS", HandleOptions}, {"OPTIONS", HandleOptions},
{"PATCH", HandlePatch}, {"PATCH", HandlePatch},
{"POST", HandlePost}, {"POST", HandlePost},
{"PUT", HandlePut}, {"PUT", HandlePut},
{"TRACE", HandleTrace} {"TRACE", HandleTrace}
}; };
} }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
protected WebApiBaseRequestHandler() protected WebApiBaseRequestHandler()
: this(false) : this(false)
{ {
} }
/// <summary> /// <summary>
/// Handles CONNECT method requests /// Handles CONNECT method requests
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
protected virtual void HandleConnect(HttpCwsContext context) protected virtual void HandleConnect(HttpCwsContext context)
{ {
context.Response.StatusCode = 501; context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented"; context.Response.StatusDescription = "Not Implemented";
context.Response.End(); context.Response.End();
} }
/// <summary> /// <summary>
/// Handles DELETE method requests /// Handles DELETE method requests
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
protected virtual void HandleDelete(HttpCwsContext context) protected virtual void HandleDelete(HttpCwsContext context)
{ {
context.Response.StatusCode = 501; context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented"; context.Response.StatusDescription = "Not Implemented";
context.Response.End(); context.Response.End();
} }
/// <summary> /// <summary>
/// Handles GET method requests /// Handles GET method requests
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
protected virtual void HandleGet(HttpCwsContext context) protected virtual void HandleGet(HttpCwsContext context)
{ {
context.Response.StatusCode = 501; context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented"; context.Response.StatusDescription = "Not Implemented";
context.Response.End(); context.Response.End();
} }
/// <summary> /// <summary>
/// Handles HEAD method requests /// Handles HEAD method requests
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
protected virtual void HandleHead(HttpCwsContext context) protected virtual void HandleHead(HttpCwsContext context)
{ {
context.Response.StatusCode = 501; context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented"; context.Response.StatusDescription = "Not Implemented";
context.Response.End(); context.Response.End();
} }
/// <summary> /// <summary>
/// Handles OPTIONS method requests /// Handles OPTIONS method requests
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
protected virtual void HandleOptions(HttpCwsContext context) protected virtual void HandleOptions(HttpCwsContext context)
{ {
context.Response.StatusCode = 501; context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented"; context.Response.StatusDescription = "Not Implemented";
context.Response.End(); context.Response.End();
} }
/// <summary> /// <summary>
/// Handles PATCH method requests /// Handles PATCH method requests
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
protected virtual void HandlePatch(HttpCwsContext context) protected virtual void HandlePatch(HttpCwsContext context)
{ {
context.Response.StatusCode = 501; context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented"; context.Response.StatusDescription = "Not Implemented";
context.Response.End(); context.Response.End();
} }
/// <summary> /// <summary>
/// Handles POST method requests /// Handles POST method requests
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
protected virtual void HandlePost(HttpCwsContext context) protected virtual void HandlePost(HttpCwsContext context)
{ {
context.Response.StatusCode = 501; context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented"; context.Response.StatusDescription = "Not Implemented";
context.Response.End(); context.Response.End();
} }
/// <summary> /// <summary>
/// Handles PUT method requests /// Handles PUT method requests
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
protected virtual void HandlePut(HttpCwsContext context) protected virtual void HandlePut(HttpCwsContext context)
{ {
context.Response.StatusCode = 501; context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented"; context.Response.StatusDescription = "Not Implemented";
context.Response.End(); context.Response.End();
} }
/// <summary> /// <summary>
/// Handles TRACE method requests /// Handles TRACE method requests
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
protected virtual void HandleTrace(HttpCwsContext context) protected virtual void HandleTrace(HttpCwsContext context)
{ {
context.Response.StatusCode = 501; context.Response.StatusCode = 501;
context.Response.StatusDescription = "Not Implemented"; context.Response.StatusDescription = "Not Implemented";
context.Response.End(); context.Response.End();
} }
/// <summary> /// <summary>
/// Process request /// Process request
/// </summary> /// </summary>
/// <param name="context"></param> /// <param name="context"></param>
public void ProcessRequest(HttpCwsContext context) public void ProcessRequest(HttpCwsContext context)
{ {
Action<HttpCwsContext> handler; Action<HttpCwsContext> handler;
if (!_handlers.TryGetValue(context.Request.HttpMethod, out handler)) if (!_handlers.TryGetValue(context.Request.HttpMethod, out handler))
{ {
return; return;
} }
if (EnableCors) if (EnableCors)
{ {
context.Response.Headers.Add("Access-Control-Allow-Origin", "*"); context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS"); context.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
} }
handler(context); handler(context);
} }
} }
} }

View file

@ -1,284 +1,284 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Crestron.SimplSharp; using Crestron.SimplSharp;
using Crestron.SimplSharp.WebScripting; using Crestron.SimplSharp.WebScripting;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using PepperDash.Core.Web.RequestHandlers; using PepperDash.Core.Web.RequestHandlers;
namespace PepperDash.Core.Web namespace PepperDash.Core.Web
{ {
/// <summary> /// <summary>
/// Web API server /// Web API server
/// </summary> /// </summary>
public class WebApiServer : IKeyName public class WebApiServer : IKeyName
{ {
private const string SplusKey = "Uninitialized Web API Server"; private const string SplusKey = "Uninitialized Web API Server";
private const string DefaultName = "Web API Server"; private const string DefaultName = "Web API Server";
private const string DefaultBasePath = "/api"; private const string DefaultBasePath = "/api";
private const uint DebugTrace = 0; private const uint DebugTrace = 0;
private const uint DebugInfo = 1; private const uint DebugInfo = 1;
private const uint DebugVerbose = 2; private const uint DebugVerbose = 2;
private readonly CCriticalSection _serverLock = new CCriticalSection(); private readonly CCriticalSection _serverLock = new CCriticalSection();
private HttpCwsServer _server; private HttpCwsServer _server;
/// <summary> /// <summary>
/// Web API server key /// Web API server key
/// </summary> /// </summary>
public string Key { get; private set; } public string Key { get; private set; }
/// <summary> /// <summary>
/// Web API server name /// Web API server name
/// </summary> /// </summary>
public string Name { get; private set; } public string Name { get; private set; }
/// <summary> /// <summary>
/// CWS base path, will default to "/api" if not set via initialize method /// CWS base path, will default to "/api" if not set via initialize method
/// </summary> /// </summary>
public string BasePath { get; private set; } public string BasePath { get; private set; }
/// <summary> /// <summary>
/// Indicates CWS is registered with base path /// Indicates CWS is registered with base path
/// </summary> /// </summary>
public bool IsRegistered { get; private set; } public bool IsRegistered { get; private set; }
/// <summary> /// <summary>
/// Http request handler /// Http request handler
/// </summary> /// </summary>
//public IHttpCwsHandler HttpRequestHandler //public IHttpCwsHandler HttpRequestHandler
//{ //{
// get { return _server.HttpRequestHandler; } // get { return _server.HttpRequestHandler; }
// set // set
// { // {
// if (_server == null) return; // if (_server == null) return;
// _server.HttpRequestHandler = value; // _server.HttpRequestHandler = value;
// } // }
//} //}
/// <summary> /// <summary>
/// Received request event handler /// Received request event handler
/// </summary> /// </summary>
//public event EventHandler<HttpCwsRequestEventArgs> ReceivedRequestEvent //public event EventHandler<HttpCwsRequestEventArgs> ReceivedRequestEvent
//{ //{
// add { _server.ReceivedRequestEvent += new HttpCwsRequestEventHandler(value); } // add { _server.ReceivedRequestEvent += new HttpCwsRequestEventHandler(value); }
// remove { _server.ReceivedRequestEvent -= new HttpCwsRequestEventHandler(value); } // remove { _server.ReceivedRequestEvent -= new HttpCwsRequestEventHandler(value); }
//} //}
/// <summary> /// <summary>
/// Constructor for S+. Make sure to set necessary properties using init method /// Constructor for S+. Make sure to set necessary properties using init method
/// </summary> /// </summary>
public WebApiServer() public WebApiServer()
: this(SplusKey, DefaultName, null) : this(SplusKey, DefaultName, null)
{ {
} }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
/// <param name="key"></param> /// <param name="key"></param>
/// <param name="basePath"></param> /// <param name="basePath"></param>
public WebApiServer(string key, string basePath) public WebApiServer(string key, string basePath)
: this(key, DefaultName, basePath) : this(key, DefaultName, basePath)
{ {
} }
/// <summary> /// <summary>
/// Constructor /// Constructor
/// </summary> /// </summary>
/// <param name="key"></param> /// <param name="key"></param>
/// <param name="name"></param> /// <param name="name"></param>
/// <param name="basePath"></param> /// <param name="basePath"></param>
public WebApiServer(string key, string name, string basePath) public WebApiServer(string key, string name, string basePath)
{ {
Key = key; Key = key;
Name = string.IsNullOrEmpty(name) ? DefaultName : name; Name = string.IsNullOrEmpty(name) ? DefaultName : name;
BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath;
if (_server == null) _server = new HttpCwsServer(BasePath); if (_server == null) _server = new HttpCwsServer(BasePath);
_server.setProcessName(Key); _server.setProcessName(Key);
_server.HttpRequestHandler = new DefaultRequestHandler(); _server.HttpRequestHandler = new DefaultRequestHandler();
CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler; CrestronEnvironment.ProgramStatusEventHandler += CrestronEnvironment_ProgramStatusEventHandler;
CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler; CrestronEnvironment.EthernetEventHandler += CrestronEnvironment_EthernetEventHandler;
} }
/// <summary> /// <summary>
/// Program status event handler /// Program status event handler
/// </summary> /// </summary>
/// <param name="programEventType"></param> /// <param name="programEventType"></param>
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{ {
if (programEventType != eProgramStatusEventType.Stopping) return; if (programEventType != eProgramStatusEventType.Stopping) return;
Debug.Console(DebugInfo, this, "Program stopping. stopping server"); Debug.Console(DebugInfo, this, "Program stopping. stopping server");
Stop(); Stop();
} }
/// <summary> /// <summary>
/// Ethernet event handler /// Ethernet event handler
/// </summary> /// </summary>
/// <param name="ethernetEventArgs"></param> /// <param name="ethernetEventArgs"></param>
void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs) void CrestronEnvironment_EthernetEventHandler(EthernetEventArgs ethernetEventArgs)
{ {
// Re-enable the server if the link comes back up and the status should be connected // 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. Server is alreedy registered."); Debug.Console(DebugInfo, this, "Ethernet link up. Server is alreedy registered.");
return; return;
} }
Debug.Console(DebugInfo, this, "Ethernet link up. Starting server"); Debug.Console(DebugInfo, this, "Ethernet link up. Starting server");
Start(); Start();
} }
/// <summary> /// <summary>
/// Initializes CWS class /// Initializes CWS class
/// </summary> /// </summary>
public void Initialize(string key, string basePath) public void Initialize(string key, string basePath)
{ {
Key = key; Key = key;
BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath; BasePath = string.IsNullOrEmpty(basePath) ? DefaultBasePath : basePath;
} }
/// <summary> /// <summary>
/// Adds a route to CWS /// Adds a route to CWS
/// </summary> /// </summary>
public void AddRoute(HttpCwsRoute route) public void AddRoute(HttpCwsRoute route)
{ {
if (route == null) if (route == null)
{ {
Debug.Console(DebugInfo, this, "Failed to add route, route parameter is null"); Debug.Console(DebugInfo, this, "Failed to add route, route parameter is null");
return; return;
} }
_server.Routes.Add(route); _server.Routes.Add(route);
} }
/// <summary> /// <summary>
/// Removes a route from CWS /// Removes a route from CWS
/// </summary> /// </summary>
/// <param name="route"></param> /// <param name="route"></param>
public void RemoveRoute(HttpCwsRoute route) public void RemoveRoute(HttpCwsRoute route)
{ {
if (route == null) if (route == null)
{ {
Debug.Console(DebugInfo, this, "Failed to remote route, orute parameter is null"); Debug.Console(DebugInfo, this, "Failed to remote route, orute parameter is null");
return; return;
} }
_server.Routes.Remove(route); _server.Routes.Remove(route);
} }
/// <summary> /// <summary>
/// Returns a list of the current routes /// Returns a list of the current routes
/// </summary> /// </summary>
public HttpCwsRouteCollection GetRouteCollection() public HttpCwsRouteCollection GetRouteCollection()
{ {
return _server.Routes; return _server.Routes;
} }
/// <summary> /// <summary>
/// Starts CWS instance /// Starts CWS instance
/// </summary> /// </summary>
public void Start() public void Start()
{ {
try try
{ {
_serverLock.Enter(); _serverLock.Enter();
if (_server == null) if (_server == null)
{ {
Debug.Console(DebugInfo, this, "Server is null, unable to start"); Debug.Console(DebugInfo, this, "Server is null, unable to start");
return; return;
} }
if (IsRegistered) if (IsRegistered)
{ {
Debug.Console(DebugInfo, this, "Server has already been started"); Debug.Console(DebugInfo, this, "Server has already been started");
return; return;
} }
IsRegistered = _server.Register(); IsRegistered = _server.Register();
Debug.Console(DebugInfo, this, "Starting server, registration {0}", IsRegistered ? "was successful" : "failed"); Debug.Console(DebugInfo, this, "Starting server, registration {0}", IsRegistered ? "was successful" : "failed");
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.Console(DebugInfo, this, "Start Exception Message: {0}", ex.Message); Debug.Console(DebugInfo, this, "Start Exception Message: {0}", ex.Message);
Debug.Console(DebugVerbose, this, "Start Exception StackTrace: {0}", ex.StackTrace); Debug.Console(DebugVerbose, this, "Start Exception StackTrace: {0}", ex.StackTrace);
if (ex.InnerException != null) if (ex.InnerException != null)
Debug.Console(DebugVerbose, this, "Start Exception InnerException: {0}", ex.InnerException); Debug.Console(DebugVerbose, this, "Start Exception InnerException: {0}", ex.InnerException);
} }
finally finally
{ {
_serverLock.Leave(); _serverLock.Leave();
} }
} }
/// <summary> /// <summary>
/// Stop CWS instance /// Stop CWS instance
/// </summary> /// </summary>
public void Stop() public void Stop()
{ {
try try
{ {
_serverLock.Enter(); _serverLock.Enter();
if (_server == null) if (_server == null)
{ {
Debug.Console(DebugInfo, this, "Server is null or has already been stopped"); Debug.Console(DebugInfo, this, "Server is null or has already been stopped");
return; return;
} }
IsRegistered = _server.Unregister() == false; IsRegistered = _server.Unregister() == false;
Debug.Console(DebugInfo, this, "Stopping server, unregistration {0}", IsRegistered ? "failed" : "was successful"); Debug.Console(DebugInfo, this, "Stopping server, unregistration {0}", IsRegistered ? "failed" : "was successful");
_server.Dispose(); _server.Dispose();
_server = null; _server = null;
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.Console(DebugInfo, this, "Server Stop Exception Message: {0}", ex.Message); Debug.Console(DebugInfo, this, "Server Stop Exception Message: {0}", ex.Message);
Debug.Console(DebugVerbose, this, "Server Stop Exception StackTrace: {0}", ex.StackTrace); Debug.Console(DebugVerbose, this, "Server Stop Exception StackTrace: {0}", ex.StackTrace);
if (ex.InnerException != null) if (ex.InnerException != null)
Debug.Console(DebugVerbose, this, "Server Stop Exception InnerException: {0}", ex.InnerException); Debug.Console(DebugVerbose, this, "Server Stop Exception InnerException: {0}", ex.InnerException);
} }
finally finally
{ {
_serverLock.Leave(); _serverLock.Leave();
} }
} }
/// <summary> /// <summary>
/// Received request handler /// Received request handler
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// This is here for development and testing /// This is here for development and testing
/// </remarks> /// </remarks>
/// <param name="sender"></param> /// <param name="sender"></param>
/// <param name="args"></param> /// <param name="args"></param>
public void ReceivedRequestEventHandler(object sender, HttpCwsRequestEventArgs args) public void ReceivedRequestEventHandler(object sender, HttpCwsRequestEventArgs args)
{ {
try try
{ {
var j = JsonConvert.SerializeObject(args.Context, Formatting.Indented); var j = JsonConvert.SerializeObject(args.Context, Formatting.Indented);
Debug.Console(DebugVerbose, this, "RecieveRequestEventHandler Context:\x0d\x0a{0}", j); Debug.Console(DebugVerbose, this, "RecieveRequestEventHandler Context:\x0d\x0a{0}", j);
} }
catch (Exception ex) catch (Exception ex)
{ {
Debug.Console(DebugInfo, this, "ReceivedRequestEventHandler Exception Message: {0}", ex.Message); Debug.Console(DebugInfo, this, "ReceivedRequestEventHandler Exception Message: {0}", ex.Message);
Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception StackTrace: {0}", ex.StackTrace); Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception StackTrace: {0}", ex.StackTrace);
if (ex.InnerException != null) if (ex.InnerException != null)
Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException); Debug.Console(DebugVerbose, this, "ReceivedRequestEventHandler Exception InnerException: {0}", ex.InnerException);
} }
} }
} }
} }

View file

@ -1,11 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Newtonsoft.Json;
namespace PepperDash.Core.WebApi.Presets namespace PepperDash.Core.WebApi.Presets
{ {

View file

@ -1,14 +1,10 @@
using System; using System;
using System.Text;
using Crestron.SimplSharp; // For Basic SIMPL# Classes using Crestron.SimplSharp; // For Basic SIMPL# Classes
using Crestron.SimplSharp.CrestronIO; using Crestron.SimplSharp.CrestronIO;
using Crestron.SimplSharp.Net;
using Crestron.SimplSharp.Net.Http; using Crestron.SimplSharp.Net.Http;
using Crestron.SimplSharp.Net.Https; using Crestron.SimplSharp.Net.Https;
using Newtonsoft.Json; using Newtonsoft.Json;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
using PepperDash.Core;
using PepperDash.Core.JsonToSimpl; using PepperDash.Core.JsonToSimpl;

Some files were not shown because too many files have changed in this diff Show more