Merge branch 'rustdesk:master' into master

This commit is contained in:
Arash Hatami 2021-11-14 18:52:51 +03:30 committed by GitHub
commit 70a4ee4318
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 443 additions and 109 deletions

181
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,181 @@
name: CI
# env:
# MIN_SUPPORTED_RUST_VERSION: "1.46.0"
# CICD_INTERMEDIATES_DIR: "_cicd-intermediates"
on:
workflow_dispatch:
pull_request:
push:
branches:
- master
tags:
- '*'
jobs:
# ensure_cargo_fmt:
# name: Ensure 'cargo fmt' has been run
# runs-on: ubuntu-20.04
# steps:
# - uses: actions-rs/toolchain@v1
# with:
# toolchain: stable
# default: true
# profile: minimal
# components: rustfmt
# - uses: actions/checkout@v2
# - run: cargo fmt -- --check
# min_version:
# name: Minimum supported rust version
# runs-on: ubuntu-20.04
# steps:
# - name: Checkout source code
# uses: actions/checkout@v2
# - name: Install rust toolchain (v${{ env.MIN_SUPPORTED_RUST_VERSION }})
# uses: actions-rs/toolchain@v1
# with:
# toolchain: ${{ env.MIN_SUPPORTED_RUST_VERSION }}
# default: true
# profile: minimal # minimal component installation (ie, no documentation)
# components: clippy
# - name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
# uses: actions-rs/cargo@v1
# with:
# command: clippy
# args: --locked --all-targets --all-features -- --allow clippy::unknown_clippy_lints
# - name: Run tests
# uses: actions-rs/cargo@v1
# with:
# command: test
# args: --locked
build:
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
runs-on: ${{ matrix.job.os }}
strategy:
fail-fast: false
matrix:
job:
# - { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
# - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true }
# - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
# - { target: i686-pc-windows-msvc , os: windows-2019 }
# - { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
# - { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
# - { target: x86_64-apple-darwin , os: macos-10.15 }
# - { target: x86_64-pc-windows-gnu , os: windows-2019 }
# - { target: x86_64-pc-windows-msvc , os: windows-2019 }
- { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04 }
# - { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
steps:
- name: Checkout source code
uses: actions/checkout@v2
- name: Install prerequisites
shell: bash
run: |
case ${{ matrix.job.target }} in
x86_64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt install -y g++ gcc 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 ;;
# arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
# aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
esac
- name: Restore from cache and install vcpkg
uses: lukka/run-vcpkg@v7
with:
setupOnly: true
vcpkgGitCommitId: '1d4128f08e30cec31b94500840c7eca8ebc579cb'
- name: Install vcpkg dependencies
run: |
$VCPKG_ROOT/vcpkg install libvpx libyuv opus
shell: bash
- 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)
- name: Show version information (Rust, cargo, GCC)
shell: bash
run: |
gcc --version || true
rustup -V
rustup toolchain list
rustup default
cargo -V
rustc -V
- uses: Swatinem/rust-cache@v1
- name: Build
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.job.use-cross }}
command: build
args: --locked --release --target=${{ matrix.job.target }}
# - name: Strip debug information from executable
# id: strip
# shell: bash
# run: |
# # Figure out suffix of binary
# EXE_suffix=""
# case ${{ matrix.job.target }} in
# *-pc-windows-*) EXE_suffix=".exe" ;;
# esac;
# # Figure out what strip tool to use if any
# STRIP="strip"
# case ${{ matrix.job.target }} in
# arm-unknown-linux-*) STRIP="arm-linux-gnueabihf-strip" ;;
# aarch64-unknown-linux-gnu) STRIP="aarch64-linux-gnu-strip" ;;
# *-pc-windows-msvc) STRIP="" ;;
# esac;
# # Setup paths
# BIN_DIR="${{ env.CICD_INTERMEDIATES_DIR }}/stripped-release-bin/"
# mkdir -p "${BIN_DIR}"
# BIN_NAME="${{ env.PROJECT_NAME }}${EXE_suffix}"
# BIN_PATH="${BIN_DIR}/${BIN_NAME}"
# # Copy the release build binary to the result location
# cp "target/${{ matrix.job.target }}/release/${BIN_NAME}" "${BIN_DIR}"
# # Also strip if possible
# if [ -n "${STRIP}" ]; then
# "${STRIP}" "${BIN_PATH}"
# fi
# # Let subsequent steps know where to find the (stripped) bin
# echo ::set-output name=BIN_PATH::${BIN_PATH}
# echo ::set-output name=BIN_NAME::${BIN_NAME}
- name: Set testing options
id: test-options
shell: bash
run: |
# test only library unit tests and binary for arm-type targets
unset CARGO_TEST_OPTIONS
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--lib --bin ${PROJECT_NAME}" ;; esac;
echo ::set-output name=CARGO_TEST_OPTIONS::${CARGO_TEST_OPTIONS}
- name: Build tests
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.job.use-cross }}
command: build
args: --locked --tests --target=${{ matrix.job.target }}
# - name: Run tests
# uses: actions-rs/cargo@v1
# with:
# use-cross: ${{ matrix.job.use-cross }}
# command: test
# args: --locked --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}

