feat(desktop): enhance error handling and logging for session synchronization and window mode transitions
Desktop Client Build / Resolve Build Metadata (push) Successful in 24s
Desktop Client Build / Build Desktop Client (push) Successful in 22m50s
Desktop Client Build / Publish Client Artifacts to NAS (push) Successful in 27s

This commit is contained in:
2026-06-04 16:39:30 +08:00
parent ae455ea21c
commit b40434018a
6 changed files with 85 additions and 22 deletions
@@ -62,6 +62,7 @@ const SOHU_ORIGIN = 'https://mp.sohu.com'
const SOHU_MANAGE_URL = `${SOHU_ORIGIN}/mpfe/v4/contentManagement/first/page?newsType=1` const SOHU_MANAGE_URL = `${SOHU_ORIGIN}/mpfe/v4/contentManagement/first/page?newsType=1`
const SOHU_PUBLISH_URL = `${SOHU_ORIGIN}/mpbp/bp/news/v4/news/publish/v2` const SOHU_PUBLISH_URL = `${SOHU_ORIGIN}/mpbp/bp/news/v4/news/publish/v2`
const SOHU_DRAFT_URL = `${SOHU_ORIGIN}/mpbp/bp/news/v4/news/draft/v2` const SOHU_DRAFT_URL = `${SOHU_ORIGIN}/mpbp/bp/news/v4/news/draft/v2`
const SOHU_NOT_LOGGED_IN_MESSAGE = '搜狐号账号登录态已失效,请重新登录搜狐号后再重试。'
function stringId(value: unknown): string { function stringId(value: unknown): string {
if (typeof value === 'number') { if (typeof value === 'number') {
@@ -296,7 +297,7 @@ function failureResult(
summary: '搜狐号登录态失效,无法执行发布。', summary: '搜狐号登录态失效,无法执行发布。',
error: { error: {
code: 'sohuhao_not_logged_in', code: 'sohuhao_not_logged_in',
message, message: SOHU_NOT_LOGGED_IN_MESSAGE,
}, },
} }
} }
+44 -15
View File
@@ -757,13 +757,39 @@ async function createSettingsWindow(): Promise<ElectronBrowserWindow> {
return window return window
} }
function flattenError(error: unknown): Error { function ipcErrorMessage(error: unknown): string {
if (error instanceof Error) { if (error instanceof Error) {
const copy = new Error(error.message || 'ipc_handler_failed') return error.message || 'ipc_handler_failed'
}
if (typeof error === 'string') {
return error || 'ipc_handler_failed'
}
if (
error &&
typeof error === 'object' &&
'message' in error &&
typeof (error as { message?: unknown }).message === 'string'
) {
return (error as { message: string }).message || 'ipc_handler_failed'
}
return 'ipc_handler_failed'
}
function flattenError(channel: string, error: unknown): Error {
const message = ipcErrorMessage(error)
console.error('[desktop-main] ipc handler failed', {
channel,
name: error instanceof Error ? error.name : typeof error,
message,
stack: error instanceof Error ? error.stack : undefined,
})
if (error instanceof Error) {
const copy = new Error(message)
copy.name = error.name copy.name = error.name
return copy return copy
} }
return new Error(typeof error === 'string' ? error : 'ipc_handler_failed') return new Error(message)
} }
function safeHandle<Args extends unknown[], Result>( function safeHandle<Args extends unknown[], Result>(
@@ -774,7 +800,7 @@ function safeHandle<Args extends unknown[], Result>(
try { try {
return await handler(...(args as unknown as Args)) return await handler(...(args as unknown as Args))
} catch (error) { } catch (error) {
throw flattenError(error) throw flattenError(channel, error)
} }
}) })
} }
@@ -1065,7 +1091,7 @@ function registerBridgeHandlers(): void {
return setDesktopAppSetting(key, value) return setDesktopAppSetting(key, value)
}, },
) )
ipcMain.handle( safeHandle(
'desktop:runtime-session-sync', 'desktop:runtime-session-sync',
(_event, session: DesktopRuntimeSessionSyncRequest | null) => { (_event, session: DesktopRuntimeSessionSyncRequest | null) => {
syncRuntimeSession(session) syncRuntimeSession(session)
@@ -1105,16 +1131,19 @@ function registerBridgeHandlers(): void {
await releaseRuntimeSession({ revoke: Boolean(revoke) }) await releaseRuntimeSession({ revoke: Boolean(revoke) })
return null return null
}) })
ipcMain.handle('desktop:set-window-mode', async (event, mode: WindowMode, request?: unknown) => { safeHandle(
if (mode === 'login' || mode === 'main') { 'desktop:set-window-mode',
await queueWindowModeSwitch( async (event: IpcMainInvokeEvent, mode: WindowMode, request?: unknown) => {
mode, if (mode === 'login' || mode === 'main') {
normalizeWindowModeRequest(request), await queueWindowModeSwitch(
windowFromIpcEvent(event), mode,
) normalizeWindowModeRequest(request),
} windowFromIpcEvent(event),
return null )
}) }
return null
},
)
} }
const hasSingleInstanceLock = initSingleInstance((argv) => { const hasSingleInstanceLock = initSingleInstance((argv) => {
+13 -2
View File
@@ -30,7 +30,14 @@ function getModeBridge(): WindowModeBridge | undefined {
} }
function syncWindowMode(authenticated: boolean): void { function syncWindowMode(authenticated: boolean): void {
void getModeBridge()?.setWindowMode?.(authenticated ? 'main' : 'login', { source: 'auth-state' }) void getModeBridge()
?.setWindowMode?.(authenticated ? 'main' : 'login', { source: 'auth-state' })
.catch((err) => {
console.warn('[desktop-app] window mode sync failed', {
authenticated,
message: err instanceof Error ? err.message : String(err),
})
})
} }
const rendererWindowMode = resolveRendererWindowMode() const rendererWindowMode = resolveRendererWindowMode()
@@ -62,7 +69,11 @@ if (rendererWindowMode === 'main') {
onMounted(() => { onMounted(() => {
if (rendererWindowMode !== 'login') { if (rendererWindowMode !== 'login') {
void syncRuntimeSession() void syncRuntimeSession().catch((err) => {
console.warn('[desktop-app] runtime session sync failed', {
message: err instanceof Error ? err.message : String(err),
})
})
} }
if (usesAutomaticWindowMode) { if (usesAutomaticWindowMode) {
syncWindowMode(isAuthenticated.value) syncWindowMode(isAuthenticated.value)
@@ -55,6 +55,13 @@ let logoutPromise: Promise<void> | null = null
let renewPromise: Promise<void> | null = null let renewPromise: Promise<void> | null = null
let tokenRenewTimer: ReturnType<typeof setInterval> | null = null let tokenRenewTimer: ReturnType<typeof setInterval> | null = null
function logRuntimeSessionSyncFailure(reason: string, err: unknown): void {
console.warn('[desktop-session] runtime session sync failed', {
reason,
message: err instanceof Error ? err.message : String(err),
})
}
function readStoredSession(): DesktopSession | null { function readStoredSession(): DesktopSession | null {
if (typeof window === 'undefined') { if (typeof window === 'undefined') {
return null return null
@@ -117,7 +124,9 @@ function persistSession(next: DesktopSession | null): void {
window.localStorage.setItem(sessionStorageKey, JSON.stringify(next)) window.localStorage.setItem(sessionStorageKey, JSON.stringify(next))
} }
void syncRuntimeSessionToMain(next) void syncRuntimeSessionToMain(next).catch((err) => {
logRuntimeSessionSyncFailure('persist-session', err)
})
} }
function readStoredApiBaseURL(): string { function readStoredApiBaseURL(): string {
@@ -141,7 +150,9 @@ function persistApiBaseURL(value: string): void {
window.localStorage.setItem(apiBaseURLStorageKey, normalized) window.localStorage.setItem(apiBaseURLStorageKey, normalized)
} }
void syncRuntimeSessionToMain() void syncRuntimeSessionToMain().catch((err) => {
logRuntimeSessionSyncFailure('api-base-url-change', err)
})
} }
function createPublicClient() { function createPublicClient() {
@@ -753,7 +764,9 @@ if (typeof window !== 'undefined') {
window.addEventListener('storage', (event) => { window.addEventListener('storage', (event) => {
if (event.key === apiBaseURLStorageKey) { if (event.key === apiBaseURLStorageKey) {
apiBaseURL.value = normalizeDesktopApiBaseURL(event.newValue, normalizedDefaultApiBaseURL) apiBaseURL.value = normalizeDesktopApiBaseURL(event.newValue, normalizedDefaultApiBaseURL)
void syncRuntimeSessionToMain() void syncRuntimeSessionToMain().catch((err) => {
logRuntimeSessionSyncFailure('storage-api-base-url-change', err)
})
} }
}) })
void syncStoredDesktopClientDeviceInfo() void syncStoredDesktopClientDeviceInfo()
@@ -62,7 +62,13 @@ async function submitLogin() {
password: form.password, password: form.password,
}) })
await persistCredentialsPreference() await persistCredentialsPreference()
await window.desktopBridge?.app?.setWindowMode?.('main', { source: 'login' }) try {
await window.desktopBridge?.app?.setWindowMode?.('main', { source: 'login' })
} catch (err) {
console.warn('[login-view] switch to main window failed', {
message: err instanceof Error ? err.message : String(err),
})
}
} }
async function hydrateSavedCredentials() { async function hydrateSavedCredentials() {
@@ -47,6 +47,9 @@ describe('publisher error normalization', () => {
expect(normalizePublisherErrorMessage('qiehao_cookie_missing')).toBe( expect(normalizePublisherErrorMessage('qiehao_cookie_missing')).toBe(
'企鹅号账号登录态已失效,请重新登录该平台后再重试。', '企鹅号账号登录态已失效,请重新登录该平台后再重试。',
) )
expect(normalizePublisherErrorMessage('sohuhao_not_logged_in')).toBe(
'搜狐号账号登录态已失效,请重新登录该平台后再重试。',
)
}) })
it('uses a generic Chinese message for unknown publisher login-state failures', () => { it('uses a generic Chinese message for unknown publisher login-state failures', () => {