name: Build the flutter version of the RustDesk

on:
  workflow_call:
    inputs:
      upload-artifact:
        type: boolean
        default: true
      upload-tag:
        type: string
        default: "nightly"

# NOTE: F-Droid builder script 'flutter/build_fdroid.sh' reads environment
# variables from this workflow!
#
# It does NOT read build steps, however, so please fix 'flutter/build_fdroid.sh
# whenever you add changes to Android CI build action ('build-rustdesk-android')
# in this file!

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.19.6"
  ANDROID_FLUTTER_VERSION: "3.13.9" # >= 3.16 is very slow on my android phone, but work well on most of others. We may switch to new flutter after changing to texture rendering (I believe it can solve my problem).
  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: "1de2026f28ead93ff1773e6e680387643e914ea1"
  VERSION: "1.3.0"
  NDK_VERSION: "r27"
  #signing keys env variable checks
  ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"
  MACOS_P12_BASE64: "${{ secrets.MACOS_P12_BASE64 }}"
  # To make a custom build with your own servers set the below secret values
  RS_PUB_KEY: "${{ secrets.RS_PUB_KEY }}"
  RENDEZVOUS_SERVER: "${{ secrets.RENDEZVOUS_SERVER }}"
  API_SERVER: "${{ secrets.API_SERVER }}"
  UPLOAD_ARTIFACT: "${{ inputs.upload-artifact }}"
  SIGN_BASE_URL: "${{ secrets.SIGN_BASE_URL }}"

