| import { resolveGlobalMap } from "../shared/global-singleton.js"; |
|
|
| |
| |
| |
| |
| |
|
|
| const TTL_MS = 24 * 60 * 60 * 1000; |
| const MAX_ENTRIES = 5000; |
|
|
| |
| |
| |
| |
| const SLACK_THREAD_PARTICIPATION_KEY = Symbol.for("openclaw.slackThreadParticipation"); |
|
|
| const threadParticipation = resolveGlobalMap<string, number>(SLACK_THREAD_PARTICIPATION_KEY); |
|
|
| function makeKey(accountId: string, channelId: string, threadTs: string): string { |
| return `${accountId}:${channelId}:${threadTs}`; |
| } |
|
|
| function evictExpired(): void { |
| const now = Date.now(); |
| for (const [key, timestamp] of threadParticipation) { |
| if (now - timestamp > TTL_MS) { |
| threadParticipation.delete(key); |
| } |
| } |
| } |
|
|
| function evictOldest(): void { |
| const oldest = threadParticipation.keys().next().value; |
| if (oldest) { |
| threadParticipation.delete(oldest); |
| } |
| } |
|
|
| export function recordSlackThreadParticipation( |
| accountId: string, |
| channelId: string, |
| threadTs: string, |
| ): void { |
| if (!accountId || !channelId || !threadTs) { |
| return; |
| } |
| if (threadParticipation.size >= MAX_ENTRIES) { |
| evictExpired(); |
| } |
| if (threadParticipation.size >= MAX_ENTRIES) { |
| evictOldest(); |
| } |
| threadParticipation.set(makeKey(accountId, channelId, threadTs), Date.now()); |
| } |
|
|
| export function hasSlackThreadParticipation( |
| accountId: string, |
| channelId: string, |
| threadTs: string, |
| ): boolean { |
| if (!accountId || !channelId || !threadTs) { |
| return false; |
| } |
| const key = makeKey(accountId, channelId, threadTs); |
| const timestamp = threadParticipation.get(key); |
| if (timestamp == null) { |
| return false; |
| } |
| if (Date.now() - timestamp > TTL_MS) { |
| threadParticipation.delete(key); |
| return false; |
| } |
| return true; |
| } |
|
|
| export function clearSlackThreadParticipationCache(): void { |
| threadParticipation.clear(); |
| } |
|
|