@cn-shell/storage-engine
Version:
A Cloud Native Shell extension for stoarge engine using LevelDB
188 lines (187 loc) • 5.31 kB
JavaScript
"use strict";
var __importDefault =
(this && this.__importDefault) ||
function(mod) {
return mod && mod.__esModule ? mod : { default: mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.CNStorageEngine = void 0;
// imports here
const cn_shell_1 = __importDefault(require("cn-shell"));
const levelup_1 = __importDefault(require("levelup"));
const leveldown_1 = __importDefault(require("leveldown"));
// Config consts here
const CFG_STORAGE_DIR = "STORAGE_DIR";
const CFG_KEEP_OPEN_INTERVAL = "KEEP_OPEN_INTERVAL";
const DEFAULT_CFG_KEEP_OPEN_INTERVAL = "0";
// Route consts here:
const ROUTE_DATA = "/data";
const QRY_STRING_STORE = "store";
// Class CNStorageEngine here
class CNStorageEngine extends cn_shell_1.default {
// Constructor here
constructor(name) {
super(name);
this._storageDir = this.getRequiredCfg(CFG_STORAGE_DIR);
this.info("Setting storage directory to (%s)", this._storageDir);
let keepOpenInterval = this.getCfg(
CFG_KEEP_OPEN_INTERVAL,
DEFAULT_CFG_KEEP_OPEN_INTERVAL,
);
this._keepOpenInterval = parseInt(keepOpenInterval, 10) * 1000;
this.info("Setting keep open interval to %ds", keepOpenInterval);
this._stores = new Map();
this.setupCreateRoute();
this.setupReadRoute();
}
// Methods here
async start() {
if (this._keepOpenInterval !== 0) {
this._closeStorageTimer = setInterval(
() => this.checkStorage(),
this._keepOpenInterval,
);
}
return true;
}
async stop() {
clearInterval(this._closeStorageTimer);
for (const [, v] of this._stores) {
this.info("Closing Storage (%s)", v.name);
await v.db.close();
}
}
async healthCheck() {
return true;
}
// Private methods here
async checkStorage() {
let now = Date.now();
let closed = [];
// Check if any stores have not been accessed in the alloacted interval
for (const [, v] of this._stores) {
if (now - v.lastAccessed > this._keepOpenInterval) {
closed.push(v);
}
}
// Remove and close the selected stores
for (let details of closed) {
this.info("Closing storage (%s)", details.name);
await details.db.close();
this._stores.delete(details.name);
}
}
setupCreateRoute() {
this.createRoute(ROUTE_DATA, async body => {
if (
body.name === undefined ||
body.key === undefined ||
body.value === undefined
) {
let error = { status: 404, message: "Body invalid!" };
throw error;
}
let written = await this.write(body.name, body.key, body.value);
if (written === false) {
let error = {
status: 500,
message: "Ooops - we have had a problem!",
};
throw error;
}
return body.key;
});
}
setupReadRoute() {
this.simpleReadRoute(ROUTE_DATA, async (id, query) => {
if (id === undefined) {
let error = { status: 404, message: "No ID specified!" };
throw error;
}
if (query === undefined || query[QRY_STRING_STORE] === undefined) {
let error = { status: 400, message: "No store specified!" };
throw error;
}
if (Array.isArray(query[QRY_STRING_STORE])) {
let error = {
status: 400,
message: "Can only specify one store!",
};
throw error;
}
// We know this is a string because we checked if it was an arrray above
let name = query[QRY_STRING_STORE];
let value = await this.get(name, id);
if (value === null) {
let error = {
status: 404,
message: "Ooops - can't find that key!",
};
throw error;
}
return value;
});
}
getStore(name) {
let now = Date.now();
let details = this._stores.get(name);
if (details !== undefined) {
details.lastAccessed = now;
return details;
}
this.info("Creating/Opening storage (%s)", name);
details = {
name,
lastAccessed: now,
db: levelup_1.default(leveldown_1.default(`${this._storageDir}/${name}`)),
};
this._stores.set(name, details);
return details;
}
// Public methods here
async get(name, key) {
let store = this.getStore(name);
let value = await store.db.get(key).catch(e => {
this.error(
"Error (%s) while attempting to get key (%s) from store (%s)",
e,
key,
name,
);
});
if (value === undefined) {
return null;
}
return value.toString();
}
async write(name, key, value) {
let store = this.getStore(name);
let written = true;
await store.db.put(key, value).catch(e => {
this.error(
"Error (%s) while attempting to write key (%s) from store (%s)",
e,
key,
name,
);
written = false;
});
return written;
}
async del(name, key) {
let store = this.getStore(name);
let deleted = true;
await store.db.del(key).catch(e => {
this.error(
"Error (%s) while attempting to delete key (%s) from store (%s)",
e,
key,
name,
);
deleted = false;
});
return deleted;
}
}
exports.CNStorageEngine = CNStorageEngine;
//# sourceMappingURL=main.js.map