dsh-mobile-plugin 0.5.24 → 0.5.27
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/README.md +6 -6
- package/knowledge/apps/alipay.md +30 -0
- package/knowledge/apps/android-settings.md +30 -0
- package/knowledge/apps/bilibili.md +30 -0
- package/knowledge/apps/boss-zhipin.md +32 -0
- package/knowledge/apps/douyin.md +32 -0
- package/knowledge/apps/taobao.md +33 -0
- package/knowledge/apps/wechat.md +33 -0
- package/knowledge/apps/weibo.md +31 -0
- package/knowledge/apps/xiaohongshu.md +29 -0
- package/knowledge/apps/zhihu.md +30 -0
- package/knowledge/sites/bilibili.com.md +27 -0
- package/knowledge/sites/github.com.md +27 -0
- package/knowledge/sites/x.com.md +28 -0
- package/knowledge/sites/xiaohongshu.com.md +27 -0
- package/knowledge/sites/youtube.com.md +28 -0
- package/knowledge/sites/zhihu.com.md +27 -0
- package/lib/impl.js +9 -0
- package/lib/mobile/cli/acp.js +3 -2
- package/lib/mobile/phone/confirm.js +189 -0
- package/lib/mobile/phone/index.js +21 -1
- package/lib/mobile/phone/irreversible.js +146 -0
- package/lib/mobile/phone/pacing.js +173 -0
- package/lib/mobile/phone/route-hint.js +164 -0
- package/lib/mobile/phone/routes-memory.js +133 -0
- package/lib/mobile/phone/routes.js +84 -0
- package/lib/mobile/phone/service.js +90 -5
- package/lib/mobile/phone/tools.js +1190 -64
- package/lib/mobile/phone-knowledge.js +301 -0
- package/lib/mobile/schedule.js +64 -7
- package/lib/mobile/sessions.js +40 -5
- package/lib/mobile/wechat.js +26 -1
- package/lib/p2p/rendezvous.cjs +118 -0
- package/lib/p2p/session.cjs +595 -0
- package/lib/p2p/wiring.cjs +117 -0
- package/lib/panel/index.html +10 -10
- package/lib/relay/status.js +2 -0
- package/lib/routes/control-plane.js +24 -1
- package/lib/routes/mobile-api.js +20 -1
- package/lib/shared/e2ee-request.js +27 -7
- package/lib/tailcat/host-process.cjs +54 -1
- package/package.json +4 -2
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 把点对点隧道挂进装配层:只要一条助手会话,不要回环入口。
|
|
5
|
+
*
|
|
6
|
+
* 与直连隧道(`tailcat/wiring.cjs`)的差别就在这:那条要在本机开一个回环门、再把连接转给
|
|
7
|
+
* 局域网端口;这条的连接是**从隧道里进来的**(WireGuard 的虚拟网卡),助手自己转给
|
|
8
|
+
* `127.0.0.1:<插件端口>`,所以插件这边不需要任何监听。
|
|
9
|
+
*
|
|
10
|
+
* 隧道里进来的连接最终转给谁由 `chooseP2PTarget` 决定(局域网开着转局域网端口、关着转宿主
|
|
11
|
+
* web 端口),与会合那一发拿到的 `targetPort` 是同一个答案。
|
|
12
|
+
*
|
|
13
|
+
* 任何一步起不来都只意味着「这台机器没有这条通道」:`mount` 兜住异常并留一行日志,别的
|
|
14
|
+
* 通道一行不受影响。
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const { createP2PSession, P2P_PORT } = require('./session.cjs');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 隧道里进来的连接该转到哪个端口。
|
|
21
|
+
*
|
|
22
|
+
* 与直连隧道(`tailcat/wiring.cjs` 的 `chooseTailcatTarget`)同一个形状、同一个理由:
|
|
23
|
+
* 局域网开着就照旧转给「当前的局域网端口」,和一台 LAN 手机走完全同一条路;局域网关着
|
|
24
|
+
* 那个端口根本没人监听(`resolveLanPort` 直接早返回、sidecar 也不起),隧道会握手成功、
|
|
25
|
+
* 数据一到就断 —— 手机那边看到的是「连上了却毫无反应」。此时改转宿主自己的 web 端口,
|
|
26
|
+
* 手机 API 就在那里,局域网 sidecar 平时也只是把连接原样转给它。
|
|
27
|
+
*
|
|
28
|
+
* 端口是取值器而不是一个数:局域网开关与端口都会漂,隧道却未必每次会合都重建。
|
|
29
|
+
*/
|
|
30
|
+
function chooseP2PTarget({ lanEnabled, lanPort, webPort }) {
|
|
31
|
+
return () => (lanEnabled() ? lanPort() : webPort());
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @param {object} options
|
|
36
|
+
* @param {(label: string, fn: Function) => any} options.mount 装配层的兜底挂载
|
|
37
|
+
* @param {(message: string) => void} options.warn 告警出口
|
|
38
|
+
* @param {object} options.state relay.json 那份内存状态(唯一真值)
|
|
39
|
+
* @param {(state: object) => void} options.saveState 落盘
|
|
40
|
+
* @param {() => number} options.localPort 插件本机端口(隧道里唯一的去处)
|
|
41
|
+
* @param {() => number} [options.targetPort] 隧道里进来的连接该转给谁;给了就用它,否则退回
|
|
42
|
+
* localPort(见 chooseP2PTarget)
|
|
43
|
+
* @param {object} options.ctx 插件 ctx(只为 `ctx.effect`)
|
|
44
|
+
* @param {string} options.name 插件名,用于 effect 标签
|
|
45
|
+
* @param {() => (string|null)} [options.resolveBinary] 测试缝:钉住「本机有没有助手」,
|
|
46
|
+
* 不让用例的结果取决于开发机上刚好有没有编译好的助手。
|
|
47
|
+
* @returns {object|undefined} 会话;起不来就是 undefined(路由与面板按「不可用」处理)
|
|
48
|
+
*/
|
|
49
|
+
function mountP2P({ mount, warn, state, saveState, localPort, targetPort, ctx, name, resolveBinary }) {
|
|
50
|
+
const resolvedTargetPort = typeof targetPort === 'function' ? targetPort : localPort;
|
|
51
|
+
/**
|
|
52
|
+
* 端口是异步拿到的(`lanPortInUse()` 依赖 sidebar 起来),所以会话也是异步建好的。
|
|
53
|
+
* 与直连隧道同一个做法:对外交**门面**,里面那格可能还是空,调用方问到的就是
|
|
54
|
+
* 「暂不可用」,等挂上自然就通。
|
|
55
|
+
*/
|
|
56
|
+
let session = null;
|
|
57
|
+
const door = {
|
|
58
|
+
status: () => (session
|
|
59
|
+
? session.status()
|
|
60
|
+
: { available: false, enabled: true, ready: false, url: '', path: 'unknown', active: false, error: 'starting' }),
|
|
61
|
+
exchange: peer => (session ? session.exchange(peer) : { ok: false, error: 'starting', port: 0 }),
|
|
62
|
+
open: options => (session ? session.open(options) : Promise.resolve(null)),
|
|
63
|
+
refresh: () => (session ? session.refresh() : Promise.resolve(null)),
|
|
64
|
+
// 起来之后开始定时问现状:不问,面板那一格永远是「正在启动」(见 session 的 watch)。
|
|
65
|
+
watch: () => (session ? session.watch() : undefined),
|
|
66
|
+
start: () => (session ? session.start() : null),
|
|
67
|
+
stop: () => (session ? session.stop() : Promise.resolve()),
|
|
68
|
+
// 会合那一发要的「本机落点端口」:**每次现取**,不缓存。局域网开关与端口都会漂,
|
|
69
|
+
// 缓存一个数就会在关掉局域网之后继续往一个没人听的口转。
|
|
70
|
+
targetPort: () => Number(resolvedTargetPort()) || 0,
|
|
71
|
+
// 会合回包要报「手机在隧道里拨哪个口」。会话还没建好时也得给得出来 —— 它是固定常量,
|
|
72
|
+
// 与会话在不在跑无关;漏了这一格,手机拿到空端口就判「这次没有这条通道」。
|
|
73
|
+
constants: { P2P_PORT },
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// 启停单独一条命:跟 sidecar 不是一件事,谁挂了都不该带走对方。
|
|
77
|
+
mount('点对点隧道生命周期', () =>
|
|
78
|
+
ctx.effect(() => {
|
|
79
|
+
let closed = false;
|
|
80
|
+
Promise.resolve()
|
|
81
|
+
.then(() => {
|
|
82
|
+
if (closed) return;
|
|
83
|
+
const port = Number(localPort());
|
|
84
|
+
if (!Number.isInteger(port) || port <= 0) return;
|
|
85
|
+
session = createP2PSession({
|
|
86
|
+
readState: () => state,
|
|
87
|
+
writeState: patch => {
|
|
88
|
+
Object.assign(state, patch);
|
|
89
|
+
saveState(state);
|
|
90
|
+
},
|
|
91
|
+
localPort: port,
|
|
92
|
+
log: message => warn(message),
|
|
93
|
+
...(typeof resolveBinary === 'function' ? { resolveBinary } : {}),
|
|
94
|
+
});
|
|
95
|
+
session.start();
|
|
96
|
+
// 立刻开始问现状:面板读的是「助手报回来的那一格」,不问它就一直是空的。
|
|
97
|
+
session.watch();
|
|
98
|
+
})
|
|
99
|
+
.catch(error => warn(`点对点隧道没有起来:${error && error.message ? error.message : error}`));
|
|
100
|
+
return () => {
|
|
101
|
+
closed = true;
|
|
102
|
+
try {
|
|
103
|
+
if (session) {
|
|
104
|
+
session.unwatch();
|
|
105
|
+
void session.stop();
|
|
106
|
+
}
|
|
107
|
+
session = null;
|
|
108
|
+
} catch {
|
|
109
|
+
/* 已经在停 */
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
}, `${name}: p2p`),
|
|
113
|
+
);
|
|
114
|
+
return door;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
module.exports = { mountP2P, chooseP2PTarget };
|