mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-27 08:02:09 +08:00
fix(events): close run-state race and restore single error toasts
Self-review findings: the bus now re-reads the run-state snapshot in onSubscribed so an event racing the store's initial read cannot leave a stale snapshot (the ordering the old layout listener guaranteed), and the patch hooks pass errorNotice:false so GuardState/page handlers remain the only error toast, matching the pre-migration behavior.
This commit is contained in:
@@ -108,6 +108,7 @@ export const useClash = () => {
|
||||
await mutate(() => patchClashConfig(patch), {
|
||||
id: 'patch-clash-config',
|
||||
revalidate: [['getRuntimeConfig']],
|
||||
errorNotice: false,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -138,6 +139,7 @@ export const useClashInfo = () => {
|
||||
await mutate(() => patchClashConfig(patch), {
|
||||
id: 'patch-clash-info',
|
||||
revalidate: [['getClashInfo'], ['getClashConfig']],
|
||||
errorNotice: false,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -39,10 +39,13 @@ export const useVerge = () => {
|
||||
)
|
||||
}
|
||||
|
||||
// Callers own the error toast (GuardState onCatch / page onError), so the
|
||||
// funnel must not add a second one.
|
||||
const patchVerge = useCallback(async (value: Partial<IVergeConfig>) => {
|
||||
await mutate(() => patchVergeConfig(value), {
|
||||
id: 'patch-verge-config',
|
||||
revalidate: [['getVergeConfig']],
|
||||
errorNotice: false,
|
||||
})
|
||||
}, [])
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ const mountBus = async () => {
|
||||
revalidateProfiles: () => {},
|
||||
refreshProxyView: () => {},
|
||||
readPendingFailures: () => {},
|
||||
readRunState: () => {},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -190,6 +191,7 @@ it('routes every event exactly once through one handler', async () => {
|
||||
revalidateProfiles: vi.fn(),
|
||||
refreshProxyView: vi.fn(),
|
||||
readPendingFailures: vi.fn(),
|
||||
readRunState: vi.fn(),
|
||||
})
|
||||
|
||||
bus.handlers['verge://run-state-changed']({ mode: 'Service' } as RunState)
|
||||
|
||||
@@ -24,6 +24,8 @@ export interface BusHandlerDeps {
|
||||
refreshProxyView: () => void
|
||||
/** Re-read the backend pending-failure snapshot into the store. */
|
||||
readPendingFailures: () => void
|
||||
/** Re-read the run-state snapshot into the store. */
|
||||
readRunState: () => void
|
||||
}
|
||||
|
||||
export interface EventBus {
|
||||
@@ -107,6 +109,9 @@ export const createEventBus = (deps: BusHandlerDeps): EventBus => {
|
||||
} as BusHandlers
|
||||
|
||||
const onSubscribed = () => {
|
||||
// Run state is read after subscribing so an event racing the store's
|
||||
// initial read cannot leave a stale snapshot behind.
|
||||
deps.readRunState()
|
||||
deps.revalidateKeys(['getVergeConfig'])
|
||||
deps.readPendingFailures()
|
||||
deps.handleNotice(['dns_override::auto_disabled', ''])
|
||||
|
||||
@@ -28,6 +28,7 @@ vi.mock('@/store/app-store-context', () => ({
|
||||
}))
|
||||
vi.mock('@/services/cmds', () => ({
|
||||
getPendingFailures: vi.fn().mockResolvedValue([]),
|
||||
getRuntimeState: vi.fn().mockResolvedValue({ mode: 'NotRunning' }),
|
||||
}))
|
||||
vi.mock('@/services/query-client', () => ({ revalidateQueries: vi.fn() }))
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { listen, type UnlistenFn } from '@tauri-apps/api/event'
|
||||
import { getCurrentWindow } from '@tauri-apps/api/window'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
import { getPendingFailures } from '@/services/cmds'
|
||||
import { getPendingFailures, getRuntimeState } from '@/services/cmds'
|
||||
import { revalidateQueries } from '@/services/query-client'
|
||||
import { useAppDispatch } from '@/store/app-store-context'
|
||||
|
||||
@@ -31,6 +31,11 @@ export const useEventBus = (
|
||||
console.warn('[bus] pending failures could not be read:', error)
|
||||
})
|
||||
}
|
||||
const readRunState = () => {
|
||||
getRuntimeState()
|
||||
.then((runState) => dispatch({ type: 'runState/loaded', runState }))
|
||||
.catch(() => {})
|
||||
}
|
||||
|
||||
const bus = createEventBus({
|
||||
dispatch,
|
||||
@@ -41,6 +46,7 @@ export const useEventBus = (
|
||||
},
|
||||
refreshProxyView: () => revalidateKeys(['getProxyView']),
|
||||
readPendingFailures,
|
||||
readRunState,
|
||||
})
|
||||
|
||||
let disposed = false
|
||||
|
||||
Reference in New Issue
Block a user