Repository navigation
Conversation
|
感谢这个修复—— 这个反应的bug的确存在 #121 里已经有等价实现,并且更完整:插件在 43189–43198 取首个空闲回环端口发布避免端口冲突,扩展侧配套探测编排;本机同时跑多个 dsh 实例时可以在面板里分别发现并切换。 如果急需这个能力 #121,可以先使用 fork 版本:https://github.com/graydovee/dsh-browser (v0.1.7 已发布, |
DSH Desktop starts its web server with `dsh web --port 0`, so the port that carries /ext/bridge is reassigned by the OS on every launch. The extension only probes a fixed port list (3080/3081/3090/14389/43189), so a dynamically assigned host looks permanently offline: the side panel stays on "disconnected" and every browser_* tool reports "no browser extension is connected", even though /ext/bridge-config answers normally. The bridge now also binds a stable loopback port (`discoveryPort`, default 43189, `0` disables it) and republishes /ext/bridge-config there with the live WebSocket URL. The listener is loopback-only, answers that single read-only route, publishes no token, and degrades to one warning when the port is taken (including when the web server itself already owns it). - src/discovery.ts: handler, URL helper, and resilient listener - src/index.ts: mount it inside the effect scope, next to the existing route - tests: handler/bind/degradation coverage; config defaults updated - docs: config table row and a port-discovery section (en/zh)
dsh 0.2.1-rc.2 requires every gateway entry point to come from a live Peer:
- `openWireStream` calls `assertPeerLive(peer)` before opening `$events` and
binds the stream to that Peer, so a later `$events/result` must arrive from
the same object. The plugin passed `undefined`, the first `$events` open
threw "Cannot read properties of undefined (reading 'signal')", and the
socket closed 1011 — every reconnect ended in the same loop.
- `prepareInvocation` starts with the same `assertPeerLive(request.peer)`, so
every unary call (`session.list` included) failed the same way.
The plugin now creates one in-process owner Peer per bridge and forwards it to
`wireStream.open`, `connection.createSharedFetchHandler('/api').fetch(request,
peer)`, and every `gateway.invoke`. `createPeer` stays optional: dsh 0.2.0 has
no Peer seam and keeps the previous call shape.
Asheblog
force-pushed
the
fix/bridge-discovery-port
branch
from
October 20, 2026 08:47
9c2c321 to
3131994
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
概述 / Summary
让桥接插件在 DSH 0.2.1-rc.2 + 动态 Web 端口 的桌面环境下重新可被扩展连接,修掉三个叠加缺陷:扩展发现不到地址、事件流握手后立刻 1011、以及所有 unary RPC 报
reading 'signal'。动机 / Motivation
DSH Desktop 用
dsh web --port 0启动内嵌 Web 服务,每次启动端口都由系统重新分配(实测连续三次:1646 → 10472 → 1496)。这暴露了几个独立问题。根因 1:扩展只能探测固定端口
扩展通过
/ext/bridge-config在固定端口表(3080 / 3081 / 3090 / 14389 / 43189)里找本机 dsh。端口随机后侧栏永远停在「未连接」,所有browser_*工具报no browser extension is connected to the bridge,而直接请求当前端口的/ext/bridge-config却返回 200 和正确wsUrl。根因 2:0.2.1 的 Peer 槽位传了
undefined修好发现后,扩展进入「连接中 → 断开 → 重连」循环。用与扩展一致的方式握手复现:
dsh-api-gateway@0.2.1-rc.2的openWireStream在$events分支调用assertPeerLive(peer)(内部是peer.signal.aborted),而插件在wireStream.open(endpoint, payload, uplink, peer, signal)的第 4 槽传的是undefined。同一版本还把转发事件流绑定到发起它的 Peer($events/result校验client.peer !== peer),所以必须是同一个真实 Peer 对象。根因 3:unary RPC 同样缺 Peer
连接稳定后,面板一列会话就又报同一条 TypeError:
因为
prepareInvocation(request, control)的第一行也是assertPeerLive(request.peer, endpoint),而gateway.invoke({ namespace, method, args, signal })从来没带过 peer。改动内容 / Changes
固定端口发现
src/discovery.ts:在discoveryPort(默认 43189,0关闭)上监听回环地址,只回答GET/HEAD /ext/bridge-config,返回当前实时 Web 端口对应的wsUrl;其它方法 405、其它路径 404;端口被占用(含 Web 服务自身占用该端口)时只记一条 warning 并跳过,不阻断启动。src/index.ts:Config增加discoveryPort(schema 默认 43189,校验 0–65535),在mountBridge的 effect 作用域内挂载。in-process Peer(覆盖 stream + unary)
src/remote-host-api.ts:通过connection.createPeer({ principal: { kind: 'owner' }, interactions: 'answer' })为每个桥创建一个 owner Peer。wireStream.open($events、session/follow、workspace/follow)与connection.createSharedFetchHandler('/api').fetch(request, peer)($events/result)。TypertGatewayLike.invoke接受可选peer,四个 invoke 调用点全部前传。EventGeneration持有该 Peer 供其流使用。createPeer保持可选:DSH 0.2.0 没有 Peer 机制,调用形态不变。测试与文档
tests/discovery.spec.ts:发布、HEAD、405、404、等于 Web 端口时跳过、端口被占用时降级。tests/remote-host-api.spec.ts:新增「0.2.1 Peer 槽位」回归用例;tests/index.spec.ts更新配置默认值与端口校验。README.md/README.zh.md增加配置行与「端口发现」小节;cordis.patch.yml显式写出discoveryPort: 43189。测试 / Testing
实机验证(Windows 11 / Chrome 116+ / DSH Desktop 0.2.1-rc.2):
注:仓库里
session-purge(symlink)与token(0600 权限)两个用例在 Windows 本机失败,与本次改动无关,Linux CI 正常。影响范围 / Impact
--port 0)用户:扩展恢复自动发现,且事件流与 RPC 都能正常往返。reading 'signal'。createPeer不存在时走原路径,行为不变;dsh web默认 3080 的部署不会命中额外端口。127.0.0.1、只回一条只读路由、返回值不含 token;WebSocket 认证逻辑未改动。discoveryPort被占用或恰好等于 Web 端口时自动跳过并告警。