From 573be5501ea6f048e2ab8f2d09085170cbf08298 Mon Sep 17 00:00:00 2001 From: xmk23333 Date: Sun, 28 Dec 2025 12:22:28 +0800 Subject: [PATCH] refactor: simplify main process IPC handler registration --- src/main/utils/ipc.ts | 380 ++++++++++++++++++------------------------ 1 file changed, 158 insertions(+), 222 deletions(-) diff --git a/src/main/utils/ipc.ts b/src/main/utils/ipc.ts index 5d33cb7..f4db684 100644 --- a/src/main/utils/ipc.ts +++ b/src/main/utils/ipc.ts @@ -126,23 +126,31 @@ import { addProfileUpdater, removeProfileUpdater } from '../core/profileUpdater' import { readFile, writeFile } from 'fs/promises' // eslint-disable-next-line @typescript-eslint/no-explicit-any -function wrapAsync Promise>( +type AsyncFn = (...args: any[]) => Promise +// eslint-disable-next-line @typescript-eslint/no-explicit-any +type SyncFn = (...args: any[]) => any + +function wrapAsync( fn: T ): (...args: Parameters) => Promise | { invokeError: unknown }> { return async (...args) => { try { return await fn(...args) } catch (e) { - if (e && typeof e === 'object') { - if ('message' in e) { - return { invokeError: e.message } - } - return { invokeError: JSON.stringify(e) } + if (e && typeof e === 'object' && 'message' in e) { + return { invokeError: e.message } } - if (typeof e === 'string') { - return { invokeError: e } - } - return { invokeError: 'Unknown Error' } + return { invokeError: typeof e === 'string' ? e : 'Unknown Error' } + } + } +} + +function registerHandlers(handlers: Record, async = true): void { + for (const [channel, handler] of Object.entries(handlers)) { + if (async) { + ipcMain.handle(channel, (_e, ...args) => wrapAsync(handler as AsyncFn)(...args)) + } else { + ipcMain.handle(channel, (_e, ...args) => (handler as SyncFn)(...args)) } } } @@ -190,232 +198,160 @@ async function setTitleBarOverlay(overlay: Electron.TitleBarOverlayOptions): Pro } } -export function registerIpcMainHandlers(): void { +const asyncHandlers: Record = { // Mihomo API - ipcMain.handle('mihomoVersion', wrapAsync(mihomoVersion)) - ipcMain.handle('mihomoCloseConnection', (_e, id: string) => wrapAsync(mihomoCloseConnection)(id)) - ipcMain.handle('mihomoCloseAllConnections', wrapAsync(mihomoCloseAllConnections)) - ipcMain.handle('mihomoRules', wrapAsync(mihomoRules)) - ipcMain.handle('mihomoProxies', wrapAsync(mihomoProxies)) - ipcMain.handle('mihomoGroups', wrapAsync(mihomoGroups)) - ipcMain.handle('mihomoProxyProviders', wrapAsync(mihomoProxyProviders)) - ipcMain.handle('mihomoUpdateProxyProviders', (_e, name: string) => - wrapAsync(mihomoUpdateProxyProviders)(name) - ) - ipcMain.handle('mihomoRuleProviders', wrapAsync(mihomoRuleProviders)) - ipcMain.handle('mihomoUpdateRuleProviders', (_e, name: string) => - wrapAsync(mihomoUpdateRuleProviders)(name) - ) - ipcMain.handle('mihomoChangeProxy', (_e, group: string, proxy: string) => - wrapAsync(mihomoChangeProxy)(group, proxy) - ) - ipcMain.handle('mihomoUnfixedProxy', (_e, group: string) => wrapAsync(mihomoUnfixedProxy)(group)) - ipcMain.handle('mihomoUpgradeGeo', wrapAsync(mihomoUpgradeGeo)) - ipcMain.handle('mihomoUpgrade', wrapAsync(mihomoUpgrade)) - ipcMain.handle('mihomoUpgradeUI', wrapAsync(mihomoUpgradeUI)) - ipcMain.handle('mihomoUpgradeConfig', wrapAsync(mihomoUpgradeConfig)) - ipcMain.handle('mihomoProxyDelay', (_e, proxy: string, url?: string) => - wrapAsync(mihomoProxyDelay)(proxy, url) - ) - ipcMain.handle('mihomoGroupDelay', (_e, group: string, url?: string) => - wrapAsync(mihomoGroupDelay)(group, url) - ) - ipcMain.handle('patchMihomoConfig', (_e, patch: Partial) => - wrapAsync(patchMihomoConfig)(patch) - ) - ipcMain.handle('mihomoSmartGroupWeights', (_e, groupName: string) => - wrapAsync(mihomoSmartGroupWeights)(groupName) - ) - ipcMain.handle('mihomoSmartFlushCache', (_e, configName?: string) => - wrapAsync(mihomoSmartFlushCache)(configName) - ) - + mihomoVersion, + mihomoCloseConnection, + mihomoCloseAllConnections, + mihomoRules, + mihomoProxies, + mihomoGroups, + mihomoProxyProviders, + mihomoUpdateProxyProviders, + mihomoRuleProviders, + mihomoUpdateRuleProviders, + mihomoChangeProxy, + mihomoUnfixedProxy, + mihomoUpgradeGeo, + mihomoUpgrade, + mihomoUpgradeUI, + mihomoUpgradeConfig, + mihomoProxyDelay, + mihomoGroupDelay, + patchMihomoConfig, + mihomoSmartGroupWeights, + mihomoSmartFlushCache, // AutoRun - ipcMain.handle('checkAutoRun', wrapAsync(checkAutoRun)) - ipcMain.handle('enableAutoRun', wrapAsync(enableAutoRun)) - ipcMain.handle('disableAutoRun', wrapAsync(disableAutoRun)) - + checkAutoRun, + enableAutoRun, + disableAutoRun, // Config - ipcMain.handle('getAppConfig', (_e, force?: boolean) => wrapAsync(getAppConfig)(force)) - ipcMain.handle('patchAppConfig', (_e, config: Partial) => - wrapAsync(patchAppConfig)(config) - ) - ipcMain.handle('getControledMihomoConfig', (_e, force?: boolean) => - wrapAsync(getControledMihomoConfig)(force) - ) - ipcMain.handle('patchControledMihomoConfig', (_e, config: Partial) => - wrapAsync(patchControledMihomoConfig)(config) - ) - ipcMain.handle('resetAppConfig', () => resetAppConfig()) - + getAppConfig, + patchAppConfig, + getControledMihomoConfig, + patchControledMihomoConfig, // Profile - ipcMain.handle('getProfileConfig', (_e, force?: boolean) => wrapAsync(getProfileConfig)(force)) - ipcMain.handle('setProfileConfig', (_e, config: IProfileConfig) => - wrapAsync(setProfileConfig)(config) - ) - ipcMain.handle('getCurrentProfileItem', wrapAsync(getCurrentProfileItem)) - ipcMain.handle('getProfileItem', (_e, id?: string) => wrapAsync(getProfileItem)(id)) - ipcMain.handle('getProfileStr', (_e, id: string) => wrapAsync(getProfileStr)(id)) - ipcMain.handle('setProfileStr', (_e, id: string, str: string) => - wrapAsync(setProfileStr)(id, str) - ) - ipcMain.handle('addProfileItem', (_e, item: Partial) => - wrapAsync(addProfileItem)(item) - ) - ipcMain.handle('removeProfileItem', (_e, id: string) => wrapAsync(removeProfileItem)(id)) - ipcMain.handle('updateProfileItem', (_e, item: IProfileItem) => wrapAsync(updateProfileItem)(item)) - ipcMain.handle('changeCurrentProfile', (_e, id: string) => wrapAsync(changeCurrentProfile)(id)) - ipcMain.handle('addProfileUpdater', (_e, item: IProfileItem) => wrapAsync(addProfileUpdater)(item)) - ipcMain.handle('removeProfileUpdater', (_e, id: string) => wrapAsync(removeProfileUpdater)(id)) - + getProfileConfig, + setProfileConfig, + getCurrentProfileItem, + getProfileItem, + getProfileStr, + setProfileStr, + addProfileItem, + removeProfileItem, + updateProfileItem, + changeCurrentProfile, + addProfileUpdater, + removeProfileUpdater, // Override - ipcMain.handle('getOverrideConfig', (_e, force?: boolean) => wrapAsync(getOverrideConfig)(force)) - ipcMain.handle('setOverrideConfig', (_e, config: IOverrideConfig) => - wrapAsync(setOverrideConfig)(config) - ) - ipcMain.handle('getOverrideItem', (_e, id: string) => wrapAsync(getOverrideItem)(id)) - ipcMain.handle('addOverrideItem', (_e, item: Partial) => - wrapAsync(addOverrideItem)(item) - ) - ipcMain.handle('removeOverrideItem', (_e, id: string) => wrapAsync(removeOverrideItem)(id)) - ipcMain.handle('updateOverrideItem', (_e, item: IOverrideItem) => - wrapAsync(updateOverrideItem)(item) - ) - ipcMain.handle('getOverride', (_e, id: string, ext: 'js' | 'yaml' | 'log') => - wrapAsync(getOverride)(id, ext) - ) - ipcMain.handle('setOverride', (_e, id: string, ext: 'js' | 'yaml', str: string) => - wrapAsync(setOverride)(id, ext, str) - ) - + getOverrideConfig, + setOverrideConfig, + getOverrideItem, + addOverrideItem, + removeOverrideItem, + updateOverrideItem, + getOverride, + setOverride, // File - ipcMain.handle('getFileStr', (_e, filePath: string) => wrapAsync(getFileStr)(filePath)) - ipcMain.handle('setFileStr', (_e, filePath: string, str: string) => - wrapAsync(setFileStr)(filePath, str) - ) - ipcMain.handle('convertMrsRuleset', (_e, filePath: string, behavior: string) => - wrapAsync(convertMrsRuleset)(filePath, behavior) - ) - ipcMain.handle('getRuntimeConfig', wrapAsync(getRuntimeConfig)) - ipcMain.handle('getRuntimeConfigStr', wrapAsync(getRuntimeConfigStr)) - ipcMain.handle('getSmartOverrideContent', wrapAsync(getSmartOverrideContent)) - ipcMain.handle('getRuleStr', (_e, id: string) => wrapAsync(getRuleStr)(id)) - ipcMain.handle('setRuleStr', (_e, id: string, str: string) => wrapAsync(setRuleStr)(id, str)) - ipcMain.handle('getFilePath', (_e, ext: string[]) => getFilePath(ext)) - ipcMain.handle('readTextFile', (_e, filePath: string) => wrapAsync(readTextFile)(filePath)) - ipcMain.handle('openFile', (_e, type: 'profile' | 'override', id: string, ext?: 'yaml' | 'js') => - openFile(type, id, ext) - ) - + getFileStr, + setFileStr, + convertMrsRuleset, + getRuntimeConfig, + getRuntimeConfigStr, + getSmartOverrideContent, + getRuleStr, + setRuleStr, + readTextFile, // Core - ipcMain.handle('restartCore', wrapAsync(restartCore)) - ipcMain.handle('startMonitor', (_e, detached?: boolean) => wrapAsync(startMonitor)(detached)) - ipcMain.handle('quitWithoutCore', wrapAsync(quitWithoutCore)) - + restartCore, + startMonitor, + quitWithoutCore, // System - ipcMain.handle('triggerSysProxy', (_e, enable: boolean) => wrapAsync(triggerSysProxy)(enable)) - ipcMain.handle('checkTunPermissions', wrapAsync(checkTunPermissions)) - ipcMain.handle('grantTunPermissions', wrapAsync(grantTunPermissions)) - ipcMain.handle('manualGrantCorePermition', wrapAsync(manualGrantCorePermition)) - ipcMain.handle('checkAdminPrivileges', wrapAsync(checkAdminPrivileges)) - ipcMain.handle('restartAsAdmin', (_e, forTun?: boolean) => wrapAsync(restartAsAdmin)(forTun)) - ipcMain.handle('checkMihomoCorePermissions', wrapAsync(checkMihomoCorePermissions)) - ipcMain.handle('requestTunPermissions', wrapAsync(requestTunPermissions)) - ipcMain.handle('checkHighPrivilegeCore', wrapAsync(checkHighPrivilegeCore)) - ipcMain.handle('showTunPermissionDialog', wrapAsync(showTunPermissionDialog)) - ipcMain.handle('showErrorDialog', (_e, title: string, message: string) => - wrapAsync(showErrorDialog)(title, message) - ) - ipcMain.handle('openUWPTool', wrapAsync(openUWPTool)) - ipcMain.handle('setupFirewall', wrapAsync(setupFirewall)) - ipcMain.handle('getInterfaces', getInterfaces) - ipcMain.handle('setNativeTheme', (_e, theme: 'system' | 'light' | 'dark') => setNativeTheme(theme)) - ipcMain.handle('copyEnv', (_e, type: 'bash' | 'cmd' | 'powershell') => wrapAsync(copyEnv)(type)) - + triggerSysProxy, + checkTunPermissions, + grantTunPermissions, + manualGrantCorePermition, + checkAdminPrivileges, + restartAsAdmin, + checkMihomoCorePermissions, + requestTunPermissions, + checkHighPrivilegeCore, + showTunPermissionDialog, + showErrorDialog, + openUWPTool, + setupFirewall, + copyEnv, // Update - ipcMain.handle('checkUpdate', wrapAsync(checkUpdate)) - ipcMain.handle('downloadAndInstallUpdate', (_e, version: string) => - wrapAsync(downloadAndInstallUpdate)(version) - ) - ipcMain.handle('getVersion', () => app.getVersion()) - ipcMain.handle('platform', () => process.platform) - ipcMain.handle('fetchMihomoTags', (_e, forceRefresh?: boolean) => - wrapAsync(fetchMihomoTags)(forceRefresh) - ) - ipcMain.handle('installSpecificMihomoCore', (_e, version: string) => - wrapAsync(installSpecificMihomoCore)(version) - ) - ipcMain.handle('clearMihomoVersionCache', wrapAsync(clearMihomoVersionCache)) - + checkUpdate, + downloadAndInstallUpdate, + fetchMihomoTags, + installSpecificMihomoCore, + clearMihomoVersionCache, // Backup - ipcMain.handle('webdavBackup', wrapAsync(webdavBackup)) - ipcMain.handle('webdavRestore', (_e, filename: string) => wrapAsync(webdavRestore)(filename)) - ipcMain.handle('listWebdavBackups', wrapAsync(listWebdavBackups)) - ipcMain.handle('webdavDelete', (_e, filename: string) => wrapAsync(webdavDelete)(filename)) - ipcMain.handle('reinitWebdavBackupScheduler', wrapAsync(reinitScheduler)) - ipcMain.handle('exportLocalBackup', wrapAsync(exportLocalBackup)) - ipcMain.handle('importLocalBackup', wrapAsync(importLocalBackup)) - + webdavBackup, + webdavRestore, + listWebdavBackups, + webdavDelete, + reinitWebdavBackupScheduler: reinitScheduler, + exportLocalBackup, + importLocalBackup, // SubStore - ipcMain.handle('startSubStoreFrontendServer', wrapAsync(startSubStoreFrontendServer)) - ipcMain.handle('stopSubStoreFrontendServer', wrapAsync(stopSubStoreFrontendServer)) - ipcMain.handle('startSubStoreBackendServer', wrapAsync(startSubStoreBackendServer)) - ipcMain.handle('stopSubStoreBackendServer', wrapAsync(stopSubStoreBackendServer)) - ipcMain.handle('downloadSubStore', wrapAsync(downloadSubStore)) - ipcMain.handle('subStorePort', () => subStorePort) - ipcMain.handle('subStoreFrontendPort', () => subStoreFrontendPort) - ipcMain.handle('subStoreSubs', wrapAsync(subStoreSubs)) - ipcMain.handle('subStoreCollections', wrapAsync(subStoreCollections)) - + startSubStoreFrontendServer, + stopSubStoreFrontendServer, + startSubStoreBackendServer, + stopSubStoreBackendServer, + downloadSubStore, + subStoreSubs, + subStoreCollections, // Theme - ipcMain.handle('resolveThemes', wrapAsync(resolveThemes)) - ipcMain.handle('fetchThemes', wrapAsync(fetchThemes)) - ipcMain.handle('importThemes', (_e, files: string[]) => wrapAsync(importThemes)(files)) - ipcMain.handle('readTheme', (_e, theme: string) => wrapAsync(readTheme)(theme)) - ipcMain.handle('writeTheme', (_e, theme: string, css: string) => - wrapAsync(writeTheme)(theme, css) - ) - ipcMain.handle('applyTheme', (_e, theme: string) => wrapAsync(applyTheme)(theme)) - + resolveThemes, + fetchThemes, + importThemes, + readTheme, + writeTheme, + applyTheme, // Tray - ipcMain.handle('showTrayIcon', wrapAsync(showTrayIcon)) - ipcMain.handle('closeTrayIcon', wrapAsync(closeTrayIcon)) - ipcMain.handle('updateTrayIcon', wrapAsync(updateTrayIcon)) - ipcMain.handle('updateTrayIconImmediate', (_e, sysProxyEnabled: boolean, tunEnabled: boolean) => - updateTrayIconImmediate(sysProxyEnabled, tunEnabled) - ) - - // Window - ipcMain.handle('showMainWindow', showMainWindow) - ipcMain.handle('closeMainWindow', closeMainWindow) - ipcMain.handle('triggerMainWindow', (_e, force?: boolean) => triggerMainWindow(force)) - ipcMain.handle('showFloatingWindow', wrapAsync(showFloatingWindow)) - ipcMain.handle('closeFloatingWindow', wrapAsync(closeFloatingWindow)) - ipcMain.handle('showContextMenu', wrapAsync(showContextMenu)) - ipcMain.handle('setTitleBarOverlay', (_e, overlay: Electron.TitleBarOverlayOptions) => - wrapAsync(setTitleBarOverlay)(overlay) - ) - ipcMain.handle('setAlwaysOnTop', (_e, alwaysOnTop: boolean) => - mainWindow?.setAlwaysOnTop(alwaysOnTop) - ) - ipcMain.handle('isAlwaysOnTop', () => mainWindow?.isAlwaysOnTop()) - ipcMain.handle('openDevTools', () => mainWindow?.webContents.openDevTools()) - ipcMain.handle('createHeapSnapshot', () => - v8.writeHeapSnapshot(path.join(logDir(), `${Date.now()}.heapsnapshot`)) - ) - - // Shortcut - ipcMain.handle('registerShortcut', (_e, oldShortcut: string, newShortcut: string, action: string) => - wrapAsync(registerShortcut)(oldShortcut, newShortcut, action) - ) - + showTrayIcon, + closeTrayIcon, + updateTrayIcon, + // Floating Window + showFloatingWindow, + closeFloatingWindow, + showContextMenu, // Misc - ipcMain.handle('getGistUrl', wrapAsync(getGistUrl)) - ipcMain.handle('getImageDataURL', (_e, url: string) => wrapAsync(getImageDataURL)(url)) - ipcMain.handle('relaunchApp', () => { + getGistUrl, + getImageDataURL, + changeLanguage, + setTitleBarOverlay, + registerShortcut +} + +const syncHandlers: Record = { + resetAppConfig, + getFilePath, + openFile, + getInterfaces, + setNativeTheme, + getVersion: () => app.getVersion(), + platform: () => process.platform, + subStorePort: () => subStorePort, + subStoreFrontendPort: () => subStoreFrontendPort, + updateTrayIconImmediate, + showMainWindow, + closeMainWindow, + triggerMainWindow, + setAlwaysOnTop: (alwaysOnTop: boolean) => mainWindow?.setAlwaysOnTop(alwaysOnTop), + isAlwaysOnTop: () => mainWindow?.isAlwaysOnTop(), + openDevTools: () => mainWindow?.webContents.openDevTools(), + createHeapSnapshot: () => v8.writeHeapSnapshot(path.join(logDir(), `${Date.now()}.heapsnapshot`)), + relaunchApp: () => { app.relaunch() app.quit() - }) - ipcMain.handle('quitApp', () => app.quit()) - ipcMain.handle('changeLanguage', (_e, lng: string) => wrapAsync(changeLanguage)(lng)) + }, + quitApp: () => app.quit() +} + +export function registerIpcMainHandlers(): void { + registerHandlers(asyncHandlers, true) + registerHandlers(syncHandlers, false) }