@adpt/core
Version:
AdaptJS core library
134 lines • 4.49 kB
JavaScript
;
/*
* Copyright 2019 Unbounded Systems, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const async_lock_1 = tslib_1.__importDefault(require("async-lock"));
const p_defer_1 = tslib_1.__importDefault(require("p-defer"));
const error_1 = require("../error");
const server_1 = require("./server");
class NoLocker {
lock() {
return Promise.resolve({ [server_1.$serverLock]: true });
}
unlock(l) {
return Promise.resolve();
}
}
exports.NoLocker = NoLocker;
class ProcessLocker {
constructor() {
this.locks = new async_lock_1.default();
}
lock() {
return new Promise((resolve, reject) => {
const releaseComplete = p_defer_1.default();
this.locks.acquire("thelock", (releaseLock) => {
resolve({
release: async () => {
releaseLock();
return releaseComplete.promise;
},
[server_1.$serverLock]: true,
});
}, (err) => {
if (err) {
reject(err);
releaseComplete.reject(err);
}
else {
releaseComplete.resolve();
}
});
});
}
async unlock(lock) {
await lock.release();
}
}
exports.ProcessLocker = ProcessLocker;
class ServerBase {
constructor(worldLocker) {
this.processLocker = new ProcessLocker();
this.worldLocker = worldLocker || (new NoLocker());
}
async lock() {
let pLock;
try {
pLock = await this.processLocker.lock();
if (this.currentProcessLock) {
throw new error_1.InternalError(`AdaptServer: previous process lock not cleared`);
}
this.currentProcessLock = pLock;
this.currentWorldLock = await this.worldLocker.lock();
return pLock;
}
catch (err) {
if (pLock) {
if (pLock === this.currentProcessLock)
delete this.currentProcessLock;
await this.processLocker.unlock(pLock);
}
throw err;
}
}
async unlock(l) {
if (!this.assertLock(l, "unlock"))
throw new error_1.InternalError(`Bad lock`);
const wLock = this.currentWorldLock;
if (wLock) {
delete this.currentWorldLock;
await this.worldLocker.unlock(wLock);
}
delete this.currentProcessLock;
await this.processLocker.unlock(l);
}
async withLock(options, f) {
let release;
if (options.lock) {
// Requester thinks they already hold the lock. But do they?
this.assertLock(options.lock, "use");
// They do hold the lock. So don't unlock when this
// operation is complete; requester will call unlock later.
release = async () => { };
}
else {
// Get a temporary per-operation lock
const tempLock = await this.lock();
release = () => this.unlock(tempLock);
}
try {
return await f();
}
finally {
await release();
}
}
// Confirm that a lock is the current lock
assertLock(l, op) {
if (!this.currentProcessLock) {
throw new error_1.InternalError(`AdaptServer: Attempt to ${op} a stale lock. Server is not ` +
`currently locked.`);
}
if (l !== this.currentProcessLock) {
throw new error_1.InternalError(`AdaptServer: Attempt to ${op} a stale lock. Server is locked ` +
`by another user.`);
}
return true;
}
}
exports.ServerBase = ServerBase;
//# sourceMappingURL=server_base.js.map