mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-31 07:46:51 +00:00
perf(slack): memoize allow-from and mention paths
This commit is contained in:
@@ -8,13 +8,89 @@ import {
|
||||
import { resolveSlackChannelConfig } from "./channel-config.js";
|
||||
import { normalizeSlackChannelType, type SlackMonitorContext } from "./context.js";
|
||||
|
||||
type ResolvedAllowFromLists = {
|
||||
allowFrom: string[];
|
||||
allowFromLower: string[];
|
||||
};
|
||||
|
||||
type SlackAllowFromCacheState = {
|
||||
baseSignature?: string;
|
||||
base?: ResolvedAllowFromLists;
|
||||
pairingKey?: string;
|
||||
pairing?: ResolvedAllowFromLists;
|
||||
pairingExpiresAtMs?: number;
|
||||
pairingPending?: Promise<ResolvedAllowFromLists>;
|
||||
};
|
||||
|
||||
let slackAllowFromCache = new WeakMap<SlackMonitorContext, SlackAllowFromCacheState>();
|
||||
const DEFAULT_PAIRING_ALLOW_FROM_CACHE_TTL_MS = 5000;
|
||||
|
||||
function getPairingAllowFromCacheTtlMs(): number {
|
||||
const raw = process.env.OPENCLAW_SLACK_PAIRING_ALLOWFROM_CACHE_TTL_MS?.trim();
|
||||
if (!raw) {
|
||||
return DEFAULT_PAIRING_ALLOW_FROM_CACHE_TTL_MS;
|
||||
}
|
||||
const parsed = Number(raw);
|
||||
if (!Number.isFinite(parsed)) {
|
||||
return DEFAULT_PAIRING_ALLOW_FROM_CACHE_TTL_MS;
|
||||
}
|
||||
return Math.max(0, Math.floor(parsed));
|
||||
}
|
||||
|
||||
function getAllowFromCacheState(ctx: SlackMonitorContext): SlackAllowFromCacheState {
|
||||
const existing = slackAllowFromCache.get(ctx);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
const next: SlackAllowFromCacheState = {};
|
||||
slackAllowFromCache.set(ctx, next);
|
||||
return next;
|
||||
}
|
||||
|
||||
function buildBaseAllowFrom(ctx: SlackMonitorContext): ResolvedAllowFromLists {
|
||||
const allowFrom = normalizeAllowList(ctx.allowFrom);
|
||||
return {
|
||||
allowFrom,
|
||||
allowFromLower: normalizeAllowListLower(allowFrom),
|
||||
};
|
||||
}
|
||||
|
||||
export async function resolveSlackEffectiveAllowFrom(
|
||||
ctx: SlackMonitorContext,
|
||||
options?: { includePairingStore?: boolean },
|
||||
) {
|
||||
const includePairingStore = options?.includePairingStore === true;
|
||||
let storeAllowFrom: string[] = [];
|
||||
if (includePairingStore) {
|
||||
const cache = getAllowFromCacheState(ctx);
|
||||
const baseSignature = JSON.stringify(ctx.allowFrom);
|
||||
if (cache.baseSignature !== baseSignature || !cache.base) {
|
||||
cache.baseSignature = baseSignature;
|
||||
cache.base = buildBaseAllowFrom(ctx);
|
||||
cache.pairing = undefined;
|
||||
cache.pairingKey = undefined;
|
||||
cache.pairingExpiresAtMs = undefined;
|
||||
cache.pairingPending = undefined;
|
||||
}
|
||||
if (!includePairingStore) {
|
||||
return cache.base;
|
||||
}
|
||||
|
||||
const ttlMs = getPairingAllowFromCacheTtlMs();
|
||||
const nowMs = Date.now();
|
||||
const pairingKey = `${ctx.accountId}:${ctx.dmPolicy}`;
|
||||
if (
|
||||
ttlMs > 0 &&
|
||||
cache.pairing &&
|
||||
cache.pairingKey === pairingKey &&
|
||||
(cache.pairingExpiresAtMs ?? 0) >= nowMs
|
||||
) {
|
||||
return cache.pairing;
|
||||
}
|
||||
if (cache.pairingPending && cache.pairingKey === pairingKey) {
|
||||
return await cache.pairingPending;
|
||||
}
|
||||
|
||||
const pairingPending = (async (): Promise<ResolvedAllowFromLists> => {
|
||||
let storeAllowFrom: string[] = [];
|
||||
try {
|
||||
const resolved = await readStoreAllowFromForDmPolicy({
|
||||
provider: "slack",
|
||||
@@ -25,10 +101,34 @@ export async function resolveSlackEffectiveAllowFrom(
|
||||
} catch {
|
||||
storeAllowFrom = [];
|
||||
}
|
||||
const allowFrom = normalizeAllowList([...(cache.base?.allowFrom ?? []), ...storeAllowFrom]);
|
||||
return {
|
||||
allowFrom,
|
||||
allowFromLower: normalizeAllowListLower(allowFrom),
|
||||
};
|
||||
})();
|
||||
|
||||
cache.pairingKey = pairingKey;
|
||||
cache.pairingPending = pairingPending;
|
||||
try {
|
||||
const resolved = await pairingPending;
|
||||
if (ttlMs > 0) {
|
||||
cache.pairing = resolved;
|
||||
cache.pairingExpiresAtMs = nowMs + ttlMs;
|
||||
} else {
|
||||
cache.pairing = undefined;
|
||||
cache.pairingExpiresAtMs = undefined;
|
||||
}
|
||||
return resolved;
|
||||
} finally {
|
||||
if (cache.pairingPending === pairingPending) {
|
||||
cache.pairingPending = undefined;
|
||||
}
|
||||
}
|
||||
const allowFrom = normalizeAllowList([...ctx.allowFrom, ...storeAllowFrom]);
|
||||
const allowFromLower = normalizeAllowListLower(allowFrom);
|
||||
return { allowFrom, allowFromLower };
|
||||
}
|
||||
|
||||
export function clearSlackAllowFromCacheForTest(): void {
|
||||
slackAllowFromCache = new WeakMap<SlackMonitorContext, SlackAllowFromCacheState>();
|
||||
}
|
||||
|
||||
export function isSlackSenderAllowListed(params: {
|
||||
|
||||
Reference in New Issue
Block a user