#pragma once // The seam between the dispatcher and the scheduler for user-initiated task/queue actions // (download.pause/resume/start/cancel, queue.stop's pauseRunning) — owned by rpc/ so // dispatcher.hpp (part of veloxd_rpc) never has to include sched/scheduler.hpp, which // would make veloxd_rpc depend on veloxd_sched at compile time. veloxd_sched already // depends on veloxd_rpc (for EventHub); the other direction too would be a real circular // library dependency, not just an inconvenience — anything linking veloxd_rpc alone (e.g. // the CLI's tests) would fail to link over symbols it never calls. // // sched::Scheduler implements this directly (it already lives in a library that depends on // rpc/, so adding an rpc-defined base costs nothing new); main.cpp hands the dispatcher a // `TaskActionPort*` pointing at the same Scheduler it constructs. #include #include #include #include "velox_proto.hpp" namespace velox::daemon::rpc { class TaskActionPort { public: virtual ~TaskActionPort() = default; // Mirrors sched::Scheduler::UserActionResult: whether the task was found at all, // whether it actually changed state (a task already in the target/a terminal state is // reported found=true, changed=false — BulkTaskResult's own "not an error" contract), // and its resulting/current state spelling either way. struct Result { bool found = false; bool changed = false; std::string state; }; virtual Result user_pause(const std::string& wire_id) = 0; virtual Result user_resume(const std::string& wire_id) = 0; virtual Result user_start(const std::string& wire_id) = 0; virtual Result user_cancel(const std::string& wire_id, bool discard_partial) = 0; // queue.stop(pauseRunning=true): pause every currently-running task in `queue_id` now. // Returns the wire ids actually paused. virtual std::vector pause_queue(const std::string& queue_id) = 0; // download.provideAuth: answers a task auto-paused on a 401/407. false if the task // isn't currently holding a live engine handle (nothing waiting on credentials). // `remember` is accepted but not yet acted on — persisting to the Secret Service isn't // wired anywhere in this build yet (CLAUDE.md §4: never SQLite, never logs); this // always does the "this retry only" half. Noted in deferrals.md. virtual bool provide_auth(const std::string& wire_id, const std::string& username, const std::string& password, bool remember) = 0; // download.probe (D2), the File Info dialog's own network round trip — no task row // involved. Genuinely async (the engine's probe pool; up to the schema's 30s // x-deadlineMs) and so cannot fit VeloxDispatcher's synchronous on_download_probe: // the RPC server layer (uds_server.cpp / ws_server.cpp) special-cases "download.probe" // before the generic dispatch(), the same way it already special-cases session.hello, // calls this, and queues the reply whenever `done` fires — on an engine thread, so the // implementation must marshal back to the loop before calling it, the same as every // other EnginePort callback. Kept in std::string/proto terms (not vdm::net::*) so this // header — included by dispatcher.hpp, part of veloxd_rpc — never needs core/include's // vdm headers; the vdm::net::ProbeRequest/ProbeResult conversion lives in sched/, which // already depends on vdm. virtual void probe_now( const velox::proto::DownloadProbeParams& params, std::function)> done) = 0; // download.refreshUrl ("IDM's 'Refresh Download Address'"): same async reasoning and // the same server-layer special-case as probe_now — a real network round trip, up to // the schema's own 30s x-deadlineMs. Re-probes the new URL, compares size/validator // against what the task already has on record (contentChanged), persists the new URL // and probe result, and — if the task holds a live engine handle — swaps its URL // in-flight without losing progress. virtual void refresh_url( const std::string& wire_id, const std::string& url, const std::optional& headers, const std::optional>& cookies, std::function)> done) = 0; // settings.set of a connection.* key: re-read connection.maxConcurrentDownloads / // maxActiveSegments and the per-host cap table, push the new caps to the engine and // the governor (Scheduler::reload_config's own doc comment names this exact trigger). // Named apply_settings_reload rather than reload_config to avoid colliding with // sched::Scheduler's own already-public reload_config() (returns DbResult, // consumed by main.cpp and a unit test — kept as-is rather than reshaped to fit here). virtual void apply_settings_reload() = 0; // limiter.set: pushed straight to the engine's shared global token bucket. 0 means // unlimited (the bucket's own convention). virtual void set_global_speed_limit(std::uint64_t bps) = 0; }; } // namespace velox::daemon::rpc