43
Cargo.lock generated
View File

@ -352,6 +352,20 @@ dependencies = [
"vec_map", "vec_map",
] ]
[[package]]
name = "clipboard-master"
version = "3.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cd1cb2f0df685eb4a61c656faeb6ef391ad776943d3723afb12bdcbceff824d"
dependencies = [
"objc",
"objc-foundation",
"objc_id",
"winapi 0.3.9",
"windows-win",
"x11-clipboard",
]
[[package]] [[package]]
name = "clipboard-win" name = "clipboard-win"
version = "4.2.1" version = "4.2.1"
@ -2860,6 +2874,7 @@ dependencies = [
"cc", "cc",
"cfg-if 1.0.0", "cfg-if 1.0.0",
"clap", "clap",
"clipboard-master",
"cocoa", "cocoa",
"core-foundation 0.9.1", "core-foundation 0.9.1",
"core-graphics", "core-graphics",
@ -3771,6 +3786,15 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "windows-win"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d4243ec23afe4e9b4e668b3c0a0e973f1b8265f6a46223cfcbc16fd267480c0"
dependencies = [
"winapi 0.3.9",
]
[[package]] [[package]]
name = "winreg" name = "winreg"
version = "0.6.2" version = "0.6.2"
@ -3814,6 +3838,15 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214"
[[package]]
name = "x11-clipboard"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b397ace6e980510de59a4fe3d4c758dffab231d6d747ce9fa1aba6b6035d5f32"
dependencies = [
"xcb",
]
[[package]] [[package]]
name = "x11rb" name = "x11rb"
version = "0.8.1" version = "0.8.1"
@ -3826,6 +3859,16 @@ dependencies = [
"winapi-wsapoll", "winapi-wsapoll",
] ]
[[package]]
name = "xcb"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62056f63138b39116f82a540c983cc11f1c90cd70b3d492a70c25eaa50bd22a6"
dependencies = [
"libc",
"log",
]
[[package]] [[package]]
name = "yansi" name = "yansi"
version = "0.5.0" version = "0.5.0"

View File

@ -51,6 +51,7 @@ mac_address = "1.1"
sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn" } sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn" }
ctrlc = "3.2" ctrlc = "3.2"
arboard = "2.0" arboard = "2.0"
clipboard-master = "3"
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
#systray = { git = "https://github.com/open-trade/systray-rs" } #systray = { git = "https://github.com/open-trade/systray-rs" }

View File

@ -7,7 +7,7 @@ RUN git clone https://github.com/microsoft/vcpkg && cd vcpkg && git checkout 134
RUN /vcpkg/bootstrap-vcpkg.sh -disableMetrics RUN /vcpkg/bootstrap-vcpkg.sh -disableMetrics
RUN /vcpkg/vcpkg --disable-metrics install libvpx libyuv opus RUN /vcpkg/vcpkg --disable-metrics install libvpx libyuv opus
RUN groupadd -r user && useradd -r -g user user --home /home/user && mkdir -p /home/user && chown user /home/user RUN groupadd -r user && useradd -r -g user user --home /home/user && mkdir -p /home/user && chown user /home/user && echo "user ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/user
WORKDIR /home/user WORKDIR /home/user
RUN wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so RUN wget https://raw.githubusercontent.com/c-smile/sciter-sdk/master/bin.lnx/x64/libsciter-gtk.so
USER user USER user

View File

@ -106,6 +106,10 @@ mv libsciter-gtk.so target/debug
cargo run cargo run
``` ```
### Ändere Wayland zu X11 (Xorg)
RustDesk unterstützt "Wayland" nicht. Siehe [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) um Xorg als Standard GNOME Session zu nutzen.
## Auf Docker Kompilieren ## Auf Docker Kompilieren
Beginne damit das Repository zu klonen und den Docker Container zu bauen: Beginne damit das Repository zu klonen und den Docker Container zu bauen:
@ -136,10 +140,6 @@ target/release/rustdesk
Bitte gehe sicher, dass du diese Befehle vom Stammverzeichnis vom RustDesk Repository nutzt, sonst kann es passieren, dass das Programm die Ressourcen nicht finden kann. Bitte bedenke auch, dass Unterbefehle von Cargo, wie z.B. `install` oder `run` aktuell noch nicht unterstützt werden, da sie das Programm innerhalb des Containers starten oder installieren würden, anstatt auf deinem eigentlichen System. Bitte gehe sicher, dass du diese Befehle vom Stammverzeichnis vom RustDesk Repository nutzt, sonst kann es passieren, dass das Programm die Ressourcen nicht finden kann. Bitte bedenke auch, dass Unterbefehle von Cargo, wie z.B. `install` oder `run` aktuell noch nicht unterstützt werden, da sie das Programm innerhalb des Containers starten oder installieren würden, anstatt auf deinem eigentlichen System.
### Ändere Wayland zu X11 (Xorg)
RustDesk unterstützt "Wayland" nicht. Siehe [hier](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) um Xorg als Standard GNOME Session zu nutzen.
## Dateistruktur ## Dateistruktur
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: Video Codec, Konfiguration, TCP/UDP Wrapper, Protokoll Puffer, fs Funktionen für Dateitransfer, und ein paar andere nützliche Funktionen - **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: Video Codec, Konfiguration, TCP/UDP Wrapper, Protokoll Puffer, fs Funktionen für Dateitransfer, und ein paar andere nützliche Funktionen

