Initial commit

This commit is contained in:
2025-03-07 19:22:02 +01:00
commit 4a98255d83
55743 changed files with 5280367 additions and 0 deletions
+13
View File
@@ -0,0 +1,13 @@
import MutexInterface from './MutexInterface';
declare class Mutex implements MutexInterface {
constructor(cancelError?: Error);
acquire(): Promise<MutexInterface.Releaser>;
runExclusive<T>(callback: MutexInterface.Worker<T>): Promise<T>;
isLocked(): boolean;
waitForUnlock(): Promise<void>;
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */
release(): void;
cancel(): void;
private _semaphore;
}
export default Mutex;
+40
View File
@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var Semaphore_1 = require("./Semaphore");
var Mutex = /** @class */ (function () {
function Mutex(cancelError) {
this._semaphore = new Semaphore_1.default(1, cancelError);
}
Mutex.prototype.acquire = function () {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var _a, releaser;
return (0, tslib_1.__generator)(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this._semaphore.acquire()];
case 1:
_a = _b.sent(), releaser = _a[1];
return [2 /*return*/, releaser];
}
});
});
};
Mutex.prototype.runExclusive = function (callback) {
return this._semaphore.runExclusive(function () { return callback(); });
};
Mutex.prototype.isLocked = function () {
return this._semaphore.isLocked();
};
Mutex.prototype.waitForUnlock = function () {
return this._semaphore.waitForUnlock();
};
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */
Mutex.prototype.release = function () {
this._semaphore.release();
};
Mutex.prototype.cancel = function () {
return this._semaphore.cancel();
};
return Mutex;
}());
exports.default = Mutex;
+18
View File
@@ -0,0 +1,18 @@
interface MutexInterface {
acquire(): Promise<MutexInterface.Releaser>;
runExclusive<T>(callback: MutexInterface.Worker<T>): Promise<T>;
waitForUnlock(): Promise<void>;
isLocked(): boolean;
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */
release(): void;
cancel(): void;
}
declare namespace MutexInterface {
interface Releaser {
(): void;
}
interface Worker<T> {
(): Promise<T> | T;
}
}
export default MutexInterface;
+2
View File
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
+20
View File
@@ -0,0 +1,20 @@
import SemaphoreInterface from './SemaphoreInterface';
declare class Semaphore implements SemaphoreInterface {
private _maxConcurrency;
private _cancelError;
constructor(_maxConcurrency: number, _cancelError?: Error);
acquire(): Promise<[number, SemaphoreInterface.Releaser]>;
runExclusive<T>(callback: SemaphoreInterface.Worker<T>): Promise<T>;
waitForUnlock(): Promise<void>;
isLocked(): boolean;
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */
release(): void;
cancel(): void;
private _dispatch;
private _resolveWaiters;
private _queue;
private _waiters;
private _currentReleaser;
private _value;
}
export default Semaphore;
+102
View File
@@ -0,0 +1,102 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var errors_1 = require("./errors");
var Semaphore = /** @class */ (function () {
function Semaphore(_maxConcurrency, _cancelError) {
if (_cancelError === void 0) { _cancelError = errors_1.E_CANCELED; }
this._maxConcurrency = _maxConcurrency;
this._cancelError = _cancelError;
this._queue = [];
this._waiters = [];
if (_maxConcurrency <= 0) {
throw new Error('semaphore must be initialized to a positive value');
}
this._value = _maxConcurrency;
}
Semaphore.prototype.acquire = function () {
var _this = this;
var locked = this.isLocked();
var ticketPromise = new Promise(function (resolve, reject) {
return _this._queue.push({ resolve: resolve, reject: reject });
});
if (!locked)
this._dispatch();
return ticketPromise;
};
Semaphore.prototype.runExclusive = function (callback) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var _a, value, release;
return (0, tslib_1.__generator)(this, function (_b) {
switch (_b.label) {
case 0: return [4 /*yield*/, this.acquire()];
case 1:
_a = _b.sent(), value = _a[0], release = _a[1];
_b.label = 2;
case 2:
_b.trys.push([2, , 4, 5]);
return [4 /*yield*/, callback(value)];
case 3: return [2 /*return*/, _b.sent()];
case 4:
release();
return [7 /*endfinally*/];
case 5: return [2 /*return*/];
}
});
});
};
Semaphore.prototype.waitForUnlock = function () {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var waitPromise;
var _this = this;
return (0, tslib_1.__generator)(this, function (_a) {
if (!this.isLocked()) {
return [2 /*return*/, Promise.resolve()];
}
waitPromise = new Promise(function (resolve) { return _this._waiters.push({ resolve: resolve }); });
return [2 /*return*/, waitPromise];
});
});
};
Semaphore.prototype.isLocked = function () {
return this._value <= 0;
};
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */
Semaphore.prototype.release = function () {
if (this._maxConcurrency > 1) {
throw new Error('this method is unavailable on semaphores with concurrency > 1; use the scoped release returned by acquire instead');
}
if (this._currentReleaser) {
var releaser = this._currentReleaser;
this._currentReleaser = undefined;
releaser();
}
};
Semaphore.prototype.cancel = function () {
var _this = this;
this._queue.forEach(function (ticket) { return ticket.reject(_this._cancelError); });
this._queue = [];
};
Semaphore.prototype._dispatch = function () {
var _this = this;
var nextTicket = this._queue.shift();
if (!nextTicket)
return;
var released = false;
this._currentReleaser = function () {
if (released)
return;
released = true;
_this._value++;
_this._resolveWaiters();
_this._dispatch();
};
nextTicket.resolve([this._value--, this._currentReleaser]);
};
Semaphore.prototype._resolveWaiters = function () {
this._waiters.forEach(function (waiter) { return waiter.resolve(); });
this._waiters = [];
};
return Semaphore;
}());
exports.default = Semaphore;
+18
View File
@@ -0,0 +1,18 @@
interface SemaphoreInterface {
acquire(): Promise<[number, SemaphoreInterface.Releaser]>;
runExclusive<T>(callback: SemaphoreInterface.Worker<T>): Promise<T>;
waitForUnlock(): Promise<void>;
isLocked(): boolean;
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */
release(): void;
cancel(): void;
}
declare namespace SemaphoreInterface {
interface Releaser {
(): void;
}
interface Worker<T> {
(value: number): Promise<T> | T;
}
}
export default SemaphoreInterface;
+2
View File
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
+3
View File
@@ -0,0 +1,3 @@
export declare const E_TIMEOUT: Error;
export declare const E_ALREADY_LOCKED: Error;
export declare const E_CANCELED: Error;
+6
View File
@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.E_CANCELED = exports.E_ALREADY_LOCKED = exports.E_TIMEOUT = void 0;
exports.E_TIMEOUT = new Error('timeout while waiting for mutex to become available');
exports.E_ALREADY_LOCKED = new Error('mutex already locked');
exports.E_CANCELED = new Error('request for lock canceled');
+7
View File
@@ -0,0 +1,7 @@
export { default as Mutex } from './Mutex';
export { default as MutexInterface } from './MutexInterface';
export { default as Semaphore } from './Semaphore';
export { default as SemaphoreInterface } from './SemaphoreInterface';
export { withTimeout } from './withTimeout';
export { tryAcquire } from './tryAcquire';
export * from './errors';
+13
View File
@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.tryAcquire = exports.withTimeout = exports.Semaphore = exports.Mutex = void 0;
var tslib_1 = require("tslib");
var Mutex_1 = require("./Mutex");
Object.defineProperty(exports, "Mutex", { enumerable: true, get: function () { return Mutex_1.default; } });
var Semaphore_1 = require("./Semaphore");
Object.defineProperty(exports, "Semaphore", { enumerable: true, get: function () { return Semaphore_1.default; } });
var withTimeout_1 = require("./withTimeout");
Object.defineProperty(exports, "withTimeout", { enumerable: true, get: function () { return withTimeout_1.withTimeout; } });
var tryAcquire_1 = require("./tryAcquire");
Object.defineProperty(exports, "tryAcquire", { enumerable: true, get: function () { return tryAcquire_1.tryAcquire; } });
(0, tslib_1.__exportStar)(require("./errors"), exports);
+4
View File
@@ -0,0 +1,4 @@
import MutexInterface from './MutexInterface';
import SemaphoreInterface from './SemaphoreInterface';
export declare function tryAcquire(mutex: MutexInterface, alreadyAcquiredError?: Error): MutexInterface;
export declare function tryAcquire(semaphore: SemaphoreInterface, alreadyAcquiredError?: Error): SemaphoreInterface;
+12
View File
@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.tryAcquire = void 0;
var errors_1 = require("./errors");
var withTimeout_1 = require("./withTimeout");
// eslint-disable-next-lisne @typescript-eslint/explicit-module-boundary-types
function tryAcquire(sync, alreadyAcquiredError) {
if (alreadyAcquiredError === void 0) { alreadyAcquiredError = errors_1.E_ALREADY_LOCKED; }
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (0, withTimeout_1.withTimeout)(sync, 0, alreadyAcquiredError);
}
exports.tryAcquire = tryAcquire;
+4
View File
@@ -0,0 +1,4 @@
import MutexInterface from './MutexInterface';
import SemaphoreInterface from './SemaphoreInterface';
export declare function withTimeout(mutex: MutexInterface, timeout: number, timeoutError?: Error): MutexInterface;
export declare function withTimeout(semaphore: SemaphoreInterface, timeout: number, timeoutError?: Error): SemaphoreInterface;
+90
View File
@@ -0,0 +1,90 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.withTimeout = void 0;
var tslib_1 = require("tslib");
var errors_1 = require("./errors");
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
function withTimeout(sync, timeout, timeoutError) {
var _this = this;
if (timeoutError === void 0) { timeoutError = errors_1.E_TIMEOUT; }
return {
acquire: function () {
return new Promise(function (resolve, reject) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () {
var isTimeout, handle, ticket, release, e_1;
return (0, tslib_1.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
isTimeout = false;
handle = setTimeout(function () {
isTimeout = true;
reject(timeoutError);
}, timeout);
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, sync.acquire()];
case 2:
ticket = _a.sent();
if (isTimeout) {
release = Array.isArray(ticket) ? ticket[1] : ticket;
release();
}
else {
clearTimeout(handle);
resolve(ticket);
}
return [3 /*break*/, 4];
case 3:
e_1 = _a.sent();
if (!isTimeout) {
clearTimeout(handle);
reject(e_1);
}
return [3 /*break*/, 4];
case 4: return [2 /*return*/];
}
});
}); });
},
runExclusive: function (callback) {
return (0, tslib_1.__awaiter)(this, void 0, void 0, function () {
var release, ticket;
return (0, tslib_1.__generator)(this, function (_a) {
switch (_a.label) {
case 0:
release = function () { return undefined; };
_a.label = 1;
case 1:
_a.trys.push([1, , 7, 8]);
return [4 /*yield*/, this.acquire()];
case 2:
ticket = _a.sent();
if (!Array.isArray(ticket)) return [3 /*break*/, 4];
release = ticket[1];
return [4 /*yield*/, callback(ticket[0])];
case 3: return [2 /*return*/, _a.sent()];
case 4:
release = ticket;
return [4 /*yield*/, callback()];
case 5: return [2 /*return*/, _a.sent()];
case 6: return [3 /*break*/, 8];
case 7:
release();
return [7 /*endfinally*/];
case 8: return [2 /*return*/];
}
});
});
},
/** @deprecated Deprecated in 0.3.0, will be removed in 0.4.0. Use runExclusive instead. */
release: function () {
sync.release();
},
cancel: function () {
return sync.cancel();
},
waitForUnlock: function () { return sync.waitForUnlock(); },
isLocked: function () { return sync.isLocked(); },
};
}
exports.withTimeout = withTimeout;