1b3c3496c5
- Убраны все машинно/инфра-специфичные данные из README/CODEMAP/скриптов/ workflows (хосты, IP, домен gitea -> github.server_url). - preconfigure: enable-check-update=N (выкл. проверку обновлений); подсказка «set up your own server» и так гаснет с override-сервером. - CI публикует exe/apk в Gitea Release `latest` (обновляется каждый прогон, стабильная ссылка) + версионный релиз на теге v*. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
133 lines
13 KiB
Markdown
133 lines
13 KiB
Markdown
# CODEMAP — rustdesk-custom
|
||
|
||
Карта overlay-репозитория для преднастроенной сборки RustDesk. Держать актуальной при каждом изменении.
|
||
|
||
## Структура
|
||
|
||
| Путь | Назначение |
|
||
|------|-----------|
|
||
| `upstream.txt` | Пины: `RUSTDESK_TAG`, версии Rust/LLVM/Flutter, `VCPKG_COMMIT_ID`, `VCPKG_TRIPLET`, Android-пины. Единственный источник версий. |
|
||
| `scripts/preconfigure.sh` | Патчит `RENDEZVOUS_SERVERS` и `RS_PUB_KEY` в `hbb_common/src/config.rs` клона. Значения из env. Проверяет, что патч применился. |
|
||
| `scripts/bump-upstream.sh` | `[<tag>|latest]` → тянет пины тулчейна из CI-конфигов целевого тега RustDesk (flutter-build.yml + bridge.yml) и переписывает `upstream.txt` (с диффом). Так бамп версии не разъезжается с Flutter/vcpkg/LLVM/FRB/NDK. |
|
||
| `scripts/provision-windows.ps1` | Идемпотентно доводит тулчейн до пинов (Rust+rustfmt, Flutter, LLVM, vcpkg@коммит). Ставит только отсутствующее/несовпадающее. Зовётся из build-windows.ps1 (skip: `RD_SKIP_PROVISION=1`). |
|
||
| `scripts/build-windows.ps1` | Оркестратор Windows-сборки: provision → load env → клон@пин → preconfigure → codegen → vcpkg install → build.py → портативный установщик → `dist/`. |
|
||
| `scripts/provision-android.sh` | Идемпотентный Android-тулчейн на build-VM под пины (Flutter/NDK/cargo-ndk/vcpkg/JDK17/apt). Пишет `~/dev/rd-android.env`. |
|
||
| `scripts/build-android.sh` | Оркестратор Android APK (arm64-v8a): env → клон@пин → preconfigure → build_android_deps → codegen → cargo-ndk → jniLibs → flutter apk → `dist/`. |
|
||
| `config/server.env.example` | Шаблон значений. Реальный `config/server.env` — в `.gitignore`. |
|
||
| `.gitea/workflows/` | CI: `build-windows.yaml` (раннер `windows`, ✅ зелёный), `build-android.yaml` (раннер `android`/build-VM). |
|
||
| `rustdesk/` | Клон апстрима (gitignored, создаётся сборкой). |
|
||
| `dist/` | Готовые артефакты (gitignored). |
|
||
|
||
## Механизм преднастройки (важно)
|
||
|
||
RustDesk 1.4.9, `libs/hbb_common/src/config.rs` (сабмодуль `rustdesk/hbb_common`, пин `7e1c392`):
|
||
```rust
|
||
pub const RENDEZVOUS_SERVERS: &[&str] = &["rs-ny.rustdesk.com"];
|
||
pub const RS_PUB_KEY: &str = "OeVuKk5nlHiXp+APNn0Y3pC1Iwpwn44JGqrQCsWqmBw=";
|
||
```
|
||
- `option_env!(RENDEZVOUS_SERVER/RS_PUB_KEY)` из старого PR #2810 **в master вырезан** — только патч констант.
|
||
- Порт hbbs по умолчанию 21116 (не указывать, если стандартный). Нестандартный — `host:port`.
|
||
- API-сервер (только RustDesk Server Pro) отдельной const в 1.4.9 не имеет; для обычного hbbs/hbbr не нужен.
|
||
- Альтернатива без сборки (на будущее): переименовать официальный бинарь в
|
||
`rustdesk-host=<server>,key=<pubkey>.exe` — конфиг читается из имени файла (`EXE_RENDEZVOUS_SERVER`).
|
||
|
||
## Windows toolchain (поднять один раз на Windows-хосте)
|
||
|
||
Версии — из `upstream.txt` (пины из `flutter-build.yml@1.4.9`):
|
||
- **Rust 1.75** — `rustup toolchain install 1.75`; в дереве клона `rustup override set 1.75`
|
||
(апстрим держит 1.75 из-за i128 ABI-изменения в 1.78+).
|
||
- **LLVM 15.0.6** — для bindgen; задать `LIBCLANG_PATH` на `bin` LLVM.
|
||
- **Flutter 3.24.5** (канал stable) в PATH. Апстрим применяет патч
|
||
`.github/patches/flutter_3.24.4_dropdown_menu_enableFilter.diff` к SDK — при ошибке сборки применить.
|
||
- **vcpkg@120deac3** — склонировать, `bootstrap-vcpkg`, задать `VCPKG_ROOT`. Триплет `x64-windows-static`.
|
||
Зависимости из `vcpkg.json`: aom, libvpx, libyuv, opus, libjpeg-turbo, mfx-dispatch,
|
||
**ffmpeg** (static, features amf/nvcodec/qsv — hwcodec). ffmpeg/aom — длинная первая компиляция.
|
||
- Сборка: `python build.py --flutter` (флаги: `--hwcodec`, `--portable`, `--vram`, `--skip-cargo`).
|
||
|
||
### Грабля: bridge_generated.rs (обязательный codegen)
|
||
RustDesk **не коммитит** `src/bridge_generated.rs` (`lib.rs` объявляет `mod bridge_generated;`). Без
|
||
генерации cargo build падает: `E0583 file not found for module bridge_generated` + `E0277 EventToUI:
|
||
IntoIntoDart`. Генерится `flutter_rust_bridge_codegen` (в CI RustDesk — отдельный `bridge.yml`):
|
||
```
|
||
cargo +stable install cargo-expand --version 1.0.95 --locked
|
||
cargo +stable install flutter_rust_bridge_codegen --version 1.80.1 --features uuid --locked
|
||
pushd flutter && flutter pub get && popd
|
||
RUSTC_BOOTSTRAP=1 flutter_rust_bridge_codegen --rust-input ./src/flutter_ffi.rs \
|
||
--dart-output ./flutter/lib/generated_bridge.dart --c-output ./flutter/macos/Runner/bridge_generated.h \
|
||
--llvm-path S:/dev/LLVM # ffigen ищет libclang.dll в дефолтных путях, LLVM у нас на S:
|
||
```
|
||
Пины FRB_VERSION/CARGO_EXPAND_VERSION — в `upstream.txt`. Шаг встроен в `build-windows.ps1` перед build.py.
|
||
RUSTC_BOOTSTRAP=1 нужен, т.к. cargo-expand требует nightly-фич, а тулчейн 1.75 stable.
|
||
**Грабля:** codegen зовёт `rustfmt`; без него (`rustup component add rustfmt --toolchain 1.75-...`) он
|
||
крэшится ПОСЛЕ генерации rust-моста, но ДО dart-стороны — `bridge_generated.rs` есть, а
|
||
`generated_bridge.dart`/`.freezed.dart` нет → flutter build падает `EventToUI_Event/RustdeskImpl isn't a type`.
|
||
Поэтому проверять надо dart-файлы, не только rust.
|
||
|
||
### Грабля: portable-pack и python3-заглушка (Windows-хосте)
|
||
`build.py --flutter` в конце зовёт `python3 ./generate.py` для сборки портативного установщика. На
|
||
Windows-хосте `python3` = Microsoft Store-заглушка (реальный только `python` = 3.12) → шаг падает
|
||
(«Python Error occurred when executing generate.py»), хотя **клиент к этому моменту уже собран** в
|
||
`flutter/build/windows/x64/runner/Release/`. Поэтому `build-windows.ps1` зовёт `build.py --skip-portable-pack`,
|
||
а установщик пакует отдельным шагом реальным `python generate.py` → `target/release/rustdesk-portable-packer.exe`
|
||
→ копия в `dist/rustdesk-<tag>-install.exe`.
|
||
|
||
### Разрешённый вопрос: flutter-engine
|
||
Стоковый Flutter 3.24.5 x64 engine отработал — `flutter build windows` собрался БЕЗ кастомного
|
||
`windows-x64-release.zip` (тот нужен апстриму только для Win7). Для Win10/11 подмена не требуется.
|
||
|
||
## Android (build-VM, раннер `android`)
|
||
Тулчейн: `scripts/provision-android.sh` (Flutter 3.24.5, NDK r28c от Google напрямую, cargo-ndk 3.1.2,
|
||
Rust+aarch64-target, vcpkg@пин, FRB codegen; apt: clang/cmake/nasm/libssl-dev/openjdk-17). Пишет
|
||
`~/dev/rd-android.env`. Ставит в `~/dev` (нужно ~40 ГБ свободного места под vcpkg-android/target).
|
||
Сборка: `scripts/build-android.sh` (arm64-v8a): клон@пин → preconfigure → `build_android_deps.sh arm64-v8a`
|
||
(vcpkg под arm, ffmpeg/aom из исходников — долго) → FRB codegen (`--llvm-path` авто) → `cargo ndk build`
|
||
→ jniLibs (.so+libc++_shared.so) → `flutter build apk` → `dist/rustdesk-<tag>-arm64.apk`.
|
||
Пороговый Rust-target ставит provision. Пин submodule hbb_common, пины из upstream.txt.
|
||
|
||
### Android-грабли (все зашиты в скрипты)
|
||
- **openssl-sys (host)**: `cargo ndk` падал «Could not find OpenSSL» для host-таргета → `libssl-dev` (provision).
|
||
- **bindgen NDK-sysroot**: magnum-opus/hwcodec/scrap bindgen резолвил `#include <stdint.h>` в host-glibc →
|
||
`bits/libc-header-start.h not found`. Фикс: `BINDGEN_EXTRA_CLANG_ARGS_aarch64_linux_android="--sysroot=$NDK/.../sysroot --target=aarch64-linux-android21"` (build-android.sh).
|
||
- **hwcodec**: пока БЕЗ него (`RUSTDESK_ANDROID_FEATURES=flutter`); его build.rs добавлял свои bindgen-грабли.
|
||
Включить: `RUSTDESK_ANDROID_FEATURES=flutter,hwcodec` (после доводки).
|
||
- **Java/Gradle**: VM дефолт Java 21, Gradle 7.6.4 не тянет → `JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64`
|
||
(build-android.sh, как RustDesk CI). Kotlin `e:`-варнинги (metadata 2.1.0 vs 1.6.0) — НЕ фатальны.
|
||
- **Подпись**: release требует key.properties → без него патчим build.gradle на debug-подпись
|
||
(`signingConfig = key.properties есть ? release : debug`). Свой keystore = `flutter/android/key.properties`.
|
||
|
||
Публикация APK: `.gitea/workflows/build-android.yaml` (раннер `android`) → gitea release на теге. F-Droid — позже.
|
||
|
||
## Грабли: прокси и vcpkg (Windows-хосте)
|
||
На машине в env задан `NO_PROXY=...,10.0.0.0/8,...` (CIDR). WinHTTP-загрузчик vcpkg (и
|
||
`bootstrap.ps1`) не парсит CIDR → падает с `WinHttpSetOption/WinHttpOpen error 87/0x57` на первом же
|
||
скачивании (nasm и т.п.). У машины есть прямой интернет (`netsh winhttp` = Direct, HEAD к nasm.us = 200),
|
||
поэтому `build-windows.ps1` **очищает HTTP(S)_PROXY/NO_PROXY для процесса** сборки — качается напрямую.
|
||
vcpkg.exe тоже качали вручную через IWR (bootstrap не смог) — лежит в `S:\dev\vcpkg\vcpkg.exe` (tool 2025-07-21).
|
||
|
||
## Тулчейн (фактические пути на Windows-хосте)
|
||
Flutter: `S:\dev\flutter` · vcpkg: `S:\dev\vcpkg` (VCPKG_ROOT) · **LLVM 15.0.6: `S:\dev\LLVM`**
|
||
(VS-бандл содержит только clang-format/tidy, БЕЗ libclang.dll — ставили LLVM отдельно, LIBCLANG_PATH=`S:\dev\LLVM\bin`) ·
|
||
Rust 1.75 (rustup override в клоне) · MSVC 14.44 из vcvars64.
|
||
|
||
## Секреты в CI (gitea Actions)
|
||
`RUSTDESK_SERVER`, `RUSTDESK_PUB_KEY`, (опц.) `RUSTDESK_API_SERVER`. Префикс имён — не `GITHUB_`/`GITEA_`
|
||
(зарезервированы), при необходимости `GT_`.
|
||
|
||
## Custom-client: сервер виден+залочен + preset-пароль
|
||
Требование: сервер показан в Настройках и НЕизменяем + вшитый постоянный пароль (+ временный).
|
||
Механизм RustDesk (изучен по коду 1.4.9):
|
||
- `src/common.rs::load_custom_client()` (зовётся из core_main) читает `custom.txt` рядом с exe —
|
||
base64 + **ED25519-подпись** по вшитому pubkey `5Qbwsde3…` (приватник у генератора RustDesk Pro, у нас нет).
|
||
- Он заполняет `OVERWRITE_SETTINGS` (override — залоченные опции), `DEFAULT_SETTINGS`, `BUILTIN_SETTINGS` (локи),
|
||
`HARD_SETTINGS` (top-level, вкл. preset-пароль).
|
||
- `custom-rendezvous-server`/`relay-server`/`key`/`api-server`/`verification-method` ∈ `KEYS_SETTINGS` →
|
||
в `override-settings` показываются И залочены. `disable-change-permanent-password` ∈ BUILDIN.
|
||
- Preset-пароль (`hbb_common/src/config/permanent_password.rs`): `HARD_SETTINGS.password="00"+base64(sha256(pw+salt))`,
|
||
`HARD_SETTINGS.salt=<любая непустая соль>`. Формат «00»+b64(h1), h1=sha256(pw+salt)[..32].
|
||
|
||
Наша реализация (`preconfigure.sh`, вкл. по умолчанию; выкл. `RUSTDESK_NO_CUSTOM_CLIENT=1`):
|
||
- Пишет `src/custom_client.json` (override-settings + password/salt из `RUSTDESK_PRESET_PASSWORD`).
|
||
- Патчит `common.rs`: добавляет `read_custom_client_unsigned()` (парсит JSON БЕЗ подписи, тот же apply-код) +
|
||
`include_str!("custom_client.json")` в начало `load_custom_client()`. Работает Windows+Android (без внешнего файла).
|
||
- Пароль — только из env/secret `RUSTDESK_PRESET_PASSWORD`, солёный хэш пишется в gitignored-клон, plaintext нигде.
|