mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-12-12 18:29:10 +08:00
Merge branch 'rustdesk:master' into master
This commit is contained in:
commit
98234830a3
809
.github/workflows/flutter-ci.yml
vendored
809
.github/workflows/flutter-ci.yml
vendored
@ -16,808 +16,9 @@ on:
|
||||
- "docs/**"
|
||||
- "README.md"
|
||||
|
||||
env:
|
||||
LLVM_VERSION: "15.0.6"
|
||||
FLUTTER_VERSION: "3.7.5"
|
||||
# vcpkg version: 2022.05.10
|
||||
# for multiarch gcc compatibility
|
||||
VCPKG_COMMIT_ID: "14e7bb4ae24616ec54ff6b2f6ef4e8659434ea44"
|
||||
VERSION: "1.2.0"
|
||||
NDK_VERSION: "r23"
|
||||
|
||||
jobs:
|
||||
build-for-windows:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
job:
|
||||
# - { target: i686-pc-windows-msvc , os: windows-2019 }
|
||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
||||
- { target: x86_64-pc-windows-msvc, os: windows-2019 }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install LLVM and Clang
|
||||
uses: KyleMayes/install-llvm-action@v1
|
||||
with:
|
||||
version: ${{ env.LLVM_VERSION }}
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
cache: true
|
||||
|
||||
- name: Replace engine with rustdesk custom flutter engine
|
||||
run: |
|
||||
flutter doctor -v
|
||||
flutter precache --windows
|
||||
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.7.0-rustdesk/windows-x64-release-flutter.zip -OutFile windows-x64-flutter-release.zip
|
||||
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
|
||||
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-${{ env.FLUTTER_VERSION }}-x64/bin/cache/artifacts/engine/windows-x64-release/
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
components: rustfmt
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}
|
||||
|
||||
- name: Install flutter rust bridge deps
|
||||
run: |
|
||||
cargo install flutter_rust_bridge_codegen
|
||||
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: Restore from cache and install vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
with:
|
||||
setupOnly: true
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
$VCPKG_ROOT/vcpkg install libvpx:x64-windows-static libyuv:x64-windows-static opus:x64-windows-static
|
||||
shell: bash
|
||||
|
||||
- name: Build rustdesk
|
||||
run: python3 .\build.py --portable --hwcodec --flutter
|
||||
|
||||
build-for-macOS:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-args }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
job:
|
||||
- {
|
||||
target: x86_64-apple-darwin,
|
||||
os: macos-latest,
|
||||
extra-build-args: "",
|
||||
}
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install build runtime
|
||||
run: |
|
||||
brew install llvm create-dmg nasm yasm cmake gcc wget ninja pkg-config
|
||||
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- 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
|
||||
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
|
||||
|
||||
- name: Restore from cache and install vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
with:
|
||||
setupOnly: true
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
$VCPKG_ROOT/vcpkg install libvpx libyuv opus
|
||||
|
||||
- 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: |
|
||||
# --hwcodec not supported on macos yet
|
||||
./build.py --flutter ${{ matrix.job.extra-build-args }}
|
||||
|
||||
build-vcpkg-deps-linux:
|
||||
uses: ./.github/workflows/vcpkg-deps-linux.yml
|
||||
|
||||
generate-bridge-linux:
|
||||
uses: ./.github/workflows/bridge.yml
|
||||
|
||||
build-rustdesk-android:
|
||||
needs: [generate-bridge-linux]
|
||||
name: build rustdesk android apk ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
job:
|
||||
- {
|
||||
arch: x86_64,
|
||||
target: aarch64-linux-android,
|
||||
os: ubuntu-20.04,
|
||||
extra-build-features: "",
|
||||
openssl-arch: android-arm64
|
||||
}
|
||||
- {
|
||||
arch: x86_64,
|
||||
target: armv7-linux-androideabi,
|
||||
os: ubuntu-18.04,
|
||||
extra-build-features: "",
|
||||
openssl-arch: android-arm
|
||||
}
|
||||
steps:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ libc6-dev gcc-multilib g++-multilib openjdk-11-jdk-headless
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
- name: Install flutter
|
||||
uses: subosito/flutter-action@v2
|
||||
with:
|
||||
channel: "stable"
|
||||
flutter-version: ${{ env.FLUTTER_VERSION }}
|
||||
- uses: nttld/setup-ndk@v1
|
||||
id: setup-ndk
|
||||
with:
|
||||
ndk-version: ${{ env.NDK_VERSION }}
|
||||
add-to-path: true
|
||||
|
||||
- name: Clone deps
|
||||
shell: bash
|
||||
run: |
|
||||
pushd /opt
|
||||
git clone https://github.com/Kingtous/rustdesk_thirdparty_lib.git --depth=1
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: rustdesk-lib-cache
|
||||
key: ${{ matrix.job.target }}-${{ matrix.job.extra-build-features }}
|
||||
|
||||
- name: Disable rust bridge build
|
||||
run: |
|
||||
sed -i "s/gen_flutter_rust_bridge();/\/\//g" build.rs
|
||||
|
||||
- name: Build rustdesk lib
|
||||
env:
|
||||
ANDROID_NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
ANDROID_NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }}
|
||||
VCPKG_ROOT: /opt/rustdesk_thirdparty_lib/vcpkg
|
||||
run: |
|
||||
rustup target add ${{ matrix.job.target }}
|
||||
cargo install cargo-ndk
|
||||
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
|
||||
;;
|
||||
esac
|
||||
|
||||
- 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 /opt/rustdesk_thirdparty_lib/android/app/src/main/jniLibs/arm64-v8a/*.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 --release --target-platform android-arm64 --split-per-abi
|
||||
mv build/app/outputs/flutter-apk/app-arm64-v8a-release.apk ../rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-release.apk
|
||||
;;
|
||||
armv7-linux-androideabi)
|
||||
mkdir -p ./flutter/android/app/src/main/jniLibs/armeabi-v7a
|
||||
cp /opt/rustdesk_thirdparty_lib/android/app/src/main/jniLibs/armeabi-v7a/*.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 --release --target-platform android-arm --split-per-abi
|
||||
mv build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk ../rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-release.apk
|
||||
;;
|
||||
esac
|
||||
popd
|
||||
mkdir -p signed-apk; pushd signed-apk
|
||||
mv ../rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-release.apk .
|
||||
|
||||
build-rustdesk-lib-linux-amd64:
|
||||
needs: [generate-bridge-linux, build-vcpkg-deps-linux]
|
||||
name: build-rust-lib ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
# use a high level qemu-user-static
|
||||
job:
|
||||
# - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
|
||||
# - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
- {
|
||||
arch: x86_64,
|
||||
target: x86_64-unknown-linux-gnu,
|
||||
os: ubuntu-20.04,
|
||||
extra-build-features: "",
|
||||
}
|
||||
- {
|
||||
arch: x86_64,
|
||||
target: x86_64-unknown-linux-gnu,
|
||||
os: ubuntu-20.04,
|
||||
extra-build-features: "flatpak",
|
||||
}
|
||||
- {
|
||||
arch: x86_64,
|
||||
target: x86_64-unknown-linux-gnu,
|
||||
os: ubuntu-20.04,
|
||||
extra-build-features: "appimage",
|
||||
}
|
||||
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
- name: Maximize build space
|
||||
run: |
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo apt update -y
|
||||
sudo apt install qemu-user-static
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Swap Space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 12
|
||||
|
||||
- name: Free Space
|
||||
run: |
|
||||
df
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: rustdesk-lib-cache
|
||||
key: ${{ matrix.job.target }}-${{ matrix.job.extra-build-features }}
|
||||
cache-directories: "/opt/rust-registry"
|
||||
|
||||
- name: Install local registry
|
||||
run: |
|
||||
mkdir -p /opt/rust-registry
|
||||
cargo install cargo-local-registry
|
||||
|
||||
- name: Build local registry
|
||||
uses: nick-fields/retry@v2
|
||||
id: build-local-registry
|
||||
continue-on-error: true
|
||||
with:
|
||||
max_attempts: 3
|
||||
timeout_minutes: 15
|
||||
retry_on: error
|
||||
command: cargo local-registry --sync ./Cargo.lock /opt/rust-registry
|
||||
|
||||
- name: Disable rust bridge build
|
||||
run: |
|
||||
sed -i "s/gen_flutter_rust_bridge();/\/\//g" build.rs
|
||||
# only build cdylib
|
||||
sed -i "s/\[\"cdylib\", \"staticlib\", \"rlib\"\]/\[\"cdylib\"\]/g" Cargo.toml
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Restore vcpkg files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: vcpkg-artifact-${{ matrix.job.arch }}
|
||||
path: /opt/artifacts/vcpkg/installed
|
||||
|
||||
- uses: Kingtous/run-on-arch-action@amd64-support
|
||||
name: Build rustdesk library for ${{ matrix.job.arch }}
|
||||
id: vcpkg
|
||||
with:
|
||||
arch: ${{ matrix.job.arch }}
|
||||
distro: ubuntu18.04
|
||||
# not ready yet
|
||||
# distro: ubuntu18.04-rustdesk
|
||||
githubToken: ${{ github.token }}
|
||||
setup: |
|
||||
ls -l "${PWD}"
|
||||
ls -l /opt/artifacts/vcpkg/installed
|
||||
dockerRunArgs: |
|
||||
--volume "${PWD}:/workspace"
|
||||
--volume "/opt/artifacts:/opt/artifacts"
|
||||
--volume "/opt/rust-registry:/opt/rust-registry"
|
||||
shell: /bin/bash
|
||||
install: |
|
||||
apt update -y
|
||||
echo -e "installing deps"
|
||||
apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ gcc libvpx-dev tree > /dev/null
|
||||
# we have libopus compiled by us.
|
||||
apt 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
|
||||
wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-1.64.0-${{ matrix.job.target }}.tar.gz
|
||||
tar -zxvf rust.tar.gz > /dev/null && rm rust.tar.gz
|
||||
cd rust-1.64.0-${{ matrix.job.target }} && ./install.sh
|
||||
rm -rf rust-1.64.0-${{ matrix.job.target }}
|
||||
# edit config
|
||||
mkdir -p ~/.cargo/
|
||||
echo """
|
||||
[source.crates-io]
|
||||
registry = 'https://github.com/rust-lang/crates.io-index'
|
||||
replace-with = 'local-registry'
|
||||
|
||||
[source.local-registry]
|
||||
local-registry = '/opt/rust-registry/'
|
||||
""" > ~/.cargo/config
|
||||
cat ~/.cargo/config
|
||||
# start build
|
||||
pushd /workspace
|
||||
# mock
|
||||
case "${{ matrix.job.arch }}" in
|
||||
x86_64)
|
||||
# no need mock on x86_64
|
||||
export VCPKG_ROOT=/opt/artifacts/vcpkg
|
||||
cargo build --lib --features hwcodec,flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so
|
||||
path: target/release/liblibrustdesk.so
|
||||
|
||||
build-rustdesk-lib-linux-arm:
|
||||
needs: [generate-bridge-linux, build-vcpkg-deps-linux]
|
||||
name: build-rust-lib ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
# use a high level qemu-user-static
|
||||
job:
|
||||
- {
|
||||
arch: aarch64,
|
||||
target: aarch64-unknown-linux-gnu,
|
||||
os: ubuntu-20.04,
|
||||
use-cross: true,
|
||||
extra-build-features: "",
|
||||
}
|
||||
- {
|
||||
arch: aarch64,
|
||||
target: aarch64-unknown-linux-gnu,
|
||||
os: ubuntu-18.04, # just for naming package, not running host
|
||||
use-cross: true,
|
||||
extra-build-features: "appimage",
|
||||
}
|
||||
# - { arch: aarch64, target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true, extra-build-features: "flatpak" }
|
||||
# - {
|
||||
# arch: armv7,
|
||||
# target: arm-unknown-linux-gnueabihf,
|
||||
# os: ubuntu-20.04,
|
||||
# use-cross: true,
|
||||
# extra-build-features: "",
|
||||
# }
|
||||
# - { arch: armv7, target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "flatpak" }
|
||||
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
- name: Maximize build space
|
||||
run: |
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo apt update -y
|
||||
sudo apt install qemu-user-static
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Swap Space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 12
|
||||
|
||||
- name: Free Space
|
||||
run: |
|
||||
df
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: rustdesk-lib-cache
|
||||
key: ${{ matrix.job.target }}-${{ matrix.job.extra-build-features }}
|
||||
cache-directories: "/opt/rust-registry"
|
||||
|
||||
- name: Install local registry
|
||||
run: |
|
||||
mkdir -p /opt/rust-registry
|
||||
cargo install cargo-local-registry
|
||||
|
||||
- name: Build local registry
|
||||
uses: nick-fields/retry@v2
|
||||
id: build-local-registry
|
||||
continue-on-error: true
|
||||
with:
|
||||
max_attempts: 3
|
||||
timeout_minutes: 15
|
||||
retry_on: error
|
||||
command: cargo local-registry --sync ./Cargo.lock /opt/rust-registry
|
||||
|
||||
- name: Disable rust bridge build
|
||||
run: |
|
||||
sed -i "s/gen_flutter_rust_bridge();/\/\//g" build.rs
|
||||
# only build cdylib
|
||||
sed -i "s/\[\"cdylib\", \"staticlib\", \"rlib\"\]/\[\"cdylib\"\]/g" Cargo.toml
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Restore vcpkg files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: vcpkg-artifact-${{ matrix.job.arch }}
|
||||
path: /opt/artifacts/vcpkg/installed
|
||||
|
||||
- uses: Kingtous/run-on-arch-action@amd64-support
|
||||
name: Build rustdesk library for ${{ matrix.job.arch }}
|
||||
id: vcpkg
|
||||
with:
|
||||
arch: ${{ matrix.job.arch }}
|
||||
distro: ubuntu18.04-rustdesk
|
||||
githubToken: ${{ github.token }}
|
||||
setup: |
|
||||
ls -l "${PWD}"
|
||||
ls -l /opt/artifacts/vcpkg/installed
|
||||
dockerRunArgs: |
|
||||
--volume "${PWD}:/workspace"
|
||||
--volume "/opt/artifacts:/opt/artifacts"
|
||||
--volume "/opt/rust-registry:/opt/rust-registry"
|
||||
shell: /bin/bash
|
||||
install: |
|
||||
apt update -y
|
||||
echo -e "installing deps"
|
||||
apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev clang libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev libpulse-dev cmake libclang-dev ninja-build libappindicator3-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvdpau-dev libva-dev libclang-dev llvm-dev libclang-10-dev llvm-10-dev pkg-config tree g++ gcc libvpx-dev tree > /dev/null
|
||||
# we have libopus compiled by us.
|
||||
apt 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
|
||||
wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-1.64.0-${{ matrix.job.target }}.tar.gz
|
||||
tar -zxvf rust.tar.gz > /dev/null && rm rust.tar.gz
|
||||
cd rust-1.64.0-${{ matrix.job.target }} && ./install.sh
|
||||
rm -rf rust-1.64.0-${{ matrix.job.target }}
|
||||
# edit config
|
||||
mkdir -p ~/.cargo/
|
||||
echo """
|
||||
[source.crates-io]
|
||||
registry = 'https://github.com/rust-lang/crates.io-index'
|
||||
replace-with = 'local-registry'
|
||||
|
||||
[source.local-registry]
|
||||
local-registry = '/opt/rust-registry/'
|
||||
""" > ~/.cargo/config
|
||||
cat ~/.cargo/config
|
||||
# start build
|
||||
pushd /workspace
|
||||
# mock
|
||||
case "${{ matrix.job.arch }}" in
|
||||
aarch64)
|
||||
cp -r /opt/artifacts/vcpkg/installed/lib/* /usr/lib/aarch64-linux-gnu/
|
||||
cp -r /opt/artifacts/vcpkg/installed/include/* /usr/include/
|
||||
ls -l /opt/artifacts/vcpkg/installed/lib/
|
||||
mkdir -p /vcpkg/installed/arm64-linux
|
||||
ln -s /usr/lib/aarch64-linux-gnu /vcpkg/installed/arm64-linux/lib
|
||||
ln -s /usr/include /vcpkg/installed/arm64-linux/include
|
||||
export VCPKG_ROOT=/vcpkg
|
||||
# disable hwcodec for compilation
|
||||
cargo build --lib --features flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release
|
||||
;;
|
||||
armv7)
|
||||
cp -r /opt/artifacts/vcpkg/installed/lib/* /usr/lib/arm-linux-gnueabihf/
|
||||
cp -r /opt/artifacts/vcpkg/installed/include/* /usr/include/
|
||||
mkdir -p /vcpkg/installed/arm-linux
|
||||
ln -s /usr/lib/arm-linux-gnueabihf /vcpkg/installed/arm-linux/lib
|
||||
ln -s /usr/include /vcpkg/installed/arm-linux/include
|
||||
export VCPKG_ROOT=/vcpkg
|
||||
# disable hwcodec for compilation
|
||||
cargo build --lib --features flutter,flutter_texture_render,${{ matrix.job.extra-build-features }} --release
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so
|
||||
path: target/release/liblibrustdesk.so
|
||||
|
||||
build-rustdesk-linux-arm:
|
||||
needs: [build-rustdesk-lib-linux-arm]
|
||||
name: build-rustdesk ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
runs-on: ubuntu-20.04 # 20.04 has more performance on arm build
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
job:
|
||||
- {
|
||||
arch: aarch64,
|
||||
target: aarch64-unknown-linux-gnu,
|
||||
os: ubuntu-18.04, # just for naming package, not running host
|
||||
use-cross: true,
|
||||
extra-build-features: "",
|
||||
}
|
||||
- {
|
||||
arch: aarch64,
|
||||
target: aarch64-unknown-linux-gnu,
|
||||
os: ubuntu-18.04, # just for naming package, not running host
|
||||
use-cross: true,
|
||||
extra-build-features: "appimage",
|
||||
}
|
||||
# - {
|
||||
# arch: aarch64,
|
||||
# target: aarch64-unknown-linux-gnu,
|
||||
# os: ubuntu-18.04, # just for naming package, not running host
|
||||
# use-cross: true,
|
||||
# extra-build-features: "flatpak",
|
||||
# }
|
||||
# - { arch: armv7, target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "" }
|
||||
# - { arch: armv7, target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "flatpak" }
|
||||
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Prepare env
|
||||
run: |
|
||||
sudo apt update -y
|
||||
sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools
|
||||
mkdir -p ./target/release/
|
||||
|
||||
- name: Restore the rustdesk lib file
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so
|
||||
path: ./target/release/
|
||||
|
||||
- name: Download Flutter
|
||||
shell: bash
|
||||
run: |
|
||||
# disable git safe.directory
|
||||
git config --global --add safe.directory "*"
|
||||
pushd /opt
|
||||
# clone repo and reset to flutter 3.7.0
|
||||
git clone https://github.com/sony/flutter-elinux.git || true
|
||||
pushd flutter-elinux
|
||||
# reset to flutter 3.7.0
|
||||
git fetch
|
||||
git reset --hard 51a1d685901f79fbac51665a967c3a1a789ecee5
|
||||
popd
|
||||
|
||||
- uses: Kingtous/run-on-arch-action@amd64-support
|
||||
name: Build rustdesk binary for ${{ matrix.job.arch }}
|
||||
id: vcpkg
|
||||
with:
|
||||
arch: ${{ matrix.job.arch }}
|
||||
distro: ubuntu18.04-rustdesk
|
||||
githubToken: ${{ github.token }}
|
||||
setup: |
|
||||
ls -l "${PWD}"
|
||||
dockerRunArgs: |
|
||||
--volume "${PWD}:/workspace"
|
||||
--volume "/opt/artifacts:/opt/artifacts"
|
||||
--volume "/opt/flutter-elinux:/opt/flutter-elinux"
|
||||
shell: /bin/bash
|
||||
install: |
|
||||
apt update -y
|
||||
apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm
|
||||
run: |
|
||||
# disable git safe.directory
|
||||
git config --global --add safe.directory "*"
|
||||
pushd /workspace
|
||||
# we use flutter-elinux to build our rustdesk
|
||||
export PATH=/opt/flutter-elinux/bin:$PATH
|
||||
sed -i "s/flutter build linux --release/flutter-elinux build linux/g" ./build.py
|
||||
# Setup flutter-elinux. Run doctor to check if issues here.
|
||||
flutter-elinux doctor -v
|
||||
# Patch arm64 engine for flutter 3.6.0+
|
||||
flutter-elinux precache --linux
|
||||
pushd /tmp
|
||||
curl -O https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_3.7.0-stable.tar.xz
|
||||
tar -xvf flutter_linux_3.7.0-stable.tar.xz flutter/bin/cache/artifacts/engine/linux-x64/shader_lib
|
||||
cp -R flutter/bin/cache/artifacts/engine/linux-x64/shader_lib /opt/flutter-elinux/flutter/bin/cache/artifacts/engine/linux-arm64
|
||||
popd
|
||||
case ${{ matrix.job.arch }} in
|
||||
aarch64)
|
||||
sed -i "s/Architecture: amd64/Architecture: arm64/g" ./build.py
|
||||
sed -i "s/x64\/release/arm64\/release/g" ./build.py
|
||||
;;
|
||||
armv7)
|
||||
sed -i "s/Architecture: amd64/Architecture: arm/g" ./build.py
|
||||
sed -i "s/x64\/release/arm\/release/g" ./build.py
|
||||
;;
|
||||
esac
|
||||
python3 ./build.py --flutter --hwcodec --skip-cargo
|
||||
|
||||
build-rustdesk-linux-amd64:
|
||||
needs: [build-rustdesk-lib-linux-amd64]
|
||||
name: build-rustdesk ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
job:
|
||||
# - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
|
||||
# - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
- {
|
||||
arch: x86_64,
|
||||
target: x86_64-unknown-linux-gnu,
|
||||
os: ubuntu-20.04,
|
||||
extra-build-features: "",
|
||||
}
|
||||
- {
|
||||
arch: x86_64,
|
||||
target: x86_64-unknown-linux-gnu,
|
||||
os: ubuntu-20.04,
|
||||
extra-build-features: "flatpak",
|
||||
}
|
||||
- {
|
||||
arch: x86_64,
|
||||
target: x86_64-unknown-linux-gnu,
|
||||
os: ubuntu-20.04,
|
||||
extra-build-features: "appimage",
|
||||
}
|
||||
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Restore bridge files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: bridge-artifact
|
||||
path: ./
|
||||
|
||||
- name: Prepare env
|
||||
run: |
|
||||
sudo apt update -y
|
||||
sudo apt-get -qq install -y git curl wget nasm yasm libgtk-3-dev libarchive-tools
|
||||
mkdir -p ./target/release/
|
||||
|
||||
- name: Restore the rustdesk lib file
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so
|
||||
path: ./target/release/
|
||||
|
||||
- uses: Kingtous/run-on-arch-action@amd64-support
|
||||
name: Build rustdesk binary for ${{ matrix.job.arch }}
|
||||
id: vcpkg
|
||||
with:
|
||||
arch: ${{ matrix.job.arch }}
|
||||
distro: ubuntu18.04
|
||||
githubToken: ${{ github.token }}
|
||||
setup: |
|
||||
ls -l "${PWD}"
|
||||
dockerRunArgs: |
|
||||
--volume "${PWD}:/workspace"
|
||||
--volume "/opt/artifacts:/opt/artifacts"
|
||||
shell: /bin/bash
|
||||
install: |
|
||||
apt update -y
|
||||
apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm
|
||||
run: |
|
||||
# disable git safe.directory
|
||||
git config --global --add safe.directory "*"
|
||||
# Setup Flutter
|
||||
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
|
||||
ls -l .
|
||||
export PATH=/opt/flutter/bin:$PATH
|
||||
flutter doctor -v
|
||||
pushd /workspace
|
||||
python3 ./build.py --flutter --hwcodec --skip-cargo
|
||||
run-ci:
|
||||
uses: ./.github/workflows/flutter-nightly.yml
|
||||
with:
|
||||
upload-artifact: false
|
||||
|
335
.github/workflows/flutter-nightly.yml
vendored
335
.github/workflows/flutter-nightly.yml
vendored
@ -5,6 +5,16 @@ on:
|
||||
# schedule build every night
|
||||
- cron: "0 0 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
upload-artifact:
|
||||
description: "Upload the artifact produced by this workflow to the Release page."
|
||||
type: boolean
|
||||
default: true
|
||||
workflow_call:
|
||||
inputs:
|
||||
upload-artifact:
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
env:
|
||||
LLVM_VERSION: "15.0.6"
|
||||
@ -21,9 +31,10 @@ env:
|
||||
# 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 }}'
|
||||
UPLOAD_ARTIFACT: '${{ inputs.upload-artifact }}'
|
||||
|
||||
jobs:
|
||||
build-for-windows:
|
||||
build-for-windows-flutter:
|
||||
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
@ -33,7 +44,7 @@ jobs:
|
||||
# - { target: i686-pc-windows-msvc , os: windows-2019 }
|
||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
||||
- { target: x86_64-pc-windows-msvc, os: windows-2019 }
|
||||
# - { target: aarch64-pc-windows-msvc, os: windows-2019 }
|
||||
# - { target: aarch64-pc-windows-msvc, os: windows-2019, arch: aarch64 }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
@ -92,6 +103,7 @@ jobs:
|
||||
|
||||
- name: Sign rustdesk files
|
||||
uses: GermanBluefox/code-sign-action@v7
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
certificate: '${{ secrets.WINDOWS_PFX_BASE64 }}'
|
||||
password: '${{ secrets.WINDOWS_PFX_PASSWORD }}'
|
||||
@ -102,6 +114,7 @@ jobs:
|
||||
|
||||
- name: Build self-extracted executable
|
||||
shell: bash
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
run: |
|
||||
pushd ./libs/portable
|
||||
python3 ./generate.py -f ../../flutter/build/windows/runner/Release/ -o . -e ../../flutter/build/windows/runner/Release/rustdesk.exe
|
||||
@ -118,6 +131,7 @@ jobs:
|
||||
|
||||
- name: Sign rustdesk self-extracted file
|
||||
uses: GermanBluefox/code-sign-action@v7
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
certificate: '${{ secrets.WINDOWS_PFX_BASE64 }}'
|
||||
password: '${{ secrets.WINDOWS_PFX_PASSWORD }}'
|
||||
@ -128,6 +142,110 @@ jobs:
|
||||
|
||||
- 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
|
||||
|
||||
# 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-2019 }
|
||||
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
|
||||
- { target: i686-pc-windows-msvc, os: windows-2019 }
|
||||
# - { target: aarch64-pc-windows-msvc, os: windows-2019 }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install LLVM and Clang
|
||||
uses: Kingtous/install-llvm-action-32bit@master
|
||||
with:
|
||||
version: ${{ env.LLVM_VERSION }}
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable-${{ matrix.job.target }}
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- name: Set Rust toolchain to the target
|
||||
run: |
|
||||
rustup default stable-${{ matrix.job.target }}
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: ${{ matrix.job.os }}-sciter
|
||||
|
||||
- name: Restore from cache and install vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
with:
|
||||
setupOnly: true
|
||||
vcpkgGitCommitId: ${{ env.VCPKG_COMMIT_ID }}
|
||||
|
||||
- name: Install vcpkg dependencies
|
||||
run: |
|
||||
$VCPKG_ROOT/vcpkg install libvpx:x86-windows-static libyuv:x86-windows-static opus:x86-windows-static
|
||||
shell: bash
|
||||
|
||||
- name: Build rustdesk
|
||||
id: build
|
||||
shell: bash
|
||||
run: |
|
||||
python3 res/inline-sciter.py
|
||||
# Replace the link for the ico.
|
||||
rm res/icon.ico && cp flutter/windows/runner/resources/app_icon.ico res/icon.ico
|
||||
cargo build --features inline --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
|
||||
|
||||
- name: Sign rustdesk files
|
||||
uses: GermanBluefox/code-sign-action@v7
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
certificate: '${{ secrets.WINDOWS_PFX_BASE64 }}'
|
||||
password: '${{ secrets.WINDOWS_PFX_PASSWORD }}'
|
||||
certificatesha1: '${{ secrets.WINDOWS_PFX_SHA1_THUMBPRINT }}'
|
||||
# certificatename: '${{ secrets.CERTNAME }}'
|
||||
folder: './Release/'
|
||||
recursive: true
|
||||
|
||||
- name: Build self-extracted executable
|
||||
shell: bash
|
||||
run: |
|
||||
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.target }}-sciter.exe
|
||||
|
||||
- name: Sign rustdesk self-extracted file
|
||||
uses: GermanBluefox/code-sign-action@v7
|
||||
with:
|
||||
certificate: '${{ secrets.WINDOWS_PFX_BASE64 }}'
|
||||
password: '${{ secrets.WINDOWS_PFX_PASSWORD }}'
|
||||
certificatesha1: '${{ secrets.WINDOWS_PFX_SHA1_THUMBPRINT }}'
|
||||
# certificatename: '${{ secrets.WINDOWS_PFX_NAME }}'
|
||||
folder: './SignOutput'
|
||||
recursive: false
|
||||
|
||||
- name: Publish Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
@ -146,11 +264,6 @@ jobs:
|
||||
os: macos-latest,
|
||||
extra-build-args: "",
|
||||
}
|
||||
- {
|
||||
target: aarch64-apple-darwin,
|
||||
os: macos-latest,
|
||||
extra-build-args: "",
|
||||
}
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
@ -262,6 +375,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Publish DMG package
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -411,14 +525,14 @@ jobs:
|
||||
BUILD_TOOLS_VERSION: "30.0.2"
|
||||
|
||||
- name: Upload Artifacts
|
||||
if: env.ANDROID_SIGNING_KEY != null
|
||||
if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: actions/upload-artifact@master
|
||||
with:
|
||||
name: rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-release-signed.apk
|
||||
path: ${{steps.sign-rustdesk.outputs.signedReleaseFile}}
|
||||
|
||||
- name: Publish signed apk package
|
||||
if: env.ANDROID_SIGNING_KEY != null
|
||||
if: env.ANDROID_SIGNING_KEY != null && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -427,7 +541,7 @@ jobs:
|
||||
${{steps.sign-rustdesk.outputs.signedReleaseFile}}
|
||||
|
||||
- name: Publish unsigned apk package
|
||||
if: env.ANDROID_SIGNING_KEY == null
|
||||
if: env.ANDROID_SIGNING_KEY == null && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -622,12 +736,12 @@ jobs:
|
||||
# - { arch: aarch64, target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true, extra-build-features: "flatpak" }
|
||||
# - {
|
||||
# arch: armv7,
|
||||
# target: arm-unknown-linux-gnueabihf,
|
||||
# target: armv7-unknown-linux-gnueabihf,
|
||||
# os: ubuntu-20.04,
|
||||
# use-cross: true,
|
||||
# extra-build-features: "",
|
||||
# }
|
||||
# - { arch: armv7, target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "flatpak" }
|
||||
# - { arch: armv7, target: armv7-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "appimage" }
|
||||
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
- name: Maximize build space
|
||||
@ -743,30 +857,8 @@ jobs:
|
||||
cat ~/.cargo/config
|
||||
# start build
|
||||
pushd /workspace
|
||||
# mock
|
||||
case "${{ matrix.job.arch }}" in
|
||||
aarch64)
|
||||
cp -r /opt/artifacts/vcpkg/installed/lib/* /usr/lib/aarch64-linux-gnu/
|
||||
cp -r /opt/artifacts/vcpkg/installed/include/* /usr/include/
|
||||
ls -l /opt/artifacts/vcpkg/installed/lib/
|
||||
mkdir -p /vcpkg/installed/arm64-linux
|
||||
ln -s /usr/lib/aarch64-linux-gnu /vcpkg/installed/arm64-linux/lib
|
||||
ln -s /usr/include /vcpkg/installed/arm64-linux/include
|
||||
export VCPKG_ROOT=/vcpkg
|
||||
# disable hwcodec for compilation
|
||||
cargo build --lib --features flutter,${{ matrix.job.extra-build-features }} --release
|
||||
;;
|
||||
armv7)
|
||||
cp -r /opt/artifacts/vcpkg/installed/lib/* /usr/lib/arm-linux-gnueabihf/
|
||||
cp -r /opt/artifacts/vcpkg/installed/include/* /usr/include/
|
||||
mkdir -p /vcpkg/installed/arm-linux
|
||||
ln -s /usr/lib/arm-linux-gnueabihf /vcpkg/installed/arm-linux/lib
|
||||
ln -s /usr/include /vcpkg/installed/arm-linux/include
|
||||
export VCPKG_ROOT=/vcpkg
|
||||
# disable hwcodec for compilation
|
||||
cargo build --lib --features flutter,${{ matrix.job.extra-build-features }} --release
|
||||
;;
|
||||
esac
|
||||
export VCPKG_ROOT=/opt/artifacts/vcpkg
|
||||
cargo build --lib --features flutter,${{ matrix.job.extra-build-features }} --release
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@master
|
||||
@ -774,6 +866,158 @@ jobs:
|
||||
name: librustdesk-${{ matrix.job.arch }}-${{ matrix.job.extra-build-features }}.so
|
||||
path: target/release/liblibrustdesk.so
|
||||
|
||||
build-rustdesk-sciter-arm:
|
||||
needs: [build-vcpkg-deps-linux]
|
||||
name: build-rustdesk(sciter) ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
runs-on: ${{ matrix.job.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# use a high level qemu-user-static
|
||||
job:
|
||||
- {
|
||||
arch: armv7,
|
||||
target: armv7-unknown-linux-gnueabihf,
|
||||
deb-arch: armhf,
|
||||
os: ubuntu-latest,
|
||||
use-cross: true,
|
||||
extra-build-features: "",
|
||||
}
|
||||
# - { arch: armv7, target: armv7-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "appimage" }
|
||||
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
|
||||
- name: Maximize build space
|
||||
run: |
|
||||
sudo rm -rf /opt/ghc
|
||||
sudo rm -rf /usr/local/lib/android
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
sudo apt update -y
|
||||
sudo apt install qemu-user-static
|
||||
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set Swap Space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 12
|
||||
|
||||
- name: Free Space
|
||||
run: |
|
||||
df
|
||||
|
||||
- name: Install Rust toolchain
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
target: ${{ matrix.job.target }}
|
||||
override: true
|
||||
profile: minimal # minimal component installation (ie, no documentation)
|
||||
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
prefix-key: rustdesk-lib-cache
|
||||
key: ${{ matrix.job.target }}-${{ matrix.job.extra-build-features }}
|
||||
cache-directories: "/opt/rust-registry"
|
||||
|
||||
- name: Install local registry
|
||||
run: |
|
||||
mkdir -p /opt/rust-registry
|
||||
cargo install cargo-local-registry
|
||||
|
||||
- name: Build local registry
|
||||
uses: nick-fields/retry@v2
|
||||
id: build-local-registry
|
||||
continue-on-error: true
|
||||
with:
|
||||
max_attempts: 3
|
||||
timeout_minutes: 15
|
||||
retry_on: error
|
||||
command: cargo local-registry --sync ./Cargo.lock /opt/rust-registry
|
||||
|
||||
- name: Restore vcpkg files
|
||||
uses: actions/download-artifact@master
|
||||
with:
|
||||
name: vcpkg-artifact-${{ matrix.job.arch }}
|
||||
path: /opt/artifacts/vcpkg/installed
|
||||
|
||||
- uses: Kingtous/run-on-arch-action@amd64-support
|
||||
name: Build rustdesk sciter binary for ${{ matrix.job.arch }}
|
||||
id: vcpkg
|
||||
with:
|
||||
arch: ${{ matrix.job.arch }}
|
||||
distro: ubuntu18.04-rustdesk
|
||||
githubToken: ${{ github.token }}
|
||||
setup: |
|
||||
ls -l "${PWD}"
|
||||
dockerRunArgs: |
|
||||
--volume "${PWD}:/workspace"
|
||||
--volume "/opt/artifacts:/opt/artifacts"
|
||||
--volume "/opt/rust-registry:/opt/rust-registry"
|
||||
shell: /bin/bash
|
||||
install: |
|
||||
apt update -y
|
||||
apt-get -qq install -y git cmake g++ gcc build-essential nasm yasm curl unzip xz-utils python3 wget pkg-config ninja-build pkg-config libgtk-3-dev liblzma-dev clang libappindicator3-dev rpm libclang-dev
|
||||
apt-get -qq install -y libdbus-1-dev pkg-config nasm yasm libglib2.0-dev libxcb-randr0-dev libxdo-dev libxfixes-dev libxcb-shape0-dev libxcb-xfixes0-dev libasound2-dev
|
||||
apt-get -qq install -y libpulse-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libvpx-dev libvdpau-dev libva-dev
|
||||
run: |
|
||||
# disable git safe.directory
|
||||
git config --global --add safe.directory "*"
|
||||
# rust
|
||||
pushd /opt
|
||||
wget -O rust.tar.gz https://static.rust-lang.org/dist/rust-1.64.0-${{ matrix.job.target }}.tar.gz
|
||||
tar -zxvf rust.tar.gz > /dev/null && rm rust.tar.gz
|
||||
cd rust-1.64.0-${{ matrix.job.target }} && ./install.sh
|
||||
rm -rf rust-1.64.0-${{ matrix.job.target }}
|
||||
# edit config
|
||||
mkdir -p ~/.cargo/
|
||||
echo """
|
||||
[source.crates-io]
|
||||
registry = 'https://github.com/rust-lang/crates.io-index'
|
||||
replace-with = 'local-registry'
|
||||
|
||||
[source.local-registry]
|
||||
local-registry = '/opt/rust-registry/'
|
||||
""" > ~/.cargo/config
|
||||
cat ~/.cargo/config
|
||||
|
||||
# build
|
||||
pushd /workspace
|
||||
python3 ./res/inline-sciter.py
|
||||
export VCPKG_ROOT=/opt/artifacts/vcpkg
|
||||
export ARCH=armhf
|
||||
cargo build --features inline --release --bins
|
||||
# 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/arm32/libsciter-gtk.so
|
||||
./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.target }}-${{ matrix.job.os }}-sciter.deb"
|
||||
done
|
||||
|
||||
- name: Publish debian package
|
||||
if: ${{ matrix.job.extra-build-features == '' }} && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
files: |
|
||||
rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-${{ matrix.job.os }}-sciter.deb
|
||||
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@master
|
||||
if: ${{ contains(matrix.job.extra-build-features, 'flatpak') }}
|
||||
with:
|
||||
name: rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-${{ matrix.job.os }}-sciter.deb
|
||||
path: rustdesk-${{ env.VERSION }}-${{ matrix.job.target }}-${{ matrix.job.os }}-sciter.deb
|
||||
|
||||
build-rustdesk-linux-arm:
|
||||
needs: [build-rustdesk-lib-linux-arm]
|
||||
name: build-rustdesk ${{ matrix.job.target }} (${{ matrix.job.os }}) [${{ matrix.job.extra-build-features }}]
|
||||
@ -803,8 +1047,8 @@ jobs:
|
||||
# use-cross: true,
|
||||
# extra-build-features: "flatpak",
|
||||
# }
|
||||
# - { arch: armv7, target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "" }
|
||||
# - { arch: armv7, target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "flatpak" }
|
||||
# - { arch: armv7, target: armv7-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "" }
|
||||
# - { arch: armv7, target: armv7-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true, extra-build-features: "appimage" }
|
||||
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
@ -932,7 +1176,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Publish debian package
|
||||
if: ${{ matrix.job.extra-build-features == '' }}
|
||||
if: ${{ matrix.job.extra-build-features == '' }} && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -955,7 +1199,7 @@ jobs:
|
||||
sudo appimage-builder --skip-tests --recipe ./AppImageBuilder-${{ matrix.job.arch }}.yml
|
||||
|
||||
- name: Publish appimage package
|
||||
if: ${{ matrix.job.extra-build-features == 'appimage' }}
|
||||
if: ${{ matrix.job.extra-build-features == 'appimage' }} && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -1029,7 +1273,7 @@ jobs:
|
||||
# res/rustdesk*.zst
|
||||
|
||||
- name: Publish fedora28/centos8 package
|
||||
if: ${{ matrix.job.extra-build-features == '' }}
|
||||
if: ${{ matrix.job.extra-build-features == '' }} && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -1152,7 +1396,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Publish debian package
|
||||
if: ${{ matrix.job.extra-build-features == '' }}
|
||||
if: ${{ matrix.job.extra-build-features == '' }} && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -1208,7 +1452,7 @@ jobs:
|
||||
cd res && HBB=`pwd`/.. FLUTTER=1 makepkg -f
|
||||
|
||||
- name: Publish archlinux package
|
||||
if: ${{ matrix.job.extra-build-features == '' }}
|
||||
if: ${{ matrix.job.extra-build-features == '' }} && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -1231,7 +1475,7 @@ jobs:
|
||||
sudo appimage-builder --skip-tests --recipe ./AppImageBuilder-x86_64.yml
|
||||
|
||||
- name: Publish appimage package
|
||||
if: ${{ matrix.job.extra-build-features == 'appimage' }}
|
||||
if: ${{ matrix.job.extra-build-features == 'appimage' }} && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -1240,7 +1484,7 @@ jobs:
|
||||
./appimage/rustdesk-${{ env.VERSION }}-*.AppImage
|
||||
|
||||
- name: Publish fedora28/centos8 package
|
||||
if: ${{ matrix.job.extra-build-features == '' }}
|
||||
if: ${{ matrix.job.extra-build-features == '' }} && env.UPLOAD_ARTIFACT == 'true'
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
prerelease: true
|
||||
@ -1369,6 +1613,7 @@ jobs:
|
||||
|
||||
- name: Publish flatpak package
|
||||
uses: softprops/action-gh-release@v1
|
||||
if: env.UPLOAD_ARTIFACT == 'true'
|
||||
with:
|
||||
prerelease: true
|
||||
tag_name: ${{ env.TAG_NAME }}
|
||||
|
36
.github/workflows/vcpkg-deps-linux.yml
vendored
36
.github/workflows/vcpkg-deps-linux.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
job:
|
||||
# - { arch: armv7, os: ubuntu-20.04 }
|
||||
- { arch: armv7, os: ubuntu-20.04 }
|
||||
- { arch: x86_64, os: ubuntu-20.04 }
|
||||
- { arch: aarch64, os: ubuntu-20.04 }
|
||||
steps:
|
||||
@ -46,12 +46,12 @@ jobs:
|
||||
wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
|
||||
apt update -y
|
||||
apt install -y curl zip unzip tar git cmake g++ gcc build-essential pkg-config wget nasm yasm ninja-build libjpeg8-dev
|
||||
cmake --version
|
||||
gcc -v
|
||||
;;
|
||||
aarch64|armv7)
|
||||
apt install -y curl zip unzip tar git cmake g++ gcc build-essential pkg-config wget nasm yasm ninja-build libjpeg8-dev automake libtool
|
||||
apt install -y curl zip unzip git
|
||||
esac
|
||||
cmake --version
|
||||
gcc -v
|
||||
run: |
|
||||
# disable git safe.directory
|
||||
git config --global --add safe.directory "*"
|
||||
@ -65,25 +65,19 @@ jobs:
|
||||
./bootstrap-vcpkg.sh
|
||||
./vcpkg install libvpx libyuv opus
|
||||
;;
|
||||
aarch64|armv7)
|
||||
aarch64)
|
||||
pushd /artifacts
|
||||
# libyuv
|
||||
git clone https://chromium.googlesource.com/libyuv/libyuv || true
|
||||
pushd libyuv
|
||||
git pull
|
||||
mkdir -p build
|
||||
pushd build
|
||||
rm -rf rustdesk_thirdparty_lib
|
||||
git clone https://github.com/Kingtous/rustdesk_thirdparty_lib.git --depth=1
|
||||
mkdir -p /artifacts/vcpkg/installed
|
||||
cmake .. -DCMAKE_INSTALL_PREFIX=/artifacts/vcpkg/installed
|
||||
make -j4 && make install
|
||||
popd
|
||||
popd
|
||||
# libopus, ubuntu 18.04 prebuilt is not be compiled with -fPIC
|
||||
wget -O opus.tar.gz http://archive.ubuntu.com/ubuntu/pool/main/o/opus/opus_1.1.2.orig.tar.gz
|
||||
tar -zxvf opus.tar.gz; ls -l
|
||||
pushd opus-1.1.2
|
||||
./autogen.sh; ./configure --prefix=/artifacts/vcpkg/installed
|
||||
make -j4; make install
|
||||
mv ./rustdesk_thirdparty_lib/vcpkg/installed/arm64-linux /artifacts/vcpkg/installed/arm64-linux
|
||||
;;
|
||||
armv7)
|
||||
pushd /artifacts
|
||||
rm -rf rustdesk_thirdparty_lib
|
||||
git clone https://github.com/Kingtous/rustdesk_thirdparty_lib.git --depth=1
|
||||
mkdir -p /artifacts/vcpkg/installed
|
||||
mv ./rustdesk_thirdparty_lib/vcpkg/installed/arm-linux /artifacts/vcpkg/installed/arm-linux
|
||||
;;
|
||||
esac
|
||||
- name: Upload artifacts
|
||||
|
1089
Cargo.lock
generated
1089
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
21
Cargo.toml
21
Cargo.toml
@ -57,21 +57,22 @@ rpassword = "7.0"
|
||||
base64 = "0.21"
|
||||
num_cpus = "1.13"
|
||||
bytes = { version = "1.2", features = ["serde"] }
|
||||
default-net = "0.12.0"
|
||||
default-net = "0.14"
|
||||
wol-rs = "1.0"
|
||||
flutter_rust_bridge = { version = "1.61.1", optional = true }
|
||||
errno = "0.3"
|
||||
rdev = { git = "https://github.com/fufesou/rdev" }
|
||||
url = { version = "2.1", features = ["serde"] }
|
||||
dlopen = "0.1"
|
||||
hex = "0.4.3"
|
||||
|
||||
crossbeam-queue = "0.3"
|
||||
hex = "0.4"
|
||||
reqwest = { version = "0.11", features = ["blocking", "json", "rustls-tls"], default-features=false }
|
||||
chrono = "0.4.23"
|
||||
cidr-utils = "0.5.9"
|
||||
chrono = "0.4"
|
||||
cidr-utils = "0.5"
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "linux")))'.dependencies]
|
||||
cpal = "0.14"
|
||||
ringbuf = "0.3"
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||
machine-uid = "0.2"
|
||||
@ -93,8 +94,8 @@ winreg = "0.10"
|
||||
windows-service = "0.4"
|
||||
virtual_display = { path = "libs/virtual_display" }
|
||||
impersonate_system = { git = "https://github.com/21pages/impersonate-system" }
|
||||
shared_memory = "0.12.4"
|
||||
shutdown_hooks = "0.1.0"
|
||||
shared_memory = "0.12"
|
||||
shutdown_hooks = "0.1"
|
||||
|
||||
[target.'cfg(target_os = "macos")'.dependencies]
|
||||
objc = "0.2"
|
||||
@ -102,10 +103,10 @@ cocoa = "0.24"
|
||||
dispatch = "0.2"
|
||||
core-foundation = "0.9"
|
||||
core-graphics = "0.22"
|
||||
include_dir = "0.7.2"
|
||||
include_dir = "0.7"
|
||||
dark-light = "1.0"
|
||||
fruitbasket = "0.10.0"
|
||||
objc_id = "0.1.1"
|
||||
fruitbasket = "0.10"
|
||||
objc_id = "0.1"
|
||||
|
||||
[target.'cfg(any(target_os = "macos", target_os = "linux"))'.dependencies]
|
||||
tray-icon = "0.4"
|
||||
|
51
build.py
51
build.py
@ -18,6 +18,12 @@ exe_path = 'target/release/' + hbb_name
|
||||
flutter_win_target_dir = 'flutter/build/windows/runner/Release/'
|
||||
skip_cargo = False
|
||||
|
||||
def get_arch() -> str:
|
||||
custom_arch = os.environ.get("ARCH")
|
||||
if custom_arch is None:
|
||||
return "amd64"
|
||||
return custom_arch
|
||||
|
||||
def system2(cmd):
|
||||
err = os.system(cmd)
|
||||
if err != 0:
|
||||
@ -106,6 +112,10 @@ def make_parser():
|
||||
action='store_true',
|
||||
help='Skip cargo build process, only flutter version + Linux supported currently'
|
||||
)
|
||||
parser.add_argument(
|
||||
"--package",
|
||||
type=str
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
@ -251,13 +261,13 @@ def generate_control_file(version):
|
||||
|
||||
content = """Package: rustdesk
|
||||
Version: %s
|
||||
Architecture: amd64
|
||||
Architecture: %s
|
||||
Maintainer: open-trade <info@rustdesk.com>
|
||||
Homepage: https://rustdesk.com
|
||||
Depends: libgtk-3-0, libxcb-randr0, libxdo3, libxfixes3, libxcb-shape0, libxcb-xfixes0, libasound2, libsystemd0, curl, libva-drm2, libva-x11-2, libvdpau1, libgstreamer-plugins-base1.0-0
|
||||
Description: A remote control software.
|
||||
|
||||
""" % version
|
||||
""" % (version, get_arch())
|
||||
file = open(control_file_path, "w")
|
||||
file.write(content)
|
||||
file.close()
|
||||
@ -307,6 +317,39 @@ def build_flutter_deb(version, features):
|
||||
os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version)
|
||||
os.chdir("..")
|
||||
|
||||
def build_deb_from_folder(version, binary_folder):
|
||||
os.chdir('flutter')
|
||||
system2('mkdir -p tmpdeb/usr/bin/')
|
||||
system2('mkdir -p tmpdeb/usr/lib/rustdesk')
|
||||
system2('mkdir -p tmpdeb/usr/share/rustdesk/files/systemd/')
|
||||
system2('mkdir -p tmpdeb/usr/share/applications/')
|
||||
system2('mkdir -p tmpdeb/usr/share/polkit-1/actions')
|
||||
system2('rm tmpdeb/usr/bin/rustdesk || true')
|
||||
system2(
|
||||
f'cp -r ../{binary_folder}/* tmpdeb/usr/lib/rustdesk/')
|
||||
system2(
|
||||
'cp ../res/rustdesk.service tmpdeb/usr/share/rustdesk/files/systemd/')
|
||||
system2(
|
||||
'cp ../res/128x128@2x.png tmpdeb/usr/share/rustdesk/files/rustdesk.png')
|
||||
system2(
|
||||
'cp ../res/rustdesk.desktop tmpdeb/usr/share/applications/rustdesk.desktop')
|
||||
system2(
|
||||
'cp ../res/rustdesk-link.desktop tmpdeb/usr/share/applications/rustdesk-link.desktop')
|
||||
system2(
|
||||
'cp ../res/com.rustdesk.RustDesk.policy tmpdeb/usr/share/polkit-1/actions/')
|
||||
system2(
|
||||
"echo \"#!/bin/sh\" >> tmpdeb/usr/share/rustdesk/files/polkit && chmod a+x tmpdeb/usr/share/rustdesk/files/polkit")
|
||||
|
||||
system2('mkdir -p tmpdeb/DEBIAN')
|
||||
generate_control_file(version)
|
||||
system2('cp -a ../res/DEBIAN/* tmpdeb/DEBIAN/')
|
||||
md5_file('usr/share/rustdesk/files/systemd/rustdesk.service')
|
||||
system2('dpkg-deb -b tmpdeb rustdesk.deb;')
|
||||
|
||||
system2('/bin/rm -rf tmpdeb/')
|
||||
system2('/bin/rm -rf ../res/DEBIAN/control')
|
||||
os.rename('rustdesk.deb', '../rustdesk-%s.deb' % version)
|
||||
os.chdir("..")
|
||||
|
||||
def build_flutter_dmg(version, features):
|
||||
if not skip_cargo:
|
||||
@ -381,6 +424,10 @@ def main():
|
||||
if args.skip_cargo:
|
||||
skip_cargo = True
|
||||
portable = args.portable
|
||||
package = args.package
|
||||
if package:
|
||||
build_deb_from_folder(version, package)
|
||||
return
|
||||
if windows:
|
||||
# build virtual display dynamic library
|
||||
os.chdir('libs/virtual_display/dylib')
|
||||
|
@ -186,6 +186,71 @@ class MyTheme {
|
||||
static const Color button = Color(0xFF2C8CFF);
|
||||
static const Color hoverBorder = Color(0xFF999999);
|
||||
|
||||
// ListTile
|
||||
static const ListTileThemeData listTileTheme = ListTileThemeData(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(5),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Checkbox
|
||||
static const CheckboxThemeData checkboxTheme = CheckboxThemeData(
|
||||
splashRadius: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(5),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// TextButton
|
||||
// Value is used to calculate "dialog.actionsPadding"
|
||||
static const double mobileTextButtonPaddingLR = 20;
|
||||
|
||||
// TextButton on mobile needs a fixed padding, otherwise small buttons
|
||||
// like "OK" has a larger left/right padding.
|
||||
static TextButtonThemeData mobileTextButtonTheme = TextButtonThemeData(
|
||||
style: TextButton.styleFrom(
|
||||
padding: EdgeInsets.symmetric(horizontal: mobileTextButtonPaddingLR),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8.0),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// Dialogs
|
||||
static const double dialogPadding = 24;
|
||||
|
||||
// padding bottom depends on content (some dialogs has no content)
|
||||
static EdgeInsets dialogTitlePadding({bool content = true}) {
|
||||
final double p = dialogPadding;
|
||||
|
||||
return EdgeInsets.fromLTRB(p, p, p, content ? 0 : p);
|
||||
}
|
||||
|
||||
// padding bottom depends on actions (mobile has dialogs without actions)
|
||||
static EdgeInsets dialogContentPadding({bool actions = true}) {
|
||||
final double p = dialogPadding;
|
||||
|
||||
return isDesktop
|
||||
? EdgeInsets.fromLTRB(p, p, p, actions ? (p - 4) : p)
|
||||
: EdgeInsets.fromLTRB(p, p, p, actions ? (p / 2) : p);
|
||||
}
|
||||
|
||||
static EdgeInsets dialogActionsPadding() {
|
||||
final double p = dialogPadding;
|
||||
|
||||
return isDesktop
|
||||
? EdgeInsets.fromLTRB(p, 0, p, (p - 4))
|
||||
: EdgeInsets.fromLTRB(p, 0, (p - mobileTextButtonPaddingLR), (p / 2));
|
||||
}
|
||||
|
||||
static EdgeInsets dialogButtonPadding = isDesktop
|
||||
? EdgeInsets.only(left: dialogPadding)
|
||||
: EdgeInsets.only(left: dialogPadding / 3);
|
||||
|
||||
static ThemeData lightTheme = ThemeData(
|
||||
brightness: Brightness.light,
|
||||
hoverColor: Color.fromARGB(255, 224, 224, 224),
|
||||
@ -236,7 +301,7 @@ class MyTheme {
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
: mobileTextButtonTheme,
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: MyTheme.accent,
|
||||
@ -254,21 +319,8 @@ class MyTheme {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkboxTheme: const CheckboxThemeData(
|
||||
splashRadius: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(5),
|
||||
),
|
||||
),
|
||||
),
|
||||
listTileTheme: ListTileThemeData(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(5),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkboxTheme: checkboxTheme,
|
||||
listTileTheme: listTileTheme,
|
||||
menuBarTheme: MenuBarThemeData(
|
||||
style:
|
||||
MenuStyle(backgroundColor: MaterialStatePropertyAll(Colors.white))),
|
||||
@ -334,7 +386,7 @@ class MyTheme {
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
: mobileTextButtonTheme,
|
||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: MyTheme.accent,
|
||||
@ -357,21 +409,8 @@ class MyTheme {
|
||||
),
|
||||
),
|
||||
),
|
||||
checkboxTheme: const CheckboxThemeData(
|
||||
splashRadius: 0,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(5),
|
||||
),
|
||||
),
|
||||
),
|
||||
listTileTheme: ListTileThemeData(
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(5),
|
||||
),
|
||||
),
|
||||
),
|
||||
checkboxTheme: checkboxTheme,
|
||||
listTileTheme: listTileTheme,
|
||||
menuBarTheme: MenuBarThemeData(
|
||||
style: MenuStyle(
|
||||
backgroundColor: MaterialStatePropertyAll(Color(0xFF121212)))),
|
||||
@ -771,6 +810,10 @@ void showToast(String text, {Duration timeout = const Duration(seconds: 2)}) {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO
|
||||
// - Remove argument "contentPadding", no need for it, all should look the same.
|
||||
// - Remove "required" for argument "content". See simple confirm dialog "delete peer", only title and actions are used. No need to "content: SizedBox.shrink()".
|
||||
// - Make dead code alive, transform arguments "onSubmit" and "onCancel" into correspondenting buttons "ConfirmOkButton", "CancelButton".
|
||||
class CustomAlertDialog extends StatelessWidget {
|
||||
const CustomAlertDialog(
|
||||
{Key? key,
|
||||
@ -798,8 +841,8 @@ class CustomAlertDialog extends StatelessWidget {
|
||||
Future.delayed(Duration.zero, () {
|
||||
if (!scopeNode.hasFocus) scopeNode.requestFocus();
|
||||
});
|
||||
const double padding = 30;
|
||||
bool tabTapped = false;
|
||||
|
||||
return FocusScope(
|
||||
node: scopeNode,
|
||||
autofocus: true,
|
||||
@ -824,22 +867,18 @@ class CustomAlertDialog extends StatelessWidget {
|
||||
return KeyEventResult.ignored;
|
||||
},
|
||||
child: AlertDialog(
|
||||
scrollable: true,
|
||||
title: title,
|
||||
titlePadding: EdgeInsets.fromLTRB(padding, 24, padding, 0),
|
||||
contentPadding: EdgeInsets.fromLTRB(
|
||||
contentPadding ?? padding,
|
||||
25,
|
||||
contentPadding ?? padding,
|
||||
actions is List ? 10 : padding,
|
||||
),
|
||||
content: ConstrainedBox(
|
||||
constraints: contentBoxConstraints,
|
||||
child: content,
|
||||
),
|
||||
actions: actions,
|
||||
actionsPadding: EdgeInsets.fromLTRB(padding, 0, padding, padding),
|
||||
),
|
||||
scrollable: true,
|
||||
title: title,
|
||||
content: ConstrainedBox(
|
||||
constraints: contentBoxConstraints,
|
||||
child: content,
|
||||
),
|
||||
actions: actions,
|
||||
titlePadding: MyTheme.dialogTitlePadding(content: content != null),
|
||||
contentPadding:
|
||||
MyTheme.dialogContentPadding(actions: actions is List),
|
||||
actionsPadding: MyTheme.dialogActionsPadding(),
|
||||
buttonPadding: MyTheme.dialogButtonPadding),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1115,25 +1154,32 @@ class AndroidPermissionManager {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO move this to mobile/widgets.
|
||||
// Used only for mobile, pages remote, settings, dialog
|
||||
// TODO remove argument contentPadding, it’s not used, getToggle() has not
|
||||
RadioListTile<T> getRadio<T>(
|
||||
String name, T toValue, T curValue, void Function(T?) onChange,
|
||||
{EdgeInsetsGeometry? contentPadding}) {
|
||||
return RadioListTile<T>(
|
||||
contentPadding: contentPadding,
|
||||
contentPadding: contentPadding ?? EdgeInsets.zero,
|
||||
visualDensity: VisualDensity.compact,
|
||||
controlAffinity: ListTileControlAffinity.trailing,
|
||||
title: Text(translate(name)),
|
||||
value: toValue,
|
||||
groupValue: curValue,
|
||||
onChanged: onChange,
|
||||
dense: true,
|
||||
);
|
||||
}
|
||||
|
||||
// TODO move this to mobile/widgets.
|
||||
// Used only for mobile, pages remote, settings, dialog
|
||||
CheckboxListTile getToggle(
|
||||
String id, void Function(void Function()) setState, option, name,
|
||||
{FFI? ffi}) {
|
||||
final opt = bind.sessionGetToggleOptionSync(id: id, arg: option);
|
||||
return CheckboxListTile(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
visualDensity: VisualDensity.compact,
|
||||
value: opt,
|
||||
onChanged: (v) {
|
||||
setState(() {
|
||||
@ -1143,7 +1189,6 @@ CheckboxListTile getToggle(
|
||||
(ffi ?? gFFI).qualityMonitorModel.checkShowQualityMonitor(id);
|
||||
}
|
||||
},
|
||||
dense: true,
|
||||
title: Text(translate(name)));
|
||||
}
|
||||
|
||||
|
@ -802,7 +802,7 @@ class _FileManagerViewState extends State<FileManagerView> {
|
||||
switchType: SwitchType.scheckbox,
|
||||
text: translate("Show Hidden Files"),
|
||||
getter: () async {
|
||||
return controller.options.value.isWindows;
|
||||
return controller.options.value.showHidden;
|
||||
},
|
||||
setter: (bool v) async {
|
||||
controller.toggleShowHidden();
|
||||
|
@ -696,10 +696,8 @@ class _RemotePageState extends State<RemotePage> {
|
||||
// return CustomAlertDialog(
|
||||
// title: Text(translate('Physical Keyboard Input Mode')),
|
||||
// content: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
// getRadio('Legacy mode', 'legacy', current, setMode,
|
||||
// contentPadding: EdgeInsets.zero),
|
||||
// getRadio('Map mode', 'map', current, setMode,
|
||||
// contentPadding: EdgeInsets.zero),
|
||||
// getRadio('Legacy mode', 'legacy', current, setMode),
|
||||
// getRadio('Map mode', 'map', current, setMode),
|
||||
// ]));
|
||||
// }, clickMaskDismiss: true);
|
||||
// }
|
||||
@ -1069,7 +1067,6 @@ void showOptions(
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: displays + radios + toggles + more),
|
||||
contentPadding: 0,
|
||||
);
|
||||
}, clickMaskDismiss: true, backDismiss: true);
|
||||
}
|
||||
|
@ -502,19 +502,18 @@ void showLanguageSettings(OverlayDialogManager dialogManager) async {
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: SizedBox.shrink(),
|
||||
content: Column(
|
||||
children: [
|
||||
getRadio('Default', '', lang, setLang),
|
||||
Divider(color: MyTheme.border),
|
||||
] +
|
||||
langs.map((e) {
|
||||
final key = e[0] as String;
|
||||
final name = e[1] as String;
|
||||
return getRadio(name, key, lang, setLang);
|
||||
}).toList(),
|
||||
),
|
||||
actions: []);
|
||||
content: Column(
|
||||
children: [
|
||||
getRadio('Default', '', lang, setLang),
|
||||
Divider(color: MyTheme.border),
|
||||
] +
|
||||
langs.map((e) {
|
||||
final key = e[0] as String;
|
||||
final name = e[1] as String;
|
||||
return getRadio(name, key, lang, setLang);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
}, backDismiss: true, clickMaskDismiss: true);
|
||||
} catch (e) {
|
||||
//
|
||||
@ -536,14 +535,12 @@ void showThemeSettings(OverlayDialogManager dialogManager) async {
|
||||
}
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: SizedBox.shrink(),
|
||||
contentPadding: 10,
|
||||
content: Column(children: [
|
||||
getRadio('Light', ThemeMode.light, themeMode, setTheme),
|
||||
getRadio('Dark', ThemeMode.dark, themeMode, setTheme),
|
||||
getRadio('Follow System', ThemeMode.system, themeMode, setTheme)
|
||||
]),
|
||||
actions: []);
|
||||
content: Column(children: [
|
||||
getRadio('Light', ThemeMode.light, themeMode, setTheme),
|
||||
getRadio('Dark', ThemeMode.dark, themeMode, setTheme),
|
||||
getRadio('Follow System', ThemeMode.system, themeMode, setTheme)
|
||||
]),
|
||||
);
|
||||
}, backDismiss: true, clickMaskDismiss: true);
|
||||
}
|
||||
|
||||
|
@ -128,12 +128,19 @@ void setTemporaryPasswordLengthDialog(
|
||||
|
||||
return CustomAlertDialog(
|
||||
title: Text(translate("Set one-time password length")),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children:
|
||||
lengths.map((e) => getRadio(e, e, length, setLength)).toList()),
|
||||
actions: [],
|
||||
contentPadding: 14,
|
||||
content: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: lengths
|
||||
.map(
|
||||
(value) => Row(
|
||||
children: [
|
||||
Text(value),
|
||||
Radio(
|
||||
value: value, groupValue: length, onChanged: setLength),
|
||||
],
|
||||
),
|
||||
)
|
||||
.toList()),
|
||||
);
|
||||
}, backDismiss: true, clickMaskDismiss: true);
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ def main():
|
||||
b = toks[1].replace('ControlKey(ControlKey::', '').replace("Chr('", '').replace("' as _)),", '').replace(')),', '')
|
||||
KEY_MAP[0] += ' "%s": "%s",\n'%(a, b)
|
||||
print()
|
||||
print('export function checkIfRetry(msgtype: string, title: string, text: string) {')
|
||||
print('export function checkIfRetry(msgtype: string, title: string, text: string, retry_for_relay: boolean) {')
|
||||
print(' return %s'%check_if_retry[0].replace('to_lowercase', 'toLowerCase').replace('contains', 'indexOf').replace('!', '').replace('")', '") < 0'))
|
||||
print(';}')
|
||||
print()
|
||||
|
@ -115,7 +115,7 @@ impl Enigo {
|
||||
|
||||
impl Default for Enigo {
|
||||
fn default() -> Self {
|
||||
let is_x11 = "x11" == hbb_common::platform::linux::get_display_server();
|
||||
let is_x11 = hbb_common::platform::linux::is_x11_or_headless();
|
||||
Self {
|
||||
is_x11,
|
||||
tfc: if is_x11 {
|
||||
|
@ -915,15 +915,12 @@ impl PeerConfig {
|
||||
decrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION);
|
||||
config.password = password;
|
||||
store = store || store2;
|
||||
if let Some(v) = config.options.get_mut("rdp_password") {
|
||||
let (password, _, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
|
||||
*v = password;
|
||||
store = store || store2;
|
||||
}
|
||||
if let Some(v) = config.options.get_mut("os-password") {
|
||||
let (password, _, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
|
||||
*v = password;
|
||||
store = store || store2;
|
||||
for opt in ["rdp_password", "os-password"] {
|
||||
if let Some(v) = config.options.get_mut(opt) {
|
||||
let (encrypted, _, store2) = decrypt_str_or_original(v, PASSWORD_ENC_VERSION);
|
||||
*v = encrypted;
|
||||
store = store || store2;
|
||||
}
|
||||
}
|
||||
if store {
|
||||
config.store(id);
|
||||
@ -941,12 +938,11 @@ impl PeerConfig {
|
||||
let _lock = CONFIG.read().unwrap();
|
||||
let mut config = self.clone();
|
||||
config.password = encrypt_vec_or_original(&config.password, PASSWORD_ENC_VERSION);
|
||||
if let Some(v) = config.options.get_mut("rdp_password") {
|
||||
*v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION)
|
||||
for opt in ["rdp_password", "os-password"] {
|
||||
if let Some(v) = config.options.get_mut(opt) {
|
||||
*v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION)
|
||||
}
|
||||
}
|
||||
if let Some(v) = config.options.get_mut("os-password") {
|
||||
*v = encrypt_str_or_original(v, PASSWORD_ENC_VERSION)
|
||||
};
|
||||
if let Err(err) = store_path(Self::path(id), config) {
|
||||
log::error!("Failed to store config: {}", err);
|
||||
}
|
||||
|
@ -5,6 +5,9 @@ lazy_static::lazy_static! {
|
||||
pub static ref DISTRO: Distro = Distro::new();
|
||||
}
|
||||
|
||||
pub const DISPLAY_SERVER_WAYLAND: &str = "wayland";
|
||||
pub const DISPLAY_SERVER_X11: &str = "x11";
|
||||
|
||||
pub struct Distro {
|
||||
pub name: String,
|
||||
pub version_id: String,
|
||||
@ -12,23 +15,41 @@ pub struct Distro {
|
||||
|
||||
impl Distro {
|
||||
fn new() -> Self {
|
||||
let name = run_cmds("awk -F'=' '/^NAME=/ {print $2}' /etc/os-release".to_owned())
|
||||
let name = run_cmds("awk -F'=' '/^NAME=/ {print $2}' /etc/os-release")
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.trim_matches('"')
|
||||
.to_string();
|
||||
let version_id = run_cmds("awk -F'=' '/^VERSION_ID=/ {print $2}' /etc/os-release")
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.trim_matches('"')
|
||||
.to_string();
|
||||
let version_id =
|
||||
run_cmds("awk -F'=' '/^VERSION_ID=/ {print $2}' /etc/os-release".to_owned())
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.trim_matches('"')
|
||||
.to_string();
|
||||
Self { name, version_id }
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_gdm_user(username: &str) -> bool {
|
||||
username == "gdm"
|
||||
// || username == "lightgdm"
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_desktop_wayland() -> bool {
|
||||
get_display_server() == DISPLAY_SERVER_WAYLAND
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_x11_or_headless() -> bool {
|
||||
!is_desktop_wayland()
|
||||
}
|
||||
|
||||
// -1
|
||||
const INVALID_SESSION: &str = "4294967295";
|
||||
|
||||
pub fn get_display_server() -> String {
|
||||
let mut session = get_values_of_seat0([0].to_vec())[0].clone();
|
||||
let mut session = get_values_of_seat0(&[0])[0].clone();
|
||||
if session.is_empty() {
|
||||
// loginctl has not given the expected output. try something else.
|
||||
if let Ok(sid) = std::env::var("XDG_SESSION_ID") {
|
||||
@ -36,14 +57,20 @@ pub fn get_display_server() -> String {
|
||||
session = sid;
|
||||
}
|
||||
if session.is_empty() {
|
||||
session = run_cmds("cat /proc/self/sessionid".to_owned()).unwrap_or_default();
|
||||
session = run_cmds("cat /proc/self/sessionid").unwrap_or_default();
|
||||
if session == INVALID_SESSION {
|
||||
session = "".to_owned();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get_display_server_of_session(&session)
|
||||
if session.is_empty() {
|
||||
"".to_owned()
|
||||
} else {
|
||||
get_display_server_of_session(&session)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_display_server_of_session(session: &str) -> String {
|
||||
pub fn get_display_server_of_session(session: &str) -> String {
|
||||
let mut display_server = if let Ok(output) =
|
||||
run_loginctl(Some(vec!["show-session", "-p", "Type", session]))
|
||||
// Check session type of the session
|
||||
@ -61,7 +88,7 @@ fn get_display_server_of_session(session: &str) -> String {
|
||||
.replace("TTY=", "")
|
||||
.trim_end()
|
||||
.into();
|
||||
if let Ok(xorg_results) = run_cmds(format!("ps -e | grep \"{tty}.\\\\+Xorg\""))
|
||||
if let Ok(xorg_results) = run_cmds(&format!("ps -e | grep \"{tty}.\\\\+Xorg\""))
|
||||
// And check if Xorg is running on that tty
|
||||
{
|
||||
if xorg_results.trim_end() != "" {
|
||||
@ -87,44 +114,68 @@ fn get_display_server_of_session(session: &str) -> String {
|
||||
display_server.to_lowercase()
|
||||
}
|
||||
|
||||
pub fn get_values_of_seat0(indices: Vec<usize>) -> Vec<String> {
|
||||
#[inline]
|
||||
fn line_values(indices: &[usize], line: &str) -> Vec<String> {
|
||||
indices
|
||||
.into_iter()
|
||||
.map(|idx| line.split_whitespace().nth(*idx).unwrap_or("").to_owned())
|
||||
.collect::<Vec<String>>()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_values_of_seat0(indices: &[usize]) -> Vec<String> {
|
||||
_get_values_of_seat0(indices, true)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_values_of_seat0_with_gdm_wayland(indices: &[usize]) -> Vec<String> {
|
||||
_get_values_of_seat0(indices, false)
|
||||
}
|
||||
|
||||
fn _get_values_of_seat0(indices: &[usize], ignore_gdm_wayland: bool) -> Vec<String> {
|
||||
if let Ok(output) = run_loginctl(None) {
|
||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||
if line.contains("seat0") {
|
||||
if let Some(sid) = line.split_whitespace().next() {
|
||||
if is_active(sid) {
|
||||
return indices
|
||||
.into_iter()
|
||||
.map(|idx| line.split_whitespace().nth(idx).unwrap_or("").to_owned())
|
||||
.collect::<Vec<String>>();
|
||||
if ignore_gdm_wayland {
|
||||
if is_gdm_user(line.split_whitespace().nth(2).unwrap_or(""))
|
||||
&& get_display_server_of_session(sid) == DISPLAY_SERVER_WAYLAND
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return line_values(indices, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// some case, there is no seat0 https://github.com/rustdesk/rustdesk/issues/73
|
||||
if let Ok(output) = run_loginctl(None) {
|
||||
// some case, there is no seat0 https://github.com/rustdesk/rustdesk/issues/73
|
||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||
if let Some(sid) = line.split_whitespace().next() {
|
||||
let d = get_display_server_of_session(sid);
|
||||
if is_active(sid) && d != "tty" {
|
||||
return indices
|
||||
.into_iter()
|
||||
.map(|idx| line.split_whitespace().nth(idx).unwrap_or("").to_owned())
|
||||
.collect::<Vec<String>>();
|
||||
if is_active(sid) {
|
||||
let d = get_display_server_of_session(sid);
|
||||
if ignore_gdm_wayland {
|
||||
if is_gdm_user(line.split_whitespace().nth(2).unwrap_or(""))
|
||||
&& d == DISPLAY_SERVER_WAYLAND
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if d == "tty" {
|
||||
continue;
|
||||
}
|
||||
return line_values(indices, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return indices
|
||||
.iter()
|
||||
.map(|_x| "".to_owned())
|
||||
.collect::<Vec<String>>();
|
||||
line_values(indices, "")
|
||||
}
|
||||
|
||||
fn is_active(sid: &str) -> bool {
|
||||
pub fn is_active(sid: &str) -> bool {
|
||||
if let Ok(output) = run_loginctl(Some(vec!["show-session", "-p", "State", sid])) {
|
||||
String::from_utf8_lossy(&output.stdout).contains("active")
|
||||
} else {
|
||||
@ -132,9 +183,9 @@ fn is_active(sid: &str) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_cmds(cmds: String) -> ResultType<String> {
|
||||
pub fn run_cmds(cmds: &str) -> ResultType<String> {
|
||||
let output = std::process::Command::new("sh")
|
||||
.args(vec!["-c", &cmds])
|
||||
.args(vec!["-c", cmds])
|
||||
.output()?;
|
||||
Ok(String::from_utf8_lossy(&output.stdout).to_string())
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ const CFG_KEY_DECODER: &str = "bestHwDecoders";
|
||||
|
||||
const DEFAULT_PIXFMT: AVPixelFormat = AVPixelFormat::AV_PIX_FMT_YUV420P;
|
||||
pub const DEFAULT_TIME_BASE: [i32; 2] = [1, 30];
|
||||
const DEFAULT_GOP: i32 = 60;
|
||||
const DEFAULT_GOP: i32 = i32::MAX;
|
||||
const DEFAULT_HW_QUALITY: Quality = Quality_Default;
|
||||
const DEFAULT_RC: RateControl = RC_DEFAULT;
|
||||
|
||||
|
@ -74,7 +74,7 @@ pub trait TraitCapturer {
|
||||
#[cfg(x11)]
|
||||
#[inline]
|
||||
pub fn is_x11() -> bool {
|
||||
"x11" == hbb_common::platform::linux::get_display_server()
|
||||
hbb_common::platform::linux::is_x11_or_headless()
|
||||
}
|
||||
|
||||
#[cfg(x11)]
|
||||
|
@ -13,7 +13,10 @@ use cpal::{
|
||||
traits::{DeviceTrait, HostTrait, StreamTrait},
|
||||
Device, Host, StreamConfig,
|
||||
};
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
use magnum_opus::{Channels::*, Decoder as AudioDecoder};
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
use ringbuf::{ring_buffer::RbBase, Rb};
|
||||
use sha2::{Digest, Sha256};
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -65,6 +68,7 @@ pub mod io_loop;
|
||||
|
||||
pub const MILLI1: Duration = Duration::from_millis(1);
|
||||
pub const SEC30: Duration = Duration::from_secs(30);
|
||||
pub const VIDEO_QUEUE_SIZE: usize = 120;
|
||||
|
||||
/// Client of the remote desktop.
|
||||
pub struct Client;
|
||||
@ -701,11 +705,25 @@ pub struct AudioHandler {
|
||||
#[cfg(target_os = "linux")]
|
||||
simple: Option<psimple::Simple>,
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
audio_buffer: Arc<std::sync::Mutex<std::collections::vec_deque::VecDeque<f32>>>,
|
||||
audio_buffer: AudioBuffer,
|
||||
sample_rate: (u32, u32),
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
audio_stream: Option<Box<dyn StreamTrait>>,
|
||||
channels: u16,
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
ready: Arc<std::sync::Mutex<bool>>,
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
struct AudioBuffer(pub Arc<std::sync::Mutex<ringbuf::HeapRb<f32>>>);
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
impl Default for AudioBuffer {
|
||||
fn default() -> Self {
|
||||
Self(Arc::new(std::sync::Mutex::new(
|
||||
ringbuf::HeapRb::<f32>::new(48000 * 2), // 48000hz, 2 channel, 1 second
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
impl AudioHandler {
|
||||
@ -794,7 +812,7 @@ impl AudioHandler {
|
||||
#[inline]
|
||||
pub fn handle_frame(&mut self, frame: AudioFrame) {
|
||||
#[cfg(not(any(target_os = "android", target_os = "linux")))]
|
||||
if self.audio_stream.is_none() {
|
||||
if self.audio_stream.is_none() || !self.ready.lock().unwrap().clone() {
|
||||
return;
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
@ -814,11 +832,7 @@ impl AudioHandler {
|
||||
{
|
||||
let sample_rate0 = self.sample_rate.0;
|
||||
let sample_rate = self.sample_rate.1;
|
||||
let audio_buffer = self.audio_buffer.clone();
|
||||
// avoiding memory overflow if audio_buffer consumer side has problem
|
||||
if audio_buffer.lock().unwrap().len() as u32 > sample_rate * 120 {
|
||||
*audio_buffer.lock().unwrap() = Default::default();
|
||||
}
|
||||
let audio_buffer = self.audio_buffer.0.clone();
|
||||
if sample_rate != sample_rate0 {
|
||||
let buffer = crate::resample_channels(
|
||||
&buffer[0..n],
|
||||
@ -826,12 +840,12 @@ impl AudioHandler {
|
||||
sample_rate,
|
||||
channels,
|
||||
);
|
||||
audio_buffer.lock().unwrap().extend(buffer);
|
||||
audio_buffer.lock().unwrap().push_slice_overwrite(&buffer);
|
||||
} else {
|
||||
audio_buffer
|
||||
.lock()
|
||||
.unwrap()
|
||||
.extend(buffer[0..n].iter().cloned());
|
||||
.push_slice_overwrite(&buffer[0..n]);
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "android")]
|
||||
@ -859,16 +873,23 @@ impl AudioHandler {
|
||||
// too many errors, will improve later
|
||||
log::trace!("an error occurred on stream: {}", err);
|
||||
};
|
||||
let audio_buffer = self.audio_buffer.clone();
|
||||
let audio_buffer = self.audio_buffer.0.clone();
|
||||
let ready = self.ready.clone();
|
||||
let stream = device.build_output_stream(
|
||||
config,
|
||||
move |data: &mut [T], _: &_| {
|
||||
if !*ready.lock().unwrap() {
|
||||
*ready.lock().unwrap() = true;
|
||||
}
|
||||
let mut lock = audio_buffer.lock().unwrap();
|
||||
let mut n = data.len();
|
||||
if lock.len() < n {
|
||||
n = lock.len();
|
||||
if lock.occupied_len() < n {
|
||||
n = lock.occupied_len();
|
||||
}
|
||||
let mut input = lock.drain(0..n);
|
||||
let mut elems = vec![0.0f32; n];
|
||||
lock.pop_slice(&mut elems);
|
||||
drop(lock);
|
||||
let mut input = elems.into_iter();
|
||||
for sample in data.iter_mut() {
|
||||
*sample = match input.next() {
|
||||
Some(x) => T::from(&x),
|
||||
@ -1640,8 +1661,9 @@ impl LoginConfigHandler {
|
||||
|
||||
/// Media data.
|
||||
pub enum MediaData {
|
||||
VideoFrame(VideoFrame),
|
||||
AudioFrame(AudioFrame),
|
||||
VideoQueue,
|
||||
VideoFrame(Box<VideoFrame>),
|
||||
AudioFrame(Box<AudioFrame>),
|
||||
AudioFormat(AudioFormat),
|
||||
Reset,
|
||||
RecordScreen(bool, i32, i32, String),
|
||||
@ -1655,11 +1677,15 @@ pub type MediaSender = mpsc::Sender<MediaData>;
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `video_callback` - The callback for video frame. Being called when a video frame is ready.
|
||||
pub fn start_video_audio_threads<F>(video_callback: F) -> (MediaSender, MediaSender)
|
||||
pub fn start_video_audio_threads<F>(
|
||||
video_callback: F,
|
||||
) -> (MediaSender, MediaSender, Arc<ArrayQueue<VideoFrame>>)
|
||||
where
|
||||
F: 'static + FnMut(&mut Vec<u8>) + Send,
|
||||
{
|
||||
let (video_sender, video_receiver) = mpsc::channel::<MediaData>();
|
||||
let video_queue = Arc::new(ArrayQueue::<VideoFrame>::new(VIDEO_QUEUE_SIZE));
|
||||
let video_queue_cloned = video_queue.clone();
|
||||
let mut video_callback = video_callback;
|
||||
|
||||
std::thread::spawn(move || {
|
||||
@ -1668,10 +1694,17 @@ where
|
||||
if let Ok(data) = video_receiver.recv() {
|
||||
match data {
|
||||
MediaData::VideoFrame(vf) => {
|
||||
if let Ok(true) = video_handler.handle_frame(vf) {
|
||||
if let Ok(true) = video_handler.handle_frame(*vf) {
|
||||
video_callback(&mut video_handler.rgb);
|
||||
}
|
||||
}
|
||||
MediaData::VideoQueue => {
|
||||
if let Some(vf) = video_queue.pop() {
|
||||
if let Ok(true) = video_handler.handle_frame(vf) {
|
||||
video_callback(&mut video_handler.rgb);
|
||||
}
|
||||
}
|
||||
}
|
||||
MediaData::Reset => {
|
||||
video_handler.reset();
|
||||
}
|
||||
@ -1687,7 +1720,7 @@ where
|
||||
log::info!("Video decoder loop exits");
|
||||
});
|
||||
let audio_sender = start_audio_thread();
|
||||
return (video_sender, audio_sender);
|
||||
return (video_sender, audio_sender, video_queue_cloned);
|
||||
}
|
||||
|
||||
/// Start an audio thread
|
||||
@ -1700,7 +1733,7 @@ pub fn start_audio_thread() -> MediaSender {
|
||||
if let Ok(data) = audio_receiver.recv() {
|
||||
match data {
|
||||
MediaData::AudioFrame(af) => {
|
||||
audio_handler.handle_frame(af);
|
||||
audio_handler.handle_frame(*af);
|
||||
}
|
||||
MediaData::AudioFormat(f) => {
|
||||
log::debug!("recved audio format, sample rate={}", f.sample_rate);
|
||||
|
@ -9,6 +9,7 @@ use std::sync::{
|
||||
|
||||
#[cfg(windows)]
|
||||
use clipboard::{cliprdr::CliprdrClientContext, ContextSend};
|
||||
use crossbeam_queue::ArrayQueue;
|
||||
use hbb_common::config::{PeerConfig, TransferSerde};
|
||||
use hbb_common::fs::{
|
||||
can_enable_overwrite_detection, get_job, get_string, new_send_confirm, DigestCheckResult,
|
||||
@ -42,6 +43,7 @@ use crate::{client::Data, client::Interface};
|
||||
|
||||
pub struct Remote<T: InvokeUiSession> {
|
||||
handler: Session<T>,
|
||||
video_queue: Arc<ArrayQueue<VideoFrame>>,
|
||||
video_sender: MediaSender,
|
||||
audio_sender: MediaSender,
|
||||
receiver: mpsc::UnboundedReceiver<Data>,
|
||||
@ -68,6 +70,7 @@ pub struct Remote<T: InvokeUiSession> {
|
||||
impl<T: InvokeUiSession> Remote<T> {
|
||||
pub fn new(
|
||||
handler: Session<T>,
|
||||
video_queue: Arc<ArrayQueue<VideoFrame>>,
|
||||
video_sender: MediaSender,
|
||||
audio_sender: MediaSender,
|
||||
receiver: mpsc::UnboundedReceiver<Data>,
|
||||
@ -76,6 +79,7 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
) -> Self {
|
||||
Self {
|
||||
handler,
|
||||
video_queue,
|
||||
video_sender,
|
||||
audio_sender,
|
||||
receiver,
|
||||
@ -812,6 +816,18 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
}
|
||||
|
||||
fn contains_key_frame(vf: &VideoFrame) -> bool {
|
||||
match &vf.union {
|
||||
Some(vf) => match vf {
|
||||
video_frame::Union::Vp9s(f) => f.frames.iter().any(|e| e.key),
|
||||
video_frame::Union::H264s(f) => f.frames.iter().any(|e| e.key),
|
||||
video_frame::Union::H265s(f) => f.frames.iter().any(|e| e.key),
|
||||
_ => false,
|
||||
},
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_msg_from_peer(&mut self, data: &[u8], peer: &mut Stream) -> bool {
|
||||
if let Ok(msg_in) = Message::parse_from_bytes(&data) {
|
||||
match msg_in.union {
|
||||
@ -830,7 +846,15 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
..Default::default()
|
||||
})
|
||||
};
|
||||
self.video_sender.send(MediaData::VideoFrame(vf)).ok();
|
||||
if Self::contains_key_frame(&vf) {
|
||||
while let Some(_) = self.video_queue.pop() {}
|
||||
self.video_sender
|
||||
.send(MediaData::VideoFrame(Box::new(vf)))
|
||||
.ok();
|
||||
} else {
|
||||
self.video_queue.force_push(vf);
|
||||
self.video_sender.send(MediaData::VideoQueue).ok();
|
||||
}
|
||||
}
|
||||
Some(message::Union::Hash(hash)) => {
|
||||
self.handler
|
||||
@ -1217,7 +1241,9 @@ impl<T: InvokeUiSession> Remote<T> {
|
||||
}
|
||||
Some(message::Union::AudioFrame(frame)) => {
|
||||
if !self.handler.lc.read().unwrap().disable_audio.v {
|
||||
self.audio_sender.send(MediaData::AudioFrame(frame)).ok();
|
||||
self.audio_sender
|
||||
.send(MediaData::AudioFrame(Box::new(frame)))
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
Some(message::Union::FileAction(action)) => match action.union {
|
||||
|
@ -755,7 +755,7 @@ lazy_static::lazy_static! {
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
lazy_static::lazy_static! {
|
||||
pub static ref IS_X11: bool = "x11" == hbb_common::platform::linux::get_display_server();
|
||||
pub static ref IS_X11: bool = hbb_common::platform::linux::is_x11_or_headless();
|
||||
}
|
||||
|
||||
pub fn make_fd_to_json(id: i32, path: String, entries: &Vec<FileEntry>) -> String {
|
||||
|
@ -843,7 +843,7 @@ pub fn map_keyboard_mode(_peer: &str, event: &Event, mut key_event: KeyEvent) ->
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||
fn try_fill_unicode(event: &Event, key_event: &KeyEvent, events: &mut Vec<KeyEvent>) {
|
||||
fn try_fill_unicode(_peer: &str, event: &Event, key_event: &KeyEvent, events: &mut Vec<KeyEvent>) {
|
||||
match &event.unicode {
|
||||
Some(unicode_info) => {
|
||||
if let Some(name) = &unicode_info.name {
|
||||
@ -857,11 +857,13 @@ fn try_fill_unicode(event: &Event, key_event: &KeyEvent, events: &mut Vec<KeyEve
|
||||
None =>
|
||||
{
|
||||
#[cfg(target_os = "windows")]
|
||||
if is_hot_key_modifiers_down() && unsafe { !IS_0X021D_DOWN } {
|
||||
if let Some(chr) = get_char_by_vk(event.platform_code as u32) {
|
||||
let mut evt = key_event.clone();
|
||||
evt.set_seq(chr.to_string());
|
||||
events.push(evt);
|
||||
if _peer == OS_LOWER_LINUX {
|
||||
if is_hot_key_modifiers_down() && unsafe { !IS_0X021D_DOWN } {
|
||||
if let Some(chr) = get_char_by_vk(event.platform_code as u32) {
|
||||
let mut evt = key_event.clone();
|
||||
evt.set_seq(chr.to_string());
|
||||
events.push(evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -886,7 +888,12 @@ fn is_hot_key_modifiers_down() -> bool {
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn translate_key_code(peer: &str, event: &Event, key_event: KeyEvent) -> Option<KeyEvent> {
|
||||
let mut key_event = map_keyboard_mode(peer, event, key_event)?;
|
||||
key_event.set_chr((key_event.chr() & 0x0000FFFF) | ((event.platform_code as u32) << 16));
|
||||
let chr = if peer == OS_LOWER_WINDOWS {
|
||||
(key_event.chr() & 0x0000FFFF) | ((event.platform_code as u32) << 16)
|
||||
} else {
|
||||
key_event.chr()
|
||||
};
|
||||
key_event.set_chr(chr);
|
||||
Some(key_event)
|
||||
}
|
||||
|
||||
@ -962,7 +969,7 @@ pub fn translate_keyboard_mode(peer: &str, event: &Event, key_event: KeyEvent) -
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
||||
if is_press(event) {
|
||||
try_fill_unicode(event, &key_event, &mut events);
|
||||
try_fill_unicode(peer, event, &key_event, &mut events);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
@ -974,7 +981,7 @@ pub fn translate_keyboard_mode(peer: &str, event: &Event, key_event: KeyEvent) -
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
if !unsafe { IS_LEFT_OPTION_DOWN } {
|
||||
try_fill_unicode(event, &key_event, &mut events);
|
||||
try_fill_unicode(peer, event, &key_event, &mut events);
|
||||
}
|
||||
|
||||
if events.is_empty() {
|
||||
|
@ -1,4 +1,5 @@
|
||||
use super::{CursorData, ResultType};
|
||||
use desktop::Desktop;
|
||||
pub use hbb_common::platform::linux::*;
|
||||
use hbb_common::{
|
||||
allow_err, bail,
|
||||
@ -64,6 +65,11 @@ pub struct xcb_xfixes_get_cursor_image {
|
||||
pub pixels: *const c_long,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sleep_millis(millis: u64) {
|
||||
std::thread::sleep(Duration::from_millis(millis));
|
||||
}
|
||||
|
||||
pub fn get_cursor_pos() -> Option<(i32, i32)> {
|
||||
let mut res = None;
|
||||
XDO.with(|xdo| {
|
||||
@ -190,7 +196,7 @@ fn start_server(user: Option<(String, String)>, server: &mut Option<Child>) {
|
||||
fn stop_server(server: &mut Option<Child>) {
|
||||
if let Some(mut ps) = server.take() {
|
||||
allow_err!(ps.kill());
|
||||
std::thread::sleep(Duration::from_millis(30));
|
||||
sleep_millis(30);
|
||||
match ps.try_wait() {
|
||||
Ok(Some(_status)) => {}
|
||||
Ok(None) => {
|
||||
@ -201,44 +207,20 @@ fn stop_server(server: &mut Option<Child>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn set_x11_env(uid: &str) {
|
||||
log::info!("uid of seat0: {}", uid);
|
||||
let gdm = format!("/run/user/{}/gdm/Xauthority", uid);
|
||||
let mut auth = get_env_tries("XAUTHORITY", uid, 10);
|
||||
// auth is another user's when uid = 0, https://github.com/rustdesk/rustdesk/issues/2468
|
||||
if auth.is_empty() || uid == "0" {
|
||||
auth = if Path::new(&gdm).exists() {
|
||||
gdm
|
||||
} else {
|
||||
let username = get_active_username();
|
||||
if username == "root" {
|
||||
format!("/{}/.Xauthority", username)
|
||||
} else {
|
||||
let tmp = format!("/home/{}/.Xauthority", username);
|
||||
if Path::new(&tmp).exists() {
|
||||
tmp
|
||||
} else {
|
||||
format!("/var/lib/{}/.Xauthority", username)
|
||||
}
|
||||
}
|
||||
};
|
||||
fn set_x11_env(desktop: &Desktop) {
|
||||
log::info!("DISPLAY: {}", desktop.display);
|
||||
log::info!("XAUTHORITY: {}", desktop.xauth);
|
||||
if !desktop.display.is_empty() {
|
||||
std::env::set_var("DISPLAY", &desktop.display);
|
||||
}
|
||||
let mut d = get_env("DISPLAY", uid);
|
||||
if d.is_empty() {
|
||||
d = get_display();
|
||||
if !desktop.xauth.is_empty() {
|
||||
std::env::set_var("XAUTHORITY", &desktop.xauth);
|
||||
}
|
||||
if d.is_empty() {
|
||||
d = ":0".to_owned();
|
||||
}
|
||||
d = d.replace(&whoami::hostname(), "").replace("localhost", "");
|
||||
log::info!("DISPLAY: {}", d);
|
||||
log::info!("XAUTHORITY: {}", auth);
|
||||
std::env::set_var("XAUTHORITY", auth);
|
||||
std::env::set_var("DISPLAY", d);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn stop_rustdesk_servers() {
|
||||
let _ = run_cmds(format!(
|
||||
let _ = run_cmds(&format!(
|
||||
r##"ps -ef | grep -E 'rustdesk +--server' | awk '{{printf("kill -9 %d\n", $2)}}' | bash"##,
|
||||
));
|
||||
}
|
||||
@ -246,37 +228,49 @@ fn stop_rustdesk_servers() {
|
||||
fn should_start_server(
|
||||
try_x11: bool,
|
||||
uid: &mut String,
|
||||
cur_uid: String,
|
||||
desktop: &Desktop,
|
||||
cm0: &mut bool,
|
||||
last_restart: &mut Instant,
|
||||
server: &mut Option<Child>,
|
||||
) -> bool {
|
||||
let cm = get_cm();
|
||||
let mut start_new = false;
|
||||
if cur_uid != *uid && !cur_uid.is_empty() {
|
||||
*uid = cur_uid;
|
||||
let mut should_kill = false;
|
||||
|
||||
if desktop.is_headless() {
|
||||
if !uid.is_empty() {
|
||||
// From having a monitor to not having a monitor.
|
||||
*uid = "".to_owned();
|
||||
should_kill = true;
|
||||
}
|
||||
} else if desktop.uid != *uid && !desktop.uid.is_empty() {
|
||||
*uid = desktop.uid.clone();
|
||||
if try_x11 {
|
||||
set_x11_env(&uid);
|
||||
set_x11_env(&desktop);
|
||||
}
|
||||
if let Some(ps) = server.as_mut() {
|
||||
allow_err!(ps.kill());
|
||||
std::thread::sleep(Duration::from_millis(30));
|
||||
*last_restart = Instant::now();
|
||||
}
|
||||
} else if !cm
|
||||
should_kill = true;
|
||||
}
|
||||
|
||||
if !should_kill
|
||||
&& !cm
|
||||
&& ((*cm0 && last_restart.elapsed().as_secs() > 60)
|
||||
|| last_restart.elapsed().as_secs() > 3600)
|
||||
{
|
||||
// restart server if new connections all closed, or every one hour,
|
||||
// as a workaround to resolve "SpotUdp" (dns resolve)
|
||||
// and x server get displays failure issue
|
||||
should_kill = true;
|
||||
log::info!("restart server");
|
||||
}
|
||||
|
||||
if should_kill {
|
||||
if let Some(ps) = server.as_mut() {
|
||||
allow_err!(ps.kill());
|
||||
std::thread::sleep(Duration::from_millis(30));
|
||||
sleep_millis(30);
|
||||
*last_restart = Instant::now();
|
||||
log::info!("restart server");
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ps) = server.as_mut() {
|
||||
match ps.try_wait() {
|
||||
Ok(Some(_)) => {
|
||||
@ -296,7 +290,7 @@ fn should_start_server(
|
||||
// stop_rustdesk_servers() is just a temp solution here.
|
||||
fn force_stop_server() {
|
||||
stop_rustdesk_servers();
|
||||
std::thread::sleep(Duration::from_millis(super::SERVICE_INTERVAL));
|
||||
sleep_millis(super::SERVICE_INTERVAL);
|
||||
}
|
||||
|
||||
pub fn start_os_service() {
|
||||
@ -305,6 +299,8 @@ pub fn start_os_service() {
|
||||
|
||||
let running = Arc::new(AtomicBool::new(true));
|
||||
let r = running.clone();
|
||||
let mut desktop = Desktop::default();
|
||||
let mut sid = "".to_owned();
|
||||
let mut uid = "".to_owned();
|
||||
let mut server: Option<Child> = None;
|
||||
let mut user_server: Option<Child> = None;
|
||||
@ -317,31 +313,18 @@ pub fn start_os_service() {
|
||||
let mut cm0 = false;
|
||||
let mut last_restart = Instant::now();
|
||||
while running.load(Ordering::SeqCst) {
|
||||
let (cur_uid, cur_user) = get_active_user_id_name();
|
||||
desktop.refresh();
|
||||
|
||||
// for fixing https://github.com/rustdesk/rustdesk/issues/3129 to avoid too much dbus calling,
|
||||
// though duplicate logic here with should_start_server
|
||||
if !(cur_uid != *uid && !cur_uid.is_empty()) {
|
||||
let cm = get_cm();
|
||||
if !(!cm
|
||||
&& ((cm0 && last_restart.elapsed().as_secs() > 60)
|
||||
|| last_restart.elapsed().as_secs() > 3600))
|
||||
{
|
||||
std::thread::sleep(Duration::from_millis(500));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let is_wayland = current_is_wayland();
|
||||
|
||||
if cur_user == "root" || !is_wayland {
|
||||
// Duplicate logic here with should_start_server
|
||||
// Login wayland will try to start a headless --server.
|
||||
if desktop.username == "root" || !desktop.is_wayland() || desktop.is_login_wayland() {
|
||||
// try kill subprocess "--server"
|
||||
stop_server(&mut user_server);
|
||||
// try start subprocess "--server"
|
||||
if should_start_server(
|
||||
true,
|
||||
&mut uid,
|
||||
cur_uid,
|
||||
&desktop,
|
||||
&mut cm0,
|
||||
&mut last_restart,
|
||||
&mut server,
|
||||
@ -349,30 +332,42 @@ pub fn start_os_service() {
|
||||
force_stop_server();
|
||||
start_server(None, &mut server);
|
||||
}
|
||||
} else if cur_user != "" {
|
||||
if cur_user != "gdm" {
|
||||
// try kill subprocess "--server"
|
||||
stop_server(&mut server);
|
||||
} else if desktop.username != "" {
|
||||
// try kill subprocess "--server"
|
||||
stop_server(&mut server);
|
||||
|
||||
// try start subprocess "--server"
|
||||
if should_start_server(
|
||||
false,
|
||||
&mut uid,
|
||||
cur_uid.clone(),
|
||||
&mut cm0,
|
||||
&mut last_restart,
|
||||
// try start subprocess "--server"
|
||||
if should_start_server(
|
||||
false,
|
||||
&mut uid,
|
||||
&desktop,
|
||||
&mut cm0,
|
||||
&mut last_restart,
|
||||
&mut user_server,
|
||||
) {
|
||||
force_stop_server();
|
||||
start_server(
|
||||
Some((desktop.uid.clone(), desktop.username.clone())),
|
||||
&mut user_server,
|
||||
) {
|
||||
force_stop_server();
|
||||
start_server(Some((cur_uid, cur_user)), &mut user_server);
|
||||
}
|
||||
);
|
||||
}
|
||||
} else {
|
||||
force_stop_server();
|
||||
stop_server(&mut user_server);
|
||||
stop_server(&mut server);
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(super::SERVICE_INTERVAL));
|
||||
|
||||
let keeps_headless = sid.is_empty() && desktop.is_headless();
|
||||
let keeps_session = sid == desktop.sid;
|
||||
if keeps_headless || keeps_session {
|
||||
// for fixing https://github.com/rustdesk/rustdesk/issues/3129 to avoid too much dbus calling,
|
||||
sleep_millis(500);
|
||||
} else {
|
||||
sleep_millis(super::SERVICE_INTERVAL);
|
||||
}
|
||||
if !desktop.is_headless() {
|
||||
sid = desktop.sid.clone();
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(ps) = user_server.take().as_mut() {
|
||||
@ -384,13 +379,15 @@ pub fn start_os_service() {
|
||||
log::info!("Exit");
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_active_user_id_name() -> (String, String) {
|
||||
let vec_id_name = get_values_of_seat0([1, 2].to_vec());
|
||||
let vec_id_name = get_values_of_seat0(&[1, 2]);
|
||||
(vec_id_name[0].clone(), vec_id_name[1].clone())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_active_userid() -> String {
|
||||
get_values_of_seat0([1].to_vec())[0].clone()
|
||||
get_values_of_seat0(&[1])[0].clone()
|
||||
}
|
||||
|
||||
fn get_cm() -> bool {
|
||||
@ -409,45 +406,6 @@ fn get_cm() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
fn get_display() -> String {
|
||||
let user = get_active_username();
|
||||
log::debug!("w {}", &user);
|
||||
if let Ok(output) = Command::new("w").arg(&user).output() {
|
||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||
log::debug!(" {}", line);
|
||||
let mut iter = line.split_whitespace();
|
||||
let b = iter.nth(2);
|
||||
if let Some(b) = b {
|
||||
if b.starts_with(":") {
|
||||
return b.to_owned();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// above not work for gdm user
|
||||
log::debug!("ls -l /tmp/.X11-unix/");
|
||||
let mut last = "".to_owned();
|
||||
if let Ok(output) = Command::new("ls")
|
||||
.args(vec!["-l", "/tmp/.X11-unix/"])
|
||||
.output()
|
||||
{
|
||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||
log::debug!(" {}", line);
|
||||
let mut iter = line.split_whitespace();
|
||||
let user_field = iter.nth(2);
|
||||
if let Some(x) = iter.last() {
|
||||
if x.starts_with("X") {
|
||||
last = x.replace("X", ":").to_owned();
|
||||
if user_field == Some(&user) {
|
||||
return last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
last
|
||||
}
|
||||
|
||||
pub fn is_login_wayland() -> bool {
|
||||
if let Ok(contents) = std::fs::read_to_string("/etc/gdm3/custom.conf") {
|
||||
contents.contains("#WaylandEnable=false") || contents.contains("WaylandEnable=true")
|
||||
@ -458,9 +416,9 @@ pub fn is_login_wayland() -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn current_is_wayland() -> bool {
|
||||
let dtype = get_display_server();
|
||||
return "wayland" == dtype && unsafe { UNMODIFIED };
|
||||
return is_desktop_wayland() && unsafe { UNMODIFIED };
|
||||
}
|
||||
|
||||
// to-do: test the other display manager
|
||||
@ -473,8 +431,9 @@ fn _get_display_manager() -> String {
|
||||
"gdm3".to_owned()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_active_username() -> String {
|
||||
get_values_of_seat0([2].to_vec())[0].clone()
|
||||
get_values_of_seat0(&[2])[0].clone()
|
||||
}
|
||||
|
||||
pub fn get_active_user_home() -> Option<PathBuf> {
|
||||
@ -488,9 +447,16 @@ pub fn get_active_user_home() -> Option<PathBuf> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_env_var(k: &str) -> String {
|
||||
match std::env::var(k) {
|
||||
Ok(v) => v,
|
||||
Err(_e) => "".to_owned(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_prelogin() -> bool {
|
||||
let n = get_active_userid().len();
|
||||
n < 4 && n > 1
|
||||
let (uid, uname) = get_active_user_id_name();
|
||||
uid.len() >= 4 || uname == "root"
|
||||
}
|
||||
|
||||
pub fn is_root() -> bool {
|
||||
@ -498,7 +464,7 @@ pub fn is_root() -> bool {
|
||||
}
|
||||
|
||||
fn is_opensuse() -> bool {
|
||||
if let Ok(res) = run_cmds("cat /etc/os-release | grep opensuse".to_owned()) {
|
||||
if let Ok(res) = run_cmds("cat /etc/os-release | grep opensuse") {
|
||||
if !res.is_empty() {
|
||||
return true;
|
||||
}
|
||||
@ -512,6 +478,9 @@ pub fn run_as_user(arg: Vec<&str>, user: Option<(String, String)>) -> ResultType
|
||||
None => get_active_user_id_name(),
|
||||
};
|
||||
let cmd = std::env::current_exe()?;
|
||||
if uid.is_empty() {
|
||||
bail!("No valid uid");
|
||||
}
|
||||
let xdg = &format!("XDG_RUNTIME_DIR=/run/user/{}", uid) as &str;
|
||||
let mut args = vec![xdg, "-u", &username, cmd.to_str().unwrap_or("")];
|
||||
args.append(&mut arg.clone());
|
||||
@ -597,21 +566,31 @@ pub fn is_installed() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn get_env_tries(name: &str, uid: &str, n: usize) -> String {
|
||||
pub(super) fn get_env_tries(name: &str, uid: &str, process: &str, n: usize) -> String {
|
||||
for _ in 0..n {
|
||||
let x = get_env(name, uid);
|
||||
let x = get_env(name, uid, process);
|
||||
if !x.is_empty() {
|
||||
return x;
|
||||
}
|
||||
std::thread::sleep(Duration::from_millis(300));
|
||||
sleep_millis(300);
|
||||
}
|
||||
"".to_owned()
|
||||
}
|
||||
|
||||
fn get_env(name: &str, uid: &str) -> String {
|
||||
let cmd = format!("ps -u {} -o pid= | xargs -I__ cat /proc/__/environ 2>/dev/null | tr '\\0' '\\n' | grep '^{}=' | tail -1 | sed 's/{}=//g'", uid, name, name);
|
||||
log::debug!("Run: {}", &cmd);
|
||||
if let Ok(x) = run_cmds(cmd) {
|
||||
#[inline]
|
||||
fn get_env(name: &str, uid: &str, process: &str) -> String {
|
||||
let cmd = format!("ps -u {} -f | grep '{}' | grep -v 'grep' | tail -1 | awk '{{print $2}}' | xargs -I__ cat /proc/__/environ 2>/dev/null | tr '\\0' '\\n' | grep '^{}=' | tail -1 | sed 's/{}=//g'", uid, process, name, name);
|
||||
if let Ok(x) = run_cmds(&cmd) {
|
||||
x.trim_end().to_string()
|
||||
} else {
|
||||
"".to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_env_from_pid(name: &str, pid: &str) -> String {
|
||||
let cmd = format!("cat /proc/{}/environ 2>/dev/null | tr '\\0' '\\n' | grep '^{}=' | tail -1 | sed 's/{}=//g'", pid, name, name);
|
||||
if let Ok(x) = run_cmds(&cmd) {
|
||||
x.trim_end().to_string()
|
||||
} else {
|
||||
"".to_owned()
|
||||
@ -701,7 +680,7 @@ pub fn resolutions(name: &str) -> Vec<Resolution> {
|
||||
let connected_pat = get_xrandr_conn_pat(name);
|
||||
let mut v = vec![];
|
||||
if let Ok(re) = Regex::new(&format!("{}{}", connected_pat, resolutions_pat)) {
|
||||
match run_cmds("xrandr --query | tr -s ' '".to_owned()) {
|
||||
match run_cmds("xrandr --query | tr -s ' '") {
|
||||
Ok(xrandr_output) => {
|
||||
// There'are different kinds of xrandr output.
|
||||
/*
|
||||
@ -750,7 +729,7 @@ pub fn resolutions(name: &str) -> Vec<Resolution> {
|
||||
}
|
||||
|
||||
pub fn current_resolution(name: &str) -> ResultType<Resolution> {
|
||||
let xrandr_output = run_cmds("xrandr --query | tr -s ' '".to_owned())?;
|
||||
let xrandr_output = run_cmds("xrandr --query | tr -s ' '")?;
|
||||
let re = Regex::new(&get_xrandr_conn_pat(name))?;
|
||||
if let Some(caps) = re.captures(&xrandr_output) {
|
||||
if let Some((width, height)) = get_width_height_from_captures(&caps) {
|
||||
@ -775,3 +754,176 @@ pub fn change_resolution(name: &str, width: usize, height: usize) -> ResultType<
|
||||
.spawn()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
mod desktop {
|
||||
use super::*;
|
||||
|
||||
pub const XFCE4_PANEL: &str = "xfce4-panel";
|
||||
pub const GNOME_SESSION_BINARY: &str = "gnome-session-binary";
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct Desktop {
|
||||
pub sid: String,
|
||||
pub username: String,
|
||||
pub uid: String,
|
||||
pub protocal: String,
|
||||
pub display: String,
|
||||
pub xauth: String,
|
||||
}
|
||||
|
||||
impl Desktop {
|
||||
#[inline]
|
||||
pub fn is_wayland(&self) -> bool {
|
||||
self.protocal == DISPLAY_SERVER_WAYLAND
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_login_wayland(&self) -> bool {
|
||||
super::is_gdm_user(&self.username) && self.protocal == DISPLAY_SERVER_WAYLAND
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_headless(&self) -> bool {
|
||||
self.sid.is_empty()
|
||||
}
|
||||
|
||||
fn get_display(&mut self) {
|
||||
self.display = get_env_tries("DISPLAY", &self.uid, GNOME_SESSION_BINARY, 10);
|
||||
if self.display.is_empty() {
|
||||
self.display = get_env_tries("DISPLAY", &self.uid, XFCE4_PANEL, 10);
|
||||
}
|
||||
if self.display.is_empty() {
|
||||
self.display = Self::get_display_by_user(&self.username);
|
||||
}
|
||||
if self.display.is_empty() {
|
||||
self.display = ":0".to_owned();
|
||||
}
|
||||
self.display = self
|
||||
.display
|
||||
.replace(&whoami::hostname(), "")
|
||||
.replace("localhost", "");
|
||||
}
|
||||
|
||||
fn get_xauth_from_xorg(&mut self) {
|
||||
if let Ok(output) = run_cmds(&format!(
|
||||
"ps -u {} -f | grep 'Xorg' | grep -v 'grep'",
|
||||
&self.uid
|
||||
)) {
|
||||
for line in output.lines() {
|
||||
let mut auth_found = false;
|
||||
for v in line.split_whitespace() {
|
||||
if v == "-auth" {
|
||||
auth_found = true;
|
||||
} else if auth_found {
|
||||
if std::path::Path::new(v).is_absolute() {
|
||||
self.xauth = v.to_string();
|
||||
} else {
|
||||
if let Some(pid) = line.split_whitespace().nth(1) {
|
||||
let home_dir = get_env_from_pid("HOME", pid);
|
||||
if home_dir.is_empty() {
|
||||
self.xauth = format!("/home/{}/{}", self.username, v);
|
||||
} else {
|
||||
self.xauth = format!("{}/{}", home_dir, v);
|
||||
}
|
||||
} else {
|
||||
// unreachable!
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_xauth(&mut self) {
|
||||
self.xauth = get_env_tries("XAUTHORITY", &self.uid, GNOME_SESSION_BINARY, 10);
|
||||
if self.xauth.is_empty() {
|
||||
get_env_tries("XAUTHORITY", &self.uid, XFCE4_PANEL, 10);
|
||||
}
|
||||
if self.xauth.is_empty() {
|
||||
self.get_xauth_from_xorg();
|
||||
}
|
||||
|
||||
let gdm = format!("/run/user/{}/gdm/Xauthority", self.uid);
|
||||
if self.xauth.is_empty() {
|
||||
self.xauth = if std::path::Path::new(&gdm).exists() {
|
||||
gdm
|
||||
} else {
|
||||
let username = &self.username;
|
||||
if username == "root" {
|
||||
format!("/{}/.Xauthority", username)
|
||||
} else {
|
||||
let tmp = format!("/home/{}/.Xauthority", username);
|
||||
if std::path::Path::new(&tmp).exists() {
|
||||
tmp
|
||||
} else {
|
||||
format!("/var/lib/{}/.Xauthority", username)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
fn get_display_by_user(user: &str) -> String {
|
||||
// log::debug!("w {}", &user);
|
||||
if let Ok(output) = std::process::Command::new("w").arg(&user).output() {
|
||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||
let mut iter = line.split_whitespace();
|
||||
let b = iter.nth(2);
|
||||
if let Some(b) = b {
|
||||
if b.starts_with(":") {
|
||||
return b.to_owned();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// above not work for gdm user
|
||||
//log::debug!("ls -l /tmp/.X11-unix/");
|
||||
let mut last = "".to_owned();
|
||||
if let Ok(output) = std::process::Command::new("ls")
|
||||
.args(vec!["-l", "/tmp/.X11-unix/"])
|
||||
.output()
|
||||
{
|
||||
for line in String::from_utf8_lossy(&output.stdout).lines() {
|
||||
let mut iter = line.split_whitespace();
|
||||
let user_field = iter.nth(2);
|
||||
if let Some(x) = iter.last() {
|
||||
if x.starts_with("X") {
|
||||
last = x.replace("X", ":").to_owned();
|
||||
if user_field == Some(&user) {
|
||||
return last;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
last
|
||||
}
|
||||
|
||||
pub fn refresh(&mut self) {
|
||||
if !self.sid.is_empty() && is_active(&self.sid) {
|
||||
return;
|
||||
}
|
||||
|
||||
let seat0_values = get_values_of_seat0(&[0, 1, 2]);
|
||||
if seat0_values[0].is_empty() {
|
||||
*self = Self::default();
|
||||
return;
|
||||
}
|
||||
|
||||
self.sid = seat0_values[0].clone();
|
||||
self.uid = seat0_values[1].clone();
|
||||
self.username = seat0_values[2].clone();
|
||||
self.protocal = get_display_server_of_session(&self.sid).into();
|
||||
if self.is_login_wayland() {
|
||||
self.display = "".to_owned();
|
||||
self.xauth = "".to_owned();
|
||||
return;
|
||||
}
|
||||
|
||||
self.get_display();
|
||||
self.get_xauth();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -883,7 +883,7 @@ impl Connection {
|
||||
let dtype = crate::platform::linux::get_display_server();
|
||||
if dtype != "x11" && dtype != "wayland" {
|
||||
res.set_error(format!(
|
||||
"Unsupported display server type {}, x11 or wayland expected",
|
||||
"Unsupported display server type \"{}\", x11 or wayland expected",
|
||||
dtype
|
||||
));
|
||||
let mut msg_out = Message::new();
|
||||
@ -1669,7 +1669,7 @@ impl Connection {
|
||||
Some(message::Union::AudioFrame(frame)) => {
|
||||
if !self.disable_audio {
|
||||
if let Some(sender) = &self.audio_sender {
|
||||
allow_err!(sender.send(MediaData::AudioFrame(frame)));
|
||||
allow_err!(sender.send(MediaData::AudioFrame(Box::new(frame))));
|
||||
} else {
|
||||
log::warn!(
|
||||
"Processing audio frame without the voice call audio sender."
|
||||
|
@ -1193,7 +1193,9 @@ fn is_function_key(ck: &EnumOrUnknown<ControlKey>) -> bool {
|
||||
});
|
||||
res = true;
|
||||
} else if ck.value() == ControlKey::LockScreen.value() {
|
||||
lock_screen_2();
|
||||
std::thread::spawn(|| {
|
||||
lock_screen_2();
|
||||
});
|
||||
res = true;
|
||||
}
|
||||
return res;
|
||||
|
@ -189,6 +189,17 @@ impl<T: Subscriber + From<ConnInner>> ServiceTmpl<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn wait_prelogin(&self) {
|
||||
#[cfg(target_os = "linux")]
|
||||
while self.active() {
|
||||
if crate::platform::linux::is_prelogin() {
|
||||
break;
|
||||
}
|
||||
thread::sleep(time::Duration::from_millis(300));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn repeat<S, F>(&self, interval_ms: u64, callback: F)
|
||||
where
|
||||
F: 'static + FnMut(Self, &mut S) -> ResultType<()> + Send,
|
||||
@ -198,6 +209,8 @@ impl<T: Subscriber + From<ConnInner>> ServiceTmpl<T> {
|
||||
let mut callback = callback;
|
||||
let sp = self.clone();
|
||||
let thread = thread::spawn(move || {
|
||||
sp.wait_prelogin();
|
||||
|
||||
let mut state = S::default();
|
||||
let mut may_reset = false;
|
||||
while sp.active() {
|
||||
@ -232,6 +245,8 @@ impl<T: Subscriber + From<ConnInner>> ServiceTmpl<T> {
|
||||
let sp = self.clone();
|
||||
let mut callback = callback;
|
||||
let thread = thread::spawn(move || {
|
||||
sp.wait_prelogin();
|
||||
|
||||
let mut error_timeout = HIBERNATE_TIMEOUT;
|
||||
while sp.active() {
|
||||
if sp.has_subscribes() {
|
||||
|
12
src/ui.rs
12
src/ui.rs
@ -54,6 +54,18 @@ pub fn start(args: &mut [String]) {
|
||||
let dir = "/usr";
|
||||
sciter::set_library(&(prefix + dir + "/lib/rustdesk/libsciter-gtk.so")).ok();
|
||||
}
|
||||
#[cfg(windows)]
|
||||
// Check if there is a sciter.dll nearby.
|
||||
if let Ok(exe) = std::env::current_exe() {
|
||||
if let Some(parent) = exe.parent() {
|
||||
let sciter_dll_path = parent.join("sciter.dll");
|
||||
if sciter_dll_path.exists() {
|
||||
// Try to set the sciter dll.
|
||||
let p = sciter_dll_path.to_string_lossy().to_string();
|
||||
log::debug!("Found dll:{}, \n {:?}", p, sciter::set_library(&p));
|
||||
}
|
||||
}
|
||||
}
|
||||
// https://github.com/c-smile/sciter-sdk/blob/master/include/sciter-x-types.h
|
||||
// https://github.com/rustdesk/rustdesk/issues/132#issuecomment-886069737
|
||||
#[cfg(windows)]
|
||||
|
@ -1149,13 +1149,15 @@ pub async fn io_loop<T: InvokeUiSession>(handler: Session<T>) {
|
||||
let frame_count = Arc::new(AtomicUsize::new(0));
|
||||
let frame_count_cl = frame_count.clone();
|
||||
let ui_handler = handler.ui_handler.clone();
|
||||
let (video_sender, audio_sender) = start_video_audio_threads(move |data: &mut Vec<u8>| {
|
||||
frame_count_cl.fetch_add(1, Ordering::Relaxed);
|
||||
ui_handler.on_rgba(data);
|
||||
});
|
||||
let (video_sender, audio_sender, video_queue) =
|
||||
start_video_audio_threads(move |data: &mut Vec<u8>| {
|
||||
frame_count_cl.fetch_add(1, Ordering::Relaxed);
|
||||
ui_handler.on_rgba(data);
|
||||
});
|
||||
|
||||
let mut remote = Remote::new(
|
||||
handler,
|
||||
video_queue,
|
||||
video_sender,
|
||||
audio_sender,
|
||||
receiver,
|
||||
|
Loading…
Reference in New Issue
Block a user