@@ -2334,14 +2334,15 @@ kj::Array<kj::byte> measureConfig(config::Worker::Reader& config) {
23342334 return digest;
23352335}
23362336
2337- class Server ::WorkerdApiService final : public Service, private WorkerInterface {
2337+ class Server ::WorkerdApiService final : public Service {
23382338 // Service used when the service is configured as network service.
23392339
23402340public:
23412341 WorkerdApiService (Server& server): server(server) {}
23422342
23432343 kj::Own<WorkerInterface> startRequest (IoChannelFactory::SubrequestMetadata metadata) override {
2344- return { this , kj::NullDisposer::instance };
2344+ auto & context = IoContext::current ();
2345+ return kj::heap<WorkerdApiRequestHandler>(*this , context.getWorker ());
23452346 }
23462347
23472348 bool hasHandler (kj::StringPtr handlerName) override {
@@ -2351,102 +2352,102 @@ public:
23512352private:
23522353 Server& server;
23532354
2354- kj::Promise<void > request (
2355- kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers,
2356- kj::AsyncInputStream& requestBody, kj::HttpService::Response& response) override {
2357- if (url == " http://workerd.local/workers" ) {
2358- return requestBody.readAllText ().then ([this , &headers, &response](auto confJson) {
2359- capnp::MallocMessageBuilder confArena;
2360- capnp::JsonCodec json;
2361- json.handleByAnnotation <config::NewWorker>();
2362- auto conf = confArena.initRoot <config::NewWorker>();
2363- json.decode (confJson, conf);
2355+ class WorkerdApiRequestHandler final : public WorkerInterface {
2356+ public:
2357+ WorkerdApiRequestHandler (WorkerdApiService& parent, const Worker& requester)
2358+ : parent(parent), requester(requester) {}
23642359
2365- kj::String id = workerd::randomUUID (kj::none);
2360+ kj::Promise<void > request (
2361+ kj::HttpMethod method, kj::StringPtr url, const kj::HttpHeaders& headers,
2362+ kj::AsyncInputStream& requestBody, kj::HttpService::Response& response) override {
2363+ if (url != " http://workerd.local/workers" ) {
2364+ auto out = response.send (404 , " Not Found" , headers, kj::none);
2365+ auto errMsg = " Unknown workerd API endpoint" _kjc.asBytes ();
2366+ co_await out->write (errMsg.begin (), errMsg.size ());
2367+ co_return ;
2368+ }
23662369
2367- server. actorConfigs . insert ( kj::str (id), {} );
2370+ auto confJson = co_await requestBody. readAllText ( );
23682371
2369- kj::Maybe<kj::Array<kj::byte>> expectedMeasurement = kj::none;
2370- if (conf.hasExpectedMeasurement ()) {
2371- auto res = kj::decodeHex (conf.getExpectedMeasurement ());
2372- if (res.hadErrors ) {
2373- auto out = response.send (400 , " Bad Request" , headers, kj::none);
2374- auto errMsg = " invalid expected measurement" _kjc.asBytes ();
2375- return out->write (errMsg.begin (), errMsg.size ());
2376- }
2377- expectedMeasurement = kj::mv (res);
2378- }
2372+ capnp::MallocMessageBuilder confArena;
2373+ capnp::JsonCodec json;
2374+ json.handleByAnnotation <config::NewWorker>();
2375+ auto conf = confArena.initRoot <config::NewWorker>();
2376+ json.decode (confJson, conf);
23792377
2380- kj::Maybe<kj::String> configError = kj::none;
2381- auto workerService = server.makeWorker (
2382- id, conf.getWorker ().asReader (), {},
2383- [&configError](auto err) { configError = kj::mv (err); },
2384- kj::mv (expectedMeasurement)
2385- );
2386- KJ_IF_SOME (err, configError) {
2387- throw KJ_EXCEPTION (FAILED, err);
2388- }
2389- auto & worker = server.services .insert (kj::str (id), kj::mv (workerService)).value ;
2390- worker->link ();
2378+ WorkerService* requesterService;
2379+ KJ_IF_SOME (svc, parent.server .services .find (requester.getName ())) {
2380+ requesterService = &kj::downcast<WorkerService>(*svc);
2381+ } else {
2382+ auto out = response.send (500 , " Internal Server Error" , headers, kj::none);
2383+ auto errMsg = " unable to locate requester service" _kjc.asBytes ();
2384+ co_await out->write (errMsg.begin (), errMsg.size ());
2385+ co_return ;
2386+ }
23912387
2392- auto resMessage = kj::heap<capnp::MallocMessageBuilder>(); // TODO: not alloc
2393- auto res = resMessage->initRoot <config::ServiceDesignator>();
2394- res.setName (id);
2395- auto resJson = json.encode (res);
2388+ kj::String id = workerd::randomUUID (kj::none);
23962389
2397- auto out = response.send (201 , " Created" , headers, kj::none);
2398- return out->write (resJson.begin (), resJson.size ()).attach (kj::mv (out), kj::mv (resJson));
2399- });
2400- } else if (url.startsWith (" http://workerd.local/workers/" _kjc) &&
2401- url.endsWith (" /events/scheduled" )) {
2402- auto workerId = url.slice (29 , 29 + 36 );
2403- return requestBody.readAllText ().then ([this , workerId = kj::mv (workerId),
2404- &headers, &response](auto confJson) {
2405- capnp::MallocMessageBuilder confArena;
2406- capnp::JsonCodec json;
2407- json.handleByAnnotation <rpc::Trace::ScheduledEventInfo>();
2408- auto event = confArena.initRoot <rpc::Trace::ScheduledEventInfo>();
2409- json.decode (confJson, event);
2410-
2411- KJ_IF_SOME (svc, server.services .find (workerId)) {
2412- IoChannelFactory::SubrequestMetadata metadata;
2413- auto worker = svc->startRequest (kj::mv (metadata));
2414- kj::Date scheduledTime = kj::UNIX_EPOCH +
2415- static_cast <long long >(event.getScheduledTime ()) * kj::MILLISECONDS;
2416- auto cron = event.getCron ();
2417- return worker->runScheduled (scheduledTime, cron)
2418- .then ([&response, &headers](auto scheduledResult) {
2419- return response.send (204 , " No Content" , headers, kj::none)->write (nullptr , 0 );
2420- }).attach (kj::mv (cron));
2421- } else {
2422- return response.send (404 , " Not Found" , headers, kj::none)->write (nullptr , 0 );
2423- }
2424- });
2425- } else {
2426- return response.send (404 , " Not Found" , headers, kj::none)->write (nullptr , 0 );
2390+ parent.server .actorConfigs .insert (kj::str (id), {});
2391+
2392+ kj::Maybe<kj::Array<kj::byte>> expectedMeasurement = kj::none;
2393+ if (conf.hasExpectedMeasurement ()) {
2394+ auto res = kj::decodeHex (conf.getExpectedMeasurement ());
2395+ if (res.hadErrors ) {
2396+ auto out = response.send (400 , " Bad Request" , headers, kj::none);
2397+ auto errMsg = " invalid expected measurement" _kjc.asBytes ();
2398+ co_await out->write (errMsg.begin (), errMsg.size ());
2399+ co_return ;
2400+ }
2401+ expectedMeasurement = kj::mv (res);
2402+ }
2403+
2404+ kj::Maybe<kj::String> configError = kj::none;
2405+ auto workerService = parent.server .makeWorker (
2406+ id, conf.getWorker ().asReader (), {},
2407+ [&configError](auto err) { configError = kj::mv (err); },
2408+ kj::mv (expectedMeasurement)
2409+ );
2410+ KJ_IF_SOME (err, configError) {
2411+ auto out = response.send (400 , " Bad Request" , headers, kj::none);
2412+ auto errMsg = kj::str (err);
2413+ co_await out->write (errMsg.begin (), errMsg.size ());
2414+ co_return ;
2415+ }
2416+ auto & worker = parent.server .services .insert (kj::str (id), kj::mv (workerService)).value ;
2417+ worker->link ();
2418+
2419+ uint newWorkerChannel = requesterService->addChannel (worker);
2420+
2421+ auto resMsg = kj::str (newWorkerChannel);
2422+ auto out = response.send (201 , " Created" , headers, kj::none);
2423+ co_await out->write (resMsg.begin (), resMsg.size ()).attach (kj::mv (out), kj::mv (resMsg));
2424+ co_return ;
24272425 }
2428- }
24292426
2430- kj::Promise<void > connect (
2431- kj::StringPtr host, const kj::HttpHeaders& headers, kj::AsyncIoStream& connection,
2432- ConnectResponse& tunnel, kj::HttpConnectSettings settings) override {
2433- throwUnsupported ();
2434- }
2427+ kj::Promise<void > connect (
2428+ kj::StringPtr host, const kj::HttpHeaders& headers, kj::AsyncIoStream& connection,
2429+ ConnectResponse& tunnel, kj::HttpConnectSettings settings) override {
2430+ throwUnsupported ();
2431+ }
2432+ void prewarm (kj::StringPtr url) override {}
2433+ kj::Promise<ScheduledResult> runScheduled (kj::Date scheduledTime, kj::StringPtr cron) override {
2434+ throwUnsupported ();
2435+ }
2436+ kj::Promise<AlarmResult> runAlarm (kj::Date scheduledTime, uint32_t retryCount) override {
2437+ throwUnsupported ();
2438+ }
2439+ kj::Promise<CustomEvent::Result> customEvent (kj::Own<CustomEvent> event) override {
2440+ throwUnsupported ();
2441+ }
24352442
2436- void prewarm (kj::StringPtr url) override {}
2437- kj::Promise<ScheduledResult> runScheduled (kj::Date scheduledTime, kj::StringPtr cron) override {
2438- throwUnsupported ();
2439- }
2440- kj::Promise<AlarmResult> runAlarm (kj::Date scheduledTime, uint32_t retryCount) override {
2441- throwUnsupported ();
2442- }
2443- kj::Promise<CustomEvent::Result> customEvent (kj::Own<CustomEvent> event) override {
2444- throwUnsupported ();
2445- }
2443+ [[noreturn]] void throwUnsupported () {
2444+ JSG_FAIL_REQUIRE (Error, " WorkerdApiService does not support this event type." );
2445+ }
24462446
2447- [[noreturn]] void throwUnsupported () {
2448- JSG_FAIL_REQUIRE (Error, " WorkerdApiService does not support this event type." );
2449- }
2447+ private:
2448+ WorkerdApiService& parent;
2449+ const Worker& requester;
2450+ };
24502451};
24512452
24522453// =======================================================================================
@@ -2609,6 +2610,9 @@ static kj::Maybe<WorkerdApi::Global> createBinding(
26092610 binding.getService (),
26102611 kj::mv (errorContext)
26112612 });
2613+ if (binding.getService ().getName () == " @workerd" ) {
2614+ return makeGlobal (Global::WorkerdApi { .subrequestChannel = channel });
2615+ }
26122616 return makeGlobal (Global::Fetcher {
26132617 .channel = channel,
26142618 .requiresHost = true ,
0 commit comments