dsh-mobile-plugin 0.4.6 → 0.4.7
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/lib/relay/tunnel.js +10 -0
- package/lib/sidecar-facade-worker.cjs +42 -6
- package/package.json +1 -1
package/lib/relay/tunnel.js
CHANGED
|
@@ -87,6 +87,10 @@ class RelayTunnel {
|
|
|
87
87
|
this.httpPumpCursor = 0;
|
|
88
88
|
this.pendingHttpResponseBytes = 0;
|
|
89
89
|
this.lastPong = 0;
|
|
90
|
+
// 对端存不存镜像:注册回执里明确说了才改,没说(老中转)按「存」处理,行为与以前一字
|
|
91
|
+
// 不差。纯转发节点(`MIRROR_CACHE=0`)收下整份镜像也只解析完丢掉,worker 据此只把
|
|
92
|
+
// 摘要推上去(lib/sidecar-facade-worker.cjs 的 digestFrame)。
|
|
93
|
+
this.relayMirror = true;
|
|
90
94
|
// 清除所有授权的等待回调(一次一个);由 requestRevokeAll 注入,revokeAllAck 触发。
|
|
91
95
|
this._revokeAllAck = null;
|
|
92
96
|
}
|
|
@@ -462,6 +466,9 @@ class RelayTunnel {
|
|
|
462
466
|
|
|
463
467
|
/** 建立连接并注册;resolve 于收到 registered,reject 于连接/注册失败 */
|
|
464
468
|
start() {
|
|
469
|
+
// 每条新连接都从「对端存镜像」重新判定:能走到推送的那一步一定已经收到过回执,
|
|
470
|
+
// 而回执缺这个字段的老中转本来就该按「存」处理。
|
|
471
|
+
this.relayMirror = true;
|
|
465
472
|
return new Promise((resolve, reject) => {
|
|
466
473
|
let settled = false;
|
|
467
474
|
const done = (fn, arg) => {
|
|
@@ -482,6 +489,9 @@ class RelayTunnel {
|
|
|
482
489
|
|
|
483
490
|
const push = createFrameDecoder((frame) => {
|
|
484
491
|
if (frame.type === T.registered) {
|
|
492
|
+
// 回执里带 `mirror`:对端说不存镜像,就只推摘要(凭据 + 两个 revision),正文不推。
|
|
493
|
+
// 老中转回的是空载荷,`parseJson` 给空对象,于是判定为「存」——与以前完全一样。
|
|
494
|
+
this.relayMirror = parseJson(frame.payload).mirror !== false;
|
|
485
495
|
clearTimeout(timer);
|
|
486
496
|
done(resolve);
|
|
487
497
|
this.onRegistered();
|
|
@@ -41,6 +41,9 @@ let tunnel = null
|
|
|
41
41
|
let lan = null
|
|
42
42
|
let tunnelState = 'off'
|
|
43
43
|
let tunnelError = null
|
|
44
|
+
// 当前这条隧道的对端存不存镜像(注册回执里报的)。false ⇒ 宿主只推摘要帧,正文不推。
|
|
45
|
+
// 未知与老中转一律按 true:那是原来的行为,别让一次漏字段把镜像功能悄悄降级。
|
|
46
|
+
let relayMirror = true
|
|
44
47
|
let lanState = 'off'
|
|
45
48
|
let lanError = null
|
|
46
49
|
// 局域网代理**实际**在监听的端口。0 = 还没起来。首选端口被占时会退到内核分配的
|
|
@@ -62,7 +65,7 @@ function lanUrlPort() { return lanBoundPort || config.lanPort }
|
|
|
62
65
|
function publishState() {
|
|
63
66
|
process.send?.({
|
|
64
67
|
type: 'state',
|
|
65
|
-
tunnel: { state: tunnelState, error: tunnelError },
|
|
68
|
+
tunnel: { state: tunnelState, error: tunnelError, mirror: relayMirror },
|
|
66
69
|
lan: { enabled: Boolean(config.lanEnabled), port: lanUrlPort(), requestedPort: config.lanPort, state: lanState, error: lanError },
|
|
67
70
|
})
|
|
68
71
|
}
|
|
@@ -122,11 +125,40 @@ const TUNNEL_SEND_MAX_BODY = 8 * 1024 * 1024 - 64 * 1024
|
|
|
122
125
|
* 裁字段而不是改推送策略:宿主那侧「推什么、什么时候推」一个字都不用改,两侧版本
|
|
123
126
|
* 不必同时上线(老 worker + 新宿主也照旧工作,只是白推;新 worker + 老宿主也照旧)。
|
|
124
127
|
*/
|
|
125
|
-
|
|
128
|
+
/**
|
|
129
|
+
* 对端不存镜像时上隧道的那一帧:只留中转还会真的读的东西。
|
|
130
|
+
*
|
|
131
|
+
* 纯转发节点(`MIRROR_CACHE=0`)的 `mirror::remember` 只留凭据摘要与时间戳,两份清单正文
|
|
132
|
+
* 解析完就丢——那是每台宿主每 5 秒几十 KB、一天上百 GB 的白推。所以对端在注册回执里说
|
|
133
|
+
* `mirror:false` 之后,清单与工作区各只留 `ok` 和 `revision`:
|
|
134
|
+
*
|
|
135
|
+
* - `ok` 必须留着,中转用它判「这份镜像是不是畸形」;
|
|
136
|
+
* - `revision` 必须留着,它是中转镜像账本里那一版的身份;
|
|
137
|
+
* - `creds` 必须留着,`/push-token` 的鉴权真源就是这本账里的摘要,丢了它上报全 403。
|
|
138
|
+
*
|
|
139
|
+
* 本地快照不受影响:`localSnapshot` 在这一帧被裁之前就已经赋值,局域网直连的读取隔离
|
|
140
|
+
* 读的是它(见 `/tunnel/send` 那一段)。
|
|
141
|
+
*/
|
|
142
|
+
function digestFrame(body) {
|
|
143
|
+
const pick = (value) => {
|
|
144
|
+
const out = { ok: true }
|
|
145
|
+
if (value && typeof value === 'object' && typeof value.revision === 'string') out.revision = value.revision
|
|
146
|
+
return out
|
|
147
|
+
}
|
|
148
|
+
return {
|
|
149
|
+
kind: 'sync',
|
|
150
|
+
at: body.at,
|
|
151
|
+
sessions: pick(body.sessions),
|
|
152
|
+
workspaces: pick(body.workspaces),
|
|
153
|
+
creds: Array.isArray(body.creds) ? body.creds : [],
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function frameForTunnel(body, mirrorOff = false) {
|
|
126
158
|
if (!body || typeof body !== 'object') return { kind: 'raw', data: body }
|
|
127
159
|
if (body.kind !== 'sync') return body
|
|
128
160
|
const { messages, stats, models, ...rest } = body
|
|
129
|
-
return rest
|
|
161
|
+
return mirrorOff ? digestFrame(rest) : rest
|
|
130
162
|
}
|
|
131
163
|
// /configure 只送 relay.json 那几十个字段,给 64KB 绰绰有余;放宽只会让误用更难发现。
|
|
132
164
|
const CONFIGURE_MAX_BODY = 64 * 1024
|
|
@@ -255,6 +287,8 @@ function stopTunnel() {
|
|
|
255
287
|
reconnect.cancel()
|
|
256
288
|
if (tunnel) tunnel.stop()
|
|
257
289
|
tunnel = null; tunnelState = 'off'; tunnelError = null
|
|
290
|
+
// 断开即忘掉上一台中转的口径:下次连的可能是另一台,别拿旧的判断去决定推不推正文。
|
|
291
|
+
relayMirror = true
|
|
258
292
|
publishState()
|
|
259
293
|
}
|
|
260
294
|
function startNetworkMonitor() {
|
|
@@ -297,8 +331,10 @@ function openTunnel() {
|
|
|
297
331
|
// 「bg queue: sidecar facade request failed: 503」刷屏,而隧道其实在正常转发会话)。
|
|
298
332
|
onRegistered: () => {
|
|
299
333
|
// 注册成功 = 链路真的通了:连续失败账清零,下次掉线重新从 5s 起算。
|
|
334
|
+
// 回执里的镜像口径(`relayMirror`)跟着状态一起改、一起播,同样只在这道身份闸之内:
|
|
335
|
+
// 旧实例迟到的回执不许改新连接的口径。
|
|
300
336
|
if (tunnel !== current) return; reconnect.reset()
|
|
301
|
-
tunnelState = 'connected'; tunnelError = null; publishState()
|
|
337
|
+
tunnelState = 'connected'; tunnelError = null; relayMirror = current.relayMirror !== false; publishState()
|
|
302
338
|
},
|
|
303
339
|
onClose: () => { if (tunnel === current && config.enabled) { tunnelState = 'error'; tunnelError = '连接断开'; publishState(); scheduleReconnect() } },
|
|
304
340
|
onPairRequest: async (message) => {
|
|
@@ -444,7 +480,7 @@ function status() {
|
|
|
444
480
|
// 量不到的一律报 null、不拿 0 顶替:0 是「一条都没有」,与「不知道」是两件事。
|
|
445
481
|
const lanStreams = lan && typeof lan.stats === 'function' ? lan.stats() : null
|
|
446
482
|
const relaySseOpen = tunnel ? (typeof tunnel.upstreamSseCount === 'number' ? tunnel.upstreamSseCount : null) : 0
|
|
447
|
-
return { ok: true, sidecar: true, enabled: Boolean(config.enabled), relayUrl: config.relayUrl || '', instanceId: config.instanceId, name: config.name, localPort: config.upstreamPort, tunnel: { state: tunnelState, error: tunnelError }, lan: { enabled: Boolean(config.lanEnabled), port: lanUrlPort(), requestedPort: config.lanPort, state: lanState, error: lanError }, process: { memoryUsage: process.memoryUsage() }, streams: { lan: lanStreams, relaySseOpen } }
|
|
483
|
+
return { ok: true, sidecar: true, enabled: Boolean(config.enabled), relayUrl: config.relayUrl || '', instanceId: config.instanceId, name: config.name, localPort: config.upstreamPort, tunnel: { state: tunnelState, error: tunnelError, mirror: relayMirror }, lan: { enabled: Boolean(config.lanEnabled), port: lanUrlPort(), requestedPort: config.lanPort, state: lanState, error: lanError }, process: { memoryUsage: process.memoryUsage() }, streams: { lan: lanStreams, relaySseOpen } }
|
|
448
484
|
}
|
|
449
485
|
const server = http.createServer(async (req, res) => {
|
|
450
486
|
try {
|
|
@@ -470,7 +506,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
470
506
|
const frameType = body && typeof body === 'object' && body.kind === 'push'
|
|
471
507
|
? (body.pushFrame === 'register' ? T.pushRegister : T.pushSend)
|
|
472
508
|
: T.sync;
|
|
473
|
-
tunnel.sendJson(frameType, 0, frameForTunnel(body));
|
|
509
|
+
tunnel.sendJson(frameType, 0, frameForTunnel(body, relayMirror === false));
|
|
474
510
|
return send(res, 202, { ok: true });
|
|
475
511
|
}
|
|
476
512
|
return send(res, 503, { ok: false, error: 'tunnel not connected' });
|
package/package.json
CHANGED