mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-06 05:51:15 +08:00
fix(infra): centralize non-finite numeric option bounds
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { resolveGlobalSingleton } from "../shared/global-singleton.js";
|
||||
import { pruneMapToMaxSize } from "./map-size.js";
|
||||
import { resolveNonNegativeIntegerOption } from "./numeric-options.js";
|
||||
|
||||
export type DedupeCache = {
|
||||
check: (key: string | undefined | null, now?: number) => boolean;
|
||||
@@ -14,13 +15,12 @@ export type DedupeCacheOptions = {
|
||||
maxSize: number;
|
||||
};
|
||||
|
||||
export function resolveDedupeNonNegativeInteger(value: number, fallback: number): number {
|
||||
return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : fallback;
|
||||
}
|
||||
/** @deprecated Use resolveNonNegativeIntegerOption for new internal numeric option normalization. */
|
||||
export { resolveNonNegativeIntegerOption as resolveDedupeNonNegativeInteger };
|
||||
|
||||
export function createDedupeCache(options: DedupeCacheOptions): DedupeCache {
|
||||
const ttlMs = resolveDedupeNonNegativeInteger(options.ttlMs, 0);
|
||||
const maxSize = resolveDedupeNonNegativeInteger(options.maxSize, 0);
|
||||
const ttlMs = resolveNonNegativeIntegerOption(options.ttlMs, 0);
|
||||
const maxSize = resolveNonNegativeIntegerOption(options.maxSize, 0);
|
||||
const cache = new Map<string, number>();
|
||||
|
||||
const touch = (key: string, now: number) => {
|
||||
|
||||
3
src/infra/numeric-options.ts
Normal file
3
src/infra/numeric-options.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export function resolveNonNegativeIntegerOption(value: number, fallback: number): number {
|
||||
return Number.isFinite(value) ? Math.max(0, Math.floor(value)) : fallback;
|
||||
}
|
||||
@@ -69,4 +69,16 @@ describe("DirectoryCache", () => {
|
||||
cache.clear(cfg);
|
||||
expect(cache.get("a", cfg)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("uses the default max size when maxSize is non-finite", () => {
|
||||
const cache = new DirectoryCache<number>(60_000, Number.NaN);
|
||||
const cfg = {} as OpenClawConfig;
|
||||
|
||||
for (let i = 0; i <= 2000; i++) {
|
||||
cache.set(`key-${i}`, i, cfg);
|
||||
}
|
||||
|
||||
expect(cache.get("key-0", cfg)).toBeUndefined();
|
||||
expect(cache.get("key-2000", cfg)).toBe(2000);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { ChannelDirectoryEntryKind, ChannelId } from "../../channels/plugins/types.public.js";
|
||||
import type { OpenClawConfig } from "../../config/types.openclaw.js";
|
||||
import { resolveNonNegativeIntegerOption } from "../numeric-options.js";
|
||||
|
||||
type CacheEntry<T> = {
|
||||
value: T;
|
||||
@@ -22,13 +23,12 @@ export function buildDirectoryCacheKey(key: DirectoryCacheKey): string {
|
||||
export class DirectoryCache<T> {
|
||||
private readonly cache = new Map<string, CacheEntry<T>>();
|
||||
private lastConfigRef: OpenClawConfig | null = null;
|
||||
private readonly ttlMs: number;
|
||||
private readonly maxSize: number;
|
||||
|
||||
constructor(
|
||||
private readonly ttlMs: number,
|
||||
maxSize = 2000,
|
||||
) {
|
||||
this.maxSize = Math.max(1, Math.floor(maxSize));
|
||||
constructor(ttlMs: number, maxSize = 2000) {
|
||||
this.ttlMs = resolveNonNegativeIntegerOption(ttlMs, 0);
|
||||
this.maxSize = Math.max(1, resolveNonNegativeIntegerOption(maxSize, 2000));
|
||||
}
|
||||
|
||||
get(key: string, cfg: OpenClawConfig): T | undefined {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createDedupeCache, resolveDedupeNonNegativeInteger } from "../infra/dedupe.js";
|
||||
import { createDedupeCache } from "../infra/dedupe.js";
|
||||
import { resolveNonNegativeIntegerOption } from "../infra/numeric-options.js";
|
||||
import type { FileLockOptions } from "./file-lock.js";
|
||||
import { withFileLock } from "./file-lock.js";
|
||||
import { readJsonFileWithFallback, writeJsonFileAtomically } from "./json-store.js";
|
||||
@@ -148,9 +149,9 @@ function isRecentTimestamp(seenAt: number | undefined, ttlMs: number, now: numbe
|
||||
|
||||
/** Create a dedupe helper that combines in-memory fast checks with a lock-protected disk store. */
|
||||
export function createPersistentDedupe(options: PersistentDedupeOptions): PersistentDedupe {
|
||||
const ttlMs = resolveDedupeNonNegativeInteger(options.ttlMs, 0);
|
||||
const memoryMaxSize = resolveDedupeNonNegativeInteger(options.memoryMaxSize, 0);
|
||||
const fileMaxEntries = Math.max(1, resolveDedupeNonNegativeInteger(options.fileMaxEntries, 1));
|
||||
const ttlMs = resolveNonNegativeIntegerOption(options.ttlMs, 0);
|
||||
const memoryMaxSize = resolveNonNegativeIntegerOption(options.memoryMaxSize, 0);
|
||||
const fileMaxEntries = Math.max(1, resolveNonNegativeIntegerOption(options.fileMaxEntries, 1));
|
||||
const lockOptions = mergeLockOptions(options.lockOptions);
|
||||
const memory = createDedupeCache({ ttlMs, maxSize: memoryMaxSize });
|
||||
const inflight = new Map<string, Promise<boolean>>();
|
||||
@@ -324,15 +325,15 @@ function createReleasedClaimError(scopedKey: string): Error {
|
||||
|
||||
/** Create a claim/commit/release dedupe guard backed by memory and optional persistent storage. */
|
||||
export function createClaimableDedupe(options: ClaimableDedupeOptions): ClaimableDedupe {
|
||||
const ttlMs = resolveDedupeNonNegativeInteger(options.ttlMs, 0);
|
||||
const memoryMaxSize = resolveDedupeNonNegativeInteger(options.memoryMaxSize, 0);
|
||||
const ttlMs = resolveNonNegativeIntegerOption(options.ttlMs, 0);
|
||||
const memoryMaxSize = resolveNonNegativeIntegerOption(options.memoryMaxSize, 0);
|
||||
const memory = createDedupeCache({ ttlMs, maxSize: memoryMaxSize });
|
||||
const persistent =
|
||||
options.resolveFilePath != null
|
||||
? createPersistentDedupe({
|
||||
ttlMs,
|
||||
memoryMaxSize,
|
||||
fileMaxEntries: Math.max(1, resolveDedupeNonNegativeInteger(options.fileMaxEntries, 1)),
|
||||
fileMaxEntries: Math.max(1, resolveNonNegativeIntegerOption(options.fileMaxEntries, 1)),
|
||||
resolveFilePath: options.resolveFilePath,
|
||||
lockOptions: options.lockOptions,
|
||||
onDiskError: options.onDiskError,
|
||||
|
||||
Reference in New Issue
Block a user