Discord: add gateway proxy support

Conflicts:
	package.json
	pnpm-lock.yaml
	src/config/schema.ts
	src/discord/monitor/provider.ts
This commit is contained in:
ludd50155
2026-02-06 20:27:34 +08:00
committed by Shadow
parent 7f0489e473
commit 0cb69b0f28
5 changed files with 56 additions and 9 deletions

View File

@@ -139,6 +139,7 @@
"express": "^5.2.1",
"file-type": "^21.3.0",
"grammy": "^1.40.0",
"https-proxy-agent": "^7.0.6",
"jiti": "^2.6.1",
"json5": "^2.2.3",
"jszip": "^3.10.1",

3
pnpm-lock.yaml generated
View File

@@ -109,6 +109,9 @@ importers:
grammy:
specifier: ^1.40.0
version: 1.40.0
https-proxy-agent:
specifier: ^7.0.6
version: 7.0.6
jiti:
specifier: ^2.6.1
version: 2.6.1

View File

@@ -123,6 +123,8 @@ export type DiscordAccountConfig = {
/** If false, do not start this Discord account. Default: true. */
enabled?: boolean;
token?: string;
/** HTTP(S) proxy URL for Discord gateway WebSocket connections. */
proxy?: string;
/** Allow bot-authored messages to trigger replies (default: false). */
allowBots?: boolean;
/**

View File

@@ -266,6 +266,7 @@ export const DiscordAccountSchema = z
commands: ProviderCommandsSchema,
configWrites: z.boolean().optional(),
token: z.string().optional().register(sensitive),
proxy: z.string().optional(),
allowBots: z.boolean().optional(),
groupPolicy: GroupPolicySchema.optional().default("allowlist"),
historyLimit: z.number().int().min(0).optional(),

View File

@@ -1,9 +1,12 @@
import { Client, type BaseMessageInteractiveComponent } from "@buape/carbon";
import { GatewayIntents, GatewayPlugin } from "@buape/carbon/gateway";
import { Routes } from "discord-api-types/v10";
import { HttpsProxyAgent } from "https-proxy-agent";
import { inspect } from "node:util";
import WebSocket from "ws";
import type { HistoryEntry } from "../../auto-reply/reply/history.js";
import type { OpenClawConfig, ReplyToMode } from "../../config/config.js";
import type { DiscordAccountConfig } from "../../config/types.js";
import type { RuntimeEnv } from "../../runtime.js";
import { resolveTextChunkLimit } from "../../auto-reply/chunk.js";
import { listNativeCommandSpecsForConfig } from "../../auto-reply/commands-registry.js";
@@ -53,6 +56,51 @@ export type MonitorDiscordOpts = {
replyToMode?: ReplyToMode;
};
function createDiscordGatewayPlugin(params: {
discordConfig: DiscordAccountConfig;
runtime: RuntimeEnv;
}): GatewayPlugin {
const intents = resolveDiscordGatewayIntents(params.discordConfig?.intents);
const proxy = params.discordConfig?.proxy?.trim();
const options = {
reconnect: { maxAttempts: Number.POSITIVE_INFINITY },
intents,
autoInteractions: true,
};
if (!proxy) {
return new GatewayPlugin(options);
}
let agent: HttpsProxyAgent | undefined;
try {
agent = new HttpsProxyAgent(proxy);
} catch (err) {
params.runtime.error?.(danger(`discord: invalid gateway proxy: ${String(err)}`));
return new GatewayPlugin(options);
}
params.runtime.log?.("discord: gateway proxy enabled");
class ProxyGatewayPlugin extends GatewayPlugin {
#proxyAgent: HttpsProxyAgent;
constructor(proxyAgent: HttpsProxyAgent) {
super(options);
this.#proxyAgent = proxyAgent;
}
createWebSocket(url?: string) {
if (!url) {
throw new Error("Gateway URL is required");
}
return new WebSocket(url, { agent: this.#proxyAgent });
}
}
return new ProxyGatewayPlugin(agent);
}
function summarizeAllowList(list?: Array<string | number>) {
if (!list || list.length === 0) {
return "any";
@@ -527,15 +575,7 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
listeners: [],
components,
},
[
new GatewayPlugin({
reconnect: {
maxAttempts: 50,
},
intents: resolveDiscordGatewayIntents(discordCfg.intents),
autoInteractions: true,
}),
],
[createDiscordGatewayPlugin({ discordConfig: discordCfg, runtime })],
);
await deployDiscordCommands({ client, runtime, enabled: nativeEnabled });