docs: add CLAUDE.md with codebase guide for Claude Code
Generated via /init. Covers workspace layout, the TorrentManager + per-torrent scope thread + event aggregator architecture, build/test commands, the custom-protocol release-build requirement, and XDG paths. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
79
CLAUDE.md
Normal file
79
CLAUDE.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
|
||||
## Workspace layout
|
||||
|
||||
Cargo workspace (Rust 2024 edition, resolver 3) with three crates, two frontends, and an RPM packaging pipeline:
|
||||
|
||||
- `monsoon-core/` — shared library: `config`, `manager` (TorrentManager + per-torrent scope threads), `registry` (on-disk torrent list), `magnet`, `types`. Both host crates depend on this; almost all torrent logic lives here.
|
||||
- `src-tauri/` — Tauri desktop binary (crate name `monsoon`). Thin wrapper: `lib.rs` boots Tauri and the event aggregator, `commands.rs` exposes `#[tauri::command]` shims into `monsoon-core::manager::TorrentManager`.
|
||||
- `monsoon-server/` — headless `monsoon-server` axum binary. REST API (`api.rs`), WebSocket event stream (`ws.rs`). Reuses the same `TorrentManager` wrapped in a `tokio::sync::Mutex` via `AppState`.
|
||||
- `src/` + `package.json` (root) — Svelte 5 + Vite frontend for the desktop app. Built to `dist/`, embedded into the Tauri binary when the `custom-protocol` feature is enabled.
|
||||
- `monsoon-web/` — separate Svelte 5 + Vite frontend for the headless server. Built to `monsoon-web/dist/`, served by `monsoon-server` via `tower-http::ServeDir` (found via `MONSOON_WEB_DIR`, or `../monsoon-web/dist` relative to the binary, or `monsoon-web/dist` relative to cwd).
|
||||
|
||||
Version is single-sourced from `[workspace.package]` in `Cargo.toml` and stamped by CI into `src-tauri/tauri.conf.json`, both `package.json` files, and `monsoon.spec`.
|
||||
|
||||
## Architecture: the torrent manager
|
||||
|
||||
`monsoon-core::manager::TorrentManager` is the single owner of all active torrents. The host (Tauri app or axum server) holds it inside a `Mutex` and is responsible for running an **event aggregator thread**:
|
||||
|
||||
1. Each torrent runs in its own *scope thread* spawned by `add_torrent` and managed via `run_torrent_scope` (from `vortex-bittorrent`). Communication is via `SyncSender<Command>` in, and `crossbeam_channel::Sender<AggregatedEvent>` out.
|
||||
2. All scope threads share one `crossbeam_channel` receiver (`manager.event_rx`). The host clones it and spawns a thread that loops on `recv()`.
|
||||
3. For every event the aggregator must call `mgr.apply_event(&event)` to update the in-memory snapshot. Then it emits to the UI: the Tauri app uses `app_handle.emit(...)`, the server broadcasts JSON over `tokio::sync::broadcast` to WebSocket clients and optionally fires `webhook_url`.
|
||||
4. Persistence lives in `monsoon-core::registry::Registry` (a JSON list of `TorrentEntry { info_hash, name, source: TorrentFile|MagnetLink, paused }`). `restore_torrents()` re-adds entries on startup.
|
||||
|
||||
Queue management (`max_concurrent_downloads`, `min_peers_before_queue`, `STALL_TICKS_THRESHOLD`, `STALL_SPEED_THRESHOLD`) is enforced inside `TorrentManager`; stalled torrents rotate to the back of the queue.
|
||||
|
||||
When making changes that touch both hosts, the change usually belongs in `monsoon-core`. The Tauri commands and axum handlers should stay thin — they translate transport (Tauri IPC vs. HTTP/WS) into manager calls.
|
||||
|
||||
## Common commands
|
||||
|
||||
```bash
|
||||
# Rust workspace (these are the CI gates — run them before claiming "done")
|
||||
cargo fmt --check --all
|
||||
cargo clippy --workspace -- -D warnings
|
||||
cargo build --workspace
|
||||
cargo test --workspace
|
||||
|
||||
# Run a single test
|
||||
cargo test -p monsoon-core <test_name>
|
||||
|
||||
# Desktop app: build frontend (root) then the binary. custom-protocol embeds dist/.
|
||||
pnpm install && pnpm build
|
||||
cargo build --release -p monsoon --features custom-protocol
|
||||
|
||||
# Desktop dev with hot reload
|
||||
cargo tauri dev
|
||||
|
||||
# Headless server: build its own frontend, then the binary
|
||||
cd monsoon-web && pnpm install && pnpm build && cd ..
|
||||
cargo build --release -p monsoon-server
|
||||
MONSOON_WEB_DIR=$PWD/monsoon-web/dist ./target/release/monsoon-server
|
||||
|
||||
# Validate desktop/AppStream metadata (CI runs these)
|
||||
desktop-file-validate data/cafe.lair.monsoon.desktop
|
||||
appstreamcli validate --no-net data/cafe.lair.monsoon.metainfo.xml
|
||||
```
|
||||
|
||||
There is no JS/TS test or lint script — frontend validation is just `pnpm build` (typecheck via svelte/vite).
|
||||
|
||||
## Build features and packaging
|
||||
|
||||
- `custom-protocol` (in `src-tauri/Cargo.toml`) — required for **release builds** of the desktop app; without it Tauri expects a running Vite dev server. Always pass `--features custom-protocol` when building `-p monsoon` outside `cargo tauri dev`.
|
||||
- `release` profile is `lto = "fat"`, `codegen-units = 1`, `strip = "symbols"` — release builds are slow on purpose.
|
||||
- The `vortex-bittorrent` dependency is a pinned git rev (see `[workspace.dependencies]` in `Cargo.toml`). The RPM build vendors all deps including this git source; if you bump the rev, the vendor tarball regenerates on next CI run.
|
||||
- `dist.sh` produces `monsoon-<version>.tar.gz` (from `git archive`) + `monsoon-<version>-vendor.tar.gz` (from `cargo vendor`). `.copr/Makefile` calls this then `rpmbuild -bs monsoon.spec`. CI in `.gitea/workflows/ci.yml` runs the same flow on `v*` tags and publishes to the `grenade/monsoon` COPR project.
|
||||
- The CI tag workflow stamps the new version into every manifest and then commits the bump back to `main` — do not also bump versions manually when cutting a release; just tag.
|
||||
|
||||
## XDG paths (resolved by `monsoon-core::config::resolve_paths`)
|
||||
|
||||
| Purpose | Default |
|
||||
|---|---|
|
||||
| Config | `~/.config/monsoon/config.toml` |
|
||||
| Data + registry | `~/.local/share/monsoon/` (torrents.json lives here) |
|
||||
| Downloads | `~/.local/share/monsoon/downloads/` |
|
||||
| Logs | `~/.local/state/monsoon/monsoon.log` |
|
||||
| DHT bootstrap cache | `~/.cache/monsoon/dht_bootstrap_nodes` |
|
||||
|
||||
Both binaries call `config::load_or_create(None)` then `config::resolve_paths(&cfg)` at startup and create the directories before initializing the manager — keep that order if adding new path-dependent state.
|
||||
Reference in New Issue
Block a user