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:
@@ -60,12 +60,14 @@ json rpc_error(const json& id, proto::ErrorCode code, std::string_view msg, json
|
||||
} // namespace
|
||||
|
||||
WsServer::WsServer(EventLoop& loop, proto::Dispatcher& dispatcher, store::Db& db,
|
||||
PairingApprover& approver, EventHub& hub, RuntimeDir runtime)
|
||||
PairingApprover& approver, EventHub& hub, RuntimeDir runtime,
|
||||
TaskActionPort* actions)
|
||||
: loop_(loop),
|
||||
dispatcher_(dispatcher),
|
||||
db_(db),
|
||||
approver_(approver),
|
||||
hub_(hub),
|
||||
actions_(actions),
|
||||
runtime_(std::move(runtime)) {}
|
||||
|
||||
WsServer::~WsServer() {
|
||||
@@ -261,10 +263,45 @@ void WsServer::handle_rpc(Conn& c, const std::string& text) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (method == "download.probe") {
|
||||
handle_download_probe(c, req);
|
||||
return;
|
||||
}
|
||||
|
||||
json reply = proto::dispatch(dispatcher_, proto::Transport::Ws, req);
|
||||
if (!reply.is_null()) send_text(c, reply);
|
||||
}
|
||||
|
||||
void WsServer::handle_download_probe(Conn& c, const json& request) {
|
||||
const json id = request.contains("id") ? request.at("id") : json(nullptr);
|
||||
const json params_json = request.contains("params") ? request.at("params") : json::object();
|
||||
|
||||
auto parsed = proto::parse<proto::DownloadProbeParams>(params_json, "params");
|
||||
if (!parsed) {
|
||||
send_text(c, rpc_error(id, proto::ErrorCode::InvalidParams, parsed.error().message,
|
||||
json{{"path", parsed.error().path}}));
|
||||
return;
|
||||
}
|
||||
if (!actions_) {
|
||||
send_text(c, rpc_error(id, proto::ErrorCode::InternalError,
|
||||
"not implemented in this build: download.probe"));
|
||||
return;
|
||||
}
|
||||
|
||||
const int fd = c.fd;
|
||||
actions_->probe_now(
|
||||
*parsed, [this, fd, id](proto::HandlerResult<proto::DownloadProbeResult> r) {
|
||||
auto it = conns_.find(fd);
|
||||
if (it == conns_.end()) return; // client gone while the probe was outstanding
|
||||
if (r) {
|
||||
send_text(*it->second, proto::make_result(id, *r));
|
||||
} else {
|
||||
send_text(*it->second,
|
||||
rpc_error(id, r.error().code, r.error().message, r.error().data));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool WsServer::handle_session_ws(Conn& c, const std::string& method, const json& request,
|
||||
json& reply) {
|
||||
const json id = request.contains("id") ? request.at("id") : json(nullptr);
|
||||
|
||||
Reference in New Issue
Block a user