Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion apps/desktop/src/renderer/src/api/remote-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,9 @@ export function createRemoteConnection({
return (chunk) => decoder.decode(chunk, { stream: true })
},
delay: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
onUnauthorized: () => unauthorized.forEach((listener) => listener())
onUnauthorized: () => unauthorized.forEach((listener) => listener()),
// An unreachable desktop otherwise keeps the connect page on "connecting" for minutes.
sessionTimeoutMs: 10_000
})

return {
Expand Down
13 changes: 10 additions & 3 deletions apps/desktop/src/renderer/src/features/remote/connect-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,16 @@ export function ConnectPage({
<h1 className="font-heading text-lg font-semibold">连接 DevHub</h1>
</div>
{checking ? (
<p className="text-sm text-muted-foreground" role="status">
正在连接…
</p>
<>
<p className="text-sm text-muted-foreground" role="status">
正在连接…
</p>
{choosesAddress && (
<Button variant="outline" onClick={onChange}>
更换桌面端
</Button>
)}
</>
) : (
<>
{alert && (
Expand Down
1 change: 1 addition & 0 deletions docs/PROGRESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ M4-3 Android:
- #36 已完成(v1.4.0):Android 图标与启动画面由桌面端 SVG 生成。
- #37 已完成(v1.4.0):App 内扫码连接(`@capacitor/barcode-scanner`,不依赖 Google Play 服务,minSdk 26);实际识别待真机验证。
- #41 已完成,待合并:桌面端早于 1.4(不支持 App 的 CORS)时,App 提示升级桌面端,而不是「检查网络」(真机反馈)。
- #47 已完成,待合并:连接检查 10 秒超时(此前桌面不可达且丢包时一直「正在连接…」,真机反馈),连接中也可「更换桌面端」;已在模拟器验证,真机上的具体诱因(推测为 Tailscale 未连上)未确认。

桌面修复:

Expand Down
20 changes: 20 additions & 0 deletions packages/shared/src/remote-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,26 @@ describe('remote api', () => {
headers: { authorization: 'Bearer secret' }
})
})

it('gives up on a session check the desktop never answers', async () => {
const delay = vi.fn(async () => undefined)
const hanging = client(() => new Promise<FetchResponse>(() => undefined), {
delay,
sessionTimeoutMs: 10_000
})
await expect(hanging.session()).rejects.toMatchObject({ code: 'TIMEOUT', status: 0 })
expect(delay).toHaveBeenCalledWith(10_000)
})

it('returns a session answered before the timeout', async () => {
let elapse: (() => void) | undefined
const answered = client(async () => json(200, { protocol: 1, allowTerminal: true }), {
delay: () => new Promise<void>((resolve) => (elapse = resolve)),
sessionTimeoutMs: 10_000
})
await expect(answered.session()).resolves.toEqual({ protocol: 1, allowTerminal: true })
elapse?.()
})
})

describe('remote events', () => {
Expand Down
17 changes: 16 additions & 1 deletion packages/shared/src/remote-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ export interface RemoteClientOptions {
onUnauthorized?: () => void
/** Waits between event stream reconnects; the last value repeats. */
retryDelaysMs?: readonly number[]
/**
* Gives up on `session()` after this long (`TIMEOUT`). Without it the check waits as long as
* the platform does: minutes on a phone whose packets to the desktop are dropped.
*/
sessionTimeoutMs?: number
}

/** A failed remote call. `code` is the core's `DevhubError` code or a transport code. */
Expand Down Expand Up @@ -112,7 +117,17 @@ export function createRemoteClient(options: RemoteClientOptions): RemoteClient {
api,
events: createEventStream(options, () => url('/events'), auth),
async session() {
const { status, body } = await request('/session', { method: 'GET' })
const pending = request('/session', { method: 'GET' })
const { sessionTimeoutMs } = options
const { status, body } =
sessionTimeoutMs === undefined
? await pending
: await Promise.race([
pending,
options.delay(sessionTimeoutMs).then((): never => {
throw new RemoteError('TIMEOUT', 'DevHub 没有响应,请检查网络和远程访问设置', 0)
})
])
if (status === 200 && isSession(body)) return body
if (isIpcResult(body) && !body.ok) {
throw new RemoteError(body.error.code, body.error.message, status)
Expand Down
Loading