@signalk/resources-provider
Version:
Resources provider plugin for Signal K server.
236 lines (235 loc) • 10.2 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileStore = exports.getUuid = void 0;
/* eslint-disable @typescript-eslint/no-explicit-any */
const fs_1 = require("fs");
const promises_1 = require("fs/promises");
const path_1 = __importDefault(require("path"));
const utils_1 = require("./utils");
const getUuid = (skIdentifier) => skIdentifier.split(':').slice(-1)[0];
exports.getUuid = getUuid;
// File Resource Store Class
class FileStore {
constructor(pluginId, debug) {
this.debug = debug;
this.savePath = '';
this.resources = {};
this.pkg = { id: pluginId };
}
// check / create path to persist resources
init(config) {
return __awaiter(this, void 0, void 0, function* () {
if (typeof config.settings.path === 'undefined') {
this.savePath = config.basePath + '/resources';
}
else if (config.settings.path[0] == '/') {
this.savePath = config.settings.path;
}
else {
this.savePath = path_1.default.join(config.basePath, config.settings.path);
}
// std resources
if (config.settings.standard) {
Object.keys(config.settings.standard).forEach((i) => {
this.resources[i] = { path: path_1.default.join(this.savePath, `/${i}`) };
});
}
// other resources
const enabledResTypes = {};
Object.assign(enabledResTypes, config.settings.standard);
if (config.settings.custom && Array.isArray(config.settings.custom)) {
config.settings.custom.forEach((i) => {
this.resources[i.name] = {
path: path_1.default.join(this.savePath, `/${i.name}`)
};
enabledResTypes[i.name] = true;
});
}
try {
yield this.checkPath(this.savePath);
}
catch (_error) {
throw new Error(`Unable to create ${this.savePath}!`);
}
return yield this.createSavePaths(enabledResTypes);
});
}
// create save paths for resource types
createSavePaths(resTypes) {
return __awaiter(this, void 0, void 0, function* () {
this.debug('** Initialising resource storage **');
const result = { error: false, message: `` };
Object.keys(this.resources).forEach((t) => __awaiter(this, void 0, void 0, function* () {
if (resTypes[t]) {
try {
yield (0, promises_1.access)(this.resources[t].path, fs_1.constants.W_OK | fs_1.constants.R_OK);
this.debug(`${this.resources[t].path} - OK....`);
}
catch (_error) {
this.debug(`${this.resources[t].path} NOT available...`);
this.debug(`Creating ${this.resources[t].path} ...`);
try {
yield (0, promises_1.mkdir)(this.resources[t].path, { recursive: true });
this.debug(`Created ${this.resources[t].path} - OK....`);
}
catch (_error) {
result.error = true;
result.message += `ERROR creating ${this.resources[t].path} folder\r\n `;
}
}
}
}));
return result;
});
}
// return resource or property value of supplied resource id
getResource(type, itemUuid, property) {
return __awaiter(this, void 0, void 0, function* () {
try {
let result = JSON.parse(yield (0, promises_1.readFile)(path_1.default.join(this.resources[type].path, itemUuid), 'utf8'));
if (property) {
const value = property.split('.').reduce((acc, val) => {
return acc[val];
}, result);
if (value) {
result = { value: value };
}
else {
throw new Error(`${type}/${itemUuid}.${property} not found!`);
}
}
const stats = yield (0, promises_1.stat)(path_1.default.join(this.resources[type].path, itemUuid));
result.timestamp = stats.mtime;
result.$source = this.pkg.id;
return result;
}
catch (e) {
if (e.code === 'ENOENT') {
throw new Error(`No such resource ${type} ${itemUuid}`);
}
console.error(e);
throw new Error(`Error retrieving resource ${type} ${itemUuid}`);
}
});
}
// return persisted resources from storage
getResources(type, params) {
return __awaiter(this, void 0, void 0, function* () {
const result = {};
// ** parse supplied params
params = (0, utils_1.processParameters)(params);
try {
// return matching resources
const rt = this.resources[type];
const files = yield (0, promises_1.readdir)(rt.path, { withFileTypes: true });
// check resource count
const fcount = params.limit && files.length > params.limit
? params.limit
: files.length;
let count = 0;
for (const f in files) {
if (!files[f].isFile()) {
this.debug(`${files[f].name} is not a File => ignore.`);
continue;
}
if (++count > fcount) {
break;
}
try {
const res = JSON.parse(yield (0, promises_1.readFile)(path_1.default.join(rt.path, files[f].name), 'utf8'));
// apply param filters
if ((0, utils_1.passFilter)(res, type, params)) {
const uuid = files[f].name;
result[uuid] = res;
const stats = yield (0, promises_1.stat)(path_1.default.join(rt.path, files[f].name));
result[uuid].timestamp = stats.mtime;
result[uuid].$source = this.pkg.id;
}
}
catch (err) {
console.error(err);
throw new Error(`Invalid file contents: ${files[f]}`);
}
}
return result;
}
catch (error) {
console.error(error);
throw new Error(`Error retrieving resources from ${this.savePath}. Ensure plugin is active or restart plugin!`);
}
});
}
// save / delete (r.value==null) resource file
setResource(r) {
return __awaiter(this, void 0, void 0, function* () {
const fname = (0, exports.getUuid)(r.id);
const p = path_1.default.join(this.resources[r.type].path, fname);
if (r.value === null) {
// delete file
try {
yield (0, promises_1.unlink)(p);
this.debug(`** DELETED: ${r.type} entry ${fname} **`);
return;
}
catch (error) {
console.error('Error deleting resource!');
error.message = 'Error deleting resource!';
throw error;
}
}
else {
// add / update file
try {
yield (0, promises_1.writeFile)(p, JSON.stringify(r.value));
this.debug(`** ${r.type} written to ${fname} **`);
return;
}
catch (error) {
console.error('Error updating resource!');
throw error;
}
}
});
}
// check path exists / create it if it doesn't
checkPath(path = this.savePath) {
return __awaiter(this, void 0, void 0, function* () {
if (!path) {
throw new Error(`Path not supplied!`);
}
try {
yield (0, promises_1.access)(
// check path exists
path, fs_1.constants.W_OK | fs_1.constants.R_OK);
this.debug(`${path} - OK...`);
return true;
}
catch (_error) {
// if not then create it
this.debug(`${path} does NOT exist...`);
this.debug(`Creating ${path} ...`);
try {
yield (0, promises_1.mkdir)(path, { recursive: true });
this.debug(`Created ${path} - OK...`);
return true;
}
catch (_error) {
throw new Error(`Unable to create ${path}!`);
}
}
});
}
}
exports.FileStore = FileStore;