mirror of
https://github.com/hansjone/dsh-im-ops.git
synced 2026-10-10 23:10:46 +08:00
40 lines
1.2 KiB
JavaScript
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);
|
|
}
|
|
}
|
|
}
|