mirror of
https://github.com/PepperDash/Essentials.git
synced 2026-02-16 13:15:03 +00:00
Compare commits
9 Commits
feature-2.
...
3.0.0-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6e51ed643c | ||
|
|
135d65c515 | ||
|
|
493ef59497 | ||
|
|
488dda2c0c | ||
|
|
e314f58035 | ||
|
|
3fad74e595 | ||
|
|
a654560506 | ||
|
|
2138a29b31 | ||
|
|
d6f7a12eb9 |
140
.github/workflows/docker.yml
vendored
140
.github/workflows/docker.yml
vendored
@@ -1,140 +0,0 @@
|
|||||||
name: Branch Build Using Docker
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- feature-2.0.0/*
|
|
||||||
- hotfix-2.0.0/*
|
|
||||||
- release-2.0.0/*
|
|
||||||
- development-2.0.0
|
|
||||||
|
|
||||||
env:
|
|
||||||
# solution path doesn't need slashes unless there it is multiple folders deep
|
|
||||||
# solution name does not include extension. .sln is assumed
|
|
||||||
SOLUTION_PATH: .
|
|
||||||
SOLUTION_FILE: PepperDash.Essentials
|
|
||||||
# Do not edit this, we're just creating it here
|
|
||||||
VERSION: 0.0.0-buildtype-buildnumber
|
|
||||||
# Defaults to debug for build type
|
|
||||||
BUILD_TYPE: Debug
|
|
||||||
# Defaults to main as the release branch. Change as necessary
|
|
||||||
RELEASE_BRANCH: main
|
|
||||||
jobs:
|
|
||||||
Build_Project_4-Series:
|
|
||||||
runs-on: windows-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v3
|
|
||||||
- name: Set Version Number
|
|
||||||
id: setVersion
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
$latestVersion = [version]"2.0.0"
|
|
||||||
|
|
||||||
$newVersion = [version]$latestVersion
|
|
||||||
$phase = ""
|
|
||||||
$newVersionString = ""
|
|
||||||
|
|
||||||
switch -regex ($Env:GITHUB_REF) {
|
|
||||||
'^refs\/pull\/*.' {
|
|
||||||
$phase = 'beta';
|
|
||||||
$newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER
|
|
||||||
}
|
|
||||||
'^refs\/heads\/hotfix-2.0.0\/*.' {
|
|
||||||
$phase = 'hotfix'
|
|
||||||
$newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER
|
|
||||||
}
|
|
||||||
'^refs\/heads\/release-2.0.0\/*.' {
|
|
||||||
$splitRef = $Env:GITHUB_REF -split "/"
|
|
||||||
$version = [version]($splitRef[-1] -replace "v", "")
|
|
||||||
$phase = 'rc'
|
|
||||||
$newVersionString = "{0}-{1}-{2}" -f $version, $phase, $Env:GITHUB_RUN_NUMBER
|
|
||||||
}
|
|
||||||
'^refs\/heads\/feature-2.0.0\/*.' {
|
|
||||||
$phase = 'alpha'
|
|
||||||
$newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER
|
|
||||||
}
|
|
||||||
'development-2.0.0' {
|
|
||||||
$phase = 'beta'
|
|
||||||
$newVersionString = "{0}-{1}-{2}" -f $newVersion, $phase, $Env:GITHUB_RUN_NUMBER
|
|
||||||
}
|
|
||||||
}
|
|
||||||
echo "version=$newVersionString" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
|
|
||||||
- name: Setup MS Build
|
|
||||||
uses: microsoft/setup-msbuild@v1.1
|
|
||||||
- name: restore Nuget Packages
|
|
||||||
run: nuget restore .\$($Env:SOLUTION_FILE).sln
|
|
||||||
# Build the solutions in the docker image
|
|
||||||
- name: Build Solution
|
|
||||||
run: msbuild .\$($Env:SOLUTION_FILE).sln /p:Platform="Any CPU" /p:Configuration="Debug" /p:Version="${{ steps.setVersion.outputs.version }}" -m
|
|
||||||
- name: Debug CPZ Files
|
|
||||||
shell: powershell
|
|
||||||
run: |
|
|
||||||
Write-Host "Checking for CPZ files..."
|
|
||||||
|
|
||||||
# First, let's find out the actual directory structure
|
|
||||||
Write-Host "Current directory: $(Get-Location)"
|
|
||||||
Write-Host "Directory structure:"
|
|
||||||
Get-ChildItem -Path . -Directory -Recurse -Depth 2 | ForEach-Object { Write-Host $_.FullName }
|
|
||||||
|
|
||||||
# Look for all CPZ files in the repository
|
|
||||||
Write-Host "Searching for all CPZ files in the repository:"
|
|
||||||
$cpzFiles = Get-ChildItem -Path . -Recurse -Filter "*.cpz"
|
|
||||||
if ($cpzFiles.Count -eq 0) {
|
|
||||||
Write-Host "No CPZ files found in the repository."
|
|
||||||
} else {
|
|
||||||
Write-Host "Found $($cpzFiles.Count) CPZ files:"
|
|
||||||
foreach ($file in $cpzFiles) {
|
|
||||||
Write-Host " $($file.FullName)"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Create output directory if it doesn't exist
|
|
||||||
$outputDir = ".\output\build"
|
|
||||||
if (-not (Test-Path $outputDir)) {
|
|
||||||
New-Item -ItemType Directory -Path $outputDir -Force
|
|
||||||
Write-Host "Created output directory: $outputDir"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Copy all CPZ files to the output directory
|
|
||||||
foreach ($file in $cpzFiles) {
|
|
||||||
$destPath = Join-Path $outputDir $file.Name
|
|
||||||
Write-Host "Copying $($file.FullName) to $destPath"
|
|
||||||
Copy-Item -Path $file.FullName -Destination $destPath -Force
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- name: Pack Solution
|
|
||||||
run: |
|
|
||||||
dotnet pack .\$($Env:SOLUTION_FILE).sln --configuration $env:BUILD_TYPE --output ./output /p:Version="${{ steps.setVersion.outputs.version }}"
|
|
||||||
|
|
||||||
# Ensure CPZ files are included in the package
|
|
||||||
$cpzFiles = Get-ChildItem -Path . -Recurse | Where-Object { $_.Extension -eq ".cpz" }
|
|
||||||
if ($cpzFiles.Count -eq 0) {
|
|
||||||
Write-Host "WARNING: No CPZ files found!"
|
|
||||||
} else {
|
|
||||||
Write-Host "Found $($cpzFiles.Count) CPZ files"
|
|
||||||
foreach ($file in $cpzFiles) {
|
|
||||||
Write-Host "CPZ file: $($file.FullName)"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- name: Create tag for non-rc builds
|
|
||||||
if: contains(steps.setVersion.outputs.version, 'alpha')
|
|
||||||
run: |
|
|
||||||
git tag ${{ steps.setVersion.outputs.version }}
|
|
||||||
git push --tags origin
|
|
||||||
# Create the release on the source repo
|
|
||||||
- name: Create Release
|
|
||||||
id: create_release
|
|
||||||
uses: ncipollo/release-action@v1
|
|
||||||
with:
|
|
||||||
artifacts: 'output\**\*.*(cpz|cplz)'
|
|
||||||
generateReleaseNotes: true
|
|
||||||
prerelease: ${{contains('debug', env.BUILD_TYPE)}}
|
|
||||||
tag: ${{ steps.setVersion.outputs.version }}
|
|
||||||
- name: Setup Nuget
|
|
||||||
run: |
|
|
||||||
nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username pepperdash -password ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
nuget setApiKey ${{ secrets.GITHUB_TOKEN }} -Source github
|
|
||||||
nuget setApiKey ${{ secrets.NUGET_API_KEY }} -Source https://api.nuget.org/v3/index.json
|
|
||||||
- name: Publish to Nuget
|
|
||||||
run: nuget push .\output\*.nupkg -Source https://api.nuget.org/v3/index.json
|
|
||||||
- name: Publish to Github Nuget
|
|
||||||
run: nuget push .\output\*.nupkg -Source github
|
|
||||||
247
.github/workflows/essentials-3-dev-build.yml
vendored
Normal file
247
.github/workflows/essentials-3-dev-build.yml
vendored
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
name: Essentials v3 Development Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- feature-3.0.0/*
|
||||||
|
- hotfix-3.0.0/*
|
||||||
|
- release-3.0.0/*
|
||||||
|
- development-3.0.0
|
||||||
|
|
||||||
|
env:
|
||||||
|
SOLUTION_PATH: .
|
||||||
|
SOLUTION_FILE: PepperDash.Essentials
|
||||||
|
VERSION: 0.0.0-buildtype-buildnumber
|
||||||
|
BUILD_TYPE: Debug
|
||||||
|
RELEASE_BRANCH: main
|
||||||
|
jobs:
|
||||||
|
Build_Project_4-Series:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Detect environment (Act vs GitHub)
|
||||||
|
- name: Detect environment
|
||||||
|
id: detect_env
|
||||||
|
run: |
|
||||||
|
if [ -n "$ACT" ]; then
|
||||||
|
echo "is_local=true" >> $GITHUB_OUTPUT
|
||||||
|
else
|
||||||
|
echo "is_local=false" >> $GITHUB_OUTPUT
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Install prerequisites
|
||||||
|
run: |
|
||||||
|
if [ "${{ steps.detect_env.outputs.is_local }}" == "true" ]; then
|
||||||
|
# For Act - no sudo needed
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y curl wget libicu-dev git unzip
|
||||||
|
else
|
||||||
|
# For GitHub runners - sudo required
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y curl wget libicu-dev git unzip
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Set Version Number
|
||||||
|
id: setVersion
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
latestVersion="3.0.0"
|
||||||
|
newVersion=$latestVersion
|
||||||
|
phase=""
|
||||||
|
newVersionString=""
|
||||||
|
|
||||||
|
if [[ $GITHUB_REF =~ ^refs/pull/.* ]]; then
|
||||||
|
phase="beta"
|
||||||
|
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
|
||||||
|
elif [[ $GITHUB_REF =~ ^refs/heads/hotfix-3.0.0/.* ]]; then
|
||||||
|
phase="hotfix"
|
||||||
|
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
|
||||||
|
elif [[ $GITHUB_REF =~ ^refs/heads/feature-3.0.0/.* ]]; then
|
||||||
|
phase="alpha"
|
||||||
|
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
|
||||||
|
elif [[ $GITHUB_REF == "refs/heads/development-3.0.0" ]]; then
|
||||||
|
phase="beta"
|
||||||
|
newVersionString="${newVersion}-${phase}-${GITHUB_RUN_NUMBER}"
|
||||||
|
elif [[ $GITHUB_REF =~ ^refs/heads/release-3.0.0/.* ]]; then
|
||||||
|
version=$(echo $GITHUB_REF | awk -F '/' '{print $NF}' | sed 's/v//')
|
||||||
|
phase="rc"
|
||||||
|
newVersionString="${version}-${phase}-${GITHUB_RUN_NUMBER}"
|
||||||
|
else
|
||||||
|
# For local builds or unrecognized branches
|
||||||
|
newVersionString="${newVersion}-local"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "version=$newVersionString" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Create Build Properties file
|
||||||
|
- name: Create Build Properties
|
||||||
|
run: |
|
||||||
|
cat > Directory.Build.props << EOF
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<Version>${{ steps.setVersion.outputs.version }}</Version>
|
||||||
|
<AssemblyVersion>${{ steps.setVersion.outputs.version }}</AssemblyVersion>
|
||||||
|
<FileVersion>${{ steps.setVersion.outputs.version }}</FileVersion>
|
||||||
|
<InformationalVersion>${{ steps.setVersion.outputs.version }}</InformationalVersion>
|
||||||
|
<PackageVersion>${{ steps.setVersion.outputs.version }}</PackageVersion>
|
||||||
|
<NuGetVersion>${{ steps.setVersion.outputs.version }}</NuGetVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
||||||
|
EOF
|
||||||
|
|
||||||
|
- name: Setup .NET
|
||||||
|
uses: actions/setup-dotnet@v3
|
||||||
|
with:
|
||||||
|
dotnet-version: '8.0.x'
|
||||||
|
|
||||||
|
- name: Restore NuGet Packages
|
||||||
|
run: dotnet restore ${SOLUTION_FILE}.sln
|
||||||
|
|
||||||
|
- name: Build Solution
|
||||||
|
run: dotnet build ${SOLUTION_FILE}.sln --configuration ${BUILD_TYPE} --no-restore
|
||||||
|
|
||||||
|
# Copy the CPZ file to the output directory with version in the filename
|
||||||
|
- name: Copy and Rename CPZ Files
|
||||||
|
run: |
|
||||||
|
mkdir -p ./output/cpz
|
||||||
|
|
||||||
|
# Find the main CPZ file in the build output
|
||||||
|
if [ -f "./src/PepperDash.Essentials/bin/${BUILD_TYPE}/net8/PepperDashEssentials.cpz" ]; then
|
||||||
|
cp "./src/PepperDash.Essentials/bin/${BUILD_TYPE}/net8/PepperDashEssentials.cpz" "./output/cpz/PepperDashEssentials.${{ steps.setVersion.outputs.version }}.cpz"
|
||||||
|
echo "Main CPZ file copied and renamed successfully."
|
||||||
|
else
|
||||||
|
echo "Warning: Main CPZ file not found at expected location."
|
||||||
|
find ./src -name "*.cpz" | xargs -I {} cp {} ./output/cpz/
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Pack Solution
|
||||||
|
run: dotnet pack ${SOLUTION_FILE}.sln --configuration ${BUILD_TYPE} --output ./output/nuget --no-build
|
||||||
|
|
||||||
|
# List build artifacts (runs in both environments)
|
||||||
|
- name: List Build Artifacts
|
||||||
|
run: |
|
||||||
|
echo "=== Build Artifacts ==="
|
||||||
|
echo "NuGet Packages:"
|
||||||
|
find ./output/nuget -type f | sort
|
||||||
|
echo ""
|
||||||
|
echo "CPZ/CPLZ Files:"
|
||||||
|
find ./output -name "*.cpz" -o -name "*.cplz" | sort
|
||||||
|
echo "======================="
|
||||||
|
|
||||||
|
# Enhanced package inspection for local runs
|
||||||
|
- name: Inspect NuGet Packages
|
||||||
|
if: steps.detect_env.outputs.is_local == 'true'
|
||||||
|
run: |
|
||||||
|
echo "=== NuGet Package Details ==="
|
||||||
|
for pkg in $(find ./output/nuget -name "*.nupkg"); do
|
||||||
|
echo "Package: $(basename "$pkg")"
|
||||||
|
echo "Size: $(du -h "$pkg" | cut -f1)"
|
||||||
|
|
||||||
|
# Extract and show package contents
|
||||||
|
echo "Contents:"
|
||||||
|
unzip -l "$pkg" | tail -n +4 | head -n -2
|
||||||
|
echo "--------------------------"
|
||||||
|
|
||||||
|
# Try to extract and show the nuspec file (contains metadata)
|
||||||
|
echo "Metadata:"
|
||||||
|
unzip -p "$pkg" "*.nuspec" 2>/dev/null | grep -E "(<id>|<version>|<description>|<authors>|<dependencies>)" || echo "Metadata extraction failed"
|
||||||
|
echo "--------------------------"
|
||||||
|
done
|
||||||
|
echo "==========================="
|
||||||
|
|
||||||
|
# Tag creation - GitHub version
|
||||||
|
- name: Create tag for non-rc builds (GitHub)
|
||||||
|
if: ${{ !contains(steps.setVersion.outputs.version, 'rc') && steps.detect_env.outputs.is_local == 'false' }}
|
||||||
|
run: |
|
||||||
|
git config --global user.name "GitHub Actions"
|
||||||
|
git config --global user.email "actions@github.com"
|
||||||
|
git tag ${{ steps.setVersion.outputs.version }}
|
||||||
|
git push --tags origin
|
||||||
|
|
||||||
|
# Tag creation - Act mock version
|
||||||
|
- name: Create tag for non-rc builds (Act Mock)
|
||||||
|
if: ${{ !contains(steps.setVersion.outputs.version, 'rc') && steps.detect_env.outputs.is_local == 'true' }}
|
||||||
|
run: |
|
||||||
|
echo "Would create git tag: ${{ steps.setVersion.outputs.version }}"
|
||||||
|
echo "Would push tag to: origin"
|
||||||
|
|
||||||
|
# Release creation - GitHub version
|
||||||
|
- name: Create Release (GitHub)
|
||||||
|
if: steps.detect_env.outputs.is_local == 'false'
|
||||||
|
id: create_release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
artifacts: 'output/cpz/*,output/**/*.cplz'
|
||||||
|
generateReleaseNotes: true
|
||||||
|
prerelease: ${{contains('debug', env.BUILD_TYPE)}}
|
||||||
|
tag: ${{ steps.setVersion.outputs.version }}
|
||||||
|
|
||||||
|
# Release creation - Act mock version with enhanced output
|
||||||
|
- name: Create Release (Act Mock)
|
||||||
|
if: steps.detect_env.outputs.is_local == 'true'
|
||||||
|
run: |
|
||||||
|
echo "=== Mock Release Creation ==="
|
||||||
|
echo "Would create release with:"
|
||||||
|
echo "- Tag: ${{ steps.setVersion.outputs.version }}"
|
||||||
|
echo "- Prerelease: ${{contains('debug', env.BUILD_TYPE)}}"
|
||||||
|
echo "- Artifacts matching pattern: output/cpz/*,output/**/*.cplz"
|
||||||
|
echo ""
|
||||||
|
echo "Matching artifacts:"
|
||||||
|
find ./output/cpz -type f
|
||||||
|
find ./output -name "*.cplz"
|
||||||
|
|
||||||
|
# Detailed info about release artifacts
|
||||||
|
echo ""
|
||||||
|
echo "Artifact Details:"
|
||||||
|
for artifact in $(find ./output/cpz -type f; find ./output -name "*.cplz"); do
|
||||||
|
echo "File: $(basename "$artifact")"
|
||||||
|
echo "Size: $(du -h "$artifact" | cut -f1)"
|
||||||
|
echo "Created: $(stat -c %y "$artifact")"
|
||||||
|
echo "MD5: $(md5sum "$artifact" | cut -d' ' -f1)"
|
||||||
|
echo "--------------------------"
|
||||||
|
done
|
||||||
|
echo "============================"
|
||||||
|
|
||||||
|
# NuGet setup - GitHub version
|
||||||
|
- name: Setup NuGet (GitHub)
|
||||||
|
if: steps.detect_env.outputs.is_local == 'false'
|
||||||
|
run: |
|
||||||
|
dotnet nuget add source https://nuget.pkg.github.com/pepperdash/index.json -n github -u pepperdash -p ${{ secrets.GITHUB_TOKEN }} --store-password-in-clear-text
|
||||||
|
|
||||||
|
# NuGet setup - Act mock version
|
||||||
|
- name: Setup NuGet (Act Mock)
|
||||||
|
if: steps.detect_env.outputs.is_local == 'true'
|
||||||
|
run: |
|
||||||
|
echo "=== Mock NuGet Setup ==="
|
||||||
|
echo "Would add GitHub NuGet source: https://nuget.pkg.github.com/pepperdash/index.json"
|
||||||
|
echo "======================="
|
||||||
|
|
||||||
|
# Publish to NuGet - GitHub version
|
||||||
|
- name: Publish to Nuget (GitHub)
|
||||||
|
if: steps.detect_env.outputs.is_local == 'false'
|
||||||
|
run: dotnet nuget push ./output/nuget/*.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_API_KEY }}
|
||||||
|
|
||||||
|
# Publish to NuGet - Act mock version
|
||||||
|
- name: Publish to Nuget (Act Mock)
|
||||||
|
if: steps.detect_env.outputs.is_local == 'true'
|
||||||
|
run: |
|
||||||
|
echo "=== Mock Publish to NuGet ==="
|
||||||
|
echo "Would publish the following packages to https://api.nuget.org/v3/index.json:"
|
||||||
|
find ./output/nuget -name "*.nupkg" | sort
|
||||||
|
echo "============================="
|
||||||
|
|
||||||
|
# Publish to GitHub NuGet - GitHub version
|
||||||
|
- name: Publish to Github Nuget (GitHub)
|
||||||
|
if: steps.detect_env.outputs.is_local == 'false'
|
||||||
|
run: dotnet nuget push ./output/nuget/*.nupkg --source github --api-key ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
# Publish to GitHub NuGet - Act mock version
|
||||||
|
- name: Publish to Github Nuget (Act Mock)
|
||||||
|
if: steps.detect_env.outputs.is_local == 'true'
|
||||||
|
run: |
|
||||||
|
echo "=== Mock Publish to GitHub NuGet ==="
|
||||||
|
echo "Would publish the following packages to the GitHub NuGet registry:"
|
||||||
|
find ./output/nuget -name "*.nupkg" | sort
|
||||||
|
echo "=================================="
|
||||||
57
.github/workflows/main.yml
vendored
57
.github/workflows/main.yml
vendored
@@ -1,57 +0,0 @@
|
|||||||
name: main Build using Docker
|
|
||||||
|
|
||||||
on:
|
|
||||||
release:
|
|
||||||
types:
|
|
||||||
- published
|
|
||||||
branches:
|
|
||||||
- main-2.0.0
|
|
||||||
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: PepperDashEssentials
|
|
||||||
SOLUTION_FILE: PepperDashEssentials
|
|
||||||
# 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@v3
|
|
||||||
# Generate the appropriate version number
|
|
||||||
- name: Set Version Number
|
|
||||||
shell: powershell
|
|
||||||
id: setVersion
|
|
||||||
env:
|
|
||||||
TAG_NAME: ${{ github.event.release.tag_name }}
|
|
||||||
run: echo "VERSION=$($Env:TAG_NAME)" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
|
|
||||||
- name: Setup MS Build
|
|
||||||
uses: microsoft/setup-msbuild@v1.1
|
|
||||||
- name: restore Nuget Packages
|
|
||||||
run: nuget restore .\$($Env:SOLUTION_FILE).sln
|
|
||||||
- name: Build Solution
|
|
||||||
run: msbuild .\$($Env:SOLUTION_FILE).sln /p:Platform="Any CPU" /p:Configuration="Debug" /p:Version="${{ steps.setVersion.outputs.version }}" -m
|
|
||||||
- name: Pack Solution
|
|
||||||
run: dotnet pack .\$($Env:SOLUTION_FILE).sln --configuration $env:BUILD_TYPE --output ./output /p:Version="${{ steps.setVersion.outputs.version }}"
|
|
||||||
- name: Upload Release
|
|
||||||
id: create_release
|
|
||||||
uses: ncipollo/release-action@v1
|
|
||||||
with:
|
|
||||||
updateRelease: true
|
|
||||||
artifacts: 'output\**\*.*(cpz|cplz)'
|
|
||||||
tag: ${{ steps.setVersion.outputs.version }}
|
|
||||||
- name: Setup Nuget
|
|
||||||
run: |
|
|
||||||
nuget sources add -name github -source https://nuget.pkg.github.com/pepperdash/index.json -username pepperdash -password ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
nuget setApiKey ${{ secrets.GITHUB_TOKEN }} -Source github
|
|
||||||
nuget setApiKey ${{ secrets.NUGET_API_KEY }} -Source https://api.nuget.org/v3/index.json
|
|
||||||
- name: Publish to Nuget
|
|
||||||
run: nuget push .\output\*.nupkg -Source https://api.nuget.org/v3/index.json
|
|
||||||
- name: Publish to Github Nuget
|
|
||||||
run: nuget push .\output\*.nupkg -Source github
|
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
Provided under MIT license
|
Provided under MIT license
|
||||||
|
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
PepperDash Essentials is an open source Crestron framework that can be configured as a standalone program capable of running a wide variety of system designs and can also be utilized as a plug-in architecture to augment other Simpl# Pro and Simpl Windows programs.
|
PepperDash Essentials is an open source Crestron framework that can be configured as a standalone program capable of running a wide variety of system designs and can also be utilized as a plug-in architecture to augment other Simpl# Pro and Simpl Windows programs.
|
||||||
|
|||||||
7
runtimeconfig.json
Normal file
7
runtimeconfig.json
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"runtimeOptions": {
|
||||||
|
"configProperties": {
|
||||||
|
"System.Globalization.Invariant": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,6 @@
|
|||||||
<Project>
|
<Project>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<!-- Include CPZ files from multiple possible locations -->
|
<None Include="$(PackageOutputPath)\$(AssemblyName)\*.cpz" Condition="$(ProjectType) == 'Program'">
|
||||||
<None Include="$(TargetDir)*.cpz" Condition="$(ProjectType) == 'Program'">
|
|
||||||
<Pack>true</Pack>
|
|
||||||
<PackagePath>build;</PackagePath>
|
|
||||||
</None>
|
|
||||||
<None Include="$(OutputPath)*.cpz" Condition="$(ProjectType) == 'Program'">
|
|
||||||
<Pack>true</Pack>
|
|
||||||
<PackagePath>build;</PackagePath>
|
|
||||||
</None>
|
|
||||||
<None Include="$(MSBuildProjectDirectory)\bin\$(Configuration)\**\*.cpz" Condition="$(ProjectType) == 'Program'">
|
|
||||||
<Pack>true</Pack>
|
|
||||||
<PackagePath>build;</PackagePath>
|
|
||||||
</None>
|
|
||||||
<None Include="$(PackageOutputPath)\build\*.cpz" Condition="$(ProjectType) == 'Program'">
|
|
||||||
<Pack>true</Pack>
|
<Pack>true</Pack>
|
||||||
<PackagePath>build;</PackagePath>
|
<PackagePath>build;</PackagePath>
|
||||||
</None>
|
</None>
|
||||||
@@ -23,94 +10,17 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Target Name="Create CPLZ" AfterTargets="Build; AfterRebuild" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''">
|
<Target Name="Create CPLZ" AfterTargets="Build; AfterRebuild" Condition="$(ProjectType) == 'ProgramLibrary' And $(TargetDir) != ''">
|
||||||
<Message Text="Creating CPLZ $(TargetDir)" Importance="high" />
|
<Message Text="Creating CPLZ $(TargetDir)"></Message>
|
||||||
<Message Text="PackageOutputPath: $(PackageOutputPath)" Importance="high" />
|
|
||||||
<Message Text="AssemblyName: $(AssemblyName)" Importance="high" />
|
|
||||||
<Message Text="TargetName: $(TargetName)" Importance="high" />
|
|
||||||
<Message Text="Version: $(Version)" Importance="high" />
|
|
||||||
<Message Text="TargetFramework: $(TargetFramework)" Importance="high" />
|
|
||||||
<MakeDir Directories="$(PackageOutputPath)" Condition="!Exists($(PackageOutputPath))" />
|
<MakeDir Directories="$(PackageOutputPath)" Condition="!Exists($(PackageOutputPath))" />
|
||||||
<MakeDir Directories="$(PackageOutputPath)\$(AssemblyName)" Condition="!Exists('$(PackageOutputPath)\$(AssemblyName)')" />
|
<MakeDir Directories="$(PackageOutputPath)\$(AssemblyName)" Condition="!Exists('$(PackageOutputPath)\$(AssemblyName)')" />
|
||||||
<ZipDirectory SourceDirectory="$(TargetDir)" DestinationFile="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cplz" Overwrite="true"/>
|
<ZipDirectory SourceDirectory="$(TargetDir)" DestinationFile="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cplz" Overwrite="true"/>
|
||||||
</Target>
|
</Target>
|
||||||
<Target Name="Debug Variables" BeforeTargets="Build">
|
<Target Name="Copy CPZ NET6" AfterTargets="SimplSharpPostProcess" Condition="$(ProjectType) == 'Program' And ( ('$(TargetFramework)' == 'net6.0') Or ('$(TargetFramework)' == 'net8.0') )">
|
||||||
<Message Text="================ Debug Variables ================" Importance="high" />
|
<Message Text="Copying CPZ"></Message>
|
||||||
<Message Text="ProjectType: '$(ProjectType)'" Importance="high" />
|
<Move SourceFiles="$(TargetDir)$(TargetName).cpz" DestinationFiles="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz" />
|
||||||
<Message Text="TargetFramework: '$(TargetFramework)'" Importance="high" />
|
|
||||||
<Message Text="TargetDir: '$(TargetDir)'" Importance="high" />
|
|
||||||
<Message Text="===============================================" Importance="high" />
|
|
||||||
</Target>
|
</Target>
|
||||||
<Target Name="Copy CPZ NET472"
|
<Target Name="Copy CPZ NET47" AfterTargets="SimplSharpPostProcess47" Condition="($(ProjectType) == 'Program' And ( '$(TargetFramework)' != 'net6.0' ) And ( '$(TargetFramework)' != 'net8.0' ))">
|
||||||
AfterTargets="Build"
|
<Message Text="Copying CPZ"></Message>
|
||||||
DependsOnTargets="BuildDependencies"
|
<Move SourceFiles="$(TargetDir)$(TargetName).cpz" DestinationFiles="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz" />
|
||||||
Condition="'$(ProjectType)' == 'Program' And '$(TargetFramework)' == 'net472'">
|
|
||||||
<Message Text="========================================" Importance="high" />
|
|
||||||
<Message Text="Starting CPZ Build Process for NET472" Importance="high" />
|
|
||||||
<Message Text="ProjectType: '$(ProjectType)'" Importance="high" />
|
|
||||||
<Message Text="TargetFramework: '$(TargetFramework)'" Importance="high" />
|
|
||||||
<Message Text="========================================" Importance="high" />
|
|
||||||
|
|
||||||
<!-- Create output directory -->
|
|
||||||
<MakeDir Directories="$(PackageOutputPath)\$(AssemblyName)"
|
|
||||||
Condition="!Exists('$(PackageOutputPath)\$(AssemblyName)')" />
|
|
||||||
|
|
||||||
<!-- Copy the CPZ file -->
|
|
||||||
<Copy SourceFiles="$(TargetDir)$(TargetName).cpz"
|
|
||||||
DestinationFiles="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz"
|
|
||||||
Condition="Exists('$(TargetDir)$(TargetName).cpz')" />
|
|
||||||
|
|
||||||
<Message Text="CPZ Build completed for NET472"
|
|
||||||
Condition="Exists('$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz')"
|
|
||||||
Importance="high" />
|
|
||||||
</Target>
|
|
||||||
<Target Name="Copy CPZ NET6"
|
|
||||||
AfterTargets="Build"
|
|
||||||
DependsOnTargets="BuildDependencies"
|
|
||||||
Condition="'$(ProjectType)' == 'Program' And ('$(TargetFramework)' == 'net6.0' Or '$(TargetFramework)' == 'net8.0')">
|
|
||||||
<Message Text="========================================" Importance="high" />
|
|
||||||
<Message Text="Starting CPZ Build Process" Importance="high" />
|
|
||||||
<Message Text="ProjectType: '$(ProjectType)'" Importance="high" />
|
|
||||||
<Message Text="TargetFramework: '$(TargetFramework)'" Importance="high" />
|
|
||||||
<Message Text="MSBuildProjectDirectory: '$(MSBuildProjectDirectory)'" Importance="high" />
|
|
||||||
<Message Text="PATH: '$(PATH)'" Importance="high" />
|
|
||||||
<Message Text="========================================" Importance="high" />
|
|
||||||
|
|
||||||
<!-- Check for SimplSharp compiler -->
|
|
||||||
<PropertyGroup>
|
|
||||||
<SimplSharpCompilerPath>$(HOME)/.crestron/SimplSharpPro/SimplSharpCompiler</SimplSharpCompilerPath>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<Warning Text="SimplSharpCompiler not found at: $(SimplSharpCompilerPath)"
|
|
||||||
Condition="!Exists('$(SimplSharpCompilerPath)')" />
|
|
||||||
|
|
||||||
<!-- Run the SimplSharp compiler to create CPZ -->
|
|
||||||
<Exec Command=""$(SimplSharpCompilerPath)" "$(MSBuildProjectDirectory)" "$(TargetDir)""
|
|
||||||
IgnoreExitCode="false"
|
|
||||||
WorkingDirectory="$(MSBuildProjectDirectory)"
|
|
||||||
ConsoleToMSBuild="true"
|
|
||||||
Condition="Exists('$(SimplSharpCompilerPath)')">
|
|
||||||
<Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
|
|
||||||
</Exec>
|
|
||||||
|
|
||||||
<Message Text="SimplSharp Output: $(OutputOfExec)" Importance="high" />
|
|
||||||
|
|
||||||
<!-- Create output directory -->
|
|
||||||
<MakeDir Directories="$(PackageOutputPath)\$(AssemblyName)"
|
|
||||||
Condition="!Exists('$(PackageOutputPath)\$(AssemblyName)')" />
|
|
||||||
|
|
||||||
<!-- Copy the CPZ file -->
|
|
||||||
<Copy SourceFiles="$(TargetDir)$(TargetName).cpz"
|
|
||||||
DestinationFiles="$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz"
|
|
||||||
Condition="Exists('$(TargetDir)$(TargetName).cpz')" />
|
|
||||||
|
|
||||||
<Message Text="CPZ Build completed"
|
|
||||||
Condition="Exists('$(PackageOutputPath)\$(AssemblyName)\$(TargetName).$(Version).$(TargetFramework).cpz')"
|
|
||||||
Importance="high" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
<Target Name="BuildDependencies">
|
|
||||||
<MSBuild Projects="@(ProjectReference)"
|
|
||||||
Targets="Build"
|
|
||||||
BuildInParallel="true" />
|
|
||||||
</Target>
|
</Target>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,6 +1,4 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
@@ -35,7 +33,8 @@ namespace PepperDash.Essentials.Core
|
|||||||
public static eCrestronSeries ProcessorSeries { get { return CrestronEnvironment.ProgramCompatibility; } }
|
public static eCrestronSeries ProcessorSeries { get { return CrestronEnvironment.ProgramCompatibility; } }
|
||||||
|
|
||||||
// TODO: consider making this configurable later
|
// TODO: consider making this configurable later
|
||||||
public static IFormatProvider Culture = CultureInfo.CreateSpecificCulture("en-US");
|
public static IFormatProvider Culture = CultureInfo.InvariantCulture;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// True when the processor type is a DMPS variant
|
/// True when the processor type is a DMPS variant
|
||||||
@@ -279,6 +278,18 @@ namespace PepperDash.Essentials.Core
|
|||||||
CrestronConsole.PrintLine("Error starting CrestronDataStoreStatic: {0}", err);
|
CrestronConsole.PrintLine("Error starting CrestronDataStoreStatic: {0}", err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.CreateSpecificCulture("en");
|
||||||
|
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.CreateSpecificCulture("en");
|
||||||
|
}
|
||||||
|
catch (CultureNotFoundException)
|
||||||
|
{
|
||||||
|
// If specific culture fails, fall back to invariant
|
||||||
|
CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
|
||||||
|
CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.Reflection;
|
|
||||||
using Crestron.SimplSharp.Scheduler;
|
using Crestron.SimplSharp.Scheduler;
|
||||||
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<Configurations>Debug;Release;Debug 4.7.2</Configurations>
|
<Configurations>Debug;Release;Debug 4.7.2</Configurations>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net472;net6</TargetFrameworks>
|
<TargetFramework>net8</TargetFramework>
|
||||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<AssemblyName>PepperDash_Essentials_Core</AssemblyName>
|
<AssemblyName>PepperDash_Essentials_Core</AssemblyName>
|
||||||
@@ -25,8 +25,8 @@
|
|||||||
<DebugType>pdbonly</DebugType>
|
<DebugType>pdbonly</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.20.66" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.90" />
|
||||||
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-451" />
|
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-462" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Crestron\CrestronGenericBaseDevice.cs.orig" />
|
<None Include="Crestron\CrestronGenericBaseDevice.cs.orig" />
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.IO;
|
||||||
|
using System.Reflection.PortableExecutable;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
|
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
using PepperDash.Essentials.Core;
|
using PepperDash.Essentials.Core;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using CrestronIO = Crestron.SimplSharp.CrestronIO;
|
||||||
|
using SystemIO = System.IO;
|
||||||
|
|
||||||
namespace PepperDash.Essentials
|
namespace PepperDash.Essentials
|
||||||
{
|
{
|
||||||
@@ -27,6 +31,11 @@ namespace PepperDash.Essentials
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
static List<LoadedAssembly> LoadedPluginFolderAssemblies;
|
static List<LoadedAssembly> LoadedPluginFolderAssemblies;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// List of plugins that were found to be incompatible with .NET 8
|
||||||
|
/// </summary>
|
||||||
|
public static List<IncompatiblePlugin> IncompatiblePlugins { get; private set; }
|
||||||
|
|
||||||
public static LoadedAssembly EssentialsAssembly { get; private set; }
|
public static LoadedAssembly EssentialsAssembly { get; private set; }
|
||||||
|
|
||||||
public static LoadedAssembly PepperDashCoreAssembly { get; private set; }
|
public static LoadedAssembly PepperDashCoreAssembly { get; private set; }
|
||||||
@@ -46,12 +55,28 @@ namespace PepperDash.Essentials
|
|||||||
// The temp directory where .cplz archives will be unzipped to
|
// The temp directory where .cplz archives will be unzipped to
|
||||||
static string _tempDirectory => _pluginDirectory + Global.DirectorySeparator + "temp";
|
static string _tempDirectory => _pluginDirectory + Global.DirectorySeparator + "temp";
|
||||||
|
|
||||||
|
// Known incompatible types in .NET 8
|
||||||
|
private static readonly HashSet<string> KnownIncompatibleTypes = new HashSet<string>
|
||||||
|
{
|
||||||
|
"System.Net.ICertificatePolicy",
|
||||||
|
"System.Security.Cryptography.SHA1CryptoServiceProvider",
|
||||||
|
"System.Web.HttpUtility",
|
||||||
|
"System.Configuration.ConfigurationManager",
|
||||||
|
"System.Web.Services.Protocols.SoapHttpClientProtocol",
|
||||||
|
"System.Runtime.Remoting",
|
||||||
|
"System.EnterpriseServices",
|
||||||
|
"System.Runtime.Serialization.Formatters.Binary.BinaryFormatter",
|
||||||
|
"System.Security.SecurityManager",
|
||||||
|
"System.Security.Permissions.FileIOPermission",
|
||||||
|
"System.AppDomain.CreateDomain"
|
||||||
|
};
|
||||||
|
|
||||||
static PluginLoader()
|
static PluginLoader()
|
||||||
{
|
{
|
||||||
LoadedAssemblies = new List<LoadedAssembly>();
|
LoadedAssemblies = new List<LoadedAssembly>();
|
||||||
LoadedPluginFolderAssemblies = new List<LoadedAssembly>();
|
LoadedPluginFolderAssemblies = new List<LoadedAssembly>();
|
||||||
EssentialsPluginAssemblies = new List<LoadedAssembly>();
|
EssentialsPluginAssemblies = new List<LoadedAssembly>();
|
||||||
|
IncompatiblePlugins = new List<IncompatiblePlugin>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -61,7 +86,7 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Getting Assemblies loaded with Essentials");
|
Debug.LogMessage(LogEventLevel.Verbose, "Getting Assemblies loaded with Essentials");
|
||||||
// Get the loaded assembly filenames
|
// Get the loaded assembly filenames
|
||||||
var appDi = new DirectoryInfo(Global.ApplicationDirectoryPathPrefix);
|
var appDi = new SystemIO.DirectoryInfo(Global.ApplicationDirectoryPathPrefix);
|
||||||
var assemblyFiles = appDi.GetFiles("*.dll");
|
var assemblyFiles = appDi.GetFiles("*.dll");
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Found {0} Assemblies", assemblyFiles.Length);
|
Debug.LogMessage(LogEventLevel.Verbose, "Found {0} Assemblies", assemblyFiles.Length);
|
||||||
@@ -113,7 +138,6 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void SetEssentialsAssembly(string name, Assembly assembly)
|
public static void SetEssentialsAssembly(string name, Assembly assembly)
|
||||||
{
|
{
|
||||||
var loadedAssembly = LoadedAssemblies.FirstOrDefault(la => la.Name.Equals(name));
|
var loadedAssembly = LoadedAssemblies.FirstOrDefault(la => la.Name.Equals(name));
|
||||||
@@ -125,19 +149,108 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads an assembly via Reflection and adds it to the list of loaded assemblies
|
/// Checks if a plugin is compatible with .NET 8 by examining its metadata
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="fileName"></param>
|
/// <param name="filePath">Path to the plugin assembly</param>
|
||||||
static LoadedAssembly LoadAssembly(string filePath)
|
/// <returns>Tuple with compatibility result, reason if incompatible, and referenced assemblies</returns>
|
||||||
|
public static (bool IsCompatible, string Reason, List<string> References) IsPluginCompatibleWithNet8(string filePath)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//Debug.LogMessage(LogEventLevel.Verbose, "Attempting to load {0}", filePath);
|
List<string> referencedAssemblies = new List<string>();
|
||||||
|
|
||||||
|
using (SystemIO.FileStream fs = new SystemIO.FileStream(filePath, SystemIO.FileMode.Open,
|
||||||
|
SystemIO.FileAccess.Read, SystemIO.FileShare.ReadWrite))
|
||||||
|
using (PEReader peReader = new PEReader(fs))
|
||||||
|
{
|
||||||
|
if (!peReader.HasMetadata)
|
||||||
|
return (false, "Not a valid .NET assembly", referencedAssemblies);
|
||||||
|
|
||||||
|
MetadataReader metadataReader = peReader.GetMetadataReader();
|
||||||
|
|
||||||
|
// Collect assembly references
|
||||||
|
foreach (var assemblyRefHandle in metadataReader.AssemblyReferences)
|
||||||
|
{
|
||||||
|
var assemblyRef = metadataReader.GetAssemblyReference(assemblyRefHandle);
|
||||||
|
string assemblyName = metadataReader.GetString(assemblyRef.Name);
|
||||||
|
referencedAssemblies.Add(assemblyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for references to known incompatible types
|
||||||
|
foreach (var typeRefHandle in metadataReader.TypeReferences)
|
||||||
|
{
|
||||||
|
var typeRef = metadataReader.GetTypeReference(typeRefHandle);
|
||||||
|
string typeNamespace = metadataReader.GetString(typeRef.Namespace);
|
||||||
|
string typeName = metadataReader.GetString(typeRef.Name);
|
||||||
|
|
||||||
|
string fullTypeName = $"{typeNamespace}.{typeName}";
|
||||||
|
if (KnownIncompatibleTypes.Contains(fullTypeName))
|
||||||
|
{
|
||||||
|
return (false, $"Uses incompatible type: {fullTypeName}", referencedAssemblies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for explicit .NET 8 compatibility attribute
|
||||||
|
bool hasNet8Attribute = false;
|
||||||
|
foreach (var customAttributeHandle in metadataReader.GetAssemblyDefinition().GetCustomAttributes())
|
||||||
|
{
|
||||||
|
var customAttribute = metadataReader.GetCustomAttribute(customAttributeHandle);
|
||||||
|
var ctorHandle = customAttribute.Constructor;
|
||||||
|
|
||||||
|
if (ctorHandle.Kind == HandleKind.MemberReference)
|
||||||
|
{
|
||||||
|
var memberRef = metadataReader.GetMemberReference((MemberReferenceHandle)ctorHandle);
|
||||||
|
var typeRef = metadataReader.GetTypeReference((TypeReferenceHandle)memberRef.Parent);
|
||||||
|
|
||||||
|
string typeName = metadataReader.GetString(typeRef.Name);
|
||||||
|
if (typeName == "Net8CompatibleAttribute" || typeName == "TargetFrameworkAttribute")
|
||||||
|
{
|
||||||
|
hasNet8Attribute = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasNet8Attribute)
|
||||||
|
{
|
||||||
|
return (true, null, referencedAssemblies);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we can't determine incompatibility, assume it's compatible
|
||||||
|
return (true, null, referencedAssemblies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return (false, $"Error analyzing assembly: {ex.Message}", new List<string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads an assembly via Reflection and adds it to the list of loaded assemblies
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">Path to the assembly file</param>
|
||||||
|
/// <param name="requestedBy">Name of the plugin requesting this assembly (null for direct loads)</param>
|
||||||
|
static LoadedAssembly LoadAssembly(string filePath, string requestedBy = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check .NET 8 compatibility before loading
|
||||||
|
var (isCompatible, reason, references) = IsPluginCompatibleWithNet8(filePath);
|
||||||
|
if (!isCompatible)
|
||||||
|
{
|
||||||
|
string fileName = CrestronIO.Path.GetFileName(filePath);
|
||||||
|
Debug.LogMessage(LogEventLevel.Warning, "Assembly '{0}' is not compatible with .NET 8: {1}", fileName, reason);
|
||||||
|
|
||||||
|
var incompatiblePlugin = new IncompatiblePlugin(fileName, reason, requestedBy);
|
||||||
|
IncompatiblePlugins.Add(incompatiblePlugin);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
var assembly = Assembly.LoadFrom(filePath);
|
var assembly = Assembly.LoadFrom(filePath);
|
||||||
if (assembly != null)
|
if (assembly != null)
|
||||||
{
|
{
|
||||||
var assyVersion = GetAssemblyVersion(assembly);
|
var assyVersion = GetAssemblyVersion(assembly);
|
||||||
|
|
||||||
var loadedAssembly = new LoadedAssembly(assembly.GetName().Name, assyVersion, assembly);
|
var loadedAssembly = new LoadedAssembly(assembly.GetName().Name, assyVersion, assembly);
|
||||||
LoadedAssemblies.Add(loadedAssembly);
|
LoadedAssemblies.Add(loadedAssembly);
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Loaded assembly '{0}', version {1}", loadedAssembly.Name, loadedAssembly.Version);
|
Debug.LogMessage(LogEventLevel.Information, "Loaded assembly '{0}', version {1}", loadedAssembly.Name, loadedAssembly.Version);
|
||||||
@@ -147,14 +260,47 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Unable to load assembly: '{0}'", filePath);
|
Debug.LogMessage(LogEventLevel.Information, "Unable to load assembly: '{0}'", filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
} catch(Exception ex)
|
|
||||||
{
|
|
||||||
Debug.LogMessage(ex, "Error loading assembly from {path}", null, filePath);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
catch(SystemIO.FileLoadException ex) when (ex.Message.Contains("Assembly with same name is already loaded"))
|
||||||
|
{
|
||||||
|
// Get the assembly name from the file path
|
||||||
|
string assemblyName = CrestronIO.Path.GetFileNameWithoutExtension(filePath);
|
||||||
|
|
||||||
|
// Try to find the already loaded assembly
|
||||||
|
var existingAssembly = AppDomain.CurrentDomain.GetAssemblies()
|
||||||
|
.FirstOrDefault(a => a.GetName().Name.Equals(assemblyName, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
|
if (existingAssembly != null)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, "Assembly '{0}' is already loaded, using existing instance", assemblyName);
|
||||||
|
var assyVersion = GetAssemblyVersion(existingAssembly);
|
||||||
|
var loadedAssembly = new LoadedAssembly(existingAssembly.GetName().Name, assyVersion, existingAssembly);
|
||||||
|
LoadedAssemblies.Add(loadedAssembly);
|
||||||
|
return loadedAssembly;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Warning, "Assembly with same name already loaded but couldn't find it: {0}", filePath);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch(Exception ex)
|
||||||
|
{
|
||||||
|
string fileName = CrestronIO.Path.GetFileName(filePath);
|
||||||
|
|
||||||
|
// Check if this might be a .NET Framework compatibility issue
|
||||||
|
if (ex.Message.Contains("Could not load type") ||
|
||||||
|
ex.Message.Contains("Unable to load one or more of the requested types"))
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Error, "Error loading assembly {0}: Likely .NET 8 compatibility issue: {1}",
|
||||||
|
fileName, ex.Message);
|
||||||
|
IncompatiblePlugins.Add(new IncompatiblePlugin(fileName, ex.Message, requestedBy));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogMessage(ex, "Error loading assembly from {path}", null, filePath);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -216,12 +362,25 @@ namespace PepperDash.Essentials
|
|||||||
CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version);
|
CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version);
|
||||||
}
|
}
|
||||||
|
|
||||||
//CrestronConsole.ConsoleCommandResponse("Loaded Assemblies:" + CrestronEnvironment.NewLine);
|
if (IncompatiblePlugins.Count > 0)
|
||||||
//foreach (var assembly in LoadedAssemblies)
|
{
|
||||||
//{
|
CrestronConsole.ConsoleCommandResponse("Incompatible Plugins:" + CrestronEnvironment.NewLine);
|
||||||
// CrestronConsole.ConsoleCommandResponse("{0} Version: {1}" + CrestronEnvironment.NewLine, assembly.Name, assembly.Version);
|
foreach (var plugin in IncompatiblePlugins)
|
||||||
//}
|
{
|
||||||
|
if (plugin.TriggeredBy != "Direct load")
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("{0}: {1} (Required by: {2})" + CrestronEnvironment.NewLine,
|
||||||
|
plugin.Name, plugin.Reason, plugin.TriggeredBy);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CrestronConsole.ConsoleCommandResponse("{0}: {1}" + CrestronEnvironment.NewLine,
|
||||||
|
plugin.Name, plugin.Reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Moves any .dll assemblies not already loaded from the plugins folder to loadedPlugins folder
|
/// Moves any .dll assemblies not already loaded from the plugins folder to loadedPlugins folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -229,14 +388,14 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Looking for .dll assemblies from plugins folder...");
|
Debug.LogMessage(LogEventLevel.Information, "Looking for .dll assemblies from plugins folder...");
|
||||||
|
|
||||||
var pluginDi = new DirectoryInfo(_pluginDirectory);
|
var pluginDi = new SystemIO.DirectoryInfo(_pluginDirectory);
|
||||||
var pluginFiles = pluginDi.GetFiles("*.dll");
|
var pluginFiles = pluginDi.GetFiles("*.dll");
|
||||||
|
|
||||||
if (pluginFiles.Length > 0)
|
if (pluginFiles.Length > 0)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(_loadedPluginsDirectoryPath))
|
if (!SystemIO.Directory.Exists(_loadedPluginsDirectoryPath))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(_loadedPluginsDirectoryPath);
|
SystemIO.Directory.CreateDirectory(_loadedPluginsDirectoryPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,14 +412,14 @@ namespace PepperDash.Essentials
|
|||||||
filePath = _loadedPluginsDirectoryPath + Global.DirectorySeparator + pluginFile.Name;
|
filePath = _loadedPluginsDirectoryPath + Global.DirectorySeparator + pluginFile.Name;
|
||||||
|
|
||||||
// Check if there is a previous file in the loadedPlugins directory and delete
|
// Check if there is a previous file in the loadedPlugins directory and delete
|
||||||
if (File.Exists(filePath))
|
if (SystemIO.File.Exists(filePath))
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Found existing file in loadedPlugins: {0} Deleting and moving new file to replace it", filePath);
|
Debug.LogMessage(LogEventLevel.Information, "Found existing file in loadedPlugins: {0} Deleting and moving new file to replace it", filePath);
|
||||||
File.Delete(filePath);
|
SystemIO.File.Delete(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the file
|
// Move the file
|
||||||
File.Move(pluginFile.FullName, filePath);
|
SystemIO.File.Move(pluginFile.FullName, filePath);
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Moved {0} to {1}", pluginFile.FullName, filePath);
|
Debug.LogMessage(LogEventLevel.Verbose, "Moved {0} to {1}", pluginFile.FullName, filePath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -284,21 +443,21 @@ namespace PepperDash.Essentials
|
|||||||
static void UnzipAndMoveCplzArchives()
|
static void UnzipAndMoveCplzArchives()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Looking for .cplz archives from plugins folder...");
|
Debug.LogMessage(LogEventLevel.Information, "Looking for .cplz archives from plugins folder...");
|
||||||
var di = new DirectoryInfo(_pluginDirectory);
|
var di = new SystemIO.DirectoryInfo(_pluginDirectory);
|
||||||
var zFiles = di.GetFiles("*.cplz");
|
var zFiles = di.GetFiles("*.cplz");
|
||||||
|
|
||||||
if (zFiles.Length > 0)
|
if (zFiles.Length > 0)
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(_loadedPluginsDirectoryPath))
|
if (!SystemIO.Directory.Exists(_loadedPluginsDirectoryPath))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(_loadedPluginsDirectoryPath);
|
SystemIO.Directory.CreateDirectory(_loadedPluginsDirectoryPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var zfi in zFiles)
|
foreach (var zfi in zFiles)
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(_tempDirectory);
|
SystemIO.Directory.CreateDirectory(_tempDirectory);
|
||||||
var tempDi = new DirectoryInfo(_tempDirectory);
|
var tempDi = new SystemIO.DirectoryInfo(_tempDirectory);
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Found cplz: {0}. Unzipping into temp plugins directory", zfi.Name);
|
Debug.LogMessage(LogEventLevel.Information, "Found cplz: {0}. Unzipping into temp plugins directory", zfi.Name);
|
||||||
var result = CrestronZIP.Unzip(zfi.FullName, tempDi.FullName);
|
var result = CrestronZIP.Unzip(zfi.FullName, tempDi.FullName);
|
||||||
@@ -316,14 +475,14 @@ namespace PepperDash.Essentials
|
|||||||
filePath = _loadedPluginsDirectoryPath + Global.DirectorySeparator + tempFile.Name;
|
filePath = _loadedPluginsDirectoryPath + Global.DirectorySeparator + tempFile.Name;
|
||||||
|
|
||||||
// Check if there is a previous file in the loadedPlugins directory and delete
|
// Check if there is a previous file in the loadedPlugins directory and delete
|
||||||
if (File.Exists(filePath))
|
if (SystemIO.File.Exists(filePath))
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Found existing file in loadedPlugins: {0} Deleting and moving new file to replace it", filePath);
|
Debug.LogMessage(LogEventLevel.Information, "Found existing file in loadedPlugins: {0} Deleting and moving new file to replace it", filePath);
|
||||||
File.Delete(filePath);
|
SystemIO.File.Delete(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move the file
|
// Move the file
|
||||||
File.Move(tempFile.FullName, filePath);
|
SystemIO.File.Move(tempFile.FullName, filePath);
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Moved {0} to {1}", tempFile.FullName, filePath);
|
Debug.LogMessage(LogEventLevel.Verbose, "Moved {0} to {1}", tempFile.FullName, filePath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -339,7 +498,7 @@ namespace PepperDash.Essentials
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Delete the .cplz and the temp directory
|
// Delete the .cplz and the temp directory
|
||||||
Directory.Delete(_tempDirectory, true);
|
SystemIO.Directory.Delete(_tempDirectory, true);
|
||||||
zfi.Delete();
|
zfi.Delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,17 +511,41 @@ namespace PepperDash.Essentials
|
|||||||
static void LoadPluginAssemblies()
|
static void LoadPluginAssemblies()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Loading assemblies from loadedPlugins folder...");
|
Debug.LogMessage(LogEventLevel.Information, "Loading assemblies from loadedPlugins folder...");
|
||||||
var pluginDi = new DirectoryInfo(_loadedPluginsDirectoryPath);
|
var pluginDi = new CrestronIO.DirectoryInfo(_loadedPluginsDirectoryPath);
|
||||||
var pluginFiles = pluginDi.GetFiles("*.dll");
|
var pluginFiles = pluginDi.GetFiles("*.dll");
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "Found {0} plugin assemblies to load", pluginFiles.Length);
|
Debug.LogMessage(LogEventLevel.Verbose, "Found {0} plugin assemblies to load", pluginFiles.Length);
|
||||||
|
|
||||||
|
// First, check compatibility of all assemblies before loading any
|
||||||
|
var assemblyCompatibility = new Dictionary<string, (bool IsCompatible, string Reason, List<string> References)>();
|
||||||
|
|
||||||
foreach (var pluginFile in pluginFiles)
|
foreach (var pluginFile in pluginFiles)
|
||||||
{
|
{
|
||||||
var loadedAssembly = LoadAssembly(pluginFile.FullName);
|
string fileName = pluginFile.Name;
|
||||||
|
assemblyCompatibility[fileName] = IsPluginCompatibleWithNet8(pluginFile.FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now load compatible assemblies and track incompatible ones
|
||||||
|
foreach (var pluginFile in pluginFiles)
|
||||||
|
{
|
||||||
|
string fileName = pluginFile.Name;
|
||||||
|
var (isCompatible, reason, references) = assemblyCompatibility[fileName];
|
||||||
|
|
||||||
|
if (!isCompatible)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Warning, "Assembly '{0}' is not compatible with .NET 8: {1}", fileName, reason);
|
||||||
|
IncompatiblePlugins.Add(new IncompatiblePlugin(fileName, reason, null));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to load the assembly
|
||||||
|
var loadedAssembly = LoadAssembly(pluginFile.FullName, null);
|
||||||
|
|
||||||
|
if (loadedAssembly != null)
|
||||||
|
{
|
||||||
LoadedPluginFolderAssemblies.Add(loadedAssembly);
|
LoadedPluginFolderAssemblies.Add(loadedAssembly);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "All Plugins Loaded.");
|
Debug.LogMessage(LogEventLevel.Information, "All Plugins Loaded.");
|
||||||
}
|
}
|
||||||
@@ -373,8 +556,13 @@ namespace PepperDash.Essentials
|
|||||||
static void LoadCustomPluginTypes()
|
static void LoadCustomPluginTypes()
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Loading Custom Plugin Types...");
|
Debug.LogMessage(LogEventLevel.Information, "Loading Custom Plugin Types...");
|
||||||
|
|
||||||
foreach (var loadedAssembly in LoadedPluginFolderAssemblies)
|
foreach (var loadedAssembly in LoadedPluginFolderAssemblies)
|
||||||
{
|
{
|
||||||
|
// Skip if assembly is null (can happen if we had loading issues)
|
||||||
|
if (loadedAssembly == null || loadedAssembly.Assembly == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
// iteratate this assembly's classes, looking for "LoadPlugin()" methods
|
// iteratate this assembly's classes, looking for "LoadPlugin()" methods
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -385,11 +573,49 @@ namespace PepperDash.Essentials
|
|||||||
types = assy.GetTypes();
|
types = assy.GetTypes();
|
||||||
Debug.LogMessage(LogEventLevel.Debug, $"Got types for assembly {assy.GetName().Name}");
|
Debug.LogMessage(LogEventLevel.Debug, $"Got types for assembly {assy.GetName().Name}");
|
||||||
}
|
}
|
||||||
|
catch (ReflectionTypeLoadException e)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Error, "Unable to get types for assembly {0}: {1}",
|
||||||
|
loadedAssembly.Name, e.Message);
|
||||||
|
|
||||||
|
// Check if any of the loader exceptions are due to missing assemblies
|
||||||
|
foreach (var loaderEx in e.LoaderExceptions)
|
||||||
|
{
|
||||||
|
if (loaderEx is SystemIO.FileNotFoundException fileNotFoundEx)
|
||||||
|
{
|
||||||
|
string missingAssembly = fileNotFoundEx.FileName;
|
||||||
|
if (!string.IsNullOrEmpty(missingAssembly))
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Warning, "Assembly {0} requires missing dependency: {1}",
|
||||||
|
loadedAssembly.Name, missingAssembly);
|
||||||
|
|
||||||
|
// Add to incompatible plugins with dependency information
|
||||||
|
IncompatiblePlugins.Add(new IncompatiblePlugin(
|
||||||
|
CrestronIO.Path.GetFileName(missingAssembly),
|
||||||
|
$"Missing dependency required by {loadedAssembly.Name}",
|
||||||
|
loadedAssembly.Name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.LogMessage(LogEventLevel.Verbose, e.StackTrace);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
catch (TypeLoadException e)
|
catch (TypeLoadException e)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Error, "Unable to get types for assembly {0}: {1}",
|
Debug.LogMessage(LogEventLevel.Error, "Unable to get types for assembly {0}: {1}",
|
||||||
loadedAssembly.Name, e.Message);
|
loadedAssembly.Name, e.Message);
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, e.StackTrace);
|
Debug.LogMessage(LogEventLevel.Verbose, e.StackTrace);
|
||||||
|
|
||||||
|
// Add to incompatible plugins if this is likely a .NET 8 compatibility issue
|
||||||
|
if (e.Message.Contains("Could not load type") ||
|
||||||
|
e.Message.Contains("Unable to load one or more of the requested types"))
|
||||||
|
{
|
||||||
|
IncompatiblePlugins.Add(new IncompatiblePlugin(loadedAssembly.Name,
|
||||||
|
$"Type loading error: {e.Message}",
|
||||||
|
null));
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +640,6 @@ namespace PepperDash.Essentials
|
|||||||
loadedAssembly.Name, e.Message, type.Name);
|
loadedAssembly.Name, e.Message, type.Name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -422,14 +647,59 @@ namespace PepperDash.Essentials
|
|||||||
Debug.LogMessage(LogEventLevel.Information, "Error Loading assembly {0}: {1}",
|
Debug.LogMessage(LogEventLevel.Information, "Error Loading assembly {0}: {1}",
|
||||||
loadedAssembly.Name, e.Message);
|
loadedAssembly.Name, e.Message);
|
||||||
Debug.LogMessage(LogEventLevel.Verbose, "{0}", e.StackTrace);
|
Debug.LogMessage(LogEventLevel.Verbose, "{0}", e.StackTrace);
|
||||||
|
|
||||||
|
// Add to incompatible plugins if this is likely a .NET 8 compatibility issue
|
||||||
|
if (e.Message.Contains("Could not load type") ||
|
||||||
|
e.Message.Contains("Unable to load one or more of the requested types"))
|
||||||
|
{
|
||||||
|
IncompatiblePlugins.Add(new IncompatiblePlugin(loadedAssembly.Name,
|
||||||
|
$"Assembly loading error: {e.Message}",
|
||||||
|
null));
|
||||||
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update incompatible plugins with dependency information
|
||||||
|
var pluginDependencies = new Dictionary<string, List<string>>();
|
||||||
|
// Populate pluginDependencies with relevant data
|
||||||
|
// Example: pluginDependencies["PluginA"] = new List<string> { "Dependency1", "Dependency2" };
|
||||||
|
UpdateIncompatiblePluginDependencies(pluginDependencies);
|
||||||
|
|
||||||
// plugin dll will be loaded. Any classes in plugin should have a static constructor
|
// plugin dll will be loaded. Any classes in plugin should have a static constructor
|
||||||
// that registers that class with the Core.DeviceFactory
|
// that registers that class with the Core.DeviceFactory
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Done Loading Custom Plugin Types.");
|
Debug.LogMessage(LogEventLevel.Information, "Done Loading Custom Plugin Types.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates incompatible plugins with information about which plugins depend on them
|
||||||
|
/// </summary>
|
||||||
|
private static void UpdateIncompatiblePluginDependencies(Dictionary<string, List<string>> pluginDependencies)
|
||||||
|
{
|
||||||
|
// For each incompatible plugin
|
||||||
|
foreach (var incompatiblePlugin in IncompatiblePlugins)
|
||||||
|
{
|
||||||
|
// If it already has a requestedBy, skip it
|
||||||
|
if (incompatiblePlugin.TriggeredBy != "Direct load")
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Find plugins that depend on this incompatible plugin
|
||||||
|
foreach (var plugin in pluginDependencies)
|
||||||
|
{
|
||||||
|
string pluginName = plugin.Key;
|
||||||
|
List<string> dependencies = plugin.Value;
|
||||||
|
|
||||||
|
// If this plugin depends on the incompatible plugin
|
||||||
|
if (dependencies.Contains(incompatiblePlugin.Name) ||
|
||||||
|
dependencies.Any(d => d.StartsWith(incompatiblePlugin.Name + ",")))
|
||||||
|
{
|
||||||
|
incompatiblePlugin.UpdateTriggeringPlugin(pluginName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads a
|
/// Loads a
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -506,7 +776,6 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Loading legacy plugin: {0}", loadedAssembly.Name);
|
Debug.LogMessage(LogEventLevel.Information, "Loading legacy plugin: {0}", loadedAssembly.Name);
|
||||||
loadPlugin.Invoke(null, null);
|
loadPlugin.Invoke(null, null);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -516,7 +785,7 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Attempting to Load Plugins from {_pluginDirectory}", _pluginDirectory);
|
Debug.LogMessage(LogEventLevel.Information, "Attempting to Load Plugins from {_pluginDirectory}", _pluginDirectory);
|
||||||
|
|
||||||
if (Directory.Exists(_pluginDirectory))
|
if (SystemIO.Directory.Exists(_pluginDirectory))
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Plugins directory found, checking for plugins");
|
Debug.LogMessage(LogEventLevel.Information, "Plugins directory found, checking for plugins");
|
||||||
|
|
||||||
@@ -526,7 +795,7 @@ namespace PepperDash.Essentials
|
|||||||
// Deal with any .cplz files
|
// Deal with any .cplz files
|
||||||
UnzipAndMoveCplzArchives();
|
UnzipAndMoveCplzArchives();
|
||||||
|
|
||||||
if (Directory.Exists(_loadedPluginsDirectoryPath))
|
if (SystemIO.Directory.Exists(_loadedPluginsDirectoryPath))
|
||||||
{
|
{
|
||||||
// Load the assemblies from the loadedPlugins folder into the AppDomain
|
// Load the assemblies from the loadedPlugins folder into the AppDomain
|
||||||
LoadPluginAssemblies();
|
LoadPluginAssemblies();
|
||||||
@@ -534,9 +803,27 @@ namespace PepperDash.Essentials
|
|||||||
// Load the types from any custom plugin assemblies
|
// Load the types from any custom plugin assemblies
|
||||||
LoadCustomPluginTypes();
|
LoadCustomPluginTypes();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Report on incompatible plugins
|
||||||
|
if (IncompatiblePlugins.Count > 0)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Warning, "Found {0} incompatible plugins:", IncompatiblePlugins.Count);
|
||||||
|
foreach (var plugin in IncompatiblePlugins)
|
||||||
|
{
|
||||||
|
if (plugin.TriggeredBy != "Direct load")
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Warning, " - {0}: {1} (Required by: {2})",
|
||||||
|
plugin.Name, plugin.Reason, plugin.TriggeredBy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Warning, " - {0}: {1}",
|
||||||
|
plugin.Name, plugin.Reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -563,4 +850,52 @@ namespace PepperDash.Essentials
|
|||||||
Assembly = assembly;
|
Assembly = assembly;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a plugin that was found to be incompatible with .NET 8
|
||||||
|
/// </summary>
|
||||||
|
public class IncompatiblePlugin
|
||||||
|
{
|
||||||
|
[JsonProperty("name")]
|
||||||
|
public string Name { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty("reason")]
|
||||||
|
public string Reason { get; private set; }
|
||||||
|
|
||||||
|
[JsonProperty("triggeredBy")]
|
||||||
|
public string TriggeredBy { get; private set; }
|
||||||
|
|
||||||
|
public IncompatiblePlugin(string name, string reason, string triggeredBy = null)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Reason = reason;
|
||||||
|
TriggeredBy = triggeredBy ?? "Direct load";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the plugin that triggered this incompatibility
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="triggeringPlugin">Name of the plugin that requires this incompatible plugin</param>
|
||||||
|
public void UpdateTriggeringPlugin(string triggeringPlugin)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(triggeringPlugin))
|
||||||
|
{
|
||||||
|
TriggeredBy = triggeringPlugin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attribute to explicitly mark a plugin as .NET 8 compatible
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Assembly)]
|
||||||
|
public class Net8CompatibleAttribute : Attribute
|
||||||
|
{
|
||||||
|
public bool IsCompatible { get; }
|
||||||
|
|
||||||
|
public Net8CompatibleAttribute(bool isCompatible = true)
|
||||||
|
{
|
||||||
|
IsCompatible = isCompatible;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
37
src/PepperDash.Essentials.Core/SomeWebSocketClass.cs
Normal file
37
src/PepperDash.Essentials.Core/SomeWebSocketClass.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public class SomeWebSocketClass
|
||||||
|
{
|
||||||
|
private ClientWebSocket _webSocket;
|
||||||
|
|
||||||
|
public SomeWebSocketClass()
|
||||||
|
{
|
||||||
|
_webSocket = new ClientWebSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ConnectAsync(Uri uri)
|
||||||
|
{
|
||||||
|
await _webSocket.ConnectAsync(uri, CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendAsync(string message)
|
||||||
|
{
|
||||||
|
var buffer = System.Text.Encoding.UTF8.GetBytes(message);
|
||||||
|
await _webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> ReceiveAsync()
|
||||||
|
{
|
||||||
|
var buffer = new byte[1024];
|
||||||
|
var result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
return System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CloseAsync()
|
||||||
|
{
|
||||||
|
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,11 +10,14 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using PepperDash.Essentials.Core.Web.RequestHandlers;
|
||||||
|
|
||||||
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||||
{
|
{
|
||||||
public class DebugSessionRequestHandler : WebApiBaseRequestHandler
|
public class DebugSessionRequestHandler : WebApiBaseRequestHandler
|
||||||
{
|
{
|
||||||
|
private readonly DebugWebsocketSink _sink = new DebugWebsocketSink();
|
||||||
|
|
||||||
public DebugSessionRequestHandler()
|
public DebugSessionRequestHandler()
|
||||||
: base(true)
|
: base(true)
|
||||||
{
|
{
|
||||||
@@ -43,21 +46,21 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
|||||||
|
|
||||||
var port = 0;
|
var port = 0;
|
||||||
|
|
||||||
if (!Debug.WebsocketSink.IsRunning)
|
if (!_sink.IsRunning)
|
||||||
{
|
{
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Starting WS Server");
|
Debug.LogMessage(LogEventLevel.Information, "Starting WS Server");
|
||||||
// Generate a random port within a specified range
|
// Generate a random port within a specified range
|
||||||
port = new Random().Next(65435, 65535);
|
port = new Random().Next(65435, 65535);
|
||||||
// Start the WS Server
|
// Start the WS Server
|
||||||
Debug.WebsocketSink.StartServerAndSetPort(port);
|
_sink.StartServerAndSetPort(port);
|
||||||
Debug.SetWebSocketMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose);
|
Debug.SetWebSocketMinimumDebugLevel(Serilog.Events.LogEventLevel.Verbose);
|
||||||
}
|
}
|
||||||
|
|
||||||
var url = Debug.WebsocketSink.Url;
|
var url = _sink.Url;
|
||||||
|
|
||||||
object data = new
|
object data = new
|
||||||
{
|
{
|
||||||
url = Debug.WebsocketSink.Url
|
url = _sink.Url
|
||||||
};
|
};
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Debug Session URL: {0}", url);
|
Debug.LogMessage(LogEventLevel.Information, "Debug Session URL: {0}", url);
|
||||||
@@ -84,7 +87,7 @@ namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
|||||||
/// <param name="context"></param>
|
/// <param name="context"></param>
|
||||||
protected override void HandlePost(HttpCwsContext context)
|
protected override void HandlePost(HttpCwsContext context)
|
||||||
{
|
{
|
||||||
Debug.WebsocketSink.StopServer();
|
_sink.StopServer();
|
||||||
|
|
||||||
context.Response.StatusCode = 200;
|
context.Response.StatusCode = 200;
|
||||||
context.Response.StatusDescription = "OK";
|
context.Response.StatusDescription = "OK";
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Core.Web.RequestHandlers
|
||||||
|
{
|
||||||
|
public class DebugWebsocketSink
|
||||||
|
{
|
||||||
|
private bool _isRunning;
|
||||||
|
private string _url;
|
||||||
|
|
||||||
|
public bool IsRunning => _isRunning;
|
||||||
|
public string Url => _url;
|
||||||
|
|
||||||
|
public void StartServerAndSetPort(int port)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_url = $"ws://localhost:{port}";
|
||||||
|
_isRunning = true;
|
||||||
|
// Implement actual server startup logic here
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_isRunning = false;
|
||||||
|
throw new Exception($"Failed to start debug websocket server: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StopServer()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Implement actual server shutdown logic here
|
||||||
|
_isRunning = false;
|
||||||
|
_url = null;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new Exception($"Failed to stop debug websocket server: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
<Configurations>Debug;Release;Debug 4.7.2</Configurations>
|
<Configurations>Debug;Release;Debug 4.7.2</Configurations>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFrameworks>net472;net6</TargetFrameworks>
|
<TargetFramework>net8</TargetFramework>
|
||||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<AssemblyName>Essentials Devices Common</AssemblyName>
|
<AssemblyName>Essentials Devices Common</AssemblyName>
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
|
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.20.66" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.ProgramLibrary" Version="2.21.90" />
|
||||||
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-451" />
|
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-462" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public class SomeOtherWebSocketClass
|
||||||
|
{
|
||||||
|
private ClientWebSocket _webSocket;
|
||||||
|
|
||||||
|
public SomeOtherWebSocketClass()
|
||||||
|
{
|
||||||
|
_webSocket = new ClientWebSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ConnectAsync(Uri uri)
|
||||||
|
{
|
||||||
|
await _webSocket.ConnectAsync(uri, CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendAsync(string message)
|
||||||
|
{
|
||||||
|
var buffer = System.Text.Encoding.UTF8.GetBytes(message);
|
||||||
|
await _webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> ReceiveAsync()
|
||||||
|
{
|
||||||
|
var buffer = new byte[1024];
|
||||||
|
var result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
return System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CloseAsync()
|
||||||
|
{
|
||||||
|
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
using Crestron.SimplSharp.Reflection;
|
using System.Reflection;
|
||||||
using Crestron.SimplSharpPro.DeviceSupport;
|
using Crestron.SimplSharpPro.DeviceSupport;
|
||||||
using Crestron.SimplSharp;
|
using Crestron.SimplSharp;
|
||||||
using PepperDash.Core;
|
using PepperDash.Core;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
|
using Crestron.SimplSharp;
|
||||||
using Crestron.SimplSharp;
|
|
||||||
using Crestron.SimplSharp.CrestronIO;
|
using Crestron.SimplSharp.CrestronIO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Crestron.SimplSharpPro;
|
using Crestron.SimplSharpPro;
|
||||||
@@ -28,7 +27,9 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
public ControlSystem()
|
public ControlSystem()
|
||||||
: base()
|
: base()
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
Thread.MaxNumberOfUserThreads = 400;
|
Thread.MaxNumberOfUserThreads = 400;
|
||||||
Global.ControlSystem = this;
|
Global.ControlSystem = this;
|
||||||
DeviceManager.Initialize(this);
|
DeviceManager.Initialize(this);
|
||||||
@@ -96,6 +97,9 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
DeterminePlatform();
|
DeterminePlatform();
|
||||||
|
|
||||||
|
// Print .NET runtime version
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, "Running on .NET runtime version: {0}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription);
|
||||||
|
|
||||||
if (Debug.DoNotLoadConfigOnNextBoot)
|
if (Debug.DoNotLoadConfigOnNextBoot)
|
||||||
{
|
{
|
||||||
CrestronConsole.AddNewConsoleCommand(s => CrestronInvoke.BeginInvoke((o) => GoWithLoad()), "go", "Loads configuration file",
|
CrestronConsole.AddNewConsoleCommand(s => CrestronInvoke.BeginInvoke((o) => GoWithLoad()), "go", "Loads configuration file",
|
||||||
@@ -144,7 +148,7 @@ namespace PepperDash.Essentials
|
|||||||
CrestronConsole.AddNewConsoleCommand(DeviceManager.GetRoutingPorts,
|
CrestronConsole.AddNewConsoleCommand(DeviceManager.GetRoutingPorts,
|
||||||
"getroutingports", "Reports all routing ports, if any. Requires a device key", ConsoleAccessLevelEnum.AccessOperator);
|
"getroutingports", "Reports all routing ports, if any. Requires a device key", ConsoleAccessLevelEnum.AccessOperator);
|
||||||
|
|
||||||
DeviceManager.AddDevice(new EssentialsWebApi("essentialsWebApi", "Essentials Web API"));
|
//DeviceManager.AddDevice(new EssentialsWebApi("essentialsWebApi", "Essentials Web API"));
|
||||||
|
|
||||||
if (!Debug.DoNotLoadConfigOnNextBoot)
|
if (!Debug.DoNotLoadConfigOnNextBoot)
|
||||||
{
|
{
|
||||||
@@ -181,24 +185,10 @@ namespace PepperDash.Essentials
|
|||||||
|
|
||||||
if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) // Handles 3-series running Windows CE OS
|
if (CrestronEnvironment.DevicePlatform != eDevicePlatform.Server) // Handles 3-series running Windows CE OS
|
||||||
{
|
{
|
||||||
string userFolder;
|
string userFolder = "user";
|
||||||
string nvramFolder;
|
string nvramFolder = "nvram";
|
||||||
bool is4series = false;
|
|
||||||
|
|
||||||
if (eCrestronSeries.Series4 == (Global.ProcessorSeries & eCrestronSeries.Series4)) // Handle 4-series
|
Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{version:l} on {processorSeries:l} Appliance", Global.AssemblyVersion, "4-series");
|
||||||
{
|
|
||||||
is4series = true;
|
|
||||||
// Set path to user/
|
|
||||||
userFolder = "user";
|
|
||||||
nvramFolder = "nvram";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
userFolder = "User";
|
|
||||||
nvramFolder = "Nvram";
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{version:l} on {processorSeries:l} Appliance", Global.AssemblyVersion, is4series ? "4-series" : "3-series");
|
|
||||||
//Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{0} on {1} Appliance", Global.AssemblyVersion, is4series ? "4-series" : "3-series");
|
//Debug.LogMessage(LogEventLevel.Information, "Starting Essentials v{0} on {1} Appliance", Global.AssemblyVersion, is4series ? "4-series" : "3-series");
|
||||||
|
|
||||||
// Check if User/ProgramX exists
|
// Check if User/ProgramX exists
|
||||||
@@ -360,6 +350,7 @@ namespace PepperDash.Essentials
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
||||||
void Load()
|
void Load()
|
||||||
{
|
{
|
||||||
LoadDevices();
|
LoadDevices();
|
||||||
@@ -480,7 +471,16 @@ namespace PepperDash.Essentials
|
|||||||
{
|
{
|
||||||
var room = Core.DeviceFactory.GetDevice(roomConfig);
|
var room = Core.DeviceFactory.GetDevice(roomConfig);
|
||||||
|
|
||||||
|
if(room == null)
|
||||||
|
{
|
||||||
|
Debug.LogMessage(LogEventLevel.Information, "ERROR: Cannot load unknown room type '{roomType:l}', key '{roomKey:l}'.", roomConfig.Type, roomConfig.Key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
DeviceManager.AddDevice(room);
|
DeviceManager.AddDevice(room);
|
||||||
|
}
|
||||||
|
|
||||||
if (room is ICustomMobileControl)
|
if (room is ICustomMobileControl)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Net.WebSockets;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PepperDash.Essentials.Fusion
|
||||||
|
{
|
||||||
|
public class EssentialsHuddleSpaceFusionSystemControllerBase
|
||||||
|
{
|
||||||
|
private ClientWebSocket _webSocket;
|
||||||
|
|
||||||
|
public EssentialsHuddleSpaceFusionSystemControllerBase()
|
||||||
|
{
|
||||||
|
_webSocket = new ClientWebSocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ConnectAsync(Uri uri)
|
||||||
|
{
|
||||||
|
await _webSocket.ConnectAsync(uri, CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SendAsync(string message)
|
||||||
|
{
|
||||||
|
var buffer = System.Text.Encoding.UTF8.GetBytes(message);
|
||||||
|
await _webSocket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> ReceiveAsync()
|
||||||
|
{
|
||||||
|
var buffer = new byte[1024];
|
||||||
|
var result = await _webSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||||
|
return System.Text.Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CloseAsync()
|
||||||
|
{
|
||||||
|
await _webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,15 +6,18 @@
|
|||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<RootNamespace>PepperDash.Essentials</RootNamespace>
|
<RootNamespace>PepperDash.Essentials</RootNamespace>
|
||||||
<AssemblyName>PepperDashEssentials</AssemblyName>
|
<AssemblyName>PepperDashEssentials</AssemblyName>
|
||||||
<TargetFrameworks>net472</TargetFrameworks>
|
<TargetFramework>net8</TargetFramework>
|
||||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
<OutputPath>$(ProjectDir)bin\$(Configuration)\</OutputPath>
|
||||||
<Title>PepperDash Essentials</Title>
|
<Title>PepperDash Essentials</Title>
|
||||||
<PackageId>PepperDashEssentials</PackageId>
|
<PackageId>PepperDashEssentials</PackageId>
|
||||||
<Version>2.0.0-local</Version>
|
<Version>2.0.0-local</Version>
|
||||||
<InformationalVersion>$(Version)</InformationalVersion>
|
<InformationalVersion>$(Version)</InformationalVersion>
|
||||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<ProjectType>Program</ProjectType>
|
||||||
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
<DebugType>full</DebugType>
|
<DebugType>full</DebugType>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
@@ -48,8 +51,8 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Crestron.SimplSharp.SDK.Program" Version="2.20.66" />
|
<PackageReference Include="Crestron.SimplSharp.SDK.Program" Version="2.21.90" />
|
||||||
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-451" />
|
<PackageReference Include="PepperDashCore" Version="2.0.0-alpha-462" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
|
<ProjectReference Include="..\PepperDash.Essentials.Core\PepperDash.Essentials.Core.csproj" />
|
||||||
|
|||||||
Reference in New Issue
Block a user