daemon: D2 — download.probe, genuinely async on both transports
download.probe was a stub (-32603). It needs an HTTP round trip on the engine's probe
pool (up to the schema's 30s x-deadlineMs), which cannot fit VeloxDispatcher's
synchronous on_download_probe -> HandlerResult<T> return without blocking the RPC
loop for the duration — a hard no per CLAUDE.md ("never block the RPC loop") and
AGENT-DAEMON.md build step 1.
uds_server.cpp and ws_server.cpp special-case "download.probe" before the generic
dispatch(), exactly the way they already special-case session.hello/session.subscribe:
parse the params, call the port, and queue the reply whenever the callback fires
(dropped silently if the connection is gone by then).
rpc::TaskActionPort gains probe_now(DownloadProbeParams, callback) — kept in proto/std
terms, no vdm::net::* in the signature, so veloxd_rpc never needs core/include's vdm
headers just to declare this. sched::Scheduler::probe_now is the implementation:
builds a vdm::net::ProbeRequest, runs it on the engine's probe pool, marshals the
engine-thread callback back onto the loop (deps_.post_to_loop, same as every other
engine callback here), maps a probe failure to -32013 ProbeFailed (data.httpStatus set
when there was an HTTP response), and fills suggestedCategoryId/suggestedSaveDir with a
plain extension match against the categories table — not the real rules engine, which
is still D3; noted in a comment.
Verified against real veloxd + tools/testserver, not just unit tests: a real probe
answers in ~5ms with size/resumable/etag/redirect chain; a bad host maps to -32013;
and — the actual point of the async design — a connection running a 10s slow-loris
probe does not block a second connection's download.list, which answers in ~1ms while
the probe is still outstanding.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01GRDjHGgpYmMoPE2UFbe7pP
This commit is contained in:
@@ -361,6 +361,51 @@ void run() {
|
||||
tasks.remove("uc1");
|
||||
CHECK(db->exec("UPDATE queues SET state='stopped' WHERE queue_id='main'").has_value());
|
||||
}
|
||||
|
||||
// --- probe_now: success (with a category guess) and a mapped failure ------------
|
||||
{
|
||||
FakeEnginePort engine;
|
||||
Scheduler sched(*db, engine,
|
||||
Governor(GovernorConfig{.max_concurrent_downloads = 10,
|
||||
.max_active_segments = 32}));
|
||||
|
||||
vdm::net::ProbeResult pr;
|
||||
pr.effective_url = "https://cdn.example/movie.mp4";
|
||||
pr.filename_from_url = "movie.mp4"; // suggest_filename() needs this set; the real
|
||||
// Prober fills it from the URL path itself
|
||||
pr.total_size = 123456;
|
||||
pr.mime = "video/mp4";
|
||||
pr.resumable = true;
|
||||
pr.accept_ranges = true;
|
||||
pr.etag = "\"abc\"";
|
||||
engine.auto_probe_result = vdm::Result<vdm::net::ProbeResult>{pr};
|
||||
|
||||
velox::proto::DownloadProbeParams params;
|
||||
params.url = "https://cdn.example/movie.mp4";
|
||||
std::optional<velox::proto::HandlerResult<velox::proto::DownloadProbeResult>> got;
|
||||
sched.probe_now(params, [&](auto r) { got = std::move(r); });
|
||||
CHECK(got.has_value());
|
||||
CHECK(got->has_value());
|
||||
if (got && *got) {
|
||||
const auto& r = **got;
|
||||
CHECK_EQ(r.sizeBytes.value_or(-1), std::int64_t{123456});
|
||||
CHECK(r.resumable);
|
||||
CHECK_EQ(r.mime, std::string("video/mp4"));
|
||||
// movie.mp4 -> the 'video' built-in category by extension.
|
||||
CHECK_EQ(r.suggestedCategoryId, std::string("video"));
|
||||
}
|
||||
|
||||
vdm::ErrorInfo err;
|
||||
err.code = vdm::Error::connect_failed;
|
||||
err.context = "connection refused";
|
||||
engine.auto_probe_result = vdm::Result<vdm::net::ProbeResult>{err};
|
||||
std::optional<velox::proto::HandlerResult<velox::proto::DownloadProbeResult>> got2;
|
||||
sched.probe_now(params, [&](auto r) { got2 = std::move(r); });
|
||||
CHECK(got2.has_value());
|
||||
CHECK(!got2->has_value());
|
||||
if (got2 && !*got2)
|
||||
CHECK(got2->error().code == velox::proto::ErrorCode::ProbeFailed);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_MAIN()
|
||||
|
||||
Reference in New Issue
Block a user