mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-29 16:45:03 +00:00
refactor(gateway): unify control-ui and plugin webhook routing
This commit is contained in:
@@ -146,6 +146,22 @@ function writeUpgradeAuthFailure(
|
||||
|
||||
export type HooksRequestHandler = (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
|
||||
|
||||
type GatewayHttpRequestStage = {
|
||||
name: string;
|
||||
run: () => Promise<boolean> | boolean;
|
||||
};
|
||||
|
||||
async function runGatewayHttpRequestStages(
|
||||
stages: readonly GatewayHttpRequestStage[],
|
||||
): Promise<boolean> {
|
||||
for (const stage of stages) {
|
||||
if (await stage.run()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function createHooksRequestHandler(
|
||||
opts: {
|
||||
getHooksConfig: () => HooksConfigResolved | null;
|
||||
@@ -429,113 +445,144 @@ export function createGatewayHttpServer(opts: {
|
||||
req.url = scopedCanvas.rewrittenUrl;
|
||||
}
|
||||
const requestPath = new URL(req.url ?? "/", "http://localhost").pathname;
|
||||
if (await handleHooksRequest(req, res)) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
await handleToolsInvokeHttpRequest(req, res, {
|
||||
auth: resolvedAuth,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
rateLimiter,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (await handleSlackHttpRequest(req, res)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const requestStages: GatewayHttpRequestStage[] = [
|
||||
{
|
||||
name: "hooks",
|
||||
run: () => handleHooksRequest(req, res),
|
||||
},
|
||||
{
|
||||
name: "tools-invoke",
|
||||
run: () =>
|
||||
handleToolsInvokeHttpRequest(req, res, {
|
||||
auth: resolvedAuth,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
rateLimiter,
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "slack",
|
||||
run: () => handleSlackHttpRequest(req, res),
|
||||
},
|
||||
];
|
||||
|
||||
if (openResponsesEnabled) {
|
||||
if (
|
||||
await handleOpenResponsesHttpRequest(req, res, {
|
||||
auth: resolvedAuth,
|
||||
config: openResponsesConfig,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
rateLimiter,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
requestStages.push({
|
||||
name: "openresponses",
|
||||
run: () =>
|
||||
handleOpenResponsesHttpRequest(req, res, {
|
||||
auth: resolvedAuth,
|
||||
config: openResponsesConfig,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
rateLimiter,
|
||||
}),
|
||||
});
|
||||
}
|
||||
if (openAiChatCompletionsEnabled) {
|
||||
if (
|
||||
await handleOpenAiHttpRequest(req, res, {
|
||||
auth: resolvedAuth,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
rateLimiter,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
requestStages.push({
|
||||
name: "openai",
|
||||
run: () =>
|
||||
handleOpenAiHttpRequest(req, res, {
|
||||
auth: resolvedAuth,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
rateLimiter,
|
||||
}),
|
||||
});
|
||||
}
|
||||
if (canvasHost) {
|
||||
if (isCanvasPath(requestPath)) {
|
||||
const ok = await authorizeCanvasRequest({
|
||||
req,
|
||||
auth: resolvedAuth,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
clients,
|
||||
canvasCapability: scopedCanvas.capability,
|
||||
malformedScopedPath: scopedCanvas.malformedScopedPath,
|
||||
rateLimiter,
|
||||
});
|
||||
if (!ok.ok) {
|
||||
sendGatewayAuthFailure(res, ok);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (await handleA2uiHttpRequest(req, res)) {
|
||||
return;
|
||||
}
|
||||
if (await canvasHost.handleHttpRequest(req, res)) {
|
||||
return;
|
||||
}
|
||||
requestStages.push({
|
||||
name: "canvas-auth",
|
||||
run: async () => {
|
||||
if (!isCanvasPath(requestPath)) {
|
||||
return false;
|
||||
}
|
||||
const ok = await authorizeCanvasRequest({
|
||||
req,
|
||||
auth: resolvedAuth,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
clients,
|
||||
canvasCapability: scopedCanvas.capability,
|
||||
malformedScopedPath: scopedCanvas.malformedScopedPath,
|
||||
rateLimiter,
|
||||
});
|
||||
if (!ok.ok) {
|
||||
sendGatewayAuthFailure(res, ok);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
requestStages.push({
|
||||
name: "a2ui",
|
||||
run: () => handleA2uiHttpRequest(req, res),
|
||||
});
|
||||
requestStages.push({
|
||||
name: "canvas-http",
|
||||
run: () => canvasHost.handleHttpRequest(req, res),
|
||||
});
|
||||
}
|
||||
if (controlUiEnabled) {
|
||||
if (
|
||||
handleControlUiAvatarRequest(req, res, {
|
||||
basePath: controlUiBasePath,
|
||||
resolveAvatar: (agentId) => resolveAgentAvatar(configSnapshot, agentId),
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
if (
|
||||
handleControlUiHttpRequest(req, res, {
|
||||
basePath: controlUiBasePath,
|
||||
config: configSnapshot,
|
||||
root: controlUiRoot,
|
||||
})
|
||||
) {
|
||||
return;
|
||||
}
|
||||
requestStages.push({
|
||||
name: "control-ui-avatar",
|
||||
run: () =>
|
||||
handleControlUiAvatarRequest(req, res, {
|
||||
basePath: controlUiBasePath,
|
||||
resolveAvatar: (agentId) => resolveAgentAvatar(configSnapshot, agentId),
|
||||
}),
|
||||
});
|
||||
requestStages.push({
|
||||
name: "control-ui-http",
|
||||
run: () =>
|
||||
handleControlUiHttpRequest(req, res, {
|
||||
basePath: controlUiBasePath,
|
||||
config: configSnapshot,
|
||||
root: controlUiRoot,
|
||||
}),
|
||||
});
|
||||
}
|
||||
// Plugins run after built-in gateway routes so core surfaces keep
|
||||
// precedence on overlapping paths.
|
||||
if (handlePluginRequest) {
|
||||
if (
|
||||
(shouldEnforcePluginGatewayAuth ?? shouldEnforceDefaultPluginGatewayAuth)(requestPath)
|
||||
) {
|
||||
const pluginAuthOk = await enforcePluginRouteGatewayAuth({
|
||||
req,
|
||||
res,
|
||||
auth: resolvedAuth,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
rateLimiter,
|
||||
});
|
||||
if (!pluginAuthOk) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (await handlePluginRequest(req, res)) {
|
||||
return;
|
||||
}
|
||||
requestStages.push({
|
||||
name: "plugin-auth",
|
||||
run: async () => {
|
||||
if (
|
||||
!(shouldEnforcePluginGatewayAuth ?? shouldEnforceDefaultPluginGatewayAuth)(
|
||||
requestPath,
|
||||
)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const pluginAuthOk = await enforcePluginRouteGatewayAuth({
|
||||
req,
|
||||
res,
|
||||
auth: resolvedAuth,
|
||||
trustedProxies,
|
||||
allowRealIpFallback,
|
||||
rateLimiter,
|
||||
});
|
||||
if (!pluginAuthOk) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
});
|
||||
requestStages.push({
|
||||
name: "plugin-http",
|
||||
run: () => handlePluginRequest(req, res),
|
||||
});
|
||||
}
|
||||
if (handleGatewayProbeRequest(req, res, requestPath)) {
|
||||
|
||||
requestStages.push({
|
||||
name: "gateway-probes",
|
||||
run: () => handleGatewayProbeRequest(req, res, requestPath),
|
||||
});
|
||||
|
||||
if (await runGatewayHttpRequestStages(requestStages)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user