plex-web-downloader/node_modules/cluster/lib/plugins/cli.js

230 lines
4.6 KiB
JavaScript

/*!
* Cluster - cli
* Copyright (c) 2011 LearnBoost <dev@learnboost.com>
* MIT Licensed
*/
/**
* Module dependencies.
*/
var fs = require('fs')
, Log = require('log');
/**
* Commands.
*/
var commands = [];
/**
* Adds a command-line interface to your cluster.
*
* This plugin requires that you use `pidfiles()`
* above `cli()`, so that the pidfile directory
* is exposed.
*
* Examples:
*
* cluster(server)
* .use(cluster.pidfiles())
* .use(cluster.cli())
* .listen(3000);
*
* Once set up our server script serves as both
* the master, and the CLI. For example we may
* still launch the server(s) as shown below.
*
* $ nohup node server.js &
*
* However now we may also utilize commands
* provided by this plugin.
*
* $ node server.js status
*
* master 3281 dead
* worker 0 3282 dead
*
* For more command information use `--help`.
*
* $ node server.js --help
*
* @return {Function}
* @api public
*/
exports = module.exports = function(){
return function(master){
requirePIDs(master);
// augment master
master.killall = function(sig){
var pid = master.pidof('master');
try {
// signal master
process.kill(pid, sig);
} catch (err) {
if ('ESRCH' != err.code) throw err;
// signal children individually
master.workerpids().forEach(function(pid){
try {
process.kill(pid, sig);
} catch (err) {
if ('ESRCH' != err.code) throw err;
}
});
}
};
var args = process.argv.slice(2)
, len = commands.length
, command
, arg;
// parse arguments
while (args.length) {
arg = args.shift();
for (var i = 0; i < len; ++i) {
command = commands[i];
if (~command.flags.indexOf(arg)) {
command.callback(master);
master.preventDefault = true;
}
}
}
}
};
/**
* Define command `name` with the given callback `fn(master)`
* and a short `desc`.
*
* @param {String} name
* @param {Function} fn
* @param {String} desc
* @return {Object} exports for chaining
* @api public
*/
var define = exports.define = function(name, fn, desc){
commands.push({
flags: name.split(/ *, */)
, desc: desc
, callback: fn
});
return exports;
};
/**
* Report master / worker status based on
* the PID files saved by the pidfiles()
* plugin.
*/
define('-s, --status, status', function(master){
var dir = master.pidfiles
, files = fs.readdirSync(dir);
// null signal failed previous
// to this release
if (process.version < 'v0.4.1') {
console.log('status will not work with node < 0.4.1');
console.log('due to SIGTERM globbering the null signal');
process.exit(1);
}
console.log();
// only pids
files.filter(function(file){
return file.match(/\.pid$/);
// check status
}).forEach(function(file){
var name = file.replace('.pid', '')
, pid = master.pidof(name)
, name = name.replace('.', ' ')
, color
, status;
try {
process.kill(pid, 0);
status = 'alive';
color = '36';
} catch (err) {
if ('ESRCH' == err.code) {
color = '31';
status = 'dead';
} else {
throw err;
}
}
console.log(' %s\033[90m %d\033[0m \033[' + color + 'm%s\033[0m'
, name
, pid
, status);
});
console.log();
}, 'Output cluster status');
/**
* Restart workers.
*/
define('-r, --restart, restart', function(master){
master.killall('SIGUSR2');
}, 'Restart master by sending the SIGUSR2 signal');
/**
* Graceful shutdown.
*/
define('-g, --shutdown, shutdown', function(master){
master.killall('SIGQUIT');
}, 'Graceful shutdown by sending the SIGQUIT signal');
/**
* Hard shutdown.
*/
define('-S, --stop, stop', function(master){
master.killall('SIGTERM');
}, 'Hard shutdown by sending the SIGTERM signal');
/**
* Display help information.
*/
define('-h, --help, help', function(master){
console.log('\n Usage: node <file> <command>\n');
commands.forEach(function(command){
console.log(' '
+ command.flags.join(', ')
+ '\n '
+ '\033[90m' + command.desc + '\033[0m'
+ '\n');
});
console.log();
}, 'Show help information');
/**
* Output cluster version.
*/
define('-v, --version', function(master){
console.log(require('../cluster').version);
}, 'Output cluster version');
/**
* Require `pidfiles()` plugin.
*
* @param {Master} master
* @api private
*/
function requirePIDs(master) {
if (master.pidfiles) return;
throw new Error('cli() plugin requires pidfiles(), please add pidfiles() before cli()');
}