mirror of
https://github.com/PepperDash/PepperDashCore.git
synced 2026-07-02 10:38:14 +00:00
Merge pull request #183 from PepperDash/release-2
Step 1 to releasing PD Core v2
This commit is contained in:
commit
0454410857
106 changed files with 14031 additions and 12933 deletions
BIN
._Readme.md
BIN
._Readme.md
Binary file not shown.
45
.github/scripts/GenerateVersionNumber.ps1
vendored
45
.github/scripts/GenerateVersionNumber.ps1
vendored
|
|
@ -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
|
|
||||||
40
.github/scripts/UpdateAssemblyVersion.ps1
vendored
40
.github/scripts/UpdateAssemblyVersion.ps1
vendored
|
|
@ -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";
|
|
||||||
}
|
|
||||||
42
.github/scripts/ZipBuildOutput.ps1
vendored
42
.github/scripts/ZipBuildOutput.ps1
vendored
|
|
@ -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
|
|
||||||
21
.github/workflows/EssentialsPlugins-builds-4-series-caller.yml
vendored
Normal file
21
.github/workflows/EssentialsPlugins-builds-4-series-caller.yml
vendored
Normal 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 }}
|
||||||
154
.github/workflows/docker.yml
vendored
154
.github/workflows/docker.yml
vendored
|
|
@ -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
|
|
||||||
129
.github/workflows/main.yml
vendored
129
.github/workflows/main.yml
vendored
|
|
@ -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
|
|
||||||
410
.gitignore
vendored
410
.gitignore
vendored
|
|
@ -1,25 +1,399 @@
|
||||||
#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
|
||||||
|
|
|
||||||
36
.releaserc.json
Normal file
36
.releaserc.json
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
25
PepperDash.Core.4Series.sln
Normal file
25
PepperDash.Core.4Series.sln
Normal 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
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
Binary file not shown.
|
|
@ -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()
|
|
||||||
// {
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -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>
|
|
||||||
|
|
@ -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")]
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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";
|
|
||||||
}
|
|
||||||
BIN
output/PepperDashCore.2.0.0-local.clz
Normal file
BIN
output/PepperDashCore.2.0.0-local.clz
Normal file
Binary file not shown.
|
|
@ -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,21 +62,25 @@ 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>
|
||||||
|
|
@ -80,7 +88,6 @@ namespace PepperDash.Core
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ControlPropertiesConfig()
|
public ControlPropertiesConfig()
|
||||||
{
|
{
|
||||||
EndOfLineString = CrestronEnvironment.NewLine;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -15,8 +15,6 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.CrestronSockets;
|
using Crestron.SimplSharp.CrestronSockets;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace PepperDash.Core
|
namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
|
|
@ -1,16 +1,18 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.CrestronSockets;
|
using Crestron.SimplSharp.CrestronSockets;
|
||||||
using Crestron.SimplSharp.Ssh;
|
using Org.BouncyCastle.Utilities;
|
||||||
using Crestron.SimplSharp.Ssh.Common;
|
using PepperDash.Core.Logging;
|
||||||
|
using Renci.SshNet;
|
||||||
|
using Renci.SshNet.Common;
|
||||||
|
|
||||||
namespace PepperDash.Core
|
namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
|
public class GenericSshClient : Device, ISocketStatusWithStreamDebugging, IAutoReconnect
|
||||||
{
|
{
|
||||||
private const string SPlusKey = "Uninitialized SshClient";
|
private const string SPlusKey = "Uninitialized SshClient";
|
||||||
|
|
@ -133,7 +135,8 @@ namespace PepperDash.Core
|
||||||
CTimer ReconnectTimer;
|
CTimer ReconnectTimer;
|
||||||
|
|
||||||
//Lock object to prevent simulatneous connect/disconnect operations
|
//Lock object to prevent simulatneous connect/disconnect operations
|
||||||
private CCriticalSection connectLock = new CCriticalSection();
|
//private CCriticalSection connectLock = new CCriticalSection();
|
||||||
|
private SemaphoreSlim connectLock = new SemaphoreSlim(1);
|
||||||
|
|
||||||
private bool DisconnectLogged = false;
|
private bool DisconnectLogged = false;
|
||||||
|
|
||||||
|
|
@ -158,7 +161,7 @@ namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
Connect();
|
Connect();
|
||||||
}
|
}
|
||||||
}, Timeout.Infinite);
|
}, System.Threading.Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -176,7 +179,7 @@ namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
Connect();
|
Connect();
|
||||||
}
|
}
|
||||||
}, Timeout.Infinite);
|
}, System.Threading.Timeout.Infinite);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -196,7 +199,7 @@ namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
if (Client != null)
|
if (Client != null)
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, "Program stopping. Closing connection");
|
this.LogDebug("Program stopping. Closing connection");
|
||||||
Disconnect();
|
Disconnect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -211,7 +214,7 @@ namespace PepperDash.Core
|
||||||
if (string.IsNullOrEmpty(Hostname) || Port < 1 || Port > 65535
|
if (string.IsNullOrEmpty(Hostname) || Port < 1 || Port > 65535
|
||||||
|| Username == null || Password == null)
|
|| Username == null || Password == null)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, Debug.ErrorLogLevel.Error, "Connect failed. Check hostname, port, username and password are set or not null");
|
this.LogError("Connect failed. Check hostname, port, username and password are set or not null");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -219,14 +222,14 @@ namespace PepperDash.Core
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
connectLock.Enter();
|
connectLock.Wait();
|
||||||
if (IsConnected)
|
if (IsConnected)
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, "Connection already connected. Exiting Connect()");
|
this.LogDebug("Connection already connected. Exiting Connect");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, "Attempting connect");
|
this.LogDebug("Attempting connect");
|
||||||
|
|
||||||
// Cancel reconnect if running.
|
// Cancel reconnect if running.
|
||||||
if (ReconnectTimer != null)
|
if (ReconnectTimer != null)
|
||||||
|
|
@ -237,7 +240,7 @@ namespace PepperDash.Core
|
||||||
// Cleanup the old client if it already exists
|
// Cleanup the old client if it already exists
|
||||||
if (Client != null)
|
if (Client != null)
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, "Cleaning up disconnected client");
|
this.LogDebug("Cleaning up disconnected client");
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY);
|
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,7 +249,7 @@ namespace PepperDash.Core
|
||||||
kauth.AuthenticationPrompt += new EventHandler<AuthenticationPromptEventArgs>(kauth_AuthenticationPrompt);
|
kauth.AuthenticationPrompt += new EventHandler<AuthenticationPromptEventArgs>(kauth_AuthenticationPrompt);
|
||||||
PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(Username, Password);
|
PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(Username, Password);
|
||||||
|
|
||||||
Debug.Console(1, this, "Creating new SshClient");
|
this.LogDebug("Creating new SshClient");
|
||||||
ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth);
|
ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth);
|
||||||
Client = new SshClient(connectionInfo);
|
Client = new SshClient(connectionInfo);
|
||||||
Client.ErrorOccurred += Client_ErrorOccurred;
|
Client.ErrorOccurred += Client_ErrorOccurred;
|
||||||
|
|
@ -263,7 +266,7 @@ namespace PepperDash.Core
|
||||||
string str = TheStream.Read();
|
string str = TheStream.Read();
|
||||||
}
|
}
|
||||||
TheStream.DataReceived += Stream_DataReceived;
|
TheStream.DataReceived += Stream_DataReceived;
|
||||||
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Connected");
|
this.LogInformation("Connected");
|
||||||
ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED;
|
ClientStatus = SocketStatus.SOCKET_STATUS_CONNECTED;
|
||||||
DisconnectLogged = false;
|
DisconnectLogged = false;
|
||||||
}
|
}
|
||||||
|
|
@ -273,35 +276,52 @@ namespace PepperDash.Core
|
||||||
var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error;
|
var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error;
|
||||||
|
|
||||||
if (ie is SocketException)
|
if (ie is SocketException)
|
||||||
Debug.Console(1, this, errorLogLevel, "'{0}' CONNECTION failure: Cannot reach host, ({1})", Key, ie.Message);
|
|
||||||
else if (ie is System.Net.Sockets.SocketException)
|
|
||||||
Debug.Console(1, this, errorLogLevel, "'{0}' Connection failure: Cannot reach host '{1}' on port {2}, ({3})",
|
|
||||||
Key, Hostname, Port, ie.GetType());
|
|
||||||
else if (ie is SshAuthenticationException)
|
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, errorLogLevel, "Authentication failure for username '{0}', ({1})",
|
this.LogException(ie, "CONNECTION failure: Cannot reach host, ({1})", Key, ie.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ie is System.Net.Sockets.SocketException socketException)
|
||||||
|
{
|
||||||
|
this.LogException(ie, "'{0}' Connection failure: Cannot reach host '{1}' on port {2}, ({3})",
|
||||||
|
Key, Hostname, Port, ie.GetType());
|
||||||
|
}
|
||||||
|
if (ie is SshAuthenticationException)
|
||||||
|
{
|
||||||
|
this.LogException(ie, "Authentication failure for username '{0}', ({1})", this,
|
||||||
Username, ie.Message);
|
Username, ie.Message);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
Debug.Console(1, this, errorLogLevel, "Error on connect:\r({0})", ie.Message);
|
this.LogException(ie, "Error on connect");
|
||||||
|
|
||||||
DisconnectLogged = true;
|
DisconnectLogged = true;
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
if (AutoReconnect)
|
if (AutoReconnect)
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, "Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
|
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(SshOperationTimeoutException ex)
|
||||||
|
{
|
||||||
|
this.LogWarning("Connection attempt timed out: {message}", ex.Message);
|
||||||
|
|
||||||
|
DisconnectLogged = true;
|
||||||
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
|
if (AutoReconnect)
|
||||||
|
{
|
||||||
|
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error;
|
var errorLogLevel = DisconnectLogged == true ? Debug.ErrorLogLevel.None : Debug.ErrorLogLevel.Error;
|
||||||
Debug.Console(1, this, errorLogLevel, "Unhandled exception on connect:\r({0})", e.Message);
|
this.LogException(e, "Unhandled exception on connect");
|
||||||
DisconnectLogged = true;
|
DisconnectLogged = true;
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
if (AutoReconnect)
|
if (AutoReconnect)
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, "Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -309,7 +329,7 @@ namespace PepperDash.Core
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
connectLock.Leave();
|
connectLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -345,43 +365,15 @@ namespace PepperDash.Core
|
||||||
Client.Dispose();
|
Client.Dispose();
|
||||||
Client = null;
|
Client = null;
|
||||||
ClientStatus = status;
|
ClientStatus = status;
|
||||||
Debug.Console(1, this, "Disconnected");
|
this.LogDebug("Disconnected");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception in Kill Client:{0}", ex);
|
this.LogException(ex,"Exception in Kill Client");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Anything to do with reestablishing connection on failures
|
|
||||||
/// </summary>
|
|
||||||
void HandleConnectionFailure()
|
|
||||||
{
|
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
|
||||||
|
|
||||||
Debug.Console(1, this, "Client nulled due to connection failure. AutoReconnect: {0}, ConnectEnabled: {1}", AutoReconnect, ConnectEnabled);
|
|
||||||
if (AutoReconnect && ConnectEnabled)
|
|
||||||
{
|
|
||||||
Debug.Console(1, this, "Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
|
||||||
if (ReconnectTimer == null)
|
|
||||||
{
|
|
||||||
ReconnectTimer = new CTimer(o =>
|
|
||||||
{
|
|
||||||
Connect();
|
|
||||||
}, AutoReconnectIntervalMs);
|
|
||||||
Debug.Console(1, this, "Attempting connection in {0} seconds",
|
|
||||||
(float) (AutoReconnectIntervalMs/1000));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.Console(1, this, "{0} second reconnect cycle running",
|
|
||||||
(float) (AutoReconnectIntervalMs/1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Kills the stream
|
/// Kills the stream
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -395,12 +387,12 @@ namespace PepperDash.Core
|
||||||
TheStream.Close();
|
TheStream.Close();
|
||||||
TheStream.Dispose();
|
TheStream.Dispose();
|
||||||
TheStream = null;
|
TheStream = null;
|
||||||
Debug.Console(1, this, "Disconnected stream");
|
this.LogDebug("Disconnected stream");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception in Kill Stream:{0}", ex);
|
this.LogException(ex, "Exception in Kill Stream:{0}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -417,7 +409,7 @@ namespace PepperDash.Core
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handler for data receive on ShellStream. Passes data across to queue for line parsing.
|
/// Handler for data receive on ShellStream. Passes data across to queue for line parsing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Stream_DataReceived(object sender, Crestron.SimplSharp.Ssh.Common.ShellDataEventArgs e)
|
void Stream_DataReceived(object sender, ShellDataEventArgs e)
|
||||||
{
|
{
|
||||||
if (((ShellStream)sender).Length <= 0L)
|
if (((ShellStream)sender).Length <= 0L)
|
||||||
{
|
{
|
||||||
|
|
@ -432,7 +424,7 @@ namespace PepperDash.Core
|
||||||
var bytes = Encoding.UTF8.GetBytes(response);
|
var bytes = Encoding.UTF8.GetBytes(response);
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, "Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
|
this.LogInformation("Received {1} bytes: '{0}'", ComTextHelper.GetEscapedText(bytes), bytes.Length);
|
||||||
}
|
}
|
||||||
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
|
||||||
}
|
}
|
||||||
|
|
@ -441,7 +433,7 @@ namespace PepperDash.Core
|
||||||
if (textHandler != null)
|
if (textHandler != null)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
if (StreamDebugging.RxStreamDebuggingIsEnabled)
|
||||||
Debug.Console(0, this, "Received: '{0}'", ComTextHelper.GetDebugText(response));
|
this.LogInformation("Received: '{0}'", ComTextHelper.GetDebugText(response));
|
||||||
|
|
||||||
textHandler(this, new GenericCommMethodReceiveTextArgs(response));
|
textHandler(this, new GenericCommMethodReceiveTextArgs(response));
|
||||||
}
|
}
|
||||||
|
|
@ -453,27 +445,26 @@ namespace PepperDash.Core
|
||||||
/// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange
|
/// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange
|
||||||
/// event
|
/// event
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void Client_ErrorOccurred(object sender, Crestron.SimplSharp.Ssh.Common.ExceptionEventArgs e)
|
void Client_ErrorOccurred(object sender, ExceptionEventArgs e)
|
||||||
{
|
{
|
||||||
CrestronInvoke.BeginInvoke(o =>
|
CrestronInvoke.BeginInvoke(o =>
|
||||||
{
|
{
|
||||||
if (e.Exception is SshConnectionException || e.Exception is System.Net.Sockets.SocketException)
|
if (e.Exception is SshConnectionException || e.Exception is System.Net.Sockets.SocketException)
|
||||||
Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Disconnected by remote");
|
this.LogError("Disconnected by remote");
|
||||||
else
|
else
|
||||||
Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Unhandled SSH client error: {0}", e.Exception);
|
this.LogException(e.Exception, "Unhandled SSH client error");
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
connectLock.Enter();
|
connectLock.Wait();
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_REMOTELY);
|
KillClient(SocketStatus.SOCKET_STATUS_BROKEN_REMOTELY);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
connectLock.Leave();
|
connectLock.Release();
|
||||||
}
|
}
|
||||||
if (AutoReconnect && ConnectEnabled)
|
if (AutoReconnect && ConnectEnabled)
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, "Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
this.LogDebug("Checking autoreconnect: {0}, {1}ms", AutoReconnect, AutoReconnectIntervalMs);
|
||||||
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
ReconnectTimer.Reset(AutoReconnectIntervalMs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -501,9 +492,8 @@ namespace PepperDash.Core
|
||||||
if (Client != null && TheStream != null && IsConnected)
|
if (Client != null && TheStream != null && IsConnected)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
||||||
Debug.Console(0,
|
this.LogInformation(
|
||||||
this,
|
"Sending {length} characters of text: '{text}'",
|
||||||
"Sending {0} characters of text: '{1}'",
|
|
||||||
text.Length,
|
text.Length,
|
||||||
ComTextHelper.GetDebugText(text));
|
ComTextHelper.GetDebugText(text));
|
||||||
|
|
||||||
|
|
@ -512,23 +502,19 @@ namespace PepperDash.Core
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, "Client is null or disconnected. Cannot Send Text");
|
this.LogDebug("Client is null or disconnected. Cannot Send Text");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException ex)
|
catch (ObjectDisposedException ex)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message);
|
this.LogException(ex, "ObjectDisposedException sending {message}", text);
|
||||||
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace);
|
|
||||||
|
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
ReconnectTimer.Reset();
|
ReconnectTimer.Reset();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message);
|
this.LogException(ex, "Exception sending text: {message}", text);
|
||||||
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace);
|
|
||||||
|
|
||||||
Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stream write failed");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -538,47 +524,43 @@ namespace PepperDash.Core
|
||||||
/// <param name="bytes"></param>
|
/// <param name="bytes"></param>
|
||||||
public void SendBytes(byte[] bytes)
|
public void SendBytes(byte[] bytes)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (Client != null && TheStream != null && IsConnected)
|
if (Client != null && TheStream != null && IsConnected)
|
||||||
{
|
{
|
||||||
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
if (StreamDebugging.TxStreamDebuggingIsEnabled)
|
||||||
Debug.Console(0, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
|
this.LogInformation("Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes));
|
||||||
|
|
||||||
TheStream.Write(bytes, 0, bytes.Length);
|
TheStream.Write(bytes, 0, bytes.Length);
|
||||||
TheStream.Flush();
|
TheStream.Flush();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Debug.Console(1, this, "Client is null or disconnected. Cannot Send Bytes");
|
this.LogDebug("Client is null or disconnected. Cannot Send Bytes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ObjectDisposedException ex)
|
catch (ObjectDisposedException ex)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message);
|
this.LogException(ex, "ObjectDisposedException sending {message}", ComTextHelper.GetEscapedText(bytes));
|
||||||
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace);
|
|
||||||
|
|
||||||
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
KillClient(SocketStatus.SOCKET_STATUS_CONNECT_FAILED);
|
||||||
ReconnectTimer.Reset();
|
ReconnectTimer.Reset();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.Console(0, this, Debug.ErrorLogLevel.Notice, "Exception: {0}", ex.Message);
|
this.LogException(ex, "Exception sending {message}", ComTextHelper.GetEscapedText(bytes));
|
||||||
Debug.Console(1, this, Debug.ErrorLogLevel.Notice, "Stack Trace: {0}", ex.StackTrace);
|
}
|
||||||
|
|
||||||
Debug.Console(1, this, Debug.ErrorLogLevel.Error, "Stream write failed");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#endregion
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//*****************************************************************************************************
|
//*****************************************************************************************************
|
||||||
//*****************************************************************************************************
|
//*****************************************************************************************************
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fired when connection changes
|
/// Fired when connection changes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SshConnectionChangeEventArgs : EventArgs
|
public class SshConnectionChangeEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connection State
|
/// Connection State
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
@ -15,8 +15,6 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.CrestronSockets;
|
using Crestron.SimplSharp.CrestronSockets;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace PepperDash.Core
|
namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
@ -5,8 +5,6 @@ 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.Linq;
|
|
||||||
|
|
||||||
namespace PepperDash.Core
|
namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
|
|
@ -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"]);
|
||||||
|
|
@ -121,7 +117,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
|
using Serilog;
|
||||||
|
|
||||||
namespace PepperDash.Core
|
namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
|
|
@ -15,16 +16,17 @@ namespace PepperDash.Core
|
||||||
/// Unique Key
|
/// Unique Key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
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>
|
||||||
string Name { get; }
|
string Name { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using Serilog.Events;
|
||||||
|
|
||||||
namespace PepperDash.Core
|
namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
|
|
@ -10,6 +10,7 @@ namespace PepperDash.Core
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Device : IKeyName
|
public class Device : IKeyName
|
||||||
{
|
{
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unique Key
|
/// Unique Key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -49,9 +50,8 @@ namespace PepperDash.Core
|
||||||
public Device(string key)
|
public Device(string key)
|
||||||
{
|
{
|
||||||
Key = key;
|
Key = key;
|
||||||
if (key.Contains('.')) Debug.Console(0, this, "WARNING: Device name's should not include '.'");
|
if (key.Contains(".")) Debug.LogMessage(LogEventLevel.Information, "WARNING: Device key should not include '.'", this);
|
||||||
Name = "";
|
Name = "";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
19
src/Directory.build.props
Normal file
19
src/Directory.build.props
Normal 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>
|
||||||
43
src/Directory.build.targets
Normal file
43
src/Directory.build.targets
Normal 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>
|
||||||
21
src/EssentialsPlugins-builds-4-series-caller.yml
Normal file
21
src/EssentialsPlugins-builds-4-series-caller.yml
Normal 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 }}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -1,10 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using PepperDash.Core.JsonToSimpl;
|
using PepperDash.Core.JsonToSimpl;
|
||||||
|
|
||||||
namespace PepperDash.Core.JsonStandardObjects
|
namespace PepperDash.Core.JsonStandardObjects
|
||||||
|
|
@ -1,9 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace PepperDash.Core.JsonToSimpl
|
namespace PepperDash.Core.JsonToSimpl
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
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 Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace PepperDash.Core.JsonToSimpl
|
namespace PepperDash.Core.JsonToSimpl
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
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;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace PepperDash.Core.JsonToSimpl
|
namespace PepperDash.Core.JsonToSimpl
|
||||||
|
|
@ -196,7 +194,7 @@ namespace PepperDash.Core.JsonToSimpl
|
||||||
/// Sets the debug level
|
/// Sets the debug level
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="level"></param>
|
/// <param name="level"></param>
|
||||||
public void setDebugLevel(int level)
|
public void setDebugLevel(uint level)
|
||||||
{
|
{
|
||||||
Debug.SetDebugLevel(level);
|
Debug.SetDebugLevel(level);
|
||||||
}
|
}
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
//using System.IO;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
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 +159,7 @@ 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)))
|
using (var reader = new JsonTextReader(new StringReader(json)))
|
||||||
{
|
{
|
||||||
var startDepth = reader.Depth;
|
var startDepth = reader.Depth;
|
||||||
var obj = JObject.Load(reader);
|
var obj = JObject.Load(reader);
|
||||||
|
|
@ -179,7 +176,7 @@ 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)))
|
using (var reader = new JsonTextReader(new StringReader(json)))
|
||||||
{
|
{
|
||||||
var startDepth = reader.Depth;
|
var startDepth = reader.Depth;
|
||||||
var obj = JArray.Load(reader);
|
var obj = JArray.Load(reader);
|
||||||
|
|
@ -1,13 +1,9 @@
|
||||||
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 Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
using PepperDash.Core.Config;
|
using PepperDash.Core.Config;
|
||||||
|
|
||||||
namespace PepperDash.Core.JsonToSimpl
|
namespace PepperDash.Core.JsonToSimpl
|
||||||
|
|
@ -132,7 +128,7 @@ namespace PepperDash.Core.JsonToSimpl
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="level"></param>
|
/// <param name="level"></param>
|
||||||
public void setDebugLevel(int level)
|
public void setDebugLevel(uint level)
|
||||||
{
|
{
|
||||||
Debug.SetDebugLevel(level);
|
Debug.SetDebugLevel(level);
|
||||||
}
|
}
|
||||||
37
src/Logging/CrestronEnricher.cs
Normal file
37
src/Logging/CrestronEnricher.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,13 +1,20 @@
|
||||||
using System;
|
using Crestron.SimplSharp;
|
||||||
using System.Collections.Generic;
|
using Crestron.SimplSharp.CrestronDataStore;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Crestron.SimplSharp.Reflection;
|
|
||||||
using Crestron.SimplSharp.CrestronLogger;
|
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
|
using Crestron.SimplSharp.CrestronLogger;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using PepperDash.Core.DebugThings;
|
using PepperDash.Core.Logging;
|
||||||
|
using Serilog;
|
||||||
|
using Serilog.Context;
|
||||||
|
using Serilog.Core;
|
||||||
|
using Serilog.Events;
|
||||||
|
using Serilog.Formatting.Compact;
|
||||||
|
using Serilog.Formatting.Json;
|
||||||
|
using Serilog.Templates;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
namespace PepperDash.Core
|
namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
|
|
@ -16,6 +23,43 @@ namespace PepperDash.Core
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class Debug
|
public static class Debug
|
||||||
{
|
{
|
||||||
|
private static readonly string LevelStoreKey = "ConsoleDebugLevel";
|
||||||
|
private static readonly string WebSocketLevelStoreKey = "WebsocketDebugLevel";
|
||||||
|
private static readonly string ErrorLogLevelStoreKey = "ErrorLogDebugLevel";
|
||||||
|
private static readonly string FileLevelStoreKey = "FileDebugLevel";
|
||||||
|
|
||||||
|
private static readonly Dictionary<uint, LogEventLevel> _logLevels = new Dictionary<uint, LogEventLevel>()
|
||||||
|
{
|
||||||
|
{0, LogEventLevel.Information },
|
||||||
|
{3, LogEventLevel.Warning },
|
||||||
|
{4, LogEventLevel.Error },
|
||||||
|
{5, LogEventLevel.Fatal },
|
||||||
|
{1, LogEventLevel.Debug },
|
||||||
|
{2, LogEventLevel.Verbose },
|
||||||
|
};
|
||||||
|
|
||||||
|
private static ILogger _logger;
|
||||||
|
|
||||||
|
private static readonly LoggingLevelSwitch _consoleLoggingLevelSwitch;
|
||||||
|
|
||||||
|
private static readonly LoggingLevelSwitch _websocketLoggingLevelSwitch;
|
||||||
|
|
||||||
|
private static readonly LoggingLevelSwitch _errorLogLevelSwitch;
|
||||||
|
|
||||||
|
private static readonly LoggingLevelSwitch _fileLevelSwitch;
|
||||||
|
|
||||||
|
public static LogEventLevel WebsocketMinimumLogLevel
|
||||||
|
{
|
||||||
|
get { return _websocketLoggingLevelSwitch.MinimumLevel; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly DebugWebsocketSink _websocketSink;
|
||||||
|
|
||||||
|
public static DebugWebsocketSink WebsocketSink
|
||||||
|
{
|
||||||
|
get { return _websocketSink; }
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Describes the folder location where a given program stores it's debug level memory. By default, the
|
/// Describes the folder location where a given program stores it's debug level memory. By default, the
|
||||||
/// file written will be named appNdebug where N is 1-10.
|
/// file written will be named appNdebug where N is 1-10.
|
||||||
|
|
@ -41,12 +85,14 @@ namespace PepperDash.Core
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When this is true, the configuration file will NOT be loaded until triggered by either a console command or a signal
|
/// When this is true, the configuration file will NOT be loaded until triggered by either a console command or a signal
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool DoNotLoadOnNextBoot { get; private set; }
|
public static bool DoNotLoadConfigOnNextBoot { get; private set; }
|
||||||
|
|
||||||
private static DebugContextCollection _contexts;
|
private static DebugContextCollection _contexts;
|
||||||
|
|
||||||
private const int SaveTimeoutMs = 30000;
|
private const int SaveTimeoutMs = 30000;
|
||||||
|
|
||||||
|
public static bool IsRunningOnAppliance = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version for the currently loaded PepperDashCore dll
|
/// Version for the currently loaded PepperDashCore dll
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -64,29 +110,93 @@ namespace PepperDash.Core
|
||||||
|
|
||||||
private static readonly Dictionary<string, object> IncludedExcludedKeys;
|
private static readonly Dictionary<string, object> IncludedExcludedKeys;
|
||||||
|
|
||||||
|
private static readonly LoggerConfiguration _defaultLoggerConfiguration;
|
||||||
|
|
||||||
|
private static LoggerConfiguration _loggerConfiguration;
|
||||||
|
|
||||||
|
public static LoggerConfiguration LoggerConfiguration => _loggerConfiguration;
|
||||||
|
|
||||||
static Debug()
|
static Debug()
|
||||||
{
|
{
|
||||||
|
CrestronDataStoreStatic.InitCrestronDataStore();
|
||||||
|
|
||||||
|
var defaultConsoleLevel = GetStoredLogEventLevel(LevelStoreKey);
|
||||||
|
|
||||||
|
var defaultWebsocketLevel = GetStoredLogEventLevel(WebSocketLevelStoreKey);
|
||||||
|
|
||||||
|
var defaultErrorLogLevel = GetStoredLogEventLevel(ErrorLogLevelStoreKey);
|
||||||
|
|
||||||
|
var defaultFileLogLevel = GetStoredLogEventLevel(FileLevelStoreKey);
|
||||||
|
|
||||||
|
_consoleLoggingLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultConsoleLevel);
|
||||||
|
|
||||||
|
_websocketLoggingLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultWebsocketLevel);
|
||||||
|
|
||||||
|
_errorLogLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultErrorLogLevel);
|
||||||
|
|
||||||
|
_fileLevelSwitch = new LoggingLevelSwitch(initialMinimumLevel: defaultFileLogLevel);
|
||||||
|
|
||||||
|
_websocketSink = new DebugWebsocketSink(new JsonFormatter(renderMessage: true));
|
||||||
|
|
||||||
|
var logFilePath = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ?
|
||||||
|
$@"{Directory.GetApplicationRootDirectory()}{Path.DirectorySeparatorChar}user{Path.DirectorySeparatorChar}debug{Path.DirectorySeparatorChar}app{InitialParametersClass.ApplicationNumber}{Path.DirectorySeparatorChar}global-log.log" :
|
||||||
|
$@"{Directory.GetApplicationRootDirectory()}{Path.DirectorySeparatorChar}user{Path.DirectorySeparatorChar}debug{Path.DirectorySeparatorChar}room{InitialParametersClass.RoomId}{Path.DirectorySeparatorChar}global-log.log";
|
||||||
|
|
||||||
|
CrestronConsole.PrintLine($"Saving log files to {logFilePath}");
|
||||||
|
|
||||||
|
var errorLogTemplate = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance
|
||||||
|
? "{@t:fff}ms [{@l:u4}]{#if Key is not null}[{Key}]{#end} {@m}{#if @x is not null}\r\n{@x}{#end}"
|
||||||
|
: "[{@t:yyyy-MM-dd HH:mm:ss.fff}][{@l:u4}][{App}]{#if Key is not null}[{Key}]{#end} {@m}{#if @x is not null}\r\n{@x}{#end}";
|
||||||
|
|
||||||
|
_defaultLoggerConfiguration = new LoggerConfiguration()
|
||||||
|
.MinimumLevel.Verbose()
|
||||||
|
.Enrich.FromLogContext()
|
||||||
|
.Enrich.With(new CrestronEnricher())
|
||||||
|
.WriteTo.Sink(new DebugConsoleSink(new ExpressionTemplate("[{@t:yyyy-MM-dd HH:mm:ss.fff}][{@l:u4}][{App}]{#if Key is not null}[{Key}]{#end} {@m}{#if @x is not null}\r\n{@x}{#end}")), levelSwitch: _consoleLoggingLevelSwitch)
|
||||||
|
.WriteTo.Sink(_websocketSink, levelSwitch: _websocketLoggingLevelSwitch)
|
||||||
|
.WriteTo.Sink(new DebugErrorLogSink(new ExpressionTemplate(errorLogTemplate)), levelSwitch: _errorLogLevelSwitch)
|
||||||
|
.WriteTo.File(new RenderedCompactJsonFormatter(), logFilePath,
|
||||||
|
rollingInterval: RollingInterval.Day,
|
||||||
|
restrictedToMinimumLevel: LogEventLevel.Debug,
|
||||||
|
retainedFileCountLimit: CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? 30 : 60,
|
||||||
|
levelSwitch: _fileLevelSwitch
|
||||||
|
);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (InitialParametersClass.NumberOfRemovableDrives > 0)
|
||||||
|
{
|
||||||
|
CrestronConsole.PrintLine("{0} RM Drive(s) Present. Initializing CrestronLogger", InitialParametersClass.NumberOfRemovableDrives);
|
||||||
|
_defaultLoggerConfiguration.WriteTo.Sink(new DebugCrestronLoggerSink());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
CrestronConsole.PrintLine("No RM Drive(s) Present. Not using Crestron Logger");
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
CrestronConsole.PrintLine("Initializing of CrestronLogger failed: {0}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Instantiate the root logger
|
||||||
|
_loggerConfiguration = _defaultLoggerConfiguration;
|
||||||
|
|
||||||
|
_logger = _loggerConfiguration.CreateLogger();
|
||||||
// Get the assembly version and print it to console and the log
|
// Get the assembly version and print it to console and the log
|
||||||
GetVersion();
|
GetVersion();
|
||||||
|
|
||||||
string msg = "";
|
string msg = $"[App {InitialParametersClass.ApplicationNumber}] Using PepperDash_Core v{PepperDashCoreVersion}";
|
||||||
|
|
||||||
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
|
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server)
|
||||||
{
|
{
|
||||||
msg = string.Format("[App {0}] Using PepperDash_Core v{1}", InitialParametersClass.ApplicationNumber, PepperDashCoreVersion);
|
msg = $"[Room {InitialParametersClass.RoomId}] Using PepperDash_Core v{PepperDashCoreVersion}";
|
||||||
}
|
|
||||||
else if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server)
|
|
||||||
{
|
|
||||||
msg = string.Format("[Room {0}] Using PepperDash_Core v{1}", InitialParametersClass.RoomId, PepperDashCoreVersion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CrestronConsole.PrintLine(msg);
|
CrestronConsole.PrintLine(msg);
|
||||||
|
|
||||||
LogError(ErrorLogLevel.Notice, msg);
|
LogMessage(LogEventLevel.Information,msg);
|
||||||
|
|
||||||
IncludedExcludedKeys = new Dictionary<string, object>();
|
IncludedExcludedKeys = new Dictionary<string, object>();
|
||||||
|
|
||||||
//CrestronDataStoreStatic.InitCrestronDataStore();
|
|
||||||
if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro)
|
if (CrestronEnvironment.RuntimeEnvironment == eRuntimeEnvironment.SimplSharpPro)
|
||||||
{
|
{
|
||||||
// Add command to console
|
// Add command to console
|
||||||
|
|
@ -94,7 +204,7 @@ namespace PepperDash.Core
|
||||||
"donotloadonnextboot:P [true/false]: Should the application load on next boot", ConsoleAccessLevelEnum.AccessOperator);
|
"donotloadonnextboot:P [true/false]: Should the application load on next boot", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
|
||||||
CrestronConsole.AddNewConsoleCommand(SetDebugFromConsole, "appdebug",
|
CrestronConsole.AddNewConsoleCommand(SetDebugFromConsole, "appdebug",
|
||||||
"appdebug:P [0-2]: Sets the application's console debug message level",
|
"appdebug:P [0-5]: Sets the application's console debug message level",
|
||||||
ConsoleAccessLevelEnum.AccessOperator);
|
ConsoleAccessLevelEnum.AccessOperator);
|
||||||
CrestronConsole.AddNewConsoleCommand(ShowDebugLog, "appdebuglog",
|
CrestronConsole.AddNewConsoleCommand(ShowDebugLog, "appdebuglog",
|
||||||
"appdebuglog:P [all] Use \"all\" for full log.",
|
"appdebuglog:P [all] Use \"all\" for full log.",
|
||||||
|
|
@ -112,25 +222,54 @@ namespace PepperDash.Core
|
||||||
|
|
||||||
var context = _contexts.GetOrCreateItem("DEFAULT");
|
var context = _contexts.GetOrCreateItem("DEFAULT");
|
||||||
Level = context.Level;
|
Level = context.Level;
|
||||||
DoNotLoadOnNextBoot = context.DoNotLoadOnNextBoot;
|
DoNotLoadConfigOnNextBoot = context.DoNotLoadOnNextBoot;
|
||||||
|
|
||||||
if(DoNotLoadOnNextBoot)
|
if(DoNotLoadConfigOnNextBoot)
|
||||||
CrestronConsole.PrintLine(string.Format("Program {0} will not load config after next boot. Use console command go:{0} to load the config manually", InitialParametersClass.ApplicationNumber));
|
CrestronConsole.PrintLine(string.Format("Program {0} will not load config after next boot. Use console command go:{0} to load the config manually", InitialParametersClass.ApplicationNumber));
|
||||||
|
|
||||||
|
_consoleLoggingLevelSwitch.MinimumLevelChanged += (sender, args) =>
|
||||||
|
{
|
||||||
|
Console(0, "Console debug level set to {0}", _consoleLoggingLevelSwitch.MinimumLevel);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateLoggerConfiguration(LoggerConfiguration config)
|
||||||
|
{
|
||||||
|
_loggerConfiguration = config;
|
||||||
|
|
||||||
|
_logger = config.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ResetLoggerConfiguration()
|
||||||
|
{
|
||||||
|
_loggerConfiguration = _defaultLoggerConfiguration;
|
||||||
|
|
||||||
|
_logger = _loggerConfiguration.CreateLogger();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LogEventLevel GetStoredLogEventLevel(string levelStoreKey)
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (InitialParametersClass.NumberOfRemovableDrives > 0)
|
var result = CrestronDataStoreStatic.GetLocalIntValue(levelStoreKey, out int logLevel);
|
||||||
{
|
|
||||||
CrestronConsole.PrintLine("{0} RM Drive(s) Present.", InitialParametersClass.NumberOfRemovableDrives);
|
|
||||||
CrestronLogger.Initialize(2, LoggerModeEnum.DEFAULT); // Use RM instead of DEFAULT as not to double-up console messages.
|
|
||||||
}
|
|
||||||
else
|
|
||||||
CrestronConsole.PrintLine("No RM Drive(s) Present.");
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
|
|
||||||
CrestronConsole.PrintLine("Initializing of CrestronLogger failed: {0}", e);
|
if (result != CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
|
||||||
|
{
|
||||||
|
CrestronConsole.Print($"Unable to retrieve stored log level for {levelStoreKey}.\r\nError: {result}.\r\nSetting level to {LogEventLevel.Information}\r\n");
|
||||||
|
return LogEventLevel.Information;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(logLevel < 0 || logLevel > 5)
|
||||||
|
{
|
||||||
|
CrestronConsole.PrintLine($"Stored Log level not valid for {levelStoreKey}: {logLevel}. Setting level to {LogEventLevel.Information}");
|
||||||
|
return LogEventLevel.Information;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (LogEventLevel)logLevel;
|
||||||
|
} catch (Exception ex)
|
||||||
|
{
|
||||||
|
CrestronConsole.PrintLine($"Exception retrieving log level for {levelStoreKey}: {ex.Message}");
|
||||||
|
return LogEventLevel.Information;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -143,9 +282,7 @@ namespace PepperDash.Core
|
||||||
|
|
||||||
if (ver != null && ver.Length > 0)
|
if (ver != null && ver.Length > 0)
|
||||||
{
|
{
|
||||||
var verAttribute = ver[0] as AssemblyInformationalVersionAttribute;
|
if (ver[0] is AssemblyInformationalVersionAttribute verAttribute)
|
||||||
|
|
||||||
if (verAttribute != null)
|
|
||||||
{
|
{
|
||||||
PepperDashCoreVersion = verAttribute.InformationalVersion;
|
PepperDashCoreVersion = verAttribute.InformationalVersion;
|
||||||
}
|
}
|
||||||
|
|
@ -153,8 +290,7 @@ namespace PepperDash.Core
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var version = assembly.GetName().Version;
|
var version = assembly.GetName().Version;
|
||||||
PepperDashCoreVersion = string.Format("{0}.{1}.{2}.{3}", version.Major, version.Minor, version.Build,
|
PepperDashCoreVersion = version.ToString();
|
||||||
version.Revision);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,8 +300,11 @@ namespace PepperDash.Core
|
||||||
/// <param name="programEventType"></param>
|
/// <param name="programEventType"></param>
|
||||||
static void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
|
static void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (programEventType == eProgramStatusEventType.Stopping)
|
if (programEventType == eProgramStatusEventType.Stopping)
|
||||||
{
|
{
|
||||||
|
Log.CloseAndFlush();
|
||||||
|
|
||||||
if (_saveTimer != null)
|
if (_saveTimer != null)
|
||||||
{
|
{
|
||||||
_saveTimer.Stop();
|
_saveTimer.Stop();
|
||||||
|
|
@ -184,20 +323,121 @@ namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(levelString.Trim()))
|
if (levelString.Trim() == "?")
|
||||||
{
|
{
|
||||||
CrestronConsole.PrintLine("AppDebug level = {0}", Level);
|
CrestronConsole.ConsoleCommandResponse(
|
||||||
|
$@"Used to set the minimum level of debug messages to be printed to the console:
|
||||||
|
{_logLevels[0]} = 0
|
||||||
|
{_logLevels[1]} = 1
|
||||||
|
{_logLevels[2]} = 2
|
||||||
|
{_logLevels[3]} = 3
|
||||||
|
{_logLevels[4]} = 4
|
||||||
|
{_logLevels[5]} = 5");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetDebugLevel(Convert.ToInt32(levelString));
|
if (string.IsNullOrEmpty(levelString.Trim()))
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("AppDebug level = {0}", _consoleLoggingLevelSwitch.MinimumLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(int.TryParse(levelString, out var levelInt))
|
||||||
|
{
|
||||||
|
if(levelInt < 0 || levelInt > 5)
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse($"Error: Unable to parse {levelString} to valid log level. If using a number, value must be between 0-5");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SetDebugLevel((uint) levelInt);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Enum.TryParse<LogEventLevel>(levelString, out var levelEnum))
|
||||||
|
{
|
||||||
|
SetDebugLevel(levelEnum);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CrestronConsole.ConsoleCommandResponse($"Error: Unable to parse {levelString} to valid log level");
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
CrestronConsole.PrintLine("Usage: appdebug:P [0-2]");
|
CrestronConsole.ConsoleCommandResponse("Usage: appdebug:P [0-5]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the debug level
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level"> Valid values 0-5</param>
|
||||||
|
public static void SetDebugLevel(uint level)
|
||||||
|
{
|
||||||
|
if(!_logLevels.TryGetValue(level, out var logLevel))
|
||||||
|
{
|
||||||
|
logLevel = LogEventLevel.Information;
|
||||||
|
|
||||||
|
CrestronConsole.ConsoleCommandResponse($"{level} not valid. Setting level to {logLevel}");
|
||||||
|
|
||||||
|
SetDebugLevel(logLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetDebugLevel(logLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetDebugLevel(LogEventLevel level)
|
||||||
|
{
|
||||||
|
_consoleLoggingLevelSwitch.MinimumLevel = level;
|
||||||
|
|
||||||
|
CrestronConsole.ConsoleCommandResponse("[Application {0}], Debug level set to {1}\r\n",
|
||||||
|
InitialParametersClass.ApplicationNumber, _consoleLoggingLevelSwitch.MinimumLevel);
|
||||||
|
|
||||||
|
CrestronConsole.ConsoleCommandResponse($"Storing level {level}:{(int) level}");
|
||||||
|
|
||||||
|
var err = CrestronDataStoreStatic.SetLocalIntValue(LevelStoreKey, (int) level);
|
||||||
|
|
||||||
|
CrestronConsole.ConsoleCommandResponse($"Store result: {err}:{(int)level}");
|
||||||
|
|
||||||
|
if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
|
||||||
|
CrestronConsole.PrintLine($"Error saving console debug level setting: {err}");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetWebSocketMinimumDebugLevel(LogEventLevel level)
|
||||||
|
{
|
||||||
|
_websocketLoggingLevelSwitch.MinimumLevel = level;
|
||||||
|
|
||||||
|
var err = CrestronDataStoreStatic.SetLocalUintValue(WebSocketLevelStoreKey, (uint) level);
|
||||||
|
|
||||||
|
if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
|
||||||
|
LogMessage(LogEventLevel.Information, "Error saving websocket debug level setting: {erro}", err);
|
||||||
|
|
||||||
|
LogMessage(LogEventLevel.Information, "Websocket debug level set to {0}", _websocketLoggingLevelSwitch.MinimumLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetErrorLogMinimumDebugLevel(LogEventLevel level)
|
||||||
|
{
|
||||||
|
_errorLogLevelSwitch.MinimumLevel = level;
|
||||||
|
|
||||||
|
var err = CrestronDataStoreStatic.SetLocalUintValue(ErrorLogLevelStoreKey, (uint)level);
|
||||||
|
|
||||||
|
if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
|
||||||
|
LogMessage(LogEventLevel.Information, "Error saving Error Log debug level setting: {error}", err);
|
||||||
|
|
||||||
|
LogMessage(LogEventLevel.Information, "Error log debug level set to {0}", _websocketLoggingLevelSwitch.MinimumLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetFileMinimumDebugLevel(LogEventLevel level)
|
||||||
|
{
|
||||||
|
_errorLogLevelSwitch.MinimumLevel = level;
|
||||||
|
|
||||||
|
var err = CrestronDataStoreStatic.SetLocalUintValue(ErrorLogLevelStoreKey, (uint)level);
|
||||||
|
|
||||||
|
if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
|
||||||
|
LogMessage(LogEventLevel.Information, "Error saving File debug level setting: {error}", err);
|
||||||
|
|
||||||
|
LogMessage(LogEventLevel.Information, "File debug level set to {0}", _websocketLoggingLevelSwitch.MinimumLevel);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Callback for console command
|
/// Callback for console command
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -208,15 +448,15 @@ namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(stateString.Trim()))
|
if (string.IsNullOrEmpty(stateString.Trim()))
|
||||||
{
|
{
|
||||||
CrestronConsole.PrintLine("DoNotLoadOnNextBoot = {0}", DoNotLoadOnNextBoot);
|
CrestronConsole.ConsoleCommandResponse("DoNotLoadOnNextBoot = {0}", DoNotLoadConfigOnNextBoot);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetDoNotLoadOnNextBoot(Boolean.Parse(stateString));
|
SetDoNotLoadConfigOnNextBoot(bool.Parse(stateString));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
CrestronConsole.PrintLine("Usage: donotloadonnextboot:P [true/false]");
|
CrestronConsole.ConsoleCommandResponse("Usage: donotloadonnextboot:P [true/false]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -232,7 +472,7 @@ namespace PepperDash.Core
|
||||||
CrestronConsole.ConsoleCommandResponse("Usage:\r APPDEBUGFILTER key1 key2 key3....\r " +
|
CrestronConsole.ConsoleCommandResponse("Usage:\r APPDEBUGFILTER key1 key2 key3....\r " +
|
||||||
"+all: at beginning puts filter into 'default include' mode\r" +
|
"+all: at beginning puts filter into 'default include' mode\r" +
|
||||||
" All keys that follow will be excluded from output.\r" +
|
" All keys that follow will be excluded from output.\r" +
|
||||||
"-all: at beginning puts filter into 'default excluse all' mode.\r" +
|
"-all: at beginning puts filter into 'default exclude all' mode.\r" +
|
||||||
" All keys that follow will be the only keys that are shown\r" +
|
" All keys that follow will be the only keys that are shown\r" +
|
||||||
"+nokey: Enables messages with no key (default)\r" +
|
"+nokey: Enables messages with no key (default)\r" +
|
||||||
"-nokey: Disables messages with no key.\r" +
|
"-nokey: Disables messages with no key.\r" +
|
||||||
|
|
@ -300,26 +540,7 @@ namespace PepperDash.Core
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the debug level
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="level"> Valid values 0 (no debug), 1 (critical), 2 (all messages)</param>
|
|
||||||
public static void SetDebugLevel(int level)
|
|
||||||
{
|
|
||||||
if (level <= 2)
|
|
||||||
{
|
|
||||||
Level = level;
|
|
||||||
_contexts.GetOrCreateItem("DEFAULT").Level = level;
|
|
||||||
SaveMemoryOnTimeout();
|
|
||||||
|
|
||||||
CrestronConsole.PrintLine("[Application {0}], Debug level set to {1}",
|
|
||||||
InitialParametersClass.ApplicationNumber, Level);
|
|
||||||
|
|
||||||
//var err = CrestronDataStoreStatic.SetLocalUintValue("DebugLevel", level);
|
|
||||||
//if (err != CrestronDataStore.CDS_ERROR.CDS_SUCCESS)
|
|
||||||
// CrestronConsole.PrintLine("Error saving console debug level setting: {0}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// sets the settings for a device or creates a new entry
|
/// sets the settings for a device or creates a new entry
|
||||||
|
|
@ -347,14 +568,14 @@ namespace PepperDash.Core
|
||||||
/// Sets the flag to prevent application starting on next boot
|
/// Sets the flag to prevent application starting on next boot
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="state"></param>
|
/// <param name="state"></param>
|
||||||
public static void SetDoNotLoadOnNextBoot(bool state)
|
public static void SetDoNotLoadConfigOnNextBoot(bool state)
|
||||||
{
|
{
|
||||||
DoNotLoadOnNextBoot = state;
|
DoNotLoadConfigOnNextBoot = state;
|
||||||
_contexts.GetOrCreateItem("DEFAULT").DoNotLoadOnNextBoot = state;
|
_contexts.GetOrCreateItem("DEFAULT").DoNotLoadOnNextBoot = state;
|
||||||
SaveMemoryOnTimeout();
|
SaveMemoryOnTimeout();
|
||||||
|
|
||||||
CrestronConsole.PrintLine("[Application {0}], Do Not Start on Next Boot set to {1}",
|
CrestronConsole.ConsoleCommandResponse("[Application {0}], Do Not Load Config on Next Boot set to {1}",
|
||||||
InitialParametersClass.ApplicationNumber, DoNotLoadOnNextBoot);
|
InitialParametersClass.ApplicationNumber, DoNotLoadConfigOnNextBoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -367,6 +588,66 @@ namespace PepperDash.Core
|
||||||
CrestronConsole.ConsoleCommandResponse(l + CrestronEnvironment.NewLine);
|
CrestronConsole.ConsoleCommandResponse(l + CrestronEnvironment.NewLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log an Exception using Serilog's default Exception logging mechanism
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ex">Exception to log</param>
|
||||||
|
/// <param name="message">Message template</param>
|
||||||
|
/// <param name="device">Optional IKeyed device. If provided, the Key of the device will be added to the log message</param>
|
||||||
|
/// <param name="args">Args to put into message template</param>
|
||||||
|
public static void LogMessage(Exception ex, string message, IKeyed device = null, params object[] args)
|
||||||
|
{
|
||||||
|
using (LogContext.PushProperty("Key", device?.Key))
|
||||||
|
{
|
||||||
|
_logger.Error(ex, message, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Log a message
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="level">Level to log at</param>
|
||||||
|
/// <param name="message">Message template</param>
|
||||||
|
/// <param name="device">Optional IKeyed device. If provided, the Key of the device will be added to the log message</param>
|
||||||
|
/// <param name="args">Args to put into message template</param>
|
||||||
|
public static void LogMessage(LogEventLevel level, string message, IKeyed device=null, params object[] args)
|
||||||
|
{
|
||||||
|
using (LogContext.PushProperty("Key", device?.Key))
|
||||||
|
{
|
||||||
|
_logger.Write(level, message, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogMessage(LogEventLevel level, string message, params object[] args)
|
||||||
|
{
|
||||||
|
LogMessage(level, message, null, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogMessage(LogEventLevel level, IKeyed keyed, string message, params object[] args)
|
||||||
|
{
|
||||||
|
LogMessage(level, message, keyed, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static void LogMessage(uint level, string format, params object[] items)
|
||||||
|
{
|
||||||
|
if (!_logLevels.ContainsKey(level)) return;
|
||||||
|
|
||||||
|
var logLevel = _logLevels[level];
|
||||||
|
|
||||||
|
LogMessage(logLevel, format, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void LogMessage(uint level, IKeyed keyed, string format, params object[] items)
|
||||||
|
{
|
||||||
|
if (!_logLevels.ContainsKey(level)) return;
|
||||||
|
|
||||||
|
var logLevel = _logLevels[level];
|
||||||
|
|
||||||
|
LogMessage(logLevel, keyed, format, items);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prints message to console if current debug level is equal to or higher than the level of this message.
|
/// Prints message to console if current debug level is equal to or higher than the level of this message.
|
||||||
/// Uses CrestronConsole.PrintLine.
|
/// Uses CrestronConsole.PrintLine.
|
||||||
|
|
@ -374,67 +655,52 @@ namespace PepperDash.Core
|
||||||
/// <param name="level"></param>
|
/// <param name="level"></param>
|
||||||
/// <param name="format">Console format string</param>
|
/// <param name="format">Console format string</param>
|
||||||
/// <param name="items">Object parameters</param>
|
/// <param name="items">Object parameters</param>
|
||||||
|
[Obsolete("Use LogMessage methods")]
|
||||||
public static void Console(uint level, string format, params object[] items)
|
public static void Console(uint level, string format, params object[] items)
|
||||||
{
|
{
|
||||||
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Server)
|
|
||||||
{
|
|
||||||
var logString = string.Format("[level {0}] {1}", level, string.Format(format, items));
|
|
||||||
|
|
||||||
LogError(ErrorLogLevel.Notice, logString);
|
LogMessage(level, format, items);
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Level < level)
|
//if (IsRunningOnAppliance)
|
||||||
{
|
//{
|
||||||
return;
|
// CrestronConsole.PrintLine("[{0}]App {1} Lvl {2}:{3}", DateTime.Now.ToString("HH:mm:ss.fff"),
|
||||||
}
|
// InitialParametersClass.ApplicationNumber,
|
||||||
|
// level,
|
||||||
CrestronConsole.PrintLine("[{0}]App {1}:{2}", DateTime.Now.ToString("HH:mm:ss.fff"), InitialParametersClass.ApplicationNumber,
|
// string.Format(format, items));
|
||||||
string.Format(format, items));
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logs to Console when at-level, and all messages to error log, including device key
|
/// Logs to Console when at-level, and all messages to error log, including device key
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Use LogMessage methods")]
|
||||||
public static void Console(uint level, IKeyed dev, string format, params object[] items)
|
public static void Console(uint level, IKeyed dev, string format, params object[] items)
|
||||||
{
|
{
|
||||||
if (Level >= level)
|
LogMessage(level, dev, format, items);
|
||||||
Console(level, "[{0}] {1}", dev.Key, string.Format(format, items));
|
|
||||||
|
//if (Level >= level)
|
||||||
|
// Console(level, "[{0}] {1}", dev.Key, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Prints message to console if current debug level is equal to or higher than the level of this message. Always sends message to Error Log.
|
/// Prints message to console if current debug level is equal to or higher than the level of this message. Always sends message to Error Log.
|
||||||
/// Uses CrestronConsole.PrintLine.
|
/// Uses CrestronConsole.PrintLine.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Use LogMessage methods")]
|
||||||
public static void Console(uint level, IKeyed dev, ErrorLogLevel errorLogLevel,
|
public static void Console(uint level, IKeyed dev, ErrorLogLevel errorLogLevel,
|
||||||
string format, params object[] items)
|
string format, params object[] items)
|
||||||
{
|
{
|
||||||
var str = string.Format("[{0}] {1}", dev.Key, string.Format(format, items));
|
LogMessage(level, dev, format, items);
|
||||||
if (errorLogLevel != ErrorLogLevel.None)
|
|
||||||
{
|
|
||||||
LogError(errorLogLevel, str);
|
|
||||||
}
|
|
||||||
if (Level >= level)
|
|
||||||
{
|
|
||||||
Console(level, str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logs to Console when at-level, and all messages to error log
|
/// Logs to Console when at-level, and all messages to error log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Use LogMessage methods")]
|
||||||
public static void Console(uint level, ErrorLogLevel errorLogLevel,
|
public static void Console(uint level, ErrorLogLevel errorLogLevel,
|
||||||
string format, params object[] items)
|
string format, params object[] items)
|
||||||
{
|
{
|
||||||
var str = string.Format(format, items);
|
LogMessage(level, format, items);
|
||||||
if (errorLogLevel != ErrorLogLevel.None)
|
|
||||||
{
|
|
||||||
LogError(errorLogLevel, str);
|
|
||||||
}
|
|
||||||
if (Level >= level)
|
|
||||||
{
|
|
||||||
Console(level, str);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -442,12 +708,15 @@ namespace PepperDash.Core
|
||||||
/// or above the level provided, then the output will be written to both console and the log. Otherwise
|
/// or above the level provided, then the output will be written to both console and the log. Otherwise
|
||||||
/// it will only be written to the log.
|
/// it will only be written to the log.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Use LogMessage methods")]
|
||||||
public static void ConsoleWithLog(uint level, string format, params object[] items)
|
public static void ConsoleWithLog(uint level, string format, params object[] items)
|
||||||
{
|
{
|
||||||
var str = string.Format(format, items);
|
LogMessage(level, format, items);
|
||||||
if (Level >= level)
|
|
||||||
CrestronConsole.PrintLine("App {0}:{1}", InitialParametersClass.ApplicationNumber, str);
|
// var str = string.Format(format, items);
|
||||||
CrestronLogger.WriteToLog(str, level);
|
//if (Level >= level)
|
||||||
|
// CrestronConsole.PrintLine("App {0}:{1}", InitialParametersClass.ApplicationNumber, str);
|
||||||
|
// CrestronLogger.WriteToLog(str, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -455,11 +724,13 @@ namespace PepperDash.Core
|
||||||
/// or above the level provided, then the output will be written to both console and the log. Otherwise
|
/// or above the level provided, then the output will be written to both console and the log. Otherwise
|
||||||
/// it will only be written to the log.
|
/// it will only be written to the log.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
[Obsolete("Use LogMessage methods")]
|
||||||
public static void ConsoleWithLog(uint level, IKeyed dev, string format, params object[] items)
|
public static void ConsoleWithLog(uint level, IKeyed dev, string format, params object[] items)
|
||||||
{
|
{
|
||||||
var str = string.Format(format, items);
|
LogMessage(level, dev, format, items);
|
||||||
if (Level >= level)
|
|
||||||
ConsoleWithLog(level, "[{0}] {1}", dev.Key, str);
|
// var str = string.Format(format, items);
|
||||||
|
// CrestronLogger.WriteToLog(string.Format("[{0}] {1}", dev.Key, str), level);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -467,20 +738,19 @@ namespace PepperDash.Core
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="errorLogLevel"></param>
|
/// <param name="errorLogLevel"></param>
|
||||||
/// <param name="str"></param>
|
/// <param name="str"></param>
|
||||||
|
[Obsolete("Use LogMessage methods")]
|
||||||
public static void LogError(ErrorLogLevel errorLogLevel, string str)
|
public static void LogError(ErrorLogLevel errorLogLevel, string str)
|
||||||
{
|
{
|
||||||
|
|
||||||
var msg = CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance ? string.Format("App {0}:{1}", InitialParametersClass.ApplicationNumber, str) : string.Format("Room {0}:{1}", InitialParametersClass.RoomId, str);
|
|
||||||
switch (errorLogLevel)
|
switch (errorLogLevel)
|
||||||
{
|
{
|
||||||
case ErrorLogLevel.Error:
|
case ErrorLogLevel.Error:
|
||||||
ErrorLog.Error(msg);
|
LogMessage(LogEventLevel.Error, str);
|
||||||
break;
|
break;
|
||||||
case ErrorLogLevel.Warning:
|
case ErrorLogLevel.Warning:
|
||||||
ErrorLog.Warn(msg);
|
LogMessage(LogEventLevel.Warning, str);
|
||||||
break;
|
break;
|
||||||
case ErrorLogLevel.Notice:
|
case ErrorLogLevel.Notice:
|
||||||
ErrorLog.Notice(msg);
|
LogMessage(LogEventLevel.Information, str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -553,7 +823,7 @@ namespace PepperDash.Core
|
||||||
{
|
{
|
||||||
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
|
if (CrestronEnvironment.DevicePlatform == eDevicePlatform.Appliance)
|
||||||
{
|
{
|
||||||
CheckForMigration();
|
// CheckForMigration();
|
||||||
return string.Format(@"\user\debugSettings\program{0}", InitialParametersClass.ApplicationNumber);
|
return string.Format(@"\user\debugSettings\program{0}", InitialParametersClass.ApplicationNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
55
src/Logging/DebugConsoleSink.cs
Normal file
55
src/Logging/DebugConsoleSink.cs
Normal 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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
29
src/Logging/DebugCrestronLoggerSink.cs
Normal file
29
src/Logging/DebugCrestronLoggerSink.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/Logging/DebugErrorLogSink.cs
Normal file
65
src/Logging/DebugErrorLogSink.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
44
src/Logging/DebugExtensions.cs
Normal file
44
src/Logging/DebugExtensions.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
271
src/Logging/DebugWebsocketSink.cs
Normal file
271
src/Logging/DebugWebsocketSink.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using PepperDash.Core.JsonToSimpl;
|
|
||||||
using PepperDash.Core.JsonStandardObjects;
|
|
||||||
|
|
||||||
namespace PepperDash.Core.PasswordManagement
|
namespace PepperDash.Core.PasswordManagement
|
||||||
{
|
{
|
||||||
51
src/PepperDash.Core.4Series.csproj
Normal file
51
src/PepperDash.Core.4Series.csproj
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
|
<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.20.66" />
|
||||||
|
<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>
|
||||||
|
<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>
|
||||||
356
src/Web/BouncyCertificate.cs
Normal file
356
src/Web/BouncyCertificate.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
163
src/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs
Normal file
163
src/Web/RequestHandlers/WebApiBaseRequestAsyncHandler.cs
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue