mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 18:54:31 +00:00
This commit is contained in:
111
src/discord/directory-cache.ts
Normal file
111
src/discord/directory-cache.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
import { DEFAULT_ACCOUNT_ID, normalizeAccountId } from "../routing/account-id.js";
|
||||
|
||||
const DISCORD_DIRECTORY_CACHE_MAX_ENTRIES = 4000;
|
||||
const DISCORD_DISCRIMINATOR_SUFFIX = /#\d{4}$/;
|
||||
|
||||
const DIRECTORY_HANDLE_CACHE = new Map<string, Map<string, string>>();
|
||||
|
||||
function normalizeAccountCacheKey(accountId?: string | null): string {
|
||||
const normalized = normalizeAccountId(accountId ?? DEFAULT_ACCOUNT_ID);
|
||||
return normalized || DEFAULT_ACCOUNT_ID;
|
||||
}
|
||||
|
||||
function normalizeSnowflake(value: string | number | bigint): string | null {
|
||||
const text = String(value ?? "").trim();
|
||||
if (!/^\d+$/.test(text)) {
|
||||
return null;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function normalizeHandleKey(raw: string): string | null {
|
||||
let handle = raw.trim();
|
||||
if (!handle) {
|
||||
return null;
|
||||
}
|
||||
if (handle.startsWith("@")) {
|
||||
handle = handle.slice(1).trim();
|
||||
}
|
||||
if (!handle || /\s/.test(handle)) {
|
||||
return null;
|
||||
}
|
||||
return handle.toLowerCase();
|
||||
}
|
||||
|
||||
function ensureAccountCache(accountId?: string | null): Map<string, string> {
|
||||
const cacheKey = normalizeAccountCacheKey(accountId);
|
||||
const existing = DIRECTORY_HANDLE_CACHE.get(cacheKey);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
const created = new Map<string, string>();
|
||||
DIRECTORY_HANDLE_CACHE.set(cacheKey, created);
|
||||
return created;
|
||||
}
|
||||
|
||||
function setCacheEntry(cache: Map<string, string>, key: string, userId: string): void {
|
||||
if (cache.has(key)) {
|
||||
cache.delete(key);
|
||||
}
|
||||
cache.set(key, userId);
|
||||
if (cache.size <= DISCORD_DIRECTORY_CACHE_MAX_ENTRIES) {
|
||||
return;
|
||||
}
|
||||
const oldest = cache.keys().next();
|
||||
if (!oldest.done) {
|
||||
cache.delete(oldest.value);
|
||||
}
|
||||
}
|
||||
|
||||
export function rememberDiscordDirectoryUser(params: {
|
||||
accountId?: string | null;
|
||||
userId: string | number | bigint;
|
||||
handles: Array<string | null | undefined>;
|
||||
}): void {
|
||||
const userId = normalizeSnowflake(params.userId);
|
||||
if (!userId) {
|
||||
return;
|
||||
}
|
||||
const cache = ensureAccountCache(params.accountId);
|
||||
for (const candidate of params.handles) {
|
||||
if (typeof candidate !== "string") {
|
||||
continue;
|
||||
}
|
||||
const handle = normalizeHandleKey(candidate);
|
||||
if (!handle) {
|
||||
continue;
|
||||
}
|
||||
setCacheEntry(cache, handle, userId);
|
||||
const withoutDiscriminator = handle.replace(DISCORD_DISCRIMINATOR_SUFFIX, "");
|
||||
if (withoutDiscriminator && withoutDiscriminator !== handle) {
|
||||
setCacheEntry(cache, withoutDiscriminator, userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveDiscordDirectoryUserId(params: {
|
||||
accountId?: string | null;
|
||||
handle: string;
|
||||
}): string | undefined {
|
||||
const cache = DIRECTORY_HANDLE_CACHE.get(normalizeAccountCacheKey(params.accountId));
|
||||
if (!cache) {
|
||||
return undefined;
|
||||
}
|
||||
const handle = normalizeHandleKey(params.handle);
|
||||
if (!handle) {
|
||||
return undefined;
|
||||
}
|
||||
const direct = cache.get(handle);
|
||||
if (direct) {
|
||||
return direct;
|
||||
}
|
||||
const withoutDiscriminator = handle.replace(DISCORD_DISCRIMINATOR_SUFFIX, "");
|
||||
if (!withoutDiscriminator || withoutDiscriminator === handle) {
|
||||
return undefined;
|
||||
}
|
||||
return cache.get(withoutDiscriminator);
|
||||
}
|
||||
|
||||
export function __resetDiscordDirectoryCacheForTest(): void {
|
||||
DIRECTORY_HANDLE_CACHE.clear();
|
||||
}
|
||||
Reference in New Issue
Block a user