dsh-restart-btn
在 DSH 设置页 General 区加一行「重启 Web 服务」按钮:点一下就把 dsh web 重启一遍,
用于让插件 / 主题 / 配置改动生效,不用再去双击桌面快捷方式。
页面会在服务重启期间短暂断开,服务回来后自动重新载入——不需要手动刷新。
为什么会有这个插件
在 Windows 上重启 dsh 有个隐蔽的坑:调度任务(schtasks /TR)的命令行是按ANSI 代码页
写入的,只要命令里出现非 ASCII 字符(例如中文工作区 ...\OneDrive\文档\txt2),路径就会被
静默损坏——任务照样报 Last Result: 0(成功),但脚本一行都没执行。
早期版本把重启脚本写进「客户端传来的工作区路径」,在这些机器上表现为: 点重启完全没反应,也没有任何报错。
本版本的处理方式:
- 重启助手脚本固定放在纯 ASCII、无空格的暂存目录(
%LOCALAPPDATA%\dsh-restart-btn, 不可用时依次退到%ProgramData%/%SystemRoot%\Temp/%TEMP%/~/.dsh), 调度任务的命令行里因此永远只有 ASCII。 - 所有用户相关路径(node、bin.js、工作目录、日志、启动器)走 UTF-8 JSON 配置文件, 完全不进命令行。
- 助手脚本本身是纯 ASCII,并用显式 UTF-8 解码器读 JSON——绕开 PowerShell 5.1 默认按 ANSI 读文件的第二个坑。
它怎么重启
复刻桌面快捷方式(start-dsh.ps1)验证过的机制,而不是另发明一套:
| 步骤 | 做法 |
|---|---|
| 1 | 延迟若干秒,让 HTTP 响应先回到浏览器 |
| 2 | 找到监听该端口的进程,taskkill /T /F 连子进程一起结束 |
| 3 | 轮询等端口真正释放 |
| 4 | Start-Process <node> <lib/bin.js> web --port <port>,stdout/stderr 重定向到日志文件(与快捷方式一致,崩溃才查得到) |
| 5 | TCP 轮询就绪(最多 45s)——不用 HTTP 探测,避免把「401 未授权」误判成失败 |
| 6 | 直连启动失败时,回退执行桌面启动器 %LOCALAPPDATA%\DeepSeekHarness\start-dsh.ps1(它自带自愈与浏览器拉起) |
服务端身份(instance)在每次进程启动时不同,前端只有在 ping 到另一个 instance 时才刷新页面,
因此不会把「还没死掉的旧服务」误认成「新服务已就绪」。
重启后为什么会话有时要重新授权
dsh 的 Web 认证是绑定 authority 的签名 cookie(dsh-auth-<sha256(host:port)>)。
它没有「关闭认证」的开关:requestRejection() 先做 Host/Origin 围栏(403),
再要求 cookie 通过(401);trustedHosts 只放宽围栏,不能绕过 cookie。
签名密钥存在凭据库里、重启不变,所以同一个 cookie 重启后依然有效(实测:重启前后都是 200)。
但 cookie 有寿命,而一个长期开着的标签页可以活得比它的 cookie 更久——页面还能用只是因为连接早就建好了,
这时一次普通刷新就会撞上 dsh web authentication required。
token 的唯一作用是把 cookie 种进浏览器。 桌面快捷方式之所以「总是能用」,正是因为
dsh web 启动时会打印 http://127.0.0.1:<port>/?token=… 并打开它,于是每次启动都重新签发 cookie。
所以本插件不自己转发任何 token:重启时不加 --no-open,让 dsh 照常打印并打开那个已授权地址
(行为与桌面快捷方式完全一致)。新页面完成 token 兑换后,同一个 authority 的 cookie 被刷新,
旧标签页的探测(GET / 是否 200)随之通过并自动重载——因此前端不会盲目刷新,
探测不通过就提示用桌面快捷方式,绝不会把页面刷成一片 401。
安装
# 本地目录
dsh plugin --profile web add D:/Code/dsh/restart-btn-plugin
# 或从 GitHub
dsh plugin --profile web add github:SiriusWJ/dsh-restart-btn
改完 bundle 需要重启一次 dsh 生效(第一次请手动重启)。
路由
| 方法 | 路径 | 说明 |
|---|---|---|
POST |
/dsh-restart-btn/restart |
同源校验;body {"port":"3080"};返回 instance / log / trigger |
GET |
/dsh-restart-btn/ping |
返回 {ok, instance, pid},供页面判断新进程是否就绪 |
日志与排错
| 文件 | 内容 |
|---|---|
%LOCALAPPDATA%\dsh-restart-btn\restart.log |
重启全过程(停进程 / 端口释放 / 启动 / 就绪 / 失败原因 + stderr 尾部) |
%LOCALAPPDATA%\dsh-restart-btn\dsh.out.log |
新服务的 stdout(含它打印的 token 地址) |
%LOCALAPPDATA%\dsh-restart-btn\dsh.err.log |
新服务的 stderr |
若暂存目录不是 %LOCALAPPDATA%(用户名含非 ASCII 时会自动退到 %ProgramData% 等),
以 POST /dsh-restart-btn/restart 返回的 log 字段为准。
已知取舍
- 重启时不加
--no-open,所以每次重启浏览器都会多开一个已授权的标签页(与桌面快捷方式一致)。 旧标签页靠 cookie 刷新后自动重载。想改成不弹新标签页,需要让插件把新 launch url 转交给页面, 代价是插件要对外提供一次完整会话凭据。 - 端口取自浏览器地址栏,因此非 3080 端口也能正确重启;只有 3080 才回退到
start-dsh.ps1(那个脚本自身写死了 3080)。 - 仅 Windows 走 Task Scheduler + PowerShell 路径;其他平台需自行改
buildHelperScript()。
License
MIT
No comments yet. Be the first to write one.