Architecture
How Risuko is structured — the engine, traits, and distribution model.
Risuko follows a layered architecture where the core download engine is fully decoupled from any runtime environment.
High-Level Structure
Consumers
(Tauri + Vue)
(risuko-cli)
(risuko-js)
risuko-engine (Rust crate)
HTTP, BT (risuko-bt), ED2K, M3U8, FTP/SFTP, Media (yt-dlp), ADC/DC, Gnutella, G2, giFT, RSS, Upload Sinks
desktop download-history samples
ConfigDir, Events, Storage
Cargo Workspace
The project is organized as a Cargo workspace with nine crates:
| Crate | Type | Description |
|---|---|---|
risuko-engine | Library | Core engine — protocol handlers, RPC server, RSS, upload sinks, download stats store |
risuko-bt | Library | In-tree BitTorrent engine (v1, v2 per BEP 52, and hybrid) consumed by risuko-engine |
risuko-http | Library | Minimal hyper v1 HTTP client (TLS pool, SOCKS5/HTTP proxy, redirects, cookies, gzip/br/deflate decompression, pluggable DNS resolver with optional DNS-over-HTTPS) — no reqwest dep |
risuko-cookies | Library | Browser cookie extraction (Chromium, Firefox, Safari families) |
risuko-share | Library | Peer-to-peer encrypted file sharing built on iroh |
risuko-webview-upgrade | Library | Tauri plugin that swaps in a newer WebView kernel on Android |
risuko-cli | Binary | Standalone CLI tool |
risuko-napi | cdylib | Native Node.js bindings |
risuko (root) | Binary | Tauri desktop application |
[workspace]
members = ["risuko-engine", "risuko-bt", "risuko-cli", "risuko-napi", "risuko-http", "risuko-cookies", "risuko-webview-upgrade", "risuko-share"]Key Design Decisions
Trait-Based Decoupling
The engine uses three traits to abstract away runtime-specific behavior. This lets the same engine code run inside Tauri, as a standalone CLI, or embedded in Node.js.
See Trait System for details.
JSON-RPC for CLI
The CLI communicates with the engine via JSON-RPC over HTTP. This means:
- The
servecommand starts a headless engine with an RPC server - All other commands are RPC clients
- The
downloadcommand auto-starts a temporary engine if none is running
Global Singleton for NAPI
The Node.js bindings use a global LazyLock<Mutex<Option<NapiEngine>>> singleton. This ensures only one engine instance exists per process, which matches the startEngine/stopEngine lifecycle API.
Platform-Specific npm Packages
Both the CLI (@risuko/cli) and the Node.js bindings (@risuko/risuko-js) use the esbuild distribution pattern: a main package with optionalDependencies pointing to platform-specific packages. npm automatically installs only the package matching the current platform. A third package, @risuko/app, is a launcher that downloads the desktop app from GitHub Releases on first run.