View File

@ -104,6 +104,10 @@ mv libsciter-gtk.so target/debug
cargo run cargo run
``` ```
### Cambia Wayland a X11 (Xorg)
RustDesk no soporta Wayland. Comprueba [aquí](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar Xorg en la sesión por defecto de GNOME.
## Como compilar con Docker ## Como compilar con Docker
Empieza clonando el repositorio y compilando el contenedor de docker: Empieza clonando el repositorio y compilando el contenedor de docker:
@ -134,10 +138,6 @@ target/release/rustdesk
Por favor, asegurate de que estás ejecutando estos comandos desde la raíz del repositorio de RustDesk, de lo contrario la aplicación puede ser incapaz de encontrar los recursos necesarios. También hay que tener en cuenta que otros subcomandos de carga como `install` o `run` no estan actualmente soportados via este metodo y podrían requerir ser instalados dentro del contenedor y no en el host. Por favor, asegurate de que estás ejecutando estos comandos desde la raíz del repositorio de RustDesk, de lo contrario la aplicación puede ser incapaz de encontrar los recursos necesarios. También hay que tener en cuenta que otros subcomandos de carga como `install` o `run` no estan actualmente soportados via este metodo y podrían requerir ser instalados dentro del contenedor y no en el host.
### Cambia Wayland a X11 (Xorg)
RustDesk no soporta Wayland. Comprueba [aquí](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) para configurar Xorg en la sesión por defecto de GNOME.
## Estructura de archivos ## Estructura de archivos
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, configuración, tcp/udp wrapper, protobuf, fs funciones para transferencia de ficheros, y alguna función de utilidad. - **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, configuración, tcp/udp wrapper, protobuf, fs funciones para transferencia de ficheros, y alguna función de utilidad.

View File

@ -104,6 +104,10 @@ mv libsciter-gtk.so target/debug
Exécution du cargo Exécution du cargo
``` ```
### Changer Wayland en X11 (Xorg)
RustDesk ne supporte pas Wayland. Lisez [cela](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) pour configurer Xorg comme la session GNOME par défaut.
## Comment construire avec Docker ## Comment construire avec Docker
Commencez par cloner le dépôt et construire le conteneur Docker : Commencez par cloner le dépôt et construire le conteneur Docker :
@ -134,10 +138,6 @@ target/release/rustdesk
Veuillez vous assurer que vous exécutez ces commandes à partir de la racine du référentiel RustDesk, sinon l'application ne pourra pas trouver les ressources requises. Notez également que les autres sous-commandes de cargo telles que `install` ou `run` ne sont pas actuellement supportées par cette méthode car elles installeraient ou exécuteraient le programme à l'intérieur du conteneur au lieu de l'hôte. Veuillez vous assurer que vous exécutez ces commandes à partir de la racine du référentiel RustDesk, sinon l'application ne pourra pas trouver les ressources requises. Notez également que les autres sous-commandes de cargo telles que `install` ou `run` ne sont pas actuellement supportées par cette méthode car elles installeraient ou exécuteraient le programme à l'intérieur du conteneur au lieu de l'hôte.
### Changer Wayland en X11 (Xorg)
RustDesk ne supporte pas Wayland. Lisez [cela](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) pour configurer Xorg comme la session GNOME par défaut.
## Structure du projet ## Structure du projet
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)** : codec vidéo, config, wrapper tcp/udp, protobuf, fonctions fs pour le transfert de fichiers, et quelques autres fonctions utilitaires. - **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)** : codec vidéo, config, wrapper tcp/udp, protobuf, fonctions fs pour le transfert de fichiers, et quelques autres fonctions utilitaires.

View File

@ -105,6 +105,10 @@ mv libsciter-gtk.so target/debug
cargo run cargo run
``` ```
### Zmień Wayland na X11 (Xorg)
RustDesk nie obsługuje Waylanda. Sprawdź [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) by skonfigurować Xorg jako domyślną sesję GNOME.
## Jak kompilować za pomocą Dockera ## Jak kompilować za pomocą Dockera
Rozpocznij od sklonowania repozytorium i stworzenia kontenera docker: Rozpocznij od sklonowania repozytorium i stworzenia kontenera docker:
@ -135,10 +139,6 @@ target/release/rustdesk
Upewnij się, że uruchamiasz te polecenia z katalogu głównego repozytorium RustDesk, w przeciwnym razie aplikacja może nie być w stanie znaleźć wymaganych zasobów. Należy również pamiętać, że inne podpolecenia ładowania, takie jak `install` lub `run` nie są obecnie obsługiwane za pomocą tej metody, ponieważ instalowałyby lub uruchamiały program wewnątrz kontenera zamiast na hoście. Upewnij się, że uruchamiasz te polecenia z katalogu głównego repozytorium RustDesk, w przeciwnym razie aplikacja może nie być w stanie znaleźć wymaganych zasobów. Należy również pamiętać, że inne podpolecenia ładowania, takie jak `install` lub `run` nie są obecnie obsługiwane za pomocą tej metody, ponieważ instalowałyby lub uruchamiały program wewnątrz kontenera zamiast na hoście.
### Zmień Wayland na X11 (Xorg)
RustDesk nie obsługuje Waylanda. Sprawdź [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) by skonfigurować Xorg jako domyślną sesję GNOME.
## Struktura plików ## Struktura plików
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: kodek wideo, config, wrapper tcp/udp, protobuf, funkcje fs do transferu plików i kilka innych funkcji użytkowych - **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: kodek wideo, config, wrapper tcp/udp, protobuf, funkcje fs do transferu plików i kilka innych funkcji użytkowych

