mirror of
https://github.com/stablyai/orca.git
synced 2026-10-21 00:03:46 +00:00
refactor(mobile): drop the dead all-hosts client broadcast
Moving notification ownership to the root owner left subscribeAllHosts with no consumers. It re-renders every subscriber on any host's open/close, so leaving it wired is a standing invitation to reintroduce the O(N) fanout this change removes. Per-host notifyHostState already covers every store mutation. Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -17,10 +17,8 @@ import { decrementPendingAcquisition } from './host-client-acquisition-count'
|
||||
import { subscribeHostClientRevival } from './host-client-revival-scheduler'
|
||||
import {
|
||||
clientActivePath,
|
||||
notifyAllHostListeners,
|
||||
notifyHostStateListeners,
|
||||
primeHostProfiles,
|
||||
subscribeAllHostListener,
|
||||
subscribeHostStateListener,
|
||||
type CloseEntryOptions
|
||||
} from './host-client-context-state'
|
||||
@@ -52,7 +50,6 @@ export type RpcClientContextValue = {
|
||||
getActivePath: (hostId: string) => MobileConnectionPath
|
||||
getClient: (hostId: string) => RpcClient | null
|
||||
subscribeHostState: (hostId: string, listener: (state: ConnectionState) => void) => () => void
|
||||
subscribeAllHosts: (listener: () => void) => () => void
|
||||
// Why: lets the home screen feed already-loaded HostProfiles so we don't pay loadHosts() latency twice.
|
||||
primeHosts: (hosts: HostProfile[]) => void
|
||||
}
|
||||
@@ -63,7 +60,6 @@ export function RpcClientProvider({ children }: { children: ReactNode }) {
|
||||
// Why: entries in a ref so state changes don't re-render the whole tree; propagation goes through per-host listener Sets.
|
||||
const storeRef = useRef<Map<string, StoreEntry>>(new Map())
|
||||
const stateListenersRef = useRef<Map<string, Set<(state: ConnectionState) => void>>>(new Map())
|
||||
const allHostsListenersRef = useRef<Set<() => void>>(new Set())
|
||||
|
||||
// Pending opens keyed by hostId so two acquire() callers in the same render don't race the host lookup.
|
||||
const pendingOpensRef = useRef(new HostClientOpenRegistry())
|
||||
@@ -74,7 +70,6 @@ export function RpcClientProvider({ children }: { children: ReactNode }) {
|
||||
|
||||
const notifyHostState = (hostId: string, state: ConnectionState) =>
|
||||
notifyHostStateListeners(stateListenersRef.current, hostId, state)
|
||||
const notifyAllHosts = () => notifyAllHostListeners(allHostsListenersRef.current)
|
||||
|
||||
const closeEntry = useCallback((hostId: string, options: CloseEntryOptions) => {
|
||||
const entry = storeRef.current.get(hostId)
|
||||
@@ -92,7 +87,6 @@ export function RpcClientProvider({ children }: { children: ReactNode }) {
|
||||
storeRef.current.delete(hostId)
|
||||
entry?.client.close()
|
||||
notifyHostState(hostId, 'disconnected')
|
||||
notifyAllHosts()
|
||||
}, [])
|
||||
|
||||
const closeHost = useCallback(
|
||||
@@ -126,13 +120,11 @@ export function RpcClientProvider({ children }: { children: ReactNode }) {
|
||||
} catch {
|
||||
// Why: cold-start Keychain failure (iOS mid-unlock / Android Keystore race); surface 'disconnected' so the user can Reconnect.
|
||||
notifyHostState(hostId, 'disconnected')
|
||||
notifyAllHosts()
|
||||
return null
|
||||
}
|
||||
if (!host) {
|
||||
// Why: silent return leaves screens on a permanent spinner (STA-1511); surface 'disconnected' so they show a retry affordance.
|
||||
notifyHostState(hostId, 'disconnected')
|
||||
notifyAllHosts()
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -153,7 +145,6 @@ export function RpcClientProvider({ children }: { children: ReactNode }) {
|
||||
} catch {
|
||||
// Why: openHostLogicalClient can throw synchronously (bad public key / invalid URL); notify so the UI leaves 'connecting'.
|
||||
notifyHostState(hostId, 'disconnected')
|
||||
notifyAllHosts()
|
||||
return null
|
||||
}
|
||||
const unsubState = client.onStateChange((state) => {
|
||||
@@ -173,7 +164,6 @@ export function RpcClientProvider({ children }: { children: ReactNode }) {
|
||||
pendingAcquisitionsRef.current.delete(hostId)
|
||||
storeRef.current.set(hostId, entry)
|
||||
notifyHostState(hostId, entry.state)
|
||||
notifyAllHosts()
|
||||
return entry
|
||||
} finally {
|
||||
pendingOpensRef.current.deleteIfCurrent(hostId, pendingOpen)
|
||||
@@ -312,11 +302,6 @@ export function RpcClientProvider({ children }: { children: ReactNode }) {
|
||||
[]
|
||||
)
|
||||
|
||||
const subscribeAllHosts = useCallback(
|
||||
(listener: () => void) => subscribeAllHostListener(allHostsListenersRef.current, listener),
|
||||
[]
|
||||
)
|
||||
|
||||
// Close all clients on provider unmount. Empty deps: [closeEntry] would let Fast Refresh tear down all live sockets.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
useEffect(() => {
|
||||
@@ -352,7 +337,6 @@ export function RpcClientProvider({ children }: { children: ReactNode }) {
|
||||
getActivePath,
|
||||
getClient,
|
||||
subscribeHostState,
|
||||
subscribeAllHosts,
|
||||
primeHosts
|
||||
}),
|
||||
[
|
||||
@@ -369,7 +353,6 @@ export function RpcClientProvider({ children }: { children: ReactNode }) {
|
||||
getActivePath,
|
||||
getClient,
|
||||
subscribeHostState,
|
||||
subscribeAllHosts,
|
||||
primeHosts
|
||||
]
|
||||
)
|
||||
|
||||
@@ -17,12 +17,6 @@ export function notifyHostStateListeners(
|
||||
}
|
||||
}
|
||||
|
||||
export function notifyAllHostListeners(listeners: Set<() => void>): void {
|
||||
for (const listener of listeners) {
|
||||
listener()
|
||||
}
|
||||
}
|
||||
|
||||
export function subscribeHostStateListener(
|
||||
listeners: Map<string, Set<(state: ConnectionState) => void>>,
|
||||
hostId: string,
|
||||
@@ -42,20 +36,6 @@ export function subscribeHostStateListener(
|
||||
}
|
||||
}
|
||||
|
||||
export function subscribeAllHostListener(
|
||||
listeners: Set<() => void>,
|
||||
listener: () => void
|
||||
): () => void {
|
||||
listeners.add(listener)
|
||||
return () => listeners.delete(listener)
|
||||
}
|
||||
|
||||
export function listHostClients(
|
||||
entries: ReadonlyMap<string, { client: RpcClient }>
|
||||
): { hostId: string; client: RpcClient }[] {
|
||||
return [...entries].map(([hostId, entry]) => ({ hostId, client: entry.client }))
|
||||
}
|
||||
|
||||
export function primeHostProfiles(cache: Map<string, HostProfile>, hosts: HostProfile[]): void {
|
||||
for (const host of hosts) {
|
||||
cache.set(host.id, host)
|
||||
|
||||
Reference in New Issue
Block a user