mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-22 14:41:34 +00:00
37 lines
1.2 KiB
TypeScript
37 lines
1.2 KiB
TypeScript
import { AUTH_RATE_LIMIT_SCOPE_DEFAULT, normalizeRateLimitClientIp } from "./auth-rate-limit.js";
|
|
|
|
const pendingAttempts = new Map<string, Promise<void>>();
|
|
|
|
function normalizeScope(scope: string | undefined): string {
|
|
return (scope ?? AUTH_RATE_LIMIT_SCOPE_DEFAULT).trim() || AUTH_RATE_LIMIT_SCOPE_DEFAULT;
|
|
}
|
|
|
|
function buildSerializationKey(ip: string | undefined, scope: string | undefined): string {
|
|
return `${normalizeScope(scope)}:${normalizeRateLimitClientIp(ip)}`;
|
|
}
|
|
|
|
export async function withSerializedRateLimitAttempt<T>(params: {
|
|
ip: string | undefined;
|
|
scope: string | undefined;
|
|
run: () => Promise<T>;
|
|
}): Promise<T> {
|
|
const key = buildSerializationKey(params.ip, params.scope);
|
|
const previous = pendingAttempts.get(key) ?? Promise.resolve();
|
|
let releaseCurrent!: () => void;
|
|
const current = new Promise<void>((resolve) => {
|
|
releaseCurrent = resolve;
|
|
});
|
|
const tail = previous.catch(() => {}).then(() => current);
|
|
pendingAttempts.set(key, tail);
|
|
|
|
await previous.catch(() => {});
|
|
try {
|
|
return await params.run();
|
|
} finally {
|
|
releaseCurrent();
|
|
if (pendingAttempts.get(key) === tail) {
|
|
pendingAttempts.delete(key);
|
|
}
|
|
}
|
|
}
|