From dd5a9457e64470aba777382b61b9a9d8dbab3fbe Mon Sep 17 00:00:00 2001 From: Egor Date: Thu, 18 Sep 2025 22:57:05 -0700 Subject: [PATCH] more consistent ipcRenderer.on handling, better maximize observer implementation --- src/components/StatusBar.tsx | 19 +++++---- src/components/TitleBar.tsx | 14 ++---- src/hooks/useKoboldVersions.ts | 7 ++- src/main/ipc.ts | 4 +- src/preload/index.ts | 78 ++++++++++++++++++++++------------ src/types/electron.d.ts | 21 +++------ 6 files changed, 77 insertions(+), 66 deletions(-) diff --git a/src/components/StatusBar.tsx b/src/components/StatusBar.tsx index fbcdfaf..574a04b 100644 --- a/src/components/StatusBar.tsx +++ b/src/components/StatusBar.tsx @@ -38,17 +38,20 @@ export const StatusBar = ({ maxDataPoints = 60 }: StatusBarProps) => { setGpuMetrics(metrics); }; - window.electronAPI.monitoring.onCpuMetrics(handleCpuMetrics); - window.electronAPI.monitoring.onMemoryMetrics(handleMemoryMetrics); - window.electronAPI.monitoring.onGpuMetrics(handleGpuMetrics); - void window.electronAPI.monitoring.start(); + const cleanupCpu = + window.electronAPI.monitoring.onCpuMetrics(handleCpuMetrics); + const cleanupMemory = + window.electronAPI.monitoring.onMemoryMetrics(handleMemoryMetrics); + const cleanupGpu = + window.electronAPI.monitoring.onGpuMetrics(handleGpuMetrics); + const stopMonitoring = window.electronAPI.monitoring.start(); return () => { isMounted = false; - window.electronAPI.monitoring.removeCpuMetricsListener(); - window.electronAPI.monitoring.removeMemoryMetricsListener(); - window.electronAPI.monitoring.removeGpuMetricsListener(); - window.electronAPI.monitoring.stop(); + cleanupCpu(); + cleanupMemory(); + cleanupGpu(); + stopMonitoring(); }; }, [maxDataPoints]); diff --git a/src/components/TitleBar.tsx b/src/components/TitleBar.tsx index baa57d0..8172985 100644 --- a/src/components/TitleBar.tsx +++ b/src/components/TitleBar.tsx @@ -39,18 +39,12 @@ export const TitleBar = ({ const [settingsModalOpen, setSettingsModalOpen] = useState(false); useEffect(() => { - const handleMaximize = () => setIsMaximized(true); - const handleUnmaximize = () => setIsMaximized(false); + const cleanup = window.electronAPI.app.onWindowStateToggle(() => + setIsMaximized((prev) => !prev) + ); - window.electronAPI.on('window-maximized', handleMaximize); - window.electronAPI.on('window-unmaximized', handleUnmaximize); - - return () => { - window.electronAPI.removeListener('window-maximized', handleMaximize); - window.electronAPI.removeListener('window-unmaximized', handleUnmaximize); - }; + return cleanup; }, []); - return ( { } }; - window.electronAPI.kobold.onDownloadProgress?.(handleProgress); + const cleanup = + window.electronAPI.kobold.onDownloadProgress(handleProgress); - return () => { - window.electronAPI.kobold.removeAllListeners?.('download-progress'); - }; + return cleanup; }, [downloading]); return { diff --git a/src/main/ipc.ts b/src/main/ipc.ts index 3ca252f..6b43501 100644 --- a/src/main/ipc.ts +++ b/src/main/ipc.ts @@ -273,14 +273,14 @@ export function setupIPCHandlers() { ipcMain.handle('dependencies:isUvAvailable', () => isUvAvailable()); - ipcMain.handle('monitoring:start', () => { + ipcMain.on('monitoring:start', () => { const mainWindow = getMainWindow(); if (mainWindow) { startMonitoring(mainWindow); } }); - ipcMain.handle('monitoring:stop', () => stopMonitoring()); + ipcMain.on('monitoring:stop', () => stopMonitoring()); ipcMain.handle('app:checkForUpdates', () => checkForUpdates()); diff --git a/src/preload/index.ts b/src/preload/index.ts index b829503..925b6ed 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -8,6 +8,11 @@ import type { MonitoringAPI, UpdaterAPI, } from '@/types/electron'; +import type { + CpuMetrics, + MemoryMetrics, + GpuMetrics, +} from '@/main/modules/monitoring'; const koboldAPI: KoboldAPI = { getInstalledVersions: () => ipcRenderer.invoke('kobold:getInstalledVersions'), @@ -42,10 +47,13 @@ const koboldAPI: KoboldAPI = { ipcRenderer.invoke('kobold:selectModelFile', title), stopKoboldCpp: () => ipcRenderer.invoke('kobold:stopKoboldCpp'), onDownloadProgress: (callback) => { - ipcRenderer.on( - 'download-progress', - (_: IpcRendererEvent, progress: number) => callback(progress) - ); + const handler = (_: IpcRendererEvent, progress: number) => + callback(progress); + ipcRenderer.on('download-progress', handler); + + return () => { + ipcRenderer.removeListener('download-progress', handler); + }; }, onInstallDirChanged: (callback) => { const handler = (_: IpcRendererEvent, newPath: string) => callback(newPath); @@ -71,9 +79,6 @@ const koboldAPI: KoboldAPI = { ipcRenderer.removeListener('kobold-output', handler); }; }, - removeAllListeners: (channel) => { - ipcRenderer.removeAllListeners(channel); - }, }; const appAPI: AppAPI = { @@ -95,6 +100,17 @@ const appAPI: AppAPI = { downloadUpdate: () => ipcRenderer.invoke('app:downloadUpdate'), quitAndInstall: () => ipcRenderer.invoke('app:quitAndInstall'), isUpdateDownloaded: () => ipcRenderer.invoke('app:isUpdateDownloaded'), + onWindowStateToggle: (callback) => { + const handler = () => callback(); + + ipcRenderer.on('window-maximized', handler); + ipcRenderer.on('window-unmaximized', handler); + + return () => { + ipcRenderer.removeListener('window-maximized', handler); + ipcRenderer.removeListener('window-unmaximized', handler); + }; + }, }; const configAPI: ConfigAPI = { @@ -113,25 +129,39 @@ const dependenciesAPI: DependenciesAPI = { }; const monitoringAPI: MonitoringAPI = { - start: () => ipcRenderer.invoke('monitoring:start'), - stop: () => ipcRenderer.invoke('monitoring:stop'), + start: () => { + ipcRenderer.send('monitoring:start'); + + return () => { + ipcRenderer.send('monitoring:stop'); + }; + }, onCpuMetrics: (callback) => { - ipcRenderer.on('cpu-metrics', (_, metrics) => callback(metrics)); + const handler = (_: IpcRendererEvent, metrics: CpuMetrics) => + callback(metrics); + ipcRenderer.on('cpu-metrics', handler); + + return () => { + ipcRenderer.removeListener('cpu-metrics', handler); + }; }, onMemoryMetrics: (callback) => { - ipcRenderer.on('memory-metrics', (_, metrics) => callback(metrics)); + const handler = (_: IpcRendererEvent, metrics: MemoryMetrics) => + callback(metrics); + ipcRenderer.on('memory-metrics', handler); + + return () => { + ipcRenderer.removeListener('memory-metrics', handler); + }; }, onGpuMetrics: (callback) => { - ipcRenderer.on('gpu-metrics', (_, metrics) => callback(metrics)); - }, - removeCpuMetricsListener: () => { - ipcRenderer.removeAllListeners('cpu-metrics'); - }, - removeMemoryMetricsListener: () => { - ipcRenderer.removeAllListeners('memory-metrics'); - }, - removeGpuMetricsListener: () => { - ipcRenderer.removeAllListeners('gpu-metrics'); + const handler = (_: IpcRendererEvent, metrics: GpuMetrics) => + callback(metrics); + ipcRenderer.on('gpu-metrics', handler); + + return () => { + ipcRenderer.removeListener('gpu-metrics', handler); + }; }, }; @@ -152,10 +182,4 @@ contextBridge.exposeInMainWorld('electronAPI', { dependencies: dependenciesAPI, monitoring: monitoringAPI, updater: updaterAPI, - on: (channel: string, callback: (...args: unknown[]) => void) => { - ipcRenderer.on(channel, (_, ...args) => callback(...args)); - }, - removeListener: (channel: string, callback: (...args: unknown[]) => void) => { - ipcRenderer.removeListener(channel, callback); - }, }); diff --git a/src/types/electron.d.ts b/src/types/electron.d.ts index e44aa63..65abf11 100644 --- a/src/types/electron.d.ts +++ b/src/types/electron.d.ts @@ -129,11 +129,10 @@ export interface KoboldAPI { parseConfigFile: (filePath: string) => Promise; selectModelFile: (title?: string) => Promise; stopKoboldCpp: () => void; - onDownloadProgress: (callback: (progress: number) => void) => void; + onDownloadProgress: (callback: (progress: number) => void) => () => void; onInstallDirChanged: (callback: (newPath: string) => void) => () => void; onVersionsUpdated: (callback: () => void) => () => void; onKoboldOutput: (callback: (data: string) => void) => () => void; - removeAllListeners: (channel: string) => void; } export interface VersionInfo { @@ -171,6 +170,7 @@ export interface AppAPI { downloadUpdate: () => Promise; quitAndInstall: () => Promise; isUpdateDownloaded: () => Promise; + onWindowStateToggle: (callback: () => void) => () => void; } export interface ConfigAPI { @@ -188,14 +188,10 @@ export interface DependenciesAPI { } export interface MonitoringAPI { - start: () => Promise; - stop: () => Promise; - onCpuMetrics: (callback: (metrics: CpuMetrics) => void) => void; - onMemoryMetrics: (callback: (metrics: MemoryMetrics) => void) => void; - onGpuMetrics: (callback: (metrics: GpuMetrics) => void) => void; - removeCpuMetricsListener: () => void; - removeMemoryMetricsListener: () => void; - removeGpuMetricsListener: () => void; + start: () => () => void; + onCpuMetrics: (callback: (metrics: CpuMetrics) => void) => () => void; + onMemoryMetrics: (callback: (metrics: MemoryMetrics) => void) => () => void; + onGpuMetrics: (callback: (metrics: GpuMetrics) => void) => () => void; } export interface UpdaterAPI { @@ -217,11 +213,6 @@ declare global { dependencies: DependenciesAPI; monitoring: MonitoringAPI; updater: UpdaterAPI; - on: (channel: string, callback: (...args: unknown[]) => void) => void; - removeListener: ( - channel: string, - callback: (...args: unknown[]) => void - ) => void; }; } }