mirror of
https://github.com/stablyai/orca.git
synced 2026-10-01 16:02:03 +00:00
fix(mobile): unsubscribe session tabs by request on the direct connection (#22943)
* fix(mobile): unsubscribe session tabs by request on the direct connection * fix(mobile): hold a direct session tabs unsubscribe until the first snapshot The desktop registers a tab-list stream only as it emits the first snapshot. A direct unsubscribe sent before that found nothing, and with per-request addressing no later worktree-wide sweep collects the late stream, so it kept its desktop listener until the socket closed. Hold the unsubscribe until the snapshot arrives, as the relay connection does. * test(mobile): cover a held session tabs unsubscribe whose subscribe fails * fix(mobile): keep the session tabs hold within the registry line budget after merging main Move the pre-snapshot hold into the session tabs stream module, note that only older hosts need it, and give the unsubscribe test the real registration version now that a worktree-wide unsubscribe spares later streams.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type { OrcaRuntimeService } from '../../orca-runtime'
|
||||
import { RuntimeSubscriptionRegistry } from '../../runtime-subscription-registry'
|
||||
import { RpcDispatcher } from '../dispatcher'
|
||||
import { SESSION_TAB_METHODS } from './session-tabs'
|
||||
|
||||
@@ -61,11 +62,61 @@ describe('session tab unsubscribe RPC methods', () => {
|
||||
expect(cleanupSubscription).toHaveBeenCalledWith('session.tabs:conn-1:*:sub-all-1')
|
||||
expect(cleanupSubscriptionsByPrefix).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('ends only the named stream when a newer one watches the same worktree', async () => {
|
||||
const { dispatcher, ends } = await subscribeTwiceToOneWorktree()
|
||||
|
||||
await dispatcher.dispatchStreaming(
|
||||
request('session.tabs.unsubscribe', { worktree: 'id:wt-1', subscriptionId: 'sub-old' }),
|
||||
vi.fn(),
|
||||
{ connectionId: 'conn-1' }
|
||||
)
|
||||
|
||||
await vi.waitFor(() => expect(ends['sub-old']).toBe(1))
|
||||
expect(ends['sub-new']).toBe(0)
|
||||
})
|
||||
|
||||
it('ends every stream for the worktree when the unsubscribe names no request', async () => {
|
||||
const { dispatcher, ends } = await subscribeTwiceToOneWorktree()
|
||||
|
||||
await dispatcher.dispatchStreaming(
|
||||
request('session.tabs.unsubscribe', { worktree: 'id:wt-1' }),
|
||||
vi.fn(),
|
||||
{ connectionId: 'conn-1' }
|
||||
)
|
||||
|
||||
await vi.waitFor(() => expect(ends).toEqual({ 'sub-old': 1, 'sub-new': 1 }))
|
||||
})
|
||||
})
|
||||
|
||||
async function subscribeTwiceToOneWorktree() {
|
||||
const registry = new RuntimeSubscriptionRegistry()
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: Partial runtime backed by the real subscription registry; it supplies every member session.tabs subscribe/unsubscribe call.
|
||||
const runtime = {
|
||||
...runtimeWithCleanup(registry.cleanup.bind(registry), registry.cleanupByPrefix.bind(registry)),
|
||||
registerSubscriptionCleanup: registry.register.bind(registry),
|
||||
getSubscriptionRegistrationVersion: registry.getRegistrationVersion.bind(registry),
|
||||
onMobileSessionTabsChanged: () => () => {}
|
||||
} as unknown as OrcaRuntimeService
|
||||
const dispatcher = new RpcDispatcher({ runtime, methods: SESSION_TAB_METHODS })
|
||||
const ends: Record<string, number> = { 'sub-old': 0, 'sub-new': 0 }
|
||||
for (const id of ['sub-old', 'sub-new']) {
|
||||
await dispatcher.dispatchStreaming(
|
||||
{ ...request('session.tabs.subscribe', { worktree: 'id:wt-1' }), id },
|
||||
(message) => {
|
||||
if (JSON.parse(message).result?.type === 'end') {
|
||||
ends[id]! += 1
|
||||
}
|
||||
},
|
||||
{ connectionId: 'conn-1' }
|
||||
)
|
||||
}
|
||||
return { dispatcher, ends }
|
||||
}
|
||||
|
||||
function runtimeWithCleanup(
|
||||
cleanupSubscription: ReturnType<typeof vi.fn>,
|
||||
cleanupSubscriptionsByPrefix = vi.fn()
|
||||
cleanupSubscription: (id: string) => void,
|
||||
cleanupSubscriptionsByPrefix: (prefix: string, throughVersion?: number) => void = vi.fn()
|
||||
): OrcaRuntimeService {
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the unsubscribe methods reach only these members; a missing one throws and fails the test.
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user