View File

@ -105,6 +105,11 @@ mv libsciter-gtk.so target/debug
cargo run cargo run
``` ```
### 把 Wayland 修改成 X11 (Xorg)
RustDesk 暂时不支持 Wayland不过正在积极开发中.
请查看[this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/)配置 X11.
## 使用 Docker 编译 ## 使用 Docker 编译
首先克隆存储库并构建 docker 容器: 首先克隆存储库并构建 docker 容器:
@ -186,11 +191,6 @@ target/release/rustdesk
请确保您从 RustDesk 存储库的根目录运行这些命令,否则应用程序可能无法找到所需的资源。另请注意,此方法当前不支持其他`Cargo`子命令, 请确保您从 RustDesk 存储库的根目录运行这些命令,否则应用程序可能无法找到所需的资源。另请注意,此方法当前不支持其他`Cargo`子命令,
例如 `install``run`,因为运行在容器里,而不是宿主机上。 例如 `install``run`,因为运行在容器里,而不是宿主机上。
### 把 Wayland 修改成 X11 (Xorg)
RustDesk 暂时不支持 Wayland不过正在积极开发中.
请查看[this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/)配置 X11.
## 文件结构 ## 文件结构
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: 视频编解码, 配置, tcp/udp 封装, protobuf, 文件传输相关文件系统操作函数, 以及一些其他实用函数 - **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: 视频编解码, 配置, tcp/udp 封装, protobuf, 文件传输相关文件系统操作函数, 以及一些其他实用函数

View File

