mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 12:56:01 -06:00
fix(feishu): bound card action chat cache clocks
This commit is contained in:
@@ -376,6 +376,39 @@ describe("Feishu Card Action Handler", () => {
|
||||
expect(createFeishuClientMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("does not cache resolved chat type when expiry would exceed a valid Date", async () => {
|
||||
vi.useFakeTimers();
|
||||
vi.setSystemTime(new Date(8_640_000_000_000_000));
|
||||
try {
|
||||
const getChat = vi.fn().mockResolvedValue({ code: 0, data: { chat_type: "p2p" } });
|
||||
createFeishuClientMock.mockReturnValue({
|
||||
im: {
|
||||
chat: {
|
||||
get: getChat,
|
||||
},
|
||||
},
|
||||
});
|
||||
const firstEvent = createCardActionEvent({
|
||||
token: "tok9b-boundary-1",
|
||||
chatId: "oc_dm_chat_boundary",
|
||||
actionValue: { text: "/help" },
|
||||
});
|
||||
const secondEvent = createCardActionEvent({
|
||||
token: "tok9b-boundary-2",
|
||||
chatId: "oc_dm_chat_boundary",
|
||||
actionValue: { text: "/help" },
|
||||
});
|
||||
|
||||
await handleFeishuCardAction({ cfg, event: firstEvent, runtime });
|
||||
await handleFeishuCardAction({ cfg, event: secondEvent, runtime });
|
||||
|
||||
expect(getChat).toHaveBeenCalledTimes(2);
|
||||
expect(handleFeishuMessage).toHaveBeenCalledTimes(2);
|
||||
} finally {
|
||||
vi.useRealTimers();
|
||||
}
|
||||
});
|
||||
|
||||
it("uses resolved DM chat type when building approval cards without stored context", async () => {
|
||||
createFeishuClientMock.mockReturnValueOnce({
|
||||
im: {
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
import {
|
||||
asDateTimestampMs,
|
||||
resolveExpiresAtMsFromDurationMs,
|
||||
} from "openclaw/plugin-sdk/number-runtime";
|
||||
import type { ClawdbotConfig, RuntimeEnv } from "../runtime-api.js";
|
||||
import { resolveFeishuRuntimeAccount } from "./accounts.js";
|
||||
import { handleFeishuMessage, type FeishuMessageEvent } from "./bot.js";
|
||||
@@ -47,6 +51,7 @@ export class FeishuRetryableCardActionError extends Error {
|
||||
|
||||
export function resetProcessedFeishuCardActionTokensForTests(): void {
|
||||
processedCardActionTokens.clear();
|
||||
resolvedChatTypeCache.clear();
|
||||
}
|
||||
|
||||
function pruneProcessedCardActionTokens(now: number): void {
|
||||
@@ -185,8 +190,14 @@ const CHAT_TYPE_CACHE_TTL_MS = 30 * 60_000;
|
||||
const CHAT_TYPE_CACHE_MAX_SIZE = 5_000;
|
||||
|
||||
function pruneChatTypeCache(now: number): void {
|
||||
const validNow = asDateTimestampMs(now);
|
||||
if (validNow === undefined) {
|
||||
resolvedChatTypeCache.clear();
|
||||
return;
|
||||
}
|
||||
for (const [key, entry] of resolvedChatTypeCache.entries()) {
|
||||
if (entry.expiresAt <= now) {
|
||||
const expiresAt = asDateTimestampMs(entry.expiresAt);
|
||||
if (expiresAt === undefined || expiresAt <= validNow) {
|
||||
resolvedChatTypeCache.delete(key);
|
||||
}
|
||||
}
|
||||
@@ -206,6 +217,18 @@ function sanitizeLogValue(v: string): string {
|
||||
return v.replace(/[\r\n]/g, " ").slice(0, 500);
|
||||
}
|
||||
|
||||
function cacheResolvedCardActionChatType(
|
||||
cacheKey: string,
|
||||
value: "p2p" | "group",
|
||||
now: number,
|
||||
): void {
|
||||
const expiresAt = resolveExpiresAtMsFromDurationMs(CHAT_TYPE_CACHE_TTL_MS, { nowMs: now });
|
||||
resolvedChatTypeCache.delete(cacheKey);
|
||||
if (expiresAt !== undefined) {
|
||||
resolvedChatTypeCache.set(cacheKey, { value, expiresAt });
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveCardActionChatType(params: {
|
||||
event: FeishuCardActionEvent;
|
||||
account: ReturnType<typeof resolveFeishuRuntimeAccount>;
|
||||
@@ -226,9 +249,13 @@ async function resolveCardActionChatType(params: {
|
||||
const now = Date.now();
|
||||
pruneChatTypeCache(now);
|
||||
const cached = resolvedChatTypeCache.get(cacheKey);
|
||||
if (cached) {
|
||||
const cachedExpiresAt = cached ? asDateTimestampMs(cached.expiresAt) : undefined;
|
||||
if (cached && cachedExpiresAt !== undefined) {
|
||||
return cached.value;
|
||||
}
|
||||
if (cached) {
|
||||
resolvedChatTypeCache.delete(cacheKey);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = (await createFeishuClient(params.account).im.chat.get({
|
||||
@@ -239,10 +266,7 @@ async function resolveCardActionChatType(params: {
|
||||
normalizeResolvedCardActionChatType(response.data?.chat_mode) ??
|
||||
normalizeResolvedCardActionChatType(response.data?.chat_type);
|
||||
if (resolvedChatType) {
|
||||
resolvedChatTypeCache.set(cacheKey, {
|
||||
value: resolvedChatType,
|
||||
expiresAt: now + CHAT_TYPE_CACHE_TTL_MS,
|
||||
});
|
||||
cacheResolvedCardActionChatType(cacheKey, resolvedChatType, now);
|
||||
return resolvedChatType;
|
||||
}
|
||||
params.log(
|
||||
|
||||
Reference in New Issue
Block a user