refactor(serve): WS client calls app.fetch directly, no HTTP server in gateway mode
- WS client receives app.fetch function instead of localPort - Gateway mode no longer starts a local HTTP server - Local-only mode (no secret) still starts HTTP server as before - Removes unnecessary HTTP round-trip for gateway requests
This commit is contained in:
@@ -16,9 +16,8 @@ const HEARTBEAT_INTERVAL_MS = 60_000;
|
||||
export function startServer(
|
||||
storageRoot: string,
|
||||
options: ServeOptions,
|
||||
agentToken: string | null,
|
||||
): void {
|
||||
const app = createApp(storageRoot, agentToken);
|
||||
const app = createApp(storageRoot, null);
|
||||
|
||||
const server = serve({
|
||||
fetch: app.fetch,
|
||||
@@ -95,33 +94,32 @@ export async function dispatchServe(storageRoot: string, argv: string[]): Promis
|
||||
|
||||
if (options.gatewaySecret === "") {
|
||||
// No gateway — local-only mode
|
||||
startServer(storageRoot, options, null);
|
||||
startServer(storageRoot, options);
|
||||
printCliLine("no WORKFLOW_GATEWAY_SECRET — running in local-only mode");
|
||||
await new Promise(() => {});
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Gateway mode — no HTTP server, WS client calls app.fetch directly
|
||||
const agentToken = randomUUID();
|
||||
startServer(storageRoot, options, agentToken);
|
||||
const app = createApp(storageRoot, agentToken);
|
||||
|
||||
// Start WebSocket reverse connection to gateway
|
||||
const log = createLogger({ sink: { kind: "stderr" } });
|
||||
const stopWsClient = startGatewayWsClient({
|
||||
gatewayUrl: options.gatewayUrl,
|
||||
name: options.name,
|
||||
secret: options.gatewaySecret,
|
||||
localPort: options.port,
|
||||
appFetch: app.fetch,
|
||||
log,
|
||||
});
|
||||
|
||||
printCliLine("connected to gateway via WebSocket");
|
||||
printCliLine("connected to gateway via WebSocket (no local HTTP server)");
|
||||
|
||||
// Register with gateway for discovery
|
||||
const localUrl = `http://127.0.0.1:${options.port}`;
|
||||
const registered = await registerWithGateway(
|
||||
options.gatewayUrl,
|
||||
options.name,
|
||||
localUrl,
|
||||
`ws://${options.name}`,
|
||||
options.gatewaySecret,
|
||||
agentToken,
|
||||
);
|
||||
@@ -132,7 +130,7 @@ export async function dispatchServe(storageRoot: string, argv: string[]): Promis
|
||||
const heartbeatTimer = startHeartbeat(
|
||||
options.gatewayUrl,
|
||||
options.name,
|
||||
localUrl,
|
||||
`ws://${options.name}`,
|
||||
options.gatewaySecret,
|
||||
agentToken,
|
||||
HEARTBEAT_INTERVAL_MS,
|
||||
|
||||
@@ -5,7 +5,7 @@ export type GatewayWsClientParams = {
|
||||
gatewayUrl: string;
|
||||
name: string;
|
||||
secret: string;
|
||||
localPort: number;
|
||||
appFetch: (request: Request) => Response | Promise<Response>;
|
||||
log: LogFn;
|
||||
};
|
||||
|
||||
@@ -44,20 +44,17 @@ async function handleGatewayMessage(
|
||||
params.log("ZM8K2PQ1", "gateway WebSocket dropped non-request message");
|
||||
return;
|
||||
}
|
||||
const localUrl = `http://127.0.0.1:${String(params.localPort)}${req.path}`;
|
||||
const initHeaders = new Headers();
|
||||
for (const [k, v] of Object.entries(req.headers)) {
|
||||
initHeaders.set(k, v);
|
||||
}
|
||||
const localUrl = `http://localhost${req.path}`;
|
||||
const headers = new Headers(req.headers);
|
||||
let resp: Response;
|
||||
try {
|
||||
resp = await fetch(localUrl, {
|
||||
resp = await params.appFetch(new Request(localUrl, {
|
||||
method: req.method,
|
||||
headers: initHeaders,
|
||||
headers,
|
||||
body: req.body === null ? undefined : req.body,
|
||||
});
|
||||
}));
|
||||
} catch (e) {
|
||||
params.log("R4N7BQ3C", `local proxy fetch failed: ${String(e)}`);
|
||||
params.log("R4N7BQ3C", `app.fetch failed: ${String(e)}`);
|
||||
const errBody: WsResponse = {
|
||||
id: req.id,
|
||||
status: 502,
|
||||
|
||||
Reference in New Issue
Block a user