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