fix(telegram): explain proxy-related connection failures

This commit is contained in:
cuidong233 2026-08-24 12:17:54 +08:00
parent dea9a8f2d1
commit 860faad380
5 changed files with 146 additions and 87 deletions

View file

@ -109,6 +109,18 @@ After installation, follow the built-in instructions on each channel page to sca
If this machine must use a forward proxy to reach Feishu, set `HTTPS_PROXY` to a full HTTP proxy URL before starting `dsh web` (for example, `http://proxy:8080`; lowercase `https_proxy` is also supported, with `HTTP_PROXY` accepted as a fallback), then restart the Host after changing it. Feishu registration and credential verification reuse the SDK's proxy-aware HTTP client, while the message WebSocket explicitly uses that proxy; the WebSocket path does not currently read `ALL_PROXY` or `NO_PROXY`. If this machine must use a forward proxy to reach Feishu, set `HTTPS_PROXY` to a full HTTP proxy URL before starting `dsh web` (for example, `http://proxy:8080`; lowercase `https_proxy` is also supported, with `HTTP_PROXY` accepted as a fallback), then restart the Host after changing it. Feishu registration and credential verification reuse the SDK's proxy-aware HTTP client, while the message WebSocket explicitly uses that proxy; the WebSocket path does not currently read `ALL_PROXY` or `NO_PROXY`.
If this machine cannot reach the Telegram Bot API directly, use Node.js 22.21 or newer and enable Node's environment proxy support before starting `dsh web`:
```sh
NODE_USE_ENV_PROXY=1 \
HTTPS_PROXY=http://proxy:8080 \
HTTP_PROXY=http://proxy:8080 \
NO_PROXY=localhost,127.0.0.1 \
dsh web
```
Use the proxy URL required by your network and restart the Host after changing it. If Telegram Bot Token binding reports that the Bot API cannot be reached, first check the proxy URL, Node.js version, and `NO_PROXY` configuration.
| Default behavior | Description | | Default behavior | Description |
| --- | --- | | --- | --- |
| Bot workspace | Each bot stores its workspace independently. New bots start with the Host's current working directory, which can later be changed from the bot card. | | Bot workspace | Each bot stores its workspace independently. New bots start with the Host's current working directory, which can later be changed from the bot card. |

View file

@ -112,6 +112,18 @@ GitHub 源安装会直接拉取并构建 Git 依赖;pnpm 10 及以上版本可
如果本机必须通过正向代理访问飞书,请在启动 `dsh web` 前把 `HTTPS_PROXY` 设置为包含协议的 HTTP 代理 URL(例如 `http://proxy:8080`;也支持小写 `https_proxy`,并兼容使用 `HTTP_PROXY` 作为回退),修改后重启 Host。飞书注册和凭据验证会复用 SDK 的代理感知 HTTP 客户端,消息长连接会显式通过这个代理建立 WebSocket;长连接目前不读取 `ALL_PROXY` 或 `NO_PROXY`。 如果本机必须通过正向代理访问飞书,请在启动 `dsh web` 前把 `HTTPS_PROXY` 设置为包含协议的 HTTP 代理 URL(例如 `http://proxy:8080`;也支持小写 `https_proxy`,并兼容使用 `HTTP_PROXY` 作为回退),修改后重启 Host。飞书注册和凭据验证会复用 SDK 的代理感知 HTTP 客户端,消息长连接会显式通过这个代理建立 WebSocket;长连接目前不读取 `ALL_PROXY` 或 `NO_PROXY`。
如果本机无法直连 Telegram Bot API,请使用 Node.js 22.21 或更高版本,并在启动 `dsh web` 前启用 Node 的环境变量代理支持:
```sh
NODE_USE_ENV_PROXY=1 \
HTTPS_PROXY=http://proxy:8080 \
HTTP_PROXY=http://proxy:8080 \
NO_PROXY=localhost,127.0.0.1 \
dsh web
```
代理地址按本机网络环境填写;修改代理后需要重启 Host。绑定 Telegram Bot Token 时,如果页面提示无法访问 Bot API,请优先检查代理地址、Node.js 版本和 `NO_PROXY` 配置。
| 默认行为 | 说明 | | 默认行为 | 说明 |
| --- | --- | | --- | --- |
| 机器人工作区 | 每个机器人独立保存工作区。新机器人默认使用 Host 当时的工作目录;之后可在机器人卡片中修改。 | | 机器人工作区 | 每个机器人独立保存工作区。新机器人默认使用 Host 当时的工作目录;之后可在机器人卡片中修改。 |

