@wenbin_wb/dsh-bridge 2.8.7 → 2.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +70 -0
- package/README.en.md +408 -572
- package/README.md +430 -570
- package/client/client.js +3983 -3657
- package/client/index.js +4244 -4809
- package/client/mobile-styles.js +802 -0
- package/client/unlock-manager.js +142 -0
- package/docs/fix-plan-202608.md +108 -0
- package/lib/auth/login-template.js +381 -381
- package/lib/auth/manager.js +97 -22
- package/lib/bridge-rpc.js +48 -104
- package/lib/cloudflared-manager.mjs +361 -345
- package/lib/compat.js +129 -0
- package/lib/feishu/index.js +225 -222
- package/lib/feishu/node.js +433 -409
- package/lib/index.js +271 -244
- package/lib/platform/base.js +147 -156
- package/lib/platform/commands.js +221 -0
- package/lib/platform/conversation-bridge.js +816 -1570
- package/lib/platform/dsh-storage.js +117 -0
- package/lib/platform/index.js +10 -10
- package/lib/platform/message-split.js +191 -0
- package/lib/platform/session-catalog.js +372 -0
- package/lib/platform/stream-slices.js +21 -0
- package/lib/qq/index.js +312 -309
- package/lib/qq/node.js +532 -533
- package/lib/telegram/index.js +215 -212
- package/lib/telegram/node.js +348 -350
- package/lib/tunnel-client.mjs +39 -15
- package/lib/wechat/gateway.js +973 -960
- package/lib/wechat/index.js +244 -241
- package/lib/wechat/media.js +285 -281
- package/lib/wechat/node.js +352 -350
- package/package.json +6 -2
package/lib/tunnel-client.mjs
CHANGED
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
import { WebSocket } from 'ws';
|
|
3
3
|
import { request as httpRequest } from 'node:http';
|
|
4
4
|
import { connect as netConnect } from 'node:net';
|
|
5
|
-
import {
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { gzip as gzipCallback } from 'node:zlib';
|
|
7
|
+
|
|
8
|
+
const gzipAsync = promisify(gzipCallback);
|
|
6
9
|
|
|
7
10
|
const HEARTBEAT_INTERVAL = 30000;
|
|
8
11
|
const RECONNECT_DELAY = 5000;
|
|
9
12
|
const MAX_RECONNECT_ATTEMPTS = 5;
|
|
10
13
|
|
|
14
|
+
// 单响应内存上限:隧道把整个 body 缓冲进内存再 base64 传输,无上限会在大文件
|
|
15
|
+
// 下载时把进程内存拖垮(一份 body 三份内存:chunks + Buffer + base64 字符串)
|
|
16
|
+
const MAX_RESPONSE_BYTES = 32 * 1024 * 1024; // 32MB
|
|
17
|
+
|
|
11
18
|
// 大响应 gzip 压缩阈值(超过此大小的可压缩响应将被 gzip)
|
|
12
19
|
const GZIP_THRESHOLD = 102400; // 100KB
|
|
13
20
|
// 可压缩的 content-type 前缀
|
|
@@ -215,15 +222,31 @@ export class CustomTunnelClient {
|
|
|
215
222
|
return;
|
|
216
223
|
}
|
|
217
224
|
|
|
218
|
-
|
|
219
|
-
|
|
225
|
+
let responded = false;
|
|
226
|
+
const sendResponse = (statusCode, headers, body) => {
|
|
227
|
+
if (responded) return;
|
|
228
|
+
responded = true;
|
|
220
229
|
this._sendMessage({
|
|
221
|
-
type: 'response', requestId, statusCode
|
|
222
|
-
|
|
223
|
-
body: Buffer.from('Response Error').toString('base64'),
|
|
230
|
+
type: 'response', requestId, statusCode, headers,
|
|
231
|
+
body: Buffer.from(body).toString('base64'),
|
|
224
232
|
});
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
let total = 0;
|
|
236
|
+
res.on('data', (c) => {
|
|
237
|
+
chunks.push(c);
|
|
238
|
+
total += c.length;
|
|
239
|
+
if (total > MAX_RESPONSE_BYTES) {
|
|
240
|
+
sendResponse(502, { 'content-type': 'text/plain' },
|
|
241
|
+
`Response too large for tunnel (>${Math.round(MAX_RESPONSE_BYTES / 1024 / 1024)}MB cap)`);
|
|
242
|
+
res.destroy();
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
res.on('error', () => {
|
|
246
|
+
sendResponse(502, { 'content-type': 'text/plain' }, 'Response Error');
|
|
225
247
|
});
|
|
226
248
|
res.on('end', () => {
|
|
249
|
+
if (responded) return;
|
|
227
250
|
const respHeaders = Object.fromEntries(
|
|
228
251
|
Object.entries(res.headers).filter(([k]) => !SKIP.has(k.toLowerCase()))
|
|
229
252
|
);
|
|
@@ -249,21 +272,22 @@ export class CustomTunnelClient {
|
|
|
249
272
|
} catch {} // 解析失败则原样发送
|
|
250
273
|
}
|
|
251
274
|
|
|
252
|
-
// 大响应 gzip
|
|
275
|
+
// 大响应 gzip 压缩:异步执行,避免 gzipSync 卡住整个事件循环
|
|
253
276
|
const respCt = String(res.headers['content-type'] ?? '').toLowerCase();
|
|
254
277
|
const alreadyEncoded = String(res.headers['content-encoding'] ?? '').toLowerCase();
|
|
255
278
|
const compressible = COMPRESSIBLE_TYPES.some((t) => respCt.startsWith(t));
|
|
256
279
|
if (bodyBuf.length > GZIP_THRESHOLD && compressible && !alreadyEncoded) {
|
|
257
|
-
bodyBuf
|
|
258
|
-
|
|
259
|
-
|
|
280
|
+
gzipAsync(bodyBuf).then((zipped) => {
|
|
281
|
+
respHeaders['content-encoding'] = 'gzip';
|
|
282
|
+
respHeaders['content-length'] = String(zipped.length);
|
|
283
|
+
sendResponse(res.statusCode, respHeaders, zipped);
|
|
284
|
+
}).catch(() => {
|
|
285
|
+
sendResponse(res.statusCode, respHeaders, bodyBuf);
|
|
286
|
+
});
|
|
287
|
+
return;
|
|
260
288
|
}
|
|
261
289
|
|
|
262
|
-
|
|
263
|
-
type: 'response', requestId,
|
|
264
|
-
statusCode: res.statusCode, headers: respHeaders,
|
|
265
|
-
body: bodyBuf.toString('base64'),
|
|
266
|
-
});
|
|
290
|
+
sendResponse(res.statusCode, respHeaders, bodyBuf);
|
|
267
291
|
});
|
|
268
292
|
});
|
|
269
293
|
req.on('error', err => {
|