Custom Windows Client Generator #968
This file contains hidden or 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.15.05-1" | |
| LLVM_VERSION: "15.0.6" | |
| FLUTTER_VERSION: "3.24.5" | |
| ANDROID_FLUTTER_VERSION: "3.24.5" | |
| # 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: "120deac3062162151622ca4860575a33844ba10b" | |
| ARMV7_VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836" # 2025.01.13, got "/opt/artifacts/vcpkg/vcpkg: No such file or directory" with latest version | |
| 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 | |
| continue-on-error: true | |
| 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: fix flutter_gpu_texture_renderer (fixed in master rustdesk) | |
| shell: bash | |
| run: | | |
| sed -i -e 's|2ded7f146437a761ffe6981e2f742038f85ca68d|08a471bb8ceccdd50483c81cdfa8b81b07b14b87|' ./flutter/pubspec.lock | |
| sed -i -e 's|2ded7f146437a761ffe6981e2f742038f85ca68d|08a471bb8ceccdd50483c81cdfa8b81b07b14b87|' ./flutter/pubspec.yaml | |
| - 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: fix registry if appname has a space | |
| if: contains(inputs.appname, ' ') | |
| continue-on-error: true | |
| shell: bash | |
| run: | | |
| #./src/platform/windows.rs | |
| sed -i -e 's|reg add {}|reg add \\\"{}\\\"|' ./src/platform/windows.rs | |
| sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\.{ext} /f|reg add \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\" /f|' ./src/platform/windows.rs | |
| sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\.{ext}\\\\DefaultIcon /f|reg add \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\\DefaultIcon\\\" /f|' ./src/platform/windows.rs | |
| sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell /f|reg add \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell\\\" /f|' ./src/platform/windows.rs | |
| sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell\\\\open /f|reg add \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell\\\\open\\\" /f|' ./src/platform/windows.rs | |
| sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell\\\\open\\\\command|reg add \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\\shell\\\\open\\\\command\\\"|' ./src/platform/windows.rs | |
| sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\{ext} /f|reg add \\\"HKEY_CLASSES_ROOT\\\\{ext}\\\" /f|' ./src/platform/windows.rs | |
| sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\{ext}\\\\shell /f|reg add \\\"HKEY_CLASSES_ROOT\\\\{ext}\\\\shell\\\" /f|' ./src/platform/windows.rs | |
| sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\{ext}\\\\shell\\\\open /f|reg add \\\"HKEY_CLASSES_ROOT\\\\{ext}\\\\shell\\\\open\\\" /f|' ./src/platform/windows.rs | |
| sed -i -e 's|reg add HKEY_CLASSES_ROOT\\\\{ext}\\\\shell\\\\open\\\\command /f|reg add \\\"HKEY_CLASSES_ROOT\\\\{ext}\\\\shell\\\\open\\\\command\\\" /f|' ./src/platform/windows.rs | |
| sed -i -e 's|{subkey}|\\\"{subkey}\\\"|' ./src/platform/windows.rs | |
| sed -i -e 's|reg delete HKEY_CLASSES_ROOT\\\\.{ext} /f|reg delete \\\"HKEY_CLASSES_ROOT\\\\.{ext}\\\" /f|' ./src/platform/windows.rs | |
| sed -i -e 's|reg delete HKEY_CLASSES_ROOT\\\\{ext} /f|reg delete \\\"HKEY_CLASSES_ROOT\\\\{ext}\\\" /f|' ./src/platform/windows.rs | |
| - 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 \u00A9 2025 Purslane Ltd. All rights reserved."|"Copyright \u00A9 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: | | |
| # Use double quotes for the sed commands to allow variable expansion | |
| sed -i -e "s|Homepage: https://rustdesk.com|Homepage: ${{ fromJson(inputs.extras).urlLink }}|" ./build.py | |
| # Check if file exists before attempting to modify | |
| if [ -f "./flutter/lib/common.dart" ]; then | |
| sed -i -e "s|launchUrl(Uri.parse('https://rustdesk.com'))|launchUrl(Uri.parse('${{ fromJson(inputs.extras).urlLink }}'))|" ./flutter/lib/common.dart | |
| fi | |
| if [ -f "./flutter/lib/desktop/pages/desktop_setting_page.dart" ]; then | |
| 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 | |
| fi | |
| if [ -f "./flutter/lib/mobile/pages/settings_page.dart" ]; then | |
| 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 | |
| fi | |
| if [ -f "./flutter/lib/desktop/pages/install_page.dart" ]; then | |
| sed -i -e "s|https://rustdesk.com/privacy.html|${{ fromJson(inputs.extras).urlLink }}/privacy.html|" ./flutter/lib/desktop/pages/install_page.dart | |
| fi | |
| if [ -f "./res/setup.nsi" ]; then | |
| #sed -i -e "s|https://rustdesk.com/|${{ fromJson(inputs.extras).urlLink }}|" ./res/setup.nsi | |
| else | |
| echo "Warning: ./res/setup.nsi not found, skipping URL replacement for this file" | |
| fi | |
| - 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/VenimK/creator/refs/heads/master/.github/patches/allowCustom.py -OutFile allowCustom.py | |
| git apply allowCustom.py | |
| # Remove Setup Server Tip | |
| Invoke-WebRequest -Uri https://raw.githubusercontent.com/VenimK/creator/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 | |
| continue-on-error: true | |
| 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 | |
| continue-on-error: true | |
| 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 | |
| continue-on-error: true | |
| 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 -w0 < ./res/icon.png) | |
| sed -i -e 's|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|$(echo "$b64")|' ./src/ui.rs | |
| b64="" | |
| - name: Fix connection delay in client.rs | |
| if: ${{ fromJson(inputs.extras).delayFix == 'true' }} | |
| continue-on-error: true | |
| shell: bash | |
| run: | | |
| # Create a backup of the original file | |
| cp ./src/client.rs ./src/client.rs.bak | |
| # Use a more targeted approach that preserves code structure | |
| # Instead of just replacing part of the condition which causes syntax errors, | |
| # modify the entire condition to always be false | |
| sed -i -e 's/if !key.is_empty() && !token.is_empty()/if false \/* Connection delay fix applied *\//' ./src/client.rs | |
| # Verify the change | |
| echo "Applied connection delay fix to 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/VenimK/creator/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/VenimK/creator/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' | |
| shell: bash | |
| run: | | |
| echo "Applying hide-cm changes directly with sed" | |
| if [ -f "flutter/lib/models/server_model.dart" ]; then | |
| # Change bool hideCm to bool _hideCm | |
| sed -i 's/bool hideCm = false;/bool _hideCm = false;/' flutter/lib/models/server_model.dart | |
| # Add getter | |
| sed -i '/bool get clipboardOk => _clipboardOk;/a \ | |
| bool get hideCm => _hideCm;\ | |
| ' flutter/lib/models/server_model.dart | |
| # Uncomment various blocks | |
| sed -i 's/\/\*//g' flutter/lib/models/server_model.dart | |
| sed -i 's/\*\///g' flutter/lib/models/server_model.dart | |
| echo "Modified server_model.dart" | |
| else | |
| echo "server_model.dart not found" | |
| fi | |
| if [ -f "flutter/lib/main.dart" ]; then | |
| # Comment out gFFI.serverModel.hideCm = hide; | |
| sed -i 's/gFFI.serverModel.hideCm = hide;/\/\/ gFFI.serverModel.hideCm = hide;/' flutter/lib/main.dart | |
| echo "Modified main.dart" | |
| else | |
| echo "main.dart not found" | |
| fi | |
| if [ -f "flutter/lib/desktop/pages/desktop_setting_page.dart" ]; then | |
| # Uncomment hide_cm button | |
| sed -i "s/\/\/ if (usePassword)/if (usePassword)/" flutter/lib/desktop/pages/desktop_setting_page.dart | |
| sed -i "s/\/\/ hide_cm(!locked).marginOnly(left: _kContentHSubMargin - 6),/ hide_cm(!locked).marginOnly(left: _kContentHSubMargin - 6),/" flutter/lib/desktop/pages/desktop_setting_page.dart | |
| echo "Modified desktop_setting_page.dart" | |
| else | |
| echo "desktop_setting_page.dart not found" | |
| fi | |
| - name: removeNewVersionNotif | |
| continue-on-error: true | |
| if: fromJson(inputs.extras).removeNewVersionNotif == 'true' | |
| shell: bash | |
| run: | | |
| sed -i -e 's|updateUrl.isNotEmpty|false|' ./flutter/lib/desktop/pages/desktop_home_page.dart | |
| sed -i '/let (request, url) =/,/Ok(())/{/Ok(())/!d}' ./src/common.rs | |
| - name: disable settings | |
| continue-on-error: true | |
| run: | | |
| Write-Host "=== DISABLE SETTINGS CHECK ===" | |
| Write-Host "Custom config content: ${{ inputs.custom }}" | |
| # Decode base64 and check for disable-settings: Y | |
| try { | |
| $decodedBytes = [System.Convert]::FromBase64String("${{ inputs.custom }}") | |
| $decodedConfig = [System.Text.Encoding]::UTF8.GetString($decodedBytes) | |
| Write-Host "Decoded config: $decodedConfig" | |
| # Check for global disable-settings OR any granular hide-settings | |
| if ($decodedConfig -match '"disable-settings"\s*:\s*"Y"') { | |
| Write-Host "✅ GLOBAL DISABLE SETTINGS: ENABLED - Applying patch to hide ALL settings" | |
| Write-Host "Downloading disable settings patch..." | |
| Invoke-WebRequest -Uri https://raw.githubusercontent.com/VenimK/creator/refs/heads/master/.github/patches/disableSettings.diff -OutFile disableSettings.diff | |
| Write-Host "Applying patch to source code..." | |
| git apply disableSettings.diff | |
| Write-Host "✅ All settings UI successfully disabled in build" | |
| } elseif ($decodedConfig -match '"hide-(general|security|network|display|account|plugin|remote-printer)-settings"\s*:\s*"Y"') { | |
| Write-Host "✅ GRANULAR TAB HIDING: DETECTED" | |
| Write-Host "Settings tabs to hide:" | |
| $decodedConfig | Select-String -Pattern '"hide-(general|security|network|display|account|plugin|remote-printer)-settings"\s*:\s*"Y"' -AllMatches | ForEach-Object { $_.Matches.Value } | |
| Write-Host "Downloading hide settings script..." | |
| Invoke-WebRequest -Uri https://raw.githubusercontent.com/VenimK/creator/refs/heads/master/.github/scripts/hide_granular_settings.sh -OutFile hide_granular_settings.sh | |
| Write-Host "Running script to permanently hide selected settings tabs..." | |
| bash hide_granular_settings.sh | |
| Write-Host "✅ Settings tabs permanently hidden in source code" | |
| } | |
| # Check for sub-section hiding | |
| if ($decodedConfig -match '"hide-(server|proxy|websocket)-settings"\s*:\s*"Y"') { | |
| Write-Host "✅ GRANULAR SUB-SECTION HIDING: DETECTED" | |
| Write-Host "Sub-sections to hide within Network tab:" | |
| $decodedConfig | Select-String -Pattern '"hide-(server|proxy|websocket)-settings"\s*:\s*"Y"' -AllMatches | ForEach-Object { $_.Matches.Value } | |
| Write-Host "Downloading network sub-sections hiding script..." | |
| Invoke-WebRequest -Uri https://raw.githubusercontent.com/VenimK/creator/refs/heads/master/.github/scripts/hide_network_subsections.sh -OutFile hide_network_subsections.sh | |
| Write-Host "Running script to hide selected network sub-sections..." | |
| $env:DECODED_CONFIG = $decodedConfig | |
| bash hide_network_subsections.sh | |
| Write-Host "✅ Network sub-sections hidden in source code" | |
| } | |
| if ($decodedConfig -notmatch '"(disable|hide)-[a-z-]+-settings"\s*:\s*"Y"') { | |
| Write-Host "ℹ️ SETTINGS CONTROL: NOT ENABLED - All settings UI will remain accessible" | |
| } | |
| } catch { | |
| Write-Host "ℹ️ DISABLE SETTINGS: ERROR DECODING CONFIG - Settings UI will remain accessible" | |
| } | |
| Write-Host "=== DISABLE SETTINGS CHECK END ===" | |
| # - name: run as admin | |
| # continue-on-error: true | |
| # if: ${{ fromJson(inputs.extras).runasadmin == 'true' }} | |
| # shell: bash | |
| # run: | | |
| # sed -i '/<\/compatibility>/a \ | |
| # <security> \ | |
| # <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/> \ | |
| # </security>' ./flutter/windows/runner/runner.exe.manifest | |
| - name: Report Status | |
| uses: fjogeleit/http-request-action@v1 | |
| continue-on-error: true | |
| 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 | |
| continue-on-error: true | |
| 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: | | |
| # Windows: build RustDesk | |
| python3 .\build.py --portable --hwcodec --flutter --skip-portable-pack | |
| mv ./flutter/build/windows/x64/runner/Release ./rustdesk | |
| # Download usbmmidd_v2.zip and extract it to ./rustdesk | |
| 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 | |
| Remove-Item -Path usbmmidd_v2\Win32 -Recurse | |
| Remove-Item -Path "usbmmidd_v2\deviceinstaller64.exe", "usbmmidd_v2\deviceinstaller.exe", "usbmmidd_v2\usbmmidd.bat" | |
| mv -Force .\usbmmidd_v2 ./rustdesk | |
| # Download printer driver files and extract them to ./rustdesk | |
| try { | |
| Invoke-WebRequest -Uri https://github.com/rustdesk/hbb_common/releases/download/driver/rustdesk_printer_driver_v4-1.4.zip -OutFile rustdesk_printer_driver_v4-1.4.zip | |
| Invoke-WebRequest -Uri https://github.com/rustdesk/hbb_common/releases/download/driver/printer_driver_adapter.zip -OutFile printer_driver_adapter.zip | |
| Invoke-WebRequest -Uri https://github.com/rustdesk/hbb_common/releases/download/driver/sha256sums -OutFile sha256sums | |
| # Check and move the files | |
| $checksum_driver = (Select-String -Path .\sha256sums -Pattern '^([a-fA-F0-9]{64}) \*rustdesk_printer_driver_v4-1.4\.zip$').Matches.Groups[1].Value | |
| $downloadsum_driver = Get-FileHash -Path rustdesk_printer_driver_v4-1.4.zip -Algorithm SHA256 | |
| $checksum_adapter = (Select-String -Path .\sha256sums -Pattern '^([a-fA-F0-9]{64}) \*printer_driver_adapter\.zip$').Matches.Groups[1].Value | |
| $downloadsum_adapter = Get-FileHash -Path printer_driver_adapter.zip -Algorithm SHA256 | |
| if ($checksum_driver -eq $downloadsum_driver.Hash -and $checksum_adapter -eq $downloadsum_adapter.Hash) { | |
| Write-Output "rustdesk_printer_driver_v4-1.4, checksums match, extract the file." | |
| Expand-Archive rustdesk_printer_driver_v4-1.4.zip -DestinationPath . | |
| mkdir ./rustdesk/drivers | |
| mv -Force .\rustdesk_printer_driver_v4-1.4 ./rustdesk/drivers/RustDeskPrinterDriver | |
| Expand-Archive printer_driver_adapter.zip -DestinationPath . | |
| mv -Force .\printer_driver_adapter.dll ./rustdesk | |
| } elseif ($checksum_driver -ne $downloadsum_driver.Hash) { | |
| Write-Output "rustdesk_printer_driver_v4-1.4, checksums do not match, ignore the file." | |
| } else { | |
| Write-Output "printer_driver_adapter.zip, checksums do not match, ignore the file." | |
| } | |
| } catch { | |
| Write-Host "Ingore the printer driver error." | |
| } | |
| - 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 | |
| continue-on-error: true | |
| 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' | |
| shell: pwsh | |
| run: | | |
| echo "Building MSI with version ${{ env.VERSION }}..." | |
| New-Item -ItemType Directory -Force -Path ./SignOutput | Out-Null | |
| pushd ./res/msi | |
| # Try preprocess.py with version parameter | |
| python preprocess.py --arp -d ../../rustdesk --version ${{ env.VERSION }} | |
| if ($LASTEXITCODE -ne 0) { | |
| echo "preprocess.py failed, will create Config.wxi manually" | |
| } | |
| # Check if Config.wxi was created, if not create it manually | |
| if (-not (Test-Path "./Package/Config.wxi")) { | |
| echo "Config.wxi not found, creating manually..." | |
| New-Item -ItemType Directory -Force -Path ./Package | Out-Null | |
| '<?xml version="1.0" encoding="utf-8"?>' | Out-File -FilePath ./Package/Config.wxi -Encoding UTF8 | |
| '<Include>' | Out-File -FilePath ./Package/Config.wxi -Append -Encoding UTF8 | |
| ' <?define Version="${{ env.VERSION }}" ?>' | Out-File -FilePath ./Package/Config.wxi -Append -Encoding UTF8 | |
| ' <?define Product="RustDesk" ?>' | Out-File -FilePath ./Package/Config.wxi -Append -Encoding UTF8 | |
| ' <?define Description="RustDesk Remote Desktop" ?>' | Out-File -FilePath ./Package/Config.wxi -Append -Encoding UTF8 | |
| ' <?define Manufacturer="Purslane Ltd" ?>' | Out-File -FilePath ./Package/Config.wxi -Append -Encoding UTF8 | |
| ' <?define ProductLower="rustdesk" ?>' | Out-File -FilePath ./Package/Config.wxi -Append -Encoding UTF8 | |
| ' <?define RegKeyRoot="Software\RustDesk" ?>' | Out-File -FilePath ./Package/Config.wxi -Append -Encoding UTF8 | |
| ' <?define BuildDir="../../rustdesk" ?>' | Out-File -FilePath ./Package/Config.wxi -Append -Encoding UTF8 | |
| ' <?define UpgradeCode="{59C1BC08-0A9A-4A72-8BD4-7B28BD03C00A}" ?>' | Out-File -FilePath ./Package/Config.wxi -Append -Encoding UTF8 | |
| '</Include>' | Out-File -FilePath ./Package/Config.wxi -Append -Encoding UTF8 | |
| echo "Config.wxi created successfully:" | |
| Get-Content ./Package/Config.wxi | |
| } else { | |
| echo "Config.wxi found:" | |
| Get-Content ./Package/Config.wxi | Select-Object -First 20 | |
| } | |
| nuget restore msi.sln | |
| msbuild msi.sln -p:Configuration=Release -p:Platform=x64 /p:TargetVersion=Windows10 | |
| if (Test-Path "./Package/bin/x64/Release/en-us/Package.msi") { | |
| mv ./Package/bin/x64/Release/en-us/Package.msi ../../SignOutput/rustdesk.msi | |
| pushd ../../SignOutput | |
| sha256sum rustdesk.msi | |
| popd | |
| echo "MSI build complete successfully" | |
| } else { | |
| echo "ERROR: MSI file was not generated" | |
| exit 1 | |
| } | |
| popd | |
| - name: Report Status | |
| uses: fjogeleit/http-request-action@v1 | |
| continue-on-error: true | |
| 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"}' |