Custom Windows Client Generator #1042
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Custom Windows Client Generator | |
run-name: Custom Windows Client Generator | |
on: | |
workflow_dispatch: | |
inputs: | |
server: | |
description: 'Rendezvous Server' | |
required: true | |
default: '' | |
type: string | |
key: | |
description: 'Public Key' | |
required: true | |
default: '' | |
type: string | |
apiServer: | |
description: 'API Server' | |
required: true | |
default: '' | |
type: string | |
custom: | |
description: "Custom JSON" | |
required: true | |
default: '' | |
type: string | |
uuid: | |
description: "uuid of request" | |
required: true | |
default: '' | |
type: string | |
iconlink: | |
description: "icon link" | |
required: false | |
default: 'false' | |
type: string | |
logolink: | |
description: "logo link" | |
required: false | |
default: 'false' | |
type: string | |
appname: | |
description: "app name" | |
required: true | |
default: 'rustdesk' | |
type: string | |
filename: | |
description: "Filename" | |
required: true | |
default: 'rustdesk' | |
type: string | |
extras: | |
description: "extra inputs in json" | |
required: true | |
default: '{}' | |
type: string | |
env: | |
SCITER_RUST_VERSION: "1.75" # https://github.com/rustdesk/rustdesk/discussions/7503, also 1.78 has ABI change which causes our sciter version not working, https://blog.rust-lang.org/2024/03/30/i128-layout-update.html | |
RUST_VERSION: "1.75" # sciter failed on m1 with 1.78 because of https://blog.rust-lang.org/2024/03/30/i128-layout-update.html | |
CARGO_NDK_VERSION: "3.1.2" | |
SCITER_ARMV7_CMAKE_VERSION: "3.29.7" | |
SCITER_NASM_DEBVERSION: "2.14-1" | |
LLVM_VERSION: "15.0.6" | |
FLUTTER_VERSION: "3.24.5" | |
ANDROID_FLUTTER_VERSION: "3.24.5" | |
FLUTTER_RUST_BRIDGE_VERSION: "1.80.1" | |
# for arm64 linux because official Dart SDK does not work | |
FLUTTER_ELINUX_VERSION: "3.16.9" | |
TAG_NAME: "${{ inputs.upload-tag }}" | |
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" | |
# vcpkg version: 2024.07.12 | |
VCPKG_COMMIT_ID: "b2cb0da531c2f1f740045bfe7c4dac59f0b2b69c" | |
VERSION: "${{ fromJson(inputs.extras).version }}" | |
NDK_VERSION: "r27c" | |
#signing keys env variable checks | |
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}" | |
MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}" | |
UPLOAD_ARTIFACT: 'true' | |
SIGN_BASE_URL: "${{ secrets.SIGN_BASE_URL }}" | |
STATUS_URL: "${{ secrets.GENURL }}/updategh" | |
jobs: | |
generate-bridge: | |
uses: ./.github/workflows/bridge.yml | |
with: | |
version: ${{ fromJson(inputs.extras).version }} | |
build-RustDeskTempTopMostWindow: | |
uses: ./.github/workflows/third-party-RustDeskTempTopMostWindow.yml | |
with: | |
upload-artifact: true | |
target: windows-2022 | |
configuration: Release | |
platform: x64 | |
target_version: Windows10 | |
strategy: | |
fail-fast: false | |
build-for-windows-flutter: | |
name: Build Windows | |
needs: [build-RustDeskTempTopMostWindow, generate-bridge] | |
runs-on: ${{ matrix.job.os }} | |
strategy: | |
fail-fast: false | |
matrix: | |
job: | |
# - { target: i686-pc-windows-msvc , os: windows-2022 } | |
# - { target: x86_64-pc-windows-gnu , os: windows-2022 } | |
- { | |
target: x86_64-pc-windows-msvc, | |
os: windows-2022, | |
arch: x86_64, | |
vcpkg-triplet: x64-windows-static, | |
} | |
# - { target: aarch64-pc-windows-msvc, os: windows-2022, arch: aarch64 } | |
steps: | |
- name: Export GitHub Actions cache environment variables | |
uses: actions/github-script@v6 | |
with: | |
script: | | |
core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); | |
core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); | |
- name: Set rdgen value | |
if: ${{ fromJson(inputs.extras).rdgen == 'true' }} | |
run: | | |
echo "STATUS_URL=${{ secrets.GENURL }}/updategh" >> $env:GITHUB_ENV | |
- name: Set rdgen value | |
if: ${{ fromJson(inputs.extras).rdgen == 'false' }} | |
run: | | |
echo "STATUS_URL=${{ inputs.apiServer }}/api/updategh" >> $env:GITHUB_ENV | |
- name: Report Status | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "5% complete"}' | |
- name: Checkout source code | |
if: ${{ env.VERSION != 'master' }} | |
uses: actions/checkout@v4 | |
with: | |
repository: rustdesk/rustdesk | |
ref: refs/tags/${{ env.VERSION }} | |
submodules: recursive | |
- name: Checkout source code | |
if: ${{ env.VERSION == 'master' }} | |
uses: actions/checkout@v4 | |
with: | |
repository: rustdesk/rustdesk | |
submodules: recursive | |
- name: Restore bridge files | |
uses: actions/download-artifact@master | |
with: | |
name: bridge-artifact | |
path: ./ | |
- name: Install ImageMagick on Windows | |
run: | | |
choco install -y imagemagick.app --no-progress | |
Get-ChildItem -Path "${env:ProgramFiles}" | % { $_.FullName } | Select-String -Pattern "[\/\\]ImageMagick[^\/\\]*$" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8 | |
- name: change appname to custom | |
if: inputs.appname != 'rustdesk' | |
continue-on-error: true | |
shell: bash | |
run: | | |
# ./Cargo.toml | |
sed -i -e 's|description = "RustDesk Remote Desktop"|description = "${{ inputs.appname }}"|' ./Cargo.toml | |
sed -i -e 's|ProductName = "RustDesk"|ProductName = "${{ inputs.appname }}"|' ./Cargo.toml | |
sed -i -e 's|FileDescription = "RustDesk Remote Desktop"|FileDescription = "${{ inputs.appname }}"|' ./Cargo.toml | |
sed -i -e 's|OriginalFilename = "rustdesk.exe"|OriginalFilename = "${{ inputs.appname }}.exe"|' ./Cargo.toml | |
# ./libs/portable/Cargo.toml | |
sed -i -e 's|description = "RustDesk Remote Desktop"|description = "${{ inputs.appname }}"|' ./libs/portable/Cargo.toml | |
sed -i -e 's|ProductName = "RustDesk"|ProductName = "${{ inputs.appname }}"|' ./libs/portable/Cargo.toml | |
sed -i -e 's|FileDescription = "RustDesk Remote Desktop"|FileDescription = "${{ inputs.appname }}"|' ./libs/portable/Cargo.toml | |
sed -i -e 's|OriginalFilename = "rustdesk.exe"|OriginalFilename = "${{ inputs.appname }}.exe"|' ./libs/portable/Cargo.toml | |
# ./flutter/windows/runner/Runner.rc | |
sed -i -e 's|"RustDesk Remote Desktop"|"${{ inputs.appname }}"|' ./flutter/windows/runner/Runner.rc | |
sed -i -e 's|VALUE "InternalName", "rustdesk" "\0"|VALUE "InternalName", "${{ inputs.appname }}" "\0"|' ./flutter/windows/runner/Runner.rc | |
sed -i -e 's|"rustdesk.exe"|"${{ inputs.filename }}"|' ./flutter/windows/runner/Runner.rc | |
sed -i -e 's|"RustDesk"|"${{ inputs.appname }}"|' ./flutter/windows/runner/Runner.rc | |
# ./src/lang/en.rs | |
find ./src/lang -name "*.rs" -exec sed -i -e 's|RustDesk|${{ inputs.appname }}|' {} \; | |
- name: change company name | |
if: fromJson(inputs.extras).compname != 'Purslane Ltd' | |
continue-on-error: true | |
shell: bash | |
run: | | |
sed -i -e 's|Purslane Ltd|${{ fromJson(inputs.extras).compname }}|' ./flutter/lib/desktop/pages/desktop_setting_page.dart | |
sed -i -e 's|Purslane Ltd.|${{ fromJson(inputs.extras).compname }}|' ./res/setup.nsi | |
sed -i -e 's|PURSLANE|${{ fromJson(inputs.extras).compname }}|' ./res/msi/preprocess.py | |
sed -i -e 's|Purslane Ltd|${{ fromJson(inputs.extras).compname }}|' ./res/msi/preprocess.py | |
sed -i -e 's|"Copyright © 2025 Purslane Ltd. All rights reserved."|"Copyright © 2025 ${{ fromJson(inputs.extras).compname }}. All rights reserved."|' ./flutter/windows/runner/Runner.rc | |
sed -i -e 's|Purslane Ltd|${{ fromJson(inputs.extras).compname }}|' ./flutter/windows/runner/Runner.rc | |
sed -i -e 's|Purslane Ltd|${{ fromJson(inputs.extras).compname }}|' ./Cargo.toml | |
sed -i -e 's|Purslane Ltd|${{ fromJson(inputs.extras).compname }}|' ./libs/portable/Cargo.toml | |
- name: change url to custom | |
if: fromJson(inputs.extras).urlLink != 'https://rustdesk.com' | |
continue-on-error: true | |
shell: bash | |
run: | | |
sed -i -e 's|Homepage: https://rustdesk.com|Homepage: ${{ fromJson(inputs.extras).urlLink }}|' ./build.py | |
sed -i -e "s|launchUrl(Uri.parse('https://rustdesk.com'));|launchUrl(Uri.parse('${{ fromJson(inputs.extras).urlLink }}'));|" ./flutter/lib/common.dart | |
sed -i -e "s|launchUrlString('https://rustdesk.com');|launchUrlString('${{ fromJson(inputs.extras).urlLink }}');|" ./flutter/lib/desktop/pages/desktop_setting_page.dart | |
sed -i -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ fromJson(inputs.extras).urlLink }}/privacy.html')|" ./flutter/lib/desktop/pages/desktop_setting_page.dart | |
sed -i -e "s|const url = 'https://rustdesk.com/';|const url = '${{ fromJson(inputs.extras).urlLink }}';|" ./flutter/lib/mobile/pages/settings_page.dart | |
sed -i -e "s|launchUrlString('https://rustdesk.com/privacy.html')|launchUrlString('${{ fromJson(inputs.extras).urlLink }}/privacy.html')|" ./flutter/lib/mobile/pages/settings_page.dart | |
sed -i -e "s|https://rustdesk.com/privacy.html|${{ fromJson(inputs.extras).urlLink }}/privacy.html|" ./flutter/lib/desktop/pages/install_page.dart | |
sed -i -e "s|https://rustdesk.com/|${{fromJson(inputs.extras).urlLink }}|" ./res/setup.nsi | |
- name: change download link to custom | |
if: fromJson(inputs.extras).downloadLink != 'https://rustdesk.com/download' | |
continue-on-error: true | |
shell: bash | |
run: | | |
sed -i -e 's|https://rustdesk.com/download|${{ fromJson(inputs.extras).downloadLink }}|' ./flutter/lib/desktop/pages/desktop_home_page.dart | |
sed -i -e 's|https://rustdesk.com/download|${{ fromJson(inputs.extras).downloadLink }}|' ./flutter/lib/mobile/pages/connection_page.dart | |
sed -i -e 's|https://rustdesk.com/download|${{ fromJson(inputs.extras).downloadLink }}|' ./src/ui/index.tis | |
- name: set server, key, and apiserver | |
continue-on-error: true | |
shell: bash | |
run: | | |
sed -i -e 's|rs-ny.rustdesk.com|${{ inputs.server }}|' ./libs/hbb_common/src/config.rs | |
sed -i -e 's|OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw=|${{ inputs.key }}|' ./libs/hbb_common/src/config.rs | |
sed -i -e 's|https://admin.rustdesk.com|${{ inputs.apiServer }}|' ./src/common.rs | |
# ./flutter/pubspec.yaml | |
sed -i '/intl:/a \ \ archive: ^3.6.1' ./flutter/pubspec.yaml | |
- name: allow custom.txt | |
continue-on-error: true | |
run: | | |
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/allowCustom.diff -OutFile allowCustom.diff | |
git apply allowCustom.diff | |
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/removeSetupServerTip.diff -OutFile removeSetupServerTip.diff | |
git apply removeSetupServerTip.diff | |
- name: Install LLVM and Clang | |
uses: KyleMayes/install-llvm-action@v1 | |
with: | |
version: ${{ env.LLVM_VERSION }} | |
- name: Report Status | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "10% complete"}' | |
- name: Install flutter | |
uses: subosito/[email protected] #https://github.com/subosito/flutter-action/issues/277 | |
with: | |
channel: "stable" | |
flutter-version: ${{ env.FLUTTER_VERSION }} | |
# https://github.com/flutter/flutter/issues/155685 | |
- name: Replace engine with rustdesk custom flutter engine | |
run: | | |
flutter doctor -v | |
flutter precache --windows | |
Invoke-WebRequest -Uri https://github.com/rustdesk/engine/releases/download/main/windows-x64-release.zip -OutFile windows-x64-release.zip | |
Expand-Archive -Path windows-x64-release.zip -DestinationPath windows-x64-release | |
mv -Force windows-x64-release/* C:/hostedtoolcache/windows/flutter/stable-${{ env.FLUTTER_VERSION }}-x64/bin/cache/artifacts/engine/windows-x64-release/ | |
- name: Patch flutter | |
continue-on-error: true | |
shell: bash | |
run: | | |
cp .github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff $(dirname $(dirname $(which flutter))) | |
cd $(dirname $(dirname $(which flutter))) | |
[[ "3.24.5" == ${{env.FLUTTER_VERSION}} ]] && git apply flutter_3.24.4_dropdown_menu_enableFilter.diff | |
- name: Install Rust toolchain | |
uses: dtolnay/rust-toolchain@v1 | |
with: | |
toolchain: ${{ env.SCITER_RUST_VERSION }} | |
targets: ${{ matrix.job.target }} | |
components: "rustfmt" | |
- name: Report Status | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "15% complete"}' | |
- uses: Swatinem/rust-cache@v2 | |
with: | |
prefix-key: ${{ matrix.job.os }} | |
- name: Report Status | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "20% complete"}' | |
- name: Setup vcpkg with Github Actions binary cache | |
uses: lukka/run-vcpkg@v11 | |
with: | |
vcpkgDirectory: C:\vcpkg | |
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }} | |
doNotCache: false | |
- name: Install vcpkg dependencies | |
env: | |
VCPKG_DEFAULT_HOST_TRIPLET: ${{ matrix.job.vcpkg-triplet }} | |
run: | | |
if ! $VCPKG_ROOT/vcpkg \ | |
install \ | |
--triplet ${{ matrix.job.vcpkg-triplet }} \ | |
--x-install-root="$VCPKG_ROOT/installed"; then | |
find "${VCPKG_ROOT}/" -name "*.log" | while read -r _1; do | |
echo "$_1:" | |
echo "======" | |
cat "$_1" | |
echo "======" | |
echo "" | |
done | |
exit 1 | |
fi | |
head -n 100 "${VCPKG_ROOT}/buildtrees/ffmpeg/build-${{ matrix.job.vcpkg-triplet }}-rel-out.log" || true | |
shell: bash | |
- name: icon stuff | |
if: ${{ inputs.iconlink != 'false' }} | |
continue-on-error: true | |
shell: bash | |
run: | | |
mv ./res/icon.ico ./res/icon.ico.bak | |
mv ./res/icon.png ./res/icon.png.bak | |
mv ./res/tray-icon.ico ./res/tray-icon.ico.bak | |
- name: magick stuff | |
if: ${{ inputs.iconlink != 'false' }} | |
continue-on-error: true | |
run: | | |
Invoke-WebRequest -Uri ${{ fromJson(inputs.iconlink).url }}/get_png?filename=${{ fromJson(inputs.iconlink).file }}"&"uuid=${{ fromJson(inputs.iconlink).uuid }} -OutFile ./res/icon.png | |
mv ./res/32x32.png ./res/32x32.png.bak | |
mv ./res/64x64.png ./res/64x64.png.bak | |
mv ./res/128x128.png ./res/128x128.png.bak | |
mv ./res/[email protected] ./res/[email protected] | |
magick ./res/icon.png -define icon:auto-resize=256,64,48,32,16 ./res/icon.ico | |
cp ./res/icon.ico ./res/tray-icon.ico | |
magick ./res/icon.png -resize 32x32 ./res/32x32.png | |
magick ./res/icon.png -resize 64x64 ./res/64x64.png | |
magick ./res/icon.png -resize 128x128 ./res/128x128.png | |
magick ./res/128x128.png -resize 200% ./res/[email protected] | |
- name: ui.rs icon | |
if: ${{ inputs.iconlink != 'false' }} | |
continue-on-error: true | |
shell: bash | |
run: | | |
cp ./src/ui.rs ./src/ui.rs.bak | |
b64=$(base64 < ./res/icon.png) | |
sed -i -e 's|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|$(echo "$b64")|' ./src/ui.rs | |
b64="" | |
- name: fix connection delay | |
continue-on-error: true | |
if: ${{ fromJson(inputs.extras).delayFix == 'true' }} | |
shell: bash | |
run: | | |
sed -i -e '/if !key.is_empty() && !token.is_empty() {/,/}/d' ./src/client.rs | |
- name: add cycle monitors to toolbar | |
continue-on-error: true | |
if: fromJson(inputs.extras).cycleMonitor == 'true' | |
run: | | |
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/cycle_monitor.diff -OutFile cycle_monitor.diff | |
git apply cycle_monitor.diff | |
- name: use X for offline display instead of orange circle | |
continue-on-error: true | |
if: fromJson(inputs.extras).xOffline == 'true' | |
run: | | |
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/xoffline.diff -OutFile xoffline.diff | |
git apply xoffline.diff | |
- name: hide-cm | |
continue-on-error: true | |
if: fromJson(inputs.extras).hidecm == 'true' | |
run: | | |
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/hidecm.diff -OutFile hidecm.diff | |
git apply hidecm.diff | |
- name: statussort | |
continue-on-error: true | |
if: fromJson(inputs.extras).statussort == 'true' | |
run: | | |
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/statussort.diff -OutFile statussort.diff | |
git apply statussort.diff | |
- name: removeNewVersionNotif | |
continue-on-error: true | |
if: fromJson(inputs.extras).removeNewVersionNotif == 'true' | |
run: | | |
Invoke-WebRequest -Uri https://raw.githubusercontent.com/bryangerlach/rdgen/refs/heads/master/.github/patches/removeNewVersionNotif.diff -Outfile removeNewVersionNotif.diff | |
git apply removeNewVersionNotif.diff | |
- name: run as admin | |
continue-on-error: true | |
if: ${{ fromJson(inputs.extras).runasadmin == 'true' }} | |
shell: bash | |
run: | | |
echo "SET_TARGET_PROPERTIES(\${BINARY_NAME} PROPERTIES LINK_FLAGS \"/MANIFESTUAC:\\\"level='requireAdministrator' uiAccess='false'\\\" /SUBSYSTEM:WINDOWS\")" >> ./flutter/windows/runner/CMakeLists.txt | |
sed -i '/administrator/d' res/manifest.xml | |
- name: Report Status | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "25% complete"}' | |
- name: replace flutter icons | |
if: ${{ inputs.iconlink != 'false' }} | |
continue-on-error: true | |
run: | | |
cd ./flutter | |
flutter pub upgrade win32 | |
flutter pub get | |
flutter pub run flutter_launcher_icons | |
cd .. | |
- name: Report Status | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "50% complete, this step takes about 5 minutes, be patient."}' | |
- name: Build rustdesk | |
run: | | |
Invoke-WebRequest -Uri https://github.com/rustdesk-org/rdev/releases/download/usbmmidd_v2/usbmmidd_v2.zip -OutFile usbmmidd_v2.zip | |
Expand-Archive usbmmidd_v2.zip -DestinationPath . -Force | |
python3 .\build.py --portable --hwcodec --flutter --vram --skip-portable-pack | |
Remove-Item -Path usbmmidd_v2\Win32 -Recurse | |
Remove-Item -Path "usbmmidd_v2\deviceinstaller64.exe", "usbmmidd_v2\deviceinstaller.exe", "usbmmidd_v2\usbmmidd.bat" | |
mv ./flutter/build/windows/x64/runner/Release ./rustdesk | |
mv -Force .\usbmmidd_v2 ./rustdesk | |
- name: icon stuff | |
if: ${{ inputs.iconlink != 'false' }} | |
continue-on-error: true | |
run: | | |
mv ./rustdesk/data/flutter_assets/assets/icon.svg ./rustdesk/data/flutter_assets/assets/icon.svg.bak | |
magick ./res/icon.png ./rustdesk/data/flutter_assets/assets/icon.svg | |
- name: logo stuff | |
if: ${{ inputs.logolink != 'false' }} | |
continue-on-error: true | |
run: | | |
Invoke-WebRequest -Uri ${{ fromJson(inputs.logolink).url }}/get_png?filename=${{ fromJson(inputs.logolink).file }}"&"uuid=${{ fromJson(inputs.logolink).uuid }} -OutFile ./rustdesk/data/flutter_assets/assets/logo.png | |
- name: find Runner.res | |
# Windows: find Runner.res (compiled from ./flutter/windows/runner/Runner.rc), copy to ./Runner.res | |
# Runner.rc does not contain actual version, but Runner.res does | |
continue-on-error: true | |
shell: bash | |
run: | | |
runner_res=$(find . -name "Runner.res"); | |
if [ "$runner_res" == "" ]; then | |
echo "Runner.res: not found"; | |
else | |
echo "Runner.res: $runner_res"; | |
cp $runner_res ./libs/portable/Runner.res; | |
echo "list ./libs/portable/Runner.res"; | |
ls -l ./libs/portable/Runner.res; | |
fi | |
- name: Download RustDeskTempTopMostWindow artifacts | |
uses: actions/download-artifact@master | |
if: env.UPLOAD_ARTIFACT == 'true' | |
with: | |
name: topmostwindow-artifacts | |
path: "./rustdesk" | |
- name: Report Status | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "70% complete, this step takes about 5 minutes, be patient."}' | |
- name: zip dlls | |
continue-on-error: true | |
shell: pwsh | |
run: | | |
Compress-Archive -Path ./rustdesk/*.dll, ./rustdesk/*.exe -DestinationPath ./rustdesk/unsigned_files.zip -CompressionLevel Fastest | |
- name: sign dlls | |
continue-on-error: true | |
shell: bash | |
run: | | |
if [ ! -z "${{ secrets.SIGN_BASE_URL }}" ] && [ ! -z "${{ secrets.SIGN_API_KEY }}" ]; then | |
curl -X POST -F "file=@./rustdesk/unsigned_files.zip" \ | |
-H "X-API-KEY: ${{ secrets.SIGN_API_KEY }}" \ | |
-m 900 \ | |
"${{ secrets.SIGN_BASE_URL }}/sign/" -o ./rustdesk/signed_files.zip | |
else | |
echo "Signing skipped - signing URL or API key not configured" | |
cp ./rustdesk/unsigned_files.zip ./rustdesk/signed_files.zip | |
fi | |
- name: unzip dlls | |
continue-on-error: true | |
shell: pwsh | |
run: | | |
Expand-Archive -Path ./rustdesk/signed_files.zip -DestinationPath ./rustdesk/ -Force | |
Remove-Item ./rustdesk/unsigned_files.zip | |
Remove-Item ./rustdesk/signed_files.zip | |
- name: Create custom.txt file | |
shell: bash | |
run: | | |
echo -n "${{ inputs.custom }}" | cat > ./rustdesk/custom.txt | |
- name: Build self-extracted executable | |
shell: bash | |
if: env.UPLOAD_ARTIFACT == 'true' | |
run: | | |
mv "./rustdesk/rustdesk.exe" "./rustdesk/${{ inputs.appname }}.exe" || echo "rustdesk.exe" | |
sed -i '/dpiAware/d' res/manifest.xml | |
pushd ./libs/portable | |
pip3 install -r requirements.txt | |
python3 ./generate.py -f ../../rustdesk/ -o . -e "../../rustdesk/${{ inputs.appname }}.exe" | |
popd | |
mkdir -p ./SignOutput | |
mv ./target/release/rustdesk-portable-packer.exe "./SignOutput/rustdesk.exe" | |
- name: Add MSBuild to PATH | |
uses: microsoft/setup-msbuild@v2 | |
- name: Build msi | |
continue-on-error: true | |
if: env.UPLOAD_ARTIFACT == 'true' | |
run: | | |
$myappname = "${{ inputs.appname }}" -replace '\s','_' | |
cp "rustdesk/${{ inputs.appname }}.exe" "rustdesk/${myappname}.exe" -ErrorAction SilentlyContinue | |
pushd ./res/msi | |
python preprocess.py --app-name "$myappname" --arp -d ../../rustdesk | |
nuget restore msi.sln | |
msbuild msi.sln -p:Configuration=Release -p:Platform=x64 /p:TargetVersion=Windows10 | |
cp ./Package/bin/x64/Release/en-us/Package.msi ../../SignOutput/rustdesk-latest.msi | |
mv ./Package/bin/x64/Release/en-us/Package.msi ../../SignOutput/rustdesk.msi | |
sha256sum ../../SignOutput/rustdesk.msi | |
- name: Report Status | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "85% complete"}' | |
- name: zip exe and msi | |
continue-on-error: true | |
shell: pwsh | |
run: | | |
Compress-Archive -Path ./SignOutput/*.exe, ./SignOutput/*.msi -DestinationPath ./SignOutput/unsigned_files.zip -CompressionLevel Fastest | |
- name: sign exe and msi | |
continue-on-error: true | |
shell: bash | |
run: | | |
if [ ! -z "${{ secrets.SIGN_BASE_URL }}" ] && [ ! -z "${{ secrets.SIGN_API_KEY }}" ]; then | |
curl -X POST -F "file=@./SignOutput/unsigned_files.zip" \ | |
-H "X-API-KEY: ${{ secrets.SIGN_API_KEY }}" \ | |
-m 900 \ | |
"${{ secrets.SIGN_BASE_URL }}/sign/" -o ./SignOutput/signed_files.zip | |
else | |
echo "Signing skipped - signing URL or API key not configured" | |
cp ./SignOutput/unsigned_files.zip ./SignOutput/signed_files.zip | |
fi | |
- name: unzip exe and msi | |
continue-on-error: true | |
shell: pwsh | |
run: | | |
Expand-Archive -Path ./SignOutput/signed_files.zip -DestinationPath ./SignOutput/ -Force | |
Remove-Item ./SignOutput/unsigned_files.zip | |
Remove-Item ./SignOutput/signed_files.zip | |
- name: rename rustdesk.exe to filename.exe | |
run: | | |
mv ./SignOutput/rustdesk.exe "./SignOutput/${{ inputs.filename }}.exe" || echo "rustdesk" | |
- name: rename rustdesk.msi to filename.msi | |
continue-on-error: true | |
run: | | |
mv ./SignOutput/rustdesk.msi "./SignOutput/${{ inputs.filename }}.msi" || echo "rustdesk" | |
- name: send file to rdgen server | |
if: ${{ fromJson(inputs.extras).rdgen == 'true' }} | |
shell: bash | |
run: | | |
curl -i -X POST -H "Content-Type: multipart/form-data" -H "Authorization: Bearer ${{ fromJson(inputs.extras).token }}" -F "file=@./SignOutput/${{ inputs.filename }}.exe" -F "uuid=${{ inputs.uuid }}" ${{ secrets.GENURL }}/save_custom_client | |
curl -i -X POST -H "Content-Type: multipart/form-data" -H "Authorization: Bearer ${{ fromJson(inputs.extras).token }}" -F "file=@./SignOutput/${{ inputs.filename }}.msi" -F "uuid=${{ inputs.uuid }}" ${{ secrets.GENURL }}/save_custom_client || true | |
- name: send file to api server | |
if: ${{ fromJson(inputs.extras).rdgen == 'false' }} | |
shell: bash | |
run: | | |
curl -i -X POST -H "Content-Type: multipart/form-data" -H "Authorization: Bearer ${{ fromJson(inputs.extras).token }}" -F "file=@./SignOutput/${{ inputs.filename }}.exe" ${{ inputs.apiServer }}/api/save_custom_client | |
curl -i -X POST -H "Content-Type: multipart/form-data" -H "Authorization: Bearer ${{ fromJson(inputs.extras).token }}" -F "file=@./SignOutput/${{ inputs.filename }}.msi" ${{ inputs.apiServer }}/api/save_custom_client || true | |
- name: Report Status | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "Success"}' | |
- name: failed | |
if: failure() | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "Generation failed, try again"}' | |
- name: failed | |
if: cancelled() | |
uses: fjogeleit/http-request-action@v1 | |
with: | |
url: ${{ env.STATUS_URL }} | |
method: 'POST' | |
customHeaders: '{"Content-Type": "application/json"}' | |
data: '{"uuid": "${{ inputs.uuid }}", "status": "Generation cancelled, try again"}' |