syntax = "proto3"; package torrent; service Torrents { // Add a torrent from a magnet link or .torrent file and start downloading it. rpc Add(AddRequest) returns (AddResponse); // Get the current status of a single torrent. rpc Status(StatusRequest) returns (TorrentStatus); // List all torrents known to the daemon. rpc List(ListRequest) returns (ListResponse); // Remove a torrent from tracking. rpc Remove(RemoveRequest) returns (RemoveResponse); // Pause a downloading torrent. rpc Pause(PauseRequest) returns (PauseResponse); // Resume a paused torrent. rpc Resume(ResumeRequest) returns (ResumeResponse); // Subscribe to a live stream of torrent notifications. Events are delivered // from the subscribe point onward — no history is replayed. New subscribers // only see events that fire after they connect. rpc Notifications(NotificationsRequest) returns (stream Notification); // List the files inside a torrent with their download progress. Returns // NOT_FOUND if the torrent is unknown or its metadata has not resolved yet // (e.g. a magnet link still fetching peers). rpc Files(FilesRequest) returns (FilesResponse); } message AddRequest { string magnet = 1; // Folder to download into. Empty = daemon default // (// for multi-file torrents). string download_folder = 2; // Folder to move the torrent into after completion. Empty = daemon default // (/completed//). string move_after_completion_folder = 3; } message AddResponse { string id = 1; } message StatusRequest { string id = 1; } message ListRequest {} message ListResponse { repeated TorrentStatus torrents = 1; } message RemoveRequest { string id = 1; bool delete_files = 2; } message RemoveResponse {} message PauseRequest { string id = 1; } message PauseResponse {} message ResumeRequest { string id = 1; } message ResumeResponse {} message NotificationsRequest { // If non-empty, only events for these torrent ids (or id prefixes, as // accepted by `Status`/`Remove`) are delivered. repeated string ids = 1; // If non-empty, only these event kinds are delivered. An empty list means // all kinds. repeated NotificationKind kinds = 2; } message FilesRequest { string id = 1; } enum FileState { FILE_STATE_UNSPECIFIED = 0; // File is partially downloaded. IN_PROGRESS = 1; // File's full byte range has been verified. READY = 2; } message TorrentFile { // Path relative to the torrent root, as declared in the .torrent metadata. // May contain forward slashes for multi-file torrents. string name = 1; uint64 length = 2; uint64 downloaded_bytes = 3; FileState state = 4; } message FilesResponse { repeated TorrentFile files = 1; } message Notification { // Wall-clock time the daemon observed the change, in milliseconds since the // Unix epoch. uint64 observed_at_unix_millis = 1; // What changed. Use this to dispatch; use the `oneof detail` for // kind-specific payload. NotificationKind kind = 2; // Full snapshot of the torrent *after* the change. Always populated so // consumers don't need to fan out to `Status` for context. TorrentStatus torrent = 3; oneof detail { StateChanged state_changed = 10; ProgressMark progress = 11; AddedInfo added = 12; RemovedInfo removed = 13; } } enum NotificationKind { NOTIFICATION_KIND_UNSPECIFIED = 0; // Emitted once when a torrent is added via `Add`. TORRENT_ADDED = 1; // Emitted once when a torrent is removed via `Remove`. TORRENT_REMOVED = 2; // Emitted on any `State` transition, including PAUSED <-> DOWNLOADING, // DOWNLOADING <-> STALE, * -> FINISHED, * -> ERROR. STATE_CHANGED = 3; // Emitted when the integer download percentage changes (rate-limited). // No event is sent if the percentage did not advance since the last tick. PROGRESS = 4; } message StateChanged { State previous = 1; State current = 2; } message ProgressMark { // Current integer percentage 0..=100. uint32 percent = 1; // Bytes downloaded since the previous PROGRESS event for this torrent. uint64 bytes_delta = 2; } message AddedInfo { // Source string as provided to `Add` (magnet, URL, or file path). string source = 1; } message RemovedInfo { // True if `Remove` was called with `delete_files = true`. bool files_deleted = 1; } enum State { STATE_UNSPECIFIED = 0; PENDING = 1; DOWNLOADING = 2; PAUSED = 3; FINISHED = 4; ERROR = 5; // Live per librqbit, but the daemon has detected a stall: no byte progress // for several ticks AND zero connected peers. The torrent is still // considered live by the underlying engine; this state is an application- // level overlay. Recovers to DOWNLOADING automatically when bytes advance // or a peer connects. STALE = 6; } message TorrentStatus { string id = 1; string info_hash = 2; string name = 3; string source = 4; string output_path = 5; uint64 total_bytes = 6; uint64 downloaded_bytes = 7; State state = 8; string error_message = 9; uint64 download_speed_bps = 10; uint64 eta_seconds = 11; uint64 uploaded_bytes = 12; uint64 upload_speed_bps = 13; uint32 peers = 14; uint32 seeds = 15; }