mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-08-27 08:36:42 +00:00
* Prefer active X11 session display * Update linux.rs * fix(linux): keep the logind display only when it is a local one `get_display_from_session` returns the value pam_systemd was handed at session creation, and logind never updates it afterwards. That value is not always a usable local display: it can be qualified with this host (`myhost:0`), name an X forwarding endpoint (`localhost:10.0`), or be a bare `:`. Taking it unconditionally is worse than taking nothing, because a non-empty `self.display` suppresses every fallback below it, `get_display_by_user` and the `:0` default alike. The stripping at the end of `get_display_x11` does not save the last two cases either: it leaves `:` as is and turns `localhost:10.0` into a local looking `:10.0`, either of which is then exported as DISPLAY and leaves the session unreachable, where before this PR the host got a working `:0`. Strip this host so `myhost:0` is still accepted as `:0`, leave `localhost` in place, and require a display number after the colon. Anything else falls through to the existing chain. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TKJxvTT6NQDEcnkWBx5bLA * docs(agents): prefer a little duplication over a restructure The "Be minimally invasive" rules already ask for purely additive diffs, but not in the case where the addition would otherwise reshape an existing function so the two can share code. Repeating a few lines is the better diff there. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TKJxvTT6NQDEcnkWBx5bLA --------- Co-authored-by: RustDesk <71636191+rustdesk@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
113 lines
5.7 KiB
Markdown
113 lines
5.7 KiB
Markdown
# RustDesk Guide
|
|
|
|
## Project Layout
|
|
|
|
### Directory Structure
|
|
* `src/` Rust app
|
|
* `src/server/` audio / clipboard / input / video / network
|
|
* `src/platform/` platform-specific code
|
|
* `src/ui/` legacy Sciter UI (deprecated)
|
|
* `flutter/` current UI
|
|
* `libs/hbb_common/` config / proto / shared utils
|
|
* `libs/scrap/` screen capture
|
|
* `libs/enigo/` input control
|
|
* `libs/clipboard/` clipboard
|
|
* `libs/hbb_common/src/config.rs` all options
|
|
|
|
### Key Components
|
|
- **Remote Desktop Protocol**: Custom protocol implemented in `src/rendezvous_mediator.rs` for communicating with rustdesk-server
|
|
- **Screen Capture**: Platform-specific screen capture in `libs/scrap/`
|
|
- **Input Handling**: Cross-platform input simulation in `libs/enigo/`
|
|
- **Audio/Video Services**: Real-time audio/video streaming in `src/server/`
|
|
- **File Transfer**: Secure file transfer implementation in `libs/hbb_common/`
|
|
|
|
### UI Architecture
|
|
- **Legacy UI**: Sciter-based (deprecated) - files in `src/ui/`
|
|
- **Modern UI**: Flutter-based - files in `flutter/`
|
|
- Desktop: `flutter/lib/desktop/`
|
|
- Mobile: `flutter/lib/mobile/`
|
|
- Shared: `flutter/lib/common/` and `flutter/lib/models/`
|
|
|
|
## Rust Rules
|
|
|
|
* Avoid `unwrap()` / `expect()` in production code.
|
|
* Exceptions:
|
|
|
|
* tests;
|
|
* lock acquisition where failure means poisoning, not normal control flow.
|
|
* Otherwise prefer `Result` + `?` or explicit handling.
|
|
* Do not ignore errors silently.
|
|
* Avoid unnecessary `.clone()`.
|
|
* Prefer borrowing when practical.
|
|
* Do not add dependencies unless needed.
|
|
* Keep code simple and idiomatic.
|
|
|
|
## Tokio Rules
|
|
|
|
* Assume a Tokio runtime already exists.
|
|
* Never create nested runtimes.
|
|
* Never call `Runtime::block_on()` inside Tokio / async code.
|
|
* Do not hide runtime creation inside helpers or libraries.
|
|
* Do not hold locks across `.await`.
|
|
* Prefer `.await`, `tokio::spawn`, channels.
|
|
* Use `spawn_blocking` or dedicated threads for blocking work.
|
|
* Do not use `std::thread::sleep()` in async code.
|
|
|
|
## Editing Hygiene
|
|
|
|
* Change only what is required.
|
|
* Prefer the smallest valid diff.
|
|
* Do not refactor unrelated code.
|
|
* Do not make formatting-only changes.
|
|
* Keep naming/style consistent with nearby code.
|
|
|
|
### Comments
|
|
|
|
* Avoid comments unless they explain a non-obvious reason, constraint, or workaround.
|
|
* Never restate what the code does; prefer clearer code instead.
|
|
* If the code is self-explanatory, add no comment.
|
|
|
|
### Be minimally invasive
|
|
|
|
* Prefer purely additive changes: layer new (`#[cfg]`-gated) blocks or new functions around existing code instead of restructuring it. The ideal diff for a fix adds lines and modifies/deletes none.
|
|
* Do not extract or reshape existing code just to enable your new code; look for a mechanism that leaves existing lines untouched (e.g. hide/show an existing object instead of refactoring its construction into a helper for rebuilding).
|
|
* Accept a little duplication over a restructure. A new function that repeats a few lines of an existing one is a better diff than reshaping the original so both can share it.
|
|
* Put new logic in self-contained functions in the module it belongs to (platform-specific logic in `src/platform/`, with `use` inside the function body to avoid churning shared import blocks). Call sites in shared files (`src/tray.rs`, `src/core_main.rs`, `src/server/connection.rs`, …) should be thin one-line hooks.
|
|
|
|
## Reviewing a PR
|
|
|
|
* Review only what the diff introduces. Verify ownership with `gh pr diff` before reporting a finding — if the offending lines are untouched context, it is a pre-existing problem, not this PR's.
|
|
* List pre-existing problems in a separate section at the end, or leave out the ones that are not fatal. Never mix them into the findings the author has to fix.
|
|
* Before re-reviewing, read the author's reply comments. Do not re-raise items they declined on scope grounds.
|
|
* State a finding's consequence exactly: distinguish "the value is lost" from "the shortcut is inert but the value still saves".
|
|
|
|
## Localization (`src/lang/*.rs`)
|
|
|
|
Each file is a `HashMap<key, translation>`. Layout:
|
|
|
|
* `template.rs` is the master list of every key. **Never edit it** as part of translation work.
|
|
* `en.rs` holds only the keys whose English display text differs from the key itself.
|
|
* Every other file (`de.rs`, `fr.rs`, …) carries the full key set; an untranslated entry has an empty value: `("key", "")`.
|
|
|
|
### Finding the English source for a key
|
|
|
|
When filling an empty entry, determine the source English text with this rule:
|
|
|
|
* If `key` exists in `en.rs` **with a non-empty value**, that value is the source text (look it up in `en.rs`).
|
|
* Otherwise the **key string itself is the source text** (the key is already plain English).
|
|
|
|
Then translate that source into the file's target language (infer the language from the file's existing non-empty entries / filename).
|
|
|
|
### Translation hygiene
|
|
|
|
* Only fill empty values. Never change keys, and never touch existing non-empty translations.
|
|
* Preserve placeholders (`{}`) and escape sequences (`\n`, `\"`) exactly as in the source.
|
|
* Do not translate brand or technical tokens: `RustDesk`, `Socks5`, `TLS`, `UAC`, `Wayland`, `X11`, `TCP`, `UDP`, `2FA`, `RDP`, `D3D`, etc.
|
|
* Copy URL values (e.g. `doc_*` keys) verbatim from `en.rs`.
|
|
|
|
### Adding new keys (feature work)
|
|
|
|
* New English-text keys use sentence case, not Title Case: `Use ID whitelisting`, **not** `Use ID Whitelisting`. Acronyms (ID, IP, 2FA…) stay uppercase. Legacy Title-Case keys (e.g. `Use IP Whitelisting`) stay as-is — do not rename them.
|
|
* Since the key itself is the English display text, a sentence-case key usually needs **no** `en.rs` entry; add one only when the display text must differ from the key (e.g. `*_tip` keys).
|
|
* Append each new key to `template.rs` (with `""`) and to every `src/lang/*.rs` file (translated, or `""` if unsure), at the end of the list.
|