@@ -83,16 +83,17 @@ electronApp.setAppUserModelId('ai.moeru.airi')
8383initScreenCaptureForMain ( )
8484
8585let fileLogger : FileLoggerHandle = nullFileLoggerHandle
86+ let skipFileLogging = false
8687
8788app . whenReady ( ) . then ( async ( ) => {
8889 // Initialize file logger and register the hook
8990 fileLogger = await setupFileLogger ( )
9091
9192 // Register the global hook for file logging
9293 setGlobalHookPostLog ( ( _ , formatted ) => {
93- if ( fileLogger . logFileFd !== null ) {
94- void fileLogger . appendLog ( formatted )
95- }
94+ if ( skipFileLogging || fileLogger . logFileFd === null )
95+ return
96+ void fileLogger . appendLog ( formatted )
9697 } )
9798
9899 injeca . setLogger ( createLoggLogger ( useLogg ( 'injeca' ) . useGlobalConfig ( ) ) )
@@ -211,13 +212,37 @@ async function handleAppExit() {
211212
212213 appExiting = true
213214
215+ let exitedNormally = true
216+
217+ /**
218+ * Safely execute fn and log any errors that occur, marking the exit as abnormal
219+ * if an error is caught.
220+ *
221+ * @param operation - A verb phrase describing the operation.
222+ * @param fn - Any function to execute. It can be either sync or async.
223+ * @returns A promise that resolves when the operation is complete.
224+ */
225+ async function logIfError ( operation : string , fn : ( ) => unknown ) : Promise < void > {
226+ try {
227+ await fn ( )
228+ }
229+ catch ( error ) {
230+ exitedNormally = false
231+ log . withError ( error ) . error ( `[app-exit] Failed to ${ operation } :` )
232+ }
233+ }
234+
214235 await Promise . all ( [
215- emitAppBeforeQuit ( ) ,
216- injeca . stop ( ) ,
217- fileLogger . close ( ) , // Ensure all logs are flushed
236+ logIfError ( 'execute onAppBeforeQuit hooks' , ( ) => emitAppBeforeQuit ( ) ) ,
237+ logIfError ( 'stop injeca' , ( ) => injeca . stop ( ) ) ,
218238 ] )
219239
220- app . exit ( 0 )
240+ // Prevent the global log hook from trying to write to the file after close() is called,
241+ // which would cause a recursive failure if close() itself throws.
242+ skipFileLogging = true
243+ await logIfError ( 'flush file logs' , ( ) => fileLogger . close ( ) ) // Ensure all logs are flushed
244+
245+ app . exit ( exitedNormally ? 0 : 1 )
221246}
222247
223248process . on ( 'SIGINT' , ( ) => handleAppExit ( ) )
0 commit comments