File
Blob: src/workerd/server/workerd-debug-port-client.h
| 1 | // Copyright (c) 2017-2022 Cloudflare, Inc. |
| 2 | // Licensed under the Apache 2.0 license found in the LICENSE file or at: |
| 3 | // https://opensource.org/licenses/Apache-2.0 |
| 4 | |
| 5 | #pragma once |
| 6 | |
| 7 | #include <workerd/io/io-channels.h> |
| 8 | #include <workerd/io/io-own.h> |
| 9 | #include <workerd/io/worker-interface.capnp.h> |
| 10 | #include <workerd/jsg/jsg.h> |
| 11 | |
| 12 | #include <capnp/rpc-twoparty.h> |
| 13 | |
| 14 | namespace workerd::api { |
| 15 | class Fetcher; |
| 16 | } // namespace workerd::api |
| 17 | |
| 18 | namespace workerd::server { |
| 19 | |
| 20 | // Holds the I/O state for a debug port connection: the TCP stream, capnp RPC client, |
| 21 | // and debug port capability. Refcounted to support deferred proxying - response bodies |
| 22 | // and WebSockets are proxied through the capnp connection, so it must stay alive until |
| 23 | // they're fully consumed. See WorkerdBootstrapSubrequestChannel::startRequest(). |
| 24 | class DebugPortConnectionState: public kj::Refcounted { |
| 25 | public: |
| 26 | DebugPortConnectionState(kj::Own<kj::AsyncIoStream> connection, |
| 27 | kj::Own<capnp::TwoPartyClient> rpcClient, |
| 28 | rpc::WorkerdDebugPort::Client debugPort) |
| 29 | : connection(kj::mv(connection)), |
| 30 | rpcClient(kj::mv(rpcClient)), |
| 31 | debugPort(kj::mv(debugPort)) {} |
| 32 | |
| 33 | kj::Own<DebugPortConnectionState> addRef() { |
| 34 | return kj::addRef(*this); |
| 35 | } |
| 36 | |
| 37 | kj::Own<kj::AsyncIoStream> connection; |
| 38 | kj::Own<capnp::TwoPartyClient> rpcClient; |
| 39 | rpc::WorkerdDebugPort::Client debugPort; |
| 40 | }; |
| 41 | |
| 42 | // JS interface for a connected workerd debug port. |
| 43 | // This class is returned from WorkerdDebugPortConnector::connect() and provides |
| 44 | // access to a remote workerd instance's WorkerdDebugPort RPC interface. |
| 45 | class WorkerdDebugPortClient: public jsg::Object { |
| 46 | public: |
| 47 | // Create a WorkerdDebugPortClient with an established connection. |
| 48 | // Takes an IoOwn reference to the connection state. |
| 49 | explicit WorkerdDebugPortClient(IoOwn<DebugPortConnectionState> state): state(kj::mv(state)) {} |
| 50 | |
| 51 | // Get access to a stateless entrypoint on the remote workerd instance. |
| 52 | // Uses Cap'n Proto pipelining to return a Fetcher synchronously — the actual |
| 53 | // RPC resolution is deferred until the Fetcher is first used (e.g. fetch()). |
| 54 | // |
| 55 | // @param service - The service name in the remote workerd process |
| 56 | // @param entrypoint - The entrypoint name to access (if omitted, uses the default handler) |
| 57 | // @param props - Optional props to pass to the entrypoint |
| 58 | // @returns A Fetcher that lazily resolves on first use |
| 59 | jsg::Ref<api::Fetcher> getEntrypoint(jsg::Lock& js, |
| 60 | kj::String service, |
| 61 | jsg::Optional<kj::String> entrypoint, |
| 62 | jsg::Optional<jsg::JsRef<jsg::JsObject>> props); |
| 63 | |
| 64 | // Get access to an actor (Durable Object) stub on the remote workerd instance. |
| 65 | // Uses Cap'n Proto pipelining to return a Fetcher synchronously — the actual |
| 66 | // RPC resolution is deferred until the Fetcher is first used (e.g. fetch()). |
| 67 | // |
| 68 | // @param service - The service name in the remote workerd process |
| 69 | // @param entrypoint - The entrypoint/class name to access |
| 70 | // @param actorId - The actor ID (hex string for DOs, plain string for ephemeral) |
| 71 | // @returns A Fetcher that lazily resolves on first use |
| 72 | jsg::Ref<api::Fetcher> getActor( |
| 73 | jsg::Lock& js, kj::String service, kj::String entrypoint, kj::String actorId); |
| 74 | |
| 75 | JSG_RESOURCE_TYPE(WorkerdDebugPortClient) { |
| 76 | JSG_METHOD(getEntrypoint); |
| 77 | JSG_METHOD(getActor); |
| 78 | |
| 79 | JSG_TS_ROOT(); |
| 80 | JSG_TS_OVERRIDE({ |
| 81 | getEntrypoint<T extends Rpc.WorkerEntrypointBranded | undefined>( |
| 82 | service: string, entrypoint?: string, props?: Record<string, unknown>): Fetcher<T>; |
| 83 | getActor<T extends Rpc.DurableObjectBranded | undefined>( |
| 84 | service: string, entrypoint: string, actorId: string): Fetcher<T>; |
| 85 | }); |
| 86 | } |
| 87 | |
| 88 | private: |
| 89 | IoOwn<DebugPortConnectionState> state; |
| 90 | }; |
| 91 | |
| 92 | // JS interface for the workerdDebugPort binding. |
| 93 | // This binding provides a connect() method to dynamically connect to any workerd |
| 94 | // instance's debug port. |
| 95 | class WorkerdDebugPortConnector: public jsg::Object { |
| 96 | public: |
| 97 | WorkerdDebugPortConnector() = default; |
| 98 | |
| 99 | // Connect to a remote workerd debug port at the given address. |
| 100 | // Returns synchronously using kj::newPromisedStream() to defer the TCP connection. |
| 101 | // Cap'n Proto pipelining ensures that all subsequent RPC calls (getEntrypoint, getActor) |
| 102 | // are queued until the connection is established. |
| 103 | // |
| 104 | // @param address - The address of the remote workerd debug port (e.g., "localhost:1234") |
| 105 | // @returns A WorkerdDebugPortClient that lazily connects on first use |
| 106 | jsg::Ref<WorkerdDebugPortClient> connect(jsg::Lock& js, kj::String address); |
| 107 | |
| 108 | JSG_RESOURCE_TYPE(WorkerdDebugPortConnector) { |
| 109 | JSG_METHOD(connect); |
| 110 | } |
| 111 | }; |
| 112 | |
| 113 | #define EW_WORKERD_DEBUG_PORT_CLIENT_ISOLATE_TYPES \ |
| 114 | workerd::server::WorkerdDebugPortClient, workerd::server::WorkerdDebugPortConnector |
| 115 | |
| 116 | } // namespace workerd::server |