dsh-remote-hub 0.3.1 → 0.3.2
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 +34 -2
- package/bin/dsh-remote.mjs +60 -2
- package/lib/index.js +1 -1
- package/lib/supervisor.js +19 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,9 +19,9 @@ Kotlin/Compose 直连 DSH 自带的 HTTP API + WebSocket 网关。
|
|
|
19
19
|
|
|
20
20
|
## 下载手机端 App
|
|
21
21
|
|
|
22
|
-
**DSH Remote v4.
|
|
22
|
+
**DSH Remote v4.21.0** · Android 8.0 (API 26) 及以上 · 2.8 MB
|
|
23
23
|
|
|
24
|
-
[⬇️ 下载 APK](https://github.com/liaoguogang-hub/dsh-remote-public/releases/download/v4.
|
|
24
|
+
[⬇️ 下载 APK](https://github.com/liaoguogang-hub/dsh-remote-public/releases/download/v4.21.0/DSH-Remote-v4.21.0.apk) ·
|
|
25
25
|
[全部版本](https://github.com/liaoguogang-hub/dsh-remote-public/releases)
|
|
26
26
|
|
|
27
27
|
安装后应用名「DSH Remote」,包名 `com.dsh.remote.ngrok`(可与作者的 `DSH` 自用版共存)。
|
|
@@ -235,6 +235,38 @@ dsh-remote: ready — 手机端扫码:dsh-remote qr(或浏览器打开 http:
|
|
|
235
235
|
**Cookie 跨重启有效**:桥接始终向 DSH 呈现固定 authority(默认 `127.0.0.1:1815`),
|
|
236
236
|
所以 DSH 换端口、桥接重启都不会让手机上的凭据失效;只有签名密钥变化或 Cookie 到期(30 天)才需要重新扫码。
|
|
237
237
|
|
|
238
|
+
### 升级插件(重要:必须完全重启 DSH)
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
dsh plugin --profile desktop add dsh-remote-hub # 或 --profile web
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**升级后请完全退出 DSH 再重新打开,不要只靠插件热重载。** 原因是旧版本的桥接监听可能不会被热重载回收,
|
|
245
|
+
它会继续占着端口,而这个"旧桥接"里没有新版本的路由:
|
|
246
|
+
|
|
247
|
+
| 症状 | 含义 |
|
|
248
|
+
|---|---|
|
|
249
|
+
| 配对页打不开,或打开是**乱码/无关页面** | 端口被**旧版桥接**占着,请求被它转发走了 |
|
|
250
|
+
| `dsh-remote status` 里 `bridgePort` 是 `0`、地址是 `http://x.x.x.x:0` | 旧版本绑不上端口的回退 bug(0.3.0 及更早) |
|
|
251
|
+
|
|
252
|
+
0.3.1 起这些都能自愈,但仍建议完全重启,理由是会残留**旧代码的监听**:
|
|
253
|
+
|
|
254
|
+
- 绑不上端口时先探 `/_dsh-remote/health`:
|
|
255
|
+
- 是支持配对的本插件桥接 → 直接**采纳**,不重复开隧道;
|
|
256
|
+
- 是旧版桥接(没有配对路由)或别的程序 → 自动**改用临时端口**,并在日志/`status.json` 里写明真实端口;
|
|
257
|
+
- 插件热重载时通过进程内注册表**先关闭上一实例**的监听。
|
|
258
|
+
|
|
259
|
+
升级后确认当前真实端口:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
dsh-remote status # 打印 bridgePort / 局域网 / 公网 / Cookie
|
|
263
|
+
# 或直接看健康检查
|
|
264
|
+
curl http://127.0.0.1:<bridgePort>/_dsh-remote/health
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
> 提示:`cordis.patch.yml` 里的 `port` 只是**首选**端口。若被占用,实际端口会写在 `~/.dsh/dsh-remote/status.json`,
|
|
268
|
+
> 一切链接与二维码都以那里为准,不必手改配置。
|
|
269
|
+
|
|
238
270
|
### 扫码配对(一次性配对码)
|
|
239
271
|
|
|
240
272
|
不想手抄 Cookie 就用二维码:
|
package/bin/dsh-remote.mjs
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import fs from 'node:fs'
|
|
17
|
+
import http from 'node:http'
|
|
17
18
|
import { execFile } from 'node:child_process'
|
|
18
19
|
import os from 'node:os'
|
|
19
20
|
import path from 'node:path'
|
|
@@ -69,8 +70,59 @@ function openBrowser(url) {
|
|
|
69
70
|
})
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
/**
|
|
73
|
+
/** Is a live dsh-remote bridge answering on this port? */
|
|
74
|
+
function bridgeHealthy(port, timeoutMs = 1200) {
|
|
75
|
+
return new Promise((resolve) => {
|
|
76
|
+
const req = http.request(
|
|
77
|
+
{ host: '127.0.0.1', port, path: '/_dsh-remote/health', method: 'GET', timeout: timeoutMs },
|
|
78
|
+
(res) => {
|
|
79
|
+
const chunks = []
|
|
80
|
+
res.on('data', (c) => chunks.push(c))
|
|
81
|
+
res.on('end', () => {
|
|
82
|
+
try {
|
|
83
|
+
const doc = JSON.parse(Buffer.concat(chunks).toString('utf8'))
|
|
84
|
+
resolve(doc?.ok ? doc : null)
|
|
85
|
+
} catch {
|
|
86
|
+
resolve(null)
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
},
|
|
90
|
+
)
|
|
91
|
+
req.on('error', () => resolve(null))
|
|
92
|
+
req.on('timeout', () => {
|
|
93
|
+
req.destroy()
|
|
94
|
+
resolve(null)
|
|
95
|
+
})
|
|
96
|
+
req.end()
|
|
97
|
+
})
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Point the browser at the running bridge's pairing page.
|
|
102
|
+
*
|
|
103
|
+
* The port is verified against the bridge's own health route first: status.json can be stale after
|
|
104
|
+
* a crashed run or a test on another port, and opening a dead URL looks like "the QR page is broken".
|
|
105
|
+
*/
|
|
106
|
+
async function resolveLiveBridge(preferred) {
|
|
107
|
+
const candidates = [preferred, 6300, readStatus()?.bridgePort]
|
|
108
|
+
.filter((p, i, arr) => Number.isInteger(p) && p > 0 && arr.indexOf(p) === i)
|
|
109
|
+
for (const port of candidates) {
|
|
110
|
+
// eslint-disable-next-line no-await-in-loop
|
|
111
|
+
const live = await bridgeHealthy(port)
|
|
112
|
+
if (live) return Number(live.bridgePort) || port
|
|
113
|
+
}
|
|
114
|
+
return null
|
|
115
|
+
}
|
|
116
|
+
|
|
73
117
|
async function openPairPage(bridgePort) {
|
|
118
|
+
const livePort = await resolveLiveBridge(bridgePort)
|
|
119
|
+
if (!livePort) {
|
|
120
|
+
console.log('')
|
|
121
|
+
console.log(' 找不到正在运行的桥接:先运行 dsh-remote start,或双击 connect.cmd')
|
|
122
|
+
console.log('')
|
|
123
|
+
return
|
|
124
|
+
}
|
|
125
|
+
bridgePort = livePort
|
|
74
126
|
const page = `http://127.0.0.1:${bridgePort}/_dsh-remote/pair`
|
|
75
127
|
console.log('')
|
|
76
128
|
console.log(' 配对页:', page)
|
|
@@ -81,7 +133,13 @@ async function openPairPage(bridgePort) {
|
|
|
81
133
|
|
|
82
134
|
async function qrCommand() {
|
|
83
135
|
const status = readStatus()
|
|
84
|
-
const port = status?.bridgePort ?? Number(process.env.DSH_REMOTE_PORT || 6300)
|
|
136
|
+
const port = await resolveLiveBridge(status?.bridgePort ?? Number(process.env.DSH_REMOTE_PORT || 6300))
|
|
137
|
+
if (!port) {
|
|
138
|
+
console.log('')
|
|
139
|
+
console.log(' 桥接还没运行:先执行 dsh-remote start --open(或双击 connect.cmd)')
|
|
140
|
+
console.log('')
|
|
141
|
+
return
|
|
142
|
+
}
|
|
85
143
|
const page = `http://127.0.0.1:${port}/_dsh-remote/pair`
|
|
86
144
|
console.log('')
|
|
87
145
|
console.log(' 配对页:', page)
|
package/lib/index.js
CHANGED
|
@@ -16,7 +16,7 @@ import { start } from './supervisor.js'
|
|
|
16
16
|
|
|
17
17
|
export const name = 'dsh-remote-hub'
|
|
18
18
|
|
|
19
|
-
export const version = '0.3.
|
|
19
|
+
export const version = '0.3.2'
|
|
20
20
|
|
|
21
21
|
/** No host services are required: the plugin only needs Node builtins. */
|
|
22
22
|
export const inject = []
|
package/lib/supervisor.js
CHANGED
|
@@ -250,10 +250,26 @@ export async function start(config = {}) {
|
|
|
250
250
|
const existing = await probeHealth(wanted)
|
|
251
251
|
if (existing?.ok && existing.pairing) {
|
|
252
252
|
log(`dsh-remote: port ${wanted} is already served by a dsh-remote bridge; adopting it`)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
253
|
+
// Rebuild the status from the LIVE bridge's own health report instead of trusting
|
|
254
|
+
// status.json: a stale file (from an earlier run on another port) is exactly what made
|
|
255
|
+
// connect.cmd open a dead URL.
|
|
256
|
+
const prev = readStatus() ?? {}
|
|
257
|
+
const livePort = Number(existing.bridgePort) || wanted
|
|
258
|
+
const ip = lanAddress()
|
|
259
|
+
const adopted = {
|
|
260
|
+
updatedAt: Date.now(),
|
|
261
|
+
phase: 'adopted',
|
|
262
|
+
bridgePort: livePort,
|
|
263
|
+
authority: existing.authority ?? authority,
|
|
264
|
+
upstreamPort: existing.upstreamPort ?? null,
|
|
265
|
+
lan: { ip, url: ip ? `http://${ip}:${livePort}` : null },
|
|
266
|
+
public: prev.public ?? { url: null, kind: 'none', note: 'served by an existing bridge' },
|
|
267
|
+
cookie: prev.cookie ?? null,
|
|
268
|
+
cookieExpiresAt: prev.cookieExpiresAt ?? null,
|
|
269
|
+
pairing: { url: prev.public?.url ?? (ip ? `http://${ip}:${livePort}` : null), page: '/_dsh-remote/pair' },
|
|
256
270
|
}
|
|
271
|
+
writeStatus(adopted)
|
|
272
|
+
return { status: adopted, close: async () => {} }
|
|
257
273
|
}
|
|
258
274
|
if (existing?.ok) {
|
|
259
275
|
log('dsh-remote: port is held by an old bridge WITHOUT pairing support; using another port')
|
package/package.json
CHANGED