Handle errors starting/updating presence monitors

This commit is contained in:
Samuel Elliott
2022-06-29 09:31:31 +01:00
parent b185b59d91
commit e5c54613d0
2 changed files with 106 additions and 62 deletions

View File

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

View File

@@ -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<CoralErrorResponse> | NodeJS.ErrnoException
): Promise<LoopResult> {
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<CoralErrorResponse> | NodeJS.ErrnoException) =>
Promise<LoopResult | void> | LoopResult | void = undefined;
enable() {
if (this._running !== 0) return;
@@ -298,20 +330,8 @@ export class EmbeddedPresenceMonitor extends ZncDiscordPresence {
async handleError(err: ErrorResponse<CoralErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
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<CoralErrorResponse> | NodeJS.ErrnoException) =>
Promise<LoopResult | void> | LoopResult | void = undefined;
enable() {
if (this._running !== 0) return;
@@ -364,20 +386,8 @@ export class EmbeddedProxyPresenceMonitor extends ZncProxyDiscordPresence {
async handleError(err: ErrorResponse<CoralErrorResponse> | NodeJS.ErrnoException): Promise<LoopResult> {
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;
}
}