UNPKG

iobroker.js-controller

Version:

Updated by reinstall.js on 2018-06-11T15:19:56.688Z

314 lines (313 loc) • 10.3 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var adapterUpgradeManager_exports = {}; __export(adapterUpgradeManager_exports, { AdapterUpgradeManager: () => AdapterUpgradeManager }); module.exports = __toCommonJS(adapterUpgradeManager_exports); var import_js_controller_common = require("@iobroker/js-controller-common"); var import_node_http = __toESM(require("node:http"), 1); var import_node_https = __toESM(require("node:https"), 1); var import_promises = require("node:timers/promises"); var import_js_controller_cli = require("@iobroker/js-controller-cli"); class AdapterUpgradeManager { /** Wait ms until adapter is stopped */ STOP_TIMEOUT_MS = 3e3; /** Wait ms for delivery of final response */ SHUTDOWN_TIMEOUT = 1e4; /** Name of the adapter to upgrade */ adapterName; /** Desired adapter version */ version; /** Response send by webserver */ response = { running: true, stderr: [], stdout: [] }; /** Used to stop the stop shutdown timeout */ shutdownAbortController; /** Logger to log to file and other transports */ logger; /** The server used for communicating upgrade status */ server; /** All socket connections of the webserver */ sockets = /* @__PURE__ */ new Set(); /** Name of the host for logging purposes */ hostname = import_js_controller_common.tools.getHostName(); /** The objects DB client */ objects; /** The states DB client */ states; /** List of instances which have been stopped */ stoppedInstances = []; /** If webserver should be started with https */ useHttps; /** Public certificate name if https is desired */ certPublicName; /** Private certificate name if https is desired */ certPrivateName; /** Port where the webserver should be running */ port; constructor(options) { this.adapterName = options.adapterName; this.version = options.version; this.logger = options.logger; this.objects = options.objects; this.states = options.states; this.useHttps = options.useHttps; this.port = options.port; if (options.useHttps) { this.certPublicName = options.certPublicName; this.certPrivateName = options.certPrivateName; } } /** * Stops the adapter and returns ids of stopped instances */ async stopAdapter() { this.stoppedInstances = await this.getAllEnabledInstances(); await this.enableInstances(this.stoppedInstances, false); await (0, import_promises.setTimeout)(this.STOP_TIMEOUT_MS); } /** * Start all instances which were enabled before the upgrade */ async startAdapter() { await this.enableInstances(this.stoppedInstances, true); } /** * Start or stop given instances * * @param instances id of instances which will be stopped * @param enabled if enable or disable instances */ async enableInstances(instances, enabled) { const ts = Date.now(); for (const instance of instances) { const updatedObj = { common: { enabled }, from: `system.host.${this.hostname}`, ts }; await this.objects.extendObjectAsync(instance, updatedObj); } } /** * Install given version of adapter */ async performUpgrade() { const processExitHandler = (exitCode) => { this.log(`Upgrade process exited with code: ${exitCode}`, true); }; const upgrade = new import_js_controller_cli.Upgrade({ objects: this.objects, processExit: processExitHandler, states: this.states, params: {} }); try { await upgrade.upgradeAdapter(void 0, `${this.adapterName}@${this.version}`, true, true, false); this.response.success = true; this.log(`Successfully upgraded ${this.adapterName} to version ${this.version}`); } catch (e) { this.log(e.message, true); this.response.success = false; } await this.setFinished(); } /** * Starts the web server for admin communication either secure or insecure */ async startWebServer() { if (this.useHttps && this.certPublicName && this.certPrivateName) { await this.startSecureWebServer({ certPublicName: this.certPublicName, certPrivateName: this.certPrivateName, port: this.port, useHttps: true }); } else { this.startInsecureWebServer({ port: this.port, useHttps: false }); } } /** * Shuts down the server, restarts the adapter */ shutdownServer() { if (this.shutdownAbortController) { this.shutdownAbortController.abort(); } if (!this.server) { return; } this.destroySockets(); this.server.close(async () => { await this.startAdapter(); this.log("Successfully started adapter"); }); } /** * Destroy all sockets, to prevent requests from keeping server alive */ destroySockets() { for (const socket of this.sockets) { socket.destroy(); this.sockets.delete(socket); } } /** * This function is called when the webserver receives a message * * @param req received message * @param res server response */ webServerCallback(req, res) { res.writeHead(200); res.end(JSON.stringify(this.response)); if (!this.response.running) { this.log("Final information delivered"); this.shutdownServer(); } } /** * Get all instances of the adapter */ async getAllEnabledInstances() { const res = await this.objects.getObjectListAsync({ startkey: `system.adapter.${this.adapterName}.`, endkey: `system.adapter.${this.adapterName}.\u9999` }); let enabledInstances = []; enabledInstances = res.rows.filter((row) => row.value.common.enabled && this.hostname === row.value.common.host).map((row) => row.value._id); return enabledInstances; } /** * Log via logger and provide the logs for the server too * * @param message the message which will be logged * @param error if it is an error */ log(message, error = false) { if (error) { this.logger.error(`host.${this.hostname} ${message}`); this.response.stderr.push(message); return; } this.logger.info(`host.${this.hostname} [WEBSERVER_UPGRADE] (${this.adapterName}) ${message}`); this.response.stdout.push(message); } /** * Start an insecure web server for admin communication * * @param params Web server configuration */ startInsecureWebServer(params) { const { port } = params; this.server = import_node_http.default.createServer((req, res) => { this.webServerCallback(req, res); }); this.monitorSockets(this.server); this.server.listen(port, () => { this.log(`Server is running on http://localhost:${port}`); }); } /** * Start a secure web server for admin communication * * @param params Web server configuration */ async startSecureWebServer(params) { const { port, certPublicName, certPrivateName } = params; const { certPublic, certPrivate } = await this.getCertificates({ certPublicName, certPrivateName }); this.server = import_node_https.default.createServer({ key: certPrivate, cert: certPublic }, (req, res) => { this.webServerCallback(req, res); }); this.monitorSockets(this.server); this.server.listen(port, () => { this.log(`Server is running on http://localhost:${port}`); }); } /** * Keep track of all existing sockets * * @param server the webserver */ monitorSockets(server) { server.on("connection", (socket) => { this.sockets.add(socket); server.once("close", () => { this.sockets.delete(socket); }); }); } /** * Get certificates from the DB * * @param params certificate information */ async getCertificates(params) { const { certPublicName, certPrivateName } = params; const obj = await this.objects.getObjectAsync("system.certificates"); if (!obj) { throw new Error("No certificates found"); } const certs = obj.native.certificates; return { certPrivate: certs[certPrivateName], certPublic: certs[certPublicName] }; } /** * Tells the upgrade manager, that server can be shut down on next response or on timeout */ async setFinished() { this.response.running = false; await this.startShutdownTimeout(); } /** * Start a timeout which starts adapter and shuts down the server if expired */ async startShutdownTimeout() { this.shutdownAbortController = new AbortController(); try { await (0, import_promises.setTimeout)(this.SHUTDOWN_TIMEOUT, null, { signal: this.shutdownAbortController.signal }); this.log("Timeout expired, initializing shutdown"); this.shutdownServer(); } catch (e) { if (e.code !== "ABORT_ERR") { this.log(e.message, true); } } } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { AdapterUpgradeManager }); //# sourceMappingURL=adapterUpgradeManager.js.map