@daiso-tech/core
Version:
The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.
152 lines • 4.79 kB
JavaScript
/**
* @module Lock
*/
import {} from "../../../../execution-context/contracts/_module.js";
import {} from "../../../../lock/contracts/_module.js";
import {} from "../../../../time-span/implementations/_module.js";
import {} from "../../../../utilities/_module.js";
/**
* Note the `MemoryLockAdapter` is limited to single process usage and cannot be shared across multiple servers or different processes.
* This adapter is meant for easily faking{@link ILockFactory | `ILockFactory`} for testing.
*
* IMPORT_PATH: `"@daiso-tech/core/lock/memory-lock-adapter"`
* @group Adapters
*/
export class MemoryLockAdapter {
map;
/**
* @example
* ```ts
* import { MemoryLockAdapter } from "@daiso-tech/core/lock/memory-lock-adapter";
*
* const lockAdapter = new MemoryLockAdapter();
* ```
* You can also provide an `Map`.
* @example
* ```ts
* import { MemoryLockAdapter } from "@daiso-tech/core/lock/memory-lock-adapter";
*
* const map = new Map<any, any>();
* const lockAdapter = new MemoryLockAdapter(map);
* ```
*/
constructor(map = new Map()) {
this.map = map;
}
/**
* Removes all in-memory lock data.
*/
async deInit() {
for (const [key, lockData] of this.map) {
if (lockData.hasExpiration) {
clearTimeout(lockData.timeoutId);
}
this.map.delete(key);
}
return Promise.resolve();
}
async acquire(_context, key, lockId, ttl) {
let lock = this.map.get(key);
if (lock !== undefined) {
return Promise.resolve(lock.owner === lockId);
}
if (ttl === null) {
lock = {
owner: lockId,
hasExpiration: false,
};
this.map.set(key, lock);
}
else {
const timeoutId = setTimeout(() => {
this.map.delete(key);
}, ttl.toMilliseconds());
lock = {
owner: lockId,
hasExpiration: true,
timeoutId,
expiration: ttl.toEndDate(),
};
this.map.set(key, lock);
}
return Promise.resolve(true);
}
async release(_context, key, lockId) {
const lock = this.map.get(key);
if (lock === undefined) {
return Promise.resolve(false);
}
if (lock.owner !== lockId) {
return Promise.resolve(false);
}
// Check expiration: if expired, cannot release
if (lock.hasExpiration && lock.expiration <= new Date()) {
return Promise.resolve(false);
}
if (lock.hasExpiration) {
clearTimeout(lock.timeoutId);
}
this.map.delete(key);
return Promise.resolve(true);
}
async forceRelease(_context, key) {
const lock = this.map.get(key);
if (lock === undefined) {
return Promise.resolve(false);
}
// Check expiration: if expired, cannot force release
if (lock.hasExpiration && lock.expiration <= new Date()) {
return Promise.resolve(false);
}
if (lock.hasExpiration) {
clearTimeout(lock.timeoutId);
}
this.map.delete(key);
return Promise.resolve(true);
}
async refresh(_context, key, lockId, ttl) {
const lock = this.map.get(key);
if (lock === undefined) {
return Promise.resolve(false);
}
if (lock.owner !== lockId) {
return Promise.resolve(false);
}
// Check expiration: if expired, cannot refresh
if (lock.hasExpiration && lock.expiration <= new Date()) {
return Promise.resolve(false);
}
if (!lock.hasExpiration) {
return Promise.resolve(false);
}
clearTimeout(lock.timeoutId);
const timeoutId = setTimeout(() => {
this.map.delete(key);
}, ttl.toMilliseconds());
this.map.set(key, {
...lock,
timeoutId,
});
return Promise.resolve(true);
}
async getState(_context, key) {
const lockData = this.map.get(key);
if (lockData === undefined) {
return Promise.resolve(null);
}
if (!lockData.hasExpiration) {
return Promise.resolve({
owner: lockData.owner,
expiration: null,
});
}
if (lockData.expiration <= new Date()) {
return Promise.resolve(null);
}
return Promise.resolve({
owner: lockData.owner,
expiration: lockData.expiration,
});
}
}
//# sourceMappingURL=memory-lock-adapter.js.map