mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-03-21 18:04:10 -05:00
Show presence update errors in the main window
This commit is contained in:
parent
7b838e9b3e
commit
dfb2a3eea7
|
|
@ -1,23 +1,39 @@
|
|||
import React, { useCallback, useEffect } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
import { User } from 'discord-rpc';
|
||||
import ipc, { events } from '../ipc.js';
|
||||
import { RequestState, useAsync, useEventListener } from '../util.js';
|
||||
import { DiscordPresenceSource, DiscordPresenceSourceUrl, DiscordPresenceSourceCoral } from '../../common/types.js';
|
||||
import { DiscordPresenceSource, DiscordPresenceSourceUrl, DiscordPresenceSourceCoral, DiscordStatus } from '../../common/types.js';
|
||||
import { DiscordPresence } from '../../../discord/types.js';
|
||||
import { DISCORD_COLOUR, TEXT_COLOUR_DARK } from '../constants.js';
|
||||
import Warning from '../components/icons/warning.js';
|
||||
|
||||
export default function DiscordPresenceSource(props: {
|
||||
source: DiscordPresenceSource | null;
|
||||
presence: DiscordPresence | null;
|
||||
user: User | null;
|
||||
}) {
|
||||
const [status, setStatus] = useState<DiscordStatus | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
ipc.getDiscordStatus().then(setStatus);
|
||||
}, [ipc]);
|
||||
|
||||
useEventListener(events, 'update-discord-status', setStatus, []);
|
||||
|
||||
const showErrorDetails = useCallback(() => {
|
||||
ipc.showDiscordLastUpdateError();
|
||||
}, [ipc]);
|
||||
|
||||
if (!props.source) return null;
|
||||
|
||||
return <TouchableOpacity onPress={() => ipc.showDiscordModal()}>
|
||||
<View style={[styles.discord, !props.source ? styles.discordInactive : null]}>
|
||||
{renderDiscordPresenceSource(props.source)}
|
||||
{props.presence || props.user ? <DiscordPresence presence={props.presence} user={props.user} /> : null}
|
||||
|
||||
{status?.error_message ?
|
||||
<DiscordPresenceError message={status?.error_message} onPress={showErrorDetails} /> : null}
|
||||
</View>
|
||||
</TouchableOpacity>;
|
||||
}
|
||||
|
|
@ -111,6 +127,18 @@ function DiscordPresence(props: {
|
|||
</View>;
|
||||
}
|
||||
|
||||
function DiscordPresenceError(props: {
|
||||
message: string;
|
||||
onPress?: () => void;
|
||||
}) {
|
||||
return <TouchableOpacity onPress={props.onPress} style={styles.errorTouchable}>
|
||||
<View style={styles.error}>
|
||||
<Text style={styles.icon}><Warning /></Text>
|
||||
<Text style={styles.errorText} numberOfLines={1} ellipsizeMode="tail">{props.message}</Text>
|
||||
</View>
|
||||
</TouchableOpacity>;
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
discord: {
|
||||
backgroundColor: DISCORD_COLOUR,
|
||||
|
|
@ -168,4 +196,23 @@ const styles = StyleSheet.create({
|
|||
discordUserDiscriminator: {
|
||||
opacity: 0.7,
|
||||
},
|
||||
|
||||
errorTouchable: {
|
||||
marginVertical: -16,
|
||||
marginHorizontal: -20,
|
||||
marginTop: 6,
|
||||
paddingVertical: 16,
|
||||
paddingHorizontal: 20,
|
||||
paddingTop: 10,
|
||||
},
|
||||
error: {
|
||||
flexDirection: 'row',
|
||||
},
|
||||
icon: {
|
||||
marginRight: 10,
|
||||
color: TEXT_COLOUR_DARK,
|
||||
},
|
||||
errorText: {
|
||||
color: TEXT_COLOUR_DARK,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -48,6 +48,10 @@ export interface DiscordPresenceExternalMonitorsConfiguration {
|
|||
enable_splatnet3_monitoring?: boolean;
|
||||
}
|
||||
|
||||
export interface DiscordStatus {
|
||||
error_message: string | null;
|
||||
}
|
||||
|
||||
export interface LoginItem {
|
||||
supported: boolean;
|
||||
startup_enabled: boolean;
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { createModalWindow, getWindowConfiguration, setWindowHeight } from './wi
|
|||
import { askAddNsoAccount, askAddPctlAccount } from './na-auth.js';
|
||||
import { App } from './index.js';
|
||||
import { EmbeddedPresenceMonitor } from './monitor.js';
|
||||
import { DiscordPresenceConfiguration, DiscordPresenceSource, LoginItemOptions, WindowType } from '../common/types.js';
|
||||
import { DiscordPresenceConfiguration, DiscordPresenceSource, DiscordStatus, LoginItemOptions, WindowType } from '../common/types.js';
|
||||
import { CurrentUser, Friend, Game, PresenceState, WebService } from '../../api/coral-types.js';
|
||||
import { NintendoAccountUser } from '../../api/na.js';
|
||||
import createDebug from '../../util/debug.js';
|
||||
|
|
@ -109,6 +109,8 @@ export function setupIpc(appinstance: App, ipcMain: IpcMain) {
|
|||
handle('discord:source', () => appinstance.monitors.getDiscordPresenceSource());
|
||||
handle('discord:setsource', (e, source: DiscordPresenceSource | null) => appinstance.monitors.setDiscordPresenceSource(source));
|
||||
handle('discord:presence', () => appinstance.monitors.getDiscordPresence());
|
||||
handle('discord:status', () => appinstance.monitors.getDiscordStatus());
|
||||
handle('discord:showerror', () => appinstance.monitors.showDiscordPresenceLastUpdateError());
|
||||
handle('discord:user', () => appinstance.monitors.getActiveDiscordPresenceMonitor()?.discord.rpc?.client.user ?? null);
|
||||
handle('discord:users', async () => {
|
||||
const users: User[] = [];
|
||||
|
|
@ -173,6 +175,7 @@ export function setupIpc(appinstance: App, ipcMain: IpcMain) {
|
|||
store.on('update-discord-presence-source', () => sendToAllWindows('nxapi:discord:shouldrefresh'));
|
||||
store.on('update-discord-presence', (p: DiscordPresence) => sendToAllWindows('nxapi:discord:presence', p));
|
||||
store.on('update-discord-user', (u: User) => sendToAllWindows('nxapi:discord:user', u));
|
||||
store.on('update-discord-status', (s: DiscordStatus | null) => sendToAllWindows('nxapi:discord:status', s));
|
||||
}
|
||||
|
||||
function sendToAllWindows(channel: string, ...args: any[]) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Notification } from './electron.js';
|
||||
import { App } from './index.js';
|
||||
import { showErrorDialog, tryGetNativeImageFromUrl } from './util.js';
|
||||
import { DiscordPresenceConfiguration, DiscordPresenceExternalMonitorsConfiguration, DiscordPresenceSource } from '../common/types.js';
|
||||
import { DiscordPresenceConfiguration, DiscordPresenceExternalMonitorsConfiguration, DiscordPresenceSource, DiscordStatus } from '../common/types.js';
|
||||
import { CurrentUser, Friend, Game, CoralError } from '../../api/coral-types.js';
|
||||
import { ErrorResponse } from '../../api/util.js';
|
||||
import { ZncDiscordPresence, ZncProxyDiscordPresence } from '../../common/presence.js';
|
||||
|
|
@ -11,6 +11,7 @@ import { LoopResult } from '../../util/loop.js';
|
|||
import { DiscordPresence, DiscordPresencePlayTime, ErrorResult } from '../../discord/types.js';
|
||||
import { DiscordRpcClient } from '../../discord/rpc.js';
|
||||
import SplatNet3Monitor, { getConfigFromAppConfig as getSplatNet3MonitorConfigFromAppConfig } from '../../discord/monitor/splatoon3.js';
|
||||
import { ErrorDescription } from '../../util/errors.js';
|
||||
|
||||
const debug = createDebug('app:main:monitor');
|
||||
|
||||
|
|
@ -68,6 +69,19 @@ export class PresenceMonitorManager {
|
|||
return ErrorResult.IGNORE;
|
||||
};
|
||||
|
||||
i.discord.onUpdateError = err => {
|
||||
const status: DiscordStatus = {
|
||||
error_message: err instanceof Error ?
|
||||
err.name + ': ' + err.message :
|
||||
ErrorDescription.getErrorDescription(err),
|
||||
};
|
||||
this.app.store.emit('update-discord-status', status);
|
||||
};
|
||||
i.discord.onUpdateSuccess = () => {
|
||||
const status: DiscordStatus = {error_message: null};
|
||||
this.app.store.emit('update-discord-status', status);
|
||||
};
|
||||
|
||||
i.onError = err => this.handleError(i, err);
|
||||
|
||||
this.monitors.push(i);
|
||||
|
|
@ -97,6 +111,19 @@ export class PresenceMonitorManager {
|
|||
this.app.store.emit('update-discord-user', client?.user ?? null);
|
||||
};
|
||||
|
||||
i.discord.onUpdateError = err => {
|
||||
const status: DiscordStatus = {
|
||||
error_message: err instanceof Error ?
|
||||
err.name + ': ' + err.message :
|
||||
ErrorDescription.getErrorDescription(err),
|
||||
};
|
||||
this.app.store.emit('update-discord-status', status);
|
||||
};
|
||||
i.discord.onUpdateSuccess = () => {
|
||||
const status: DiscordStatus = {error_message: null};
|
||||
this.app.store.emit('update-discord-status', status);
|
||||
};
|
||||
|
||||
i.onError = err => this.handleError(i, err);
|
||||
|
||||
this.monitors.push(i);
|
||||
|
|
@ -317,6 +344,8 @@ export class PresenceMonitorManager {
|
|||
this.app.store.saveMonitorState(this);
|
||||
this.app.menu?.updateMenu();
|
||||
this.app.store.emit('update-discord-presence-source', source);
|
||||
} else {
|
||||
this.app.store.emit('update-discord-status', null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -360,6 +389,29 @@ export class PresenceMonitorManager {
|
|||
|
||||
return LoopResult.OK;
|
||||
}
|
||||
|
||||
async getDiscordStatus(): Promise<DiscordStatus | null> {
|
||||
const monitor = this.getActiveDiscordPresenceMonitor();
|
||||
if (!monitor) return null;
|
||||
|
||||
return {
|
||||
error_message: monitor.discord.last_update_error ?
|
||||
monitor.discord.last_update_error instanceof Error ?
|
||||
monitor.discord.last_update_error.name + ': ' + monitor.discord.last_update_error.message :
|
||||
ErrorDescription.getErrorDescription(monitor.discord.last_update_error) : null,
|
||||
};
|
||||
}
|
||||
|
||||
async showDiscordPresenceLastUpdateError() {
|
||||
const monitor = this.getActiveDiscordPresenceMonitor();
|
||||
const error = monitor?.discord.last_update_error;
|
||||
if (!error) return;
|
||||
|
||||
await showErrorDialog({
|
||||
message: error.name + ' updating presence monitor',
|
||||
error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class EmbeddedPresenceMonitor extends ZncDiscordPresence {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { EventEmitter } from 'events';
|
|||
import createDebug from 'debug';
|
||||
import type { User } from 'discord-rpc';
|
||||
import type { SharingItem } from '../main/electron.js';
|
||||
import type { DiscordPresenceConfiguration, DiscordPresenceSource, LoginItem, LoginItemOptions, WindowConfiguration } from '../common/types.js';
|
||||
import type { DiscordPresenceConfiguration, DiscordPresenceSource, DiscordStatus, LoginItem, LoginItemOptions, WindowConfiguration } from '../common/types.js';
|
||||
import type { SavedToken } from '../../common/auth/coral.js';
|
||||
import type { SavedMoonToken } from '../../common/auth/moon.js';
|
||||
import type { UpdateCacheData } from '../../common/update.js';
|
||||
|
|
@ -74,6 +74,8 @@ const ipc = {
|
|||
getDiscordPresenceSource: () => inv<DiscordPresenceSource | null>('discord:source'),
|
||||
setDiscordPresenceSource: (source: DiscordPresenceSource | null) => inv<void>('discord:setsource', source),
|
||||
getDiscordPresence: () => inv<DiscordPresence | null>('discord:presence'),
|
||||
getDiscordStatus: () => inv<DiscordStatus | null>('discord:status'),
|
||||
showDiscordLastUpdateError: () => inv('discord:showerror'),
|
||||
getDiscordUser: () => inv<User | null>('discord:user'),
|
||||
getDiscordUsers: () => inv<User[]>('discord:users'),
|
||||
|
||||
|
|
@ -109,6 +111,7 @@ ipcRenderer.on('nxapi:accounts:shouldrefresh', () => events.emit('update-nintend
|
|||
ipcRenderer.on('nxapi:discord:shouldrefresh', () => events.emit('update-discord-presence-source'));
|
||||
ipcRenderer.on('nxapi:discord:presence', (e, p: DiscordPresence) => events.emit('update-discord-presence', p));
|
||||
ipcRenderer.on('nxapi:discord:user', (e, u: User) => events.emit('update-discord-user', u));
|
||||
ipcRenderer.on('nxapi:discord:status', (e, s: DiscordStatus | null) => events.emit('update-discord-status', s));
|
||||
|
||||
let accent_colour: string | undefined = invSync('systemPreferences:accent-colour');
|
||||
ipcRenderer.on('nxapi:systemPreferences:accent-colour', (event, c) => {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,11 @@ class ZncDiscordPresenceClient {
|
|||
ErrorResult | Promise<ErrorResult>) | null = null;
|
||||
|
||||
update_presence_errors = 0;
|
||||
last_update_error: Error | null = null;
|
||||
last_update_error_at: Date | null = null;
|
||||
onUpdateError: ((error: Error | null) => void) | null = null;
|
||||
onUpdateSuccess: (() => void) | null = null;
|
||||
onUpdate: (() => void) | null = null;
|
||||
|
||||
constructor(
|
||||
readonly m: ZncDiscordPresence | ZncProxyDiscordPresence,
|
||||
|
|
@ -63,6 +68,13 @@ class ZncDiscordPresenceClient {
|
|||
this.last_friendcode = friendcode;
|
||||
this.last_event = activeevent;
|
||||
|
||||
this.onUpdate?.call(null);
|
||||
|
||||
if (this.update_presence_errors) {
|
||||
this.update_presence_errors = 0;
|
||||
this.onUpdateSuccess?.call(null);
|
||||
}
|
||||
|
||||
const online = presence?.state === PresenceState.ONLINE || presence?.state === PresenceState.PLAYING;
|
||||
|
||||
const show_presence =
|
||||
|
|
@ -328,15 +340,15 @@ class ZncDiscordPresenceClient {
|
|||
|
||||
async onError(err: Error) {
|
||||
this.update_presence_errors++;
|
||||
this.last_update_error = err;
|
||||
this.last_update_error_at = new Date();
|
||||
|
||||
if (this.update_presence_errors > 2) {
|
||||
this.onUpdateError?.call(null, err);
|
||||
|
||||
if (this.update_presence_errors > 2 && this.rpc) {
|
||||
// Disconnect from Discord if the last two attempts to update presence failed
|
||||
// This prevents the user's activity on Discord being stuck
|
||||
if (this.rpc) {
|
||||
const client = this.rpc.client;
|
||||
this.rpc = null;
|
||||
await client.destroy();
|
||||
}
|
||||
this.setActivity(this.m.discord_preconnect ? this.rpc.id : null);
|
||||
}
|
||||
|
||||
if (this.update_presence_errors > 10) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user