mirror of
https://github.com/samuelthomas2774/nxapi.git
synced 2026-04-23 07:27:20 -05:00
Use cached web services from the API for the menu
Fixes https://github.com/samuelthomas2774/nxapi/issues/21
This commit is contained in:
parent
7576a16af7
commit
07a30e89be
|
|
@ -257,7 +257,7 @@ export class Store extends EventEmitter {
|
|||
super();
|
||||
|
||||
// ratelimit = false, as most users.get calls are triggered by user interaction (or at startup)
|
||||
this.users = Users.coral(storage, process.env.ZNC_PROXY_URL, false);
|
||||
this.users = Users.coral(this, process.env.ZNC_PROXY_URL, false);
|
||||
}
|
||||
|
||||
async saveMonitorState(monitors: PresenceMonitorManager) {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import { EmbeddedPresenceMonitor, EmbeddedProxyPresenceMonitor } from './monitor
|
|||
import { createWindow } from './windows.js';
|
||||
import { WindowType } from '../common/types.js';
|
||||
import CoralApi from '../../api/coral.js';
|
||||
import { CachedWebServicesList } from '../../common/users.js';
|
||||
|
||||
const debug = createDebug('app:main:menu');
|
||||
|
||||
|
|
@ -30,6 +31,10 @@ export default class MenuApp {
|
|||
this.tray.setToolTip('nxapi');
|
||||
|
||||
app.store.on('update-nintendo-accounts', () => this.updateMenu());
|
||||
app.store.on('update-cached-web-services', (language: string, cache: CachedWebServicesList) => {
|
||||
this.webservices.set(language, cache.webservices);
|
||||
this.updateMenu();
|
||||
});
|
||||
this.updateMenu();
|
||||
}
|
||||
|
||||
|
|
@ -52,6 +57,8 @@ export default class MenuApp {
|
|||
const discord_presence_active = discord_presence_monitor instanceof EmbeddedPresenceMonitor &&
|
||||
discord_presence_monitor?.data?.user.id === data.user.id;
|
||||
|
||||
const webservices = await this.getWebServiceItems(data.user.language, token);
|
||||
|
||||
const item = new MenuItem({
|
||||
label: data.nsoAccount.user.name,
|
||||
submenu: [
|
||||
|
|
@ -72,9 +79,11 @@ export default class MenuApp {
|
|||
{label: 'Update now', enabled: !!monitor, click: () => monitor?.skipIntervalInCurrentLoop(true)},
|
||||
{type: 'separator'},
|
||||
{label: 'Add friend', click: () => this.showAddFriendWindow(data.user.id)},
|
||||
{type: 'separator'},
|
||||
{label: 'Web services', enabled: false},
|
||||
...await this.getWebServiceItems(token) as any,
|
||||
...(webservices.length ? [
|
||||
{type: 'separator'},
|
||||
{label: 'Web services', enabled: false},
|
||||
...webservices as any,
|
||||
] : []),
|
||||
],
|
||||
});
|
||||
|
||||
|
|
@ -120,57 +129,21 @@ export default class MenuApp {
|
|||
addPctlAccount = (item: MenuItem, window: BrowserWindow | undefined, event: KeyboardEvent) =>
|
||||
askAddPctlAccount(this.app.store.storage, !event.shiftKey);
|
||||
|
||||
// Hardcode these temporarily until they are cached
|
||||
webservices: WebService[] | null = [
|
||||
{
|
||||
id: 4953919198265344,
|
||||
uri: 'https://web.sd.lp1.acbaa.srv.nintendo.net',
|
||||
customAttributes: [
|
||||
{attrKey: 'verifyMembership', attrValue: 'true'},
|
||||
{attrKey: 'deepLinkingEnabled', attrValue: 'true'},
|
||||
{attrKey: 'appNavigationBarBgColor', attrValue: '82D7AA'},
|
||||
{attrKey: 'appStatusBarBgColor', attrValue: '82D7AA'},
|
||||
],
|
||||
whiteList: ['*.acbaa.srv.nintendo.net'],
|
||||
name: 'Animal Crossing: New Horizons',
|
||||
imageUri: 'https://cdn.znc.srv.nintendo.net/gameWebServices/n5b4648f/n5b4648f/images/euEn/banner.png',
|
||||
},
|
||||
{
|
||||
id: 5598642853249024,
|
||||
uri: 'https://app.smashbros.nintendo.net',
|
||||
customAttributes: [
|
||||
{attrKey: 'verifyMembership', attrValue: 'true'},
|
||||
{attrKey: 'appNavigationBarBgColor', attrValue: 'A50514'},
|
||||
{attrKey: 'appStatusBarBgColor', attrValue: 'A50514'},
|
||||
],
|
||||
whiteList: ['app.smashbros.nintendo.net'],
|
||||
name: 'Super Smash Bros. Ultimate',
|
||||
imageUri: 'https://cdn.znc.srv.nintendo.net/gameWebServices/n3f32691/n3f32691/images/euEn/banner.png',
|
||||
},
|
||||
{
|
||||
id: 5741031244955648,
|
||||
uri: 'https://app.splatoon2.nintendo.net/',
|
||||
customAttributes: [
|
||||
{attrKey: 'appNavigationBarBgColor', attrValue: 'E60012'},
|
||||
{attrKey: 'appStatusBarBgColor', attrValue: 'E60012'},
|
||||
],
|
||||
whiteList: ['app.splatoon2.nintendo.net'],
|
||||
name: 'Splatoon 2',
|
||||
imageUri: 'https://cdn.znc.srv.nintendo.net/gameWebServices/splatoon2/images/euEn/banner.png',
|
||||
},
|
||||
];
|
||||
protected webservices = new Map</** language */ string, WebService[]>();
|
||||
|
||||
async getWebServices(token: string) {
|
||||
if (this.webservices) return this.webservices;
|
||||
async getWebServices(language: string) {
|
||||
const cache = this.webservices.get(language);
|
||||
if (cache) return cache;
|
||||
|
||||
const {nso, data} = await this.app.store.users.get(token);
|
||||
const webservices: CachedWebServicesList | undefined =
|
||||
await this.app.store.storage.getItem('CachedWebServicesList.' + language);
|
||||
|
||||
const webservices = await nso.getWebServices();
|
||||
return this.webservices = webservices;
|
||||
if (webservices) this.webservices.set(language, webservices.webservices);
|
||||
return webservices?.webservices ?? [];
|
||||
}
|
||||
|
||||
async getWebServiceItems(token: string) {
|
||||
const webservices = await this.getWebServices(token);
|
||||
async getWebServiceItems(language: string, token: string) {
|
||||
const webservices = await this.getWebServices(language);
|
||||
const items = [];
|
||||
|
||||
for (const webservice of webservices) {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,12 @@
|
|||
import * as crypto from 'node:crypto';
|
||||
import createDebug from 'debug';
|
||||
import * as persist from 'node-persist';
|
||||
import CoralApi from '../api/coral.js';
|
||||
import CoralApi, { Result } from '../api/coral.js';
|
||||
import ZncProxyApi from '../api/znc-proxy.js';
|
||||
import { Announcements, Friends, GetActiveEventResult, WebServices, CoralSuccessResponse, Friend } from '../api/coral-types.js';
|
||||
import { Announcements, Friends, Friend, GetActiveEventResult, CoralSuccessResponse, WebService, WebServices } from '../api/coral-types.js';
|
||||
import { getToken, SavedToken } from './auth/coral.js';
|
||||
import type { Store } from '../app/main/index.js';
|
||||
import { NintendoAccountUser } from '../api/na.js';
|
||||
|
||||
const debug = createDebug('nxapi:users');
|
||||
|
||||
|
|
@ -40,9 +43,14 @@ export default class Users<T extends UserData> {
|
|||
return promise;
|
||||
}
|
||||
|
||||
static coral(storage: persist.LocalStorage, znc_proxy_url: string, ratelimit?: boolean): Users<CoralUser<ZncProxyApi>>
|
||||
static coral(storage: persist.LocalStorage, znc_proxy_url?: string, ratelimit?: boolean): Users<CoralUser>
|
||||
static coral(storage: persist.LocalStorage, znc_proxy_url?: string, ratelimit?: boolean) {
|
||||
static coral(store: Store | persist.LocalStorage, znc_proxy_url: string, ratelimit?: boolean): Users<CoralUser<ZncProxyApi>>
|
||||
static coral(store: Store | persist.LocalStorage, znc_proxy_url?: string, ratelimit?: boolean): Users<CoralUser>
|
||||
static coral(_store: Store | persist.LocalStorage, znc_proxy_url?: string, ratelimit?: boolean) {
|
||||
const store = 'storage' in _store ? _store : null;
|
||||
const storage = 'storage' in _store ? _store.storage : _store;
|
||||
|
||||
const cached_webservices = new Map</** language */ string, string>();
|
||||
|
||||
return new Users(async token => {
|
||||
const {nso, data} = await getToken(storage, token, znc_proxy_url, ratelimit);
|
||||
|
||||
|
|
@ -53,7 +61,16 @@ export default class Users<T extends UserData> {
|
|||
nso.getActiveEvent(),
|
||||
]);
|
||||
|
||||
return new CoralUser(nso, data, announcements, friends, webservices, active_event);
|
||||
const user = new CoralUser(nso, data, announcements, friends, webservices, active_event);
|
||||
|
||||
if (store) {
|
||||
await maybeUpdateWebServicesListCache(cached_webservices, store, data.user, webservices);
|
||||
user.onUpdatedWebServices = webservices => {
|
||||
maybeUpdateWebServicesListCache(cached_webservices, store, data.user, webservices);
|
||||
};
|
||||
}
|
||||
|
||||
return user;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -80,6 +97,8 @@ export class CoralUser<T extends CoralApi = CoralApi> implements CoralUserData<T
|
|||
active_event: Date.now(),
|
||||
};
|
||||
|
||||
onUpdatedWebServices: ((webservices: Result<WebServices>) => void) | null = null;
|
||||
|
||||
constructor(
|
||||
public nso: T,
|
||||
public data: SavedToken,
|
||||
|
|
@ -125,7 +144,9 @@ export class CoralUser<T extends CoralApi = CoralApi> implements CoralUserData<T
|
|||
|
||||
async getWebServices() {
|
||||
await this.update('webservices', async () => {
|
||||
this.webservices = await this.nso.getWebServices();
|
||||
const webservices = this.webservices = await this.nso.getWebServices();
|
||||
|
||||
this.onUpdatedWebServices?.call(null, webservices);
|
||||
}, 10 * 1000);
|
||||
|
||||
return this.webservices.result;
|
||||
|
|
@ -167,3 +188,31 @@ export class CoralUser<T extends CoralApi = CoralApi> implements CoralUserData<T
|
|||
return {result, friend};
|
||||
}
|
||||
}
|
||||
|
||||
export interface CachedWebServicesList {
|
||||
webservices: WebService[];
|
||||
updated_at: number;
|
||||
language: string;
|
||||
user: string;
|
||||
}
|
||||
|
||||
async function maybeUpdateWebServicesListCache(
|
||||
cached_webservices: Map<string, string>, store: Store, // storage: persist.LocalStorage,
|
||||
user: NintendoAccountUser, webservices: WebService[]
|
||||
) {
|
||||
const webservices_hash = crypto.createHash('sha256').update(JSON.stringify(webservices)).digest('hex');
|
||||
if (cached_webservices.get(user.language) === webservices_hash) return;
|
||||
|
||||
debug('Updating web services list', user.language);
|
||||
|
||||
const cache: CachedWebServicesList = {
|
||||
webservices,
|
||||
updated_at: Date.now(),
|
||||
language: user.language,
|
||||
user: user.id,
|
||||
};
|
||||
|
||||
await store.storage.setItem('CachedWebServicesList.' + user.language, cache);
|
||||
cached_webservices.set(user.language, webservices_hash);
|
||||
store?.emit('update-cached-web-services', user.language, cache);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user