Files
MoonTVPlus/src/lib/lock.ts

97 lines
2.4 KiB
TypeScript
Raw Normal View History

2025-12-24 00:55:37 +08:00
/* eslint-disable @typescript-eslint/no-explicit-any */
// 简单的内存锁管理器
class LockManager {
private locks: Map<string, { locked: boolean; queue: Array<() => void> }> = new Map();
private readonly LOCK_TIMEOUT = 10000; // 10秒超时
async acquire(key: string): Promise<() => void> {
// 获取或创建锁对象
if (!this.locks.has(key)) {
this.locks.set(key, { locked: false, queue: [] });
}
const lock = this.locks.get(key)!;
// 如果锁未被占用,立即获取
if (!lock.locked) {
lock.locked = true;
// 设置超时自动释放
const timeoutId = setTimeout(() => {
this.release(key);
}, this.LOCK_TIMEOUT);
// 返回释放函数
return () => {
clearTimeout(timeoutId);
this.release(key);
};
}
// 如果锁已被占用,等待
return new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
// 超时,从队列中移除
const index = lock.queue.indexOf(callback);
if (index > -1) {
lock.queue.splice(index, 1);
}
reject(new Error('获取锁超时'));
}, this.LOCK_TIMEOUT);
const callback = () => {
clearTimeout(timeoutId);
lock.locked = true;
// 设置超时自动释放
const lockTimeoutId = setTimeout(() => {
this.release(key);
}, this.LOCK_TIMEOUT);
resolve(() => {
clearTimeout(lockTimeoutId);
this.release(key);
});
};
lock.queue.push(callback);
});
}
private release(key: string): void {
const lock = this.locks.get(key);
if (!lock) return;
// 如果队列中有等待者,唤醒下一个
if (lock.queue.length > 0) {
const next = lock.queue.shift();
if (next) {
next();
}
} else {
// 没有等待者,释放锁
lock.locked = false;
// 清理空的锁对象
this.locks.delete(key);
}
}
// 清理所有锁(用于测试或重置)
clear(): void {
this.locks.clear();
}
}
// 全局单例
const globalKey = Symbol.for('__MOONTV_LOCK_MANAGER__');
2025-12-24 23:19:06 +08:00
let _lockManager: LockManager | undefined = (global as any)[globalKey];
2025-12-24 00:55:37 +08:00
2025-12-24 23:19:06 +08:00
if (!_lockManager) {
_lockManager = new LockManager();
(global as any)[globalKey] = _lockManager;
2025-12-24 00:55:37 +08:00
}
2025-12-24 23:19:06 +08:00
// TypeScript doesn't recognize that lockManager is always defined after the if block
export const lockManager = _lockManager as LockManager;