From 0b905a7f678e6a8add0fefa9764e9e0cce4e2b76 Mon Sep 17 00:00:00 2001 From: Egor Date: Thu, 18 Sep 2025 18:30:21 -0700 Subject: [PATCH] remove the double try/catch cases on the frontend side for cleaner code --- src/App.tsx | 57 ++++----- src/components/ErrorBoundary.tsx | 8 +- src/components/PerformanceBadge.tsx | 8 +- src/components/screens/Download.tsx | 27 ++--- src/components/screens/Launch/AdvancedTab.tsx | 6 +- .../Launch/GeneralTab/BackendSelector.tsx | 7 +- src/components/screens/Launch/index.tsx | 67 +++++------ src/components/settings/AboutTab.tsx | 52 ++------ src/components/settings/AppearanceTab.tsx | 32 ++--- src/components/settings/GeneralTab.tsx | 26 ++-- src/components/settings/VersionsTab.tsx | 82 ++++++------- src/hooks/useAppColorScheme.ts | 6 +- src/hooks/useAppUpdateChecker.ts | 16 +-- src/hooks/useUpdateChecker.ts | 12 +- src/hooks/useWarnings.ts | 112 ++++++++---------- src/main/modules/autoUpdater.ts | 2 - src/main/modules/logging.ts | 38 +++--- src/main/modules/performance.ts | 37 ++++-- src/stores/frontendPreference.ts | 15 +-- src/utils/{shared => }/logger-core.ts | 0 src/utils/logger.ts | 2 +- src/utils/node/logger.ts | 2 +- 22 files changed, 250 insertions(+), 364 deletions(-) rename src/utils/{shared => }/logger-core.ts (100%) diff --git a/src/App.tsx b/src/App.tsx index bfa33c1..d7c3c4b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -12,7 +12,6 @@ import { StatusBar } from '@/components/StatusBar'; import { ErrorBoundary } from '@/components/ErrorBoundary'; import { useUpdateChecker } from '@/hooks/useUpdateChecker'; import { useKoboldVersions } from '@/hooks/useKoboldVersions'; -import { safeExecute } from '@/utils/logger'; import { STATUSBAR_HEIGHT, TITLEBAR_HEIGHT } from '@/constants'; import type { DownloadItem } from '@/types/electron'; import type { InterfaceTab, Screen } from '@/types'; @@ -40,26 +39,24 @@ export const App = () => { useEffect(() => { const checkInstallation = async () => { - await safeExecute(async () => { - const [currentVersion, hasSeenWelcome] = await Promise.all([ - window.electronAPI.kobold.getCurrentVersion(), - window.electronAPI.config.get('hasSeenWelcome') as Promise, - ]); + const [currentVersion, hasSeenWelcome] = await Promise.all([ + window.electronAPI.kobold.getCurrentVersion(), + window.electronAPI.config.get('hasSeenWelcome') as Promise, + ]); - if (!hasSeenWelcome) { - setCurrentScreen('welcome'); - } else if (currentVersion) { - setCurrentScreen('launch'); - } else { - setCurrentScreen('download'); - } + if (!hasSeenWelcome) { + setCurrentScreen('welcome'); + } else if (currentVersion) { + setCurrentScreen('launch'); + } else { + setCurrentScreen('download'); + } - if (currentVersion) { - setTimeout(() => { - checkForUpdates(); - }, 2000); - } - }, 'Error checking installation:'); + if (currentVersion) { + setTimeout(() => { + checkForUpdates(); + }, 2000); + } setHasInitialized(true); }; @@ -69,23 +66,19 @@ export const App = () => { }, []); const handleBinaryUpdate = async (download: DownloadItem) => { - await safeExecute(async () => { - const success = await sharedHandleDownload({ - item: download, - isUpdate: true, - wasCurrentBinary: true, - }); + const success = await sharedHandleDownload({ + item: download, + isUpdate: true, + wasCurrentBinary: true, + }); - if (success) { - dismissUpdate(); - } - }, 'Failed to update binary:'); + if (success) { + dismissUpdate(); + } }; const handleDownloadComplete = async () => { - await safeExecute(async () => { - await window.electronAPI.kobold.getCurrentVersion(); - }, 'Error refreshing versions after download:'); + await window.electronAPI.kobold.getCurrentVersion(); setTimeout(() => { setCurrentScreen('launch'); diff --git a/src/components/ErrorBoundary.tsx b/src/components/ErrorBoundary.tsx index 8e3e98f..7ab2faf 100644 --- a/src/components/ErrorBoundary.tsx +++ b/src/components/ErrorBoundary.tsx @@ -2,7 +2,6 @@ import { ReactNode } from 'react'; import { Center, Stack, Text, Button, Alert, rem } from '@mantine/core'; import { AlertTriangle, FolderOpen } from 'lucide-react'; import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary'; -import { safeExecute } from '@/utils/logger'; interface ErrorBoundaryProps { children: ReactNode; @@ -39,12 +38,7 @@ const ErrorFallback = ({ leftSection={ } - onClick={async () => { - await safeExecute( - () => window.electronAPI.app.showLogsFolder(), - 'Failed to open logs folder' - ); - }} + onClick={() => window.electronAPI.app.showLogsFolder()} > Show Logs Folder diff --git a/src/components/PerformanceBadge.tsx b/src/components/PerformanceBadge.tsx index 19bf5fd..a4d3aa3 100644 --- a/src/components/PerformanceBadge.tsx +++ b/src/components/PerformanceBadge.tsx @@ -1,6 +1,5 @@ import { Badge, Tooltip } from '@mantine/core'; import { useState } from 'react'; -import { safeExecute } from '@/utils/logger'; interface PerformanceBadgeProps { label: string; @@ -16,12 +15,9 @@ export const PerformanceBadge = ({ const [isHovered, setIsHovered] = useState(false); const handlePerformanceClick = async () => { - const result = await safeExecute( - () => window.electronAPI.app.openPerformanceManager(), - 'Failed to open performance manager' - ); + const result = await window.electronAPI.app.openPerformanceManager(); - if (result && !result.success) { + if (!result.success) { window.electronAPI.logs.logError( `Failed to open performance manager: ${result.error}` ); diff --git a/src/components/screens/Download.tsx b/src/components/screens/Download.tsx index e6cdf69..fd81af8 100644 --- a/src/components/screens/Download.tsx +++ b/src/components/screens/Download.tsx @@ -1,11 +1,10 @@ -import { useState, useCallback, useEffect, useRef } from 'react'; +import { useState, useCallback, useRef, useEffect } from 'react'; import { Card, Text, Title, Loader, Stack, Container } from '@mantine/core'; import { DownloadCard } from '@/components/DownloadCard'; import { getPlatformDisplayName } from '@/utils/platform'; import { formatDownloadSize } from '@/utils/format'; import { getAssetDescription } from '@/utils/assets'; import { useKoboldVersions } from '@/hooks/useKoboldVersions'; -import { safeExecute } from '@/utils/logger'; import type { DownloadItem } from '@/types/electron'; interface DownloadScreenProps { @@ -32,21 +31,19 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => { async (download: DownloadItem) => { setDownloadingAsset(download.name); - await safeExecute(async () => { - const success = await sharedHandleDownload({ - item: download, - isUpdate: false, - wasCurrentBinary: false, - }); + const success = await sharedHandleDownload({ + item: download, + isUpdate: false, + wasCurrentBinary: false, + }); - if (success) { - onDownloadComplete(); + if (success) { + onDownloadComplete(); - setTimeout(() => { - setDownloadingAsset(null); - }, 200); - } - }, `Failed to download ${download.name}:`); + setTimeout(() => { + setDownloadingAsset(null); + }, 200); + } setDownloadingAsset(null); }, diff --git a/src/components/screens/Launch/AdvancedTab.tsx b/src/components/screens/Launch/AdvancedTab.tsx index 45a4b0a..5ee4b9a 100644 --- a/src/components/screens/Launch/AdvancedTab.tsx +++ b/src/components/screens/Launch/AdvancedTab.tsx @@ -11,7 +11,6 @@ import { InfoTooltip } from '@/components/InfoTooltip'; import { CheckboxWithTooltip } from '@/components/CheckboxWithTooltip'; import { CommandLineArgumentsModal } from '@/components/CommandLineArgumentsModal'; import { useLaunchConfig } from '@/hooks/useLaunchConfig'; -import { safeExecute } from '@/utils/logger'; export const AdvancedTab = () => { const { @@ -56,10 +55,7 @@ export const AdvancedTab = () => { useEffect(() => { const detectBackendSupport = async () => { - const support = await safeExecute( - () => window.electronAPI.kobold.detectBackendSupport(), - 'Failed to detect backend support:' - ); + const support = await window.electronAPI.kobold.detectBackendSupport(); if (support) { setBackendSupport({ diff --git a/src/components/screens/Launch/GeneralTab/BackendSelector.tsx b/src/components/screens/Launch/GeneralTab/BackendSelector.tsx index 898c141..760c0c5 100644 --- a/src/components/screens/Launch/GeneralTab/BackendSelector.tsx +++ b/src/components/screens/Launch/GeneralTab/BackendSelector.tsx @@ -4,7 +4,6 @@ import { InfoTooltip } from '@/components/InfoTooltip'; import { BackendSelectItem } from '@/components/screens/Launch/GeneralTab/BackendSelectItem'; import { GpuDeviceSelector } from '@/components/screens/Launch/GeneralTab/GpuDeviceSelector'; import { useLaunchConfig } from '@/hooks/useLaunchConfig'; -import { safeExecute } from '@/utils/logger'; import type { BackendOption } from '@/types'; export const BackendSelector = () => { @@ -26,10 +25,8 @@ export const BackendSelector = () => { useEffect(() => { const loadBackends = async () => { setIsLoadingBackends(true); - const backends = await safeExecute( - () => window.electronAPI.kobold.getAvailableBackends(true), - 'Failed to detect available backends:' - ); + const backends = + await window.electronAPI.kobold.getAvailableBackends(true); setAvailableBackends(backends || []); setIsLoadingBackends(false); hasInitialized.current = true; diff --git a/src/components/screens/Launch/index.tsx b/src/components/screens/Launch/index.tsx index b3509ac..50ebda7 100644 --- a/src/components/screens/Launch/index.tsx +++ b/src/components/screens/Launch/index.tsx @@ -1,6 +1,6 @@ import { Card, Container, Stack, Tabs, Group, Button } from '@mantine/core'; import { useState, useEffect, useCallback, useRef } from 'react'; -import { logError, safeExecute } from '@/utils/logger'; +import { logError } from '@/utils/logger'; import { useLaunchConfig } from '@/hooks/useLaunchConfig'; import { useLaunchLogic } from '@/hooks/useLaunchLogic'; import { useWarnings } from '@/hooks/useWarnings'; @@ -81,10 +81,7 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => { }); const setHappyDefaults = useCallback(async () => { - const backends = await safeExecute( - () => window.electronAPI.kobold.getAvailableBackends(), - 'Failed to set defaults:' - ); + const backends = await window.electronAPI.kobold.getAvailableBackends(); if (!backend && backends && backends.length > 0) { handleBackendChange(backends[0].value); @@ -183,24 +180,22 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => { }); const handleCreateNewConfig = async (configName: string) => { - await safeExecute(async () => { - const fullConfigName = `${configName}.json`; - const saveSuccess = await window.electronAPI.kobold.saveConfigFile( - fullConfigName, - buildConfigData() - ); + const fullConfigName = `${configName}.json`; + const saveSuccess = await window.electronAPI.kobold.saveConfigFile( + fullConfigName, + buildConfigData() + ); - if (saveSuccess) { - await loadConfigFiles(); - setSelectedFile(fullConfigName); - await window.electronAPI.kobold.setSelectedConfig(fullConfigName); - } else { - logError( - 'Failed to create new configuration', - new Error('Save operation failed') - ); - } - }, 'Failed to create new configuration:'); + if (saveSuccess) { + await loadConfigFiles(); + setSelectedFile(fullConfigName); + await window.electronAPI.kobold.setSelectedConfig(fullConfigName); + } else { + logError( + 'Failed to create new configuration', + new Error('Save operation failed') + ); + } }; const handleSaveConfig = async () => { @@ -212,24 +207,20 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => { return false; } - const success = await safeExecute(async () => { - const saveSuccess = await window.electronAPI.kobold.saveConfigFile( - selectedFile, - buildConfigData() + const saveSuccess = await window.electronAPI.kobold.saveConfigFile( + selectedFile, + buildConfigData() + ); + + if (!saveSuccess) { + logError( + 'Failed to save configuration', + new Error('Save operation failed') ); + return false; + } - if (!saveSuccess) { - logError( - 'Failed to save configuration', - new Error('Save operation failed') - ); - return false; - } - - return true; - }, 'Failed to save configuration:'); - - return success ?? false; + return true; }; useEffect(() => { diff --git a/src/components/settings/AboutTab.tsx b/src/components/settings/AboutTab.tsx index 05d5815..3f7948d 100644 --- a/src/components/settings/AboutTab.tsx +++ b/src/components/settings/AboutTab.tsx @@ -24,10 +24,7 @@ export const AboutTab = () => { const { handleLogoClick, getLogoStyles } = useLogoClickSounds(); useEffect(() => { const loadVersionInfo = async () => { - const info = await safeExecute( - () => window.electronAPI.app.getVersionInfo(), - 'Failed to load version info' - ); + const info = await window.electronAPI.app.getVersionInfo(); if (info) { setVersionInfo(info); } @@ -48,11 +45,9 @@ export const AboutTab = () => { { label: 'Electron', value: versionInfo.electronVersion }, { label: 'Node.js', - value: - versionInfo.nodeJsSystemVersion && - versionInfo.nodeJsSystemVersion !== versionInfo.nodeVersion - ? `${versionInfo.nodeVersion} (System: ${versionInfo.nodeJsSystemVersion})` - : versionInfo.nodeVersion, + value: versionInfo.nodeJsSystemVersion + ? `${versionInfo.nodeVersion} (System: ${versionInfo.nodeJsSystemVersion})` + : versionInfo.nodeVersion, }, { label: 'Chromium', value: versionInfo.chromeVersion }, { label: 'V8', value: versionInfo.v8Version }, @@ -66,21 +61,9 @@ export const AboutTab = () => { ]; const copyVersionInfo = async () => { - const nodeJsInfo = - versionInfo.nodeJsSystemVersion && - versionInfo.nodeJsSystemVersion !== versionInfo.nodeVersion - ? `${versionInfo.nodeVersion} (system: ${versionInfo.nodeJsSystemVersion})` - : versionInfo.nodeVersion; - - const info = [ - `${PRODUCT_NAME}: ${versionInfo.appVersion}`, - `Electron: ${versionInfo.electronVersion}`, - `Node.js: ${nodeJsInfo}`, - `Chromium: ${versionInfo.chromeVersion}`, - `V8: ${versionInfo.v8Version}`, - `OS: ${versionInfo.platform} ${versionInfo.arch} (${versionInfo.osVersion})`, - ...(versionInfo.uvVersion ? [`uv: ${versionInfo.uvVersion}`] : []), - ].join('\n'); + const info = versionItems + .map((item) => `${item.label}: ${item.value}`) + .join('\n'); await safeExecute( () => navigator.clipboard.writeText(info), @@ -128,15 +111,11 @@ export const AboutTab = () => { leftSection={ } - onClick={async () => { - await safeExecute( - () => - window.electronAPI.app.openExternal( - 'https://github.com/lone-cloud/gerbil' - ), - 'Failed to open GitHub link' - ); - }} + onClick={() => + window.electronAPI.app.openExternal( + 'https://github.com/lone-cloud/gerbil' + ) + } style={{ textDecoration: 'none' }} > GitHub @@ -148,12 +127,7 @@ export const AboutTab = () => { leftSection={ } - onClick={async () => { - await safeExecute( - () => window.electronAPI.app.showLogsFolder(), - 'Failed to open logs folder' - ); - }} + onClick={() => window.electronAPI.app.showLogsFolder()} > Show Logs diff --git a/src/components/settings/AppearanceTab.tsx b/src/components/settings/AppearanceTab.tsx index b77242b..68b814a 100644 --- a/src/components/settings/AppearanceTab.tsx +++ b/src/components/settings/AppearanceTab.tsx @@ -10,7 +10,6 @@ import { } from '@mantine/core'; import { Sun, Moon, Monitor } from 'lucide-react'; import { useState, useEffect } from 'react'; -import { safeExecute } from '@/utils/logger'; import { useAppColorScheme } from '@/hooks/useAppColorScheme'; import { zoomLevelToPercentage, @@ -33,14 +32,8 @@ export const AppearanceTab = () => { useEffect(() => { const loadSettings = async () => { const [currentZoom, savedColorScheme] = await Promise.all([ - safeExecute( - () => window.electronAPI.app.getZoomLevel(), - 'Failed to load zoom level:' - ), - safeExecute( - () => window.electronAPI.app.getColorScheme(), - 'Failed to load color scheme:' - ), + window.electronAPI.app.getZoomLevel(), + window.electronAPI.app.getColorScheme(), ]); if (typeof currentZoom === 'number') { @@ -56,38 +49,29 @@ export const AppearanceTab = () => { void loadSettings(); }, []); - const handleColorSchemeChange = async (value: string) => { + const handleColorSchemeChange = (value: string) => { const newColorScheme = value as MantineColorScheme; setRawColorScheme(newColorScheme); - await safeExecute( - () => window.electronAPI.app.setColorScheme(newColorScheme), - 'Failed to save color scheme:' - ); + void window.electronAPI.app.setColorScheme(newColorScheme); }; - const handleZoomChange = async (newZoomLevel: number) => { + const handleZoomChange = (newZoomLevel: number) => { setZoomLevel(newZoomLevel); const percentage = zoomLevelToPercentage(newZoomLevel); setZoomPercentage(percentage.toString()); - await safeExecute( - () => window.electronAPI.app.setZoomLevel(newZoomLevel), - 'Failed to set zoom level:' - ); + void window.electronAPI.app.setZoomLevel(newZoomLevel); }; - const handleZoomPercentageChange = async (value: string) => { + const handleZoomPercentageChange = (value: string) => { setZoomPercentage(value); const numValue = Number(value); if (!isNaN(numValue) && isValidZoomPercentage(numValue)) { const newZoomLevel = percentageToZoomLevel(numValue); setZoomLevel(newZoomLevel); - await safeExecute( - () => window.electronAPI.app.setZoomLevel(newZoomLevel), - 'Failed to set zoom level:' - ); + void window.electronAPI.app.setZoomLevel(newZoomLevel); } }; diff --git a/src/components/settings/GeneralTab.tsx b/src/components/settings/GeneralTab.tsx index 0b547d5..1e73634 100644 --- a/src/components/settings/GeneralTab.tsx +++ b/src/components/settings/GeneralTab.tsx @@ -1,5 +1,5 @@ import { useState, useEffect, useCallback, useMemo } from 'react'; -import { tryExecute, safeExecute } from '@/utils/logger'; +import { tryExecute } from '@/utils/logger'; import { Stack, Text, @@ -99,11 +99,8 @@ export const GeneralTab = ({ for (const config of frontendConfigs) { if (config.requirementCheck) { - const isAvailable = await safeExecute( - config.requirementCheck, - `Failed to check requirements for ${config.label}:` - ); - requirementResults.set(config.value, isAvailable ?? false); + const isAvailable = await config.requirementCheck(); + requirementResults.set(config.value, isAvailable); } else { requirementResults.set(config.value, true); } @@ -163,20 +160,15 @@ export const GeneralTab = ({ }, [FrontendPreference, checkAllFrontendRequirements]); const loadCurrentInstallDir = async () => { - const currentDir = await safeExecute( - () => window.electronAPI.kobold.getCurrentInstallDir(), - 'Failed to load install directory:' - ); + const currentDir = await window.electronAPI.kobold.getCurrentInstallDir(); if (currentDir) { setInstallDir(currentDir); } }; const loadFrontendPreference = async () => { - const frontendPreference = await safeExecute( - () => window.electronAPI.config.get('frontendPreference'), - 'Failed to load frontend preference:' - ); + const frontendPreference = + await window.electronAPI.config.get('frontendPreference'); if (frontendPreference) { setFrontendPreference( (frontendPreference as FrontendPreference) || 'koboldcpp' @@ -185,10 +177,8 @@ export const GeneralTab = ({ }; const handleSelectInstallDir = async () => { - const selectedDir = await safeExecute( - () => window.electronAPI.kobold.selectInstallDirectory(), - 'Failed to select install directory:' - ); + const selectedDir = + await window.electronAPI.kobold.selectInstallDirectory(); if (selectedDir) { setInstallDir(selectedDir); } diff --git a/src/components/settings/VersionsTab.tsx b/src/components/settings/VersionsTab.tsx index 7a1b4ba..e2ce047 100644 --- a/src/components/settings/VersionsTab.tsx +++ b/src/components/settings/VersionsTab.tsx @@ -16,7 +16,6 @@ import { stripAssetExtensions, compareVersions, } from '@/utils/version'; -import { safeExecute } from '@/utils/logger'; import { formatDownloadSize } from '@/utils/format'; import { useKoboldVersions } from '@/hooks/useKoboldVersions'; @@ -60,24 +59,19 @@ export const VersionsTab = () => { const loadInstalledVersions = useCallback(async () => { setLoadingInstalled(true); - await safeExecute(async () => { - const [versions, currentVersion] = await Promise.all([ - window.electronAPI.kobold.getInstalledVersions(), - window.electronAPI.kobold.getCurrentVersion(), - ]); + const [versions, currentVersion] = await Promise.all([ + window.electronAPI.kobold.getInstalledVersions(), + window.electronAPI.kobold.getCurrentVersion(), + ]); - setInstalledVersions(versions); - setCurrentVersion(currentVersion); - }, 'Failed to load installed versions:'); + setInstalledVersions(versions); + setCurrentVersion(currentVersion); setLoadingInstalled(false); }, []); const loadLatestRelease = useCallback(async () => { - const release = await safeExecute( - () => getLatestReleaseWithDownloadStatus(), - 'Failed to load latest release:' - ); + const release = await getLatestReleaseWithDownloadStatus(); if (release) { setLatestRelease(release); } @@ -174,55 +168,45 @@ export const VersionsTab = () => { }, [downloading]); const handleDownload = async (version: VersionInfo) => { - await safeExecute(async () => { - const download = availableDownloads.find((d) => d.name === version.name); - if (!download) { - throw new Error('Download not found'); - } + const download = availableDownloads.find((d) => d.name === version.name); + if (!download) return; - const success = await sharedHandleDownload({ - item: download, - isUpdate: false, - wasCurrentBinary: false, - }); + const success = await sharedHandleDownload({ + item: download, + isUpdate: false, + wasCurrentBinary: false, + }); - if (success) { - await loadInstalledVersions(); - } - }, 'Failed to download:'); + if (success) { + await loadInstalledVersions(); + } }; const handleUpdate = async (version: VersionInfo) => { - await safeExecute(async () => { - const download = availableDownloads.find((d) => d.name === version.name); - if (!download) { - throw new Error('Download not found'); - } + const download = availableDownloads.find((d) => d.name === version.name); + if (!download) return; - const success = await sharedHandleDownload({ - item: download, - isUpdate: true, - wasCurrentBinary: version.isCurrent, - }); + const success = await sharedHandleDownload({ + item: download, + isUpdate: true, + wasCurrentBinary: version.isCurrent, + }); - if (success) { - await loadInstalledVersions(); - } - }, 'Failed to update:'); + if (success) { + await loadInstalledVersions(); + } }; const makeCurrent = async (version: VersionInfo) => { if (!version.installedPath) return; - await safeExecute(async () => { - const success = await window.electronAPI.kobold.setCurrentVersion( - version.installedPath! - ); + const success = await window.electronAPI.kobold.setCurrentVersion( + version.installedPath + ); - if (success) { - await loadInstalledVersions(); - } - }, 'Failed to set current version:'); + if (success) { + await loadInstalledVersions(); + } }; if (loadingInstalled || loadingPlatform || loadingRemote) { diff --git a/src/hooks/useAppColorScheme.ts b/src/hooks/useAppColorScheme.ts index 04e5413..338f6a0 100644 --- a/src/hooks/useAppColorScheme.ts +++ b/src/hooks/useAppColorScheme.ts @@ -1,6 +1,5 @@ import { useState, useEffect } from 'react'; import { useMantineColorScheme } from '@mantine/core'; -import { safeExecute } from '@/utils/logger'; type ColorScheme = 'light' | 'dark'; @@ -10,10 +9,7 @@ export const useAppColorScheme = () => { useEffect(() => { const loadColorScheme = async () => { - const rawScheme = await safeExecute( - () => window.electronAPI.app.getColorScheme(), - 'Failed to get app color scheme' - ); + const rawScheme = await window.electronAPI.app.getColorScheme(); if (rawScheme) { let resolvedScheme: ColorScheme; diff --git a/src/hooks/useAppUpdateChecker.ts b/src/hooks/useAppUpdateChecker.ts index 7936384..c094d17 100644 --- a/src/hooks/useAppUpdateChecker.ts +++ b/src/hooks/useAppUpdateChecker.ts @@ -1,5 +1,5 @@ import { useState, useCallback, useEffect } from 'react'; -import { safeExecute, tryExecute } from '@/utils/logger'; +import { tryExecute } from '@/utils/logger'; import { compareVersions } from '@/utils/version'; import { GITHUB_API } from '@/constants'; @@ -19,18 +19,12 @@ export const useAppUpdateChecker = () => { useEffect(() => { const initializeUpdater = async () => { const [canUpdate, isDownloaded] = await Promise.all([ - safeExecute( - () => window.electronAPI.updater.canAutoUpdate(), - 'Failed to check auto-update capability' - ), - safeExecute( - () => window.electronAPI.updater.isUpdateDownloaded(), - 'Failed to check update download status' - ), + window.electronAPI.updater.canAutoUpdate(), + window.electronAPI.updater.isUpdateDownloaded(), ]); - if (canUpdate !== null) setCanAutoUpdate(canUpdate); - if (isDownloaded !== null) setIsUpdateDownloaded(isDownloaded); + setCanAutoUpdate(canUpdate); + setIsUpdateDownloaded(isDownloaded); }; void initializeUpdater(); diff --git a/src/hooks/useUpdateChecker.ts b/src/hooks/useUpdateChecker.ts index 765d4c8..f82b24c 100644 --- a/src/hooks/useUpdateChecker.ts +++ b/src/hooks/useUpdateChecker.ts @@ -1,5 +1,5 @@ import { useState, useCallback, useEffect } from 'react'; -import { tryExecute, safeExecute } from '@/utils/logger'; +import { tryExecute } from '@/utils/logger'; import { getDisplayNameFromPath, compareVersions, @@ -27,13 +27,9 @@ export const useUpdateChecker = () => { useEffect(() => { const loadDismissedUpdates = async () => { - const dismissed = await safeExecute( - async () => - (await window.electronAPI.config.get('dismissedUpdates')) as - | string[] - | undefined, - 'Failed to load dismissed updates' - ); + const dismissed = (await window.electronAPI.config.get( + 'dismissedUpdates' + )) as string[] | undefined; if (dismissed) { setDismissedUpdates(new Set(dismissed)); diff --git a/src/hooks/useWarnings.ts b/src/hooks/useWarnings.ts index cde2cc4..b80312e 100644 --- a/src/hooks/useWarnings.ts +++ b/src/hooks/useWarnings.ts @@ -1,5 +1,4 @@ import { useEffect, useState, useCallback, useMemo } from 'react'; -import { safeExecute } from '@/utils/logger'; import type { BackendOption, BackendSupport } from '@/types'; export interface Warning { @@ -105,10 +104,7 @@ const checkVramWarnings = async (backend: string): Promise => { const isGpuBackend = ['cuda', 'rocm', 'vulkan', 'clblast'].includes(backend); if (isGpuBackend) { - const gpuMemoryInfo = await safeExecute( - () => window.electronAPI.kobold.detectGPUMemory(), - 'Failed to detect GPU memory:' - ); + const gpuMemoryInfo = await window.electronAPI.kobold.detectGPUMemory(); if (gpuMemoryInfo) { const lowVramThreshold = 8; @@ -189,47 +185,43 @@ const checkBackendWarnings = async (params?: { }): Promise => { const warnings: Warning[] = []; - const result = await safeExecute(async () => { - const [backendSupport, gpuCapabilities, gpuInfo] = await Promise.all([ - window.electronAPI.kobold.detectBackendSupport(), - window.electronAPI.kobold.detectGPUCapabilities(), - window.electronAPI.kobold.detectGPU(), - ]); - - if (!backendSupport) { - return warnings; - } - - const gpuWarnings = await checkGpuWarnings( - backendSupport, - gpuCapabilities, - gpuInfo - ); - warnings.push(...gpuWarnings); - - if (params) { - const { backend, cpuCapabilities, noavx2, failsafe, availableBackends } = - params; - - const vramWarnings = await checkVramWarnings(backend); - warnings.push(...vramWarnings); - - if (cpuCapabilities) { - const cpuWarnings = checkCpuWarnings( - backend, - cpuCapabilities, - noavx2, - failsafe, - availableBackends - ); - warnings.push(...cpuWarnings); - } - } + const [backendSupport, gpuCapabilities, gpuInfo] = await Promise.all([ + window.electronAPI.kobold.detectBackendSupport(), + window.electronAPI.kobold.detectGPUCapabilities(), + window.electronAPI.kobold.detectGPU(), + ]); + if (!backendSupport) { return warnings; - }, 'Failed to check backend warnings:'); + } - return result || warnings; + const gpuWarnings = await checkGpuWarnings( + backendSupport, + gpuCapabilities, + gpuInfo + ); + warnings.push(...gpuWarnings); + + if (params) { + const { backend, cpuCapabilities, noavx2, failsafe, availableBackends } = + params; + + const vramWarnings = await checkVramWarnings(backend); + warnings.push(...vramWarnings); + + if (cpuCapabilities) { + const cpuWarnings = checkCpuWarnings( + backend, + cpuCapabilities, + noavx2, + failsafe, + availableBackends + ); + warnings.push(...cpuWarnings); + } + } + + return warnings; }; export const useWarnings = ({ @@ -253,27 +245,25 @@ export const useWarnings = ({ return; } - const result = await safeExecute(async () => { - const [cpuCapabilitiesResult, availableBackends] = await Promise.all([ - window.electronAPI.kobold.detectCPU(), - window.electronAPI.kobold.getAvailableBackends(), - ]); + const [cpuCapabilitiesResult, availableBackends] = await Promise.all([ + window.electronAPI.kobold.detectCPU(), + window.electronAPI.kobold.getAvailableBackends(), + ]); - const cpuCapabilities = { - avx: cpuCapabilitiesResult.avx, - avx2: cpuCapabilitiesResult.avx2, - }; + const cpuCapabilities = { + avx: cpuCapabilitiesResult.avx, + avx2: cpuCapabilitiesResult.avx2, + }; - return checkBackendWarnings({ - backend, - cpuCapabilities, - noavx2, - failsafe, - availableBackends, - }); - }, 'Failed to check backend warnings:'); + const result = await checkBackendWarnings({ + backend, + cpuCapabilities, + noavx2, + failsafe, + availableBackends, + }); - setBackendWarnings(result || []); + setBackendWarnings(result); }, [backend, noavx2, failsafe]); useEffect(() => { diff --git a/src/main/modules/autoUpdater.ts b/src/main/modules/autoUpdater.ts index a24e4d8..708592a 100644 --- a/src/main/modules/autoUpdater.ts +++ b/src/main/modules/autoUpdater.ts @@ -37,7 +37,6 @@ setupAutoUpdater(); export const checkForUpdates = async () => { if (isDevelopment) { - logError('Auto-updater: Cannot check for updates in development mode'); return false; } @@ -51,7 +50,6 @@ export const checkForUpdates = async () => { export const downloadUpdate = async () => { if (isDevelopment) { - logError('Auto-updater: Cannot download updates in development mode'); return false; } diff --git a/src/main/modules/logging.ts b/src/main/modules/logging.ts index a7b41d4..4f0972a 100644 --- a/src/main/modules/logging.ts +++ b/src/main/modules/logging.ts @@ -1,21 +1,29 @@ import { app } from 'electron'; import { join } from 'path'; -import { createLogger, format, type Logger } from 'winston'; +import { mkdir } from 'fs/promises'; +import { createLogger, format } from 'winston'; import DailyRotateFile from 'winston-daily-rotate-file'; import { isDevelopment } from '@/utils/node/environment'; -let logger: Logger | null = null; -let isInitialized = false; - -export const initializeLogger = () => { - if (isInitialized) return; +const ensureLogsDirectory = async (logsDir: string) => { + try { + await mkdir(logsDir, { recursive: true }); + } catch { + return; + } +}; +const createAppLogger = () => { const logsDir = join(app.getPath('userData'), 'logs'); - logger = createLogger({ + void ensureLogsDirectory(logsDir); + + return createLogger({ level: isDevelopment ? 'debug' : 'info', format: format.combine( - format.timestamp(), + format.timestamp({ + format: 'YYYY-MM-DD HH:mm:ss.SSS', + }), format.printf(({ timestamp, level, message, error }) => { let logEntry = `${timestamp} [MAIN] [${level.toUpperCase()}] ${message}`; @@ -40,25 +48,17 @@ export const initializeLogger = () => { }), ], }); - - isInitialized = true; }; -const ensureInitialized = () => { - if (!isInitialized) { - initializeLogger(); - } -}; +const logger = createAppLogger(); export const logError = (message: string, error?: Error) => { - ensureInitialized(); - logger!.error(message, { error }); + logger.error(message, { error }); flushLogs(); }; export const flushLogs = () => { - ensureInitialized(); - const fileTransport = logger!.transports.find( + const fileTransport = logger.transports.find( (t) => t.constructor.name === 'DailyRotateFile' ); if ( diff --git a/src/main/modules/performance.ts b/src/main/modules/performance.ts index 4183069..6fba554 100644 --- a/src/main/modules/performance.ts +++ b/src/main/modules/performance.ts @@ -1,4 +1,4 @@ -import { execa } from 'execa'; +import { spawn } from 'child_process'; import { platform } from 'process'; import { safeExecute } from '@/utils/node/logger'; @@ -12,16 +12,37 @@ const LINUX_PERFORMANCE_APPS = [ ]; async function tryLaunchCommand(command: string, args: string[] = []) { - try { - await execa(command, args, { + return new Promise((resolve) => { + const child = spawn(command, args, { detached: true, stdio: 'ignore', - timeout: 2000, }); - return true; - } catch { - return false; - } + + let hasResolved = false; + + child.on('error', () => { + if (!hasResolved) { + hasResolved = true; + resolve(false); + } + }); + + child.on('spawn', () => { + if (!hasResolved) { + hasResolved = true; + child.unref(); + resolve(true); + } + }); + + setTimeout(() => { + if (!hasResolved) { + hasResolved = true; + child.kill(); + resolve(false); + } + }, 2000); + }); } export const openPerformanceManager = async () => diff --git a/src/stores/frontendPreference.ts b/src/stores/frontendPreference.ts index 1318178..5ffaba6 100644 --- a/src/stores/frontendPreference.ts +++ b/src/stores/frontendPreference.ts @@ -1,5 +1,4 @@ import { create } from 'zustand'; -import { safeExecute } from '@/utils/logger'; import type { FrontendPreference } from '@/types'; interface FrontendPreferenceState { @@ -15,19 +14,15 @@ export const useFrontendPreferenceStore = create()( setFrontendPreference: (preference: FrontendPreference) => { set({ frontendPreference: preference }); - safeExecute(async () => { - await window.electronAPI.config.set('frontendPreference', preference); - }, 'Error saving frontend preference:'); + window.electronAPI.config.set('frontendPreference', preference); }, loadFromConfig: async () => { - await safeExecute(async () => { - const preference = (await window.electronAPI.config.get( - 'frontendPreference' - )) as FrontendPreference; + const preference = (await window.electronAPI.config.get( + 'frontendPreference' + )) as FrontendPreference; - set({ frontendPreference: preference || 'koboldcpp' }); - }, 'Error loading frontend preference:'); + set({ frontendPreference: preference || 'koboldcpp' }); }, }) ); diff --git a/src/utils/shared/logger-core.ts b/src/utils/logger-core.ts similarity index 100% rename from src/utils/shared/logger-core.ts rename to src/utils/logger-core.ts diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 0f9d8f3..81669a7 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -3,7 +3,7 @@ import { createTryExecute, createTryExecuteImmediate, createSafeTryExecute, -} from '@/utils/shared/logger-core'; +} from '@/utils/logger-core'; export const logError = (message: string, error: Error) => { window.electronAPI.logs.logError(message, error); diff --git a/src/utils/node/logger.ts b/src/utils/node/logger.ts index 2d813aa..f6acec5 100644 --- a/src/utils/node/logger.ts +++ b/src/utils/node/logger.ts @@ -3,7 +3,7 @@ import { createSafeExecute, createTryExecute, createSafeTryExecute, -} from '@/utils/shared/logger-core'; +} from '@/utils/logger-core'; export const safeExecute = createSafeExecute(logError); export const tryExecute = createTryExecute(logError);