UNPKG

@signalk/resources-provider

Version:

Resources provider plugin for Signal K server.

236 lines (235 loc) 10.2 kB
"use strict"; 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;