aaaa
This commit is contained in:
parent
cb9ebad0fa
commit
2479564b8b
|
|
@ -224,7 +224,13 @@ export class GatewayManager implements DurableObject {
|
|||
token: this.env.DISCORD_BOT_TOKEN,
|
||||
intents: INTENTS,
|
||||
properties: { os: "linux", browser: "dough-restful", device: "dough-restful" },
|
||||
presence: { status: "invisible", activities: [], since: 0, afk: false },
|
||||
presence: {
|
||||
status: "idle",
|
||||
afk: false,
|
||||
since: 0,
|
||||
// Custom status (type 4): the text shown is the `state` field.
|
||||
activities: [{ name: "Custom Status", type: 4, state: "meow meow mrrp meow" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ export default {
|
|||
}
|
||||
|
||||
if (sub === "profile") {
|
||||
const profile = await getProfile(env, id);
|
||||
const profile = await getProfile(env, id, ctx);
|
||||
if (!profile) {
|
||||
return json({ success: false, error: { code: "not_found", message: "User not found." } }, 404);
|
||||
}
|
||||
|
|
@ -99,7 +99,7 @@ export default {
|
|||
}
|
||||
|
||||
// Unified record: profile (REST) + presence (gateway), in parallel.
|
||||
const [profile, presence] = await Promise.all([getProfile(env, id), fetchPresence(env, id)]);
|
||||
const [profile, presence] = await Promise.all([getProfile(env, id, ctx), fetchPresence(env, id)]);
|
||||
if (!profile) {
|
||||
return json({ success: false, error: { code: "not_found", message: "User not found." } }, 404);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,18 +84,43 @@ function cacheKey(id: string): string {
|
|||
return `profile:${id}`;
|
||||
}
|
||||
|
||||
/** Build profile from Discord, with a KV read-through cache. */
|
||||
export async function getProfile(env: Env, id: string): Promise<ProfileResult | null> {
|
||||
/**
|
||||
* Build profile from Discord — LIVE-FIRST.
|
||||
*
|
||||
* Always fetches fresh from Discord so profile/badges/connections are current,
|
||||
* and only falls back to the KV copy if the REST call fails (e.g. Discord is
|
||||
* rate-limiting us). The KV copy is refreshed in the background, throttled to
|
||||
* at most one write per TTL window so we don't blow KV write limits.
|
||||
*/
|
||||
export async function getProfile(
|
||||
env: Env,
|
||||
id: string,
|
||||
ctx?: ExecutionContext
|
||||
): Promise<ProfileResult | null> {
|
||||
const fresh = await buildFreshProfile(env, id);
|
||||
if (fresh) {
|
||||
const refresh = maybeRefreshCache(env, id, fresh);
|
||||
if (ctx) ctx.waitUntil(refresh);
|
||||
else await refresh;
|
||||
return fresh;
|
||||
}
|
||||
|
||||
// Discord REST failed — serve last-known-good from KV if we have it.
|
||||
const cached = await env.PROFILE_CACHE.get(cacheKey(id), "json");
|
||||
if (cached) {
|
||||
const c = cached as Omit<ProfileResult, "source">;
|
||||
return { ...c, source: "cache" };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
const result = await buildFreshProfile(env, id);
|
||||
if (!result) return null;
|
||||
|
||||
/** Write the fallback copy to KV, but at most once per TTL window. */
|
||||
async function maybeRefreshCache(env: Env, id: string, result: ProfileResult): Promise<void> {
|
||||
const ttl = Math.max(60, Number(env.PROFILE_CACHE_TTL_SECONDS || "300"));
|
||||
const { metadata } = await env.PROFILE_CACHE.getWithMetadata(cacheKey(id));
|
||||
const lastWrite = (metadata as { t?: number } | null)?.t ?? 0;
|
||||
if (Date.now() - lastWrite < ttl * 1000) return; // throttled
|
||||
|
||||
await env.PROFILE_CACHE.put(
|
||||
cacheKey(id),
|
||||
JSON.stringify({
|
||||
|
|
@ -103,9 +128,8 @@ export async function getProfile(env: Env, id: string): Promise<ProfileResult |
|
|||
badges: result.badges,
|
||||
connected_accounts: result.connected_accounts,
|
||||
}),
|
||||
{ expirationTtl: ttl }
|
||||
{ expirationTtl: ttl * 2, metadata: { t: Date.now() } }
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
async function buildFreshProfile(env: Env, id: string): Promise<ProfileResult | null> {
|
||||
|
|
|
|||
Loading…
Reference in New Issue