Discord: scope presence cache by account

This commit is contained in:
Shadow 2026-01-26 10:29:17 -06:00
parent 5933593659
commit 8a8d1024b4
No known key found for this signature in database
4 changed files with 47 additions and 13 deletions

View File

@ -55,7 +55,7 @@ export async function handleDiscordGuildAction(
const member = accountId const member = accountId
? await fetchMemberInfoDiscord(guildId, userId, { accountId }) ? await fetchMemberInfoDiscord(guildId, userId, { accountId })
: await fetchMemberInfoDiscord(guildId, userId); : await fetchMemberInfoDiscord(guildId, userId);
const presence = getPresence(userId); const presence = getPresence(accountId, userId);
const activities = presence?.activities ?? undefined; const activities = presence?.activities ?? undefined;
const status = presence?.status ?? undefined; const status = presence?.status ?? undefined;
return jsonResult({ ok: true, member, ...(presence ? { status, activities } : {}) }); return jsonResult({ ok: true, member, ...(presence ? { status, activities } : {}) });

View File

@ -276,10 +276,12 @@ type PresenceUpdateEvent = Parameters<PresenceUpdateListener["handle"]>[0];
export class DiscordPresenceListener extends PresenceUpdateListener { export class DiscordPresenceListener extends PresenceUpdateListener {
private logger?: Logger; private logger?: Logger;
private accountId?: string;
constructor(logger?: Logger) { constructor(params: { logger?: Logger; accountId?: string }) {
super(); super();
this.logger = logger; this.logger = params.logger;
this.accountId = params.accountId;
} }
async handle(data: PresenceUpdateEvent) { async handle(data: PresenceUpdateEvent) {
@ -289,7 +291,11 @@ export class DiscordPresenceListener extends PresenceUpdateListener {
? String(data.user.id) ? String(data.user.id)
: undefined; : undefined;
if (!userId) return; if (!userId) return;
setPresence(userId, data as import("discord-api-types/v10").GatewayPresenceUpdate); setPresence(
this.accountId,
userId,
data as import("discord-api-types/v10").GatewayPresenceUpdate,
);
} catch (err) { } catch (err) {
const logger = this.logger ?? discordEventQueueLog; const logger = this.logger ?? discordEventQueueLog;
logger.error(danger(`discord presence handler failed: ${String(err)}`)); logger.error(danger(`discord presence handler failed: ${String(err)}`));

View File

@ -4,24 +4,49 @@ import type { GatewayPresenceUpdate } from "discord-api-types/v10";
* In-memory cache of Discord user presence data. * In-memory cache of Discord user presence data.
* Populated by PRESENCE_UPDATE gateway events when the GuildPresences intent is enabled. * Populated by PRESENCE_UPDATE gateway events when the GuildPresences intent is enabled.
*/ */
const presenceCache = new Map<string, GatewayPresenceUpdate>(); const presenceCache = new Map<string, Map<string, GatewayPresenceUpdate>>();
function resolveAccountKey(accountId?: string): string {
return accountId ?? "default";
}
/** Update cached presence for a user. */ /** Update cached presence for a user. */
export function setPresence(userId: string, data: GatewayPresenceUpdate): void { export function setPresence(
presenceCache.set(userId, data); accountId: string | undefined,
userId: string,
data: GatewayPresenceUpdate,
): void {
const accountKey = resolveAccountKey(accountId);
let accountCache = presenceCache.get(accountKey);
if (!accountCache) {
accountCache = new Map();
presenceCache.set(accountKey, accountCache);
}
accountCache.set(userId, data);
} }
/** Get cached presence for a user. Returns undefined if not cached. */ /** Get cached presence for a user. Returns undefined if not cached. */
export function getPresence(userId: string): GatewayPresenceUpdate | undefined { export function getPresence(
return presenceCache.get(userId); accountId: string | undefined,
userId: string,
): GatewayPresenceUpdate | undefined {
return presenceCache.get(resolveAccountKey(accountId))?.get(userId);
} }
/** Clear all cached presence data. */ /** Clear cached presence data. */
export function clearPresences(): void { export function clearPresences(accountId?: string): void {
if (accountId) {
presenceCache.delete(resolveAccountKey(accountId));
return;
}
presenceCache.clear(); presenceCache.clear();
} }
/** Get the number of cached presence entries. */ /** Get the number of cached presence entries. */
export function presenceCacheSize(): number { export function presenceCacheSize(): number {
return presenceCache.size; let total = 0;
for (const accountCache of presenceCache.values()) {
total += accountCache.size;
}
return total;
} }

View File

@ -542,7 +542,10 @@ export async function monitorDiscordProvider(opts: MonitorDiscordOpts = {}) {
); );
if (discordCfg.intents?.presence) { if (discordCfg.intents?.presence) {
registerDiscordListener(client.listeners, new DiscordPresenceListener(logger)); registerDiscordListener(
client.listeners,
new DiscordPresenceListener({ logger, accountId: account.accountId }),
);
runtime.log?.("discord: GuildPresences intent enabled — presence listener registered"); runtime.log?.("discord: GuildPresences intent enabled — presence listener registered");
} }