@adpt/core
Version:
AdaptJS core library
153 lines • 5.33 kB
JavaScript
"use strict";
/*
* Copyright 2018-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 utils_1 = require("@adpt/utils");
const fs = tslib_1.__importStar(require("fs-extra"));
const node_json_db_1 = tslib_1.__importDefault(require("node-json-db"));
const path = tslib_1.__importStar(require("path"));
const lockfile_1 = require("../utils/lockfile");
const local_history_1 = require("./local_history");
const server_1 = require("./server");
const server_base_1 = require("./server_base");
class FileLocker {
constructor(filename) {
this.filename = filename;
}
async lock() {
return {
release: await lockfile_1.lock(this.filename),
[server_1.$serverLock]: true,
};
}
async unlock(l) {
await l.release();
}
}
exports.FileLocker = FileLocker;
// Exported for testing only
exports.dbFilename = "adapt_local.json";
const defaultOptions = {
init: false,
};
const currentVersion = 0;
const openDbs = new Map();
class LocalServer extends server_base_1.ServerBase {
constructor(url, options) {
const rootDir = path.resolve(url.pathname);
const filename = path.join(rootDir, exports.dbFilename);
super(new FileLocker(filename));
this.rootDir = rootDir;
this.filename = filename;
this.historyStores = new Map();
this.options = Object.assign({}, defaultOptions, options);
}
async init() {
const alreadyOpen = openDbs.get(this.filename);
if (alreadyOpen !== undefined) {
this.db = alreadyOpen;
return;
}
let rootStat;
try {
rootStat = await fs.stat(this.rootDir);
}
catch (err) {
if (err.code !== "ENOENT")
throw err;
// fall through
}
if (rootStat && !rootStat.isDirectory()) {
throw new Error(`Local server: ${this.rootDir} is not a directory`);
}
if (this.options.init === true && rootStat === undefined) {
await fs.ensureDir(this.rootDir);
}
const exists = await fs.pathExists(this.filename);
if (exists === false && this.options.init === false) {
throw new Error(`Adapt local server file '${this.filename}' does not exist`);
}
// Creates file if none exists. Params are:
// saveOnPush: true
// humanReadable: true
this.db = new node_json_db_1.default(this.filename, true, true);
if (exists) {
let ver = null;
try {
ver = this.db.getData("/adaptLocalServerVersion");
}
catch (err) {
// fall through
}
if (ver !== currentVersion) {
throw new Error(`File '${this.filename}' is not a valid Adapt local server file`);
}
}
else {
this.db.push("/adaptLocalServerVersion", currentVersion);
}
openDbs.set(this.filename, this.db);
}
async destroy() {
const promises = utils_1.mapMap(this.historyStores, (_, s) => s.destroy());
await Promise.all(promises);
}
async set(dataPath, val, options = {}) {
await this.withLock(options, async () => {
this.db.reload();
if (options.mustCreate) {
try {
this.db.getData(dataPath);
throw new server_1.ServerPathExists(dataPath);
}
catch (err) {
if (err.name !== "DataError")
throw err;
}
}
this.db.push(dataPath, val);
});
}
async get(dataPath, options = {}) {
return this.withLock(options, () => {
this.db.reload();
return this.db.getData(dataPath);
});
}
async delete(dataPath, options = {}) {
await this.withLock(options, async () => {
this.db.reload();
this.db.delete(dataPath);
});
}
async historyStore(dataPath, init) {
let store = this.historyStores.get(dataPath);
if (store)
return store;
store = await local_history_1.createLocalHistoryStore(this.db, dataPath, path.join(this.rootDir, dataPath), init);
const origDestroy = store.destroy;
store.destroy = async () => {
this.historyStores.delete(dataPath);
await origDestroy.call(store);
};
this.historyStores.set(dataPath, store);
return store;
}
}
LocalServer.urlMatch = /^file:/;
exports.LocalServer = LocalServer;
//# sourceMappingURL=local_server.js.map