mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-03-21 18:04:10 -05:00
Presence monitoring
This commit is contained in:
parent
eb778f0c8e
commit
4452947187
|
|
@ -5,8 +5,8 @@ import { JwtPayload } from '../util/jwt.js';
|
|||
import { timeoutSignal } from '../util/misc.js';
|
||||
import { getAdditionalUserAgents } from '../util/useragent.js';
|
||||
import type { CoralRemoteConfig } from '../common/remote-config.js';
|
||||
import { AccountLogin, AccountLoginParameter, AccountToken, AccountTokenParameter, Announcements, Announcements_4, BlockingUsers, CoralError, CoralResponse, CoralStatus, CoralSuccessResponse, CurrentUser, CurrentUserPermissions, Event, Friend_4, FriendCodeUrl, FriendCodeUser, Friends, Friends_4, GetActiveEventResult, ListChat, ListHashtag, ListHashtagParameter, ListMedia, ListMediaParameter, ListPushNotificationSettings, Media, PlayLogPermissions, PresencePermissions, PushNotificationPlayInvitationScope, ReceivedFriendRequest, ReceivedFriendRequests, SentFriendRequests, ShowUserLogin, UpdatePushNotificationSettingsParameter, UpdatePushNotificationSettingsParameterItem, User, UserPlayLog, WebServices, WebServices_4, WebServiceToken, WebServiceTokenParameter } from './coral-types.js';
|
||||
import { createZncaApi, DecryptResponseResult, FResult, getDefaultZncaApi, getPreferredZncaApiFromEnvironment, HashMethod, RequestEncryptionProvider, ZncaApi, ZncaApiNxapi } from './f.js';
|
||||
import { AccountLogin, AccountLoginParameter, AccountToken, AccountTokenParameter, Announcements_4, BlockingUsers, CoralError, CoralResponse, CoralStatus, CoralSuccessResponse, CurrentUser, CurrentUserPermissions, Event, Friend_4, FriendCodeUrl, FriendCodeUser, Friends_4, GetActiveEventResult, ListChat, ListHashtag, ListHashtagParameter, ListMedia, ListMediaParameter, ListPushNotificationSettings, Media, PlayLogPermissions, PresencePermissions, PushNotificationPlayInvitationScope, ReceivedFriendRequest, ReceivedFriendRequests, SentFriendRequests, ShowUserLogin, UpdatePushNotificationSettingsParameter, UpdatePushNotificationSettingsParameterItem, User, UserPlayLog, WebServices_4, WebServiceToken, WebServiceTokenParameter } from './coral-types.js';
|
||||
import { createZncaApi, DecryptResponseResult, FResult, HashMethod, RequestEncryptionProvider, ZncaApi } from './f.js';
|
||||
import { generateAuthData, getNintendoAccountToken, getNintendoAccountUser, NintendoAccountScope, NintendoAccountSessionAuthorisation, NintendoAccountToken, NintendoAccountUser } from './na.js';
|
||||
import { ErrorResponse, ResponseSymbol } from './util.js';
|
||||
import { ErrorDescription, ErrorDescriptionSymbol, HasErrorDescription } from '../util/errors.js';
|
||||
|
|
|
|||
|
|
@ -241,6 +241,11 @@ export interface AndroidZncaEncryptRequestRequest {
|
|||
|
||||
export interface AndroidZncaDecryptResponseRequest {
|
||||
data: string;
|
||||
request_nsa_assertion?: boolean;
|
||||
}
|
||||
export interface AndroidZncaDecryptResponseResponse {
|
||||
data: string;
|
||||
nsa_assertion?: string | null;
|
||||
}
|
||||
|
||||
export interface AndroidZncaFError {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { fetch, Response } from 'undici';
|
||||
import { ActiveEvent, CurrentUser, Event, Friend, Presence, PresencePermissions, User, WebServiceToken, CoralStatus, CoralSuccessResponse, FriendCodeUser, FriendCodeUrl, WebService_4, Media, Announcements_4, Friend_4, PresenceOnline_4, PresenceOnline, PresenceOffline } from './coral-types.js';
|
||||
import { ActiveEvent, CurrentUser, Event, Friend, Presence, PresencePermissions, User, WebServiceToken, CoralStatus, CoralSuccessResponse, FriendCodeUser, FriendCodeUrl, WebService_4, Media, Announcements_4, Friend_4, PresenceOnline_4, PresenceOnline, PresenceOffline, GetActiveEventResult } from './coral-types.js';
|
||||
import { defineResponse, ErrorResponse, ResponseSymbol } from './util.js';
|
||||
import { AbstractCoralApi, CoralApiInterface, CoralAuthData, CorrelationIdSymbol, PartialCoralAuthData, RequestFlagAddPlatformSymbol, RequestFlagAddProductVersionSymbol, RequestFlagNoParameterSymbol, RequestFlagRequestIdSymbol, RequestFlags, ResponseDataSymbol, ResponseEncryptionSymbol, Result } from './coral.js';
|
||||
import { NintendoAccountToken, NintendoAccountUser } from './na.js';
|
||||
|
|
@ -111,8 +111,8 @@ export default class ZncProxyApi extends AbstractCoralApi implements CoralApiInt
|
|||
}
|
||||
|
||||
async getActiveEvent() {
|
||||
const result = await this.fetchProxyApi<{activeevent: ActiveEvent}>('activeevent');
|
||||
return createResult(result, result.activeevent);
|
||||
const result = await this.fetchProxyApi<{activeevent: ActiveEvent | null}>('activeevent');
|
||||
return createResult<GetActiveEventResult, typeof result>(result, result.activeevent ?? {});
|
||||
}
|
||||
|
||||
async getEvent(id: number) {
|
||||
|
|
@ -235,6 +235,8 @@ export interface AuthPolicy {
|
|||
friend_presence?: boolean;
|
||||
webservices?: boolean;
|
||||
activeevent?: boolean;
|
||||
chats?: boolean;
|
||||
media?: boolean;
|
||||
current_user?: boolean;
|
||||
current_user_presence?: boolean;
|
||||
|
||||
|
|
|
|||
|
|
@ -480,11 +480,11 @@ export class Store extends EventEmitter {
|
|||
};
|
||||
|
||||
for (const monitor of monitors.monitors) {
|
||||
if (monitor instanceof EmbeddedPresenceMonitor && !users.has(monitor.data.user.id)) {
|
||||
users.add(monitor.data?.user.id);
|
||||
if (monitor instanceof EmbeddedPresenceMonitor && !users.has(monitor.user.data.user.id)) {
|
||||
users.add(monitor.user.data.user.id);
|
||||
|
||||
state.users.push({
|
||||
id: monitor.data?.user.id,
|
||||
id: monitor.user.data.user.id,
|
||||
user_notifications: monitor.user_notifications,
|
||||
friend_notifications: monitor.friend_notifications,
|
||||
});
|
||||
|
|
@ -541,7 +541,7 @@ export class Store extends EventEmitter {
|
|||
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;
|
||||
state.discord_presence.source.friend_nsa_id ?? monitor.user.data.nsoAccount.user.nsaId : null;
|
||||
monitor.user_notifications = user.user_notifications;
|
||||
monitor.friend_notifications = user.friend_notifications;
|
||||
|
||||
|
|
|
|||
|
|
@ -195,7 +195,8 @@ export function sendToAllWindows(channel: string, ...args: any[]) {
|
|||
function buildUserMenu(app: App, user: NintendoAccountUser, nso?: CurrentUser, moon?: boolean, window?: BrowserWindow) {
|
||||
const t = app.i18n.getFixedT(null, 'menus', 'user');
|
||||
const dm = app.monitors.getActiveDiscordPresenceMonitor();
|
||||
const monitor = app.monitors.monitors.find(m => m instanceof EmbeddedPresenceMonitor && m.data.user.id === user.id);
|
||||
const monitor = app.monitors.monitors.find(m => m instanceof EmbeddedPresenceMonitor &&
|
||||
m.user.data.user.id === user.id);
|
||||
|
||||
return Menu.buildFromTemplate([
|
||||
new MenuItem({label: t('na_id', {id: user.id})!, enabled: false}),
|
||||
|
|
@ -215,9 +216,9 @@ function buildUserMenu(app: App, user: NintendoAccountUser, nso?: CurrentUser, m
|
|||
click: () => app.menu?.setActiveDiscordPresenceUser(null)}),
|
||||
] : dm?.presence_user === nso.nsaId ? [
|
||||
new MenuItem({label: t('discord_enabled_via', {name:
|
||||
dm.data.user.nickname +
|
||||
(dm.data.user.nickname !== dm.data.nsoAccount.user.name ?
|
||||
'/' + dm.data.nsoAccount.user.name : '')})!,
|
||||
dm.user.data.user.nickname +
|
||||
(dm.user.data.user.nickname !== dm.user.data.nsoAccount.user.name ?
|
||||
'/' + dm.user.data.nsoAccount.user.name : '')})!,
|
||||
enabled: false}),
|
||||
new MenuItem({label: t('discord_disable')!,
|
||||
click: () => app.menu?.setActiveDiscordPresenceUser(null)}),
|
||||
|
|
|
|||
|
|
@ -61,9 +61,10 @@ export default class MenuApp {
|
|||
if (!data) continue;
|
||||
|
||||
const monitor = this.app.monitors.monitors.find(m => m instanceof EmbeddedPresenceMonitor &&
|
||||
m.data.user.id === data.user.id);
|
||||
const discord_presence_active = discord_presence_monitor instanceof EmbeddedPresenceMonitor &&
|
||||
discord_presence_monitor?.data?.user.id === data.user.id;
|
||||
m.user.data.user.id === data.user.id);
|
||||
const discord_presence_active = discord_presence_monitor &&
|
||||
discord_presence_monitor instanceof EmbeddedPresenceMonitor &&
|
||||
discord_presence_monitor.user.data.user.id === data.user.id;
|
||||
|
||||
const webservices = await this.getWebServiceItems(data.user.language, token);
|
||||
|
||||
|
|
@ -204,7 +205,7 @@ export default class MenuApp {
|
|||
const monitor = this.getActiveDiscordPresenceMonitor();
|
||||
|
||||
if (monitor) {
|
||||
if (monitor instanceof EmbeddedPresenceMonitor && monitor.data.user.id === id) return;
|
||||
if (monitor instanceof EmbeddedPresenceMonitor && monitor.user.data.user.id === id) return;
|
||||
|
||||
monitor.discord.updatePresenceForDiscord(null);
|
||||
|
||||
|
|
@ -212,7 +213,7 @@ export default class MenuApp {
|
|||
monitor.presence_user = null;
|
||||
|
||||
if (!monitor.user_notifications && !monitor.friend_notifications) {
|
||||
this.app.monitors.stop(monitor.data.user.id);
|
||||
this.app.monitors.stop(monitor.user.data.user.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,7 +223,7 @@ export default class MenuApp {
|
|||
}
|
||||
|
||||
if (id) await this.app.monitors.start(id, monitor => {
|
||||
monitor.presence_user = monitor.data.nsoAccount.user.nsaId;
|
||||
monitor.presence_user = monitor.user.data.nsoAccount.user.nsaId;
|
||||
monitor.skipIntervalInCurrentLoop();
|
||||
});
|
||||
|
||||
|
|
@ -230,13 +231,14 @@ export default class MenuApp {
|
|||
}
|
||||
|
||||
async setUserNotificationsActive(id: string, active: boolean) {
|
||||
const monitor = this.app.monitors.monitors.find(m => m instanceof EmbeddedPresenceMonitor && m.data.user.id === id);
|
||||
const monitor = this.app.monitors.monitors.find(m => m instanceof EmbeddedPresenceMonitor &&
|
||||
m.user.data.user.id === id);
|
||||
|
||||
if (monitor?.user_notifications && !active) {
|
||||
monitor.user_notifications = false;
|
||||
|
||||
if (!monitor.presence_user && !monitor.friend_notifications) {
|
||||
this.app.monitors.stop(monitor.data.user.id);
|
||||
this.app.monitors.stop(monitor.user.data.user.id);
|
||||
}
|
||||
|
||||
monitor.skipIntervalInCurrentLoop();
|
||||
|
|
@ -251,13 +253,14 @@ export default class MenuApp {
|
|||
}
|
||||
|
||||
async setFriendNotificationsActive(id: string, active: boolean) {
|
||||
const monitor = this.app.monitors.monitors.find(m => m instanceof EmbeddedPresenceMonitor && m.data.user.id === id);
|
||||
const monitor = this.app.monitors.monitors.find(m => m instanceof EmbeddedPresenceMonitor &&
|
||||
m.user.data.user.id === id);
|
||||
|
||||
if (monitor?.friend_notifications && !active) {
|
||||
monitor.friend_notifications = false;
|
||||
|
||||
if (!monitor.presence_user && !monitor.user_notifications) {
|
||||
this.app.monitors.stop(monitor.data.user.id);
|
||||
this.app.monitors.stop(monitor.user.data.user.id);
|
||||
}
|
||||
|
||||
monitor.skipIntervalInCurrentLoop();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Notification } from 'electron';
|
||||
import { i18n } from 'i18next';
|
||||
import { LocalStorage } from 'node-persist';
|
||||
import { App } from './index.js';
|
||||
import { showErrorDialog, tryGetNativeImageFromUrl } from './util.js';
|
||||
import { DiscordPresenceConfiguration, DiscordPresenceExternalMonitorsConfiguration, DiscordPresenceSource, DiscordStatus } from '../common/types.js';
|
||||
|
|
@ -13,9 +14,10 @@ import { DiscordPresence, DiscordPresencePlayTime, ErrorResult } from '../../dis
|
|||
import { DiscordRpcClient } from '../../discord/rpc.js';
|
||||
import SplatNet3Monitor, { getConfigFromAppConfig as getSplatNet3MonitorConfigFromAppConfig } from '../../discord/monitor/splatoon3.js';
|
||||
import { ErrorDescription } from '../../util/errors.js';
|
||||
import { CoralErrorResponse } from '../../api/coral.js';
|
||||
import { CoralApiInterface, CoralErrorResponse } from '../../api/coral.js';
|
||||
import { NintendoAccountAuthErrorResponse, NintendoAccountErrorResponse } from '../../api/na.js';
|
||||
import { InvalidNintendoAccountTokenError } from '../../common/auth/na.js';
|
||||
import { CoralUser } from '../../common/users.js';
|
||||
|
||||
const debug = createDebug('app:main:monitor');
|
||||
|
||||
|
|
@ -37,13 +39,15 @@ export class PresenceMonitorManager {
|
|||
|
||||
const user = await this.app.store.users.get(token);
|
||||
|
||||
const existing = this.monitors.find(m => m instanceof EmbeddedPresenceMonitor && m.data.user.id === user.data.user.id);
|
||||
const existing = this.monitors.find(m => m instanceof EmbeddedPresenceMonitor &&
|
||||
m.user.data.user.id === user.data.user.id);
|
||||
|
||||
if (existing) {
|
||||
await callback?.call(null, existing as EmbeddedPresenceMonitor, false);
|
||||
return existing;
|
||||
}
|
||||
|
||||
const i = new EmbeddedPresenceMonitor(this.app.store.storage, token, user.nso, user.data, user);
|
||||
const i = new EmbeddedPresenceMonitor(user, this.app.store.storage, token);
|
||||
|
||||
i.notifications = this.notifications;
|
||||
i.presence_user = null;
|
||||
|
|
@ -143,7 +147,7 @@ export class PresenceMonitorManager {
|
|||
async stop(id: string) {
|
||||
let index;
|
||||
while ((index = this.monitors.findIndex(m =>
|
||||
(m instanceof EmbeddedPresenceMonitor && m.data.user.id === id) ||
|
||||
(m instanceof EmbeddedPresenceMonitor && m.user.data.user.id === id) ||
|
||||
(m instanceof EmbeddedProxyPresenceMonitor && m.presence_url === id)
|
||||
)) >= 0) {
|
||||
const i = this.monitors[index];
|
||||
|
|
@ -283,8 +287,8 @@ export class PresenceMonitorManager {
|
|||
return monitor instanceof EmbeddedProxyPresenceMonitor ? {
|
||||
url: monitor.presence_url,
|
||||
} : {
|
||||
na_id: monitor.data.user.id,
|
||||
friend_nsa_id: monitor.presence_user === monitor.data.nsoAccount.user.nsaId ? undefined :
|
||||
na_id: monitor.user.data.user.id,
|
||||
friend_nsa_id: monitor.presence_user === monitor.user.data.nsoAccount.user.nsaId ? undefined :
|
||||
monitor.presence_user ?? undefined,
|
||||
};
|
||||
}
|
||||
|
|
@ -297,11 +301,11 @@ export class PresenceMonitorManager {
|
|||
|
||||
if (source && 'na_id' in source &&
|
||||
existing && existing instanceof EmbeddedPresenceMonitor &&
|
||||
existing.data.user.id === source.na_id &&
|
||||
existing.presence_user !== (source.friend_nsa_id ?? existing.data.nsoAccount.user.nsaId)
|
||||
existing.user.data.user.id === source.na_id &&
|
||||
existing.presence_user !== (source.friend_nsa_id ?? existing.user.data.nsoAccount.user.nsaId)
|
||||
) {
|
||||
await this.start(source.na_id, monitor => {
|
||||
monitor.presence_user = source.friend_nsa_id ?? monitor.data.nsoAccount.user.nsaId;
|
||||
monitor.presence_user = source.friend_nsa_id ?? monitor.user.data.nsoAccount.user.nsaId;
|
||||
this.setDiscordPresenceSourceCopyConfiguration(monitor, existing);
|
||||
callback?.call(null, monitor);
|
||||
monitor.discord.refreshExternalMonitorsConfig();
|
||||
|
|
@ -314,7 +318,7 @@ export class PresenceMonitorManager {
|
|||
|
||||
if (existing) {
|
||||
if (source && (
|
||||
('na_id' in source && existing instanceof EmbeddedPresenceMonitor && existing.data.user.id === source.na_id) ||
|
||||
('na_id' in source && existing instanceof EmbeddedPresenceMonitor && existing.user.data.user.id === source.na_id) ||
|
||||
('url' in source && existing instanceof EmbeddedProxyPresenceMonitor && existing.presence_url === source.url)
|
||||
)) {
|
||||
callback?.call(null, existing);
|
||||
|
|
@ -327,7 +331,7 @@ export class PresenceMonitorManager {
|
|||
existing.presence_user = null;
|
||||
|
||||
if (!existing.user_notifications && !existing.friend_notifications) {
|
||||
this.stop(existing.data.user.id);
|
||||
this.stop(existing.user.data.user.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -338,7 +342,7 @@ export class PresenceMonitorManager {
|
|||
|
||||
if (source && 'na_id' in source) {
|
||||
await this.start(source.na_id, async monitor => {
|
||||
monitor.presence_user = source.friend_nsa_id ?? monitor.data.nsoAccount.user.nsaId;
|
||||
monitor.presence_user = source.friend_nsa_id ?? monitor.user.data.nsoAccount.user.nsaId;
|
||||
if (existing) this.setDiscordPresenceSourceCopyConfiguration(monitor, existing);
|
||||
else await this.setDiscordPresenceSourceRestoreSavedConfiguration(monitor);
|
||||
callback?.call(null, monitor);
|
||||
|
|
@ -434,6 +438,14 @@ export class EmbeddedPresenceMonitor extends ZncDiscordPresence {
|
|||
onError?: (error: ErrorResponse<CoralError> | NodeJS.ErrnoException) =>
|
||||
Promise<LoopResult | void> | LoopResult | void = undefined;
|
||||
|
||||
constructor(
|
||||
user: CoralUser<CoralApiInterface>,
|
||||
storage: LocalStorage,
|
||||
readonly token: string,
|
||||
) {
|
||||
super(user, storage);
|
||||
}
|
||||
|
||||
enable() {
|
||||
if (this._running !== 0) return;
|
||||
this._run();
|
||||
|
|
@ -468,7 +480,7 @@ export class EmbeddedPresenceMonitor extends ZncDiscordPresence {
|
|||
|
||||
await this.onStop?.();
|
||||
|
||||
debug('Monitor for user %s finished', this.data.nsoAccount.user.name);
|
||||
debug('Monitor for user %s finished', this.user.data.nsoAccount.user.name);
|
||||
} finally {
|
||||
this._running = 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ declare global {
|
|||
namespace Express {
|
||||
interface Request {
|
||||
coralUser?: CoralUser;
|
||||
coralNaSessionToken?: string;
|
||||
coral?: CoralApi;
|
||||
coralAuthData?: SavedToken;
|
||||
|
||||
|
|
@ -169,6 +170,10 @@ class Server extends HttpServer {
|
|||
this.createProxyRequestHandler(r => this.handleWebServiceTokenRequest(r, r.req.params.id), true));
|
||||
app.get('/api/znc/activeevent', this.authTokenMiddleware, this.localAuthMiddleware,
|
||||
this.createProxyRequestHandler(r => this.handleActiveEventRequest(r)));
|
||||
app.get('/api/znc/chats', this.authTokenMiddleware, this.localAuthMiddleware,
|
||||
this.createProxyRequestHandler(r => this.handleChatsRequest(r)));
|
||||
app.get('/api/znc/media', this.authTokenMiddleware, this.localAuthMiddleware,
|
||||
this.createProxyRequestHandler(r => this.handleMediaRequest(r)));
|
||||
|
||||
app.get('/api/znc/event/:id',
|
||||
this.createProxyRequestHandler(r => this.handleEventRequest(r, r.req.params.id), true));
|
||||
|
|
@ -285,6 +290,8 @@ class Server extends HttpServer {
|
|||
na_session_token = auth.substr(3);
|
||||
}
|
||||
|
||||
req.coralNaSessionToken = na_session_token;
|
||||
|
||||
let user_naid: string | null = null;
|
||||
|
||||
const promise = this.coral_auth_promise.get(na_session_token) ?? (async () => {
|
||||
|
|
@ -326,7 +333,7 @@ class Server extends HttpServer {
|
|||
|
||||
async handleAuthRequest({user}: RequestDataWithUser) {
|
||||
if (user.nso instanceof ZncProxyApi) {
|
||||
return user.nso.fetchProxyApi('/auth');
|
||||
return user.nso.fetchProxyApi('auth');
|
||||
} else {
|
||||
return user.data;
|
||||
}
|
||||
|
|
@ -397,7 +404,7 @@ class Server extends HttpServer {
|
|||
|
||||
async handleApiCallRequest({req, policy}: RequestData) {
|
||||
if (policy && !policy.api) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const flags: Partial<RequestFlags> = {};
|
||||
|
|
@ -443,12 +450,12 @@ class Server extends HttpServer {
|
|||
|
||||
//
|
||||
// Announcements
|
||||
// This is cached for all users.
|
||||
// This is cached permanently per-user, although other requests may cause this to be updated.
|
||||
//
|
||||
|
||||
async handleAnnouncementsRequest({req, policy}: RequestData) {
|
||||
if (policy && !policy.announcements) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
|
@ -461,22 +468,15 @@ class Server extends HttpServer {
|
|||
// Nintendo Switch user data
|
||||
//
|
||||
|
||||
private user_data_promise = new Map</** NA ID */ string, Promise<[number, CurrentUser]>>();
|
||||
private cached_userdata = new Map</** NA ID */ string, [number, CurrentUser]>();
|
||||
|
||||
async getUserData(id: string, coral: CoralApiInterface) {
|
||||
return this._cache(id, () => coral.getCurrentUser(),
|
||||
this.user_data_promise, this.cached_userdata);
|
||||
}
|
||||
|
||||
async handleCurrentUserRequest({req, res, policy}: RequestData) {
|
||||
if (policy && !policy.current_user) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
||||
const [updated, current_user] = await this.getUserData(user.data.user.id, user.nso);
|
||||
const current_user = await user.getCurrentUser();
|
||||
const updated = user.updated.user;
|
||||
|
||||
res.setHeader('Cache-Control', 'private, immutable, max-age=' + cacheMaxAge(updated, this.update_interval));
|
||||
return {user: current_user, updated};
|
||||
|
|
@ -484,12 +484,13 @@ class Server extends HttpServer {
|
|||
|
||||
async handleUserPresenceRequest({req, policy}: RequestData) {
|
||||
if (policy && !policy.current_user_presence) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
||||
const [updated, current_user] = await this.getUserData(user.data.user.id, user.nso);
|
||||
const current_user = await user.getCurrentUser();
|
||||
const updated = user.updated.user;
|
||||
|
||||
return current_user.presence;
|
||||
}
|
||||
|
|
@ -500,7 +501,7 @@ class Server extends HttpServer {
|
|||
|
||||
async handleFriendsRequest({req, res, policy}: RequestData) {
|
||||
if (policy && !policy.list_friends) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
|
@ -522,7 +523,7 @@ class Server extends HttpServer {
|
|||
|
||||
async handleFavouriteFriendsRequest({req, res, policy}: RequestData) {
|
||||
if (policy && !policy.list_friends) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
|
@ -544,7 +545,7 @@ class Server extends HttpServer {
|
|||
|
||||
async handleFriendsPresenceRequest({req, res, policy}: RequestData) {
|
||||
if (policy && !policy.list_friends_presence) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
|
@ -568,7 +569,7 @@ class Server extends HttpServer {
|
|||
|
||||
async handleFavouriteFriendsPresenceRequest({req, res, policy}: RequestData) {
|
||||
if (policy && !policy.list_friends_presence) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
|
@ -594,10 +595,10 @@ class Server extends HttpServer {
|
|||
|
||||
async handleFriendRequest({req, res, policy}: RequestData, nsaid: string) {
|
||||
if (policy && !policy.friend) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
if (policy?.friends && !policy.friends.includes(nsaid)) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
|
@ -644,10 +645,10 @@ class Server extends HttpServer {
|
|||
|
||||
async handleFriendPresenceRequest({req, res, policy}: RequestData, nsaid: string) {
|
||||
if (policy && !policy.friend_presence) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
if (!(policy?.friends_presence?.includes(nsaid) ?? policy?.friends?.includes(nsaid) ?? true)) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
|
@ -666,16 +667,12 @@ class Server extends HttpServer {
|
|||
|
||||
async handleWebServicesRequest({req, res, policy}: RequestData) {
|
||||
if (policy && !policy.webservices) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
||||
const [friends, webservices, activeevent] = await Promise.all([
|
||||
user.getFriends(),
|
||||
user.getWebServices(),
|
||||
user.getActiveEvent(),
|
||||
]);
|
||||
const webservices = await user.getWebServices();
|
||||
const updated = user.updated.webservices;
|
||||
|
||||
res.setHeader('Cache-Control', 'private, immutable, max-age=' + cacheMaxAge(updated, this.update_interval));
|
||||
|
|
@ -690,22 +687,46 @@ class Server extends HttpServer {
|
|||
|
||||
async handleActiveEventRequest({req, res, policy}: RequestData) {
|
||||
if (policy && !policy.activeevent) {
|
||||
throw new ResponseError(403, 'token_unauthorised');
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
||||
const [friends, webservices, activeevent] = await Promise.all([
|
||||
user.getFriends(),
|
||||
user.getWebServices(),
|
||||
user.getActiveEvent(),
|
||||
]);
|
||||
const updated = user.updated.webservices;
|
||||
const activeevent = await user.getActiveEvent();
|
||||
const updated = user.updated.active_event;
|
||||
|
||||
res.setHeader('Cache-Control', 'private, immutable, max-age=' + cacheMaxAge(updated, this.update_interval));
|
||||
return {activeevent, updated};
|
||||
}
|
||||
|
||||
async handleChatsRequest({req, res, policy}: RequestData) {
|
||||
if (policy && !policy.chats) {
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
||||
const chats = await user.getChats();
|
||||
const updated = user.updated.chats;
|
||||
|
||||
res.setHeader('Cache-Control', 'private, immutable, max-age=' + cacheMaxAge(updated, this.update_interval));
|
||||
return {chats, updated};
|
||||
}
|
||||
|
||||
async handleMediaRequest({req, res, policy}: RequestData) {
|
||||
if (policy && !policy.media) {
|
||||
throw new ResponseError(403, 'insufficient_scope');
|
||||
}
|
||||
|
||||
const user = await this.getCoralUser(req);
|
||||
|
||||
const media = await user.getMedia();
|
||||
const updated = user.updated.media;
|
||||
|
||||
res.setHeader('Cache-Control', 'private, immutable, max-age=' + cacheMaxAge(updated, this.update_interval));
|
||||
return {media, updated};
|
||||
}
|
||||
|
||||
async handleEventRequest({user}: RequestDataWithUser, id: string) {
|
||||
const event = await user.nso.getEvent(parseInt(id));
|
||||
|
||||
|
|
@ -799,8 +820,7 @@ class Server extends HttpServer {
|
|||
//
|
||||
|
||||
async handlePresenceEventStreamRequest({req, res, user}: RequestDataWithUser) {
|
||||
const na_session_token = req.headers['authorization']!.substr(3);
|
||||
const i = new ZncNotifications(this.storage, na_session_token, user.nso, user.data, user);
|
||||
const i = new ZncNotifications(user);
|
||||
|
||||
i.user_notifications = false;
|
||||
i.friend_notifications = true;
|
||||
|
|
@ -815,7 +835,7 @@ class Server extends HttpServer {
|
|||
while (!res.destroyed) {
|
||||
await i.loop();
|
||||
|
||||
this.resetAuthTimeout(na_session_token, () => user.data.user.id);
|
||||
this.resetAuthTimeout(req.coralNaSessionToken!, () => user.data.user.id);
|
||||
}
|
||||
} catch (err) {
|
||||
stream.sendErrorEvent(err);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { getToken } from '../../common/auth/coral.js';
|
|||
import { getIksmToken } from '../../common/auth/splatnet2.js';
|
||||
import { EmbeddedSplatNet2Monitor, NotificationManager, ZncNotifications } from '../../common/notify.js';
|
||||
import { CurrentUser, Friend, PresenceGame } from '../../api/coral-types.js';
|
||||
import Users from '../../common/users.js';
|
||||
|
||||
const debug = createDebug('cli:nso:notify');
|
||||
|
||||
|
|
@ -100,9 +101,13 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
|||
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
|
||||
const token: string = argv.token ||
|
||||
await storage.getItem('NintendoAccountToken.' + usernsid);
|
||||
const {nso, data} = await getToken(storage, token, argv.zncProxyUrl);
|
||||
|
||||
const i = new ZncNotifications(storage, token, nso, data);
|
||||
const users = Users.coral(storage, argv.zncProxyUrl);
|
||||
const user = await users.get(token);
|
||||
|
||||
const data = user.data;
|
||||
|
||||
const i = new ZncNotifications(user);
|
||||
|
||||
i.notifications = await TerminalNotificationManager.create();
|
||||
i.user_notifications = argv.userNotifications;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { DiscordPresencePlayTime } from '../../discord/types.js';
|
|||
import { handleEnableSplatNet2Monitoring, TerminalNotificationManager } from './notify.js';
|
||||
import { ZncDiscordPresence, ZncProxyDiscordPresence } from '../../common/presence.js';
|
||||
import SplatNet3Monitor, { getConfigFromArgv as getSplatNet3MonitorConfigFromArgv } from '../../discord/monitor/splatoon3.js';
|
||||
import Users from '../../common/users.js';
|
||||
|
||||
const debug = createDebug('cli:nso:presence');
|
||||
const debugProxy = createDebug('cli:nso:presence:proxy');
|
||||
|
|
@ -199,9 +200,13 @@ export async function handler(argv: ArgumentsCamelCase<Arguments>) {
|
|||
const usernsid = argv.user ?? await storage.getItem('SelectedUser');
|
||||
const token: string = argv.token ||
|
||||
await storage.getItem('NintendoAccountToken.' + usernsid);
|
||||
const {nso, data} = await getToken(storage, token, argv.zncProxyUrl);
|
||||
|
||||
const i = new ZncDiscordPresence(storage, token, nso, data);
|
||||
const users = Users.coral(storage, argv.zncProxyUrl);
|
||||
const user = await users.get(token);
|
||||
|
||||
const data = user.data;
|
||||
|
||||
const i = new ZncDiscordPresence(user, storage);
|
||||
|
||||
i.notifications = await TerminalNotificationManager.create();
|
||||
i.user_notifications = argv.userNotifications;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import persist from 'node-persist';
|
||||
import { CoralApiInterface } from '../api/coral.js';
|
||||
import { ActiveEvent, CurrentUser, Friend, Presence, PresenceState, CoralError, GetActiveEventResult, FriendRouteChannel, PresenceGame, Announcements_4, Friend_4, WebServices_4, PresenceOnline_4, PresenceOffline } from '../api/coral-types.js';
|
||||
import ZncProxyApi from '../api/znc-proxy.js';
|
||||
import { CurrentUser, Friend, Presence, PresenceState, CoralError, PresenceGame } from '../api/coral-types.js';
|
||||
import { ErrorResponse } from '../api/util.js';
|
||||
import { SavedToken } from './auth/coral.js';
|
||||
import { SplatNet2RecordsMonitor } from './splatnet2/monitor.js';
|
||||
|
|
@ -24,123 +23,28 @@ export class ZncNotifications extends Loop {
|
|||
update_interval = 30;
|
||||
|
||||
constructor(
|
||||
public storage: persist.LocalStorage,
|
||||
public token: string,
|
||||
public nso: CoralApiInterface,
|
||||
public data: Omit<SavedToken, 'expires_at'>,
|
||||
public user?: CoralUser<CoralApiInterface>,
|
||||
public user: CoralUser<CoralApiInterface>,
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
async fetch(req: (
|
||||
'announcements' | 'friends' | {friend: string; presence?: boolean} | 'webservices' |
|
||||
'event' | 'chats' | 'media' | 'user' | null
|
||||
)[]) {
|
||||
const result: Partial<{
|
||||
announcements: Announcements_4;
|
||||
friends: Friend_4[];
|
||||
webservices: WebServices_4;
|
||||
activeevent: ActiveEvent;
|
||||
user: CurrentUser;
|
||||
}> = {};
|
||||
|
||||
const friends = req.filter(r => typeof r === 'object' && r && 'friend' in r) as
|
||||
{friend: string; presence?: boolean}[];
|
||||
|
||||
if (!(this.nso instanceof ZncProxyApi)) {
|
||||
if (req.includes('announcements')) req.push('webservices');
|
||||
if (req.includes('webservices')) req.push('announcements');
|
||||
if (req.includes('event')) req.push('friends', 'webservices', 'chats', 'media', 'announcements', 'user');
|
||||
if (req.includes('user')) req.push('friends', 'webservices', 'chats', 'media', 'announcements', 'event');
|
||||
if (req.includes('chats')) req.push('friends', 'webservices', 'media', 'announcements', 'event', 'user');
|
||||
}
|
||||
|
||||
if (req.includes('announcements')) {
|
||||
result.announcements = this.user ?
|
||||
await this.user?.getAnnouncements() :
|
||||
await this.nso.getAnnouncements();
|
||||
}
|
||||
if (req.includes('friends') || (friends && !(this.nso instanceof ZncProxyApi))) {
|
||||
result.friends = this.user ?
|
||||
await this.user.getFriends() :
|
||||
(await this.nso.getFriendList()).friends;
|
||||
} else if (friends && this.nso instanceof ZncProxyApi) {
|
||||
result.friends = await Promise.all(friends.map(async r => {
|
||||
const nso = this.nso as unknown as ZncProxyApi;
|
||||
|
||||
if (r.presence) {
|
||||
const friend: Friend_4 = {
|
||||
id: 0,
|
||||
nsaId: r.friend,
|
||||
imageUri: '',
|
||||
image2Uri: '',
|
||||
name: '',
|
||||
isFriend: true,
|
||||
isFavoriteFriend: false,
|
||||
isServiceUser: false,
|
||||
isNew: false,
|
||||
friendCreatedAt: 0,
|
||||
route: {
|
||||
appName: '',
|
||||
userName: '',
|
||||
shopUri: '',
|
||||
imageUri: '',
|
||||
channel: FriendRouteChannel.FRIEND_CODE,
|
||||
},
|
||||
isOnlineNotificationEnabled: false,
|
||||
presence: await nso.fetchProxyApi<PresenceOnline_4 | PresenceOffline>('/friend/' + r.friend + '/presence'),
|
||||
};
|
||||
|
||||
return friend;
|
||||
}
|
||||
|
||||
return (await nso.fetchProxyApi<{friend: Friend_4}>('/friend/' + r.friend)).friend;
|
||||
}));
|
||||
}
|
||||
if (req.includes('webservices')) {
|
||||
result.webservices = this.user ?
|
||||
await this.user.getWebServices() :
|
||||
await this.nso.getWebServices();
|
||||
}
|
||||
if (req.includes('event')) {
|
||||
const activeevent: GetActiveEventResult = this.user ?
|
||||
await this.user.getActiveEvent() :
|
||||
await this.nso.getActiveEvent();
|
||||
result.activeevent = 'id' in activeevent ? activeevent as ActiveEvent : undefined;
|
||||
}
|
||||
if (req.includes('user')) {
|
||||
result.user = await this.nso.getCurrentUser();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async init() {
|
||||
const {friends, user} = await this.fetch([
|
||||
'announcements',
|
||||
this.user_notifications ? 'user' : null,
|
||||
this.friend_notifications ? 'friends' : null,
|
||||
this.splatnet2_monitors.size ? 'user' : null,
|
||||
]);
|
||||
|
||||
await this.updatePresenceForNotifications(user, friends, this.data.user.id, true);
|
||||
if (user) await this.updatePresenceForSplatNet2Monitors([user]);
|
||||
await this.update();
|
||||
|
||||
return LoopResult.OK;
|
||||
}
|
||||
|
||||
async updateFriendsStatusForNotifications(
|
||||
friends: (CurrentUser | Friend)[],
|
||||
naid = this.data.user.id,
|
||||
naid = this.user.data.user.id,
|
||||
initialRun?: boolean
|
||||
) {
|
||||
this.notifications.updateFriendsStatusForNotifications(friends, naid, initialRun);
|
||||
}
|
||||
|
||||
async updatePresenceForNotifications(
|
||||
user: CurrentUser | undefined, friends: Friend[] | undefined,
|
||||
naid = this.data.user.id, initialRun?: boolean
|
||||
user: CurrentUser | null, friends: Friend[] | null,
|
||||
naid = this.user.data.user.id, initialRun?: boolean
|
||||
) {
|
||||
await this.updateFriendsStatusForNotifications(([] as (CurrentUser | Friend)[])
|
||||
.concat(this.user_notifications && user ? [user] : [])
|
||||
|
|
@ -182,13 +86,12 @@ export class ZncNotifications extends Loop {
|
|||
}
|
||||
|
||||
async update() {
|
||||
const {friends, user} = await this.fetch([
|
||||
this.user_notifications ? 'user' : null,
|
||||
this.friend_notifications ? 'friends' : null,
|
||||
this.splatnet2_monitors.size ? 'user' : null,
|
||||
const [user, friends] = await Promise.all([
|
||||
this.user_notifications || this.splatnet2_monitors.size ? this.user.getCurrentUser() : null,
|
||||
this.friend_notifications ? this.user.getFriends() : null,
|
||||
]);
|
||||
|
||||
await this.updatePresenceForNotifications(user, friends, this.data.user.id, false);
|
||||
await this.updatePresenceForNotifications(user, friends, this.user.data.user.id, false);
|
||||
if (user) await this.updatePresenceForSplatNet2Monitors([user]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,22 @@
|
|||
import { setTimeout } from 'node:timers';
|
||||
import { errors } from 'undici';
|
||||
import EventSource, { ErrorEvent, EventSourceErrorResponse } from '../util/eventsource.js';
|
||||
import { DiscordRpcClient, findDiscordRpcClient } from '../discord/rpc.js';
|
||||
import { getDiscordPresence, getInactiveDiscordPresence } from '../discord/util.js';
|
||||
import { DiscordPresencePlayTime, DiscordPresenceContext, DiscordPresence, ExternalMonitorConstructor, ExternalMonitor, ErrorResult } from '../discord/types.js';
|
||||
import { EmbeddedSplatNet2Monitor, ZncNotifications } from './notify.js';
|
||||
import { ActiveEvent, CurrentUser, Friend, Game, PresenceState, CoralError, PresenceOnline_4, PresenceOffline, PresenceOnline } from '../api/coral-types.js';
|
||||
import { getPresenceFromUrl } from '../api/znc-proxy.js';
|
||||
import { LocalStorage } from 'node-persist';
|
||||
import createDebug from '../util/debug.js';
|
||||
import { ErrorResponse, ResponseSymbol } from '../api/util.js';
|
||||
import Loop, { LoopResult } from '../util/loop.js';
|
||||
import { parseLinkHeader } from '../util/http.js';
|
||||
import { getUserAgent } from '../util/useragent.js';
|
||||
import { getTitleIdFromEcUrl, TemporaryErrorSymbol } from '../util/misc.js';
|
||||
import { handleError } from '../util/errors.js';
|
||||
import EventSource, { ErrorEvent, EventSourceErrorResponse } from '../util/eventsource.js';
|
||||
import { DiscordRpcClient, findDiscordRpcClient } from '../discord/rpc.js';
|
||||
import { getDiscordPresence, getInactiveDiscordPresence } from '../discord/util.js';
|
||||
import { DiscordPresencePlayTime, DiscordPresenceContext, DiscordPresence, ExternalMonitorConstructor, ExternalMonitor, ErrorResult } from '../discord/types.js';
|
||||
import { CoralApiInterface } from '../api/coral.js';
|
||||
import { ActiveEvent, CurrentUser, Friend, Game, PresenceState, CoralError, PresenceOnline_4, PresenceOffline, PresenceOnline } from '../api/coral-types.js';
|
||||
import { getPresenceFromUrl } from '../api/znc-proxy.js';
|
||||
import { ErrorResponse, ResponseSymbol } from '../api/util.js';
|
||||
import { CoralUser } from './users.js';
|
||||
import { EmbeddedSplatNet2Monitor, ZncNotifications } from './notify.js';
|
||||
import { StatusUpdateMonitor, StatusUpdateSourceHandle } from './status.js';
|
||||
|
||||
const debug = createDebug('nxapi:nso:presence');
|
||||
|
|
@ -41,9 +44,9 @@ class ZncDiscordPresenceClient {
|
|||
protected i = 0;
|
||||
|
||||
last_presence: Presence | null = null;
|
||||
last_user: CurrentUser | Friend | undefined = undefined;
|
||||
last_friendcode: CurrentUser['links']['friendCode'] | undefined = undefined;
|
||||
last_event: ActiveEvent | undefined = undefined;
|
||||
last_user: CurrentUser | Friend | null = null;
|
||||
last_friendcode: CurrentUser['links']['friendCode'] | null = null;
|
||||
last_event: ActiveEvent | null = null;
|
||||
|
||||
last_activity: DiscordPresence | string | null = null;
|
||||
onUpdateActivity: ((activity: DiscordPresence | null) => void) | null = null;
|
||||
|
|
@ -65,14 +68,14 @@ class ZncDiscordPresenceClient {
|
|||
|
||||
async updatePresenceForDiscord(
|
||||
presence: Presence | null,
|
||||
user?: CurrentUser | Friend,
|
||||
friendcode?: CurrentUser['links']['friendCode'],
|
||||
activeevent?: ActiveEvent
|
||||
user?: CurrentUser | Friend | null,
|
||||
friendcode?: CurrentUser['links']['friendCode'] | null,
|
||||
activeevent?: ActiveEvent | null,
|
||||
) {
|
||||
this.last_presence = presence;
|
||||
this.last_user = user;
|
||||
this.last_friendcode = friendcode;
|
||||
this.last_event = activeevent;
|
||||
this.last_user = user ?? null;
|
||||
this.last_friendcode = friendcode ?? null;
|
||||
this.last_event = activeevent ?? null;
|
||||
|
||||
this.onUpdate?.call(null);
|
||||
|
||||
|
|
@ -114,14 +117,14 @@ class ZncDiscordPresenceClient {
|
|||
}
|
||||
|
||||
const presence_context: DiscordPresenceContext = {
|
||||
friendcode: this.m.show_friend_code ? this.m.force_friend_code ?? friendcode : undefined,
|
||||
activeevent: this.m.show_active_event ? activeevent : undefined,
|
||||
friendcode: this.m.show_friend_code ? this.m.force_friend_code ?? friendcode ?? undefined : undefined,
|
||||
activeevent: this.m.show_active_event ? activeevent ?? undefined : undefined,
|
||||
show_play_time: this.m.show_play_time,
|
||||
znc_discord_presence: this.m,
|
||||
proxy_response: (this.m) instanceof ZncProxyDiscordPresence ? this.m.last_data : undefined,
|
||||
monitors: [...this.monitors.values()],
|
||||
nsaid: this.m.presence_user!,
|
||||
user,
|
||||
user: user ?? undefined,
|
||||
platform: 'platform' in presence ? presence.platform : undefined,
|
||||
};
|
||||
|
||||
|
|
@ -412,62 +415,30 @@ export class ZncDiscordPresence extends ZncNotifications {
|
|||
|
||||
readonly discord = new ZncDiscordPresenceClient(this);
|
||||
|
||||
async init() {
|
||||
const {friends, user, activeevent} = await this.fetch([
|
||||
'announcements',
|
||||
this.presence_user ?
|
||||
this.presence_user === this.data.nsoAccount.user.nsaId ? 'user' :
|
||||
{friend: this.presence_user} : null,
|
||||
this.presence_user && this.presence_user !== this.data.nsoAccount.user.nsaId &&
|
||||
this.show_active_event ? 'event' : null,
|
||||
this.user_notifications ? 'user' : null,
|
||||
this.friend_notifications ? 'friends' : null,
|
||||
this.splatnet2_monitors.size ? 'user' : null,
|
||||
]);
|
||||
|
||||
if (this.presence_user) {
|
||||
if (this.presence_user !== this.data.nsoAccount.user.nsaId) {
|
||||
const friend = friends!.find(f => f.nsaId === this.presence_user);
|
||||
|
||||
if (!friend) {
|
||||
throw new Error('User "' + this.presence_user + '" is not friends with this user');
|
||||
}
|
||||
|
||||
await this.restorePresenceForTitleUpdateAt(friend.nsaId, friend.presence);
|
||||
|
||||
await this.discord.updatePresenceForDiscord(friend.presence, friend);
|
||||
await this.savePresenceForTitleUpdateAt(friend.nsaId, friend.presence, this.discord.title?.since);
|
||||
} else {
|
||||
await this.restorePresenceForTitleUpdateAt(user!.nsaId, user!.presence);
|
||||
|
||||
await this.discord.updatePresenceForDiscord(user!.presence, user, user!.links.friendCode, activeevent);
|
||||
await this.savePresenceForTitleUpdateAt(user!.nsaId, user!.presence, this.discord.title?.since);
|
||||
}
|
||||
}
|
||||
|
||||
await this.updatePresenceForNotifications(user, friends, this.data.user.id, true);
|
||||
if (user) await this.updatePresenceForSplatNet2Monitors([user]);
|
||||
|
||||
return LoopResult.OK;
|
||||
constructor(
|
||||
user: CoralUser<CoralApiInterface>,
|
||||
readonly storage: LocalStorage,
|
||||
) {
|
||||
super(user);
|
||||
}
|
||||
|
||||
|
||||
get presence_enabled() {
|
||||
return !!this.presence_user;
|
||||
}
|
||||
|
||||
async update() {
|
||||
const {friends, user, activeevent} = await this.fetch([
|
||||
this.presence_user ?
|
||||
this.presence_user === this.data.nsoAccount.user.nsaId ? 'user' :
|
||||
{friend: this.presence_user} : null,
|
||||
this.presence_user && this.show_active_event ? 'event' : null,
|
||||
this.user_notifications ? 'user' : null,
|
||||
this.friend_notifications ? 'friends' : null,
|
||||
this.splatnet2_monitors.size ? 'user' : null,
|
||||
const [user, friends, activeevent] = await Promise.all([
|
||||
(this.presence_user && this.presence_user === this.user.data.nsoAccount.user.nsaId) ||
|
||||
this.user_notifications || this.splatnet2_monitors.size ? this.user.getCurrentUser() : null,
|
||||
(this.presence_user && this.presence_user !== this.user.data.nsoAccount.user.nsaId) ||
|
||||
this.friend_notifications ? this.user.getFriends() : null,
|
||||
this.presence_user && this.presence_user === this.user.data.nsoAccount.user.nsaId &&
|
||||
this.show_active_event ? this.user.getActiveEvent() : null,
|
||||
]);
|
||||
|
||||
if (this.presence_user) {
|
||||
if (this.presence_user !== this.data.nsoAccount.user.nsaId) {
|
||||
if (this.presence_user !== this.user.data.nsoAccount.user.nsaId) {
|
||||
const friend = friends!.find(f => f.nsaId === this.presence_user);
|
||||
|
||||
if (!friend) {
|
||||
|
|
@ -483,7 +454,7 @@ export class ZncDiscordPresence extends ZncNotifications {
|
|||
}
|
||||
}
|
||||
|
||||
await this.updatePresenceForNotifications(user, friends, this.data.user.id, false);
|
||||
await this.updatePresenceForNotifications(user, friends, this.user.data.user.id, false);
|
||||
if (user) await this.updatePresenceForSplatNet2Monitors([user]);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ export class CoralUser<T extends CoralApiInterface = CoralApi> implements CoralU
|
|||
this.active_event = await this.nso.getActiveEvent();
|
||||
}, this.update_interval);
|
||||
|
||||
return this.active_event.result;
|
||||
return 'id' in this.active_event.result ? this.active_event.result : null;
|
||||
}
|
||||
|
||||
async getCurrentUser() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user