UNPKG

domotz-remote-pawn

Version:

Domotz Agent

208 lines (190 loc) 7.32 kB
/** This file is part of Domotz Agent. * Copyright (C) 2016 Domotz Ltd * * Domotz Agent is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Domotz Agent is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Domotz Agent. If not, see <http://www.gnu.org/licenses/>. * * Created by Tommaso Latini <tommaso@domotz.com> on 11/09/15. */ var factory = function (q, fs, childProcess, cpu, resourceLocator) { var myConsole = resourceLocator.log.decorateLogs(); var env = process.env; var serviceDomotz = env.DOMOTZ_SS_LINK; var logDir = env.DOMOTZ_LOG_DIR; function kill(pid, signal) { signal = signal !== undefined ? signal : 'SIGTERM'; pid = pid || process.pid; myConsole.warn(' Send Signal %s to %s', signal, pid); try { return process.kill(pid, signal); } catch (e) { myConsole.error('Error killing process ' + e.message); } } function gracefulShutdown() { var delay = 500; if ( resourceLocator.utils.platform.isNetgearRouter() || (resourceLocator.utils.sentryManager && resourceLocator.utils.sentryManager.isEnabled()) ) { delay = 5000; } if (process.platform === 'win32') { resourceLocator.log.flush(); } else { kill(process.pid, 'SIGHUP'); // Flush Log } try { terminateJamDriver(); if (resourceLocator.stallWatcher) { resourceLocator.stallWatcher.kill(); } storeHttpCache(); storeRTDData(); storeDHCPData(); } catch (e) { myConsole.error(' An error happened during shutdown procedure:'); myConsole.error(e.stack); } myConsole.warn('Graceful Shutdown within %d ms', delay); setTimeout(function () { process.exit(0); }, delay); } function terminateJamDriver() { if (resourceLocator.jamDriver) { return resourceLocator.jamDriver.killDeviceJammer(); } } function storeRTDData() { if (resourceLocator.networkTools.rtd) { resourceLocator.networkTools.rtd.storeToFS(); } } function storeDHCPData() { if (resourceLocator.DHCPRequestCounters) { resourceLocator.DHCPRequestCounters.storeToFS(); } } function storeHttpCache() { if (resourceLocator.httpOutCache) { resourceLocator.httpOutCache.storeCache(); } } /** * DEPRECATED --> use gracefulShutdown instead * Used when there was also zabbix proxy. * In order to avoid memory leak it can be called once per day by the * suicide event. */ function restart() { myConsole.warn(' Rebooting services'); var cmd = serviceDomotz, args = ['restart'], options = { detached: true, stdio: [ 'ignore', // out and err below fs.openSync(logDir + '/reboot.log', 'w'), fs.openSync(logDir + '/reboot_error.log', 'w'), ], }; if (resourceLocator.utils.platform.needsSudo()) { cmd = 'sudo'; args.unshift(serviceDomotz); } childProcess.spawn(cmd, args, options).unref(); } /** * Same arguments as child_process.spawn. It returns a promise, hiding * the event emitter behind! * * @param command * @param args * @param options * @returns {*|promise} */ function spawn(command, args, options) { if (!command || typeof command !== 'string') { throw new Error('Command must be a string. command: <' + command + '> type=' + typeof command); } var deferred = q.defer(); cpu.schedule(deferred, command, args, options); return deferred.promise; } /** * Same arguments as child_process.exec except for the callback. * It returns a promise! * This function originally exploited the exec method of child_process. * We rewrite it because exec it's not efficient, insofar it opens an * interpreter (by default a shell) and then the command for 2 process in * total. * * @param command * @param options * @returns {*|promise} * */ function exec(command, options) { var isCountDiscoveryEnabled = process.env.ENABLE_COMMAND_SUFFIX_COMMENT; var commandSuffixComment = ''; if (isCountDiscoveryEnabled && options && options.suffix_comment) { commandSuffixComment = ' #' + options.suffix_comment; } var argv = (command + commandSuffixComment).trim().split(' '); return spawn(argv[0], argv.slice(1), options); } /** * This is a special case of the spawn() functionality for spawning * Node processes. In addition to having all the methods in a normal * ChildProcess instance, the returned object has a communication channel * built-in. See child.send(message, [sendHandle]) for details. * * N.B. THESE CHILD NODES ARE STILL WHOLE NEW INSTANCES OF V8. * ASSUME AT LEAST 30MS STARTUP AND 10MB MEMORY FOR EACH NEW NODE. * THAT IS, YOU CANNOT CREATE MANY THOUSANDS OF THEM !! * * TODO: Embed this type of call to external process in the scheduler * * @param modulePath: The module to run in the child * @param args: Array List of string arguments * @param options: Object * --> cwd: String Current working directory of the child process * --> env: Object Environment key-value pairs * --> execPath: String Executable used to create the child process * --> execArgv: Array List of string arguments passed to the * executable (Default: process.execArgv) * --> silent: Boolean * If true, stdin, stdout, and stderr of the child * will be piped to the parent, * * If false they will be inherited from the parent, * see the "pipe" and "inherit" options for spawn()'s * stdio for more details (default is false) * @returns {*|{send, kill, on}} */ function fork(modulePath, args, options) { var child = childProcess.fork(modulePath, args, options); myConsole.info(' Forking Module --> %s. Args: %s. Options: %s.', modulePath, args.join(' '), JSON.stringify(options), { pid: child.pid }); return child; } return { kill: kill, gracefulShutdown: gracefulShutdown, restart: restart, exec: exec, spawn: spawn, fork: fork, }; }; module.exports.factory = factory;