UNPKG

@webda/core

Version:

Expose API with Lambda

178 lines 6.49 kB
import jsonpath from "jsonpath"; import { WebdaError } from "../index.js"; import { Service, ServiceParameters } from "./service.js"; export class ConfigurationServiceParameters extends ServiceParameters { constructor(params) { super(params); this.checkInterval ?? (this.checkInterval = 3600); } } /** * Handle sessionSecret ( rolling between two secrets ) expire every hour * Handle longTermSecret ( rolling between two longer secret ) expire every month * * Load configuration from another service * * If the result contains `webda.services` in his object then webda configuration will * be dynamically reloaded * * @category CoreServices * @WebdaModda */ export default class ConfigurationService extends Service { constructor() { super(...arguments); /** * Watchs for configuration update */ this.watchs = []; } /** * Load parameters * * @param params * @ignore */ loadParameters(params) { return new ConfigurationServiceParameters(params); } /** * @inheritdoc */ async init() { // Check interval by default every hour if (!this.parameters.source) { throw new WebdaError.CodeError("CONFIGURATION_SOURCE_MISSING", "Need a source for ConfigurationService"); } let source = this.parameters.source.split(":"); this.sourceService = this.getService(source[0]); if (!this.sourceService) { throw new WebdaError.CodeError("CONFIGURATION_SOURCE_INVALID", 'Need a valid service for source ("sourceService:sourceId")'); } this.sourceId = source[1]; if (!this.sourceId) { throw new WebdaError.CodeError("CONFIGURATION_SOURCE_INVALID", 'Need a valid source ("sourceService:sourceId")'); } if (!this.sourceService.getConfiguration) { throw new WebdaError.CodeError("CONFIGURATION_SOURCE_INVALID", `Service '${source[0]}' is not implementing ConfigurationProvider interface`); } this.serializedConfiguration = JSON.stringify(this.parameters.default); await this.checkUpdate(); if (!this.sourceService.canTriggerConfiguration(this.sourceId, this.checkUpdate.bind(this, true))) { this.interval = setInterval(this.checkUpdate.bind(this), 1000); } // Add webda info this.watch("$.services", (updates) => this._webda.reinit(updates)); return this; } /** * Watch a specific configuration modification * * @param jsonPath JSON Path to the object to watch * @param callback Method to call with the updated version * @param defaultValue Default value of the jsonPath if it does not exist */ watch(jsonPath, callback, defaultValue = undefined) { this.watchs.push({ path: jsonPath, callback, defaultValue }); } /** * Clear the check interval if exist */ async stop() { if (this.interval !== undefined) { // @ts-ignore clearInterval(this.interval); } return super.stop(); } /** * * @returns current configuration */ getConfiguration() { return this.configuration || {}; } /** * We cannot reinit the configurationService by itself * * @inheritdoc */ async reinit(_config) { // Need to prevent any reinit return this; } /** * Load the configuration by calling the source service with the source id * @returns */ async loadConfiguration() { return this.sourceService.getConfiguration(this.sourceId); } async initConfiguration() { throw new Error("ConfigurationService with dependencies cannot be used"); } /** * Checking for configuration updates * * If configuration is updated, it will trigger all the watchs accordingly * * @returns */ async checkUpdate(dynamic = false) { // If the ConfigurationProvider cannot trigger we check at interval if (!dynamic && this.interval && this.nextCheck > Date.now()) { return; } this.log("DEBUG", "Refreshing configuration"); const newConfig = (await this.loadConfiguration()) || this.parameters.default; this.emit("Configuration.Loaded", newConfig); const serializedConfig = JSON.stringify(newConfig); if (serializedConfig !== this.serializedConfiguration) { this.emit("Configuration.Applying", newConfig); this.log("DEBUG", "Apply new configuration"); this.serializedConfiguration = serializedConfig; this.configuration = newConfig; // Add the webda parameters logical if (this.configuration && this.configuration.services) { // Merge parameters with each service - cannot add new services for security for (let i in this.configuration.services) { if (this.getWebda().getService(i)) { this.configuration.services[i] = this.getWebda().getServiceParams(i, this.configuration); } } } let promises = []; this.watchs.forEach(w => { this.log("TRACE", "Apply new configuration value", jsonpath.query(newConfig, w.path).pop() || w.defaultValue); let p = w.callback(jsonpath.query(newConfig, w.path).pop() || w.defaultValue); if (p) { promises.push(p); } }); await Promise.all(promises); this.emit("Configuration.Applied", newConfig); } // If the ConfigurationProvider cannot trigger we check at interval if (this.interval) { this.updateNextCheck(); this.log("DEBUG", "Next configuration refresh in", this.parameters.checkInterval, "s"); } } /** * Update the next check time */ updateNextCheck() { this.nextCheck = Date.now() + this.parameters.checkInterval * 1000; } /** * Read the file and store it */ async loadAndStoreConfiguration() { let res = await this.loadConfiguration(); this.emit("Configuration.Loaded", res); this.serializedConfiguration = JSON.stringify(res); return res; } } export { ConfigurationService }; //# sourceMappingURL=configuration.js.map