jobs:
  build-RustDeskTempTopMostWindow:
    uses: ./.github/workflows/third-party-RustDeskTempTopMostWindow.yml
    with:
      upload-artifact: ${{ inputs.upload-artifact }}
      target: windows-2022
      configuration: Release
      platform: x64
      target_version: Windows10
    strategy:
      fail-fast: false

  build-for-windows-flutter:
    name: ${{ matrix.job.target }}
    needs: [build-RustDeskTempTopMostWindow]
    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: Checkout source code
        uses: actions/checkout@v4

      - name: Install LLVM and Clang
        uses: KyleMayes/install-llvm-action@v1
        with:
          version: ${{ env.LLVM_VERSION }}

      - name: Install flutter
        uses: subosito/flutter-action@v2.12.0 #https://github.com/subosito/flutter-action/issues/277
        with:
          channel: "stable"
          flutter-version: ${{ env.FLUTTER_VERSION }}
          cache: true

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: ${{ env.SCITER_RUST_VERSION }}
          targets: ${{ matrix.job.target }}
          components: "rustfmt"

      - uses: Swatinem/rust-cache@v2
        with:
          prefix-key: ${{ matrix.job.os }}

      - name: Install flutter rust bridge deps
        run: |
          git config --global core.longpaths true
          cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid"
          Push-Location flutter ; flutter pub get ; Pop-Location
          ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart

      - 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
        shell: bash

      - 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 .
          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: 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: ${{ inputs.upload-artifact }}
        with:
          name: topmostwindow-artifacts
          path: "./rustdesk"

      - name: Upload unsigned
        if: env.UPLOAD_ARTIFACT == 'true'
        uses: actions/upload-artifact@master
        with:
          name: rustdesk-unsigned-windows-${{ matrix.job.arch }}
          path: rustdesk

      - name: Sign rustdesk files
        if: env.UPLOAD_ARTIFACT == 'true' && env.SIGN_BASE_URL != ''
        shell: bash
        run: |
          pip3 install requests argparse
          BASE_URL=${{ secrets.SIGN_BASE_URL }} SECRET_KEY=${{ secrets.SIGN_SECRET_KEY }} python3 res/job.py sign_files ./rustdesk/

      - name: Build self-extracted executable
        shell: bash
        if: env.UPLOAD_ARTIFACT == 'true'
        run: |
          sed -i '/dpiAware/d' res/manifest.xml
          pushd ./libs/portable
          pip3 install -r requirements.txt
          python3 ./generate.py -f ../../rustdesk/ -o . -e ../../rustdesk/rustdesk.exe
          popd
          mkdir -p ./SignOutput
          mv ./target/release/rustdesk-portable-packer.exe ./SignOutput/rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.exe

      - name: Add MSBuild to PATH
        uses: microsoft/setup-msbuild@v2

      - name: Build msi
        if: env.UPLOAD_ARTIFACT == 'true'
        run: |
          pushd ./res/msi
          python preprocess.py --arp -d ../../rustdesk
          nuget restore msi.sln
          msbuild msi.sln -p:Configuration=Release -p:Platform=x64 /p:TargetVersion=Windows10
          mv ./Package/bin/x64/Release/en-us/Package.msi ../../SignOutput/rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.msi
          sha256sum ../../SignOutput/rustdesk-*.msi

      - name: Sign rustdesk self-extracted file
        if: env.UPLOAD_ARTIFACT == 'true' && env.SIGN_BASE_URL != ''
        shell: bash
        run: |
          BASE_URL=${{ secrets.SIGN_BASE_URL }} SECRET_KEY=${{ secrets.SIGN_SECRET_KEY }} python3 res/job.py sign_files ./SignOutput

      - name: Publish Release
        uses: softprops/action-gh-release@v1
        if: env.UPLOAD_ARTIFACT == 'true'
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            ./SignOutput/rustdesk-*.msi
            ./SignOutput/rustdesk-*.exe

  # The fallback for the flutter version, we use Sciter for 32bit Windows.
  build-for-windows-sciter:
    name: ${{ matrix.job.target }} (${{ matrix.job.os }})
    runs-on: ${{ matrix.job.os }}
    # Temporarily disable this action due to additional test is needed.
    # if: false
    strategy:
      fail-fast: false
      matrix:
        job:
          # - { target: i686-pc-windows-msvc        , os: windows-2022                  }
          # - { target: x86_64-pc-windows-gnu       , os: windows-2022                  }
          - {
              target: i686-pc-windows-msvc,
              os: windows-2022,
              arch: x86,
              vcpkg-triplet: x86-windows-static,
            }
          # - { target: aarch64-pc-windows-msvc, os: windows-2022 }
    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: Checkout source code
        uses: actions/checkout@v4

      - name: Install LLVM and Clang
        uses: rustdesk-org/install-llvm-action-32bit@master
        with:
          version: ${{ env.LLVM_VERSION }}

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: nightly-2023-10-13-${{ matrix.job.target }} # must use nightly here, because of abi_thiscall feature required
          targets: ${{ matrix.job.target }}
          components: "rustfmt"

      - uses: Swatinem/rust-cache@v2
        with:
          prefix-key: ${{ matrix.job.os }}-sciter

      - 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
        shell: bash

      - name: Build rustdesk
        id: build
        shell: bash
        run: |
          python3 res/inline-sciter.py
          # Patch sciter x86
          sed -i 's/branch = "dyn"/branch = "dyn_x86"/g' ./Cargo.toml
          cargo build --features inline,vram,hwcodec --release --bins
          mkdir -p ./Release
          mv ./target/release/rustdesk.exe ./Release/rustdesk.exe
          curl -LJ -o ./Release/sciter.dll https://github.com/c-smile/sciter-sdk/raw/master/bin.win/x32/sciter.dll
          echo "output_folder=./Release" >> $GITHUB_OUTPUT
          curl -LJ -o ./usbmmidd_v2.zip https://github.com/rustdesk-org/rdev/releases/download/usbmmidd_v2/usbmmidd_v2.zip
          unzip usbmmidd_v2.zip
          # Do not remove x64 files, because the user may run the 32bit version on a 64bit system.
          # Do not remove ./usbmmidd_v2/deviceinstaller64.exe, as x86 exe cannot install and uninstall drivers when running on x64,
          # we need the x64 exe to install and uninstall the driver.
          rm -rf ./usbmmidd_v2/deviceinstaller.exe ./usbmmidd_v2/usbmmidd.bat
          mv ./usbmmidd_v2 ./Release || true

      - 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: Sign rustdesk files
        if: env.UPLOAD_ARTIFACT == 'true' && env.SIGN_BASE_URL != ''
        shell: bash
        run: |
          pip3 install requests argparse
          BASE_URL=${{ secrets.SIGN_BASE_URL }} SECRET_KEY=${{ secrets.SIGN_SECRET_KEY }} python3 res/job.py sign_files ./Release/

      - name: Build self-extracted executable
        shell: bash
        run: |
          sed -i '/dpiAware/d' res/manifest.xml
          pushd ./libs/portable
          pip3 install -r requirements.txt
          python3 ./generate.py -f ../../Release/ -o . -e ../../Release/rustdesk.exe
          popd
          mkdir -p ./SignOutput
          mv ./target/release/rustdesk-portable-packer.exe ./SignOutput/rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}-sciter.exe

      - name: Sign rustdesk self-extracted file
        if: env.UPLOAD_ARTIFACT == 'true' && env.SIGN_BASE_URL != ''
        shell: bash
        run: |
          BASE_URL=${{ secrets.SIGN_BASE_URL }} SECRET_KEY=${{ secrets.SIGN_SECRET_KEY }} python3 res/job.py sign_files ./SignOutput/

      - name: Publish Release
        uses: softprops/action-gh-release@v1
        if: env.UPLOAD_ARTIFACT == 'true'
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            ./SignOutput/rustdesk-*.exe

  build-for-macOS-arm64-selfhost:
    # use build-for-macOS instead
    if: false
    runs-on: [self-hosted, macOS, ARM64]
    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: Checkout source code
        uses: actions/checkout@v4

      - name: Install flutter rust bridge deps
        shell: bash
        run: |
          cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid"
          pushd flutter && flutter pub get && popd
          ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart --c-output ./flutter/macos/Runner/bridge_generated.h

      - name: Build rustdesk
        run: |
          ./build.py --flutter --hwcodec

      - name: create unsigned dmg
        if: env.UPLOAD_ARTIFACT == 'true'
        run: |
          CREATE_DMG="$(command -v create-dmg)"
          CREATE_DMG="$(readlink -f "$CREATE_DMG")"
          sed -i -e 's/MAXIMUM_UNMOUNTING_ATTEMPTS=3/MAXIMUM_UNMOUNTING_ATTEMPTS=7/' "$CREATE_DMG"
          create-dmg --icon "RustDesk.app" 200 190 --hide-extension "RustDesk.app" --window-size 800 400 --app-drop-link 600 185 rustdesk-${{ env.VERSION }}-arm64.dmg ./flutter/build/macos/Build/Products/Release/RustDesk.app

      - name: Upload unsigned macOS app
        if: env.UPLOAD_ARTIFACT == 'true'
        uses: actions/upload-artifact@master
        with:
          name: rustdesk-unsigned-macos-arm64
          path: rustdesk-${{ env.VERSION }}-arm64.dmg # can not upload the directory directly or tar.gz file, which destroy the link structure, causing the codesign failed

      - name: Codesign app and create signed dmg
        if: env.MACOS_P12_BASE64 != null && env.UPLOAD_ARTIFACT == 'true'
        run: |
          # Patch create-dmg to give more attempts to unmount image
          CREATE_DMG="$(command -v create-dmg)"
          CREATE_DMG="$(readlink -f "$CREATE_DMG")"
          sed -i -e 's/MAXIMUM_UNMOUNTING_ATTEMPTS=3/MAXIMUM_UNMOUNTING_ATTEMPTS=7/' "$CREATE_DMG"
          # start sign the rustdesk.app and dmg
          rm -rf *.dmg || true
          codesign --force --options runtime -s ${{ secrets.MACOS_CODESIGN_IDENTITY }} --deep --strict ./flutter/build/macos/Build/Products/Release/RustDesk.app -vvv
          create-dmg --icon "RustDesk.app" 200 190 --hide-extension "RustDesk.app" --window-size 800 400 --app-drop-link 600 185 rustdesk-${{ env.VERSION }}.dmg ./flutter/build/macos/Build/Products/Release/RustDesk.app
          codesign --force --options runtime -s ${{ secrets.MACOS_CODESIGN_IDENTITY }} --deep --strict rustdesk-${{ env.VERSION }}.dmg -vvv
          # notarize the rustdesk-${{ env.VERSION }}.dmg
          rcodesign notary-submit --api-key-path ~/.p12/api-key.json  --staple rustdesk-${{ env.VERSION }}.dmg

      - name: Rename rustdesk
        if: env.UPLOAD_ARTIFACT == 'true'
        run: |
          for name in rustdesk*??.dmg; do
              mv "$name" "${name%%.dmg}-aarch64.dmg"
          done

      - name: Publish DMG package
        if: env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            rustdesk*-aarch64.dmg

  build-rustdesk-ios:
    if: ${{ inputs.upload-artifact }}
    name: build rustdesk ios ipa
    runs-on: ${{ matrix.job.os }}
    strategy:
      fail-fast: false
      matrix:
        job:
          - {
              arch: aarch64,
              target: aarch64-apple-ios,
              os: macos-13,
              vcpkg-triplet: arm64-ios,
            }
    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: Install dependencies
        run: |
          brew install nasm yasm
      - name: Checkout source code
        uses: actions/checkout@v4
      - name: Install flutter
        uses: subosito/flutter-action@v2
        with:
          channel: "stable"
          flutter-version: ${{ env.FLUTTER_VERSION }}

      - name: Setup vcpkg with Github Actions binary cache
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
          doNotCache: false

      - name: Install vcpkg dependencies
        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
        shell: bash

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: ${{ env.RUST_VERSION }}
          targets: ${{ matrix.job.target }}
          components: "rustfmt"

      - uses: Swatinem/rust-cache@v2
        with:
          prefix-key: rustdesk-lib-cache-ios
          key: ${{ matrix.job.target }}

      - name: Install flutter rust bridge deps
        shell: bash
        run: |
          cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid"
          pushd flutter && flutter pub get && popd
          ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart --c-output ./flutter/ios/Runner/bridge_generated.h

      - name: Build rustdesk lib
        run: |
          rustup target add ${{ matrix.job.target }}
          cargo build --features flutter,hwcodec --release --target aarch64-apple-ios --lib

      - name: Build rustdesk
        shell: bash
        run: |
          pushd flutter
          # flutter build ipa --release --obfuscate --split-debug-info=./split-debug-info --no-codesign
          # for easy debugging
          flutter build ipa --release --no-codesign

      # - name: Upload Artifacts
      #   # if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
      #   uses: actions/upload-artifact@master
      #   with:
      #     name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
      #     path: flutter/build/ios/ipa/*.ipa

      # - name: Publish ipa package
      #   # if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
      #   uses: softprops/action-gh-release@v1
      #   with:
      #     prerelease: true
      #     tag_name: ${{ env.TAG_NAME }}
      #     files: |
      #       flutter/build/ios/ipa/*.ipa

  build-rustdesk-ios-selfhost:
    #if: ${{ inputs.upload-artifact }}
    if: false
    runs-on: [self-hosted, macOS, ARM64]
    strategy:
      fail-fast: false
    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: Checkout source code
        uses: actions/checkout@v4

      # $VCPKG_ROOT/vcpkg install --triplet arm64-ios --x-install-root="$VCPKG_ROOT/installed"

      - name: Install flutter rust bridge deps
        shell: bash
        run: |
          cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid"
          pushd flutter && flutter pub get && popd
          ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart --c-output ./flutter/ios/Runner/bridge_generated.h

      - name: Build rustdesk lib
        run: |
          cargo build --features flutter,hwcodec --release --target aarch64-apple-ios --lib

      - name: Build rustdesk
        # ios sdk not installed on this machine, I will install it later after I am back home
        if: false
        shell: bash
        run: |
          pushd flutter
          # flutter build ipa --release --obfuscate --split-debug-info=./split-debug-info --no-codesign
          # for easy debugging
          flutter build ipa --release --no-codesign

      # - name: Upload Artifacts
      #   # if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
      #   uses: actions/upload-artifact@master
      #   with:
      #     name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
      #     path: flutter/build/ios/ipa/*.ipa

      # - name: Publish ipa package
      #   # if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
      #   uses: softprops/action-gh-release@v1
      #   with:
      #     prerelease: true
      #     tag_name: ${{ env.TAG_NAME }}
      #     files: |
      #       flutter/build/ios/ipa/*.ipa

  build-for-macOS:
    name: ${{ matrix.job.target }}
    runs-on: ${{ matrix.job.os }}
    strategy:
      fail-fast: false
      matrix:
        job:
          - {
              target: x86_64-apple-darwin,
              os: macos-13, #macos-latest or macos-14 use M1 now, https://docs.github.com/en/actions/using-github-hosted-runners/about-github-hosted-runners/about-github-hosted-runners#:~:text=14%20GB-,macos%2Dlatest%20or%20macos%2D14,-The%20macos%2Dlatestlabel
              extra-build-args: "",
              arch: x86_64,
            }
          - {
              target: aarch64-apple-darwin,
              os: macos-latest,
              # extra-build-args: "--disable-flutter-texture-render", # disable this for mac, because we see a lot of users reporting flickering both on arm and x64, and we can not confirm if texture rendering has better performance if htere is no vram, https://github.com/rustdesk/rustdesk/issues/6296
              extra-build-args: "",
              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: Checkout source code
        uses: actions/checkout@v4

      - name: Import the codesign cert
        if: env.MACOS_P12_BASE64 != null
        uses: apple-actions/import-codesign-certs@v1
        with:
          p12-file-base64: ${{ secrets.MACOS_P12_BASE64 }}
          p12-password: ${{ secrets.MACOS_P12_PASSWORD }}
          keychain: rustdesk

      - name: Check sign and import sign key
        if: env.MACOS_P12_BASE64 != null
        run: |
          security default-keychain -s rustdesk.keychain
          security find-identity -v

      - name: Import notarize key
        if: env.MACOS_P12_BASE64 != null
        uses: timheuer/base64-to-file@v1.2
        with:
          # https://gregoryszorc.com/docs/apple-codesign/stable/apple_codesign_rcodesign.html#notarizing-and-stapling
          fileName: rustdesk.json
          fileDir: ${{ github.workspace }}
          encodedString: ${{ secrets.MACOS_NOTARIZE_JSON }}

      - name: Install rcodesign tool
        if: env.MACOS_P12_BASE64 != null
        shell: bash
        run: |
          pushd /tmp
          wget https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.22.0/apple-codesign-0.22.0-macos-universal.tar.gz
          tar -zxvf apple-codesign-0.22.0-macos-universal.tar.gz
          mv apple-codesign-0.22.0-macos-universal/rcodesign /usr/local/bin
          popd

      - name: Install build runtime
        run: |
          brew install llvm create-dmg nasm cmake gcc wget ninja pkg-config

      - name: Install flutter
        uses: subosito/flutter-action@v2
        with:
          channel: "stable"
          flutter-version: ${{ env.FLUTTER_VERSION }}

      - name: Workaround for flutter issue
        shell: bash
        run: |
          cd "$(dirname "$(which flutter)")"
          # https://github.com/flutter/flutter/issues/133533
          sed -i -e 's/_setFramesEnabledState(false);/\/\/_setFramesEnabledState(false);/g' ../packages/flutter/lib/src/scheduler/binding.dart
          grep -n '_setFramesEnabledState(false);' ../packages/flutter/lib/src/scheduler/binding.dart

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: ${{ env.RUST_VERSION }}
          targets: ${{ matrix.job.target }}
          components: "rustfmt"

      - uses: Swatinem/rust-cache@v2
        with:
          prefix-key: ${{ matrix.job.os }}

      - name: Install flutter rust bridge deps
        shell: bash
        run: |
          cargo install flutter_rust_bridge_codegen --version ${{ env.FLUTTER_RUST_BRIDGE_VERSION }} --features "uuid"
          pushd flutter && flutter pub get && popd
          ~/.cargo/bin/flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs --dart-output ./flutter/lib/generated_bridge.dart --c-output ./flutter/macos/Runner/bridge_generated.h

      - name: Setup vcpkg with Github Actions binary cache
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
          doNotCache: false

      - name: Install vcpkg dependencies
        run: |
          if ! $VCPKG_ROOT/vcpkg \
            install \
            --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

      - name: Show version information (Rust, cargo, Clang)
        shell: bash
        run: |
          clang --version || true
          rustup -V
          rustup toolchain list
          rustup default
          cargo -V
          rustc -V

      - name: Build rustdesk
        run: |
          ./build.py --flutter --hwcodec ${{ matrix.job.extra-build-args }}

      - name: create unsigned dmg
        if: env.UPLOAD_ARTIFACT == 'true'
        run: |
          CREATE_DMG="$(command -v create-dmg)"
          CREATE_DMG="$(readlink -f "$CREATE_DMG")"
          sed -i -e 's/MAXIMUM_UNMOUNTING_ATTEMPTS=3/MAXIMUM_UNMOUNTING_ATTEMPTS=7/' "$CREATE_DMG"
          create-dmg --icon "RustDesk.app" 200 190 --hide-extension "RustDesk.app" --window-size 800 400 --app-drop-link 600 185 rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.dmg ./flutter/build/macos/Build/Products/Release/RustDesk.app

      - name: Upload unsigned macOS app
        if: env.UPLOAD_ARTIFACT == 'true'
        uses: actions/upload-artifact@master
        with:
          name: rustdesk-unsigned-macos-${{ matrix.job.arch }}
          path: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.dmg # can not upload the directory directly or tar.gz, which destroy the link structure, causing the codesign failed

      - name: Codesign app and create signed dmg
        if: env.MACOS_P12_BASE64 != null && env.UPLOAD_ARTIFACT == 'true'
        run: |
          # Patch create-dmg to give more attempts to unmount image
          CREATE_DMG="$(command -v create-dmg)"
          CREATE_DMG="$(readlink -f "$CREATE_DMG")"
          sed -i -e 's/MAXIMUM_UNMOUNTING_ATTEMPTS=3/MAXIMUM_UNMOUNTING_ATTEMPTS=7/' "$CREATE_DMG"
          # Unlock keychain
          security default-keychain -s rustdesk.keychain
          security unlock-keychain -p ${{ secrets.MACOS_P12_PASSWORD }} rustdesk.keychain
          # start sign the rustdesk.app and dmg
          rm -rf *.dmg || true
          codesign --force --options runtime -s ${{ secrets.MACOS_CODESIGN_IDENTITY }} --deep --strict ./flutter/build/macos/Build/Products/Release/RustDesk.app -vvv
          create-dmg --icon "RustDesk.app" 200 190 --hide-extension "RustDesk.app" --window-size 800 400 --app-drop-link 600 185 rustdesk-${{ env.VERSION }}.dmg ./flutter/build/macos/Build/Products/Release/RustDesk.app
          codesign --force --options runtime -s ${{ secrets.MACOS_CODESIGN_IDENTITY }} --deep --strict rustdesk-${{ env.VERSION }}.dmg -vvv
          # notarize the rustdesk-${{ env.VERSION }}.dmg
          rcodesign notary-submit --api-key-path ${{ github.workspace }}/rustdesk.json  --staple rustdesk-${{ env.VERSION }}.dmg

      - name: Rename rustdesk
        if: env.UPLOAD_ARTIFACT == 'true'
        run: |
          for name in rustdesk*??.dmg; do
              mv "$name" "${name%%.dmg}-${{ matrix.job.arch }}.dmg"
          done

      - name: Publish DMG package
        if: env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            rustdesk*-${{ matrix.job.arch }}.dmg

  publish_unsigned:
    needs:
      - build-for-macOS
      - build-for-windows-flutter
    runs-on: ubuntu-latest
    if: ${{ inputs.upload-artifact }}
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@master
        with:
          name: rustdesk-unsigned-macos-x86_64
          path: ./

      - name: Download Artifacts
        uses: actions/download-artifact@master
        with:
          name: rustdesk-unsigned-macos-aarch64
          path: ./

      - name: Download Artifacts
        uses: actions/download-artifact@master
        with:
          name: rustdesk-unsigned-windows-x86_64
          path: ./windows-x86_64/

      - name: Combine unsigned app
        run: |
          tar czf rustdesk-${{ env.VERSION }}-unsigned.tar.gz *.dmg windows-x86_64

      - name: Publish unsigned app
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: rustdesk-${{ env.VERSION }}-unsigned.tar.gz

  generate-bridge-linux:
    uses: ./.github/workflows/bridge.yml

  build-rustdesk-android:
    needs: [generate-bridge-linux]
    name: build rustdesk android apk ${{ matrix.job.target }}
    runs-on: ${{ matrix.job.os }}
    strategy:
      fail-fast: false
      matrix:
        job:
          - {
              arch: aarch64,
              target: aarch64-linux-android,
              os: ubuntu-20.04,
              reltype: release,
              suffix: "",
            }
          - {
              arch: armv7,
              target: armv7-linux-androideabi,
              os: ubuntu-20.04,
              reltype: release,
              suffix: "",
            }
          - {
              arch: x86_64,
              target: x86_64-linux-android,
              os: ubuntu-20.04,
              reltype: release,
              suffix: "",
            }
    steps:
      - name: Free Disk Space (Ubuntu)
        uses: jlumbroso/free-disk-space@main
        with:
          tool-cache: false
          android: false
          dotnet: true
          haskell: true
          large-packages: false
          docker-images: true
          swap-storage: false

      - 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: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y \
               clang \
               cmake \
               curl \
               gcc-multilib \
               git \
               g++ \
               g++-multilib \
               libappindicator3-dev \
               libasound2-dev \
               libc6-dev \
               libclang-10-dev \
               libgstreamer1.0-dev \
               libgstreamer-plugins-base1.0-dev \
               libgtk-3-dev \
               libpam0g-dev \
               libpulse-dev \
               libva-dev \
               libvdpau-dev \
               libxcb-randr0-dev \
               libxcb-shape0-dev \
               libxcb-xfixes0-dev \
               libxdo-dev \
               libxfixes-dev \
               llvm-10-dev \
               nasm \
               ninja-build \
               openjdk-11-jdk-headless \
               pkg-config \
               tree \
               wget

      - name: Checkout source code
        uses: actions/checkout@v4
      - name: Install flutter
        uses: subosito/flutter-action@v2
        with:
          channel: "stable"
          flutter-version: ${{ env.ANDROID_FLUTTER_VERSION }}
      - uses: nttld/setup-ndk@v1
        id: setup-ndk
        with:
          ndk-version: ${{ env.NDK_VERSION }}
          add-to-path: true

      - name: Setup vcpkg with Github Actions binary cache
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgDirectory: /opt/artifacts/vcpkg
          vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
          doNotCache: false

      - name: Install vcpkg dependencies
        run: |
          case ${{ matrix.job.target }} in
            aarch64-linux-android)
              ANDROID_TARGET=arm64-v8a
            ;;
            armv7-linux-androideabi)
              ANDROID_TARGET=armeabi-v7a
            ;;
            x86_64-linux-android)
              ANDROID_TARGET=x86_64
            ;;
            i686-linux-android)
              ANDROID_TARGET=x86
            ;;
          esac
          if ! ./flutter/build_android_deps.sh "${ANDROID_TARGET}"; then
            find "${VCPKG_ROOT}/" -name "*.log" | while read -r _1; do
              echo "$_1:"
              echo "======"
              cat "$_1"
              echo "======"
              echo ""
            done
            exit 1
          fi
        shell: bash

      - name: Restore bridge files
        uses: actions/download-artifact@master
        with:
          name: bridge-artifact
          path: ./

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: ${{ env.RUST_VERSION }}
          components: "rustfmt"

      - uses: Swatinem/rust-cache@v2
        with:
          prefix-key: rustdesk-lib-cache-android # TODO: drop '-android' part after caches are invalidated
          key: ${{ matrix.job.target }}

      - name: fix android for flutter 3.13
        if: $${{ env.ANDROID_FLUTTER_VERSION == '3.13.9' }}
        run: |
          sed -i 's/uni_links_desktop/#uni_links_desktop/g' flutter/pubspec.yaml
          cd flutter/lib
          find . | grep dart | xargs sed -i 's/textScaler: TextScaler.linear(\(.*\)),/textScaleFactor: \1,/g'

      - name: Build rustdesk lib
        env:
          ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
          ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }}
        run: |
          rustup target add ${{ matrix.job.target }}
          cargo install cargo-ndk --version ${{ env.CARGO_NDK_VERSION }}
          case ${{ matrix.job.target }} in
            aarch64-linux-android)
              ./flutter/ndk_arm64.sh
              mkdir -p ./flutter/android/app/src/main/jniLibs/arm64-v8a
              cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so
            ;;
            armv7-linux-androideabi)
              ./flutter/ndk_arm.sh
              mkdir -p ./flutter/android/app/src/main/jniLibs/armeabi-v7a
              cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/armeabi-v7a/librustdesk.so
            ;;
            x86_64-linux-android)
              ./flutter/ndk_x64.sh
              mkdir -p ./flutter/android/app/src/main/jniLibs/x86_64
              cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/x86_64/librustdesk.so
            ;;
            i686-linux-android)
              ./flutter/ndk_x86.sh
              mkdir -p ./flutter/android/app/src/main/jniLibs/x86
              cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/x86/librustdesk.so
            ;;
          esac

      - name: Upload Rustdesk library to Artifacts
        uses: actions/upload-artifact@master
        with:
          name: librustdesk.so.${{ matrix.job.target }}
          path: ./target/${{ matrix.job.target }}/release/liblibrustdesk.so

      - name: Build rustdesk
        shell: bash
        env:
          JAVA_HOME: /usr/lib/jvm/java-11-openjdk-amd64
        run: |
          export PATH=/usr/lib/jvm/java-11-openjdk-amd64/bin:$PATH
          # temporary use debug sign config
          sed -i "s/signingConfigs.release/signingConfigs.debug/g" ./flutter/android/app/build.gradle
          case ${{ matrix.job.target }} in
            aarch64-linux-android)
              mkdir -p ./flutter/android/app/src/main/jniLibs/arm64-v8a
              cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so ./flutter/android/app/src/main/jniLibs/arm64-v8a/
              cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so
              # build flutter
              pushd flutter
              flutter build apk "--${{ matrix.job.reltype }}" --target-platform android-arm64 --split-per-abi
              mv build/app/outputs/flutter-apk/app-arm64-v8a-${{ matrix.job.reltype }}.apk ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk
            ;;
            armv7-linux-androideabi)
              mkdir -p ./flutter/android/app/src/main/jniLibs/armeabi-v7a
              cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so ./flutter/android/app/src/main/jniLibs/armeabi-v7a/
              cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/armeabi-v7a/librustdesk.so
              # build flutter
              pushd flutter
              flutter build apk "--${{ matrix.job.reltype }}" --target-platform android-arm --split-per-abi
              mv build/app/outputs/flutter-apk/app-armeabi-v7a-${{ matrix.job.reltype }}.apk ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk
            ;;
            x86_64-linux-android)
              mkdir -p ./flutter/android/app/src/main/jniLibs/x86_64
              cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so ./flutter/android/app/src/main/jniLibs/x86_64/
              cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/x86_64/librustdesk.so
              # build flutter
              pushd flutter
              flutter build apk "--${{ matrix.job.reltype }}" --target-platform android-x64 --split-per-abi
              mv build/app/outputs/flutter-apk/app-x86_64-${{ matrix.job.reltype }}.apk ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk
            ;;
            i686-linux-android)
              mkdir -p ./flutter/android/app/src/main/jniLibs/x86
              cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android/libc++_shared.so ./flutter/android/app/src/main/jniLibs/x86/
              cp ./target/${{ matrix.job.target }}/release/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/x86/librustdesk.so
              # build flutter
              pushd flutter
              flutter build apk "--${{ matrix.job.reltype }}" --target-platform android-x86 --split-per-abi
              mv build/app/outputs/flutter-apk/app-x86-${{ matrix.job.reltype }}.apk ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk
            ;;
          esac
          popd
          mkdir -p signed-apk; pushd signed-apk
          mv ../rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.apk .

      - uses: r0adkll/sign-android-release@v1
        name: Sign app APK
        if: env.ANDROID_SIGNING_KEY != null
        id: sign-rustdesk
        with:
          releaseDirectory: ./signed-apk
          signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }}
          alias: ${{ secrets.ANDROID_ALIAS }}
          keyStorePassword: ${{ secrets.ANDROID_KEY_STORE_PASSWORD }}
          keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }}
        env:
          # override default build-tools version (29.0.3) -- optional
          BUILD_TOOLS_VERSION: "30.0.2"

      - name: Upload Artifacts
        if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
        uses: actions/upload-artifact@master
        with:
          name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
          path: ${{steps.sign-rustdesk.outputs.signedReleaseFile}}

      - name: Publish signed apk package
        if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            ${{steps.sign-rustdesk.outputs.signedReleaseFile}}

      - name: Publish unsigned apk package
        if: env.ANDROID_SIGNING_KEY == null && env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            signed-apk/rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk

  build-rustdesk-android-universal:
    needs: [build-rustdesk-android]
    name: build rustdesk android universal apk
    if: ${{ inputs.upload-artifact }}
    runs-on: ubuntu-20.04
    env:
      reltype: release
      x86_target: "" # can be ",android-x86"
      suffix: ""
    steps:
      - name: Free Disk Space (Ubuntu)
        uses: jlumbroso/free-disk-space@main
        with:
          tool-cache: false
          android: false
          dotnet: true
          haskell: true
          large-packages: false
          docker-images: true
          swap-storage: false

      - 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: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y \
               clang \
               cmake \
               curl \
               gcc-multilib \
               git \
               g++ \
               g++-multilib \
               libappindicator3-dev \
               libasound2-dev \
               libc6-dev \
               libclang-10-dev \
               libgstreamer1.0-dev \
               libgstreamer-plugins-base1.0-dev \
               libgtk-3-dev \
               libpam0g-dev \
               libpulse-dev \
               libva-dev \
               libvdpau-dev \
               libxcb-randr0-dev \
               libxcb-shape0-dev \
               libxcb-xfixes0-dev \
               libxdo-dev \
               libxfixes-dev \
               llvm-10-dev \
               nasm \
               ninja-build \
               openjdk-11-jdk-headless \
               pkg-config \
               tree \
               wget

      - name: Checkout source code
        uses: actions/checkout@v4
      - name: Install flutter
        uses: subosito/flutter-action@v2
        with:
          channel: "stable"
          flutter-version: ${{ env.ANDROID_FLUTTER_VERSION }}

      - name: Restore bridge files
        uses: actions/download-artifact@master
        with:
          name: bridge-artifact
          path: ./

      - name: Download Rustdesk library from Artifacts
        uses: actions/download-artifact@master
        with:
          name: librustdesk.so.aarch64-linux-android
          path: ./flutter/android/app/src/main/jniLibs/arm64-v8a

      - name: Download Rustdesk library from Artifacts
        uses: actions/download-artifact@master
        with:
          name: librustdesk.so.armv7-linux-androideabi
          path: ./flutter/android/app/src/main/jniLibs/armeabi-v7a

      - name: Download Rustdesk library from Artifacts
        uses: actions/download-artifact@master
        with:
          name: librustdesk.so.x86_64-linux-android
          path: ./flutter/android/app/src/main/jniLibs/x86_64

      - name: Download Rustdesk library from Artifacts
        if: ${{ env.reltype == 'debug' }}
        uses: actions/download-artifact@master
        with:
          name: librustdesk.so.i686-linux-android
          path: ./flutter/android/app/src/main/jniLibs/x86

      - name: fix android for flutter 3.13
        if: $${{ env.ANDROID_FLUTTER_VERSION == '3.13.9' }}
        run: |
          sed -i 's/uni_links_desktop/#uni_links_desktop/g' flutter/pubspec.yaml
          cd flutter/lib
          find . | grep dart | xargs sed -i 's/textScaler: TextScaler.linear(\(.*\)),/textScaleFactor: \1,/g'

      - name: Build rustdesk
        shell: bash
        env:
          JAVA_HOME: /usr/lib/jvm/java-11-openjdk-amd64
        run: |
          export PATH=/usr/lib/jvm/java-11-openjdk-amd64/bin:$PATH
          # temporary use debug sign config
          sed -i "s/signingConfigs.release/signingConfigs.debug/g" ./flutter/android/app/build.gradle
          mv ./flutter/android/app/src/main/jniLibs/arm64-v8a/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/arm64-v8a/librustdesk.so
          cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/aarch64-linux-android/libc++_shared.so ./flutter/android/app/src/main/jniLibs/arm64-v8a/
          mv ./flutter/android/app/src/main/jniLibs/armeabi-v7a/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/armeabi-v7a/librustdesk.so
          cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/arm-linux-androideabi/libc++_shared.so ./flutter/android/app/src/main/jniLibs/armeabi-v7a/
          mv ./flutter/android/app/src/main/jniLibs/x86_64/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/x86_64/librustdesk.so
          cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/x86_64-linux-android/libc++_shared.so ./flutter/android/app/src/main/jniLibs/x86_64/
          if [ "${{ env.reltype }}" = "debug" ]; then
            mv ./flutter/android/app/src/main/jniLibs/x86/liblibrustdesk.so ./flutter/android/app/src/main/jniLibs/x86/librustdesk.so
            cp ${ANDROID_NDK_HOME}/toolchains/llvm/prebuilt/linux-x86_64/sysroot/usr/lib/i686-linux-android/libc++_shared.so ./flutter/android/app/src/main/jniLibs/x86/
          fi
          # build flutter
          pushd flutter
          flutter build apk "--${{ env.reltype }}" --target-platform android-arm64,android-arm,android-x64${{ env.x86_target }}
          popd
          mkdir -p signed-apk
          mv ./flutter/build/app/outputs/flutter-apk/app-${{ env.reltype }}.apk signed-apk/rustdesk-${{ env.VERSION }}-universal${{ env.suffix }}.apk

      - uses: r0adkll/sign-android-release@v1
        name: Sign app APK
        if: env.ANDROID_SIGNING_KEY != null
        id: sign-rustdesk
        with:
          releaseDirectory: ./signed-apk
          signingKeyBase64: ${{ secrets.ANDROID_SIGNING_KEY }}
          alias: ${{ secrets.ANDROID_ALIAS }}
          keyStorePassword: ${{ secrets.ANDROID_KEY_STORE_PASSWORD }}
          keyPassword: ${{ secrets.ANDROID_KEY_PASSWORD }}
        env:
          # override default build-tools version (29.0.3) -- optional
          BUILD_TOOLS_VERSION: "30.0.2"

      - name: Upload Artifacts
        if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
        uses: actions/upload-artifact@master
        with:
          name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.apk
          path: ${{steps.sign-rustdesk.outputs.signedReleaseFile}}

      - name: Publish signed apk package
        if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            ${{steps.sign-rustdesk.outputs.signedReleaseFile}}

      - name: Publish unsigned apk package
        if: env.ANDROID_SIGNING_KEY == null && env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            signed-apk/rustdesk-${{ env.VERSION }}-universal${{ env.suffix }}.apk

  build-rustdesk-linux:
    needs: [generate-bridge-linux]
    name: build rustdesk linux ${{ matrix.job.target }}
    runs-on: ${{ matrix.job.on }}
    strategy:
      fail-fast: false
      matrix:
        # use a high level qemu-user-static
        job:
          - {
              arch: x86_64,
              target: x86_64-unknown-linux-gnu,
              distro: ubuntu18.04,
              on: ubuntu-20.04,
              deb_arch: amd64,
              vcpkg-triplet: x64-linux,
            }
          - {
              arch: aarch64,
              target: aarch64-unknown-linux-gnu,
              distro: ubuntu18.04,
              on: [self-hosted, Linux, ARM64],
              deb_arch: arm64,
              vcpkg-triplet: arm64-linux,
            }
    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: Maximize build space
        if: ${{ matrix.job.arch == 'x86_64' }}
        run: |
          sudo rm -rf /opt/ghc
          sudo rm -rf /usr/local/lib/android
          sudo rm -rf /usr/share/dotnet
          sudo apt-get update -y
          sudo apt-get install -y nasm qemu-user-static

      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Set Swap Space
        if: ${{ matrix.job.arch == 'x86_64' }}
        uses: pierotofy/set-swap-space@master
        with:
          swap-size-gb: 12

      - name: Free Space
        run: |
          df -h
          free -m

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@v1
        if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
        with:
          toolchain: ${{ env.RUST_VERSION }}
          targets: ${{ matrix.job.target }}
          components: "rustfmt"

      - name: Save Rust toolchain version
        run: |
          RUST_TOOLCHAIN_VERSION=$(cargo --version | awk '{print $2}')
          echo "RUST_TOOLCHAIN_VERSION=$RUST_TOOLCHAIN_VERSION" >> $GITHUB_ENV

      - name: Disable rust bridge build
        run: |
          # only build cdylib
          sed -i  "s/\[\"cdylib\", \"staticlib\", \"rlib\"\]/\[\"cdylib\"\]/g" Cargo.toml

      - name: Restore bridge files
        if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
        uses: actions/download-artifact@master
        with:
          name: bridge-artifact
          path: ./

      - name: Setup vcpkg with Github Actions binary cache
        if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
        uses: lukka/run-vcpkg@v11
        with:
          vcpkgDirectory: /opt/artifacts/vcpkg
          vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
          doNotCache: false

      - name: Install vcpkg dependencies
        if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
        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
        shell: bash

      - name: Restore bridge files
        if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
        uses: actions/download-artifact@master
        with:
          name: bridge-artifact
          path: ./

      - uses: rustdesk-org/run-on-arch-action@amd64-support
        name: Build rustdesk
        id: vcpkg
        if: matrix.job.arch == 'x86_64' || env.UPLOAD_ARTIFACT == 'true'
        with:
          arch: ${{ matrix.job.arch }}
          distro: ${{ matrix.job.distro }}
          githubToken: ${{ github.token }}
          setup: |
            ls -l "${PWD}"
            ls -l /opt/artifacts/vcpkg/installed
          dockerRunArgs: |
            --volume "${PWD}:/workspace"
            --volume "/opt/artifacts:/opt/artifacts"
          shell: /bin/bash
          install: |
            apt-get update -y
            echo -e "installing deps"
            apt-get install -y \
               build-essential \
               clang \
               cmake \
               curl \
               gcc \
               git \
               g++ \
               libappindicator3-dev \
               libasound2-dev \
               libclang-10-dev \
               libgstreamer1.0-dev \
               libgstreamer-plugins-base1.0-dev \
               libgtk-3-dev \
               libpam0g-dev \
               libpulse-dev \
               libva-dev \
               libvdpau-dev \
               libxcb-randr0-dev \
               libxcb-shape0-dev \
               libxcb-xfixes0-dev \
               libxdo-dev \
               libxfixes-dev \
               llvm-10-dev \
               nasm \
               ninja-build \
               pkg-config \
               tree \
               python3 \
               rpm \
               unzip \
               wget \
               xz-utils
            # we have libopus compiled by us.
            apt-get remove -y libopus-dev || true
            # output devs
            ls -l ./
            tree -L 3 /opt/artifacts/vcpkg/installed
          run: |
            # disable git safe.directory
            git config --global --add safe.directory "*"
            # rust
            pushd /opt
            # do not use rustup, because memory overflow in qemu
            wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}.tar.gz
            tar -zxvf rust.tar.gz > /dev/null && rm rust.tar.gz
            cd rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }} && ./install.sh
            rm -rf rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}
            # edit config
            mkdir -p ~/.cargo/
            echo """
              [source.crates-io]
              registry = 'https://github.com/rust-lang/crates.io-index'
            """ > ~/.cargo/config
            cat ~/.cargo/config
            # start build
            pushd /workspace
            export VCPKG_ROOT=/opt/artifacts/vcpkg
            if [[ "${{ matrix.job.arch }}" == "aarch64" ]]; then
              export JOBS="--jobs 3"
            else
              export JOBS=""
            fi
            echo $JOBS
            cargo build --lib $JOBS --features hwcodec,flutter --release
            rm -rf target/release/deps target/release/build
            rm -rf ~/.cargo

            # Setup Flutter
            # disable git safe.directory
            git config --global --add safe.directory "*"
            pushd /workspace
            case ${{ matrix.job.arch }} in
              aarch64)
                export PATH=/opt/flutter-elinux/bin:$PATH
                sed -i "s/flutter build linux --release/flutter-elinux build linux --verbose/g" ./build.py
                sed -i "s/x64\/release/arm64\/release/g" ./build.py
              ;;
              x86_64)
                export PATH=/opt/flutter/bin:$PATH
              ;;
            esac
            popd
            pushd /opt
            wget https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${{ env.FLUTTER_VERSION }}-stable.tar.xz
            tar xf flutter_linux_${{ env.FLUTTER_VERSION }}-stable.tar.xz
            case ${{ matrix.job.arch }} in
              aarch64)
                # clone repo and reset to flutter ${{ env.FLUTTER_VERSION }}
                git clone https://github.com/sony/flutter-elinux.git || true
                pushd flutter-elinux
                  git fetch
                  git reset --hard ${{ env.FLUTTER_VERSION }}
                  bin/flutter-elinux doctor -v
                  bin/flutter-elinux precache --linux
                popd
                cp -R flutter/bin/cache/artifacts/engine/linux-x64/shader_lib flutter-elinux/flutter/bin/cache/artifacts/engine/linux-arm64
                rm -rf flutter
              ;;
              x86_64)
                flutter doctor -v
              ;;
            esac

            # build flutter
            pushd /workspace
            export CARGO_INCREMENTAL=0
            export DEB_ARCH=${{ matrix.job.deb_arch }}
            python3 ./build.py --flutter --skip-cargo
            for name in rustdesk*??.deb; do
              mv "$name" "${name%%.deb}-${{ matrix.job.arch }}.deb"
            done

            # rpm package
            echo -e "start packaging fedora package"
            pushd /workspace
            case ${{ matrix.job.arch }} in
              aarch64)
                sed -i "s/linux\/x64/linux\/arm64/g" ./res/rpm-flutter.spec
                ;;
            esac
            HBB=`pwd` rpmbuild ./res/rpm-flutter.spec -bb
            pushd ~/rpmbuild/RPMS/${{ matrix.job.arch }}
            for name in rustdesk*??.rpm; do
                mv "$name" /workspace/"${name%%.rpm}.rpm"
            done

            # rpm suse package
            echo -e "start packaging suse package"
            pushd /workspace
            case ${{ matrix.job.arch }} in
              aarch64)
                sed -i "s/linux\/x64/linux\/arm64/g" ./res/rpm-flutter-suse.spec
                ;;
            esac
            HBB=`pwd` rpmbuild ./res/rpm-flutter-suse.spec -bb
            pushd ~/rpmbuild/RPMS/${{ matrix.job.arch }}
            for name in rustdesk*??.rpm; do
                mv "$name" /workspace/"${name%%.rpm}-suse.rpm"
            done

      - name: Publish debian/rpm package
        if: env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            rustdesk-*.deb
            rustdesk-*.rpm

      - name: Upload deb
        uses: actions/upload-artifact@master
        if: env.UPLOAD_ARTIFACT == 'true'
        with:
          name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb
          path: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb

      # only x86_64 for arch since we can not find newest arm64 docker image to build
      # old arch image does not make sense for arch since it is "arch" which always update to date
      # and failed to makepkg arm64 on x86_64
      - name: Patch archlinux PKGBUILD
        if: matrix.job.arch == 'x86_64' && env.UPLOAD_ARTIFACT == 'true'
        run: |
          sed -i "s/x86_64/${{ matrix.job.arch }}/g" res/PKGBUILD
          if [[ "${{ matrix.job.arch }}" == "aarch64" ]]; then
            sed -i "s/x86_64/aarch64/g" ./res/PKGBUILD
          fi

      - name: Build archlinux package
        if: matrix.job.arch == 'x86_64' && env.UPLOAD_ARTIFACT == 'true'
        uses: rustdesk-org/arch-makepkg-action@master
        with:
          packages:
          scripts: |
            cd res && HBB=`pwd`/.. FLUTTER=1 makepkg -f

      - name: Publish archlinux package
        if: matrix.job.arch == 'x86_64' && env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            res/rustdesk-${{ env.VERSION }}*.zst

  build-rustdesk-linux-sciter:
    if: ${{ inputs.upload-artifact }}
    needs: build-rustdesk-linux # not for dep, just make it run later for parallelism
    runs-on: ${{ matrix.job.on }}
    name: build-rustdesk-linux-sciter ${{ matrix.job.target }}
    strategy:
      fail-fast: false
      matrix:
        # use a high level qemu-user-static
        job:
          - {
              arch: x86_64,
              target: x86_64-unknown-linux-gnu,
              on: ubuntu-20.04,
              distro: ubuntu18.04,
              deb_arch: amd64,
              sciter_arch: x64,
              vcpkg-triplet: x64-linux,
              extra_features: ",hwcodec",
            }
          - {
              arch: armv7,
              target: armv7-unknown-linux-gnueabihf,
              on: [self-hosted, Linux, ARM64],
              distro: ubuntu18.04-rustdesk,
              deb_arch: armhf,
              sciter_arch: arm32,
              vcpkg-triplet: arm-linux,
              extra_features: "",
            }
    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: Checkout source code
        uses: actions/checkout@v4

      - name: Free Space
        run: |
          df -h
          free -m

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: ${{ env.SCITER_RUST_VERSION }}
          targets: ${{ matrix.job.target }}
          components: "rustfmt"

      - name: Save Rust toolchain version
        run: |
          RUST_TOOLCHAIN_VERSION=$(cargo --version | awk '{print $2}')
          echo "RUST_TOOLCHAIN_VERSION=$RUST_TOOLCHAIN_VERSION" >> $GITHUB_ENV

      - uses: rustdesk-org/run-on-arch-action@amd64-support
        name: Build rustdesk sciter binary for ${{ matrix.job.arch }}
        id: vcpkg
        with:
          arch: ${{ matrix.job.arch }}
          distro: ${{ matrix.job.distro }}
          githubToken: ${{ github.token }}
          setup: |
            ls -l "${PWD}"
          dockerRunArgs: |
            --volume "${PWD}:/workspace"
          shell: /bin/bash
          install: |
            apt-get update
            apt-get install -y \
               build-essential \
               clang \
               curl \
               gcc \
               git \
               g++ \
               libappindicator3-dev \
               libasound2-dev \
               libclang-dev \
               libdbus-1-dev \
               libglib2.0-dev \
               libgstreamer1.0-dev \
               libgstreamer-plugins-base1.0-dev \
               libgtk-3-dev \
               liblzma-dev \
               libpam0g-dev \
               libpulse-dev \
               libva-dev \
               libvdpau-dev \
               libxcb-randr0-dev \
               libxcb-shape0-dev \
               libxcb-xfixes0-dev \
               libxdo-dev \
               libxfixes-dev \
               ninja-build \
               pkg-config \
               python3 \
               python3.7 \
               rpm \
               unzip \
               wget \
               xz-utils \
               zip
            # arm-linux needs CMake and vcokg built from source as there
            # are no prebuilts available from Kitware and Microsoft
            if [ "${{ matrix.job.vcpkg-triplet }}" = "arm-linux" ]; then
              # install gcc/g++ 8 for vcpkg and OpenSSL headers for CMake
              apt-get install -y gcc-8 g++-8 libssl-dev
              # bootstrap CMake amd add it to PATH
              git clone --depth 1 https://github.com/kitware/cmake -b "v${{ env.SCITER_ARMV7_CMAKE_VERSION }}" /tmp/cmake
              pushd /tmp/cmake
              ./bootstrap --generator='Unix Makefiles' "--prefix=/opt/cmake-${{ env.SCITER_ARMV7_CMAKE_VERSION }}-linux-armhf"
              make -j1 install
              popd
              rm -rf /tmp/cmake
              export PATH="/opt/cmake-${{ env.SCITER_ARMV7_CMAKE_VERSION }}-linux-armhf/bin:$PATH"
            fi
            # bootstrap vcpkg and set VCPKG_ROOT
            export VCPKG_ROOT=/opt/artifacts/vcpkg
            mkdir -p /opt/artifacts
            pushd /opt/artifacts
            rm -rf vcpkg
            git clone https://github.com/microsoft/vcpkg
            pushd vcpkg
            git reset --hard ${{ env.VCPKG_COMMIT_ID }}
            # build vcpkg helper executable with gcc-8 for arm-linux but use prebuilt one on x64-linux
            if [ "${{ matrix.job.vcpkg-triplet }}" = "arm-linux" ]; then
              CC=/usr/bin/gcc-8 CXX=/usr/bin/g++-8 sh bootstrap-vcpkg.sh -disableMetrics
            else
              sh bootstrap-vcpkg.sh -disableMetrics
            fi
            popd
            popd
            # rust
            pushd /opt
            # do not use rustup, because memory overflow in qemu
            wget --output-document rust.tar.gz https://static.rust-lang.org/dist/rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}.tar.gz
            tar -zxvf rust.tar.gz > /dev/null && rm rust.tar.gz
            pushd rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}
            ./install.sh
            popd
            rm -rf rust-${{env.RUST_TOOLCHAIN_VERSION}}-${{ matrix.job.target }}
            popd
            # install newer nasm for aom
            wget --output-document nasm.deb "http://ftp.us.debian.org/debian/pool/main/n/nasm/nasm_${{ env.SCITER_NASM_DEBVERSION }}_${{ matrix.job.deb_arch }}.deb"
            dpkg -i nasm.deb
            rm -f nasm.deb
          run: |
            # disable git safe.directory
            git config --global --add safe.directory "*"
            # set python3.7 as default python3
            update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.7 1
            # add built CMake to PATH and set VCPKG_FORCE_SYSTEM_BINARIES Afor arm-linux
            if [ "${{ matrix.job.vcpkg-triplet }}" = "arm-linux" ]; then
              export PATH="/opt/cmake-${{ env.SCITER_ARMV7_CMAKE_VERSION }}-linux-armhf/bin:$PATH"
              export VCPKG_FORCE_SYSTEM_BINARIES=1
            fi
            # edit cargo config
            mkdir -p ~/.cargo/
            echo """
              [source.crates-io]
              registry = 'https://github.com/rust-lang/crates.io-index'
            """ > ~/.cargo/config
            cat ~/.cargo/config
            # install dependencies from vcpkg
            export VCPKG_ROOT=/opt/artifacts/vcpkg
            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
            # build rustdesk
            python3 ./res/inline-sciter.py
            export CARGO_INCREMENTAL=0
            cargo build --features inline${{ matrix.job.extra_features }} --release --bins --jobs 1
            # make debian package
            mkdir -p ./Release
            mv ./target/release/rustdesk ./Release/rustdesk
            wget -O ./Release/libsciter-gtk.so https://github.com/c-smile/sciter-sdk/raw/master/bin.lnx/${{ matrix.job.sciter_arch }}/libsciter-gtk.so
            export DEB_ARCH=${{ matrix.job.deb_arch }}
            ./build.py --package ./Release

      - name: Rename rustdesk
        shell: bash
        run: |
          for name in rustdesk*??.deb; do
              # use cp to duplicate deb files to fit other packages.
              cp "$name" "${name%%.deb}-${{ matrix.job.arch }}-sciter.deb"
          done

      - name: Publish debian package
        if: env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}-sciter.deb

      - name: Upload deb
        uses: actions/upload-artifact@master
        if: env.UPLOAD_ARTIFACT == 'true'
        with:
          name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}-sciter.deb
          path: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}-sciter.deb

  build-appimage:
    name: Build appimage ${{ matrix.job.target }}
    needs: [build-rustdesk-linux]
    runs-on: ubuntu-20.04
    if: ${{ inputs.upload-artifact }}
    strategy:
      fail-fast: false
      matrix:
        job:
          - { target: x86_64-unknown-linux-gnu, arch: x86_64 }
          - { target: aarch64-unknown-linux-gnu, arch: aarch64 }
    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Download Binary
        uses: actions/download-artifact@master
        with:
          name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb
          path: .

      - name: Rename Binary
        run: |
          mv rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}.deb appimage/rustdesk.deb

      - name: Build appimage package
        shell: bash
        run: |
          # install libarchive-tools for bsdtar command used in AppImageBuilder.yml
          sudo apt-get update -y
          sudo apt-get install -y libarchive-tools
          # set-up appimage-builder
          pushd /tmp
          wget -O appimage-builder-x86_64.AppImage https://github.com/AppImageCrafters/appimage-builder/releases/download/v1.1.0/appimage-builder-1.1.0-x86_64.AppImage
          chmod +x appimage-builder-x86_64.AppImage
          sudo mv appimage-builder-x86_64.AppImage /usr/local/bin/appimage-builder
          popd
          # run appimage-builder
          pushd appimage
          sudo appimage-builder --skip-tests --recipe ./AppImageBuilder-${{ matrix.job.arch }}.yml

      - name: Publish appimage package
        if: env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            ./appimage/rustdesk-${{ env.VERSION }}-*.AppImage

  build-flatpak:
    name: Build flatpak ${{ matrix.job.target }}${{ matrix.job.suffix }}
    needs:
      - build-rustdesk-linux
      - build-rustdesk-linux-sciter
    runs-on: ${{ matrix.job.on }}
    if: ${{ inputs.upload-artifact }}
    strategy:
      fail-fast: false
      matrix:
        job:
          - {
              target: x86_64-unknown-linux-gnu,
              distro: ubuntu18.04,
              on: ubuntu-20.04,
              arch: x86_64,
              suffix: "",
            }
          - {
              target: x86_64-unknown-linux-gnu,
              distro: ubuntu18.04,
              on: ubuntu-20.04,
              arch: x86_64,
              suffix: "-sciter",
            }
          - {
              target: aarch64-unknown-linux-gnu,
              # try out newer flatpak since error of "error: Nothing matches org.freedesktop.Platform in remote flathub"
              distro: ubuntu22.04,
              on: [self-hosted, Linux, ARM64],
              arch: aarch64,
              suffix: "",
            }
    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Download Binary
        uses: actions/download-artifact@master
        with:
          name: rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.deb
          path: .

      - name: Rename Binary
        run: |
          mv rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.deb flatpak/rustdesk.deb

      - uses: rustdesk-org/run-on-arch-action@amd64-support
        name: Build rustdesk flatpak package for ${{ matrix.job.arch }}
        id: flatpak
        with:
          arch: ${{ matrix.job.arch }}
          distro: ${{ matrix.job.distro }}
          githubToken: ${{ github.token }}
          setup: |
            ls -l "${PWD}"
          dockerRunArgs: |
            --volume "${PWD}:/workspace"
          shell: /bin/bash
          install: |
            apt-get update -y
            apt-get install -y \
               curl \
               git \
               rpm \
               wget
          run: |
            # disable git safe.directory
            git config --global --add safe.directory "*"
            pushd /workspace
            # install
            apt-get update -y
            apt-get install -y \
               cmake \
               curl \
               flatpak \
               flatpak-builder \
               gcc \
               git \
               g++ \
               libgtk-3-dev \
               nasm \
               wget
            # flatpak deps
            flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
            flatpak --user install -y flathub org.freedesktop.Platform/${{ matrix.job.arch }}/23.08
            flatpak --user install -y flathub org.freedesktop.Sdk/${{ matrix.job.arch }}/23.08
            # package
            pushd flatpak
            git clone https://github.com/flathub/shared-modules.git --depth=1
            flatpak-builder --user --force-clean --repo=repo ./build ./rustdesk.json
            flatpak build-bundle ./repo rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.flatpak com.rustdesk.RustDesk

      - name: Publish flatpak package
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            flatpak/rustdesk-${{ env.VERSION }}-${{ matrix.job.arch }}${{ matrix.job.suffix }}.flatpak

  build-rustdesk-web:
    if: False
    name: build-rustdesk-web
    runs-on: ubuntu-20.04
    strategy:
      fail-fast: false
    env:
      RELEASE_NAME: web-basic
    steps:
      - name: Checkout source code
        uses: actions/checkout@v4

      - name: Prepare env
        run: |
          sudo apt-get update -y
          sudo apt-get install -y wget npm

      - name: Install flutter
        uses: subosito/flutter-action@v2.12.0 #https://github.com/subosito/flutter-action/issues/277
        with:
          channel: "stable"
          flutter-version: ${{ env.FLUTTER_VERSION }}
          cache: true

      # https://rustdesk.com/docs/en/dev/build/web/
      - name: Build web
        shell: bash
        run: |
          pushd flutter/web/js
          npm install yarn -g
          npm install typescript -g
          npm install protoc -g
          # Install protoc first, see: https://google.github.io/proto-lens/installing-protoc.html
          npm install ts-proto
          # Only works with vite <= 2.8, see: https://github.com/vitejs/vite/blob/main/docs/guide/build.md#chunking-strategy
          npm install vite@2.8
          yarn install && yarn build
          popd

          pushd flutter/web
          wget https://github.com/rustdesk/doc.rustdesk.com/releases/download/console/web_deps.tar.gz
          tar xzf web_deps.tar.gz
          popd

          pushd flutter
          flutter build web --release
          cd build
          cp ../web/README.md web
          # TODO: Remove the following line when the web is almost complete.
          echo -e "\n\nThis build is for preview and not full functionality." >> web/README.md
          dir_name="rustdesk-${{ env.VERSION }}-${{ env.RELEASE_NAME }}"
          mv web "${dir_name}" && tar czf "${dir_name}".tar.gz "${dir_name}"
          sha256sum "${dir_name}".tar.gz
          popd

      - name: Publish web
        if: env.UPLOAD_ARTIFACT == 'true'
        uses: softprops/action-gh-release@v1
        with:
          prerelease: true
          tag_name: ${{ env.TAG_NAME }}
          files: |
            flutter/build/rustdesk-${{ env.VERSION }}-${{ env.RELEASE_NAME }}.tar.gz