DAEMON's daemon/docs/proto-requests-m1.md P1: velox::proto::Dispatcher's
on_* methods returned Result<T> = expected<T, ParseError>, and dispatch()
mapped every handler error to -32603 InternalError. A handler had no way to
return -32010 (download.get not-found), -32011 (download.add invalid-path)
or -32013 (probe-failed) with their data payloads -- three error fixtures a
conformant server must satisfy were unreachable, blocking DAEMON's
"conformance as a server" M1 DoD.
Two error channels now, kept separate on purpose:
- parse: Result<T> / ParseError -- dispatch() failing to turn the wire into
typed params. Always -32602, always structural.
- handler: HandlerResult<T> / HandlerError -- a handler deciding the request
can't be fulfilled. Carries any ErrorCode + message + free-form data.
struct HandlerError {
ErrorCode code{ErrorCode::InternalError}; // bare {} is a valid -32603
std::string message;
nlohmann::json data = nullptr; // straight into the error's data
};
template <class T> using HandlerResult = std::expected<T, HandlerError>;
dispatch()'s handler branch is now
make_error(id, r.error().code, r.error().message, r.error().data)
instead of a hard-coded InternalError. -32001/-32002/-32003 stay the server
layer's to raise around dispatch(), as DAEMON already does.
Verified end to end against the real dispatch() path: a handler returning
TaskNotFound/InvalidPath/ProbeFailed produces -32010/-32011/-32013 with the
data object intact, and a bare HandlerError{} still yields a clean -32603
with no data field. The `= nullptr` on the member (not `{nullptr}`) matters:
brace-init of nlohmann::json from nullptr is the array [null], not JSON null.
FixtureDispatcher regenerated to HandlerResult; conformance_main.cpp only
inspects dispatch()'s JSON and needed no change. TS side is untouched beyond
the version string -- no server Dispatcher is generated there.
P2 also handled: session.hello.version-mismatch's data.expected was a stale
"1.0.0"; now $any, with a note that the error-fixture compare is on `code`
only so a server echoing kProtocolVersion there is fine.
Version: minor, 1.3.0 -> 1.4.0. Wire is byte-identical (no schema, fixture,
or OpenRPC change) but every Dispatcher implementer must swap Result ->
HandlerResult on regen, and the bump is how lanes are told to. Not an ADR:
one lane consumes this binding, it's the one that asked, and the shape is
the one they proposed. Answered in contracts/proto-answers-daemon-m1.md.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_012fgjnqFCS5h5L7gZTZo3rV
2022 lines
95 KiB
C++
2022 lines
95 KiB
C++
// ---------------------------------------------------------------------------
|
|
// GENERATED FILE — DO NOT EDIT.
|
|
//
|
|
// Source: contracts/schema/**
|
|
// Generator: contracts/codegen/gen_cpp.py
|
|
// Contract: v1.4.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.4.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 engine 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, retry_wait, or (when the daemon paused it on its own initiative
|
|
/// rather than the user) paused 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. A pause the
|
|
/// user or the scheduler requested carries no error: this field only explains a paused state
|
|
/// the daemon entered unilaterally (auth_required, server_file_changed, disk_full and the
|
|
/// like), never a deliberate one.
|
|
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{};
|
|
/// Set when state is failed or retry_wait, and also when state is paused and the daemon entered
|
|
/// that state on its own initiative rather than at a user's or scheduler's request. null on
|
|
/// every other state, including a deliberate pause.
|
|
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 engine 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{};
|
|
/// Set when the new state is failed or retry_wait, and also when it is paused and the daemon
|
|
/// entered that state on its own initiative — auth_required, server_file_changed, disk_full and
|
|
/// the like — rather than because of a user action, a schedule window closing, or an
|
|
/// admission-control decision. null on every other transition, including every
|
|
/// deliberately-requested pause. A client must not assume a paused task has no error just
|
|
/// because it usually doesn't; check this field rather than the state name alone.
|
|
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);
|
|
|
|
/// A handler's own failure — as opposed to ParseError, which is the wire failing
|
|
/// to become typed params. Carries any contract error code, a message, and a
|
|
/// free-form `data` object that goes straight into the JSON-RPC error's `data`
|
|
/// field: `{"taskId": ...}` for TaskNotFound, `{"path": ...}` for InvalidPath,
|
|
/// `{"httpStatus": ...}` for ProbeFailed. `code` defaults to InternalError so a
|
|
/// handler that sets only a message still produces a valid error response.
|
|
///
|
|
/// -32001/-32002/-32003 are the server layer's to raise around dispatch(), not a
|
|
/// handler's: they are decided before or without reference to method params.
|
|
struct HandlerError {
|
|
ErrorCode code{ErrorCode::InternalError};
|
|
std::string message;
|
|
// `= nullptr`, not `{nullptr}`: brace-init of nlohmann::json from nullptr
|
|
// yields the array [null], not JSON null. make_error() drops a null data.
|
|
nlohmann::json data = nullptr;
|
|
};
|
|
|
|
template <class T>
|
|
using HandlerResult = std::expected<T, HandlerError>;
|
|
|
|
/// 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. Return `std::unexpected(
|
|
/// HandlerError{...})` to answer with a specific error code and data.
|
|
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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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 HandlerResult<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
|