diff --git a/src/app/main/index.ts b/src/app/main/index.ts index e242058..474da07 100644 --- a/src/app/main/index.ts +++ b/src/app/main/index.ts @@ -10,7 +10,7 @@ import MenuApp from './menu.js'; import { handleOpenWebServiceUri } from './webservices.js'; import { EmbeddedPresenceMonitor, PresenceMonitorManager } from './monitor.js'; import { createWindow } from './windows.js'; -import { DiscordPresenceConfiguration, WindowType } from '../common/types.js'; +import { DiscordPresenceConfiguration, DiscordPresenceSourceUrl, WindowType } from '../common/types.js'; import { initStorage, paths } from '../../util/storage.js'; import { checkUpdates, UpdateCacheData } from '../../common/update.js'; import Users, { CoralUser } from '../../common/users.js'; @@ -206,44 +206,78 @@ export class Store extends EventEmitter { if (!state) return; for (const user of state.users) { - const discord_presence_active = state.discord_presence && 'na_id' in state.discord_presence.source && - state.discord_presence.source.na_id === user.id; - - if (!discord_presence_active && - !user.user_notifications && - !user.friend_notifications - ) continue; - - try { - await monitors.start(user.id, monitor => { - monitor.presence_user = state.discord_presence && 'na_id' in state.discord_presence.source && - state.discord_presence.source.na_id === user.id ? - state.discord_presence.source.friend_nsa_id ?? monitor.data.nsoAccount.user.nsaId : null; - monitor.user_notifications = user.user_notifications; - monitor.friend_notifications = user.friend_notifications; - - if (monitor.presence_user) { - monitors.setDiscordPresenceConfigurationForMonitor(monitor, state.discord_presence!); - this.emit('update-discord-presence-source', monitors.getDiscordPresenceSource()); - } - }); - } catch (err) { - dialog.showErrorBox('Error restoring monitor for user ' + user.id, - err instanceof Error ? err.stack ?? err.message : err as any); - } + this.restoreUserMonitorState(monitors, state, user); } if (state.discord_presence && 'url' in state.discord_presence.source) { - try { - const monitor = await monitors.startUrl(state.discord_presence.source.url); - monitors.setDiscordPresenceConfigurationForMonitor(monitor, state.discord_presence); - this.emit('update-discord-presence-source', monitors.getDiscordPresenceSource()); - } catch (err) { - dialog.showErrorBox('Error restoring monitor for presence URL ' + state.discord_presence.source.url, - err instanceof Error ? err.stack ?? err.message : err as any); + this.restorePresenceUrlMonitorState(monitors, state); + } + } + + async restoreUserMonitorState( + monitors: PresenceMonitorManager, + state: SavedMonitorState, user: SavedMonitorState['users'][0] + ): Promise { + const discord_presence_active = state.discord_presence && 'na_id' in state.discord_presence.source && + state.discord_presence.source.na_id === user.id; + + if (!discord_presence_active && + !user.user_notifications && + !user.friend_notifications + ) return; + + try { + await monitors.start(user.id, monitor => { + monitor.presence_user = state.discord_presence && 'na_id' in state.discord_presence.source && + state.discord_presence.source.na_id === user.id ? + state.discord_presence.source.friend_nsa_id ?? monitor.data.nsoAccount.user.nsaId : null; + monitor.user_notifications = user.user_notifications; + monitor.friend_notifications = user.friend_notifications; + + if (monitor.presence_user) { + monitors.setDiscordPresenceConfigurationForMonitor(monitor, state.discord_presence!); + this.emit('update-discord-presence-source', monitors.getDiscordPresenceSource()); + } + }); + + await this.app.menu?.updateMenu(); + } catch (err) { + const {response} = await dialog.showMessageBox({ + message: 'Error restoring monitor for user ' + user.id, + detail: err instanceof Error ? err.stack ?? err.message : err as any, + type: 'error', + buttons: ['OK', 'Retry'], + }); + + if (response === 1) { + return this.restoreUserMonitorState(monitors, state, user); } } + } - await this.app.menu?.updateMenu(); + async restorePresenceUrlMonitorState( + monitors: PresenceMonitorManager, + state: SavedMonitorState + ): Promise { + if (!state.discord_presence || !('url' in state.discord_presence.source)) return; + + try { + const monitor = await monitors.startUrl(state.discord_presence.source.url); + monitors.setDiscordPresenceConfigurationForMonitor(monitor, state.discord_presence); + this.emit('update-discord-presence-source', monitors.getDiscordPresenceSource()); + + await this.app.menu?.updateMenu(); + } catch (err) { + const {response} = await dialog.showMessageBox({ + message: 'Error restoring monitor for presence URL ' + state.discord_presence.source.url, + detail: err instanceof Error ? err.stack ?? err.message : err as any, + type: 'error', + buttons: ['OK', 'Retry'], + }); + + if (response === 1) { + return this.restorePresenceUrlMonitorState(monitors, state); + } + } } } diff --git a/src/app/main/monitor.ts b/src/app/main/monitor.ts index 29e35aa..b28b2a9 100644 --- a/src/app/main/monitor.ts +++ b/src/app/main/monitor.ts @@ -49,6 +49,8 @@ export class PresenceMonitorManager { this.app.store.emit('update-discord-user', client?.user ?? null); }; + i.onError = err => this.handleError(i, err); + this.monitors.push(i); callback?.call(null, i, true); @@ -75,6 +77,8 @@ export class PresenceMonitorManager { this.app.store.emit('update-discord-user', client?.user ?? null); }; + i.onError = err => this.handleError(i, err); + this.monitors.push(i); i.enable(); @@ -253,10 +257,38 @@ export class PresenceMonitorManager { if (monitor instanceof ZncDiscordPresence) monitor.show_active_event = existing.show_active_event; monitor.show_play_time = existing.show_play_time; } + + async handleError( + monitor: EmbeddedPresenceMonitor | EmbeddedProxyPresenceMonitor, + err: ErrorResponse | NodeJS.ErrnoException + ): Promise { + const {response} = await dialog.showMessageBox(err instanceof ErrorResponse ? { + message: 'Request error updating presence monitor', + detail: err.response.status + ' ' + err.response.statusText + ' ' + + err.response.url + '\n' + + err.body + '\n\n' + + (err.stack ?? err.message), + type: 'error', + buttons: ['OK', 'Retry'], + } : { + message: 'Error updating presence monitor', + detail: err instanceof Error ? err.stack ?? err.message : err as any, + type: 'error', + buttons: ['OK', 'Retry'], + }); + + if (response === 1) { + return LoopResult.OK_SKIP_INTERVAL; + } + + return LoopResult.OK; + } } export class EmbeddedPresenceMonitor extends ZncDiscordPresence { notifications = new ElectronNotificationManager(); + onError?: (error: ErrorResponse | NodeJS.ErrnoException) => + Promise | LoopResult | void = undefined; enable() { if (this._running !== 0) return; @@ -298,20 +330,8 @@ export class EmbeddedPresenceMonitor extends ZncDiscordPresence { async handleError(err: ErrorResponse | NodeJS.ErrnoException): Promise { try { return await super.handleError(err); - } catch (err) { - if (err instanceof ErrorResponse) { - dialog.showErrorBox('Request error', - err.response.status + ' ' + err.response.statusText + ' ' + - err.response.url + '\n' + - err.body + '\n\n' + - (err.stack ?? err.message)); - } else if (err instanceof Error) { - dialog.showErrorBox(err.name, err.stack ?? err.message); - } else { - dialog.showErrorBox('Error', err as any); - } - - return LoopResult.OK; + } catch (err: any) { + return await this.onError?.call(null, err) ?? LoopResult.OK; } } @@ -323,6 +343,8 @@ export class EmbeddedPresenceMonitor extends ZncDiscordPresence { export class EmbeddedProxyPresenceMonitor extends ZncProxyDiscordPresence { notifications = new ElectronNotificationManager(); + onError?: (error: ErrorResponse | NodeJS.ErrnoException) => + Promise | LoopResult | void = undefined; enable() { if (this._running !== 0) return; @@ -364,20 +386,8 @@ export class EmbeddedProxyPresenceMonitor extends ZncProxyDiscordPresence { async handleError(err: ErrorResponse | NodeJS.ErrnoException): Promise { try { return await super.handleError(err); - } catch (err) { - if (err instanceof ErrorResponse) { - dialog.showErrorBox('Request error', - err.response.status + ' ' + err.response.statusText + ' ' + - err.response.url + '\n' + - err.body + '\n\n' + - (err.stack ?? err.message)); - } else if (err instanceof Error) { - dialog.showErrorBox(err.name, err.stack ?? err.message); - } else { - dialog.showErrorBox('Error', err as any); - } - - return LoopResult.OK; + } catch (err: any) { + return await this.onError?.call(null, err) ?? LoopResult.OK; } }