mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-03 21:14:04 +00:00
fix(qqbot): bound upload cache expiry
This commit is contained in:
34
extensions/qqbot/src/engine/utils/upload-cache.test.ts
Normal file
34
extensions/qqbot/src/engine/utils/upload-cache.test.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { computeFileHash, getCachedFileInfo, setCachedFileInfo } from "./upload-cache.js";
|
||||
|
||||
describe("qqbot upload-cache", () => {
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("reuses cached file info before expiry", () => {
|
||||
const hash = computeFileHash("qqbot-cache-hit");
|
||||
|
||||
setCachedFileInfo(hash, "group", "target-hit", 1, "file-info-hit", "uuid-hit", 3600);
|
||||
|
||||
expect(getCachedFileInfo(hash, "group", "target-hit", 1)).toBe("file-info-hit");
|
||||
});
|
||||
|
||||
it("drops cached file info when the current clock is invalid", () => {
|
||||
const hash = computeFileHash("qqbot-invalid-clock");
|
||||
setCachedFileInfo(hash, "group", "target-invalid-clock", 1, "file-info-invalid", "uuid", 3600);
|
||||
vi.spyOn(Date, "now").mockReturnValue(Number.NaN);
|
||||
|
||||
expect(getCachedFileInfo(hash, "group", "target-invalid-clock", 1)).toBeNull();
|
||||
});
|
||||
|
||||
it("does not cache file info when ttl expiry exceeds the Date range", () => {
|
||||
vi.spyOn(Date, "now").mockReturnValue(8_640_000_000_000_000);
|
||||
const hash = computeFileHash("qqbot-overflow");
|
||||
|
||||
setCachedFileInfo(hash, "group", "target-overflow", 1, "file-info-overflow", "uuid", 3600);
|
||||
|
||||
expect(getCachedFileInfo(hash, "group", "target-overflow", 1)).toBeNull();
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,10 @@
|
||||
*/
|
||||
|
||||
import * as crypto from "node:crypto";
|
||||
import {
|
||||
isFutureDateTimestampMs,
|
||||
resolveExpiresAtMsFromDurationSeconds,
|
||||
} from "openclaw/plugin-sdk/number-runtime";
|
||||
import type { ChatScope } from "../types.js";
|
||||
import { debugLog } from "./log.js";
|
||||
|
||||
@@ -46,7 +50,7 @@ export function getCachedFileInfo(
|
||||
return null;
|
||||
}
|
||||
|
||||
if (Date.now() >= entry.expiresAt) {
|
||||
if (!isFutureDateTimestampMs(entry.expiresAt)) {
|
||||
cache.delete(key);
|
||||
return null;
|
||||
}
|
||||
@@ -68,7 +72,7 @@ export function setCachedFileInfo(
|
||||
if (cache.size >= MAX_CACHE_SIZE) {
|
||||
const now = Date.now();
|
||||
for (const [k, v] of cache) {
|
||||
if (now >= v.expiresAt) {
|
||||
if (!isFutureDateTimestampMs(v.expiresAt, { nowMs: now })) {
|
||||
cache.delete(k);
|
||||
}
|
||||
}
|
||||
@@ -83,11 +87,16 @@ export function setCachedFileInfo(
|
||||
const key = buildCacheKey(contentHash, scope, targetId, fileType);
|
||||
const safetyMargin = 60;
|
||||
const effectiveTtl = Math.max(ttl - safetyMargin, 10);
|
||||
const expiresAt = resolveExpiresAtMsFromDurationSeconds(effectiveTtl);
|
||||
if (expiresAt === undefined) {
|
||||
cache.delete(key);
|
||||
return;
|
||||
}
|
||||
|
||||
cache.set(key, {
|
||||
fileInfo,
|
||||
fileUuid,
|
||||
expiresAt: Date.now() + effectiveTtl * 1000,
|
||||
expiresAt,
|
||||
});
|
||||
|
||||
debugLog(
|
||||
|
||||
Reference in New Issue
Block a user