File diff suppressed because one or more lines are too long

View file

@ -23,6 +23,11 @@ const ENDPOINTS = Object.freeze(Object.values(TOKEN_BOT_ENDPOINTS));
const FORBIDDEN_PUBLIC_KEYS = new Set([ const FORBIDDEN_PUBLIC_KEYS = new Set([
'token', 'botToken', 'tokenRef', 'platformId', 'secret', 'secretRef', 'token', 'botToken', 'tokenRef', 'platformId', 'secret', 'secretRef',
]); ]);
const TELEGRAM_NETWORK_ERRORS = new Set([
'telegram-transport-error',
'telegram-timeout',
'telegram-response-invalid',
]);
function isRecord(value) { function isRecord(value) {
return value !== null && typeof value === 'object' && !Array.isArray(value); return value !== null && typeof value === 'object' && !Array.isArray(value);
@ -88,6 +93,12 @@ function operationError(channel, error) {
if (error?.code === 'telegram-401' || error?.code === 'discord-401') { if (error?.code === 'telegram-401' || error?.code === 'discord-401') {
return { code: 'invalid-token', message: `${channel} Bot Token 无效,请重新填写。` }; return { code: 'invalid-token', message: `${channel} Bot Token 无效,请重新填写。` };
} }
if (channel === 'Telegram' && TELEGRAM_NETWORK_ERRORS.has(error?.code)) {
return {
code: 'telegram-network-error',
message: '无法访问 Telegram Bot API。请检查网络或代理设置;Node.js 22.21+ 可设置 NODE_USE_ENV_PROXY=1,并配置 HTTPS_PROXY、HTTP_PROXY 和 NO_PROXY,然后重启 dsh web。',
};
}
if (error?.code === 'discord-intents') { if (error?.code === 'discord-intents') {
return { code: 'discord-intents', message: error.message }; return { code: 'discord-intents', message: error.message };
} }

View file

@ -1317,6 +1317,30 @@ test('workspace RPC validates payloads and returns the updated public status', a
assert.match(missing.error.message, /不存在/); assert.match(missing.error.message, /不存在/);
}); });
test('Telegram RPC explains network and proxy failures without exposing credentials', async () => {
const token = '123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef123456';
for (const code of ['telegram-transport-error', 'telegram-timeout', 'telegram-response-invalid']) {
const controller = {
status() { return { bots: [] }; },
bindCredentials() {
const error = new Error('Telegram request failed');
error.code = code;
throw error;
},
reconnectBot() { return { bots: [] }; },
deleteBot() { return { bots: [] }; },
};
const handler = createTokenBotRpcHandler(controller, { channel: 'Telegram' });
const result = await handler(TOKEN_BOT_ENDPOINTS.bindCredentials, { token });
assert.equal(result.ok, false);
assert.equal(result.error.code, 'telegram-network-error');
assert.match(result.error.message, /Telegram Bot API/);
assert.match(result.error.message, /NODE_USE_ENV_PROXY/);
assert.doesNotMatch(result.error.message, new RegExp(token));
}
});
test('BotWorkspaceStore persists per-bot agent presets without changing workspaces', async (t) => { test('BotWorkspaceStore persists per-bot agent presets without changing workspaces', async (t) => {
const { path, defaultWorkspace, alternateWorkspace } = await fixture(t); const { path, defaultWorkspace, alternateWorkspace } = await fixture(t);
const store = await new BotWorkspaceStore(path, { defaultWorkspace }).load(); const store = await new BotWorkspaceStore(path, { defaultWorkspace }).load();