daemon: download.add / download.list / download.get behind the store

VeloxDispatcher now takes a store::Db& and three handlers are real:

- download.list -> store::Tasks::list (filter / sort / paging in SQL) ->
  to_summary per row. No more empty-table stub.
- download.add -> resolve saveDir (spec, else saveTo.defaultDir; ~ expanded)
  and the leaf (spec.filename, else the URL's last segment percent-decoded,
  else download.bin) -> fs::resolve_target against canonicalize_root'd
  saveTo.allowedRoots. Any path-destination failure is -32011 with the
  *original* saveDir in data.path. On success a TaskRow is inserted in
  state `queued` (or `new` for startMode "manual") and {taskId, state}
  returned. The scheduler that would then admit it is D4.
- download.get -> store::Tasks::get; a real -32010 + data.taskId for an
  unknown id, else a TaskDetail (segmentDetail empty until the engine
  segments the task, which the schema permits).

util/time.hpp: now_iso() factored out of ws_server.cpp.

main.cpp constructs the dispatcher with the opened db. The three
integration tests build an in-memory migrated db for it; velox.client
now drives the full slice through the CLI — add outside roots -> -32011
with data.path, add into an allowed root -> a task that download.list
shows and download.get details, unknown id -> -32010. Verified with the
real binaries: velox add persists, velox ls shows it, it survives a
daemon restart, /etc is refused.

ASan+UBSan and TSan clean; 34 daemon/cli tests green. deferrals.md:
D2 down to just download.probe; D3 down to categories/queues/rules/
settings/limiter/schedule.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Upd9WhG9oppieig5nRDLig
This commit is contained in:
2026-09-10 19:58:45 +04:00
co-authored by Claude Sonnet 5
parent 7514f5a4c4
commit 3db0d01f9d
10 changed files with 257 additions and 42 deletions
+2 -2
View File
@@ -11,11 +11,11 @@ function(veloxd_test name)
endfunction()
veloxd_test(ndjson LIBS veloxd_rpc)
veloxd_test(uds_roundtrip LIBS veloxd_rpc)
veloxd_test(uds_roundtrip LIBS veloxd_rpc veloxd_store)
veloxd_test(store_migrations LIBS veloxd_store)
veloxd_test(pairings LIBS veloxd_store veloxd_rpc)
veloxd_test(ws_frame LIBS veloxd_rpc)
veloxd_test(ws_server LIBS veloxd_rpc)
veloxd_test(ws_server LIBS veloxd_rpc veloxd_store)
veloxd_test(sched_window LIBS veloxd_sched)
veloxd_test(sched_governor LIBS veloxd_sched)
veloxd_test(safepath LIBS veloxd_fs)
+8 -1
View File
@@ -17,6 +17,8 @@
#include "rpc/event_loop.hpp"
#include "rpc/ndjson.hpp"
#include "rpc/uds_server.hpp"
#include "store/migrations.hpp"
#include "store/sqlite.hpp"
#include "velox_proto.hpp"
using nlohmann::json;
@@ -63,8 +65,13 @@ json call(int fd, const json& request) {
void run() {
const std::string sock = make_temp_socket_path();
auto db = velox::daemon::store::Db::open(":memory:");
CHECK(db.has_value());
if (!db) return;
CHECK(velox::daemon::store::migrate_to_head(*db).has_value());
rpc::EventLoop loop;
rpc::VeloxDispatcher dispatcher;
rpc::VeloxDispatcher dispatcher(*db);
rpc::UdsServer server(loop, dispatcher, sock);
const auto ec = server.start();
CHECK(!ec);
+1 -1
View File
@@ -123,7 +123,7 @@ void run() {
rpc::RuntimeDir rt{dir ? dir : "/tmp"};
rpc::EventLoop loop;
rpc::VeloxDispatcher dispatcher;
rpc::VeloxDispatcher dispatcher(*db);
rpc::EnvAutoApprover approver;
rpc::WsServer server(loop, dispatcher, *db, approver, rt);
const auto ec = server.start();