more consistent ipcRenderer.on handling, better maximize observer implementation

This commit is contained in:
Egor 2025-09-18 22:57:05 -07:00
parent a07ee2711f
commit dd5a9457e6
6 changed files with 77 additions and 66 deletions

View file

@ -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]);

View file

@ -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 (
<AppShell.Header
style={{ display: 'flex', flexDirection: 'column', border: 'none' }}

View file

@ -259,11 +259,10 @@ export const useKoboldVersions = () => {
}
};
window.electronAPI.kobold.onDownloadProgress?.(handleProgress);
const cleanup =
window.electronAPI.kobold.onDownloadProgress(handleProgress);
return () => {
window.electronAPI.kobold.removeAllListeners?.('download-progress');
};
return cleanup;
}, [downloading]);
return {

View file

@ -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());

View file

@ -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);
},
});

View file

@ -129,11 +129,10 @@ export interface KoboldAPI {
parseConfigFile: (filePath: string) => Promise<KoboldConfig | null>;
selectModelFile: (title?: string) => Promise<string | null>;
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<boolean>;
quitAndInstall: () => Promise<void>;
isUpdateDownloaded: () => Promise<boolean>;
onWindowStateToggle: (callback: () => void) => () => void;
}
export interface ConfigAPI {
@ -188,14 +188,10 @@ export interface DependenciesAPI {
}
export interface MonitoringAPI {
start: () => Promise<void>;
stop: () => Promise<void>;
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;
};
}
}