UNPKG

@adpt/core

Version:
153 lines 5.33 kB
"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