@ -105,6 +105,10 @@ mv libsciter-gtk.so target/debug
VCPKG_ROOT=$HOME/vcpkg cargo run VCPKG_ROOT=$HOME/vcpkg cargo run
``` ```
### Change Wayland to X11 (Xorg)
RustDesk does not support Wayland. Check [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) to configuring Xorg as the default GNOME session.
## How to build with Docker ## How to build with Docker
Begin by cloning the repository and building the docker container: Begin by cloning the repository and building the docker container:
@ -135,10 +139,6 @@ target/release/rustdesk
Please ensure that you are running these commands from the root of the RustDesk repository, otherwise the application may be unable to find the required resources. Also note that other cargo subcommands such as `install` or `run` are not currently supported via this method as they would install or run the program inside the container instead of the host. Please ensure that you are running these commands from the root of the RustDesk repository, otherwise the application may be unable to find the required resources. Also note that other cargo subcommands such as `install` or `run` are not currently supported via this method as they would install or run the program inside the container instead of the host.
### Change Wayland to X11 (Xorg)
RustDesk does not support Wayland. Check [this](https://docs.fedoraproject.org/en-US/quick-docs/configuring-xorg-as-default-gnome-session/) to configuring Xorg as the default GNOME session.
## File Structure ## File Structure
- **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs functions for file transfer, and some other utility functions - **[libs/hbb_common](https://github.com/rustdesk/rustdesk/tree/master/libs/hbb_common)**: video codec, config, tcp/udp wrapper, protobuf, fs functions for file transfer, and some other utility functions

View File

@ -1,13 +1,5 @@
#!/bin/sh #!/bin/sh
if [ "$(id -u)" != "${PUID:-1000}" ] || [ "$(id -g)" != "${PGID:-1000}" ]; then
usermod -o -u "${PUID:-1000}" user
groupmod -o -g "${PGID:-1000}" user
chown -R user /home/user
sudo -u user /entrypoint $@
exit 0
fi
cd $HOME/rustdesk cd $HOME/rustdesk
. $HOME/.cargo/env . $HOME/.cargo/env

View File

@ -48,6 +48,7 @@ message PunchHoleSent {
string id = 2; string id = 2;
string relay_server = 3; string relay_server = 3;
NatType nat_type = 4; NatType nat_type = 4;
string version = 5;
} }
message RegisterPk { message RegisterPk {
@ -110,6 +111,7 @@ message RelayResponse {
bytes pk = 5; bytes pk = 5;
} }
string refuse_reason = 6; string refuse_reason = 6;
string version = 7;
} }
message SoftwareUpdate { string url = 1; } message SoftwareUpdate { string url = 1; }
@ -128,6 +130,7 @@ message LocalAddr {
bytes local_addr = 2; bytes local_addr = 2;
string relay_server = 3; string relay_server = 3;
string id = 4; string id = 4;
string version = 5;
} }
message RendezvousMessage { message RendezvousMessage {

View File

@ -1,6 +1,6 @@
pub use arboard::Clipboard as ClipboardContext; pub use arboard::Clipboard as ClipboardContext;
use hbb_common::{ use hbb_common::{
allow_err, allow_err, bail,
compress::{compress as compress_func, decompress}, compress::{compress as compress_func, decompress},
config::{Config, COMPRESS_LEVEL, RENDEZVOUS_TIMEOUT}, config::{Config, COMPRESS_LEVEL, RENDEZVOUS_TIMEOUT},
log, log,
@ -240,6 +240,10 @@ async fn test_nat_type_() -> ResultType<bool> {
let rendezvous_server = get_rendezvous_server(100).await; let rendezvous_server = get_rendezvous_server(100).await;
let server1 = rendezvous_server; let server1 = rendezvous_server;
let mut server2 = server1; let mut server2 = server1;
if server1.port() == 0 { // offline
// avoid overflow crash
bail!("Offline");
}
server2.set_port(server1.port() - 1); server2.set_port(server1.port() - 1);
let mut msg_out = RendezvousMessage::new(); let mut msg_out = RendezvousMessage::new();
let serial = Config::get_serial(); let serial = Config::get_serial();

View File

@ -285,6 +285,7 @@ impl RendezvousMediator {
let mut msg_out = Message::new(); let mut msg_out = Message::new();
let mut rr = RelayResponse { let mut rr = RelayResponse {
socket_addr, socket_addr,
version: crate::VERSION.to_owned(),
..Default::default() ..Default::default()
}; };
if initiate { if initiate {
@ -321,6 +322,7 @@ impl RendezvousMediator {
socket_addr: AddrMangle::encode(peer_addr), socket_addr: AddrMangle::encode(peer_addr),
local_addr: AddrMangle::encode(local_addr), local_addr: AddrMangle::encode(local_addr),
relay_server, relay_server,
version: crate::VERSION.to_owned(),
..Default::default() ..Default::default()
}); });
let bytes = msg_out.write_to_bytes()?; let bytes = msg_out.write_to_bytes()?;
@ -359,6 +361,7 @@ impl RendezvousMediator {
id: Config::get_id(), id: Config::get_id(),
relay_server, relay_server,
nat_type: nat_type.into(), nat_type: nat_type.into(),
version: crate::VERSION.to_owned(),
..Default::default() ..Default::default()
}); });
let bytes = msg_out.write_to_bytes()?; let bytes = msg_out.write_to_bytes()?;

View File

@ -3,49 +3,102 @@ pub use crate::common::{
check_clipboard, ClipboardContext, CLIPBOARD_INTERVAL as INTERVAL, CLIPBOARD_NAME as NAME, check_clipboard, ClipboardContext, CLIPBOARD_INTERVAL as INTERVAL, CLIPBOARD_NAME as NAME,
CONTENT, CONTENT,
}; };
use clipboard_master::{CallbackResult, ClipboardHandler, Master};
struct State { use hbb_common::{anyhow, ResultType};
ctx: Option<ClipboardContext>, use std::{
} io, sync,
sync::{
impl Default for State { atomic::{AtomicBool, Ordering},
fn default() -> Self { mpsc::SyncSender,
let ctx = match ClipboardContext::new() { },
Ok(ctx) => Some(ctx), time::Duration,
Err(err) => { };
log::error!("Failed to start {}: {}", NAME, err);
None
}
};
Self { ctx }
}
}
impl super::service::Reset for State {
fn reset(&mut self) {
*CONTENT.lock().unwrap() = Default::default();
}
}
pub fn new() -> GenericService { pub fn new() -> GenericService {
let sp = GenericService::new(NAME, true); let sp = GenericService::new(NAME, true);
sp.repeat::<State, _>(INTERVAL, run); sp.run::<_>(listen::run);
sp sp
} }
fn run(sp: GenericService, state: &mut State) -> ResultType<()> { mod listen {
if let Some(ctx) = state.ctx.as_mut() { use super::*;
if let Some(msg) = check_clipboard(ctx, None) {
sp.send(msg); static RUNNING: AtomicBool = AtomicBool::new(true);
} static WAIT: Duration = Duration::from_millis(1500);
sp.snapshot(|sps| {
let txt = crate::CONTENT.lock().unwrap().clone(); struct ClipHandle {
if !txt.is_empty() { tx: SyncSender<()>,
let msg_out = crate::create_clipboard_msg(txt); }
sps.send_shared(Arc::new(msg_out));
} impl ClipboardHandler for ClipHandle {
Ok(()) fn on_clipboard_change(&mut self) -> CallbackResult {
})?; if !RUNNING.load(Ordering::SeqCst) {
return CallbackResult::Stop;
}
let _ = self.tx.send(());
CallbackResult::Next
}
fn on_clipboard_error(&mut self, error: io::Error) -> CallbackResult {
if !RUNNING.load(Ordering::SeqCst) {
CallbackResult::Stop
} else {
CallbackResult::StopWithError(error)
}
}
}
#[tokio::main]
pub async fn run(sp: GenericService) -> ResultType<()> {
let mut ctx = match ClipboardContext::new() {
Ok(ctx) => ctx,
Err(err) => {
log::error!("Failed to start {}: {}", NAME, err);
return Err(anyhow::Error::from(err));
}
};
if !RUNNING.load(Ordering::SeqCst) {
RUNNING.store(true, Ordering::SeqCst);
}
let (tx, rx) = sync::mpsc::sync_channel(12);
let listener = tokio::spawn(async {
log::info!("Clipboard listener running!");
let _ = Master::new(ClipHandle { tx }).run();
});
while sp.ok() {
if let Ok(_) = rx.recv_timeout(WAIT) {
if let Some(msg) = check_clipboard(&mut ctx, None) {
sp.send(msg);
}
}
sp.snapshot(|sps| {
let txt = crate::CONTENT.lock().unwrap().clone();
if !txt.is_empty() {
let msg_out = crate::create_clipboard_msg(txt);
sps.send_shared(Arc::new(msg_out));
}
Ok(())
})?;
}
RUNNING.store(false, Ordering::SeqCst);
trigger(&mut ctx);
let _ = listener.await;
log::info!("Clipboard listener stopped!");
*CONTENT.lock().unwrap() = Default::default();
Ok(())
}
fn trigger(ctx: &mut ClipboardContext) {
let _ = match ctx.get_text() {
Ok(text) => ctx.set_text(text),
Err(_) => ctx.set_text(Default::default()),
};
} }
Ok(())
} }

View File

@ -333,9 +333,21 @@ impl UI {
} }
} }
} }
*self.2.lock().unwrap() = m.clone();
ipc::set_options(m).ok(); ipc::set_options(m).ok();
} }
fn set_option(&self, key: String, value: String) {
let mut options = self.2.lock().unwrap();
if value.is_empty() {
options.remove(&key);
} else {
options.insert(key, value);
}
ipc::set_options(options.clone()).ok();
}
fn install_path(&mut self) -> String { fn install_path(&mut self) -> String {
#[cfg(windows)] #[cfg(windows)]
return crate::platform::windows::get_install_info().1; return crate::platform::windows::get_install_info().1;
@ -587,6 +599,7 @@ impl sciter::EventHandler for UI {
fn test_if_valid_server(String); fn test_if_valid_server(String);
fn get_sound_inputs(); fn get_sound_inputs();
fn set_options(Value); fn set_options(Value);
fn set_option(String, String);
fn get_software_update_url(); fn get_software_update_url();
fn get_new_version(); fn get_new_version();
fn get_version(); fn get_version();

View File

@ -257,6 +257,10 @@ handler.msgbox = function(type, title, text, callback=null, height=180, width=50
self.timer(150ms, function() { msgbox(type, title, text, callback, height, width, retry); }); self.timer(150ms, function() { msgbox(type, title, text, callback, height, width, retry); });
} }
handler.block_msgbox = function(type, title, text, callback=null, height=180, width=500, retry=0) {
msgbox(type, title, text, callback, height, width, retry);
}
var reconnectTimeout = 1; var reconnectTimeout = 1;
handler.msgbox_retry = function(type, title, text, hasRetry, callback=null, height=180, width=500) { handler.msgbox_retry = function(type, title, text, hasRetry, callback=null, height=180, width=500) {
handler.msgbox(type, title, text, callback, height, width, hasRetry ? reconnectTimeout : 0); handler.msgbox(type, title, text, callback, height, width, hasRetry ? reconnectTimeout : 0);

View File

@ -30,6 +30,7 @@ table > thead {
} }
table > tbody { table > tbody {
behavior: select-multiple;
overflow-y: scroll-indicator; overflow-y: scroll-indicator;
size: *; size: *;
background: white; background: white;
@ -85,6 +86,15 @@ table.has_current tr:current /* current row */
background-color: color(accent); background-color: color(accent);
} }
table.has_current tbody tr:checked
{
background-color: color(accent);
}
table.has_current tbody tr:checked td {
color: highlighttext;
}
table td table td
{ {
padding: 4px; padding: 4px;

View File

@ -374,7 +374,7 @@ class FolderView : Reactor.Component {
path = this.joinPath(entry.name); path = this.joinPath(entry.name);
} }
var tm = entry.time ? new Date(entry.time.toFloat() * 1000.).toLocaleString() : 0; var tm = entry.time ? new Date(entry.time.toFloat() * 1000.).toLocaleString() : 0;
return <tr> return <tr role="option">
<td type={entry.type} filename={path}></td> <td type={entry.type} filename={path}></td>
<td>{entry.name}</td> <td>{entry.name}</td>
<td value={entry.time || 0}>{tm || ""}</td> <td value={entry.time || 0}>{tm || ""}</td>
@ -401,20 +401,31 @@ class FolderView : Reactor.Component {
} }
event click $(.trash) () { event click $(.trash) () {
var row = this.getCurrentRow(); var rows = this.getCurrentRows();
if (!row) return; if (!rows || rows.length == 0) return;
var path = row[0];
var type = row[1]; var delete_dirs = new Array();
var new_history = [];
for (var i = 0; i < this.history.length; ++i) { for (var i = 0; i < rows.length; ++i) {
var h = this.history[i]; var row = rows[i];
if ((h + this.sep()).indexOf(path + this.sep()) == -1) new_history.push(h);
var path = row[0];
var type = row[1];
var new_history = [];
for (var j = 0; j < this.history.length; ++j) {
var h = this.history[j];
if ((h + this.sep()).indexOf(path + this.sep()) == -1) new_history.push(h);
}
this.history = new_history;
if (type == 1) {
delete_dirs.push(path);
} else {
confirmDelete(path, this.is_remote);
}
} }
this.history = new_history; for (var i = 0; i < delete_dirs.length; ++i) {
if (type == 1) { file_transfer.job_table.addDelDir(delete_dirs[i], this.is_remote);
file_transfer.job_table.addDelDir(path, this.is_remote);
} else {
confirmDelete(path, this.is_remote);
} }
} }
@ -463,10 +474,28 @@ class FolderView : Reactor.Component {
return [this.joinPath(name), type]; return [this.joinPath(name), type];
} }
function getCurrentRows() {
var rows = this.table.getCurrentRows();
if (!rows || rows.length== 0) return;
var records = new Array();
for (var i = 0; i < rows.length; ++i) {
var name = rows[i][1].text;
if (!name || name == "..") continue;
var type = rows[i][0].attributes["type"];
records.push([this.joinPath(name), type]);
}
return records;
}
event click $(.send) () { event click $(.send) () {
var cur = this.getCurrentRow(); var rows = this.getCurrentRows();
if (!cur) return; if (!rows || rows.length == 0) return;
file_transfer.job_table.send(cur[0], this.is_remote); for (var i = 0; i < rows.length; ++i) {
file_transfer.job_table.send(rows[i][0], this.is_remote);
}
} }
event change $(.select-dir) (_, el) { event change $(.select-dir) (_, el) {
@ -570,7 +599,7 @@ var deleting_single_file_jobs = {};
var create_dir_jobs = {} var create_dir_jobs = {}
function confirmDelete(path, is_remote) { function confirmDelete(path, is_remote) {
handler.msgbox("custom-skip", "Confirm Delete", "<div .form> \ handler.block_msgbox("custom-skip", "Confirm Delete", "<div .form> \
<div>Are you sure you want to delete this file?</div> \ <div>Are you sure you want to delete this file?</div> \
<div.ellipsis style=\"font-weight: bold;\">" + path + "</div> \ <div.ellipsis style=\"font-weight: bold;\">" + path + "</div> \
</div>", function(res=null) { </div>", function(res=null) {
@ -590,7 +619,7 @@ handler.confirmDeleteFiles = function(id, i, name) {
if (i >= n) return; if (i >= n) return;
var file_path = job.path; var file_path = job.path;
if (name) file_path += handler.get_path_sep(job.is_remote) + name; if (name) file_path += handler.get_path_sep(job.is_remote) + name;
handler.msgbox("custom-skip", "Confirm Delete", "<div .form> \ handler.block_msgbox("custom-skip", "Confirm Delete", "<div .form> \
<div>Deleting #" + (i + 1) + " of " + n + " files.</div> \ <div>Deleting #" + (i + 1) + " of " + n + " files.</div> \
<div>Are you sure you want to delete this file?</div> \ <div>Are you sure you want to delete this file?</div> \
<div.ellipsis style=\"font-weight: bold;\" .text>" + name + "</div> \ <div.ellipsis style=\"font-weight: bold;\" .text>" + name + "</div> \

View File

@ -25,6 +25,11 @@ class Grid: Behavior {
return this.$(tbody>tr:current); return this.$(tbody>tr:current);
} }
function getCurrentRows()
{
return this.$$(tbody>tr:checked);
}
function getCurrentColumn() function getCurrentColumn()
{ {
return this.$(thead>:current); // return current cell in header row return this.$(thead>:current); // return current cell in header row

View File

@ -40,9 +40,7 @@ class ConnectStatus: Reactor.Component {
} }
event click $(.connect-status .link) () { event click $(.connect-status .link) () {
var options = handler.get_options(); handler.set_option("stop-service", "");
options["stop-service"] = "";
handler.set_options(options);
} }
} }
@ -138,7 +136,6 @@ function createNewConnect(id, type) {
var myIdMenu; var myIdMenu;
var audioInputMenu; var audioInputMenu;
var configOptions = {};
class AudioInputs: Reactor.Component { class AudioInputs: Reactor.Component {
function this() { function this() {
audioInputMenu = this; audioInputMenu = this;
@ -167,7 +164,7 @@ class AudioInputs: Reactor.Component {
} }
function get_value() { function get_value() {
return configOptions["audio-input"] || this.get_default(); return handler.get_option("audio-input") || this.get_default();
} }
function toggleMenuState() { function toggleMenuState() {
@ -182,8 +179,7 @@ class AudioInputs: Reactor.Component {
var v = me.id; var v = me.id;
if (v == this.get_value()) return; if (v == this.get_value()) return;
if (v == this.get_default()) v = ""; if (v == this.get_default()) v = "";
configOptions["audio-input"] = v; handler.set_option("audio-input", v);
handler.set_options(configOptions);
this.toggleMenuState(); this.toggleMenuState();
} }
} }
@ -223,7 +219,6 @@ class MyIdMenu: Reactor.Component {
event click $(svg#menu) (_, me) { event click $(svg#menu) (_, me) {
audioInputMenu.update({ show: true }); audioInputMenu.update({ show: true });
configOptions = handler.get_options();
this.toggleMenuState(); this.toggleMenuState();
var menu = $(menu#config-options); var menu = $(menu#config-options);
me.popup(menu); me.popup(menu);
@ -232,7 +227,7 @@ class MyIdMenu: Reactor.Component {
function toggleMenuState() { function toggleMenuState() {
for (var el in $$(menu#config-options>li)) { for (var el in $$(menu#config-options>li)) {
if (el.id && el.id.indexOf("enable-") == 0) { if (el.id && el.id.indexOf("enable-") == 0) {
var enabled = configOptions[el.id] != "N"; var enabled = handler.get_option(el.id) != "N";
el.attributes.toggleClass("selected", enabled); el.attributes.toggleClass("selected", enabled);
el.attributes.toggleClass("line-through", !enabled); el.attributes.toggleClass("line-through", !enabled);
} }
@ -241,11 +236,10 @@ class MyIdMenu: Reactor.Component {
event click $(menu#config-options>li) (_, me) { event click $(menu#config-options>li) (_, me) {
if (me.id && me.id.indexOf("enable-") == 0) { if (me.id && me.id.indexOf("enable-") == 0) {
configOptions[me.id] = configOptions[me.id] == "N" ? "" : "N"; handler.set_option(me.id, handler.get_option(me.id) == "N" ? "" : "N");
handler.set_options(configOptions);
} }
if (me.id == "whitelist") { if (me.id == "whitelist") {
var old_value = (configOptions["whitelist"] || "").split(",").join("\n"); var old_value = handler.get_option("whitelist").split(",").join("\n");
handler.msgbox("custom-whitelist", "IP Whitelisting", "<div .form> \ handler.msgbox("custom-whitelist", "IP Whitelisting", "<div .form> \
<textarea spellcheck=\"false\" name=\"text\" novalue=\"0.0.0.0\" style=\"overflow: scroll-indicator; height: 160px; font-size: 1.2em; padding: 0.5em;\">" + old_value + "</textarea>\ <textarea spellcheck=\"false\" name=\"text\" novalue=\"0.0.0.0\" style=\"overflow: scroll-indicator; height: 160px; font-size: 1.2em; padding: 0.5em;\">" + old_value + "</textarea>\
</div> \ </div> \
@ -253,7 +247,7 @@ class MyIdMenu: Reactor.Component {
if (!res) return; if (!res) return;
var value = (res.text || "").trim(); var value = (res.text || "").trim();
if (value) { if (value) {
var values = value.split(/[\s,;]+/g); var values = value.split(/[\s,;\n]+/g);
for (var ip in values) { for (var ip in values) {
if (!ip.match(/^\d+\.\d+\.\d+\.\d+$/)) { if (!ip.match(/^\d+\.\d+\.\d+\.\d+$/)) {
return "Invalid ip: " + ip; return "Invalid ip: " + ip;
@ -262,11 +256,11 @@ class MyIdMenu: Reactor.Component {
value = values.join("\n"); value = values.join("\n");
} }
if (value == old_value) return; if (value == old_value) return;
configOptions["whitelist"] = value.replace("\n", ",");
stdout.println("whitelist updated"); stdout.println("whitelist updated");
handler.set_options(configOptions); handler.set_option("whitelist", value.replace("\n", ","));
}, 300); }, 300);
} else if (me.id == "custom-server") { } else if (me.id == "custom-server") {
var configOptions = handler.get_options();
var old_relay = configOptions["relay-server"] || ""; var old_relay = configOptions["relay-server"] || "";
var old_id = configOptions["custom-rendezvous-server"] || ""; var old_id = configOptions["custom-rendezvous-server"] || "";
handler.msgbox("custom-server", "ID/Relay Server", "<div .form> \ handler.msgbox("custom-server", "ID/Relay Server", "<div .form> \
@ -293,8 +287,7 @@ class MyIdMenu: Reactor.Component {
} else if (me.id == "forum") { } else if (me.id == "forum") {
handler.open_url("https:://forum.rustdesk.com"); handler.open_url("https:://forum.rustdesk.com");
} else if (me.id == "stop-service") { } else if (me.id == "stop-service") {
configOptions["stop-service"] = service_stopped ? "" : "Y"; handler.set_option("stop-service", service_stopped ? "" : "Y");
handler.set_options(configOptions);
} else if (me.id == "about") { } else if (me.id == "about") {
var name = handler.get_app_name(); var name = handler.get_app_name();
handler.msgbox("custom-nocancel-nook-hasclose", "About " + name, "<div style='line-height: 2em'> \ handler.msgbox("custom-nocancel-nook-hasclose", "About " + name, "<div style='line-height: 2em'> \