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, RSS
ConfigDir, Events, Storage
Cargo Workspace
The project is organized as a Cargo workspace with five crates:
| Crate | Type | Description |
|---|---|---|
risuko-engine | Library | Core engine with zero runtime dependencies |
risuko-bt | Library | In-tree BitTorrent v1 engine consumed by risuko-engine |
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"]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 risuko-cli and 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.