dsh-mobile-plugin 0.5.10 → 0.5.12

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.
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /**
5
+ * 在终端里把配对二维码打出来(`dsh-mobile-plugin-pair`)。
6
+ *
7
+ * 为什么需要它:二维码那条路由只在本机屏幕或者两小时窗口里给码,而**服务器部署**上
8
+ * 「本机屏幕」这个概念是空的 —— 那台机器的设置页往往开不了,人也够不到它的回环地址。
9
+ * 能在服务器终端里敲命令的人本来就有这台机器的权限,把码打给他,信任量级与「在本机屏幕
10
+ * 上看码」相同,也不新增任何对外的口子。
11
+ *
12
+ * 载荷与面板同一份(`../relay/pairing-payload.cjs`),所以打出来的码一定和面板里那张能
13
+ * 配上同一台机器;这里只负责画图与说人话,不碰配对流程。
14
+ *
15
+ * 用法:
16
+ * dsh-mobile-plugin-pair 在终端里打出二维码
17
+ * dsh-mobile-plugin-pair --svg qr.svg 另外存一份 SVG(终端太窄、想发给别人时用)
18
+ */
19
+
20
+ const fs = require('node:fs');
21
+ const path = require('node:path');
22
+ const QRCode = require('qrcode');
23
+ const core = require('../relay/core.js');
24
+ const { pairingPayload } = require('../relay/pairing-payload.cjs');
25
+
26
+ const USAGE = `用法:
27
+ dsh-mobile-plugin-pair 在终端里打印配对二维码
28
+ dsh-mobile-plugin-pair --svg <路径> 同时把二维码存成 SVG 图片`;
29
+
30
+ function fail(message) {
31
+ process.stderr.write(`${message}\n`);
32
+ process.exitCode = 1;
33
+ }
34
+
35
+ function parseArgs(argv) {
36
+ const out = { svg: '' };
37
+ for (let index = 0; index < argv.length; index += 1) {
38
+ const arg = argv[index];
39
+ if (arg === '--svg') {
40
+ const next = argv[index + 1];
41
+ if (!next || next.startsWith('-')) return { error: '--svg 后面要跟一个文件路径' };
42
+ out.svg = next;
43
+ index += 1;
44
+ continue;
45
+ }
46
+ if (arg === '--help' || arg === '-h') return { help: true };
47
+ return { error: `不认识的参数:${arg}` };
48
+ }
49
+ return out;
50
+ }
51
+
52
+ async function main(argv) {
53
+ const args = parseArgs(argv);
54
+ if (args.help) {
55
+ process.stdout.write(`${USAGE}\n`);
56
+ return;
57
+ }
58
+ if (args.error) {
59
+ fail(`${args.error}\n\n${USAGE}`);
60
+ return;
61
+ }
62
+
63
+ // 状态文件是宿主与这里唯一的交接口:宿主每次换码换票据都会落盘,所以读到的那份就是
64
+ // 跑着的宿主手上那份。文件不存在时**不替它建**(`loadState()` 会建),直接说清楚。
65
+ if (!fs.existsSync(core.STATE_FILE)) {
66
+ fail(`这台机器上还没跑过这个插件(找不到 ${core.STATE_FILE})。先启动 DSH,并在移动端插件里启用远程控制。`);
67
+ return;
68
+ }
69
+ const state = core.loadState();
70
+ if (!state.enabled) {
71
+ fail('远程控制还没启用:先在 DSH 的移动端设置页(或面板)里打开远程控制并保存配置。');
72
+ return;
73
+ }
74
+ const { payload, text } = pairingPayload(state, state.lanPort);
75
+ if (!payload.relayUrl && payload.lanUrls.length === 0) {
76
+ fail('没有可用的中转或直连地址:先在面板上配好中转地址,或打开局域网直连,再回来打码。');
77
+ return;
78
+ }
79
+
80
+ const lines = [];
81
+ lines.push(`宿主:${payload.name}`);
82
+ lines.push(`配对码:${payload.code}`);
83
+ lines.push(`中转地址:${payload.relayUrl || '(没配)'}`);
84
+ if (payload.lanUrls.length > 0) {
85
+ lines.push(`直连地址:${payload.lanUrls.join(' ')}`);
86
+ lines.push(`局域网端口:${state.lanPort}`);
87
+ }
88
+ process.stdout.write(`${lines.join('\n')}\n\n`);
89
+
90
+ if (args.svg) {
91
+ const target = path.resolve(args.svg);
92
+ fs.mkdirSync(path.dirname(target), { recursive: true });
93
+ fs.writeFileSync(target, await QRCode.toString(text, { type: 'svg', errorCorrectionLevel: 'M', margin: 2, width: 480 }));
94
+ process.stdout.write(`二维码已存成图片:${target}\n如果终端太窄扫不动,把这个文件拿下来用看图软件打开再扫。\n\n`);
95
+ }
96
+
97
+ // small: true 让一个字符带两行模块,绝大多数终端一行装得下;扫不动就加 --svg。
98
+ process.stdout.write(`${await QRCode.toString(text, { type: 'terminal', small: true, errorCorrectionLevel: 'M' })}\n`);
99
+ process.stdout.write('用 DSH App 扫这张码即可配对。它等于一次配对权限,别截图发给别人;配完可以在面板上点「重新生成配对码」。\n');
100
+ }
101
+
102
+ main(process.argv.slice(2)).catch((error) => {
103
+ fail(`打码失败:${error && error.message ? error.message : String(error)}`);
104
+ });