UNPKG

@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.

225 lines 7.69 kB
/** * @module Lock */ import {} from "../../../../event-bus/contracts/_module.js"; import {} from "../../../../execution-context/contracts/_module.js"; import { FailedAcquireLockError, LOCK_EVENTS, FailedReleaseLockError, FailedRefreshLockError, LOCK_STATE, } from "../../../../lock/contracts/_module.js"; import { handleDispatch, handleUnexpectedError, } from "../../../../lock/implementations/derivables/lock-factory/event-helpers.js"; import {} from "../../../../middleware/contracts/_module.js"; import {} from "../../../../namespace/contracts/_module.js"; import {} from "../../../../time-span/contracts/_module.js"; import { TimeSpan } from "../../../../time-span/implementations/_module.js"; import { callInvokable, resolveLazyable, } from "../../../../utilities/_module.js"; /** * @internal */ export class Lock { /** * @internal */ static _serialize(deserializedValue) { return { version: "1", key: deserializedValue._key.get(), lockId: deserializedValue.lockId, ttlInMs: deserializedValue._ttl?.toMilliseconds() ?? null, }; } namespace; adapter; originalAdapter; eventDispatcher; _key; lockId; _ttl; defaultRefreshTime; serdeTransformerName; waitUntil; executionContext; use; constructor(settings) { const { namespace, adapter, originalAdapter, eventDispatcher, key, lockId, ttl, serdeTransformerName, defaultRefreshTime, waitUntil, executionContext, use, } = settings; this.use = use; this.executionContext = executionContext; this.waitUntil = waitUntil; this.namespace = namespace; this.originalAdapter = originalAdapter; this.serdeTransformerName = serdeTransformerName; this.adapter = adapter; this.eventDispatcher = eventDispatcher; this._key = key; this.lockId = lockId; this._ttl = ttl; this.defaultRefreshTime = defaultRefreshTime; } _getNamespace() { return this.namespace; } _getSerdeTransformerName() { return this.serdeTransformerName; } _getAdapter() { return this.originalAdapter; } async runOrFail(asyncFn) { await this.acquireOrFail(); try { return await resolveLazyable(asyncFn); } finally { await this.release(); } } async acquire() { return this.use(async () => { return await this.adapter.acquire(this.executionContext, this._key.toString(), this.lockId, this._ttl); }, [ handleUnexpectedError(this.waitUntil, this.eventDispatcher, this), handleDispatch({ on: "true", eventName: LOCK_EVENTS.ACQUIRED, eventData: { lock: this, }, waitUntil: this.waitUntil, eventDispatcher: this.eventDispatcher, }), handleDispatch({ on: "false", eventName: LOCK_EVENTS.UNAVAILABLE, eventData: { lock: this, }, waitUntil: this.waitUntil, eventDispatcher: this.eventDispatcher, }), ])(); } async acquireOrFail() { const hasAquired = await this.acquire(); if (!hasAquired) { throw FailedAcquireLockError.create(this._key); } } async release() { return this.use(async () => { return await this.adapter.release(this.executionContext, this._key.toString(), this.lockId); }, [ handleUnexpectedError(this.waitUntil, this.eventDispatcher, this), handleDispatch({ on: "true", eventName: LOCK_EVENTS.RELEASED, eventData: { lock: this, }, waitUntil: this.waitUntil, eventDispatcher: this.eventDispatcher, }), handleDispatch({ on: "false", eventName: LOCK_EVENTS.FAILED_RELEASE, eventData: { lock: this, }, waitUntil: this.waitUntil, eventDispatcher: this.eventDispatcher, }), ])(); } async releaseOrFail() { const hasRelased = await this.release(); if (!hasRelased) { throw FailedReleaseLockError.create(this._key, this.lockId); } } async forceRelease() { return this.use(async () => { return await this.adapter.forceRelease(this.executionContext, this._key.toString()); }, [ handleUnexpectedError(this.waitUntil, this.eventDispatcher, this), async ({ next }) => { const hasReleased = await next(); callInvokable(this.waitUntil, this.eventDispatcher.dispatch(LOCK_EVENTS.FORCE_RELEASED, { lock: this, hasReleased, })); return hasReleased; }, ])(); } async refresh(ttl = this.defaultRefreshTime) { return this.use(async () => { return await this.adapter.refresh(this.executionContext, this._key.toString(), this.lockId, TimeSpan.fromTimeSpan(ttl)); }, [ handleUnexpectedError(this.waitUntil, this.eventDispatcher, this), handleDispatch({ on: "true", eventName: LOCK_EVENTS.REFRESHED, eventData: { lock: this, }, waitUntil: this.waitUntil, eventDispatcher: this.eventDispatcher, }), handleDispatch({ on: "false", eventName: LOCK_EVENTS.FAILED_REFRESH, eventData: { lock: this, }, waitUntil: this.waitUntil, eventDispatcher: this.eventDispatcher, }), async ({ next }) => { const hasRefreshed = await next(); if (hasRefreshed) { this._ttl = TimeSpan.fromTimeSpan(ttl); } return hasRefreshed; }, ])(); } async refreshOrFail(ttl) { const hasRefreshed = await this.refresh(ttl); if (!hasRefreshed) { throw FailedRefreshLockError.create(this._key, this.lockId); } } get key() { return this._key; } get id() { return this.lockId; } get ttl() { return this._ttl; } async getState() { return this.use(async () => { const state = await this.adapter.getState(this.executionContext, this._key.toString()); if (state === null) { return { type: LOCK_STATE.EXPIRED, }; } if (state.owner === this.lockId) { return { type: LOCK_STATE.ACQUIRED, remainingTime: state.expiration === null ? null : TimeSpan.fromDateRange({ start: new Date(), end: state.expiration, }), }; } return { type: LOCK_STATE.UNAVAILABLE, owner: state.owner, }; }, [ handleUnexpectedError(this.waitUntil, this.eventDispatcher, this), ])(); } } //# sourceMappingURL=lock.js.map