dsh-im-ops/src/channels/shared/session-binding-lock.mjs
2026-08-20 01:28:51 +08:00

40 lines
1.2 KiB
JavaScript

const bindingLocks = new WeakMap();
function stateLocks(state) {
let locks = bindingLocks.get(state);
if (!locks) {
locks = new Map();
bindingLocks.set(state, locks);
}
return locks;
}
/**
* Serialize the short Session binding transaction for one conversation.
* The caller must keep long-running Session work, such as ask(), outside.
*/
export async function withSessionBindingLock(state, key, operation) {
const stateType = typeof state;
if ((stateType !== 'object' && stateType !== 'function') || state === null) {
throw new TypeError('state is required');
}
if (typeof key !== 'string' || !key) throw new TypeError('conversation key is required');
if (typeof operation !== 'function') throw new TypeError('operation is required');
const locks = stateLocks(state);
const previous = locks.get(key) ?? Promise.resolve();
let release;
const current = new Promise((resolve) => { release = resolve; });
locks.set(key, current);
await previous;
try {
return await operation();
} finally {
release();
if (locks.get(key) === current) {
locks.delete(key);
if (locks.size === 0) bindingLocks.delete(state);
}
}
}