The last contract gap blocking an M1 definition-of-done item: CORE's "401
handled" has no return path without it, and B2a's sibling F2 was accepted in
proto-answers-m1.md but never actually landed.
download.provideAuth {taskId, username, password, save?} -> {ok}, exactly as
proposed there. Privileged and Unix-socket-only: a credential-bearing method
must never be reachable from the browser, which is the other half of the
promise event.auth.required's own description already makes ("never back
through this event, never into a log"). It answers the challenge; it does not
itself resume the task -- the daemon retries with the credential attached and
the ordinary event.task.state reports the task leaving retry_wait, the same
as any other state change.
save only tells the daemon whether to persist the credential in the Secret
Service for next time, or use it for this attempt alone -- it never touches
SQLite or a log either way, in keeping with CLAUDE.md's secrets rule.
Three fixtures: the success path, -32010 for a task that no longer exists
(credentials submitted for it are simply discarded), and -32003 confirming
the extension has no path to this method under any transport.
mockd gets a real handler rather than falling through to the generic fixture
responder: it validates the taskId exists (so the -32010 fixture is
replayable) and actually transitions the task out of retry_wait.
Minor bump, 1.1.0 -> 1.2.0: additive method, no existing type touched.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_012fgjnqFCS5h5L7gZTZo3rV
1988 lines
93 KiB
C++
1988 lines
93 KiB
C++
// ---------------------------------------------------------------------------
|
|
// GENERATED FILE — DO NOT EDIT.
|
|
//
|
|
// Source: contracts/schema/**
|
|
// Generator: contracts/codegen/gen_cpp.py
|
|
// Contract: v1.2.0
|
|
//
|
|
// Hand-editing this file is a merge blocker. Fix the schema and regenerate:
|
|
// python3 contracts/codegen/gen_cpp.py
|
|
// Only lane PROTO commits to contracts/.
|
|
// ---------------------------------------------------------------------------
|
|
|
|
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <expected>
|
|
#include <map>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <vector>
|
|
|
|
#include <nlohmann/json.hpp>
|
|
|
|
// This is libveloxproto, NOT libveloxcore. The layering rule in CLAUDE.md forbids
|
|
// JSON inside the engine; the engine does not link this target. See
|
|
// docs/adr/0009-generated-protocol-library.md.
|
|
namespace velox::proto {
|
|
|
|
inline constexpr std::string_view kProtocolVersion = "1.2.0";
|
|
|
|
/// Why a payload could not be turned into a typed value. `path` is a JSON Pointer
|
|
/// into the offending document, so a conformance failure names the exact field.
|
|
struct ParseError {
|
|
std::string path;
|
|
std::string message;
|
|
};
|
|
|
|
/// Every parse in this file returns one of these. Nothing here throws.
|
|
template <class T>
|
|
using Result = std::expected<T, ParseError>;
|
|
|
|
/// Which listener a request arrived on. Decides whether a privileged method is
|
|
/// allowed: see `is_allowed_on`.
|
|
enum class Transport { Uds, Ws };
|
|
|
|
/// Every error code the daemon may return. Adding one is a minor bump; changing the meaning of
|
|
/// one is a major bump.
|
|
enum class ErrorCode : std::int32_t {
|
|
/// Malformed JSON on the wire.
|
|
ParseError = -32700,
|
|
/// Not a valid JSON-RPC 2.0 request object.
|
|
InvalidRequest = -32600,
|
|
/// Unknown method name.
|
|
MethodNotFound = -32601,
|
|
/// Params failed schema validation.
|
|
InvalidParams = -32602,
|
|
/// Unhandled daemon-side failure.
|
|
InternalError = -32603,
|
|
/// Protocol major version mismatch. GUI renders this as 'Velox needs updating'.
|
|
VersionMismatch = -32001,
|
|
/// Missing or invalid token on the WebSocket transport.
|
|
NotPaired = -32002,
|
|
/// Method is privileged and was called over a transport that may not use it.
|
|
TransportForbidden = -32003,
|
|
/// No task with that id.
|
|
TaskNotFound = -32010,
|
|
/// Destination is outside the allowed roots, or is not writable. data.path is set.
|
|
InvalidPath = -32011,
|
|
/// Not enough free space to preallocate.
|
|
DiskFull = -32012,
|
|
/// Could not probe the URL. data.httpStatus is set when there was an HTTP response.
|
|
ProbeFailed = -32013,
|
|
/// Pairing brute-force lockout. data.retryAfterSec is set.
|
|
RateLimited = -32014,
|
|
};
|
|
std::string_view to_string(ErrorCode v) noexcept;
|
|
std::optional<ErrorCode> errorcode_from_int(std::int32_t v) noexcept;
|
|
|
|
/// Lifecycle of one download. The daemon is the only writer; clients render it and nothing
|
|
/// more. Terminal states are complete, failed and cancelled.
|
|
enum class TaskState {
|
|
New, // "new"
|
|
Probing, // "probing"
|
|
Queued, // "queued"
|
|
Connecting, // "connecting"
|
|
Downloading, // "downloading"
|
|
Paused, // "paused"
|
|
RetryWait, // "retry_wait"
|
|
Assembling, // "assembling"
|
|
Verifying, // "verifying"
|
|
Complete, // "complete"
|
|
Failed, // "failed"
|
|
Cancelled, // "cancelled"
|
|
};
|
|
std::string_view to_string(TaskState v) noexcept;
|
|
Result<TaskState> parse_TaskState(std::string_view s);
|
|
|
|
/// The modifier key a user holds to make one click bypass capture and let Firefox download
|
|
/// normally. Shared by Settings and CaptureRules so the daemon's setting and the extension's
|
|
/// mirror of it are literally the same type.
|
|
enum class BypassModifier {
|
|
Alt, // "alt"
|
|
Ctrl, // "ctrl"
|
|
Shift, // "shift"
|
|
None, // "none"
|
|
};
|
|
std::string_view to_string(BypassModifier v) noexcept;
|
|
Result<BypassModifier> parse_BypassModifier(std::string_view s);
|
|
|
|
enum class ChecksumAlgorithm {
|
|
Md5, // "md5"
|
|
Sha1, // "sha1"
|
|
Sha256, // "sha256"
|
|
Sha512, // "sha512"
|
|
};
|
|
std::string_view to_string(ChecksumAlgorithm v) noexcept;
|
|
Result<ChecksumAlgorithm> parse_ChecksumAlgorithm(std::string_view s);
|
|
|
|
/// HTTP request headers, verbatim as the browser would have sent them. Needed for signed-URL
|
|
/// and referrer-gated CDNs.
|
|
using Headers = std::map<std::string, std::string>;
|
|
|
|
/// What the daemon does with a task the moment it is added. 'later' is the File Info dialog's
|
|
/// Download Later button and lands the task in paused.
|
|
enum class StartMode {
|
|
Now, // "now"
|
|
Later, // "later"
|
|
Queue, // "queue"
|
|
};
|
|
std::string_view to_string(StartMode v) noexcept;
|
|
Result<StartMode> parse_StartMode(std::string_view s);
|
|
|
|
enum class MediaVariantContainer {
|
|
Ts, // "ts"
|
|
Mp4, // "mp4"
|
|
Webm, // "webm"
|
|
Mkv, // "mkv"
|
|
};
|
|
std::string_view to_string(MediaVariantContainer v) noexcept;
|
|
Result<MediaVariantContainer> parse_MediaVariantContainer(std::string_view s);
|
|
|
|
enum class MediaVariantKind {
|
|
Video, // "video"
|
|
Audio, // "audio"
|
|
Muxed, // "muxed"
|
|
Subtitle, // "subtitle"
|
|
};
|
|
std::string_view to_string(MediaVariantKind v) noexcept;
|
|
Result<MediaVariantKind> parse_MediaVariantKind(std::string_view s);
|
|
|
|
/// shutdown goes through org.freedesktop.login1 and must be confirmed by the user.
|
|
enum class QueueOnComplete {
|
|
Nothing, // "nothing"
|
|
Exit, // "exit"
|
|
Shutdown, // "shutdown"
|
|
Hangup, // "hangup"
|
|
};
|
|
std::string_view to_string(QueueOnComplete v) noexcept;
|
|
Result<QueueOnComplete> parse_QueueOnComplete(std::string_view s);
|
|
|
|
enum class QueueState {
|
|
Running, // "running"
|
|
Stopped, // "stopped"
|
|
};
|
|
std::string_view to_string(QueueState v) noexcept;
|
|
Result<QueueState> parse_QueueState(std::string_view s);
|
|
|
|
enum class ScheduleMode {
|
|
Once, // "once"
|
|
Periodic, // "periodic"
|
|
};
|
|
std::string_view to_string(ScheduleMode v) noexcept;
|
|
Result<ScheduleMode> parse_ScheduleMode(std::string_view s);
|
|
|
|
/// Lets a rule veto capture for a host without touching the exclusion list.
|
|
enum class RuleActionCapture {
|
|
Take, // "take"
|
|
Ignore, // "ignore"
|
|
};
|
|
std::string_view to_string(RuleActionCapture v) noexcept;
|
|
Result<RuleActionCapture> parse_RuleActionCapture(std::string_view s);
|
|
|
|
/// 'downloading' is spelled as in TaskState, not 'receiving'. 'pending' is a range that has
|
|
/// been planned but not yet dialled.
|
|
enum class SegmentState {
|
|
Pending, // "pending"
|
|
Connecting, // "connecting"
|
|
Downloading, // "downloading"
|
|
Stalled, // "stalled"
|
|
Complete, // "complete"
|
|
Failed, // "failed"
|
|
};
|
|
std::string_view to_string(SegmentState v) noexcept;
|
|
Result<SegmentState> parse_SegmentState(std::string_view s);
|
|
|
|
/// Every settings key that exists. The Options dialog maps 1:1 onto this list and the GUI must
|
|
/// not invent a key that is not here. Kept in lockstep with Settings.schema.json by a
|
|
/// conformance check.
|
|
enum class SettingKey {
|
|
GeneralLaunchOnLogin, // "general.launchOnLogin"
|
|
GeneralMinimizeToTray, // "general.minimizeToTray"
|
|
GeneralShowDropTarget, // "general.showDropTarget"
|
|
GeneralConfirmOnExit, // "general.confirmOnExit"
|
|
GeneralLanguage, // "general.language"
|
|
GeneralCheckForUpdates, // "general.checkForUpdates"
|
|
CaptureEnabled, // "capture.enabled"
|
|
CaptureMonitoredExtensions, // "capture.monitoredExtensions"
|
|
CaptureMonitoredMimeTypes, // "capture.monitoredMimeTypes"
|
|
CaptureMinSizeBytes, // "capture.minSizeBytes"
|
|
CaptureExcludedHosts, // "capture.excludedHosts"
|
|
CaptureBypassModifier, // "capture.bypassModifier"
|
|
CaptureAutoStartTypes, // "capture.autoStartTypes"
|
|
SaveToDefaultDir, // "saveTo.defaultDir"
|
|
SaveToTempDir, // "saveTo.tempDir"
|
|
SaveToAllowedRoots, // "saveTo.allowedRoots"
|
|
SaveToFileExistsPolicy, // "saveTo.fileExistsPolicy"
|
|
SaveToCreateSubfolderPerSite, // "saveTo.createSubfolderPerSite"
|
|
ConnectionPreset, // "connection.preset"
|
|
ConnectionMaxSegmentsPerDownload, // "connection.maxSegmentsPerDownload"
|
|
ConnectionBufferBytes, // "connection.bufferBytes"
|
|
ConnectionMaxTotalBufferBytes, // "connection.maxTotalBufferBytes"
|
|
ConnectionMaxActiveSegments, // "connection.maxActiveSegments"
|
|
ConnectionMaxConcurrentDownloads, // "connection.maxConcurrentDownloads"
|
|
ConnectionTimeoutSec, // "connection.timeoutSec"
|
|
ConnectionMaxRetries, // "connection.maxRetries"
|
|
ConnectionRetryBackoffSec, // "connection.retryBackoffSec"
|
|
DownloadsSpeedLimitBps, // "downloads.speedLimitBps"
|
|
DownloadsSpeedLimitEnabled, // "downloads.speedLimitEnabled"
|
|
DownloadsVirusScanCommand, // "downloads.virusScanCommand"
|
|
DownloadsPostDownloadCommand, // "downloads.postDownloadCommand"
|
|
DownloadsDuplicatePolicy, // "downloads.duplicatePolicy"
|
|
DownloadsVerifyChecksums, // "downloads.verifyChecksums"
|
|
ProxyMode, // "proxy.mode"
|
|
ProxyHost, // "proxy.host"
|
|
ProxyPort, // "proxy.port"
|
|
ProxyUsername, // "proxy.username"
|
|
ProxyBypassHosts, // "proxy.bypassHosts"
|
|
ProxyPacUrl, // "proxy.pacUrl"
|
|
SoundsEnabled, // "sounds.enabled"
|
|
SoundsOnComplete, // "sounds.onComplete"
|
|
SoundsOnQueueComplete, // "sounds.onQueueComplete"
|
|
SoundsOnError, // "sounds.onError"
|
|
};
|
|
std::string_view to_string(SettingKey v) noexcept;
|
|
Result<SettingKey> parse_SettingKey(std::string_view s);
|
|
|
|
enum class SettingsConnectionPreset {
|
|
Auto, // "auto"
|
|
Lan, // "lan"
|
|
Broadband, // "broadband"
|
|
Slow, // "slow"
|
|
};
|
|
std::string_view to_string(SettingsConnectionPreset v) noexcept;
|
|
Result<SettingsConnectionPreset> parse_SettingsConnectionPreset(std::string_view s);
|
|
|
|
enum class SettingsDownloadsDuplicatePolicy {
|
|
Ask, // "ask"
|
|
Skip, // "skip"
|
|
Rename, // "rename"
|
|
Redownload, // "redownload"
|
|
};
|
|
std::string_view to_string(SettingsDownloadsDuplicatePolicy v) noexcept;
|
|
Result<SettingsDownloadsDuplicatePolicy> parse_SettingsDownloadsDuplicatePolicy(std::string_view s);
|
|
|
|
enum class SettingsProxyMode {
|
|
System, // "system"
|
|
None, // "none"
|
|
Http, // "http"
|
|
Https, // "https"
|
|
Socks5, // "socks5"
|
|
Pac, // "pac"
|
|
};
|
|
std::string_view to_string(SettingsProxyMode v) noexcept;
|
|
Result<SettingsProxyMode> parse_SettingsProxyMode(std::string_view s);
|
|
|
|
enum class SettingsSaveToFileExistsPolicy {
|
|
Ask, // "ask"
|
|
Rename, // "rename"
|
|
Overwrite, // "overwrite"
|
|
Resume, // "resume"
|
|
};
|
|
std::string_view to_string(SettingsSaveToFileExistsPolicy v) noexcept;
|
|
Result<SettingsSaveToFileExistsPolicy> parse_SettingsSaveToFileExistsPolicy(std::string_view s);
|
|
|
|
/// Why a download failed. This is the WIRE failure taxonomy and it is deliberately NOT the
|
|
/// JSON-RPC ErrorCode space: ErrorCode says why a *call* failed, TaskErrorCode says why a
|
|
/// *download* failed. A task can fail while every RPC involved succeeded. The values mirror
|
|
/// vdm::Error in core/include/vdm/util/error.hpp one-for-one, by name, so DAEMON's projection
|
|
/// from the engine taxonomy onto the wire is lossless and the GUI can tell 'the file on the
|
|
/// server changed' from 'the checksum did not match'. CORE's 'ok' has no wire spelling: a
|
|
/// TaskError only exists when there is a failure. Adding a value here is a minor bump; renaming
|
|
/// or removing one is major, and would desynchronise the engine.
|
|
enum class TaskErrorCode {
|
|
Canceled, // "canceled"
|
|
ResolveFailed, // "resolve_failed"
|
|
ConnectFailed, // "connect_failed"
|
|
TlsFailed, // "tls_failed"
|
|
ConnectionReset, // "connection_reset"
|
|
Timeout, // "timeout"
|
|
TooManyRedirects, // "too_many_redirects"
|
|
HttpClientError, // "http_client_error"
|
|
HttpServerError, // "http_server_error"
|
|
AuthRequired, // "auth_required"
|
|
Forbidden, // "forbidden"
|
|
NotFound, // "not_found"
|
|
RangeNotSatisfiable, // "range_not_satisfiable"
|
|
Gone, // "gone"
|
|
ServerFileChanged, // "server_file_changed"
|
|
ContentLengthMismatch, // "content_length_mismatch"
|
|
ChecksumMismatch, // "checksum_mismatch"
|
|
DiskFull, // "disk_full"
|
|
IoError, // "io_error"
|
|
PathRejected, // "path_rejected"
|
|
PermissionDenied, // "permission_denied"
|
|
MetaCorrupt, // "meta_corrupt"
|
|
MetaVersionUnsupported, // "meta_version_unsupported"
|
|
ProbeFailed, // "probe_failed"
|
|
UnsupportedUrlScheme, // "unsupported_url_scheme"
|
|
MaxRetriesExhausted, // "max_retries_exhausted"
|
|
Internal, // "internal"
|
|
};
|
|
std::string_view to_string(TaskErrorCode v) noexcept;
|
|
Result<TaskErrorCode> parse_TaskErrorCode(std::string_view s);
|
|
|
|
enum class TaskSortDirection {
|
|
Asc, // "asc"
|
|
Desc, // "desc"
|
|
};
|
|
std::string_view to_string(TaskSortDirection v) noexcept;
|
|
Result<TaskSortDirection> parse_TaskSortDirection(std::string_view s);
|
|
|
|
enum class TaskSortField {
|
|
Filename, // "filename"
|
|
SizeBytes, // "sizeBytes"
|
|
State, // "state"
|
|
EtaSeconds, // "etaSeconds"
|
|
SpeedBps, // "speedBps"
|
|
LastTryAt, // "lastTryAt"
|
|
CreatedAt, // "createdAt"
|
|
QueuePosition, // "queuePosition"
|
|
Description, // "description"
|
|
};
|
|
std::string_view to_string(TaskSortField v) noexcept;
|
|
Result<TaskSortField> parse_TaskSortField(std::string_view s);
|
|
|
|
enum class CaptureOfferParamsMethod {
|
|
GET, // "GET"
|
|
POST, // "POST"
|
|
};
|
|
std::string_view to_string(CaptureOfferParamsMethod v) noexcept;
|
|
Result<CaptureOfferParamsMethod> parse_CaptureOfferParamsMethod(std::string_view s);
|
|
|
|
enum class CaptureOfferResultAction {
|
|
Take, // "take"
|
|
Ignore, // "ignore"
|
|
};
|
|
std::string_view to_string(CaptureOfferResultAction v) noexcept;
|
|
Result<CaptureOfferResultAction> parse_CaptureOfferResultAction(std::string_view s);
|
|
|
|
/// Why the offer was declined. Set when action is 'ignore'; the extension logs it in the
|
|
/// popup's diagnostics.
|
|
enum class CaptureOfferResultReason {
|
|
ExcludedHost, // "excluded_host"
|
|
TypeNotMonitored, // "type_not_monitored"
|
|
BelowMinSize, // "below_min_size"
|
|
Duplicate, // "duplicate"
|
|
CaptureDisabled, // "capture_disabled"
|
|
UserDeclined, // "user_declined"
|
|
RuleIgnore, // "rule_ignore"
|
|
};
|
|
std::string_view to_string(CaptureOfferResultReason v) noexcept;
|
|
Result<CaptureOfferResultReason> parse_CaptureOfferResultReason(std::string_view s);
|
|
|
|
enum class GrabberStatusResultState {
|
|
Crawling, // "crawling"
|
|
Done, // "done"
|
|
Failed, // "failed"
|
|
Cancelled, // "cancelled"
|
|
};
|
|
std::string_view to_string(GrabberStatusResultState v) noexcept;
|
|
Result<GrabberStatusResultState> parse_GrabberStatusResultState(std::string_view s);
|
|
|
|
enum class MediaListVariantsResultManifestType {
|
|
Hls, // "hls"
|
|
Dash, // "dash"
|
|
};
|
|
std::string_view to_string(MediaListVariantsResultManifestType v) noexcept;
|
|
Result<MediaListVariantsResultManifestType> parse_MediaListVariantsResultManifestType(std::string_view s);
|
|
|
|
enum class SessionHelloParamsClientType {
|
|
Gui, // "gui"
|
|
Cli, // "cli"
|
|
Extension, // "extension"
|
|
Nmhost, // "nmhost"
|
|
Test, // "test"
|
|
};
|
|
std::string_view to_string(SessionHelloParamsClientType v) noexcept;
|
|
Result<SessionHelloParamsClientType> parse_SessionHelloParamsClientType(std::string_view s);
|
|
|
|
/// How the daemon sees this connection. Lets a client know up front which privileged methods
|
|
/// will be refused.
|
|
enum class SessionHelloResultTransport {
|
|
Uds, // "uds"
|
|
Ws, // "ws"
|
|
};
|
|
std::string_view to_string(SessionHelloResultTransport v) noexcept;
|
|
Result<SessionHelloResultTransport> parse_SessionHelloResultTransport(std::string_view s);
|
|
|
|
enum class SessionSubscribeParamsEventsItem {
|
|
EventTaskAdded, // "event.task.added"
|
|
EventTaskRemoved, // "event.task.removed"
|
|
EventTaskState, // "event.task.state"
|
|
EventTaskProgress, // "event.task.progress"
|
|
EventSpeedGlobal, // "event.speed.global"
|
|
EventAuthRequired, // "event.auth.required"
|
|
EventNotify, // "event.notify"
|
|
EventSettingsChanged, // "event.settings.changed"
|
|
EventGrabberProgress, // "event.grabber.progress"
|
|
};
|
|
std::string_view to_string(SessionSubscribeParamsEventsItem v) noexcept;
|
|
Result<SessionSubscribeParamsEventsItem> parse_SessionSubscribeParamsEventsItem(std::string_view s);
|
|
|
|
enum class AuthRequiredEventScheme {
|
|
Basic, // "basic"
|
|
Digest, // "digest"
|
|
Ntlm, // "ntlm"
|
|
Negotiate, // "negotiate"
|
|
Proxy, // "proxy"
|
|
};
|
|
std::string_view to_string(AuthRequiredEventScheme v) noexcept;
|
|
Result<AuthRequiredEventScheme> parse_AuthRequiredEventScheme(std::string_view s);
|
|
|
|
enum class NotifyEventLevel {
|
|
Info, // "info"
|
|
Success, // "success"
|
|
Warning, // "warning"
|
|
Error, // "error"
|
|
};
|
|
std::string_view to_string(NotifyEventLevel v) noexcept;
|
|
Result<NotifyEventLevel> parse_NotifyEventLevel(std::string_view s);
|
|
|
|
enum class NotifyEventSound {
|
|
Complete, // "complete"
|
|
QueueComplete, // "queueComplete"
|
|
Error, // "error"
|
|
};
|
|
std::string_view to_string(NotifyEventSound v) noexcept;
|
|
Result<NotifyEventSound> parse_NotifyEventSound(std::string_view s);
|
|
|
|
struct BulkTaskResultFailedItem {
|
|
std::string taskId{};
|
|
ErrorCode code{};
|
|
std::string message{};
|
|
};
|
|
|
|
struct BulkTaskResultUpdatedItem {
|
|
std::string taskId{};
|
|
TaskState state{};
|
|
bool changed{};
|
|
};
|
|
|
|
/// Result of a state transition applied to many tasks. A bulk call never fails as a whole
|
|
/// because one id was bad: the ids that moved come back in 'updated' and the rest are explained
|
|
/// in 'failed'. This is what lets the GUI's toolbar act on a multi-selection without
|
|
/// pre-validating it.
|
|
struct BulkTaskResult {
|
|
/// One entry per task that actually changed. A task already in the target state is reported
|
|
/// here with changed false rather than as a failure.
|
|
std::vector<BulkTaskResultUpdatedItem> updated{};
|
|
std::vector<BulkTaskResultFailedItem> failed{};
|
|
};
|
|
|
|
/// The daemon's capture policy, mirrored into the extension so the two can never disagree about
|
|
/// what should be intercepted. The extension refreshes this on connect and on
|
|
/// event.settings.changed.
|
|
struct CaptureRules {
|
|
bool enabled{};
|
|
std::vector<std::string> monitoredExtensions{};
|
|
std::vector<std::string> monitoredMimeTypes{};
|
|
std::int64_t minSizeBytes{};
|
|
std::vector<std::string> excludedHosts{};
|
|
std::optional<BypassModifier> bypassModifier{};
|
|
/// Bumped on every change. The extension re-fetches when it sees a higher value.
|
|
std::int64_t rulesVersion{};
|
|
};
|
|
|
|
/// A destination folder plus the extensions that route to it. The extension mirrors the
|
|
/// extension lists so its capture decision agrees with the daemon's.
|
|
struct Category {
|
|
std::string categoryId{};
|
|
std::string name{};
|
|
std::string saveDir{};
|
|
/// Without the leading dot, lowercase.
|
|
std::vector<std::string> extensions{};
|
|
std::optional<std::vector<std::string>> mimeTypes{};
|
|
/// Compressed, Documents, Music, Programs, Video. Cannot be removed; can be renamed and
|
|
/// re-pointed.
|
|
bool builtin{};
|
|
std::optional<std::int64_t> sortOrder{};
|
|
};
|
|
|
|
/// Optional integrity check, verified during the verifying state. A mismatch moves the task to
|
|
/// failed and never overwrites a good file.
|
|
struct Checksum {
|
|
ChecksumAlgorithm algorithm{};
|
|
std::string value{};
|
|
};
|
|
|
|
/// One cookie the daemon replays so an authenticated download works outside the browser.
|
|
struct Cookie {
|
|
std::string name{};
|
|
std::string value{};
|
|
std::optional<std::string> domain{};
|
|
std::optional<std::string> path{};
|
|
std::optional<bool> secure{};
|
|
std::optional<bool> httpOnly{};
|
|
};
|
|
|
|
/// Everything needed to create one task. Shared by download.add and each item of
|
|
/// download.addBatch, so the two can never drift apart.
|
|
struct DownloadSpec {
|
|
std::string url{};
|
|
std::optional<Headers> headers{};
|
|
std::optional<std::vector<Cookie>> cookies{};
|
|
std::optional<std::string> referrer{};
|
|
std::optional<std::string> userAgent{};
|
|
/// Overrides the name derived from Content-Disposition or the URL.
|
|
std::optional<std::string> filename{};
|
|
/// Canonicalized and checked against the allowed roots before any write. -32011 if it fails.
|
|
std::optional<std::string> saveDir{};
|
|
/// null means the rules engine picks one.
|
|
std::optional<std::string> categoryId{};
|
|
/// Required when startMode is 'queue'.
|
|
std::optional<std::string> queueId{};
|
|
/// The REQUESTED connection count. An upper bound, not a promise: the daemon lowers it to the
|
|
/// per-host cap, and to 1 when the source turns out not to be resumable. What is actually in
|
|
/// use comes back as TaskSummary.segments. null means use connection.maxSegmentsPerDownload.
|
|
std::optional<std::int64_t> segments{};
|
|
/// Requested write buffer per segment, in bytes. null means use connection.bufferBytes. Default
|
|
/// 1 MiB; range 64 KiB - 16 MiB. Silently reduced to fit connection.maxTotalBufferBytes across
|
|
/// all live segments; the effective value is reported back as TaskDetail.effectiveBufferBytes.
|
|
std::optional<std::int64_t> bufferBytes{};
|
|
std::optional<StartMode> startMode{};
|
|
std::optional<std::string> description{};
|
|
std::optional<Checksum> checksum{};
|
|
};
|
|
|
|
/// One candidate found by the Site Grabber crawl. Nothing is downloaded until grabber.harvest
|
|
/// selects it.
|
|
struct GrabberFile {
|
|
std::string fileId{};
|
|
std::string url{};
|
|
std::optional<std::string> filename{};
|
|
/// From a HEAD, when the server answered one.
|
|
std::optional<std::int64_t> sizeBytes{};
|
|
std::optional<std::string> contentType{};
|
|
std::int64_t depth{};
|
|
/// The page this link was found on.
|
|
std::optional<std::string> foundOn{};
|
|
};
|
|
|
|
/// Global token-bucket speed limit. Applies across every active task, not per task.
|
|
struct Limiter {
|
|
bool enabled{};
|
|
/// Bytes per second. 0 with enabled true means 'stop everything', which the GUI must not offer.
|
|
std::int64_t globalBps{};
|
|
/// Re-tune already-running transfers instead of waiting for the next task.
|
|
std::optional<bool> applyToRunning{};
|
|
};
|
|
|
|
/// One quality rendition from an HLS or DASH manifest. The daemon parses the manifest; the
|
|
/// extension only renders this list. DRM-protected variants are reported with drm true and must
|
|
/// be shown greyed out rather than failing later.
|
|
struct MediaVariant {
|
|
std::string variantId{};
|
|
MediaVariantKind kind{};
|
|
std::optional<std::string> resolution{};
|
|
std::optional<std::int64_t> bitrateBps{};
|
|
std::optional<std::string> codec{};
|
|
std::optional<MediaVariantContainer> container{};
|
|
std::optional<double> frameRate{};
|
|
std::optional<std::string> language{};
|
|
/// bitrate x duration. Never exact — the GUI must label it as approximate.
|
|
std::optional<std::int64_t> sizeEstimate{};
|
|
/// Widevine/EME detected. Explicitly out of scope; refuse rather than fail mysteriously.
|
|
bool drm{};
|
|
};
|
|
|
|
/// When a queue may run. Times are local wall-clock in HH:MM; the daemon re-evaluates them on a
|
|
/// DST change rather than caching absolute instants.
|
|
struct Schedule {
|
|
bool enabled{};
|
|
ScheduleMode mode{};
|
|
std::optional<std::string> startTime{};
|
|
/// null means run until the queue drains.
|
|
std::optional<std::string> stopTime{};
|
|
/// 0 = Sunday. Ignored when mode is 'once'.
|
|
std::optional<std::vector<std::int64_t>> daysOfWeek{};
|
|
/// Set only when mode is 'once'.
|
|
std::optional<std::string> onceDate{};
|
|
};
|
|
|
|
/// An ordered run of tasks with its own concurrency cap and optional schedule.
|
|
struct Queue {
|
|
std::string queueId{};
|
|
std::string name{};
|
|
QueueState state{};
|
|
std::int64_t maxConcurrent{};
|
|
/// In run order. queue.reorder rewrites this.
|
|
std::optional<std::vector<std::string>> taskIds{};
|
|
std::optional<Schedule> schedule{};
|
|
/// shutdown goes through org.freedesktop.login1 and must be confirmed by the user.
|
|
std::optional<QueueOnComplete> onComplete{};
|
|
};
|
|
|
|
/// What to do with a matching download.
|
|
struct RuleAction {
|
|
std::optional<std::string> categoryId{};
|
|
std::optional<std::string> saveDir{};
|
|
std::optional<std::string> queueId{};
|
|
std::optional<std::int64_t> segments{};
|
|
std::optional<StartMode> startMode{};
|
|
/// Lets a rule veto capture for a host without touching the exclusion list.
|
|
std::optional<RuleActionCapture> capture{};
|
|
};
|
|
|
|
/// All present clauses must match. An absent clause is not a constraint.
|
|
struct RuleMatch {
|
|
std::optional<std::vector<std::string>> extensions{};
|
|
std::optional<std::vector<std::string>> mimeTypes{};
|
|
/// Glob against the effective URL's host, e.g. *.example.com
|
|
std::optional<std::string> hostPattern{};
|
|
/// Glob against the whole effective URL.
|
|
std::optional<std::string> urlPattern{};
|
|
std::optional<std::int64_t> minSizeBytes{};
|
|
std::optional<std::int64_t> maxSizeBytes{};
|
|
};
|
|
|
|
/// One row of the rules engine: match on extension, MIME, host or size, then route. First match
|
|
/// by priority wins; no rule matching means the default category.
|
|
struct Rule {
|
|
std::string ruleId{};
|
|
std::optional<std::string> name{};
|
|
bool enabled{};
|
|
/// Lower runs first.
|
|
std::int64_t priority{};
|
|
/// All present clauses must match. An absent clause is not a constraint.
|
|
RuleMatch match{};
|
|
/// What to do with a matching download.
|
|
RuleAction action{};
|
|
};
|
|
|
|
/// One byte range being fetched by one connection. This is the deepest the contract ever
|
|
/// exposes the engine: the GUI draws a bar per segment and is never told what a segment steal
|
|
/// is. RANGE CONVENTION — READ THIS BEFORE IMPLEMENTING. The range is CLOSED and INCLUSIVE on
|
|
/// both ends: [startByte, endByte]. The segment covers endByte - startByte + 1 bytes, and
|
|
/// endByte is the index of the LAST byte in the range, not one past it. This deliberately
|
|
/// matches the HTTP Range header the engine actually sends ('Range:
|
|
/// bytes=<startByte>-<endByte>' is a byte-for-byte copy of these two fields, and RFC 9110
|
|
/// ranges are inclusive), so no arithmetic happens between the wire and the socket and there is
|
|
/// nowhere for an off-by-one to hide. CORE asked for half-open [start, end); PROTO chose
|
|
/// inclusive for that reason and this note exists so nobody discovers the difference at
|
|
/// integration. A segment always covers at least one byte: endByte >= startByte always holds.
|
|
/// An empty range is not representable and is not needed — a zero-length download carries an
|
|
/// empty segmentDetail array, and a segment that has donated its remainder to a steal keeps the
|
|
/// bytes it already wrote.
|
|
struct Segment {
|
|
/// Position in TaskDetail.segmentDetail. Spelled 'index' here and in event.task.progress; there
|
|
/// is no 'i' spelling anywhere in the contract.
|
|
std::int64_t index{};
|
|
/// Absolute offset of the first byte of the range. Inclusive.
|
|
std::int64_t startByte{};
|
|
/// Absolute offset of the LAST byte of the range. Inclusive — this is not one-past-the-end.
|
|
/// Always >= startByte.
|
|
std::int64_t endByte{};
|
|
/// Bytes written for this range so far, out of endByte - startByte + 1.
|
|
std::int64_t downloadedBytes{};
|
|
std::optional<std::int64_t> speedBps{};
|
|
/// 'downloading' is spelled as in TaskState, not 'receiving'. 'pending' is a range that has
|
|
/// been planned but not yet dialled.
|
|
SegmentState state{};
|
|
/// The status this segment's request got. 206 on a healthy ranged fetch.
|
|
std::optional<std::int64_t> httpStatus{};
|
|
};
|
|
|
|
/// A sparse bag of settings. Every property is optional because settings.get returns only the
|
|
/// keys that were asked for and settings.set carries only the keys that changed. Property names
|
|
/// must match SettingKey exactly. NOTE: no password lives here — proxy and site-login
|
|
/// credentials go to the Secret Service, never to SQLite and never over the wire.
|
|
struct Settings {
|
|
std::optional<bool> general_launchOnLogin{};
|
|
std::optional<bool> general_minimizeToTray{};
|
|
std::optional<bool> general_showDropTarget{};
|
|
std::optional<bool> general_confirmOnExit{};
|
|
/// BCP 47, or 'system'.
|
|
std::optional<std::string> general_language{};
|
|
std::optional<bool> general_checkForUpdates{};
|
|
std::optional<bool> capture_enabled{};
|
|
std::optional<std::vector<std::string>> capture_monitoredExtensions{};
|
|
std::optional<std::vector<std::string>> capture_monitoredMimeTypes{};
|
|
std::optional<std::int64_t> capture_minSizeBytes{};
|
|
std::optional<std::vector<std::string>> capture_excludedHosts{};
|
|
std::optional<BypassModifier> capture_bypassModifier{};
|
|
/// Extensions that skip the File Info dialog and start immediately.
|
|
std::optional<std::vector<std::string>> capture_autoStartTypes{};
|
|
std::optional<std::string> saveTo_defaultDir{};
|
|
std::optional<std::string> saveTo_tempDir{};
|
|
/// Every write target is canonicalized and must resolve inside one of these. Read-only over the
|
|
/// WebSocket transport.
|
|
std::optional<std::vector<std::string>> saveTo_allowedRoots{};
|
|
std::optional<SettingsSaveToFileExistsPolicy> saveTo_fileExistsPolicy{};
|
|
std::optional<bool> saveTo_createSubfolderPerSite{};
|
|
std::optional<SettingsConnectionPreset> connection_preset{};
|
|
std::optional<std::int64_t> connection_maxSegmentsPerDownload{};
|
|
/// Default per-segment write buffer, in bytes, when a task does not request its own. Default 1
|
|
/// MiB (1048576); range 64 KiB - 16 MiB. This is the single biggest throughput knob and is
|
|
/// exposed in Options -> Downloads -> 'Write buffer per connection'.
|
|
std::optional<std::int64_t> connection_bufferBytes{};
|
|
std::optional<std::int64_t> connection_maxConcurrentDownloads{};
|
|
std::optional<std::int64_t> connection_timeoutSec{};
|
|
std::optional<std::int64_t> connection_maxRetries{};
|
|
std::optional<std::int64_t> connection_retryBackoffSec{};
|
|
std::optional<std::int64_t> downloads_speedLimitBps{};
|
|
std::optional<bool> downloads_speedLimitEnabled{};
|
|
std::optional<std::string> downloads_virusScanCommand{};
|
|
std::optional<std::string> downloads_postDownloadCommand{};
|
|
std::optional<SettingsDownloadsDuplicatePolicy> downloads_duplicatePolicy{};
|
|
std::optional<bool> downloads_verifyChecksums{};
|
|
std::optional<SettingsProxyMode> proxy_mode{};
|
|
std::optional<std::string> proxy_host{};
|
|
std::optional<std::int64_t> proxy_port{};
|
|
std::optional<std::string> proxy_username{};
|
|
std::optional<std::vector<std::string>> proxy_bypassHosts{};
|
|
std::optional<std::string> proxy_pacUrl{};
|
|
std::optional<bool> sounds_enabled{};
|
|
std::optional<std::string> sounds_onComplete{};
|
|
std::optional<std::string> sounds_onQueueComplete{};
|
|
std::optional<std::string> sounds_onError{};
|
|
/// Global cap on write-buffer memory across every live segment, in bytes. Default 128 MiB
|
|
/// (134217728). Every live segment's buffer is reduced to fit maxTotalBufferBytes / (live
|
|
/// segment count, capped at maxActiveSegments); the reduced value is reported per task as
|
|
/// TaskDetail.effectiveBufferBytes. Exists so a burst of large downloads with a large
|
|
/// per-segment buffer cannot exhaust memory.
|
|
std::optional<std::int64_t> connection_maxTotalBufferBytes{};
|
|
/// Global ceiling on segments actually transferring at once, across every task. Default 32.
|
|
/// This is the real bound behind '20 active downloads': the rest of each download's segments
|
|
/// queue rather than all dialling out simultaneously. DAEMON's scheduler needs this value to
|
|
/// decide what to admit; CORE enforces it.
|
|
std::optional<std::int64_t> connection_maxActiveSegments{};
|
|
};
|
|
|
|
/// Why a task is in the failed or retry_wait state. Distinct from the JSON-RPC Error, which
|
|
/// describes a failed call rather than a failed download — the two live in different code
|
|
/// spaces on purpose, and `code` here is a TaskErrorCode string, never a JSON-RPC integer.
|
|
struct TaskError {
|
|
TaskErrorCode code{};
|
|
/// Human-readable, safe to show a user. Never carries a credential, a token or a full local
|
|
/// path outside the download roots.
|
|
std::string message{};
|
|
/// Set for the codes listed in TaskErrorCode's x-carriesHttpStatus, and null otherwise.
|
|
std::optional<std::int64_t> httpStatus{};
|
|
/// Whether the scheduler will pick this task up again on its own. Carried per-occurrence rather
|
|
/// than derived from the code, because 'probe_failed' is retryable or not depending on what the
|
|
/// probe hit.
|
|
bool retryable{};
|
|
/// The underlying failure, for codes that wrap one. max_retries_exhausted sets it to whatever
|
|
/// the last attempt actually failed with, so a user learns the reason rather than just that
|
|
/// Velox gave up.
|
|
std::optional<TaskErrorCode> cause{};
|
|
/// How many attempts have been made so far.
|
|
std::optional<std::int64_t> attempt{};
|
|
std::optional<std::string> nextRetryAt{};
|
|
};
|
|
|
|
/// One row of the main download list. Everything the GUI table needs, and nothing more.
|
|
/// TaskDetail is the same shape plus the fields only the progress dialog and File Info dialog
|
|
/// need.
|
|
struct TaskSummary {
|
|
std::string taskId{};
|
|
std::string filename{};
|
|
/// Absolute, canonicalized, inside an allowed root.
|
|
std::string saveDir{};
|
|
/// The URL as the user or the extension supplied it.
|
|
std::string url{};
|
|
/// After redirects. null until the first probe succeeds.
|
|
std::optional<std::string> effectiveUrl{};
|
|
/// null when the server did not report a length.
|
|
std::optional<std::int64_t> sizeBytes{};
|
|
std::int64_t downloadedBytes{};
|
|
TaskState state{};
|
|
std::int64_t speedBps{};
|
|
/// null when the size or the speed is unknown.
|
|
std::optional<std::int64_t> etaSeconds{};
|
|
bool resumable{};
|
|
/// The EFFECTIVE connection count in use right now — not the number that was requested. It is
|
|
/// what remains after the per-host connection cap has been applied and after the demotion to 1
|
|
/// for a non-resumable source, so a task the user asked for 16 connections on legitimately
|
|
/// reports 4, or 1. The GUI displays this value and must not assume it equals what download.add
|
|
/// asked for. The requested value lives in DownloadSpec.segments and is not echoed back on this
|
|
/// type. TaskDetail.segmentDetail always has exactly this many entries.
|
|
std::int64_t segments{};
|
|
std::optional<std::string> categoryId{};
|
|
std::optional<std::string> queueId{};
|
|
/// The Q column.
|
|
std::optional<std::int64_t> queuePosition{};
|
|
std::optional<std::string> description{};
|
|
std::string createdAt{};
|
|
std::optional<std::string> lastTryAt{};
|
|
std::optional<std::string> completedAt{};
|
|
std::optional<TaskError> error{};
|
|
};
|
|
|
|
/// Everything TaskSummary carries, plus what only the progress dialog and the File Info dialog
|
|
/// need. Returned by download.get; never sent in a list or an event, because it is expensive to
|
|
/// build.
|
|
struct TaskDetail {
|
|
TaskSummary summary{};
|
|
/// Exactly TaskSummary.segments entries, in index order, covering [0, sizeBytes) with no gaps
|
|
/// and no overlaps. Empty for a zero-length download, and empty before the task has been
|
|
/// segmented.
|
|
std::vector<Segment> segmentDetail{};
|
|
std::optional<Headers> headers{};
|
|
std::optional<std::string> referrer{};
|
|
std::optional<std::string> userAgent{};
|
|
std::optional<std::string> mime{};
|
|
/// The REQUESTED write buffer per segment. See effectiveBufferBytes for what is actually in
|
|
/// use.
|
|
std::optional<std::int64_t> bufferBytes{};
|
|
/// The write buffer actually in use per live segment, right now. May be well below bufferBytes:
|
|
/// the daemon reduces every live segment's buffer to fit connection.maxTotalBufferBytes across
|
|
/// connection.maxActiveSegments concurrently-transferring segments, and reports the reduced
|
|
/// value here so the GUI can show '16 MiB (using 4 MiB)'. null before the task has started its
|
|
/// first segment.
|
|
std::optional<std::int64_t> effectiveBufferBytes{};
|
|
/// Absolute path of the .veloxpart file while the task is unfinished.
|
|
std::optional<std::string> partPath{};
|
|
std::optional<Checksum> checksum{};
|
|
/// null until the verifying state has run.
|
|
std::optional<bool> checksumVerified{};
|
|
std::optional<std::int64_t> averageSpeedBps{};
|
|
std::optional<std::int64_t> retryCount{};
|
|
};
|
|
|
|
/// Which rows download.list returns. This is the category tree and the All/Unfinished/Finished
|
|
/// nodes, expressed on the wire. Absent clauses are not constraints.
|
|
struct TaskFilter {
|
|
std::optional<std::vector<TaskState>> states{};
|
|
std::optional<std::string> categoryId{};
|
|
std::optional<std::string> queueId{};
|
|
/// Case-insensitive substring of filename or url.
|
|
std::optional<std::string> query{};
|
|
std::optional<std::string> addedAfter{};
|
|
std::optional<std::string> addedBefore{};
|
|
};
|
|
|
|
/// Sort order for download.list. The GUI persists the user's choice and sends it on every list
|
|
/// call; the daemon does the sorting so a 100k-row list never has to be materialized
|
|
/// client-side.
|
|
struct TaskSort {
|
|
TaskSortField field{};
|
|
TaskSortDirection direction{};
|
|
};
|
|
|
|
struct CaptureGetRulesParams {
|
|
// No fields: this method takes no parameters.
|
|
};
|
|
|
|
struct CaptureOfferParams {
|
|
std::string url{};
|
|
CaptureOfferParamsMethod method{};
|
|
std::string tabUrl{};
|
|
std::optional<Headers> headers{};
|
|
/// Cookies for the URL, so authenticated downloads work outside the browser.
|
|
std::optional<std::vector<Cookie>> cookies{};
|
|
std::optional<std::string> contentType{};
|
|
std::optional<std::int64_t> contentLength{};
|
|
std::optional<std::string> contentDisposition{};
|
|
/// The extension's best guess; the daemon may override it.
|
|
std::optional<std::string> filename{};
|
|
std::optional<std::string> userAgent{};
|
|
std::optional<std::string> referrer{};
|
|
/// moz-extension://... The daemon verifies this on the WS transport and refuses anything else.
|
|
std::optional<std::string> origin{};
|
|
/// The extension's webRequest id, echoed in logs so a capture decision can be traced back to
|
|
/// one browser request.
|
|
std::optional<std::string> requestId{};
|
|
};
|
|
|
|
struct CaptureOfferResult {
|
|
CaptureOfferResultAction action{};
|
|
/// Set when action is 'take'.
|
|
std::optional<std::string> taskId{};
|
|
/// Why the offer was declined. Set when action is 'ignore'; the extension logs it in the
|
|
/// popup's diagnostics.
|
|
std::optional<CaptureOfferResultReason> reason{};
|
|
};
|
|
|
|
struct CategoryListParams {
|
|
// No fields: this method takes no parameters.
|
|
};
|
|
|
|
struct CategoryListResult {
|
|
std::vector<Category> items{};
|
|
};
|
|
|
|
struct CategoryRemoveParams {
|
|
std::string categoryId{};
|
|
std::optional<std::string> reassignTo{};
|
|
};
|
|
|
|
struct CategoryRemoveResult {
|
|
bool removed{};
|
|
std::vector<std::string> reassignedTaskIds{};
|
|
};
|
|
|
|
struct CategoryUpsertParams {
|
|
Category category{};
|
|
};
|
|
|
|
/// The stored category, with categoryId filled in on create.
|
|
struct CategoryUpsertResult {
|
|
Category category{};
|
|
};
|
|
|
|
struct DownloadAddResult {
|
|
std::string taskId{};
|
|
TaskState state{};
|
|
/// The existing task this URL matched, when downloads.duplicatePolicy resolved to 'skip'.
|
|
/// taskId then names that existing task.
|
|
std::optional<std::string> duplicate{};
|
|
};
|
|
|
|
struct DownloadAddBatchParams {
|
|
std::vector<DownloadSpec> items{};
|
|
/// Applied to any field an item left unset. Its url is ignored.
|
|
std::optional<DownloadSpec> defaults{};
|
|
};
|
|
|
|
struct DownloadAddBatchResultFailedItem {
|
|
std::int64_t index{};
|
|
ErrorCode code{};
|
|
std::string message{};
|
|
};
|
|
|
|
struct DownloadAddBatchResult {
|
|
/// In the same order as the accepted items.
|
|
std::vector<std::string> taskIds{};
|
|
/// One entry per item that could not be added. index refers to params.items.
|
|
std::vector<DownloadAddBatchResultFailedItem> failed{};
|
|
};
|
|
|
|
struct DownloadCancelParams {
|
|
std::vector<std::string> taskIds{};
|
|
};
|
|
|
|
struct DownloadGetParams {
|
|
std::string taskId{};
|
|
};
|
|
|
|
struct DownloadListParams {
|
|
std::optional<TaskFilter> filter{};
|
|
std::optional<TaskSort> sort{};
|
|
std::optional<std::int64_t> offset{};
|
|
/// Defaults to 500. The GUI pages; the extension popup asks for far fewer.
|
|
std::optional<std::int64_t> limit{};
|
|
};
|
|
|
|
struct DownloadListResult {
|
|
/// Rows matching the filter, ignoring offset and limit.
|
|
std::int64_t total{};
|
|
std::vector<TaskSummary> items{};
|
|
};
|
|
|
|
struct DownloadPauseParams {
|
|
std::vector<std::string> taskIds{};
|
|
};
|
|
|
|
struct DownloadProbeParams {
|
|
std::string url{};
|
|
std::optional<Headers> headers{};
|
|
std::optional<std::vector<Cookie>> cookies{};
|
|
std::optional<std::string> referrer{};
|
|
std::optional<std::string> userAgent{};
|
|
};
|
|
|
|
struct DownloadProbeResult {
|
|
/// From Content-Disposition when present, else the URL path, sanitized.
|
|
std::string filename{};
|
|
std::optional<std::int64_t> sizeBytes{};
|
|
std::string mime{};
|
|
/// Accept-Ranges: bytes and a validator (ETag or Last-Modified) are both present.
|
|
bool resumable{};
|
|
std::string effectiveUrl{};
|
|
/// What the rules engine would pick. The dialog preselects it; the user may override.
|
|
std::string suggestedCategoryId{};
|
|
std::optional<std::string> suggestedSaveDir{};
|
|
std::optional<std::string> etag{};
|
|
std::optional<std::string> lastModified{};
|
|
std::optional<bool> acceptRanges{};
|
|
/// Every hop, so the user can see where a shortener actually led.
|
|
std::optional<std::vector<std::string>> redirectChain{};
|
|
/// The probe got a 401/407. The GUI should collect credentials before adding.
|
|
std::optional<bool> requiresAuth{};
|
|
};
|
|
|
|
struct DownloadProvideAuthParams {
|
|
std::string taskId{};
|
|
std::string username{};
|
|
std::string password{};
|
|
/// true persists the credential in the Secret Service, keyed by host and realm, for future
|
|
/// downloads from the same site. false or null uses it for this task's retry only. Never
|
|
/// affects SQLite or the daemon's logs either way.
|
|
std::optional<bool> save{};
|
|
};
|
|
|
|
struct DownloadProvideAuthResult {
|
|
bool ok{};
|
|
};
|
|
|
|
struct DownloadRefreshUrlParams {
|
|
std::string taskId{};
|
|
std::string url{};
|
|
std::optional<Headers> headers{};
|
|
std::optional<std::vector<Cookie>> cookies{};
|
|
};
|
|
|
|
struct DownloadRefreshUrlResult {
|
|
bool ok{};
|
|
bool resumable{};
|
|
/// true when size or validator differ from what was recorded. The GUI must ask before
|
|
/// restarting from zero — never discard bytes without consent.
|
|
bool contentChanged{};
|
|
std::optional<std::int64_t> sizeBytes{};
|
|
std::optional<std::string> effectiveUrl{};
|
|
};
|
|
|
|
struct DownloadRemoveParams {
|
|
std::vector<std::string> taskIds{};
|
|
/// Explicit and required — there is no default for deleting a user's file.
|
|
bool deleteFile{};
|
|
};
|
|
|
|
struct DownloadRemoveResultFailedItem {
|
|
std::string taskId{};
|
|
ErrorCode code{};
|
|
std::string message{};
|
|
};
|
|
|
|
struct DownloadRemoveResult {
|
|
std::vector<std::string> removed{};
|
|
std::vector<DownloadRemoveResultFailedItem> failed{};
|
|
};
|
|
|
|
struct DownloadResumeParams {
|
|
std::vector<std::string> taskIds{};
|
|
};
|
|
|
|
struct DownloadStartParams {
|
|
std::vector<std::string> taskIds{};
|
|
};
|
|
|
|
/// Only the present fields change. An explicit null clears a nullable field.
|
|
struct DownloadUpdateParamsPatch {
|
|
std::optional<std::string> filename{};
|
|
std::optional<std::string> saveDir{};
|
|
std::optional<std::string> categoryId{};
|
|
std::optional<std::string> queueId{};
|
|
std::optional<std::string> description{};
|
|
/// The REQUESTED connection count, subject to the same per-host cap and non-resumable demotion
|
|
/// as DownloadSpec.segments. Takes effect on the next start; a running task is not re-segmented
|
|
/// underneath the user.
|
|
std::optional<std::int64_t> segments{};
|
|
/// The REQUESTED write buffer per segment. Subject to the same maxTotalBufferBytes reduction as
|
|
/// DownloadSpec.bufferBytes; the effective value comes back on the next download.get.
|
|
std::optional<std::int64_t> bufferBytes{};
|
|
std::optional<Checksum> checksum{};
|
|
};
|
|
|
|
struct DownloadUpdateParams {
|
|
std::string taskId{};
|
|
/// Only the present fields change. An explicit null clears a nullable field.
|
|
DownloadUpdateParamsPatch patch{};
|
|
};
|
|
|
|
struct GrabberHarvestParams {
|
|
std::string jobId{};
|
|
/// fileIds from grabber.status.
|
|
std::vector<std::string> select{};
|
|
std::optional<DownloadSpec> defaults{};
|
|
};
|
|
|
|
struct GrabberHarvestResultFailedItem {
|
|
std::string fileId{};
|
|
ErrorCode code{};
|
|
std::string message{};
|
|
};
|
|
|
|
struct GrabberHarvestResult {
|
|
std::vector<std::string> taskIds{};
|
|
std::vector<GrabberHarvestResultFailedItem> failed{};
|
|
};
|
|
|
|
struct GrabberStartParams {
|
|
std::string startUrl{};
|
|
std::int64_t depth{};
|
|
std::optional<std::vector<std::string>> includePatterns{};
|
|
std::optional<std::vector<std::string>> excludePatterns{};
|
|
/// Extensions, without the dot. null means every type.
|
|
std::optional<std::vector<std::string>> fileTypes{};
|
|
std::optional<bool> sameHostOnly{};
|
|
std::optional<std::int64_t> maxFiles{};
|
|
std::optional<Headers> headers{};
|
|
std::optional<std::vector<Cookie>> cookies{};
|
|
};
|
|
|
|
struct GrabberStartResult {
|
|
std::string jobId{};
|
|
};
|
|
|
|
struct GrabberStatusParams {
|
|
std::string jobId{};
|
|
};
|
|
|
|
struct GrabberStatusResult {
|
|
std::string jobId{};
|
|
GrabberStatusResultState state{};
|
|
std::int64_t crawled{};
|
|
std::int64_t found{};
|
|
std::vector<GrabberFile> files{};
|
|
std::optional<std::string> error{};
|
|
};
|
|
|
|
struct LimiterGetParams {
|
|
// No fields: this method takes no parameters.
|
|
};
|
|
|
|
/// spec carries the same destination and queueing fields as download.add; its url is ignored
|
|
/// because the manifest and variant determine the source.
|
|
struct MediaAddVariantParams {
|
|
std::string manifestUrl{};
|
|
std::string variantId{};
|
|
/// For DASH and HLS renditions where audio is a separate track to be muxed in.
|
|
std::optional<std::string> audioVariantId{};
|
|
std::optional<DownloadSpec> spec{};
|
|
};
|
|
|
|
struct MediaAddVariantResult {
|
|
std::string taskId{};
|
|
TaskState state{};
|
|
std::optional<std::int64_t> estimatedBytes{};
|
|
};
|
|
|
|
struct MediaListVariantsParams {
|
|
std::string manifestUrl{};
|
|
std::optional<Headers> headers{};
|
|
std::optional<std::vector<Cookie>> cookies{};
|
|
std::optional<std::string> referrer{};
|
|
};
|
|
|
|
struct MediaListVariantsResult {
|
|
std::vector<MediaVariant> variants{};
|
|
MediaListVariantsResultManifestType manifestType{};
|
|
std::optional<double> durationSec{};
|
|
std::optional<std::string> title{};
|
|
/// The manifest as a whole is DRM-protected. Refuse with a clear message rather than
|
|
/// downloading undecryptable segments.
|
|
bool drmProtected{};
|
|
};
|
|
|
|
struct QueueListParams {
|
|
// No fields: this method takes no parameters.
|
|
};
|
|
|
|
struct QueueListResult {
|
|
std::vector<Queue> items{};
|
|
};
|
|
|
|
struct QueueReorderParams {
|
|
std::string queueId{};
|
|
std::vector<std::string> taskIds{};
|
|
};
|
|
|
|
struct QueueReorderResult {
|
|
Queue queue{};
|
|
};
|
|
|
|
struct QueueStartParams {
|
|
std::string queueId{};
|
|
};
|
|
|
|
struct QueueStartResult {
|
|
Queue queue{};
|
|
std::vector<std::string> startedTaskIds{};
|
|
};
|
|
|
|
struct QueueStopParams {
|
|
std::string queueId{};
|
|
std::optional<bool> pauseRunning{};
|
|
};
|
|
|
|
struct QueueStopResult {
|
|
Queue queue{};
|
|
std::vector<std::string> pausedTaskIds{};
|
|
};
|
|
|
|
struct QueueUpsertParams {
|
|
Queue queue{};
|
|
};
|
|
|
|
struct QueueUpsertResult {
|
|
Queue queue{};
|
|
};
|
|
|
|
struct RulesListParams {
|
|
// No fields: this method takes no parameters.
|
|
};
|
|
|
|
struct RulesListResult {
|
|
std::vector<Rule> items{};
|
|
};
|
|
|
|
struct RulesUpsertParams {
|
|
std::vector<Rule> upsert{};
|
|
std::optional<std::vector<std::string>> remove{};
|
|
};
|
|
|
|
/// The full table after the write, in priority order.
|
|
struct RulesUpsertResult {
|
|
std::vector<Rule> items{};
|
|
};
|
|
|
|
struct ScheduleGetParams {
|
|
std::optional<std::string> queueId{};
|
|
};
|
|
|
|
struct ScheduleGetResultItemsItem {
|
|
std::string queueId{};
|
|
std::optional<Schedule> schedule{};
|
|
};
|
|
|
|
struct ScheduleGetResult {
|
|
std::vector<ScheduleGetResultItemsItem> items{};
|
|
};
|
|
|
|
struct ScheduleSetParams {
|
|
std::string queueId{};
|
|
std::optional<Schedule> schedule{};
|
|
};
|
|
|
|
struct ScheduleSetResult {
|
|
std::string queueId{};
|
|
std::optional<Schedule> schedule{};
|
|
std::optional<std::string> nextRunAt{};
|
|
};
|
|
|
|
struct SessionHelloParams {
|
|
SessionHelloParamsClientType clientType{};
|
|
/// Human-readable, shown in the pairing prompt and the logs.
|
|
std::string clientName{};
|
|
std::string protocolVersion{};
|
|
/// Required on the WebSocket transport once paired. Ignored on the Unix socket, where
|
|
/// SO_PEERCRED is the authorization.
|
|
std::optional<std::string> token{};
|
|
};
|
|
|
|
struct SessionHelloResult {
|
|
std::string daemonVersion{};
|
|
std::string protocolVersion{};
|
|
/// Optional features this build has, e.g. 'media', 'grabber', 'secretservice'. A client must
|
|
/// degrade gracefully when one is absent rather than assuming it.
|
|
std::vector<std::string> capabilities{};
|
|
std::string sessionId{};
|
|
/// How the daemon sees this connection. Lets a client know up front which privileged methods
|
|
/// will be refused.
|
|
std::optional<SessionHelloResultTransport> transport{};
|
|
};
|
|
|
|
struct SessionPairParams {
|
|
std::string clientName{};
|
|
/// The moz-extension origin UUID. Must match the Origin header verified on the WS upgrade.
|
|
std::string extensionId{};
|
|
/// Set when the user typed the code into the extension's Options page instead of clicking Allow
|
|
/// in the GUI.
|
|
std::optional<std::string> code{};
|
|
};
|
|
|
|
struct SessionPairResult {
|
|
/// 256 bits, base64url. Stored by the extension in browser.storage.local and sent on every
|
|
/// later connect.
|
|
std::string token{};
|
|
/// null means the token does not expire; it is revoked from Options -> Unpair.
|
|
std::optional<std::string> expiresAt{};
|
|
};
|
|
|
|
struct SessionSubscribeParams {
|
|
std::vector<SessionSubscribeParamsEventsItem> events{};
|
|
/// Narrow task events to these ids. The extension popup uses it to avoid receiving progress for
|
|
/// downloads it is not showing. null means all tasks.
|
|
std::optional<std::vector<std::string>> taskIds{};
|
|
};
|
|
|
|
struct SessionSubscribeResult {
|
|
bool ok{};
|
|
/// Echoed back so a client can detect that it asked for an event this daemon does not emit.
|
|
std::vector<std::string> events{};
|
|
};
|
|
|
|
struct SettingsGetParams {
|
|
std::optional<std::vector<SettingKey>> keys{};
|
|
};
|
|
|
|
struct SettingsGetResult {
|
|
Settings values{};
|
|
};
|
|
|
|
struct SettingsSetParams {
|
|
Settings values{};
|
|
};
|
|
|
|
/// The stored values for the keys that were set, and the list of keys that actually changed.
|
|
struct SettingsSetResult {
|
|
Settings values{};
|
|
std::vector<SettingKey> changed{};
|
|
};
|
|
|
|
struct AuthRequiredEvent {
|
|
std::string taskId{};
|
|
std::string host{};
|
|
std::optional<std::string> realm{};
|
|
AuthRequiredEventScheme scheme{};
|
|
};
|
|
|
|
struct GrabberProgressEvent {
|
|
std::string jobId{};
|
|
std::int64_t found{};
|
|
std::int64_t crawled{};
|
|
bool done{};
|
|
std::optional<std::string> currentUrl{};
|
|
};
|
|
|
|
struct NotifyEvent {
|
|
NotifyEventLevel level{};
|
|
std::string title{};
|
|
std::string body{};
|
|
std::optional<std::string> taskId{};
|
|
std::optional<NotifyEventSound> sound{};
|
|
};
|
|
|
|
struct SettingsChangedEvent {
|
|
std::vector<SettingKey> keys{};
|
|
};
|
|
|
|
struct SpeedGlobalEvent {
|
|
std::int64_t downBps{};
|
|
std::int64_t activeCount{};
|
|
std::optional<std::int64_t> queuedCount{};
|
|
/// null when the limiter is off.
|
|
std::optional<std::int64_t> limitBps{};
|
|
};
|
|
|
|
struct TaskAddedEvent {
|
|
std::string taskId{};
|
|
TaskSummary summary{};
|
|
};
|
|
|
|
/// Only what a segment bar needs. Full segment state comes from download.get.
|
|
struct TaskProgressEventTasksItemSegmentsItem {
|
|
std::int64_t index{};
|
|
std::int64_t downloadedBytes{};
|
|
std::int64_t speedBps{};
|
|
};
|
|
|
|
struct TaskProgressEventTasksItem {
|
|
std::string taskId{};
|
|
std::int64_t downloadedBytes{};
|
|
std::int64_t speedBps{};
|
|
std::optional<std::int64_t> etaSeconds{};
|
|
std::optional<std::vector<TaskProgressEventTasksItemSegmentsItem>> segments{};
|
|
};
|
|
|
|
struct TaskProgressEvent {
|
|
std::vector<TaskProgressEventTasksItem> tasks{};
|
|
std::string at{};
|
|
};
|
|
|
|
struct TaskRemovedEvent {
|
|
std::string taskId{};
|
|
bool deletedFile{};
|
|
};
|
|
|
|
struct TaskStateEvent {
|
|
std::string taskId{};
|
|
TaskState state{};
|
|
std::optional<TaskState> previousState{};
|
|
std::optional<TaskSummary> summary{};
|
|
std::optional<TaskError> error{};
|
|
};
|
|
|
|
// --- serialisation ---------------------------------------------------------
|
|
// ADL hooks, so `nlohmann::json j = value;` works. Outbound only: there is no
|
|
// generated from_json, because nlohmann's inbound path throws and the wire is
|
|
// never trusted. Use parse<T> below.
|
|
|
|
void to_json(nlohmann::json& j, const ErrorCode& v);
|
|
void to_json(nlohmann::json& j, const BulkTaskResultFailedItem& v);
|
|
void to_json(nlohmann::json& j, const TaskState& v);
|
|
void to_json(nlohmann::json& j, const BulkTaskResultUpdatedItem& v);
|
|
void to_json(nlohmann::json& j, const BulkTaskResult& v);
|
|
void to_json(nlohmann::json& j, const BypassModifier& v);
|
|
void to_json(nlohmann::json& j, const CaptureRules& v);
|
|
void to_json(nlohmann::json& j, const Category& v);
|
|
void to_json(nlohmann::json& j, const ChecksumAlgorithm& v);
|
|
void to_json(nlohmann::json& j, const Checksum& v);
|
|
void to_json(nlohmann::json& j, const Cookie& v);
|
|
void to_json(nlohmann::json& j, const StartMode& v);
|
|
void to_json(nlohmann::json& j, const DownloadSpec& v);
|
|
void to_json(nlohmann::json& j, const GrabberFile& v);
|
|
void to_json(nlohmann::json& j, const Limiter& v);
|
|
void to_json(nlohmann::json& j, const MediaVariantContainer& v);
|
|
void to_json(nlohmann::json& j, const MediaVariantKind& v);
|
|
void to_json(nlohmann::json& j, const MediaVariant& v);
|
|
void to_json(nlohmann::json& j, const QueueOnComplete& v);
|
|
void to_json(nlohmann::json& j, const QueueState& v);
|
|
void to_json(nlohmann::json& j, const ScheduleMode& v);
|
|
void to_json(nlohmann::json& j, const Schedule& v);
|
|
void to_json(nlohmann::json& j, const Queue& v);
|
|
void to_json(nlohmann::json& j, const RuleActionCapture& v);
|
|
void to_json(nlohmann::json& j, const RuleAction& v);
|
|
void to_json(nlohmann::json& j, const RuleMatch& v);
|
|
void to_json(nlohmann::json& j, const Rule& v);
|
|
void to_json(nlohmann::json& j, const SegmentState& v);
|
|
void to_json(nlohmann::json& j, const Segment& v);
|
|
void to_json(nlohmann::json& j, const SettingKey& v);
|
|
void to_json(nlohmann::json& j, const SettingsConnectionPreset& v);
|
|
void to_json(nlohmann::json& j, const SettingsDownloadsDuplicatePolicy& v);
|
|
void to_json(nlohmann::json& j, const SettingsProxyMode& v);
|
|
void to_json(nlohmann::json& j, const SettingsSaveToFileExistsPolicy& v);
|
|
void to_json(nlohmann::json& j, const Settings& v);
|
|
void to_json(nlohmann::json& j, const TaskErrorCode& v);
|
|
void to_json(nlohmann::json& j, const TaskError& v);
|
|
void to_json(nlohmann::json& j, const TaskSummary& v);
|
|
void to_json(nlohmann::json& j, const TaskDetail& v);
|
|
void to_json(nlohmann::json& j, const TaskFilter& v);
|
|
void to_json(nlohmann::json& j, const TaskSortDirection& v);
|
|
void to_json(nlohmann::json& j, const TaskSortField& v);
|
|
void to_json(nlohmann::json& j, const TaskSort& v);
|
|
void to_json(nlohmann::json& j, const CaptureGetRulesParams& v);
|
|
void to_json(nlohmann::json& j, const CaptureOfferParamsMethod& v);
|
|
void to_json(nlohmann::json& j, const CaptureOfferParams& v);
|
|
void to_json(nlohmann::json& j, const CaptureOfferResultAction& v);
|
|
void to_json(nlohmann::json& j, const CaptureOfferResultReason& v);
|
|
void to_json(nlohmann::json& j, const CaptureOfferResult& v);
|
|
void to_json(nlohmann::json& j, const CategoryListParams& v);
|
|
void to_json(nlohmann::json& j, const CategoryListResult& v);
|
|
void to_json(nlohmann::json& j, const CategoryRemoveParams& v);
|
|
void to_json(nlohmann::json& j, const CategoryRemoveResult& v);
|
|
void to_json(nlohmann::json& j, const CategoryUpsertParams& v);
|
|
void to_json(nlohmann::json& j, const CategoryUpsertResult& v);
|
|
void to_json(nlohmann::json& j, const DownloadAddResult& v);
|
|
void to_json(nlohmann::json& j, const DownloadAddBatchParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadAddBatchResultFailedItem& v);
|
|
void to_json(nlohmann::json& j, const DownloadAddBatchResult& v);
|
|
void to_json(nlohmann::json& j, const DownloadCancelParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadGetParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadListParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadListResult& v);
|
|
void to_json(nlohmann::json& j, const DownloadPauseParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadProbeParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadProbeResult& v);
|
|
void to_json(nlohmann::json& j, const DownloadProvideAuthParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadProvideAuthResult& v);
|
|
void to_json(nlohmann::json& j, const DownloadRefreshUrlParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadRefreshUrlResult& v);
|
|
void to_json(nlohmann::json& j, const DownloadRemoveParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadRemoveResultFailedItem& v);
|
|
void to_json(nlohmann::json& j, const DownloadRemoveResult& v);
|
|
void to_json(nlohmann::json& j, const DownloadResumeParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadStartParams& v);
|
|
void to_json(nlohmann::json& j, const DownloadUpdateParamsPatch& v);
|
|
void to_json(nlohmann::json& j, const DownloadUpdateParams& v);
|
|
void to_json(nlohmann::json& j, const GrabberHarvestParams& v);
|
|
void to_json(nlohmann::json& j, const GrabberHarvestResultFailedItem& v);
|
|
void to_json(nlohmann::json& j, const GrabberHarvestResult& v);
|
|
void to_json(nlohmann::json& j, const GrabberStartParams& v);
|
|
void to_json(nlohmann::json& j, const GrabberStartResult& v);
|
|
void to_json(nlohmann::json& j, const GrabberStatusParams& v);
|
|
void to_json(nlohmann::json& j, const GrabberStatusResultState& v);
|
|
void to_json(nlohmann::json& j, const GrabberStatusResult& v);
|
|
void to_json(nlohmann::json& j, const LimiterGetParams& v);
|
|
void to_json(nlohmann::json& j, const MediaAddVariantParams& v);
|
|
void to_json(nlohmann::json& j, const MediaAddVariantResult& v);
|
|
void to_json(nlohmann::json& j, const MediaListVariantsParams& v);
|
|
void to_json(nlohmann::json& j, const MediaListVariantsResultManifestType& v);
|
|
void to_json(nlohmann::json& j, const MediaListVariantsResult& v);
|
|
void to_json(nlohmann::json& j, const QueueListParams& v);
|
|
void to_json(nlohmann::json& j, const QueueListResult& v);
|
|
void to_json(nlohmann::json& j, const QueueReorderParams& v);
|
|
void to_json(nlohmann::json& j, const QueueReorderResult& v);
|
|
void to_json(nlohmann::json& j, const QueueStartParams& v);
|
|
void to_json(nlohmann::json& j, const QueueStartResult& v);
|
|
void to_json(nlohmann::json& j, const QueueStopParams& v);
|
|
void to_json(nlohmann::json& j, const QueueStopResult& v);
|
|
void to_json(nlohmann::json& j, const QueueUpsertParams& v);
|
|
void to_json(nlohmann::json& j, const QueueUpsertResult& v);
|
|
void to_json(nlohmann::json& j, const RulesListParams& v);
|
|
void to_json(nlohmann::json& j, const RulesListResult& v);
|
|
void to_json(nlohmann::json& j, const RulesUpsertParams& v);
|
|
void to_json(nlohmann::json& j, const RulesUpsertResult& v);
|
|
void to_json(nlohmann::json& j, const ScheduleGetParams& v);
|
|
void to_json(nlohmann::json& j, const ScheduleGetResultItemsItem& v);
|
|
void to_json(nlohmann::json& j, const ScheduleGetResult& v);
|
|
void to_json(nlohmann::json& j, const ScheduleSetParams& v);
|
|
void to_json(nlohmann::json& j, const ScheduleSetResult& v);
|
|
void to_json(nlohmann::json& j, const SessionHelloParamsClientType& v);
|
|
void to_json(nlohmann::json& j, const SessionHelloParams& v);
|
|
void to_json(nlohmann::json& j, const SessionHelloResultTransport& v);
|
|
void to_json(nlohmann::json& j, const SessionHelloResult& v);
|
|
void to_json(nlohmann::json& j, const SessionPairParams& v);
|
|
void to_json(nlohmann::json& j, const SessionPairResult& v);
|
|
void to_json(nlohmann::json& j, const SessionSubscribeParamsEventsItem& v);
|
|
void to_json(nlohmann::json& j, const SessionSubscribeParams& v);
|
|
void to_json(nlohmann::json& j, const SessionSubscribeResult& v);
|
|
void to_json(nlohmann::json& j, const SettingsGetParams& v);
|
|
void to_json(nlohmann::json& j, const SettingsGetResult& v);
|
|
void to_json(nlohmann::json& j, const SettingsSetParams& v);
|
|
void to_json(nlohmann::json& j, const SettingsSetResult& v);
|
|
void to_json(nlohmann::json& j, const AuthRequiredEventScheme& v);
|
|
void to_json(nlohmann::json& j, const AuthRequiredEvent& v);
|
|
void to_json(nlohmann::json& j, const GrabberProgressEvent& v);
|
|
void to_json(nlohmann::json& j, const NotifyEventLevel& v);
|
|
void to_json(nlohmann::json& j, const NotifyEventSound& v);
|
|
void to_json(nlohmann::json& j, const NotifyEvent& v);
|
|
void to_json(nlohmann::json& j, const SettingsChangedEvent& v);
|
|
void to_json(nlohmann::json& j, const SpeedGlobalEvent& v);
|
|
void to_json(nlohmann::json& j, const TaskAddedEvent& v);
|
|
void to_json(nlohmann::json& j, const TaskProgressEventTasksItemSegmentsItem& v);
|
|
void to_json(nlohmann::json& j, const TaskProgressEventTasksItem& v);
|
|
void to_json(nlohmann::json& j, const TaskProgressEvent& v);
|
|
void to_json(nlohmann::json& j, const TaskRemovedEvent& v);
|
|
void to_json(nlohmann::json& j, const TaskStateEvent& v);
|
|
|
|
// --- parsing ---------------------------------------------------------------
|
|
|
|
/// Turn an untrusted JSON value into a typed one. Specialised below for every
|
|
/// contract type; the primary template is intentionally not defined, so asking
|
|
/// for a type the contract does not have is a compile error, not a runtime one.
|
|
template <class T>
|
|
Result<T> parse(const nlohmann::json& j, std::string_view path = "");
|
|
|
|
template <> Result<ErrorCode> parse<ErrorCode>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<BulkTaskResultFailedItem> parse<BulkTaskResultFailedItem>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskState> parse<TaskState>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<BulkTaskResultUpdatedItem> parse<BulkTaskResultUpdatedItem>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<BulkTaskResult> parse<BulkTaskResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<BypassModifier> parse<BypassModifier>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CaptureRules> parse<CaptureRules>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<Category> parse<Category>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<ChecksumAlgorithm> parse<ChecksumAlgorithm>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<Checksum> parse<Checksum>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<Cookie> parse<Cookie>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<Headers> parse<Headers>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<StartMode> parse<StartMode>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadSpec> parse<DownloadSpec>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<GrabberFile> parse<GrabberFile>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<Limiter> parse<Limiter>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<MediaVariantContainer> parse<MediaVariantContainer>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<MediaVariantKind> parse<MediaVariantKind>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<MediaVariant> parse<MediaVariant>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueOnComplete> parse<QueueOnComplete>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueState> parse<QueueState>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<ScheduleMode> parse<ScheduleMode>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<Schedule> parse<Schedule>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<Queue> parse<Queue>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<RuleActionCapture> parse<RuleActionCapture>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<RuleAction> parse<RuleAction>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<RuleMatch> parse<RuleMatch>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<Rule> parse<Rule>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SegmentState> parse<SegmentState>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<Segment> parse<Segment>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SettingKey> parse<SettingKey>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SettingsConnectionPreset> parse<SettingsConnectionPreset>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SettingsDownloadsDuplicatePolicy> parse<SettingsDownloadsDuplicatePolicy>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SettingsProxyMode> parse<SettingsProxyMode>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SettingsSaveToFileExistsPolicy> parse<SettingsSaveToFileExistsPolicy>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<Settings> parse<Settings>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskErrorCode> parse<TaskErrorCode>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskError> parse<TaskError>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskSummary> parse<TaskSummary>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskDetail> parse<TaskDetail>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskFilter> parse<TaskFilter>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskSortDirection> parse<TaskSortDirection>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskSortField> parse<TaskSortField>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskSort> parse<TaskSort>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CaptureGetRulesParams> parse<CaptureGetRulesParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CaptureOfferParamsMethod> parse<CaptureOfferParamsMethod>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CaptureOfferParams> parse<CaptureOfferParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CaptureOfferResultAction> parse<CaptureOfferResultAction>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CaptureOfferResultReason> parse<CaptureOfferResultReason>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CaptureOfferResult> parse<CaptureOfferResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CategoryListParams> parse<CategoryListParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CategoryListResult> parse<CategoryListResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CategoryRemoveParams> parse<CategoryRemoveParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CategoryRemoveResult> parse<CategoryRemoveResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CategoryUpsertParams> parse<CategoryUpsertParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<CategoryUpsertResult> parse<CategoryUpsertResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadAddResult> parse<DownloadAddResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadAddBatchParams> parse<DownloadAddBatchParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadAddBatchResultFailedItem> parse<DownloadAddBatchResultFailedItem>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadAddBatchResult> parse<DownloadAddBatchResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadCancelParams> parse<DownloadCancelParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadGetParams> parse<DownloadGetParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadListParams> parse<DownloadListParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadListResult> parse<DownloadListResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadPauseParams> parse<DownloadPauseParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadProbeParams> parse<DownloadProbeParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadProbeResult> parse<DownloadProbeResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadProvideAuthParams> parse<DownloadProvideAuthParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadProvideAuthResult> parse<DownloadProvideAuthResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadRefreshUrlParams> parse<DownloadRefreshUrlParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadRefreshUrlResult> parse<DownloadRefreshUrlResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadRemoveParams> parse<DownloadRemoveParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadRemoveResultFailedItem> parse<DownloadRemoveResultFailedItem>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadRemoveResult> parse<DownloadRemoveResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadResumeParams> parse<DownloadResumeParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadStartParams> parse<DownloadStartParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadUpdateParamsPatch> parse<DownloadUpdateParamsPatch>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<DownloadUpdateParams> parse<DownloadUpdateParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<GrabberHarvestParams> parse<GrabberHarvestParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<GrabberHarvestResultFailedItem> parse<GrabberHarvestResultFailedItem>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<GrabberHarvestResult> parse<GrabberHarvestResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<GrabberStartParams> parse<GrabberStartParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<GrabberStartResult> parse<GrabberStartResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<GrabberStatusParams> parse<GrabberStatusParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<GrabberStatusResultState> parse<GrabberStatusResultState>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<GrabberStatusResult> parse<GrabberStatusResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<LimiterGetParams> parse<LimiterGetParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<MediaAddVariantParams> parse<MediaAddVariantParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<MediaAddVariantResult> parse<MediaAddVariantResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<MediaListVariantsParams> parse<MediaListVariantsParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<MediaListVariantsResultManifestType> parse<MediaListVariantsResultManifestType>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<MediaListVariantsResult> parse<MediaListVariantsResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueListParams> parse<QueueListParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueListResult> parse<QueueListResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueReorderParams> parse<QueueReorderParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueReorderResult> parse<QueueReorderResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueStartParams> parse<QueueStartParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueStartResult> parse<QueueStartResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueStopParams> parse<QueueStopParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueStopResult> parse<QueueStopResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueUpsertParams> parse<QueueUpsertParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<QueueUpsertResult> parse<QueueUpsertResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<RulesListParams> parse<RulesListParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<RulesListResult> parse<RulesListResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<RulesUpsertParams> parse<RulesUpsertParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<RulesUpsertResult> parse<RulesUpsertResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<ScheduleGetParams> parse<ScheduleGetParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<ScheduleGetResultItemsItem> parse<ScheduleGetResultItemsItem>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<ScheduleGetResult> parse<ScheduleGetResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<ScheduleSetParams> parse<ScheduleSetParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<ScheduleSetResult> parse<ScheduleSetResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SessionHelloParamsClientType> parse<SessionHelloParamsClientType>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SessionHelloParams> parse<SessionHelloParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SessionHelloResultTransport> parse<SessionHelloResultTransport>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SessionHelloResult> parse<SessionHelloResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SessionPairParams> parse<SessionPairParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SessionPairResult> parse<SessionPairResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SessionSubscribeParamsEventsItem> parse<SessionSubscribeParamsEventsItem>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SessionSubscribeParams> parse<SessionSubscribeParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SessionSubscribeResult> parse<SessionSubscribeResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SettingsGetParams> parse<SettingsGetParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SettingsGetResult> parse<SettingsGetResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SettingsSetParams> parse<SettingsSetParams>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SettingsSetResult> parse<SettingsSetResult>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<AuthRequiredEventScheme> parse<AuthRequiredEventScheme>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<AuthRequiredEvent> parse<AuthRequiredEvent>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<GrabberProgressEvent> parse<GrabberProgressEvent>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<NotifyEventLevel> parse<NotifyEventLevel>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<NotifyEventSound> parse<NotifyEventSound>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<NotifyEvent> parse<NotifyEvent>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SettingsChangedEvent> parse<SettingsChangedEvent>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<SpeedGlobalEvent> parse<SpeedGlobalEvent>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskAddedEvent> parse<TaskAddedEvent>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskProgressEventTasksItemSegmentsItem> parse<TaskProgressEventTasksItemSegmentsItem>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskProgressEventTasksItem> parse<TaskProgressEventTasksItem>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskProgressEvent> parse<TaskProgressEvent>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskRemovedEvent> parse<TaskRemovedEvent>(const nlohmann::json& j, std::string_view path);
|
|
template <> Result<TaskStateEvent> parse<TaskStateEvent>(const nlohmann::json& j, std::string_view path);
|
|
|
|
// --- method surface --------------------------------------------------------
|
|
|
|
/// Every method in the contract. Generated, so a daemon cannot answer a method
|
|
/// the contract does not define, and cannot silently fail to answer one it does.
|
|
enum class Method {
|
|
CaptureGetRules, // capture.getRules
|
|
CaptureOffer, // capture.offer
|
|
CategoryList, // category.list
|
|
CategoryRemove, // category.remove
|
|
CategoryUpsert, // category.upsert
|
|
DownloadAdd, // download.add
|
|
DownloadAddBatch, // download.addBatch
|
|
DownloadCancel, // download.cancel
|
|
DownloadGet, // download.get
|
|
DownloadList, // download.list
|
|
DownloadPause, // download.pause
|
|
DownloadProbe, // download.probe
|
|
DownloadProvideAuth, // download.provideAuth
|
|
DownloadRefreshUrl, // download.refreshUrl
|
|
DownloadRemove, // download.remove
|
|
DownloadResume, // download.resume
|
|
DownloadStart, // download.start
|
|
DownloadUpdate, // download.update
|
|
GrabberHarvest, // grabber.harvest
|
|
GrabberStart, // grabber.start
|
|
GrabberStatus, // grabber.status
|
|
LimiterGet, // limiter.get
|
|
LimiterSet, // limiter.set
|
|
MediaAddVariant, // media.addVariant
|
|
MediaListVariants, // media.listVariants
|
|
QueueList, // queue.list
|
|
QueueReorder, // queue.reorder
|
|
QueueStart, // queue.start
|
|
QueueStop, // queue.stop
|
|
QueueUpsert, // queue.upsert
|
|
RulesList, // rules.list
|
|
RulesUpsert, // rules.upsert
|
|
ScheduleGet, // schedule.get
|
|
ScheduleSet, // schedule.set
|
|
SessionHello, // session.hello
|
|
SessionPair, // session.pair
|
|
SessionSubscribe, // session.subscribe
|
|
SettingsGet, // settings.get
|
|
SettingsSet, // settings.set
|
|
};
|
|
|
|
inline constexpr std::size_t kMethodCount = 39;
|
|
|
|
std::string_view to_string(Method m) noexcept;
|
|
std::optional<Method> method_from_string(std::string_view s) noexcept;
|
|
|
|
/// True for methods refused over the WebSocket transport with -32003. The
|
|
/// extension is not allowed to reconfigure the daemon or destroy user data.
|
|
bool is_privileged(Method m) noexcept;
|
|
bool is_allowed_on(Method m, Transport t) noexcept;
|
|
|
|
/// The contract's answer deadline. capture.offer's 750 ms is the one that
|
|
/// matters: past it the extension has already let Firefox take the download.
|
|
std::int32_t deadline_ms(Method m) noexcept;
|
|
|
|
/// Server-to-client notifications.
|
|
enum class Event {
|
|
AuthRequired, // event.auth.required
|
|
GrabberProgress, // event.grabber.progress
|
|
Notify, // event.notify
|
|
SettingsChanged, // event.settings.changed
|
|
SpeedGlobal, // event.speed.global
|
|
TaskAdded, // event.task.added
|
|
TaskProgress, // event.task.progress
|
|
TaskRemoved, // event.task.removed
|
|
TaskState, // event.task.state
|
|
};
|
|
|
|
std::string_view to_string(Event e) noexcept;
|
|
std::optional<Event> event_from_string(std::string_view s) noexcept;
|
|
|
|
// --- dispatch --------------------------------------------------------------
|
|
|
|
/// Build a JSON-RPC error response. `id` may be null for a request that could
|
|
/// not be parsed far enough to have one.
|
|
nlohmann::json make_error(const nlohmann::json& id, ErrorCode code, std::string_view message,
|
|
nlohmann::json data = nullptr);
|
|
nlohmann::json make_result(const nlohmann::json& id, nlohmann::json result);
|
|
nlohmann::json make_notification(Event e, nlohmann::json params);
|
|
|
|
/// One virtual per method. The daemon implements this; `dispatch` below does the
|
|
/// envelope handling, the transport check and the parameter parsing, so a handler
|
|
/// only ever sees a validated, typed params struct.
|
|
class Dispatcher {
|
|
public:
|
|
virtual ~Dispatcher() = default;
|
|
|
|
/// The daemon's capture policy, so the extension's shouldCapture decision cannot drift from the
|
|
/// daemon's. Fetched on connect and whenever event.settings.changed names a capture.* key. If
|
|
/// this call fails the extension keeps its last known rules and stays fail-open.
|
|
virtual Result<CaptureRules> on_capture_getRules(const CaptureGetRulesParams& params) = 0;
|
|
|
|
/// Firefox offers an intercepted response to the daemon. The daemon MUST reply within 750 ms;
|
|
/// the extension abandons the offer and lets Firefox download normally on timeout. This
|
|
/// deadline is the whole reason capture fails open, and it is conformance-tested: a daemon that
|
|
/// is slow, down, or erroring must never cost the user a download.
|
|
virtual Result<CaptureOfferResult> on_capture_offer(const CaptureOfferParams& params) = 0;
|
|
|
|
/// Every category with its folder and extension list. The extension calls this to populate its
|
|
/// default-category picker, which is why it is not privileged; it is read-only and exposes only
|
|
/// paths the user already configured.
|
|
virtual Result<CategoryListResult> on_category_list(const CategoryListParams& params) = 0;
|
|
|
|
/// Delete a user-created category. Built-in categories are refused with -32602. Tasks filed
|
|
/// under it are reassigned to reassignTo, or to the default category when that is null; no task
|
|
/// is ever orphaned.
|
|
virtual Result<CategoryRemoveResult> on_category_remove(const CategoryRemoveParams& params) = 0;
|
|
|
|
/// Create or replace a category. Omit categoryId to create; supply it to replace. Changing
|
|
/// saveDir does not move existing files — the GUI asks separately and issues download.update
|
|
/// per task, so a re-point is never a surprise mass file move.
|
|
virtual Result<CategoryUpsertResult> on_category_upsert(const CategoryUpsertParams& params) = 0;
|
|
|
|
/// Create one task. saveDir is canonicalized and checked against saveTo.allowedRoots before
|
|
/// anything is written; a path that escapes them is refused with -32011 and no file is created.
|
|
virtual Result<DownloadAddResult> on_download_add(const DownloadSpec& params) = 0;
|
|
|
|
/// Create many tasks in one call: the clipboard blob, the wildcard expander, and the
|
|
/// extension's 'Download all links'. Partial success is normal and is reported per item rather
|
|
/// than failing the whole batch.
|
|
virtual Result<DownloadAddBatchResult> on_download_addBatch(const DownloadAddBatchParams& params) = 0;
|
|
|
|
/// Stop the given tasks and mark them cancelled. The .veloxpart file is kept so the user can
|
|
/// still resume from the list; download.remove is what deletes bytes.
|
|
virtual Result<BulkTaskResult> on_download_cancel(const DownloadCancelParams& params) = 0;
|
|
|
|
/// Full detail for one task, including per-segment state. Backs the progress dialog. Poll it no
|
|
/// faster than the progress dialog repaints; the table must use events instead.
|
|
virtual Result<TaskDetail> on_download_get(const DownloadGetParams& params) = 0;
|
|
|
|
/// The main table. Filtering, sorting and paging all happen in the daemon so the GUI never
|
|
/// materializes 100k rows to show 40. Called once on connect; after that the table is
|
|
/// maintained from events, never re-fetched on a progress tick.
|
|
virtual Result<DownloadListResult> on_download_list(const DownloadListParams& params) = 0;
|
|
|
|
/// Suspend transfers and flush every segment's progress to the .veloxpart.meta file, so a pause
|
|
/// is indistinguishable from a crash as far as resume is concerned. Never loses bytes already
|
|
/// written.
|
|
virtual Result<BulkTaskResult> on_download_pause(const DownloadPauseParams& params) = 0;
|
|
|
|
/// Ask what is at a URL without creating a task. Populates the File Info dialog. Runs a HEAD,
|
|
/// falling back to a ranged GET when HEAD is refused, which is also how resumability is
|
|
/// established. Never blocks the RPC loop; the dialog opens immediately and fills in when this
|
|
/// lands.
|
|
virtual Result<DownloadProbeResult> on_download_probe(const DownloadProbeParams& params) = 0;
|
|
|
|
/// Answer an event.auth.required challenge. The task sits in retry_wait until this arrives; on
|
|
/// success the daemon retries with the credentials attached and the task resumes on its own —
|
|
/// this method does not itself start the transfer. Privileged and Unix-socket-only: a
|
|
/// credential-bearing method must never be reachable from the browser, which is exactly the
|
|
/// boundary event.auth.required's own description draws ('never back through this event, never
|
|
/// into a log') — this is the other half of that promise. Credentials are handed to the Secret
|
|
/// Service, never to SQLite and never logged; save only tells the daemon whether to persist
|
|
/// them there for next time, or use them for this attempt alone.
|
|
virtual Result<DownloadProvideAuthResult> on_download_provideAuth(const DownloadProvideAuthParams& params) = 0;
|
|
|
|
/// IDM's 'Refresh Download Address'. Point an existing task at a freshly-issued URL when a
|
|
/// signed link has expired, keeping every byte already on disk. The daemon re-probes and
|
|
/// compares size and validator: if they still match, the transfer resumes from where it
|
|
/// stopped; if they do not, it says so rather than silently restarting.
|
|
virtual Result<DownloadRefreshUrlResult> on_download_refreshUrl(const DownloadRefreshUrlParams& params) = 0;
|
|
|
|
/// Drop tasks from the list, optionally deleting the bytes on disk. Privileged: this is the
|
|
/// only method that destroys user data, and the extension is never allowed to reach it. The
|
|
/// daemon deletes the .veloxpart and .veloxpart.meta pair, and the finished file only when
|
|
/// deleteFile is true.
|
|
virtual Result<DownloadRemoveResult> on_download_remove(const DownloadRemoveParams& params) = 0;
|
|
|
|
/// Continue paused tasks. Resumption is revalidated with If-Range against the stored ETag or
|
|
/// Last-Modified; a 200 where 206 was expected means the file changed on the server, and the
|
|
/// task moves to failed with a clear error rather than corrupting the part file.
|
|
virtual Result<BulkTaskResult> on_download_resume(const DownloadResumeParams& params) = 0;
|
|
|
|
/// Begin or restart the given tasks. A task in 'queued' jumps its queue; a task already
|
|
/// downloading is a no-op reported as changed false.
|
|
virtual Result<BulkTaskResult> on_download_start(const DownloadStartParams& params) = 0;
|
|
|
|
/// Change a task's mutable fields. Moving saveDir or filename moves the file on disk in the
|
|
/// same operation, which is what makes dragging a row onto a category work as one RPC.
|
|
/// Privileged: it can name a destination path.
|
|
virtual Result<TaskSummary> on_download_update(const DownloadUpdateParams& params) = 0;
|
|
|
|
/// Turn selected crawl results into tasks. This is the only grabber call that creates
|
|
/// downloads, and it names exactly the files the user ticked — a crawl never starts a download
|
|
/// on its own.
|
|
virtual Result<GrabberHarvestResult> on_grabber_harvest(const GrabberHarvestParams& params) = 0;
|
|
|
|
/// Start a depth-limited crawl. Nothing is downloaded by this call: it only walks pages and
|
|
/// collects candidate links, which the wizard then shows for selection. Privileged because an
|
|
/// unbounded crawl is a resource commitment the browser must not be able to make on the user's
|
|
/// behalf.
|
|
virtual Result<GrabberStartResult> on_grabber_start(const GrabberStartParams& params) = 0;
|
|
|
|
/// Poll one crawl. Also delivered as event.grabber.progress; the poll exists so the wizard can
|
|
/// be reopened on a job it did not start and still catch up.
|
|
virtual Result<GrabberStatusResult> on_grabber_status(const GrabberStatusParams& params) = 0;
|
|
|
|
/// Current global speed limit. Privileged: changing or reading the limiter belongs to the GUI
|
|
/// and CLI; the extension shows throughput from event.speed.global instead.
|
|
virtual Result<Limiter> on_limiter_get(const LimiterGetParams& params) = 0;
|
|
|
|
/// Set the global token-bucket limit. With applyToRunning true the change re-tunes transfers
|
|
/// already in flight instead of taking effect only on the next task — the Speed Limiter
|
|
/// window's 'apply now' button.
|
|
virtual Result<Limiter> on_limiter_set(const Limiter& params) = 0;
|
|
|
|
/// Turn one enumerated variant into a task. The daemon fetches the segments in parallel and
|
|
/// muxes them with ffmpeg; the result is an ordinary task that appears in the list like any
|
|
/// other download. Refused with -32602 when the variant is DRM-protected.
|
|
virtual Result<MediaAddVariantResult> on_media_addVariant(const MediaAddVariantParams& params) = 0;
|
|
|
|
/// Parse an HLS or DASH manifest in the daemon and enumerate its renditions. The extension
|
|
/// never parses a manifest — that logic lives in one language, in one place. Variants with drm
|
|
/// true are reported so the UI can grey them out; DRM-protected streams are refused, not
|
|
/// attempted.
|
|
virtual Result<MediaListVariantsResult> on_media_listVariants(const MediaListVariantsParams& params) = 0;
|
|
|
|
/// Every queue with its run state and ordering. Not privileged: the extension's 'Add to Queue'
|
|
/// picker needs it.
|
|
virtual Result<QueueListResult> on_queue_list(const QueueListParams& params) = 0;
|
|
|
|
/// Rewrite a queue's run order. taskIds must be a permutation of the queue's current
|
|
/// membership; anything else is -32602 rather than a partial reorder, so a stale drag from an
|
|
/// out-of-date view cannot quietly reshuffle the queue.
|
|
virtual Result<QueueReorderResult> on_queue_reorder(const QueueReorderParams& params) = 0;
|
|
|
|
/// Start a queue running. The scheduler then admits up to maxConcurrent tasks from it, in
|
|
/// order, and keeps that many running until the queue drains or is stopped.
|
|
virtual Result<QueueStartResult> on_queue_start(const QueueStartParams& params) = 0;
|
|
|
|
/// Stop admitting new tasks from a queue. Tasks already running are paused when pauseRunning is
|
|
/// true, and otherwise allowed to finish — the difference between 'stop the queue' and 'stop
|
|
/// everything', which IDM conflates and users trip over.
|
|
virtual Result<QueueStopResult> on_queue_stop(const QueueStopParams& params) = 0;
|
|
|
|
/// Create or replace a queue, including its schedule and concurrency cap. Omit queueId to
|
|
/// create. taskIds in the payload is ignored — membership changes through download.update and
|
|
/// queue.reorder so that two clients editing at once cannot silently drop a task.
|
|
virtual Result<QueueUpsertResult> on_queue_upsert(const QueueUpsertParams& params) = 0;
|
|
|
|
/// The rules engine's table, in priority order. Privileged: these are the daemon's routing
|
|
/// policy. The extension gets its own narrowed view through capture.getRules instead.
|
|
virtual Result<RulesListResult> on_rules_list(const RulesListParams& params) = 0;
|
|
|
|
/// Create, replace, or delete rules in one atomic write. 'upsert' carries the rules to store
|
|
/// and 'remove' the ruleIds to drop; applying both at once means a reprioritisation never
|
|
/// leaves the table in a half-valid state.
|
|
virtual Result<RulesUpsertResult> on_rules_upsert(const RulesUpsertParams& params) = 0;
|
|
|
|
/// The schedule for one queue, or every schedule when queueId is null. Backs the Scheduler
|
|
/// window.
|
|
virtual Result<ScheduleGetResult> on_schedule_get(const ScheduleGetParams& params) = 0;
|
|
|
|
/// Set or clear a queue's schedule. A null schedule clears it and leaves the queue under manual
|
|
/// control. Times are local wall-clock and are re-evaluated on a DST change rather than being
|
|
/// resolved to absolute instants at set time.
|
|
virtual Result<ScheduleSetResult> on_schedule_set(const ScheduleSetParams& params) = 0;
|
|
|
|
/// First call on every connection, on every transport. The daemon compares protocolVersion
|
|
/// majors and refuses a mismatch with -32001 so a stale GUI or extension fails loudly on
|
|
/// connect instead of subtly at the tenth field. On the WebSocket transport a valid token is
|
|
/// required unless the client is about to call session.pair.
|
|
virtual Result<SessionHelloResult> on_session_hello(const SessionHelloParams& params) = 0;
|
|
|
|
/// WebSocket transport only. Triggers a GUI or desktop-notification prompt showing a four-digit
|
|
/// code; the user must approve before a token is issued. Failed attempts are rate-limited to
|
|
/// 5/min followed by a 60 s lockout (-32014) so a token cannot be brute-forced by another local
|
|
/// process. The daemon stores only a hash of the token.
|
|
virtual Result<SessionPairResult> on_session_pair(const SessionPairParams& params) = 0;
|
|
|
|
/// Choose which notifications this connection receives. Subscribing replaces the previous
|
|
/// selection rather than adding to it, so a client can narrow its firehose without
|
|
/// reconnecting. Nothing is delivered until this is called.
|
|
virtual Result<SessionSubscribeResult> on_session_subscribe(const SessionSubscribeParams& params) = 0;
|
|
|
|
/// Read settings. keys null means everything. Privileged: the settings bag names local
|
|
/// filesystem paths and the allowed write roots, which the extension has no business
|
|
/// enumerating — it gets capture.getRules instead.
|
|
virtual Result<SettingsGetResult> on_settings_get(const SettingsGetParams& params) = 0;
|
|
|
|
/// Write settings. Only the keys present in values change. Rejected with -32602 if a key is
|
|
/// unknown or a value fails the Settings schema, and with -32011 if a directory key names a
|
|
/// path that cannot be written. Emits event.settings.changed with exactly the keys that took
|
|
/// effect.
|
|
virtual Result<SettingsSetResult> on_settings_set(const SettingsSetParams& params) = 0;
|
|
|
|
};
|
|
|
|
/// Parse one JSON-RPC request, route it, and return the response to write back.
|
|
/// Never throws. Returns a null json for a notification that needs no reply.
|
|
nlohmann::json dispatch(Dispatcher& handler, Transport transport, const nlohmann::json& request);
|
|
|
|
} // namespace velox::proto
|