mirror of https://github.com/openclaw/openclaw.git
fix: keep Discord proxy fallback local (#57465) (thanks @geekhuashan)
This commit is contained in:
parent
3a4fd62135
commit
86ff57518f
|
|
@ -38,6 +38,7 @@ Docs: https://docs.openclaw.ai
|
|||
- Slack/app manifest: add the missing `groups:read` scope to the onboarding and example Slack app manifest so apps copied from the OpenClaw templates can resolve private group conversations reliably.
|
||||
- Mobile pairing/Android: stop generating Tailscale and public mobile setup codes that point at unusable cleartext remote gateways, keep private LAN pairing allowed, and make Android reject insecure remote endpoints with clearer guidance while mixed bootstrap approvals honor operator scopes correctly. (#60128) Thanks @obviyus.
|
||||
- Telegram/media: add `channels.telegram.network.dangerouslyAllowPrivateNetwork` for trusted fake-IP or transparent-proxy environments where Telegram media downloads resolve `api.telegram.org` to private/internal/special-use addresses.
|
||||
- Discord/proxy: keep Carbon REST, monitor startup, and webhook sends on the configured Discord proxy while falling back cleanly when the proxy URL is invalid, so Discord replies and deploys do not hard-fail on malformed proxy config. (#57465) Thanks @geekhuashan.
|
||||
|
||||
## 2026.4.2
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,23 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../../../src/config/config.js";
|
||||
import { createDiscordRestClient } from "./client.js";
|
||||
|
||||
const makeProxyFetchMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("openclaw/plugin-sdk/infra-runtime", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("openclaw/plugin-sdk/infra-runtime")>();
|
||||
makeProxyFetchMock.mockImplementation((proxyUrl: string) => {
|
||||
if (proxyUrl === "bad-proxy") {
|
||||
throw new Error("bad proxy");
|
||||
}
|
||||
return actual.makeProxyFetch(proxyUrl);
|
||||
});
|
||||
return {
|
||||
...actual,
|
||||
makeProxyFetch: makeProxyFetchMock,
|
||||
};
|
||||
});
|
||||
|
||||
describe("createDiscordRestClient proxy support", () => {
|
||||
it("injects a custom fetch into RequestClient when a Discord proxy is configured", () => {
|
||||
const cfg = {
|
||||
|
|
@ -39,4 +55,23 @@ describe("createDiscordRestClient proxy support", () => {
|
|||
|
||||
expect(requestClient.options?.fetch).toBeUndefined();
|
||||
});
|
||||
|
||||
it("falls back to direct fetch when the Discord proxy URL is invalid", () => {
|
||||
const cfg = {
|
||||
channels: {
|
||||
discord: {
|
||||
token: "Bot test-token",
|
||||
proxy: "bad-proxy",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
const { rest } = createDiscordRestClient({}, cfg);
|
||||
const requestClient = rest as unknown as {
|
||||
options?: { fetch?: typeof fetch };
|
||||
};
|
||||
|
||||
expect(makeProxyFetchMock).toHaveBeenCalledWith("bad-proxy");
|
||||
expect(requestClient.options?.fetch).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { loadConfig } from "openclaw/plugin-sdk/config-runtime";
|
|||
import { makeProxyFetch } from "openclaw/plugin-sdk/infra-runtime";
|
||||
import type { RetryConfig, RetryRunner } from "openclaw/plugin-sdk/retry-runtime";
|
||||
import { normalizeAccountId } from "openclaw/plugin-sdk/routing";
|
||||
import { danger, type RuntimeEnv } from "openclaw/plugin-sdk/runtime-env";
|
||||
import {
|
||||
mergeDiscordAccountConfig,
|
||||
resolveDiscordAccount,
|
||||
|
|
@ -46,24 +47,41 @@ function resolveDiscordProxyUrl(
|
|||
return trimmed || undefined;
|
||||
}
|
||||
|
||||
function resolveDiscordProxyFetchByUrl(
|
||||
proxyUrl: string | undefined,
|
||||
runtime?: Pick<RuntimeEnv, "error">,
|
||||
): typeof fetch | undefined {
|
||||
const proxy = proxyUrl?.trim();
|
||||
if (!proxy) {
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
return makeProxyFetch(proxy);
|
||||
} catch (err) {
|
||||
runtime?.error?.(danger(`discord: invalid rest proxy: ${String(err)}`));
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveDiscordProxyFetchForAccount(
|
||||
account: Pick<ResolvedDiscordAccount, "config">,
|
||||
cfg?: ReturnType<typeof loadConfig>,
|
||||
runtime?: Pick<RuntimeEnv, "error">,
|
||||
): typeof fetch | undefined {
|
||||
const proxy = resolveDiscordProxyUrl(account, cfg);
|
||||
return proxy ? makeProxyFetch(proxy) : undefined;
|
||||
return resolveDiscordProxyFetchByUrl(resolveDiscordProxyUrl(account, cfg), runtime);
|
||||
}
|
||||
|
||||
export function resolveDiscordProxyFetch(
|
||||
opts: Pick<DiscordClientOpts, "cfg" | "accountId">,
|
||||
cfg?: ReturnType<typeof loadConfig>,
|
||||
runtime?: Pick<RuntimeEnv, "error">,
|
||||
): typeof fetch | undefined {
|
||||
const resolvedCfg = opts.cfg ?? cfg ?? loadConfig();
|
||||
const account = resolveAccountWithoutToken({
|
||||
cfg: resolvedCfg,
|
||||
accountId: opts.accountId,
|
||||
});
|
||||
return resolveDiscordProxyFetchForAccount(account, resolvedCfg);
|
||||
return resolveDiscordProxyFetchForAccount(account, resolvedCfg, runtime);
|
||||
}
|
||||
|
||||
function resolveRest(
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
|
|||
const discordAccountThreadBindings =
|
||||
cfg.channels?.discord?.accounts?.[account.accountId]?.threadBindings;
|
||||
const discordRestFetch = resolveDiscordRestFetch(rawDiscordCfg.proxy, runtime);
|
||||
const discordProxyFetch = resolveDiscordProxyFetchForAccount(account, cfg);
|
||||
const discordProxyFetch = resolveDiscordProxyFetchForAccount(account, cfg, runtime);
|
||||
const dmConfig = rawDiscordCfg.dm;
|
||||
let guildEntries = rawDiscordCfg.guilds;
|
||||
const defaultGroupPolicy = resolveDefaultGroupPolicy(cfg);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,36 @@ vi.mock("openclaw/plugin-sdk/infra-runtime", async (importOriginal) => {
|
|||
});
|
||||
|
||||
describe("sendWebhookMessageDiscord proxy support", () => {
|
||||
it("falls back to global fetch when the Discord proxy URL is invalid", async () => {
|
||||
makeProxyFetchMock.mockImplementation(() => {
|
||||
throw new Error("bad proxy");
|
||||
});
|
||||
const globalFetchMock = vi
|
||||
.spyOn(globalThis, "fetch")
|
||||
.mockResolvedValue(new Response(JSON.stringify({ id: "msg-0" }), { status: 200 }));
|
||||
|
||||
const cfg = {
|
||||
channels: {
|
||||
discord: {
|
||||
token: "Bot test-token",
|
||||
proxy: "bad-proxy",
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig;
|
||||
|
||||
await sendWebhookMessageDiscord("hello", {
|
||||
cfg,
|
||||
accountId: "default",
|
||||
webhookId: "123",
|
||||
webhookToken: "abc",
|
||||
wait: true,
|
||||
});
|
||||
|
||||
expect(makeProxyFetchMock).toHaveBeenCalledWith("bad-proxy");
|
||||
expect(globalFetchMock).toHaveBeenCalledOnce();
|
||||
globalFetchMock.mockRestore();
|
||||
});
|
||||
|
||||
it("uses proxy fetch when a Discord proxy is configured", async () => {
|
||||
const proxiedFetch = vi
|
||||
.fn()
|
||||
|
|
|
|||
Loading…
Reference in New Issue