feat: 초기 프로젝트 설정 및 룰.md 파일 추가

This commit is contained in:
2025-07-28 09:53:31 +09:00
commit 09a4d38512
8165 changed files with 1021855 additions and 0 deletions

View File

@@ -0,0 +1,212 @@
var Common = require('../Common.js');
var cst = require('../../constants.js');
var UX = require('./UX');
var chalk = require('chalk');
var Configuration = require('../Configuration.js');
module.exports = function(CLI) {
CLI.prototype.get = function(key, cb) {
var that = this;
if (!key || key == 'all') {
displayConf(function(err, data) {
if (err)
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
});
return false;
}
Configuration.get(key, function(err, data) {
if (err) {
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
// pm2 conf module-name
if (key.indexOf(':') === -1 && key.indexOf('.') === -1) {
displayConf(key, function() {
console.log('Modules configuration. Copy/Paste line to edit values.')
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT)
});
return false;
}
// pm2 conf module-name:key
var module_name, key_name;
if (key.indexOf(':') > -1) {
module_name = key.split(':')[0];
key_name = key.split(':')[1];
} else if (key.indexOf('.') > -1) {
module_name = key.split('.')[0];
key_name = key.split('.')[1];
}
Common.printOut('Value for module ' + chalk.blue(module_name), 'key ' + chalk.blue(key_name) + ': ' + chalk.bold.green(data));
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
});
};
CLI.prototype.set = function(key, value, cb) {
var that = this;
if (!key) {
interactiveConfigEdit(function(err) {
if (err)
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
});
return false;
}
/**
* Set value
*/
Configuration.set(key, value, function(err) {
if (err)
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
var values = [];
if (key.indexOf('.') > -1)
values = key.split('.');
if (key.indexOf(':') > -1)
values = key.split(':');
if (values && values.length > 1) {
// The first element is the app name (module_conf.json)
var app_name = values[0];
process.env.PM2_PROGRAMMATIC = 'true';
that.restart(app_name, {
updateEnv : true
}, function(err, data) {
process.env.PM2_PROGRAMMATIC = 'false';
if (!err)
Common.printOut(cst.PREFIX_MSG + 'Module %s restarted', app_name);
Common.log('Setting changed')
displayConf(app_name, function() {
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
});
});
return false;
}
displayConf(null, function() {
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
});
});
};
CLI.prototype.multiset = function(serial, cb) {
var that = this;
Configuration.multiset(serial, function(err, data) {
if (err)
return cb ? cb({success:false, err:err}) : that.exitCli(cst.ERROR_EXIT);
var values = [];
var key = serial.match(/(?:[^ "]+|"[^"]*")+/g)[0];
if (key.indexOf('.') > -1)
values = key.split('.');
if (key.indexOf(':') > -1)
values = key.split(':');
if (values && values.length > 1) {
// The first element is the app name (module_conf.json)
var app_name = values[0];
process.env.PM2_PROGRAMMATIC = 'true';
that.restart(app_name, {
updateEnv : true
}, function(err, data) {
process.env.PM2_PROGRAMMATIC = 'false';
if (!err)
Common.printOut(cst.PREFIX_MSG + 'Module %s restarted', app_name);
displayConf(app_name, function() {
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT)
});
});
return false;
}
displayConf(app_name, function() {
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT)
});
});
};
CLI.prototype.unset = function(key, cb) {
var that = this;
Configuration.unset(key, function(err) {
if (err) {
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
displayConf(function() { cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT) });
});
};
CLI.prototype.conf = function(key, value, cb) {
var that = this;
if (typeof(value) === 'function') {
cb = value;
value = null;
}
// If key + value = set
if (key && value) {
that.set(key, value, function(err) {
if (err)
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
});
}
// If only key = get
else if (key) {
that.get(key, function(err, data) {
if (err)
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
});
}
else {
interactiveConfigEdit(function(err) {
if (err)
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
});
}
};
};
function interactiveConfigEdit(cb) {
UX.helpers.openEditor(cst.PM2_MODULE_CONF_FILE, function(err, data) {
Common.printOut(chalk.bold('Module configuration (%s) edited.'), cst.PM2_MODULE_CONF_FILE);
Common.printOut(chalk.bold('To take changes into account, please restart module related.'), cst.PM2_MODULE_CONF_FILE);
if (err)
return cb(Common.retErr(err));
return cb(null, {success:true});
});
}
/**
* Configuration
*/
function displayConf(target_app, cb) {
if (typeof(target_app) == 'function') {
cb = target_app;
target_app = null;
}
Configuration.getAll(function(err, data) {
UX.helpers.dispKeys(data, target_app);
return cb();
});
}

View File

@@ -0,0 +1,335 @@
var spawn = require('child_process').spawn;
var exec = require('child_process').exec;
var chalk = require('chalk');
var util = require('util');
var fmt = require('../tools/fmt.js');
var fs = require('fs');
var path = require('path');
var cst = require('../../constants.js');
var Promise = require('../tools/promise.min.js');
function pspawn(cmd) {
return new Promise(function(resolve, reject) {
var p_cmd = cmd.split(' ');
var install_instance = spawn(p_cmd[0], p_cmd.splice(1, cmd.length), {
stdio : 'inherit',
env : process.env,
shell : true
});
install_instance.on('close', function(code) {
if (code != 0) {
console.log(chalk.bold.red('Command failed'));
return reject(new Error('Bad cmd return'));
}
return resolve();
});
install_instance.on('error', function (err) {
return reject(err);
});
});
}
function checkDockerSetup() {
return new Promise(function(resolve, reject) {
exec("docker version -f '{{.Client.Version}}'", function(err, stdout, stderr) {
if (err) {
console.error(chalk.red.bold('[Docker access] Error while trying to use docker command'));
if (err.message && err.message.indexOf('Cannot connect to the Docker') > -1) {
console.log();
console.log(chalk.blue.bold('[Solution] Setup Docker to be able to be used without sudo rights:'));
console.log(chalk.bold('$ sudo groupadd docker'));
console.log(chalk.bold('$ sudo usermod -aG docker $USER'));
console.log(chalk.bold('Then LOGOUT and LOGIN your Linux session'));
console.log('Read more: http://bit.ly/29JGdCE');
}
return reject(err);
}
return resolve();
});
});
}
/**
* Switch Dockerfile mode
* check test/programmatic/containerizer.mocha.js
*/
function parseAndSwitch(file_content, main_file, opts) {
var lines = file_content.split('\n');
var mode = opts.mode;
lines[0] = 'FROM keymetrics/pm2:' + opts.node_version;
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
if (['## DISTRIBUTION MODE', '## DEVELOPMENT MODE'].indexOf(line) > -1 ||
i == lines.length - 1) {
lines.splice(i, lines.length);
lines[i] = '## ' + mode.toUpperCase() + ' MODE';
lines[i + 1] = 'ENV NODE_ENV=' + (mode == 'distribution' ? 'production' : mode);
if (mode == 'distribution') {
lines[i + 2] = 'COPY . /var/app';
lines[i + 3] = 'CMD ["pm2-docker", "' + main_file + '", "--env", "production"]';
}
if (mode == 'development') {
lines[i + 2] = 'CMD ["pm2-dev", "' + main_file + '", "--env", "development"]';
}
break;
}
};
lines = lines.join('\n');
return lines;
};
/**
* Replace ENV, COPY and CMD depending on the mode
* @param {String} docker_filepath Dockerfile absolute path
* @param {String} main_file Main file to start in container
* @param {String} mode Mode to switch the Dockerfile
*/
function switchDockerFile(docker_filepath, main_file, opts) {
return new Promise(function(resolve, reject) {
var data = fs.readFileSync(docker_filepath, 'utf8').toString();
if (['distribution', 'development'].indexOf(opts.mode) == -1)
return reject(new Error('Unknown mode'));
var lines = parseAndSwitch(data, main_file, opts)
fs.writeFile(docker_filepath, lines, function(err) {
if (err) return reject(err);
resolve({
Dockerfile_path : docker_filepath,
Dockerfile : lines,
CMD : ''
});
})
});
}
/**
* Generate sample Dockerfile (lib/templates/Dockerfiles)
* @param {String} docker_filepath Dockerfile absolute path
* @param {String} main_file Main file to start in container
* @param {String} mode Mode to switch the Dockerfile
*/
function generateDockerfile(docker_filepath, main_file, opts) {
return new Promise(function(resolve, reject) {
var tpl_file = path.join(cst.TEMPLATE_FOLDER, cst.DOCKERFILE_NODEJS);
var template = fs.readFileSync(tpl_file, {encoding: 'utf8'});
var CMD;
template = parseAndSwitch(template, main_file, opts);
fs.writeFile(docker_filepath, template, function(err) {
if (err) return reject(err);
resolve({
Dockerfile_path : docker_filepath,
Dockerfile : template,
CMD : CMD
});
});
});
}
function handleExit(CLI, opts, mode) {
process.on('SIGINT', function() {
CLI.disconnect();
if (mode != 'distribution')
return false;
exec('docker ps -lq', function(err, stdout, stderr) {
if (err) {
console.error(err);
}
require('vizion').analyze({folder : process.cwd()}, function recur_path(err, meta){
if (!err && meta.revision) {
var commit_id = util.format('#%s(%s) %s',
meta.branch,
meta.revision.slice(0, 5),
meta.comment);
console.log(chalk.bold.magenta('$ docker commit -m "%s" %s %s'),
commit_id,
stdout.replace('\n', ''),
opts.imageName);
}
else
console.log(chalk.bold.magenta('$ docker commit %s %s'), stdout.replace('\n', ''), opts.imageName);
console.log(chalk.bold.magenta('$ docker push %s'), opts.imageName);
});
});
});
}
module.exports = function(CLI) {
CLI.prototype.generateDockerfile = function(script, opts) {
var docker_filepath = path.join(process.cwd(), 'Dockerfile');
var that = this;
fs.stat(docker_filepath, function(err, stat) {
if (err || opts.force == true) {
generateDockerfile(docker_filepath, script, {
mode : 'development'
})
.then(function() {
console.log(chalk.bold('New Dockerfile generated in current folder'));
console.log(chalk.bold('You can now run\n$ pm2 docker:dev <file|config>'));
return that.exitCli(cst.SUCCESS_EXIT);
});
return false;
}
console.log(chalk.red.bold('Dockerfile already exists in this folder, use --force if you want to replace it'));
that.exitCli(cst.ERROR_EXIT);
});
};
CLI.prototype.dockerMode = function(script, opts, mode) {
var promptly = require('promptly');
var self = this;
handleExit(self, opts, mode);
if (mode == 'distribution' && !opts.imageName) {
console.error(chalk.bold.red('--image-name [name] option is missing'));
return self.exitCli(cst.ERROR_EXIT);
}
var template;
var app_path, main_script;
var image_name;
var node_version = opts.nodeVersion ? opts.nodeVersion.split('.')[0] : 'latest';
image_name = opts.imageName || require('crypto').randomBytes(6).toString('hex');
if (script.indexOf('/') > -1) {
app_path = path.join(process.cwd(), path.dirname(script));
main_script = path.basename(script);
}
else {
app_path = process.cwd();
main_script = script;
}
checkDockerSetup()
.then(function() {
/////////////////////////
// Generate Dockerfile //
/////////////////////////
return new Promise(function(resolve, reject) {
var docker_filepath = path.join(process.cwd(), 'Dockerfile');
fs.stat(docker_filepath, function(err, stat) {
if (err) {
// Dockerfile does not exist, generate one
// console.log(chalk.blue.bold('Generating new Dockerfile'));
if (opts.force == true) {
return resolve(generateDockerfile(docker_filepath, main_script, {
node_version : node_version,
mode : mode
}));
}
if (opts.dockerdaemon)
return resolve(generateDockerfile(docker_filepath, main_script, {
node_version : node_version,
mode : mode
}));
promptly.prompt('No Dockerfile in current directory, ok to generate a new one? (y/n)', function(err, value) {
if (value == 'y')
return resolve(generateDockerfile(docker_filepath, main_script, {
node_version : node_version,
mode : mode
}));
else
return self.exitCli(cst.SUCCESS_EXIT);
});
return false;
}
return resolve(switchDockerFile(docker_filepath, main_script, {
node_version : node_version,
mode : mode
}));
});
});
})
.then(function(_template) {
template = _template;
return Promise.resolve();
})
.then(function() {
//////////////////
// Docker build //
//////////////////
var docker_build = util.format('docker build -t %s -f %s',
image_name,
template.Dockerfile_path);
if (opts.fresh == true)
docker_build += ' --no-cache';
docker_build += ' .';
console.log();
fmt.sep();
fmt.title('Building Boot System');
fmt.field('Type', chalk.cyan.bold('Docker'));
fmt.field('Mode', mode);
fmt.field('Image name', image_name);
fmt.field('Docker build command', docker_build);
fmt.field('Dockerfile path', template.Dockerfile_path);
fmt.sep();
return pspawn(docker_build);
})
.then(function() {
////////////////
// Docker run //
////////////////
var docker_run = 'docker run --net host';
if (opts.dockerdaemon == true)
docker_run += ' -d';
if (mode != 'distribution')
docker_run += util.format(' -v %s:/var/app -v /var/app/node_modules', app_path);
docker_run += ' ' + image_name;
var dockerfile_parsed = template.Dockerfile.split('\n');
var base_image = dockerfile_parsed[0];
var run_cmd = dockerfile_parsed[dockerfile_parsed.length - 1];
console.log();
fmt.sep();
fmt.title('Booting');
fmt.field('Type', chalk.cyan.bold('Docker'));
fmt.field('Mode', mode);
fmt.field('Base Image', base_image);
fmt.field('Image Name', image_name);
fmt.field('Docker Command', docker_run);
fmt.field('RUN Command', run_cmd);
fmt.field('CWD', app_path);
fmt.sep();
return pspawn(docker_run);
})
.then(function() {
console.log(chalk.blue.bold('>>> Leaving Docker instance uuid=%s'), image_name);
self.disconnect();
return Promise.resolve();
})
.catch(function(err) {
console.log();
console.log(chalk.grey('Raw error=', err.message));
self.disconnect();
});
};
};
module.exports.generateDockerfile = generateDockerfile;
module.exports.parseAndSwitch = parseAndSwitch;
module.exports.switchDockerFile = switchDockerFile;

459
api.hyungi.net/node_modules/pm2/lib/API/Dashboard.js generated vendored Normal file
View File

@@ -0,0 +1,459 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
var os = require('os');
var p = require('path');
var blessed = require('blessed');
var debug = require('debug')('pm2:monit');
var printf = require('sprintf-js').sprintf;
// Total memory
const totalMem = os.totalmem();
var Dashboard = {};
var DEFAULT_PADDING = {
top : 0,
left : 1,
right : 1
};
var WIDTH_LEFT_PANEL = 30;
/**
* Synchronous Dashboard init method
* @method init
* @return this
*/
Dashboard.init = function() {
// Init Screen
this.screen = blessed.screen({
smartCSR: true,
fullUnicode: true
});
this.screen.title = 'PM2 Dashboard';
this.logLines = {}
this.list = blessed.list({
top: '0',
left: '0',
width: WIDTH_LEFT_PANEL + '%',
height: '70%',
padding: 0,
scrollbar: {
ch: ' ',
inverse: false
},
border: {
type: 'line'
},
keys: true,
autoCommandKeys: true,
tags: true,
style: {
selected: {
bg: 'blue',
fg: 'white'
},
scrollbar: {
bg: 'blue',
fg: 'black'
},
fg: 'white',
border: {
fg: 'blue'
},
header: {
fg: 'blue'
}
}
});
this.list.on('select item', (item, i) => {
this.logBox.clearItems()
})
this.logBox = blessed.list({
label: ' Logs ',
top: '0',
left: WIDTH_LEFT_PANEL + '%',
width: 100 - WIDTH_LEFT_PANEL + '%',
height: '70%',
padding: DEFAULT_PADDING,
scrollable: true,
scrollbar: {
ch: ' ',
inverse: false
},
keys: true,
autoCommandKeys: true,
tags: true,
border: {
type: 'line'
},
style: {
fg: 'white',
border: {
fg: 'white'
},
scrollbar: {
bg: 'blue',
fg: 'black'
}
}
});
this.metadataBox = blessed.box({
label: ' Metadata ',
top: '70%',
left: WIDTH_LEFT_PANEL + '%',
width: 100 - WIDTH_LEFT_PANEL + '%',
height: '26%',
padding: DEFAULT_PADDING,
scrollable: true,
scrollbar: {
ch: ' ',
inverse: false
},
keys: true,
autoCommandKeys: true,
tags: true,
border: {
type: 'line'
},
style: {
fg: 'white',
border: {
fg: 'white'
},
scrollbar: {
bg: 'blue',
fg: 'black'
}
}
});
this.metricsBox = blessed.list({
label: ' Custom Metrics ',
top: '70%',
left: '0%',
width: WIDTH_LEFT_PANEL + '%',
height: '26%',
padding: DEFAULT_PADDING,
scrollbar: {
ch: ' ',
inverse: false
},
keys: true,
autoCommandKeys: true,
tags: true,
border: {
type: 'line'
},
style: {
fg: 'white',
border: {
fg: 'white'
},
scrollbar: {
bg: 'blue',
fg: 'black'
}
}
});
this.box4 = blessed.text({
content: ' left/right: switch boards | up/down/mouse: scroll | Ctrl-C: exit{|} {cyan-fg}{bold}To go further check out https://pm2.io/{/} ',
left: '0%',
top: '95%',
width: '100%',
height: '6%',
valign: 'middle',
tags: true,
style: {
fg: 'white'
}
});
this.list.focus();
this.screen.append(this.list);
this.screen.append(this.logBox);
this.screen.append(this.metadataBox);
this.screen.append(this.metricsBox);
this.screen.append(this.box4);
this.list.setLabel(' Process List ');
this.screen.render();
var that = this;
var i = 0;
var boards = ['list', 'logBox', 'metricsBox', 'metadataBox'];
this.screen.key(['left', 'right'], function(ch, key) {
(key.name === 'left') ? i-- : i++;
if (i == 4)
i = 0;
if (i == -1)
i = 3;
that[boards[i]].focus();
that[boards[i]].style.border.fg = 'blue';
if (key.name === 'left') {
if (i == 3)
that[boards[0]].style.border.fg = 'white';
else
that[boards[i + 1]].style.border.fg = 'white';
}
else {
if (i == 0)
that[boards[3]].style.border.fg = 'white';
else
that[boards[i - 1]].style.border.fg = 'white';
}
});
this.screen.key(['escape', 'q', 'C-c'], function(ch, key) {
this.screen.destroy();
process.exit(0);
});
// async refresh of the ui
setInterval(function () {
that.screen.render();
}, 300);
return this;
}
/**
* Refresh dashboard
* @method refresh
* @param {} processes
* @return this
*/
Dashboard.refresh = function(processes) {
debug('Monit refresh');
if(!processes) {
this.list.setItem(0, 'No process available');
return;
}
if (processes.length != this.list.items.length) {
this.list.clearItems();
}
// Total of processes memory
var mem = 0;
processes.forEach(function(proc) {
mem += proc.monit.memory;
})
// Sort process list
processes.sort(function(a, b) {
if (a.pm2_env.name < b.pm2_env.name)
return -1;
if (a.pm2_env.name > b.pm2_env.name)
return 1;
return 0;
});
// Loop to get process infos
for (var i = 0; i < processes.length; i++) {
// Percent of memory use by one process in all pm2 processes
var memPercent = (processes[i].monit.memory / mem) * 100;
// Status of process
var status = processes[i].pm2_env.status == 'online' ? '{green-fg}' : '{red-fg}';
status = status + '{bold}' + processes[i].pm2_env.status + '{/}';
var name = processes[i].pm2_env.name || p.basename(processes[i].pm2_env.pm_exec_path);
// Line of list
var item = printf('[%2s] %s {|} Mem: {bold}{%s-fg}%3d{/} MB CPU: {bold}{%s-fg}%2d{/} %s %s',
processes[i].pm2_env.pm_id,
name,
gradient(memPercent, [255, 0, 0], [0, 255, 0]),
(processes[i].monit.memory / 1048576).toFixed(2),
gradient(processes[i].monit.cpu, [255, 0, 0], [0, 255, 0]),
processes[i].monit.cpu,
"%",
status);
// Check if item exist
if (this.list.getItem(i)) {
this.list.setItem(i, item);
}
else {
this.list.pushItem(item);
}
var proc = processes[this.list.selected];
// render the logBox
let process_id = proc.pm_id
let logs = this.logLines[process_id];
if(typeof(logs) !== "undefined"){
this.logBox.setItems(logs)
if (!this.logBox.focused) {
this.logBox.setScrollPerc(100);
}
}else{
this.logBox.clearItems();
}
this.logBox.setLabel(` ${proc.pm2_env.name} Logs `)
this.metadataBox.setLine(0, 'App Name ' + '{bold}' + proc.pm2_env.name + '{/}');
this.metadataBox.setLine(1, 'Namespace ' + '{bold}' + proc.pm2_env.namespace + '{/}');
this.metadataBox.setLine(2, 'Version ' + '{bold}' + proc.pm2_env.version + '{/}');
this.metadataBox.setLine(3, 'Restarts ' + proc.pm2_env.restart_time);
this.metadataBox.setLine(4, 'Uptime ' + ((proc.pm2_env.pm_uptime && proc.pm2_env.status == 'online') ? timeSince(proc.pm2_env.pm_uptime) : 0));
this.metadataBox.setLine(5, 'Script path ' + proc.pm2_env.pm_exec_path);
this.metadataBox.setLine(6, 'Script args ' + (proc.pm2_env.args ? (typeof proc.pm2_env.args == 'string' ? JSON.parse(proc.pm2_env.args.replace(/'/g, '"')):proc.pm2_env.args).join(' ') : 'N/A'));
this.metadataBox.setLine(7, 'Interpreter ' + proc.pm2_env.exec_interpreter);
this.metadataBox.setLine(8, 'Interpreter args ' + (proc.pm2_env.node_args.length != 0 ? proc.pm2_env.node_args : 'N/A'));
this.metadataBox.setLine(9, 'Exec mode ' + (proc.pm2_env.exec_mode == 'fork_mode' ? '{bold}fork{/}' : '{blue-fg}{bold}cluster{/}'));
this.metadataBox.setLine(10, 'Node.js version ' + proc.pm2_env.node_version);
this.metadataBox.setLine(11, 'watch & reload ' + (proc.pm2_env.watch ? '{green-fg}{bold}✔{/}' : '{red-fg}{bold}✘{/}'));
this.metadataBox.setLine(12, 'Unstable restarts ' + proc.pm2_env.unstable_restarts);
this.metadataBox.setLine(13, 'Comment ' + ((proc.pm2_env.versioning) ? proc.pm2_env.versioning.comment : 'N/A'));
this.metadataBox.setLine(14, 'Revision ' + ((proc.pm2_env.versioning) ? proc.pm2_env.versioning.revision : 'N/A'));
this.metadataBox.setLine(15, 'Branch ' + ((proc.pm2_env.versioning) ? proc.pm2_env.versioning.branch : 'N/A'));
this.metadataBox.setLine(16, 'Remote url ' + ((proc.pm2_env.versioning) ? proc.pm2_env.versioning.url : 'N/A'));
this.metadataBox.deleteLine(17)
this.metadataBox.setLine(17, 'Last update ' + ((proc.pm2_env.versioning) ? proc.pm2_env.versioning.update_time : 'N/A'));
if (Object.keys(proc.pm2_env.axm_monitor).length != this.metricsBox.items.length) {
this.metricsBox.clearItems();
}
var j = 0;
for (var key in proc.pm2_env.axm_monitor) {
var metric_name = proc.pm2_env.axm_monitor[key].hasOwnProperty('value') ? proc.pm2_env.axm_monitor[key].value : proc.pm2_env.axm_monitor[key]
var metric_unit = proc.pm2_env.axm_monitor[key].hasOwnProperty('unit') ? proc.pm2_env.axm_monitor[key].unit : null
var probe = `{bold}${key}{/} {|} ${metric_name}${metric_unit == null ? '' : ' ' + metric_unit}`
if (this.metricsBox.getItem(j)) {
this.metricsBox.setItem(j, probe);
}
else {
this.metricsBox.pushItem(probe);
}
j++;
}
this.screen.render();
}
return this;
}
/**
* Put Log
* @method log
* @param {} data
* @return this
*/
Dashboard.log = function(type, data) {
var that = this;
if(typeof(this.logLines[data.process.pm_id]) == "undefined"){
this.logLines[data.process.pm_id]=[];
}
// Logs colors
switch (type) {
case 'PM2':
var color = '{blue-fg}';
break;
case 'out':
var color = '{green-fg}';
break;
case 'err':
var color = '{red-fg}';
break;
default:
var color = '{white-fg}';
}
var logs = data.data.split('\n')
logs.forEach((log) => {
if (log.length > 0) {
this.logLines[data.process.pm_id].push(color + data.process.name + '{/} > ' + log)
//removing logs if longer than limit
let count = 0;
let max_count = 0;
let leading_process_id = -1;
for(var process_id in this.logLines){
count += this.logLines[process_id].length;
if( this.logLines[process_id].length > max_count){
leading_process_id = process_id;
max_count = this.logLines[process_id].length;
}
}
if (count > 200) {
this.logLines[leading_process_id].shift()
}
}
})
return this;
}
module.exports = Dashboard;
function timeSince(date) {
var seconds = Math.floor((new Date() - date) / 1000);
var interval = Math.floor(seconds / 31536000);
if (interval > 1) {
return interval + 'Y';
}
interval = Math.floor(seconds / 2592000);
if (interval > 1) {
return interval + 'M';
}
interval = Math.floor(seconds / 86400);
if (interval > 1) {
return interval + 'D';
}
interval = Math.floor(seconds / 3600);
if (interval > 1) {
return interval + 'h';
}
interval = Math.floor(seconds / 60);
if (interval > 1) {
return interval + 'm';
}
return Math.floor(seconds) + 's';
}
/* Args :
* p : Percent 0 - 100
* rgb_ : Array of rgb [255, 255, 255]
* Return :
* Hexa #FFFFFF
*/
function gradient(p, rgb_beginning, rgb_end) {
var w = (p / 100) * 2 - 1;
var w1 = (w + 1) / 2.0;
var w2 = 1 - w1;
var rgb = [parseInt(rgb_beginning[0] * w1 + rgb_end[0] * w2),
parseInt(rgb_beginning[1] * w1 + rgb_end[1] * w2),
parseInt(rgb_beginning[2] * w1 + rgb_end[2] * w2)];
return "#" + ((1 << 24) + (rgb[0] << 16) + (rgb[1] << 8) + rgb[2]).toString(16).slice(1);
}

117
api.hyungi.net/node_modules/pm2/lib/API/Deploy.js generated vendored Normal file
View File

@@ -0,0 +1,117 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
var fs = require('fs');
var cst = require('../../constants.js');
var Utility = require('../Utility.js');
var Common = require('../Common.js');
function deployHelper() {
console.log('');
console.log('-----> Helper: Deployment with PM2');
console.log('');
console.log(' Generate a sample ecosystem.config.js with the command');
console.log(' $ pm2 ecosystem');
console.log(' Then edit the file depending on your needs');
console.log('');
console.log(' Commands:');
console.log(' setup run remote setup commands');
console.log(' update update deploy to the latest release');
console.log(' revert [n] revert to [n]th last deployment or 1');
console.log(' curr[ent] output current release commit');
console.log(' prev[ious] output previous release commit');
console.log(' exec|run <cmd> execute the given <cmd>');
console.log(' list list previous deploy commits');
console.log(' [ref] deploy to [ref], the "ref" setting, or latest tag');
console.log('');
console.log('');
console.log(' Basic Examples:');
console.log('');
console.log(' First initialize remote production host:');
console.log(' $ pm2 deploy ecosystem.config.js production setup');
console.log('');
console.log(' Then deploy new code:');
console.log(' $ pm2 deploy ecosystem.config.js production');
console.log('');
console.log(' If I want to revert to the previous commit:');
console.log(' $ pm2 deploy ecosystem.config.js production revert 1');
console.log('');
console.log(' Execute a command on remote server:');
console.log(' $ pm2 deploy ecosystem.config.js production exec "pm2 restart all"');
console.log('');
console.log(' PM2 will look by default to the ecosystem.config.js file so you dont need to give the file name:');
console.log(' $ pm2 deploy production');
console.log(' Else you have to tell PM2 the name of your ecosystem file');
console.log('');
console.log(' More examples in https://github.com/Unitech/pm2');
console.log('');
};
module.exports = function(CLI) {
CLI.prototype.deploy = function(file, commands, cb) {
var that = this;
if (file == 'help') {
deployHelper();
return cb ? cb() : that.exitCli(cst.SUCCESS_EXIT);
}
var args = commands.rawArgs;
var env;
args.splice(0, args.indexOf('deploy') + 1);
// Find ecosystem file by default
if (!Common.isConfigFile(file)) {
env = args[0];
var defaultConfigNames = [ ...Common.getConfigFileCandidates('ecosystem'), 'ecosystem.json5', 'package.json'];
file = Utility.whichFileExists(defaultConfigNames);
if (!file) {
Common.printError('Not any default deployment file exists.'+
' Allowed default config file names are: ' + defaultConfigNames.join(', '));
return cb ? cb('Not any default ecosystem file present') : that.exitCli(cst.ERROR_EXIT);
}
}
else
env = args[1];
var json_conf = null;
try {
json_conf = Common.parseConfig(fs.readFileSync(file), file);
} catch (e) {
Common.printError(e);
return cb ? cb(e) : that.exitCli(cst.ERROR_EXIT);
}
if (!env) {
deployHelper();
return cb ? cb() : that.exitCli(cst.SUCCESS_EXIT);
}
if (!json_conf.deploy || !json_conf.deploy[env]) {
Common.printError('%s environment is not defined in %s file', env, file);
return cb ? cb('%s environment is not defined in %s file') : that.exitCli(cst.ERROR_EXIT);
}
if (!json_conf.deploy[env]['post-deploy']) {
json_conf.deploy[env]['post-deploy'] = 'pm2 startOrRestart ' + file + ' --env ' + env;
}
require('pm2-deploy').deployForEnv(json_conf.deploy, env, args, function(err, data) {
if (err) {
Common.printError('Deploy failed');
Common.printError(err.message || err);
return cb ? cb(err) : that.exitCli(cst.ERROR_EXIT);
}
Common.printOut('--> Success');
return cb ? cb(null, data) : that.exitCli(cst.SUCCESS_EXIT);
});
};
};

775
api.hyungi.net/node_modules/pm2/lib/API/Extra.js generated vendored Normal file
View File

@@ -0,0 +1,775 @@
/***************************
*
* Extra methods
*
**************************/
var cst = require('../../constants.js');
var Common = require('../Common.js');
var UX = require('./UX');
var chalk = require('chalk');
var path = require('path');
var fs = require('fs');
var fmt = require('../tools/fmt.js');
var dayjs = require('dayjs');
var pkg = require('../../package.json');
const copyDirSync = require('../tools/copydirSync.js')
module.exports = function(CLI) {
/**
* Get version of the daemonized PM2
* @method getVersion
* @callback cb
*/
CLI.prototype.getVersion = function(cb) {
var that = this;
that.Client.executeRemote('getVersion', {}, function(err) {
return cb ? cb.apply(null, arguments) : that.exitCli(cst.SUCCESS_EXIT);
});
};
/**
* Install pm2-sysmonit
*/
CLI.prototype.launchSysMonitoring = function(cb) {
if ((this.pm2_configuration && this.pm2_configuration.sysmonit != 'true') ||
process.env.TRAVIS ||
global.it === 'function' ||
cst.IS_WINDOWS === true)
return cb ? cb(null) : null
var filepath
try {
filepath = path.dirname(require.resolve('pm2-sysmonit'))
} catch(e) {
return cb ? cb(null) : null
}
this.start({
script: filepath
}, {
started_as_module : true
}, (err, res) => {
if (err) {
Common.printError(cst.PREFIX_MSG_ERR + 'Error while trying to serve : ' + err.message || err);
return cb ? cb(err) : this.speedList(cst.ERROR_EXIT);
}
return cb ? cb(null) : this.speedList();
});
};
/**
* Show application environment
* @method env
* @callback cb
*/
CLI.prototype.env = function(app_id, cb) {
var procs = []
var printed = 0
this.Client.executeRemote('getMonitorData', {}, (err, list) => {
list.forEach(l => {
if (app_id == l.pm_id) {
printed++
var env = Common.safeExtend({}, l.pm2_env)
Object.keys(env).forEach(key => {
console.log(`${key}: ${chalk.green(env[key])}`)
})
}
})
if (printed == 0) {
Common.err(`Modules with id ${app_id} not found`)
return cb ? cb.apply(null, arguments) : this.exitCli(cst.ERROR_EXIT);
}
return cb ? cb.apply(null, arguments) : this.exitCli(cst.SUCCESS_EXIT);
})
};
/**
* Get version of the daemonized PM2
* @method getVersion
* @callback cb
*/
CLI.prototype.report = function() {
var that = this;
var Log = require('./Log');
that.Client.executeRemote('getReport', {}, function(err, report) {
console.log()
console.log()
console.log()
console.log('```')
fmt.title('PM2 report')
fmt.field('Date', new Date());
fmt.sep();
if (report && !err) {
fmt.title(chalk.bold.blue('Daemon'));
fmt.field('pm2d version', report.pm2_version);
fmt.field('node version', report.node_version);
fmt.field('node path', report.node_path);
fmt.field('argv', report.argv);
fmt.field('argv0', report.argv0);
fmt.field('user', report.user);
fmt.field('uid', report.uid);
fmt.field('gid', report.gid);
fmt.field('uptime', dayjs(new Date()).diff(report.started_at, 'minute') + 'min');
}
fmt.sep();
fmt.title(chalk.bold.blue('CLI'));
fmt.field('local pm2', pkg.version);
fmt.field('node version', process.versions.node);
fmt.field('node path', process.env['_'] || 'not found');
fmt.field('argv', process.argv);
fmt.field('argv0', process.argv0);
fmt.field('user', process.env.USER || process.env.LNAME || process.env.USERNAME);
if (cst.IS_WINDOWS === false && process.geteuid)
fmt.field('uid', process.geteuid());
if (cst.IS_WINDOWS === false && process.getegid)
fmt.field('gid', process.getegid());
var os = require('os');
fmt.sep();
fmt.title(chalk.bold.blue('System info'));
fmt.field('arch', os.arch());
fmt.field('platform', os.platform());
fmt.field('type', os.type());
fmt.field('cpus', os.cpus()[0].model);
fmt.field('cpus nb', Object.keys(os.cpus()).length);
fmt.field('freemem', os.freemem());
fmt.field('totalmem', os.totalmem());
fmt.field('home', os.homedir());
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
fmt.sep();
fmt.title(chalk.bold.blue('PM2 list'));
UX.list(list, that.gl_interact_infos);
fmt.sep();
fmt.title(chalk.bold.blue('Daemon logs'));
Log.tail([{
path : cst.PM2_LOG_FILE_PATH,
app_name : 'PM2',
type : 'PM2'
}], 20, false, function() {
console.log('```')
console.log()
console.log()
console.log(chalk.bold.green('Please copy/paste the above report in your issue on https://github.com/Unitech/pm2/issues'));
console.log()
console.log()
that.exitCli(cst.SUCCESS_EXIT);
});
});
});
};
CLI.prototype.getPID = function(app_name, cb) {
var that = this;
if (typeof(app_name) === 'function') {
cb = app_name;
app_name = null;
}
this.Client.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
Common.printError(cst.PREFIX_MSG_ERR + err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
var pids = [];
list.forEach(function(app) {
if (!app_name || app_name == app.name)
pids.push(app.pid);
})
if (!cb) {
Common.printOut(pids.join("\n"))
return that.exitCli(cst.SUCCESS_EXIT);
}
return cb(null, pids);
})
}
/**
* Create PM2 memory snapshot
* @method getVersion
* @callback cb
*/
CLI.prototype.profile = function(type, time, cb) {
var that = this;
var dayjs = require('dayjs');
var cmd
if (type == 'cpu') {
cmd = {
ext: '.cpuprofile',
action: 'profileCPU'
}
}
if (type == 'mem') {
cmd = {
ext: '.heapprofile',
action: 'profileMEM'
}
}
var file = path.join(process.cwd(), dayjs().format('dd-HH:mm:ss') + cmd.ext);
time = time || 10000
console.log(`Starting ${cmd.action} profiling for ${time}ms...`)
that.Client.executeRemote(cmd.action, {
pwd : file,
timeout: time
}, function(err) {
if (err) {
console.error(err);
return that.exitCli(1);
}
console.log(`Profile done in ${file}`)
return cb ? cb.apply(null, arguments) : that.exitCli(cst.SUCCESS_EXIT);
});
};
function basicMDHighlight(lines) {
console.log('\n\n+-------------------------------------+')
console.log(chalk.bold('README.md content:'))
lines = lines.split('\n')
var isInner = false
lines.forEach(l => {
if (l.startsWith('#'))
console.log(chalk.bold.green(l))
else if (isInner || l.startsWith('```')) {
if (isInner && l.startsWith('```'))
isInner = false
else if (isInner == false)
isInner = true
console.log(chalk.grey(l))
}
else if (l.startsWith('`'))
console.log(chalk.grey(l))
else
console.log(l)
})
console.log('+-------------------------------------+')
}
/**
* pm2 create command
* create boilerplate of application for fast try
* @method boilerplate
*/
CLI.prototype.boilerplate = function(cb) {
var i = 0
var projects = []
var enquirer = require('enquirer')
const forEach = require('async/forEach')
fs.readdir(path.join(__dirname, '../templates/sample-apps'), (err, items) => {
forEach(items, (app, next) => {
var fp = path.join(__dirname, '../templates/sample-apps', app)
fs.readFile(path.join(fp, 'package.json'), (err, dt) => {
var meta = JSON.parse(dt)
meta.fullpath = fp
meta.folder_name = app
projects.push(meta)
next()
})
}, () => {
const prompt = new enquirer.Select({
name: 'boilerplate',
message: 'Select a boilerplate',
choices: projects.map((p, i) => {
return {
message: `${chalk.bold.blue(p.name)} ${p.description}`,
value: `${i}`
}
})
});
prompt.run()
.then(answer => {
var p = projects[parseInt(answer)]
basicMDHighlight(fs.readFileSync(path.join(p.fullpath, 'README.md')).toString())
console.log(chalk.bold(`>> Project copied inside folder ./${p.folder_name}/\n`))
copyDirSync(p.fullpath, path.join(process.cwd(), p.folder_name));
this.start(path.join(p.fullpath, 'ecosystem.config.js'), {
cwd: p.fullpath
}, () => {
return cb ? cb.apply(null, arguments) : this.speedList(cst.SUCCESS_EXIT);
})
})
.catch(e => {
return cb ? cb.apply(null, arguments) : this.speedList(cst.SUCCESS_EXIT);
});
})
})
}
/**
* Description
* @method sendLineToStdin
*/
CLI.prototype.sendLineToStdin = function(pm_id, line, separator, cb) {
var that = this;
if (!cb && typeof(separator) == 'function') {
cb = separator;
separator = null;
}
var packet = {
pm_id : pm_id,
line : line + (separator || '\n')
};
that.Client.executeRemote('sendLineToStdin', packet, function(err, res) {
if (err) {
Common.printError(cst.PREFIX_MSG_ERR + err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
return cb ? cb(null, res) : that.speedList();
});
};
/**
* Description
* @method attachToProcess
*/
CLI.prototype.attach = function(pm_id, separator, cb) {
var that = this;
var readline = require('readline');
if (isNaN(pm_id)) {
Common.printError('pm_id must be a process number (not a process name)');
return cb ? cb(Common.retErr('pm_id must be number')) : that.exitCli(cst.ERROR_EXIT);
}
if (typeof(separator) == 'function') {
cb = separator;
separator = null;
}
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
rl.on('close', function() {
return cb ? cb() : that.exitCli(cst.SUCCESS_EXIT);
});
that.Client.launchBus(function(err, bus, socket) {
if (err) {
Common.printError(err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
bus.on('log:*', function(type, packet) {
if (packet.process.pm_id !== parseInt(pm_id))
return;
process.stdout.write(packet.data);
});
});
rl.on('line', function(line) {
that.sendLineToStdin(pm_id, line, separator, function() {});
});
};
/**
* Description
* @method sendDataToProcessId
*/
CLI.prototype.sendDataToProcessId = function(proc_id, packet, cb) {
var that = this;
if (typeof proc_id === 'object' && typeof packet === 'function') {
// the proc_id is packet.
cb = packet;
packet = proc_id;
} else {
packet.id = proc_id;
}
that.Client.executeRemote('sendDataToProcessId', packet, function(err, res) {
if (err) {
Common.printError(err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
Common.printOut('successfully sent data to process');
return cb ? cb(null, res) : that.speedList();
});
};
/**
* Used for custom actions, allows to trigger function inside an app
* To expose a function you need to use keymetrics/pmx
*
* @method msgProcess
* @param {Object} opts
* @param {String} id process id
* @param {String} action_name function name to trigger
* @param {Object} [opts.opts] object passed as first arg of the function
* @param {String} [uuid] optional unique identifier when logs are emitted
*
*/
CLI.prototype.msgProcess = function(opts, cb) {
var that = this;
that.Client.executeRemote('msgProcess', opts, cb);
};
/**
* Trigger a PMX custom action in target application
* Custom actions allows to interact with an application
*
* @method trigger
* @param {String|Number} pm_id process id or application name
* @param {String} action_name name of the custom action to trigger
* @param {Mixed} params parameter to pass to target action
* @param {Function} cb callback
*/
CLI.prototype.trigger = function(pm_id, action_name, params, cb) {
if (typeof(params) === 'function') {
cb = params;
params = null;
}
var cmd = {
msg : action_name
};
var counter = 0;
var process_wait_count = 0;
var that = this;
var results = [];
if (params)
cmd.opts = params;
if (isNaN(pm_id))
cmd.name = pm_id;
else
cmd.id = pm_id;
this.launchBus(function(err, bus) {
bus.on('axm:reply', function(ret) {
if (ret.process.name == pm_id || ret.process.pm_id == pm_id || ret.process.namespace == pm_id || pm_id == 'all') {
results.push(ret);
Common.printOut('[%s:%s:%s]=%j', ret.process.name, ret.process.pm_id, ret.process.namespace, ret.data.return);
if (++counter == process_wait_count)
return cb ? cb(null, results) : that.exitCli(cst.SUCCESS_EXIT);
}
});
that.msgProcess(cmd, function(err, data) {
if (err) {
Common.printError(err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
if (data.process_count == 0) {
Common.printError('Not any process has received a command (offline or unexistent)');
return cb ? cb(Common.retErr('Unknown process')) : that.exitCli(cst.ERROR_EXIT);
}
process_wait_count = data.process_count;
Common.printOut(chalk.bold('%s processes have received command %s'),
data.process_count, action_name);
});
});
};
/**
* Description
* @method sendSignalToProcessName
* @param {} signal
* @param {} process_name
* @return
*/
CLI.prototype.sendSignalToProcessName = function(signal, process_name, cb) {
var that = this;
that.Client.executeRemote('sendSignalToProcessName', {
signal : signal,
process_name : process_name
}, function(err, list) {
if (err) {
Common.printError(err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
Common.printOut('successfully sent signal %s to process name %s', signal, process_name);
return cb ? cb(null, list) : that.speedList();
});
};
/**
* Description
* @method sendSignalToProcessId
* @param {} signal
* @param {} process_id
* @return
*/
CLI.prototype.sendSignalToProcessId = function(signal, process_id, cb) {
var that = this;
that.Client.executeRemote('sendSignalToProcessId', {
signal : signal,
process_id : process_id
}, function(err, list) {
if (err) {
Common.printError(err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
Common.printOut('successfully sent signal %s to process id %s', signal, process_id);
return cb ? cb(null, list) : that.speedList();
});
};
/**
* API method to launch a process that will serve directory over http
*/
CLI.prototype.autoinstall = function (cb) {
var filepath = path.resolve(path.dirname(module.filename), '../Sysinfo/ServiceDetection/ServiceDetection.js');
this.start(filepath, (err, res) => {
if (err) {
Common.printError(cst.PREFIX_MSG_ERR + 'Error while trying to serve : ' + err.message || err);
return cb ? cb(err) : this.speedList(cst.ERROR_EXIT);
}
return cb ? cb(null) : this.speedList();
});
}
/**
* API method to launch a process that will serve directory over http
*
* @param {Object} opts options
* @param {String} opts.path path to be served
* @param {Number} opts.port port on which http will bind
* @param {Boolean} opts.spa single page app served
* @param {String} opts.basicAuthUsername basic auth username
* @param {String} opts.basicAuthPassword basic auth password
* @param {Object} commander commander object
* @param {Function} cb optional callback
*/
CLI.prototype.serve = function (target_path, port, opts, commander, cb) {
var that = this;
var servePort = process.env.PM2_SERVE_PORT || port || 8080;
var servePath = path.resolve(process.env.PM2_SERVE_PATH || target_path || '.');
var filepath = path.resolve(path.dirname(module.filename), './Serve.js');
if (typeof commander.name === 'string')
opts.name = commander.name
else
opts.name = 'static-page-server-' + servePort
if (!opts.env)
opts.env = {};
opts.env.PM2_SERVE_PORT = servePort;
opts.env.PM2_SERVE_PATH = servePath;
opts.env.PM2_SERVE_SPA = opts.spa;
if (opts.basicAuthUsername && opts.basicAuthPassword) {
opts.env.PM2_SERVE_BASIC_AUTH = 'true';
opts.env.PM2_SERVE_BASIC_AUTH_USERNAME = opts.basicAuthUsername;
opts.env.PM2_SERVE_BASIC_AUTH_PASSWORD = opts.basicAuthPassword;
}
if (opts.monitor) {
opts.env.PM2_SERVE_MONITOR = opts.monitor
}
opts.cwd = servePath;
this.start(filepath, opts, function (err, res) {
if (err) {
Common.printError(cst.PREFIX_MSG_ERR + 'Error while trying to serve : ' + err.message || err);
return cb ? cb(err) : that.speedList(cst.ERROR_EXIT);
}
Common.printOut(cst.PREFIX_MSG + 'Serving ' + servePath + ' on port ' + servePort);
return cb ? cb(null, res) : that.speedList();
});
}
/**
* Ping daemon - if PM2 daemon not launched, it will launch it
* @method ping
*/
CLI.prototype.ping = function(cb) {
var that = this;
that.Client.executeRemote('ping', {}, function(err, res) {
if (err) {
Common.printError(err);
return cb ? cb(new Error(err)) : that.exitCli(cst.ERROR_EXIT);
}
Common.printOut(res);
return cb ? cb(null, res) : that.exitCli(cst.SUCCESS_EXIT);
});
};
/**
* Execute remote command
*/
CLI.prototype.remote = function(command, opts, cb) {
var that = this;
that[command](opts.name, function(err_cmd, ret) {
if (err_cmd)
console.error(err_cmd);
console.log('Command %s finished', command);
return cb(err_cmd, ret);
});
};
/**
* This remote method allows to pass multiple arguments
* to PM2
* It is used for the new scoped PM2 action system
*/
CLI.prototype.remoteV2 = function(command, opts, cb) {
var that = this;
if (that[command].length == 1)
return that[command](cb);
opts.args.push(cb);
return that[command].apply(this, opts.args);
};
/**
* Description
* @method generateSample
* @param {} name
* @return
*/
CLI.prototype.generateSample = function(mode) {
var that = this;
var templatePath;
if (mode == 'simple')
templatePath = path.join(cst.TEMPLATE_FOLDER, cst.APP_CONF_TPL_SIMPLE);
else
templatePath = path.join(cst.TEMPLATE_FOLDER, cst.APP_CONF_TPL);
var sample = fs.readFileSync(templatePath);
var dt = sample.toString();
var f_name = 'ecosystem.config.js';
var pwd = process.env.PWD || process.cwd();
try {
fs.writeFileSync(path.join(pwd, f_name), dt);
} catch (e) {
console.error(e.stack || e);
return that.exitCli(cst.ERROR_EXIT);
}
Common.printOut('File %s generated', path.join(pwd, f_name));
that.exitCli(cst.SUCCESS_EXIT);
};
/**
* Description
* @method dashboard
* @return
*/
CLI.prototype.dashboard = function(cb) {
var that = this;
var Dashboard = require('./Dashboard');
if (cb)
return cb(new Error('Dashboard cant be called programmatically'));
Dashboard.init();
this.Client.launchBus(function (err, bus) {
if (err) {
console.error('Error launchBus: ' + err);
that.exitCli(cst.ERROR_EXIT);
}
bus.on('log:*', function(type, data) {
Dashboard.log(type, data)
})
});
process.on('SIGINT', function() {
this.Client.disconnectBus(function() {
process.exit(cst.SUCCESS_EXIT);
});
});
function refreshDashboard() {
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
console.error('Error retrieving process list: ' + err);
that.exitCli(cst.ERROR_EXIT);
}
Dashboard.refresh(list);
setTimeout(function() {
refreshDashboard();
}, 800);
});
}
refreshDashboard();
};
CLI.prototype.monit = function(cb) {
var that = this;
var Monit = require('./Monit.js');
if (cb) return cb(new Error('Monit cant be called programmatically'));
Monit.init();
function launchMonitor() {
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
console.error('Error retrieving process list: ' + err);
that.exitCli(conf.ERROR_EXIT);
}
Monit.refresh(list);
setTimeout(function() {
launchMonitor();
}, 400);
});
}
launchMonitor();
};
CLI.prototype.inspect = function(app_name, cb) {
const that = this;
this.trigger(app_name, 'internal:inspect', function (err, res) {
if(res && res[0]) {
if (res[0].data.return === '') {
Common.printOut(`Inspect disabled on ${app_name}`);
} else {
Common.printOut(`Inspect enabled on ${app_name} => go to chrome : chrome://inspect !!!`);
}
} else {
Common.printOut(`Unable to activate inspect mode on ${app_name} !!!`);
}
that.exitCli(cst.SUCCESS_EXIT);
});
};
};

View File

@@ -0,0 +1,30 @@
const util = require('util')
const spawn = require('child_process').spawn
const DockerMgmt = {}
module.exports = DockerMgmt
function execDocker(cmd, cb) {
var i = spawn('docker', cmd, {
stdio : 'inherit',
env: process.env,
shell : true
})
i.on('close', cb)
}
DockerMgmt.processCommand = function(PM2, start_id, select_id, action, cb) {
PM2.Client.executeRemote('getSystemData', {}, (err, sys_infos) => {
if (sys_infos.containers && sys_infos.containers.length == 0)
return cb(new Error(`Process ${select_id} not found`))
var container = sys_infos.containers[select_id - start_id - 1]
if (action == 'stopProcessId')
execDocker(['stop', container.id], cb)
if (action == 'deleteProcessId')
execDocker(['rm', container.id], cb)
if (action == 'restartProcessId')
execDocker(['restart', container.id], cb)
})
}

315
api.hyungi.net/node_modules/pm2/lib/API/Log.js generated vendored Normal file
View File

@@ -0,0 +1,315 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
var fs = require('fs'),
util = require('util'),
chalk = require('chalk'),
forEachLimit = require('async/forEachLimit'),
dayjs = require('dayjs');
var Log = module.exports = {};
var DEFAULT_PADDING = ' ';
/**
* Tail logs from file stream.
* @param {Object} apps_list
* @param {Number} lines
* @param {Boolean} raw
* @param {Function} callback
* @return
*/
Log.tail = function(apps_list, lines, raw, callback) {
var that = this;
if (lines === 0 || apps_list.length === 0)
return callback && callback();
var count = 0;
var getLastLines = function (filename, lines, callback) {
var chunk = '';
var size = Math.max(0, fs.statSync(filename).size - (lines * 200));
var fd = fs.createReadStream(filename, {start : size});
fd.on('data', function(data) { chunk += data.toString(); });
fd.on('end', function() {
chunk = chunk.split('\n').slice(-(lines+1));
chunk.pop();
callback(chunk);
});
};
apps_list.sort(function(a, b) {
return (fs.existsSync(a.path) ? fs.statSync(a.path).mtime.valueOf() : 0) -
(fs.existsSync(b.path) ? fs.statSync(b.path).mtime.valueOf() : 0);
});
forEachLimit(apps_list, 1, function(app, next) {
if (!fs.existsSync(app.path || ''))
return next();
getLastLines(app.path, lines, function(output) {
console.log(chalk.grey('%s last %d lines:'), app.path, lines);
output.forEach(function(out) {
if (raw)
return app.type === 'err' ? console.error(out) : console.log(out);
if (app.type === 'out')
process.stdout.write(chalk.green(pad(DEFAULT_PADDING, app.app_name) + ' | '));
else if (app.type === 'err')
process.stdout.write(chalk.red(pad(DEFAULT_PADDING, app.app_name) + ' | '));
else
process.stdout.write(chalk.blue(pad(DEFAULT_PADDING, 'PM2') + ' | '));
console.log(out);
});
if (output.length)
process.stdout.write('\n');
next();
});
}, function() {
callback && callback();
});
};
/**
* Stream logs in realtime from the bus eventemitter.
* @param {String} id
* @param {Boolean} raw
* @return
*/
Log.stream = function(Client, id, raw, timestamp, exclusive, highlight) {
var that = this;
Client.launchBus(function(err, bus, socket) {
socket.on('reconnect attempt', function() {
if (global._auto_exit === true) {
if (timestamp)
process.stdout.write(chalk['dim'](chalk.grey(dayjs().format(timestamp) + ' ')));
process.stdout.write(chalk.blue(pad(DEFAULT_PADDING, 'PM2') + ' | ') + '[[[ Target PM2 killed. ]]]');
process.exit(0);
}
});
var min_padding = 3
bus.on('log:*', function(type, packet) {
var isMatchingProcess = id === 'all'
|| packet.process.name == id
|| packet.process.pm_id == id
|| packet.process.namespace == id;
if (!isMatchingProcess)
return;
if ((type === 'out' && exclusive === 'err')
|| (type === 'err' && exclusive === 'out')
|| (type === 'PM2' && exclusive !== false))
return;
var lines;
if (typeof(packet.data) === 'string')
lines = (packet.data || '').split('\n');
else
return;
lines.forEach(function(line) {
if (!line || line.length === 0) return;
if (raw)
return type === 'err' ? process.stderr.write(util.format(line) + '\n') : process.stdout.write(util.format(line) + '\n');
if (timestamp)
process.stdout.write(chalk['dim'](chalk.grey(dayjs().format(timestamp) + ' ')));
var name = packet.process.pm_id + '|' + packet.process.name;
if (name.length > min_padding)
min_padding = name.length + 1
if (type === 'out')
process.stdout.write(chalk.green(pad(' '.repeat(min_padding), name) + ' | '));
else if (type === 'err')
process.stdout.write(chalk.red(pad(' '.repeat(min_padding), name) + ' | '));
else if (!raw && (id === 'all' || id === 'PM2'))
process.stdout.write(chalk.blue(pad(' '.repeat(min_padding), 'PM2') + ' | '));
if (highlight)
process.stdout.write(util.format(line).replace(highlight, chalk.bgBlackBright(highlight)) + '\n');
else
process.stdout.write(util.format(line)+ '\n');
});
});
});
};
Log.devStream = function(Client, id, raw, timestamp, exclusive) {
var that = this;
Client.launchBus(function(err, bus) {
setTimeout(function() {
bus.on('process:event', function(packet) {
if (packet.event == 'online')
console.log(chalk.green('[rundev] App %s restarted'), packet.process.name);
});
}, 1000);
var min_padding = 3
bus.on('log:*', function(type, packet) {
if (id !== 'all'
&& packet.process.name != id
&& packet.process.pm_id != id)
return;
if ((type === 'out' && exclusive === 'err')
|| (type === 'err' && exclusive === 'out')
|| (type === 'PM2' && exclusive !== false))
return;
if (type === 'PM2')
return;
var name = packet.process.pm_id + '|' + packet.process.name;
var lines;
if (typeof(packet.data) === 'string')
lines = (packet.data || '').split('\n');
else
return;
lines.forEach(function(line) {
if (!line || line.length === 0) return;
if (raw)
return process.stdout.write(util.format(line) + '\n');
if (timestamp)
process.stdout.write(chalk['dim'](chalk.grey(dayjs().format(timestamp) + ' ')));
var name = packet.process.name + '-' + packet.process.pm_id;
if (name.length > min_padding)
min_padding = name.length + 1
if (type === 'out')
process.stdout.write(chalk.green(pad(' '.repeat(min_padding), name) + ' | '));
else if (type === 'err')
process.stdout.write(chalk.red(pad(' '.repeat(min_padding), name) + ' | '));
else if (!raw && (id === 'all' || id === 'PM2'))
process.stdout.write(chalk.blue(pad(' '.repeat(min_padding), 'PM2') + ' | '));
process.stdout.write(util.format(line) + '\n');
});
});
});
};
Log.jsonStream = function(Client, id) {
var that = this;
Client.launchBus(function(err, bus) {
if (err) console.error(err);
bus.on('process:event', function(packet) {
process.stdout.write(JSON.stringify({
timestamp : dayjs(packet.at),
type : 'process_event',
status : packet.event,
app_name : packet.process.name
}));
process.stdout.write('\n');
});
bus.on('log:*', function(type, packet) {
if (id !== 'all'
&& packet.process.name != id
&& packet.process.pm_id != id)
return;
if (type === 'PM2')
return;
if (typeof(packet.data) == 'string')
packet.data = packet.data.replace(/(\r\n|\n|\r)/gm,'');
process.stdout.write(JSON.stringify({
message : packet.data,
timestamp : dayjs(packet.at),
type : type,
process_id : packet.process.pm_id,
app_name : packet.process.name
}));
process.stdout.write('\n');
});
});
};
Log.formatStream = function(Client, id, raw, timestamp, exclusive, highlight) {
var that = this;
Client.launchBus(function(err, bus) {
bus.on('log:*', function(type, packet) {
if (id !== 'all'
&& packet.process.name != id
&& packet.process.pm_id != id)
return;
if ((type === 'out' && exclusive === 'err')
|| (type === 'err' && exclusive === 'out')
|| (type === 'PM2' && exclusive !== false))
return;
if (type === 'PM2' && raw)
return;
var name = packet.process.name + '-' + packet.process.pm_id;
var lines;
if (typeof(packet.data) === 'string')
lines = (packet.data || '').split('\n');
else
return;
lines.forEach(function(line) {
if (!line || line.length === 0) return;
if (!raw) {
if (timestamp)
process.stdout.write('timestamp=' + dayjs().format(timestamp) + ' ');
if (packet.process.name === 'PM2')
process.stdout.write('app=pm2 ');
if (packet.process.name !== 'PM2')
process.stdout.write('app=' + packet.process.name + ' id=' + packet.process.pm_id + ' ');
if (type === 'out')
process.stdout.write('type=out ');
else if (type === 'err')
process.stdout.write('type=error ');
}
process.stdout.write('message=');
if (highlight)
process.stdout.write(util.format(line).replace(highlight, chalk.bgBlackBright(highlight)) + '\n');
else
process.stdout.write(util.format(line) + '\n');
});
});
});
};
function pad(pad, str, padLeft) {
if (typeof str === 'undefined')
return pad;
if (padLeft) {
return (pad + str).slice(-pad.length);
} else {
return (str + pad).substring(0, pad.length);
}
}

View File

@@ -0,0 +1,371 @@
var chalk = require('chalk');
var util = require('util');
var fs = require('fs');
var exec = require('child_process').exec;
var path = require('path');
var Log = require('./Log');
var cst = require('../../constants.js');
var Common = require('../Common.js');
module.exports = function(CLI) {
/**
* Description
* @method flush
* @return
*/
CLI.prototype.flush = function(api, cb) {
var that = this;
if (!api) {
Common.printOut(cst.PREFIX_MSG + 'Flushing ' + cst.PM2_LOG_FILE_PATH);
fs.closeSync(fs.openSync(cst.PM2_LOG_FILE_PATH, 'w'));
}
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
Common.printError(err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
list.forEach(function(l) {
if (typeof api == 'undefined') {
Common.printOut(cst.PREFIX_MSG + 'Flushing:');
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_out_log_path);
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_err_log_path);
if (l.pm2_env.pm_log_path) {
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_log_path);
fs.closeSync(fs.openSync(l.pm2_env.pm_log_path, 'w'));
}
fs.closeSync(fs.openSync(l.pm2_env.pm_out_log_path, 'w'));
fs.closeSync(fs.openSync(l.pm2_env.pm_err_log_path, 'w'));
}
else if (l.pm2_env.pm_id == api || l.pm2_env.name === api) {
Common.printOut(cst.PREFIX_MSG + 'Flushing:');
if (l.pm2_env.pm_log_path && fs.existsSync(l.pm2_env.pm_log_path)) {
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_log_path);
fs.closeSync(fs.openSync(l.pm2_env.pm_log_path, 'w'));
}
if (l.pm2_env.pm_out_log_path && fs.existsSync(l.pm2_env.pm_out_log_path)) {
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_out_log_path);
fs.closeSync(fs.openSync(l.pm2_env.pm_out_log_path, 'w'));
}
if (l.pm2_env.pm_err_log_path && fs.existsSync(l.pm2_env.pm_err_log_path)) {
Common.printOut(cst.PREFIX_MSG + l.pm2_env.pm_err_log_path);
fs.closeSync(fs.openSync(l.pm2_env.pm_err_log_path, 'w'));
}
}
});
Common.printOut(cst.PREFIX_MSG + 'Logs flushed');
return cb ? cb(null, list) : that.exitCli(cst.SUCCESS_EXIT);
});
};
CLI.prototype.logrotate = function(opts, cb) {
var that = this;
if (process.getuid() != 0) {
return exec('whoami', function(err, stdout, stderr) {
Common.printError(cst.PREFIX_MSG + 'You have to run this command as root. Execute the following command:');
Common.printError(cst.PREFIX_MSG + chalk.grey(' sudo env PATH=$PATH:' + path.dirname(process.execPath) + ' pm2 logrotate -u ' + stdout.trim()));
cb ? cb(Common.retErr('You have to run this with elevated rights')) : that.exitCli(cst.ERROR_EXIT);
});
}
if (!fs.existsSync('/etc/logrotate.d')) {
Common.printError(cst.PREFIX_MSG + '/etc/logrotate.d does not exist we can not copy the default configuration.');
return cb ? cb(Common.retErr('/etc/logrotate.d does not exist')) : that.exitCli(cst.ERROR_EXIT);
}
var templatePath = path.join(cst.TEMPLATE_FOLDER, cst.LOGROTATE_SCRIPT);
Common.printOut(cst.PREFIX_MSG + 'Getting logrorate template ' + templatePath);
var script = fs.readFileSync(templatePath, {encoding: 'utf8'});
var user = opts.user || 'root';
script = script.replace(/%HOME_PATH%/g, cst.PM2_ROOT_PATH)
.replace(/%USER%/g, user);
try {
fs.writeFileSync('/etc/logrotate.d/pm2-'+user, script);
} catch (e) {
console.error(e.stack || e);
}
Common.printOut(cst.PREFIX_MSG + 'Logrotate configuration added to /etc/logrotate.d/pm2');
return cb ? cb(null, {success:true}) : that.exitCli(cst.SUCCESS_EXIT);
};
/**
* Description
* @method reloadLogs
* @return
*/
CLI.prototype.reloadLogs = function(cb) {
var that = this;
Common.printOut('Reloading all logs...');
that.Client.executeRemote('reloadLogs', {}, function(err, logs) {
if (err) {
Common.printError(err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
Common.printOut('All logs reloaded');
return cb ? cb(null, logs) : that.exitCli(cst.SUCCESS_EXIT);
});
};
/**
* Description
* @method streamLogs
* @param {String} id
* @param {Number} lines
* @param {Boolean} raw
* @return
*/
CLI.prototype.streamLogs = function(id, lines, raw, timestamp, exclusive, highlight) {
var that = this;
var files_list = [];
// If no argument is given, we stream logs for all running apps
id = id || 'all';
lines = lines !== undefined ? lines : 20;
lines = lines < 0 ? -(lines) : lines;
// Avoid duplicates and check if path is different from '/dev/null'
var pushIfUnique = function(entry) {
var exists = false;
if (entry.path.toLowerCase
&& entry.path.toLowerCase() !== '/dev/null') {
files_list.some(function(file) {
if (file.path === entry.path)
exists = true;
return exists;
});
if (exists)
return;
files_list.push(entry);
}
}
// Get the list of all running apps
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
var regexList = [];
var namespaceList = [];
if (err) {
Common.printError(err);
that.exitCli(cst.ERROR_EXIT);
}
if (lines === 0)
return Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
Common.printOut(chalk.bold.grey(util.format.call(this, '[TAILING] Tailing last %d lines for [%s] process%s (change the value with --lines option)', lines, id, id === 'all' ? 'es' : '')));
// Populate the array `files_list` with the paths of all files we need to tail
list.forEach(function(proc) {
if (proc.pm2_env && (id === 'all' ||
proc.pm2_env.name == id ||
proc.pm2_env.pm_id == id)) {
if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
pushIfUnique({
path : proc.pm2_env.pm_out_log_path,
app_name :proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
type : 'out'});
if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
pushIfUnique({
path : proc.pm2_env.pm_err_log_path,
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
type : 'err'
});
} else if(proc.pm2_env && proc.pm2_env.namespace == id) {
if(namespaceList.indexOf(proc.pm2_env.name) === -1) {
namespaceList.push(proc.pm2_env.name)
}
if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
pushIfUnique({
path : proc.pm2_env.pm_out_log_path,
app_name :proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
type : 'out'});
if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
pushIfUnique({
path : proc.pm2_env.pm_err_log_path,
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
type : 'err'
});
}
// Populate the array `files_list` with the paths of all files we need to tail, when log in put is a regex
else if(proc.pm2_env && (isNaN(id) && id[0] === '/' && id[id.length - 1] === '/')) {
var regex = new RegExp(id.replace(/\//g, ''));
if(regex.test(proc.pm2_env.name)) {
if(regexList.indexOf(proc.pm2_env.name) === -1) {
regexList.push(proc.pm2_env.name);
}
if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
pushIfUnique({
path : proc.pm2_env.pm_out_log_path,
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
type : 'out'});
if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
pushIfUnique({
path : proc.pm2_env.pm_err_log_path,
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
type : 'err'
});
}
}
});
//for fixing issue https://github.com/Unitech/pm2/issues/3506
/* if (files_list && files_list.length == 0) {
Common.printError(cst.PREFIX_MSG_ERR + 'No file to stream for app [%s], exiting.', id);
return process.exit(cst.ERROR_EXIT);
}*/
if (!raw && (id === 'all' || id === 'PM2') && exclusive === false) {
Log.tail([{
path : cst.PM2_LOG_FILE_PATH,
app_name : 'PM2',
type : 'PM2'
}], lines, raw, function() {
Log.tail(files_list, lines, raw, function() {
Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
});
});
}
else {
Log.tail(files_list, lines, raw, function() {
if(regexList.length > 0) {
regexList.forEach(function(id) {
Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
})
}
else if(namespaceList.length > 0) {
namespaceList.forEach(function(id) {
Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
})
}
else {
Log.stream(that.Client, id, raw, timestamp, exclusive, highlight);
}
});
}
});
};
/**
* Description
* @method printLogs
* @param {String} id
* @param {Number} lines
* @param {Boolean} raw
* @return
*/
CLI.prototype.printLogs = function(id, lines, raw, timestamp, exclusive) {
var that = this;
var files_list = [];
// If no argument is given, we stream logs for all running apps
id = id || 'all';
lines = lines !== undefined ? lines : 20;
lines = lines < 0 ? -(lines) : lines;
// Avoid duplicates and check if path is different from '/dev/null'
var pushIfUnique = function(entry) {
var exists = false;
if (entry.path.toLowerCase
&& entry.path.toLowerCase() !== '/dev/null') {
files_list.some(function(file) {
if (file.path === entry.path)
exists = true;
return exists;
});
if (exists)
return;
files_list.push(entry);
}
}
// Get the list of all running apps
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
Common.printError(err);
that.exitCli(cst.ERROR_EXIT);
}
if (lines <= 0) {
return that.exitCli(cst.SUCCESS_EXIT)
}
Common.printOut(chalk.bold.grey(util.format.call(this, '[TAILING] Tailing last %d lines for [%s] process%s (change the value with --lines option)', lines, id, id === 'all' ? 'es' : '')));
// Populate the array `files_list` with the paths of all files we need to tail
list.forEach(function(proc) {
if (proc.pm2_env && (id === 'all' ||
proc.pm2_env.name == id ||
proc.pm2_env.pm_id == id)) {
if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
pushIfUnique({
path : proc.pm2_env.pm_out_log_path,
app_name :proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
type : 'out'});
if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
pushIfUnique({
path : proc.pm2_env.pm_err_log_path,
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
type : 'err'
});
}
// Populate the array `files_list` with the paths of all files we need to tail, when log in put is a regex
else if(proc.pm2_env && (isNaN(id) && id[0] === '/' && id[id.length - 1] === '/')) {
var regex = new RegExp(id.replace(/\//g, ''));
if(regex.test(proc.pm2_env.name)) {
if (proc.pm2_env.pm_out_log_path && exclusive !== 'err')
pushIfUnique({
path : proc.pm2_env.pm_out_log_path,
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
type : 'out'});
if (proc.pm2_env.pm_err_log_path && exclusive !== 'out')
pushIfUnique({
path : proc.pm2_env.pm_err_log_path,
app_name : proc.pm2_env.pm_id + '|' + proc.pm2_env.name,
type : 'err'
});
}
}
});
if (!raw && (id === 'all' || id === 'PM2') && exclusive === false) {
Log.tail([{
path : cst.PM2_LOG_FILE_PATH,
app_name : 'PM2',
type : 'PM2'
}], lines, raw, function() {
Log.tail(files_list, lines, raw, function() {
that.exitCli(cst.SUCCESS_EXIT);
});
});
}
else {
Log.tail(files_list, lines, raw, function() {
that.exitCli(cst.SUCCESS_EXIT);
});
}
});
};
};

View File

@@ -0,0 +1,122 @@
var path = require('path');
var fs = require('fs');
var os = require('os');
var spawn = require('child_process').spawn;
var chalk = require('chalk');
var parallel = require('async/parallel');
var Configuration = require('../../Configuration.js');
var cst = require('../../../constants.js');
var Common = require('../../Common');
var Utility = require('../../Utility.js');
var readline = require('readline')
var INTERNAL_MODULES = {
'deep-monitoring': {
dependencies: [{name: 'v8-profiler-node8'}, {name: 'gc-stats'}, {name: 'event-loop-inspector'}]
},
'gc-stats': {name: 'gc-stats'},
'event-loop-inspector': {name: 'event-loop-inspector'},
'v8-profiler': {name: 'v8-profiler-node8'},
'profiler': {name: 'v8-profiler-node8'},
'typescript': {dependencies: [{name: 'typescript'}, {name: 'ts-node@latest'}]},
'livescript': {name: 'livescript'},
'coffee-script': {name: 'coffee-script', message: 'Coffeescript v1 support'},
'coffeescript': {name: 'coffeescript', message: 'Coffeescript v2 support'}
};
module.exports = {
install,
INTERNAL_MODULES,
installMultipleModules
}
function install(module, cb, verbose) {
if (!module || !module.name || module.name.length === 0) {
return cb(new Error('No module name !'));
}
if (typeof verbose === 'undefined') {
verbose = true;
}
installLangModule(module.name, function (err) {
var display = module.message || module.name;
if (err) {
if (verbose) { Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green(display + ' installation has FAILED (checkout previous logs)')); }
return cb(err);
}
if (verbose) { Common.printOut(cst.PREFIX_MSG + chalk.bold.green(display + ' ENABLED')); }
return cb();
});
}
function installMultipleModules(modules, cb, post_install) {
var functionList = [];
for (var i = 0; i < modules.length; i++) {
functionList.push((function (index) {
return function (callback) {
var module = modules[index];
if (typeof modules[index] === 'string') {
module = {name: modules[index]};
}
install(module, function ($post_install, err, $index, $modules) {
try {
var install_instance = spawn(post_install[modules[index]], {
stdio : 'inherit',
windowsHide: true,
env: process.env,
shell : true,
cwd : process.cwd()
});
Common.printOut(cst.PREFIX_MSG_MOD + 'Running configuraton script.');
}
catch(e)
{
Common.printOut(cst.PREFIX_MSG_MOD + 'No configuraton script found.');
}
callback(null, { module: module, err: err });
}, false);
};
})(i));
}
parallel(functionList, function (err, results) {
for (var i = 0; i < results.length; i++) {
var display = results[i].module.message || results[i].module.name;
if (results[i].err) {
err = results[i].err;
Common.printError(cst.PREFIX_MSG_MOD_ERR + chalk.bold.green(display + ' installation has FAILED (checkout previous logs)'));
} else {
Common.printOut(cst.PREFIX_MSG + chalk.bold.green(display + ' ENABLED'));
}
}
if(cb) cb(err);
});
};
function installLangModule(module_name, cb) {
var node_module_path = path.resolve(path.join(__dirname, '../../../'));
Common.printOut(cst.PREFIX_MSG_MOD + 'Calling ' + chalk.bold.red('[NPM]') + ' to install ' + module_name + ' ...');
var install_instance = spawn(cst.IS_WINDOWS ? 'npm.cmd' : 'npm', ['install', module_name, '--loglevel=error'], {
stdio : 'inherit',
env: process.env,
shell : true,
cwd : node_module_path
});
install_instance.on('close', function(code) {
if (code > 0)
return cb(new Error('Module install failed'));
return cb(null);
});
install_instance.on('error', function (err) {
console.error(err.stack || err);
});
};

View File

@@ -0,0 +1,148 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
var path = require('path');
var eachLimit = require('async/eachLimit');
var forEachLimit = require('async/forEachLimit');
var Configuration = require('../../Configuration.js');
var cst = require('../../../constants.js');
var Common = require('../../Common');
var NPM = require('./NPM.js')
var TAR = require('./TAR.js')
var LOCAL = require('./LOCAL.js')
var Modularizer = module.exports = {};
/**
* PM2 Module System.
*/
Modularizer.install = function (CLI, module_name, opts, cb) {
module_name = module_name.replace(/[;`|]/g, "");
if (typeof(opts) == 'function') {
cb = opts;
opts = {};
}
if (LOCAL.INTERNAL_MODULES.hasOwnProperty(module_name)) {
Common.logMod(`Adding dependency ${module_name} to PM2 Runtime`);
var currentModule = LOCAL.INTERNAL_MODULES[module_name];
if (currentModule && currentModule.hasOwnProperty('dependencies')) {
LOCAL.installMultipleModules(currentModule.dependencies, cb);
} else {
LOCAL.install(currentModule, cb);
}
}
else if (module_name == '.') {
Common.logMod(`Installing local NPM module`);
return NPM.localStart(CLI, opts, cb)
}
else if (opts.tarball || /\.tar\.gz$/i.test(module_name)) {
Common.logMod(`Installing TAR module`);
TAR.install(CLI, module_name, opts, cb)
}
else {
Common.logMod(`Installing NPM ${module_name} module`);
NPM.install(CLI, module_name, opts, cb)
}
};
/**
* Launch All Modules
* Used PM2 at startup
*/
Modularizer.launchModules = function(CLI, cb) {
var modules = Modularizer.listModules();
if (!modules) return cb();
// 1#
function launchNPMModules(cb) {
if (!modules.npm_modules) return launchTARModules(cb)
eachLimit(Object.keys(modules.npm_modules), 1, function(module_name, next) {
NPM.start(CLI, modules, module_name, next)
}, function() {
launchTARModules(cb)
});
}
// 2#
function launchTARModules(cb) {
if (!modules.tar_modules) return cb()
eachLimit(Object.keys(modules.tar_modules), 1, function(module_name, next) {
TAR.start(CLI, module_name, next)
}, function() {
return cb ? cb(null) : false;
});
}
launchNPMModules(cb)
}
Modularizer.package = function(CLI, module_path, cb) {
var fullpath = process.cwd()
if (module_path)
fullpath = require('path').resolve(module_path)
TAR.package(fullpath, process.cwd(), cb)
}
/**
* Uninstall module
*/
Modularizer.uninstall = function(CLI, module_name, cb) {
Common.printOut(cst.PREFIX_MSG_MOD + 'Uninstalling module ' + module_name);
var modules_list = Modularizer.listModules();
if (module_name == 'all') {
if (!modules_list) return cb();
return forEachLimit(Object.keys(modules_list.npm_modules), 1, function(module_name, next) {
NPM.uninstall(CLI, module_name, next)
}, () => {
forEachLimit(Object.keys(modules_list.tar_modules), 1, function(module_name, next) {
TAR.uninstall(CLI, module_name, next)
}, cb)
});
}
if (modules_list.npm_modules[module_name]) {
NPM.uninstall(CLI, module_name, cb)
} else if (modules_list.tar_modules[module_name]) {
TAR.uninstall(CLI, module_name, cb)
}
else {
Common.errMod('Unknown module')
CLI.exitCli(1)
}
};
/**
* List modules based on modules present in ~/.pm2/modules/ folder
*/
Modularizer.listModules = function() {
return {
npm_modules: Configuration.getSync(cst.MODULE_CONF_PREFIX) || {},
tar_modules: Configuration.getSync(cst.MODULE_CONF_PREFIX_TAR) || {}
}
};
Modularizer.getAdditionalConf = function(app_name) {
return NPM.getModuleConf(app_name)
};
Modularizer.publish = function(PM2, folder, opts, cb) {
if (opts.npm == true) {
NPM.publish(opts, cb)
}
else {
TAR.publish(PM2, folder, cb)
}
};
Modularizer.generateSample = function(app_name, cb) {
NPM.generateSample(app_name, cb)
};

437
api.hyungi.net/node_modules/pm2/lib/API/Modules/NPM.js generated vendored Normal file
View File

@@ -0,0 +1,437 @@
const path = require('path');
const fs = require('fs');
const os = require('os');
const spawn = require('child_process').spawn;
const chalk = require('chalk');
const readline = require('readline')
const which = require('../../tools/which.js')
const sexec = require('../../tools/sexec.js')
const copydirSync = require('../../tools/copydirSync.js')
const deleteFolderRecursive = require('../../tools/deleteFolderRecursive.js')
var Configuration = require('../../Configuration.js');
var cst = require('../../../constants.js');
var Common = require('../../Common');
var Utility = require('../../Utility.js');
module.exports = {
install,
uninstall,
start,
publish,
generateSample,
localStart,
getModuleConf
}
/**
* PM2 Module System.
* Features:
* - Installed modules are listed separately from user applications
* - Always ON, a module is always up along PM2, to stop it, you need to uninstall it
* - Install a runnable module from NPM/Github/HTTP (require a package.json only)
* - Some modules add internal PM2 depencencies (like typescript, profiling...)
* - Internally it uses NPM install (https://docs.npmjs.com/cli/install)
* - Auto discover script to launch (first it checks the apps field, then bin and finally main attr)
* - Generate sample module via pm2 module:generate <module_name>
*/
function localStart(PM2, opts, cb) {
var proc_path = '',
cmd = '',
conf = {};
Common.printOut(cst.PREFIX_MSG_MOD + 'Installing local module in DEVELOPMENT MODE with WATCH auto restart');
proc_path = process.cwd();
cmd = path.join(proc_path, cst.DEFAULT_MODULE_JSON);
Common.extend(opts, {
cmd : cmd,
development_mode : true,
proc_path : proc_path
});
return StartModule(PM2, opts, function(err, dt) {
if (err) return cb(err);
Common.printOut(cst.PREFIX_MSG_MOD + 'Module successfully installed and launched');
return cb(null, dt);
});
}
function generateSample(app_name, cb) {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
function samplize(module_name) {
var cmd1 = 'git clone https://github.com/pm2-hive/sample-module.git ' + module_name + '; cd ' + module_name + '; rm -rf .git';
var cmd2 = 'cd ' + module_name + ' ; sed -i "s:sample-module:'+ module_name +':g" package.json';
var cmd3 = 'cd ' + module_name + ' ; npm install';
Common.printOut(cst.PREFIX_MSG_MOD + 'Getting sample app');
sexec(cmd1, function(err) {
if (err) Common.printError(cst.PREFIX_MSG_MOD_ERR + err.message);
sexec(cmd2, function(err) {
console.log('');
sexec(cmd3, function(err) {
console.log('');
Common.printOut(cst.PREFIX_MSG_MOD + 'Module sample created in folder: ', path.join(process.cwd(), module_name));
console.log('');
Common.printOut('Start module in development mode:');
Common.printOut('$ cd ' + module_name + '/');
Common.printOut('$ pm2 install . ');
console.log('');
Common.printOut('Module Log: ');
Common.printOut('$ pm2 logs ' + module_name);
console.log('');
Common.printOut('Uninstall module: ');
Common.printOut('$ pm2 uninstall ' + module_name);
console.log('');
Common.printOut('Force restart: ');
Common.printOut('$ pm2 restart ' + module_name);
return cb ? cb() : false;
});
});
});
}
if (app_name) return samplize(app_name);
rl.question(cst.PREFIX_MSG_MOD + "Module name: ", function(module_name) {
samplize(module_name);
});
}
function publish(opts, cb) {
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
var semver = require('semver');
var package_file = path.join(process.cwd(), 'package.json');
var package_json = require(package_file);
package_json.version = semver.inc(package_json.version, 'minor');
Common.printOut(cst.PREFIX_MSG_MOD + 'Incrementing module to: %s@%s',
package_json.name,
package_json.version);
rl.question("Write & Publish? [Y/N]", function(answer) {
if (answer != "Y")
return cb();
fs.writeFile(package_file, JSON.stringify(package_json, null, 2), function(err, data) {
if (err) return cb(err);
Common.printOut(cst.PREFIX_MSG_MOD + 'Publishing module - %s@%s',
package_json.name,
package_json.version);
sexec('npm publish', function(code) {
Common.printOut(cst.PREFIX_MSG_MOD + 'Module - %s@%s successfully published',
package_json.name,
package_json.version);
Common.printOut(cst.PREFIX_MSG_MOD + 'Pushing module on Git');
sexec('git add . ; git commit -m "' + package_json.version + '"; git push origin master', function(code) {
Common.printOut(cst.PREFIX_MSG_MOD + 'Installable with pm2 install %s', package_json.name);
return cb(null, package_json);
});
});
});
});
}
function moduleExistInLocalDB(CLI, module_name, cb) {
var modules = Configuration.getSync(cst.MODULE_CONF_PREFIX);
if (!modules) return cb(false);
var module_name_only = Utility.getCanonicModuleName(module_name)
modules = Object.keys(modules);
return cb(modules.indexOf(module_name_only) > -1 ? true : false);
};
function install(CLI, module_name, opts, cb) {
moduleExistInLocalDB(CLI, module_name, function (exists) {
if (exists) {
Common.logMod('Module already installed. Updating.');
Rollback.backup(module_name);
return uninstall(CLI, module_name, function () {
return continueInstall(CLI, module_name, opts, cb);
});
}
return continueInstall(CLI, module_name, opts, cb);
})
}
// Builtin Node Switch
function getNPMCommandLine(module_name, install_path) {
if (which('npm')) {
return spawn.bind(this, cst.IS_WINDOWS ? 'npm.cmd' : 'npm', ['install', module_name, '--loglevel=error', '--prefix', `"${install_path}"` ], {
stdio : 'inherit',
env: process.env,
windowsHide: true,
shell : true
})
}
else {
return spawn.bind(this, cst.BUILTIN_NODE_PATH, [cst.BUILTIN_NPM_PATH, 'install', module_name, '--loglevel=error', '--prefix', `"${install_path}"`], {
stdio : 'inherit',
env: process.env,
windowsHide: true,
shell : true
})
}
}
function continueInstall(CLI, module_name, opts, cb) {
Common.printOut(cst.PREFIX_MSG_MOD + 'Calling ' + chalk.bold.red('[NPM]') + ' to install ' + module_name + ' ...');
var canonic_module_name = Utility.getCanonicModuleName(module_name);
var install_path = path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name);
require('mkdirp')(install_path)
.then(function() {
process.chdir(os.homedir());
var install_instance = getNPMCommandLine(module_name, install_path)();
install_instance.on('close', finalizeInstall);
install_instance.on('error', function (err) {
console.error(err.stack || err);
});
});
function finalizeInstall(code) {
if (code != 0) {
// If install has failed, revert to previous module version
return Rollback.revert(CLI, module_name, function() {
return cb(new Error('Installation failed via NPM, module has been restored to prev version'));
});
}
Common.printOut(cst.PREFIX_MSG_MOD + 'Module downloaded');
var proc_path = path.join(install_path, 'node_modules', canonic_module_name);
var package_json_path = path.join(proc_path, 'package.json');
// Append default configuration to module configuration
try {
var conf = JSON.parse(fs.readFileSync(package_json_path).toString()).config;
if (conf) {
Object.keys(conf).forEach(function(key) {
Configuration.setSyncIfNotExist(canonic_module_name + ':' + key, conf[key]);
});
}
} catch(e) {
Common.printError(e);
}
opts = Common.extend(opts, {
cmd : package_json_path,
development_mode : false,
proc_path : proc_path
});
Configuration.set(cst.MODULE_CONF_PREFIX + ':' + canonic_module_name, {
uid : opts.uid,
gid : opts.gid
}, function(err, data) {
if (err) return cb(err);
StartModule(CLI, opts, function(err, dt) {
if (err) return cb(err);
if (process.env.PM2_PROGRAMMATIC === 'true')
return cb(null, dt);
CLI.conf(canonic_module_name, function() {
Common.printOut(cst.PREFIX_MSG_MOD + 'Module successfully installed and launched');
Common.printOut(cst.PREFIX_MSG_MOD + 'Checkout module options: `$ pm2 conf`');
return cb(null, dt);
});
});
});
}
}
function start(PM2, modules, module_name, cb) {
Common.printOut(cst.PREFIX_MSG_MOD + 'Starting NPM module ' + module_name);
var install_path = path.join(cst.DEFAULT_MODULE_PATH, module_name);
var proc_path = path.join(install_path, 'node_modules', module_name);
var package_json_path = path.join(proc_path, 'package.json');
var opts = {};
// Merge with embedded configuration inside module_conf (uid, gid)
Common.extend(opts, modules[module_name]);
// Merge meta data to start module properly
Common.extend(opts, {
// package.json path
cmd : package_json_path,
// starting mode
development_mode : false,
// process cwd
proc_path : proc_path
});
StartModule(PM2, opts, function(err, dt) {
if (err) console.error(err);
return cb();
})
}
function uninstall(CLI, module_name, cb) {
var module_name_only = Utility.getCanonicModuleName(module_name)
var proc_path = path.join(cst.DEFAULT_MODULE_PATH, module_name_only);
Configuration.unsetSync(cst.MODULE_CONF_PREFIX + ':' + module_name_only);
CLI.deleteModule(module_name_only, function(err, data) {
console.log('Deleting', proc_path)
if (module_name != '.' && proc_path.includes('modules') === true) {
deleteFolderRecursive(proc_path)
}
if (err) {
Common.printError(err);
return cb(err);
}
return cb(null, data);
});
}
function getModuleConf(app_name) {
if (!app_name) throw new Error('No app_name defined');
var module_conf = Configuration.getAllSync();
var additional_env = {};
if (!module_conf[app_name]) {
additional_env = {};
additional_env[app_name] = {};
}
else {
additional_env = Common.clone(module_conf[app_name]);
additional_env[app_name] = JSON.stringify(module_conf[app_name]);
}
return additional_env;
}
function StartModule(CLI, opts, cb) {
if (!opts.cmd && !opts.package) throw new Error('module package.json not defined');
if (!opts.development_mode) opts.development_mode = false;
var package_json = require(opts.cmd || opts.package);
/**
* Script file detection
* 1- *apps* field (default pm2 json configuration)
* 2- *bin* field
* 3- *main* field
*/
if (!package_json.apps && !package_json.pm2) {
package_json.apps = {};
if (package_json.bin) {
var bin = Object.keys(package_json.bin)[0];
package_json.apps.script = package_json.bin[bin];
}
else if (package_json.main) {
package_json.apps.script = package_json.main;
}
}
Common.extend(opts, {
cwd : opts.proc_path,
watch : opts.development_mode,
force_name : package_json.name,
started_as_module : true
});
// Start the module
CLI.start(package_json, opts, function(err, data) {
if (err) return cb(err);
if (opts.safe) {
Common.printOut(cst.PREFIX_MSG_MOD + 'Monitoring module behavior for potential issue (5secs...)');
var time = typeof(opts.safe) == 'boolean' ? 3000 : parseInt(opts.safe);
return setTimeout(function() {
CLI.describe(package_json.name, function(err, apps) {
if (err || apps[0].pm2_env.restart_time > 2) {
return Rollback.revert(CLI, package_json.name, function() {
return cb(new Error('New Module is instable, restored to previous version'));
});
}
return cb(null, data);
});
}, time);
}
return cb(null, data);
});
};
var Rollback = {
revert : function(CLI, module_name, cb) {
var canonic_module_name = Utility.getCanonicModuleName(module_name);
var backup_path = path.join(require('os').tmpdir(), canonic_module_name);
var module_path = path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name);
try {
fs.statSync(backup_path)
} catch(e) {
return cb(new Error('no backup found'));
}
Common.printOut(cst.PREFIX_MSG_MOD + chalk.bold.red('[[[[[ Module installation failure! ]]]]]'));
Common.printOut(cst.PREFIX_MSG_MOD + chalk.bold.red('[RESTORING TO PREVIOUS VERSION]'));
CLI.deleteModule(canonic_module_name, function() {
// Delete failing module
if (module_name.includes('modules') === true)
deleteFolderRecursive(module_path)
// Restore working version
copydirSync(backup_path, path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name));
var proc_path = path.join(module_path, 'node_modules', canonic_module_name);
var package_json_path = path.join(proc_path, 'package.json');
// Start module
StartModule(CLI, {
cmd : package_json_path,
development_mode : false,
proc_path : proc_path
}, cb);
});
},
backup : function(module_name) {
// Backup current module
var tmpdir = require('os').tmpdir();
var canonic_module_name = Utility.getCanonicModuleName(module_name);
var module_path = path.join(cst.DEFAULT_MODULE_PATH, canonic_module_name);
copydirSync(module_path, path.join(tmpdir, canonic_module_name));
}
}

362
api.hyungi.net/node_modules/pm2/lib/API/Modules/TAR.js generated vendored Normal file
View File

@@ -0,0 +1,362 @@
var Configuration = require('../../Configuration.js');
var cst = require('../../../constants.js');
var Common = require('../../Common');
var forEachLimit = require('async/forEachLimit');
const sexec = require('../../tools/sexec.js');
const deleteFolderRecursive = require('../../tools/deleteFolderRecursive.js');
var path = require('path');
var fs = require('fs');
var os = require('os');
var spawn = require('child_process').spawn;
var exec = require('child_process').exec;
var execSync = require('child_process').execSync;
module.exports = {
install,
uninstall,
start,
publish,
packager
}
/**
* Module management to manage tarball packages
*
* pm2 install http.tar.gz
* pm2 uninstall http
*
* - the first and only folder in the tarball must be called module (tar zcvf http module/)
* - a package.json must be present with attribute "name", "version" and "pm2" to declare apps to run
*/
function install(PM2, module_filepath, opts, cb) {
// Remote file retrieval
if (module_filepath.includes('http') === true) {
var target_file = module_filepath.split('/').pop()
var target_filepath = path.join(os.tmpdir(), target_file)
opts.install_url = module_filepath
return retrieveRemote(module_filepath, target_filepath, (err) => {
if (err) {
Common.errMod(err)
process.exit(1)
}
installLocal(PM2, target_filepath, opts, cb)
})
}
// Local install
installLocal(PM2, module_filepath, opts, cb)
}
function retrieveRemote(url, dest, cb) {
Common.logMod(`Retrieving remote package ${url}...`)
var wget = spawn('wget', [url, '-O', dest, '-q'], {
stdio : 'inherit',
env: process.env,
windowsHide: true,
shell : true
})
wget.on('error', (err) => {
console.error(err.stack || err)
})
wget.on('close', (code) => {
if (code !== 0)
return cb(new Error('Could not download'))
return cb(null)
})
}
function installLocal(PM2, module_filepath, opts, cb) {
Common.logMod(`Installing package ${module_filepath}`)
// Get module name by unpacking the module/package.json only and read the name attribute
getModuleName(module_filepath, function(err, module_name) {
if (err) return cb(err)
Common.logMod(`Module name is ${module_name}`)
Common.logMod(`Depackaging module...`)
var install_path = path.join(cst.DEFAULT_MODULE_PATH, module_name);
require('mkdirp').sync(install_path)
var install_instance = spawn('tar', ['zxf', module_filepath, '-C', install_path, '--strip-components 1'], {
stdio : 'inherit',
env: process.env,
shell : true
})
install_instance.on('close', function(code) {
Common.logMod(`Module depackaged in ${install_path}`)
if (code == 0)
return runInstall(PM2, install_path, module_name, opts, cb)
return PM2.exitCli(1)
});
install_instance.on('error', function (err) {
console.error(err.stack || err);
});
})
}
function deleteModulePath(module_name) {
var sanitized = module_name.replace(/\./g, '')
deleteFolderRecursive(path.join(cst.DEFAULT_MODULE_PATH, module_name));
}
function runInstall(PM2, target_path, module_name, opts, cb) {
var config_file = path.join(target_path, 'package.json')
var conf
try {
conf = require(config_file)
module_name = conf.name
} catch(e) {
Common.errMod(new Error('Cannot find package.json file with name attribute at least'));
}
// Force with the name in the package.json
opts.started_as_module = true
opts.cwd = target_path
if (needPrefix(conf))
opts.name_prefix = module_name
if (opts.install) {
Common.logMod(`Running YARN install...`)
sexec(`cd ${target_path} ; yarn install`, {silent: false}, function(code) {
// Start apps under "apps" or "pm2" attribute
Common.logMod(`Starting ${target_path}`)
PM2.start(conf, opts, function(err, data) {
if (err) return cb(err)
Configuration.setSync(`${cst.MODULE_CONF_PREFIX_TAR}:${module_name}`, {
source: 'tarball',
install_url: opts.install_url,
installed_at: Date.now()
})
Common.logMod(`Module INSTALLED and STARTED`)
return cb(null, 'Module installed & Started')
})
})
}
else {
PM2.start(conf, opts, function(err, data) {
if (err) return cb(err)
Configuration.setSync(`${cst.MODULE_CONF_PREFIX_TAR}:${module_name}`, {
source: 'tarball',
install_url: opts.install_url,
installed_at: Date.now()
})
Common.logMod(`Module INSTALLED and STARTED`)
return cb(null, 'Module installed & Started')
})
}
}
function start(PM2, module_name, cb) {
var module_path = path.join(cst.DEFAULT_MODULE_PATH, module_name);
Common.printOut(cst.PREFIX_MSG_MOD + 'Starting TAR module ' + module_name);
var package_json_path = path.join(module_path, 'package.json');
var module_conf = Configuration.getSync(`${cst.MODULE_CONF_PREFIX_TAR}:${module_name}`)
try {
var conf = require(package_json_path)
} catch(e) {
Common.printError(`Could not find package.json as ${package_json_path}`)
return cb()
}
var opts = {};
opts.started_as_module = true
opts.cwd = module_path
if (module_conf.install_url)
opts.install_url = module_conf.install_url
if (needPrefix(conf))
opts.name_prefix = module_name
PM2.start(conf, opts, function(err, data) {
if (err) {
Common.printError(`Could not start ${module_name} ${module_path}`)
return cb()
}
Common.printOut(`${cst.PREFIX_MSG_MOD} Module ${module_name} STARTED`)
return cb();
})
}
/**
* Retrieve from module package.json the name of each application
* delete process and delete folder
*/
function uninstall(PM2, module_name, cb) {
var module_path = path.join(cst.DEFAULT_MODULE_PATH, module_name);
Common.logMod(`Removing ${module_name} from auto startup`)
try {
var pkg = require(path.join(module_path, 'package.json'))
} catch(e) {
Common.errMod('Could not retrieve module package.json');
return cb(e)
}
var apps = pkg.apps || pkg.pm2
apps = [].concat(apps);
/**
* Some time a module can have multiple processes
*/
forEachLimit(apps, 1, (app, next) => {
var app_name
if (!app.name) {
Common.renderApplicationName(app)
}
if (apps.length > 1)
app_name = `${module_name}:${app.name}`
else if (apps.length == 1 && pkg.name != apps[0].name)
app_name = `${module_name}:${app.name}`
else
app_name = app.name
PM2._operate('deleteProcessId', app_name, () => {
deleteModulePath(module_name)
next()
})
}, () => {
Configuration.unsetSync(`${cst.MODULE_CONF_PREFIX_TAR}:${module_name}`)
cb(null)
})
}
/**
* Uncompress only module/package.json and retrieve the "name" attribute in the package.json
*/
function getModuleName(module_filepath, cb) {
var tmp_folder = path.join(os.tmpdir(), cst.MODULE_BASEFOLDER)
var install_instance = spawn('tar', ['zxf', module_filepath, '-C', os.tmpdir(), `${cst.MODULE_BASEFOLDER}/package.json`], {
stdio : 'inherit',
env: process.env,
shell : true
})
install_instance.on('close', function(code) {
try {
var pkg = JSON.parse(fs.readFileSync(path.join(tmp_folder, `package.json`)))
return cb(null, pkg.name)
} catch(e) {
return cb(e)
}
});
}
function packager(module_path, target_path, cb) {
var base_folder = path.dirname(module_path)
var module_folder_name = path.basename(module_path)
var pkg = require(path.join(module_path, 'package.json'))
var pkg_name = `${module_folder_name}-v${pkg.version.replace(/\./g, '-')}.tar.gz`
var target_fullpath = path.join(target_path, pkg_name)
var cmd = `tar zcf ${target_fullpath} -C ${base_folder} --transform 's,${module_folder_name},module,' ${module_folder_name}`
Common.logMod(`Gziping ${module_path} to ${target_fullpath}`)
var tar = exec(cmd, (err, sto, ste) => {
if (err) {
console.log(sto.toString().trim())
console.log(ste.toString().trim())
}
})
tar.on('close', function (code) {
cb(code == 0 ? null : code, {
package_name: pkg_name,
path: target_fullpath
})
})
}
function publish(PM2, folder, cb) {
var target_folder = folder ? path.resolve(folder) : process.cwd()
try {
var pkg = JSON.parse(fs.readFileSync(path.join(target_folder, 'package.json')).toString())
} catch(e) {
Common.errMod(`${process.cwd()} module does not contain any package.json`)
process.exit(1)
}
if (!pkg.name) throw new Error('Attribute name should be present')
if (!pkg.version) throw new Error('Attribute version should be present')
if (!pkg.pm2 && !pkg.apps) throw new Error('Attribute apps should be present')
var current_path = target_folder
var module_name = path.basename(current_path)
var target_path = os.tmpdir()
Common.logMod(`Starting publishing procedure for ${module_name}@${pkg.version}`)
packager(current_path, target_path, (err, res) => {
if (err) {
Common.errMod('Can\'t package, exiting')
process.exit(1)
}
Common.logMod(`Package [${pkg.name}] created in path ${res.path}`)
var data = {
module_data: {
file: res.path,
content_type: 'content/gzip'
},
id: pkg.name,
name: pkg.name,
version: pkg.version
};
var uri = `${PM2.pm2_configuration.registry}/api/v1/modules`
Common.logMod(`Sending Package to remote ${pkg.name} ${uri}`)
require('needle')
.post(uri, data, { multipart: true }, function(err, res, body) {
if (err) {
Common.errMod(err)
process.exit(1)
}
if (res.statusCode !== 200) {
Common.errMod(`${pkg.name}-${pkg.version}: ${res.body.msg}`)
process.exit(1)
}
Common.logMod(`Module ${module_name} published under version ${pkg.version}`)
process.exit(0)
})
})
}
function needPrefix(conf) {
if ((conf.apps && conf.apps.length > 1) ||
(conf.pm2 && conf.pm2.length > 1) ||
(conf.apps.length == 1 && conf.name != conf.apps[0].name))
return true
return false
}

View File

@@ -0,0 +1,46 @@
var fs = require('fs');
var conf = require('../../../constants.js');
function find_extensions(folder, ext, ret)
{
try {
fs.accessSync(folder, fs.constants.R_OK);
} catch (err) {
return;
}
if(fs.statSync(folder).isDirectory() && folder.indexOf('node_modules') == -1 && (fs.statSync(folder)["mode"] & 4))
{
fs.readdirSync(folder).forEach(file => {
var tmp;
if(Number.parseInt(folder.lastIndexOf('/') + 1) === folder.length)
tmp = folder + file;
else
tmp = folder + '/' + file;
if(fs.statSync(tmp).isDirectory())
find_extensions(tmp, ext, ret);
else
{
var p = true;
for(var i = 0; i < ext.length;i++)
if(ext[i].test(file))
p = false;
if(p)
ret.push(folder + '/' + file);
}
});
}
}
module.exports.make_available_extension = function make_available_extension(opts, ret)
{
if(typeof opts == 'object' && typeof ret == 'object')
{
var mas = opts.ext.split(',');
for(var i = 0;i < mas.length;i++)
mas[i] = '.' + mas[i];
var res = [];
for(var i = 0;i < mas.length;i++)
res[i] = new RegExp(mas[i] + '$');
find_extensions(process.cwd(), res, ret);
}
}

View File

@@ -0,0 +1,120 @@
/***************************
*
* Module methods
*
**************************/
var cst = require('../../../constants.js');
var Common = require('../../Common.js');
var chalk = require('chalk');
var forEachLimit = require('async/forEachLimit');
var Modularizer = require('./Modularizer.js');
module.exports = function(CLI) {
/**
* Install / Update a module
*/
CLI.prototype.install = function(module_name, opts, cb) {
var that = this;
if (typeof(opts) == 'function') {
cb = opts;
opts = {};
}
Modularizer.install(this, module_name, opts, function(err, data) {
if (err) {
Common.printError(cst.PREFIX_MSG_ERR + (err.message || err));
return cb ? cb(Common.retErr(err)) : that.speedList(cst.ERROR_EXIT);
}
return cb ? cb(null, data) : that.speedList(cst.SUCCESS_EXIT);
});
};
/**
* Uninstall a module
*/
CLI.prototype.uninstall = function(module_name, cb) {
var that = this;
Modularizer.uninstall(this, module_name, function(err, data) {
if (err)
return cb ? cb(Common.retErr(err)) : that.speedList(cst.ERROR_EXIT);
return cb ? cb(null, data) : that.speedList(cst.SUCCESS_EXIT);
});
};
CLI.prototype.launchAll = function(CLI, cb) {
Modularizer.launchModules(CLI, cb);
};
CLI.prototype.package = function(module_path, cb) {
Modularizer.package(this, module_path, (err, res) => {
if (err) {
Common.errMod(err)
return cb ? cb(err) : this.exitCli(1)
}
Common.logMod(`Module packaged in ${res.path}`)
return cb ? cb(err) : this.exitCli(0)
})
};
/**
* Publish module on NPM + Git push
*/
CLI.prototype.publish = function(folder, opts, cb) {
var that = this;
Modularizer.publish(this, folder, opts, function(err, data) {
if (err)
return cb ? cb(Common.retErr(err)) : that.speedList(cst.ERROR_EXIT);
return cb ? cb(null, data) : that.speedList(cst.SUCCESS_EXIT);
});
};
/**
* Publish module on NPM + Git push
*/
CLI.prototype.generateModuleSample = function(app_name, cb) {
var that = this;
Modularizer.generateSample(app_name, function(err, data) {
if (err)
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
return cb ? cb(null, data) : that.exitCli(cst.SUCCESS_EXIT);
});
};
/**
* Special delete method
*/
CLI.prototype.deleteModule = function(module_name, cb) {
var that = this;
var found_proc = [];
this.Client.getAllProcess(function(err, procs) {
if (err) {
Common.printError('Error retrieving process list: ' + err);
return cb(Common.retErr(err));
}
procs.forEach(function(proc) {
if (proc.pm2_env.name == module_name && proc.pm2_env.pmx_module) {
found_proc.push(proc.pm_id);
}
});
if (found_proc.length == 0)
return cb();
that._operate('deleteProcessId', found_proc[0], function(err) {
if (err) return cb(Common.retErr(err));
Common.printOut('In memory process deleted');
return cb();
});
});
};
};

247
api.hyungi.net/node_modules/pm2/lib/API/Monit.js generated vendored Normal file
View File

@@ -0,0 +1,247 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
// pm2-htop
// Library who interacts with PM2 to display processes resources in htop way
// by Strzelewicz Alexandre
var multimeter = require('pm2-multimeter');
var os = require('os');
var p = require('path');
var chalk = require('chalk');
var UX = require('./UX');
var debug = require('debug')('pm2:monit');
// Cst for light programs
const RATIO_T1 = Math.floor(os.totalmem() / 500);
// Cst for medium programs
const RATIO_T2 = Math.floor(os.totalmem() / 50);
// Cst for heavy programs
const RATIO_T3 = Math.floor(os.totalmem() / 5);
// Cst for heavy programs
const RATIO_T4 = Math.floor(os.totalmem());
var Monit = {};
//helper to get bars.length (num bars printed)
Object.size = function(obj) {
var size = 0, key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
/**
* Reset the monitor through charm, basically \033c
* @param String msg optional message to show
* @return Monit
*/
Monit.reset = function(msg) {
this.multi.charm.reset();
this.multi.write('\x1B[32m⌬ PM2 \x1B[39mmonitoring\x1B[96m (To go further check out https://app.pm2.io) \x1B[39m\n\n');
if(msg) {
this.multi.write(msg);
}
this.bars = {};
return this;
}
/**
* Synchronous Monitor init method
* @method init
* @return Monit
*/
Monit.init = function() {
this.multi = multimeter(process);
this.multi.on('^C', this.stop);
this.reset();
return this;
}
/**
* Stops monitor
* @method stop
*/
Monit.stop = function() {
this.multi.charm.destroy();
process.exit(0);
}
/**
* Refresh monitor
* @method refresh
* @param {} processes
* @return this
*/
Monit.refresh = function(processes) {
debug('Monit refresh');
if(!processes) {
processes = [];
}
var num = processes.length;
this.num_bars = Object.size(this.bars);
if(num !== this.num_bars) {
debug('Monit addProcesses - actual: %s, new: %s', this.num_bars, num);
return this.addProcesses(processes);
} else {
if(num === 0) {
return;
}
debug('Monit refresh');
var proc;
for(var i = 0; i < num; i++) {
proc = processes[i];
//this is to avoid a print issue when the process is restarted for example
//we might also check for the pid but restarted|restarting will be rendered bad
if(this.bars[proc.pm_id] && proc.pm2_env.status !== this.bars[proc.pm_id].status) {
debug('bars for %s does not exist', proc.pm_id);
this.addProcesses(processes);
break;
}
this.updateBars(proc);
}
}
return this;
}
Monit.addProcess = function(proc, i) {
if(proc.pm_id in this.bars) {
return ;
}
if (proc.monit.error)
throw new Error(JSON.stringify(proc.monit.error));
var process_name = proc.pm2_env.name || p.basename(proc.pm2_env.pm_exec_path);
var status = proc.pm2_env.status == 'online' ? chalk.green.bold('●') : chalk.red.bold('●');
this.multi.write(' ' + status + ' ' + chalk.green.bold(process_name));
this.multi.write('\n');
this.multi.write('[' + proc.pm2_env.pm_id + '] [' + proc.pm2_env.exec_mode + ']\n');
var bar_cpu = this.multi(40, (i * 2) + 3 + i, {
width: 30,
solid: {
text: '|',
foreground: 'white',
background: 'blue'
},
empty: {
text: ' '
}
});
var bar_memory = this.multi(40, (i * 2) + 4 + i, {
width: 30,
solid: {
text: '|',
foreground: 'white',
background: 'red'
},
empty: {
text: ' '
}
});
this.bars[proc.pm_id] = {
memory: bar_memory,
cpu: bar_cpu,
status: proc.pm2_env.status
};
this.updateBars(proc);
this.multi.write('\n');
return this;
}
Monit.addProcesses = function(processes) {
if(!processes) {
processes = [];
}
this.reset();
var num = processes.length;
if(num > 0) {
for(var i = 0; i < num; i++) {
this.addProcess(processes[i], i);
}
} else {
this.reset('No processes to monit');
}
}
// Draw memory bars
/**
* Description
* @method drawRatio
* @param {} bar_memory
* @param {} memory
* @return
*/
Monit.drawRatio = function(bar_memory, memory) {
var scale = 0;
if (memory < RATIO_T1) scale = RATIO_T1;
else if (memory < RATIO_T2) scale = RATIO_T2;
else if (memory < RATIO_T3) scale = RATIO_T3;
else scale = RATIO_T4;
bar_memory.ratio(memory,
scale,
UX.helpers.bytesToSize(memory, 3));
};
/**
* Updates bars informations
* @param {} proc proc object
* @return this
*/
Monit.updateBars = function(proc) {
if (this.bars[proc.pm_id]) {
if (proc.pm2_env.status !== 'online' || proc.pm2_env.status !== this.bars[proc.pm_id].status) {
this.bars[proc.pm_id].cpu.percent(0, chalk.red(proc.pm2_env.status));
this.drawRatio(this.bars[proc.pm_id].memory, 0, chalk.red(proc.pm2_env.status));
} else if (!proc.monit) {
this.bars[proc.pm_id].cpu.percent(0, chalk.red('No data'));
this.drawRatio(this.bars[proc.pm_id].memory, 0, chalk.red('No data'));
} else {
this.bars[proc.pm_id].cpu.percent(proc.monit.cpu);
this.drawRatio(this.bars[proc.pm_id].memory, proc.monit.memory);
}
}
return this;
}
module.exports = Monit;

342
api.hyungi.net/node_modules/pm2/lib/API/Serve.js generated vendored Normal file
View File

@@ -0,0 +1,342 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
'use strict';
var fs = require('fs');
var http = require('http');
var url = require('url');
var path = require('path');
var debug = require('debug')('pm2:serve');
var probe = require('@pm2/io');
var errorMeter = probe.meter({
name : '404/sec',
samples : 1,
timeframe : 60
})
/**
* list of supported content types.
*/
var contentTypes = {
'3gp': 'video/3gpp',
'a': 'application/octet-stream',
'ai': 'application/postscript',
'aif': 'audio/x-aiff',
'aiff': 'audio/x-aiff',
'asc': 'application/pgp-signature',
'asf': 'video/x-ms-asf',
'asm': 'text/x-asm',
'asx': 'video/x-ms-asf',
'atom': 'application/atom+xml',
'au': 'audio/basic',
'avi': 'video/x-msvideo',
'bat': 'application/x-msdownload',
'bin': 'application/octet-stream',
'bmp': 'image/bmp',
'bz2': 'application/x-bzip2',
'c': 'text/x-c',
'cab': 'application/vnd.ms-cab-compressed',
'cc': 'text/x-c',
'chm': 'application/vnd.ms-htmlhelp',
'class': 'application/octet-stream',
'com': 'application/x-msdownload',
'conf': 'text/plain',
'cpp': 'text/x-c',
'crt': 'application/x-x509-ca-cert',
'css': 'text/css',
'csv': 'text/csv',
'cxx': 'text/x-c',
'deb': 'application/x-debian-package',
'der': 'application/x-x509-ca-cert',
'diff': 'text/x-diff',
'djv': 'image/vnd.djvu',
'djvu': 'image/vnd.djvu',
'dll': 'application/x-msdownload',
'dmg': 'application/octet-stream',
'doc': 'application/msword',
'dot': 'application/msword',
'dtd': 'application/xml-dtd',
'dvi': 'application/x-dvi',
'ear': 'application/java-archive',
'eml': 'message/rfc822',
'eps': 'application/postscript',
'exe': 'application/x-msdownload',
'f': 'text/x-fortran',
'f77': 'text/x-fortran',
'f90': 'text/x-fortran',
'flv': 'video/x-flv',
'for': 'text/x-fortran',
'gem': 'application/octet-stream',
'gemspec': 'text/x-script.ruby',
'gif': 'image/gif',
'gz': 'application/x-gzip',
'h': 'text/x-c',
'hh': 'text/x-c',
'htm': 'text/html',
'html': 'text/html',
'ico': 'image/vnd.microsoft.icon',
'ics': 'text/calendar',
'ifb': 'text/calendar',
'iso': 'application/octet-stream',
'jar': 'application/java-archive',
'java': 'text/x-java-source',
'jnlp': 'application/x-java-jnlp-file',
'jpeg': 'image/jpeg',
'jpg': 'image/jpeg',
'js': 'application/javascript',
'json': 'application/json',
'log': 'text/plain',
'm3u': 'audio/x-mpegurl',
'm4v': 'video/mp4',
'man': 'text/troff',
'mathml': 'application/mathml+xml',
'mbox': 'application/mbox',
'mdoc': 'text/troff',
'me': 'text/troff',
'mid': 'audio/midi',
'midi': 'audio/midi',
'mime': 'message/rfc822',
'mml': 'application/mathml+xml',
'mng': 'video/x-mng',
'mov': 'video/quicktime',
'mp3': 'audio/mpeg',
'mp4': 'video/mp4',
'mp4v': 'video/mp4',
'mpeg': 'video/mpeg',
'mpg': 'video/mpeg',
'ms': 'text/troff',
'msi': 'application/x-msdownload',
'odp': 'application/vnd.oasis.opendocument.presentation',
'ods': 'application/vnd.oasis.opendocument.spreadsheet',
'odt': 'application/vnd.oasis.opendocument.text',
'ogg': 'application/ogg',
'p': 'text/x-pascal',
'pas': 'text/x-pascal',
'pbm': 'image/x-portable-bitmap',
'pdf': 'application/pdf',
'pem': 'application/x-x509-ca-cert',
'pgm': 'image/x-portable-graymap',
'pgp': 'application/pgp-encrypted',
'pkg': 'application/octet-stream',
'pl': 'text/x-script.perl',
'pm': 'text/x-script.perl-module',
'png': 'image/png',
'pnm': 'image/x-portable-anymap',
'ppm': 'image/x-portable-pixmap',
'pps': 'application/vnd.ms-powerpoint',
'ppt': 'application/vnd.ms-powerpoint',
'ps': 'application/postscript',
'psd': 'image/vnd.adobe.photoshop',
'py': 'text/x-script.python',
'qt': 'video/quicktime',
'ra': 'audio/x-pn-realaudio',
'rake': 'text/x-script.ruby',
'ram': 'audio/x-pn-realaudio',
'rar': 'application/x-rar-compressed',
'rb': 'text/x-script.ruby',
'rdf': 'application/rdf+xml',
'roff': 'text/troff',
'rpm': 'application/x-redhat-package-manager',
'rss': 'application/rss+xml',
'rtf': 'application/rtf',
'ru': 'text/x-script.ruby',
's': 'text/x-asm',
'sgm': 'text/sgml',
'sgml': 'text/sgml',
'sh': 'application/x-sh',
'sig': 'application/pgp-signature',
'snd': 'audio/basic',
'so': 'application/octet-stream',
'svg': 'image/svg+xml',
'svgz': 'image/svg+xml',
'swf': 'application/x-shockwave-flash',
't': 'text/troff',
'tar': 'application/x-tar',
'tbz': 'application/x-bzip-compressed-tar',
'tcl': 'application/x-tcl',
'tex': 'application/x-tex',
'texi': 'application/x-texinfo',
'texinfo': 'application/x-texinfo',
'text': 'text/plain',
'tif': 'image/tiff',
'tiff': 'image/tiff',
'torrent': 'application/x-bittorrent',
'tr': 'text/troff',
'txt': 'text/plain',
'vcf': 'text/x-vcard',
'vcs': 'text/x-vcalendar',
'vrml': 'model/vrml',
'war': 'application/java-archive',
'wav': 'audio/x-wav',
'wma': 'audio/x-ms-wma',
'wmv': 'video/x-ms-wmv',
'wmx': 'video/x-ms-wmx',
'wrl': 'model/vrml',
'wsdl': 'application/wsdl+xml',
'xbm': 'image/x-xbitmap',
'xhtml': 'application/xhtml+xml',
'xls': 'application/vnd.ms-excel',
'xml': 'application/xml',
'xpm': 'image/x-xpixmap',
'xsl': 'application/xml',
'xslt': 'application/xslt+xml',
'yaml': 'text/yaml',
'yml': 'text/yaml',
'zip': 'application/zip',
'woff': 'application/font-woff',
'woff2': 'application/font-woff',
'otf': 'application/font-sfnt',
'otc': 'application/font-sfnt',
'ttf': 'application/font-sfnt'
};
var options = {
port: process.env.PM2_SERVE_PORT || process.argv[3] || 8080,
host: process.env.PM2_SERVE_HOST || process.argv[4] || '0.0.0.0',
path: path.resolve(process.env.PM2_SERVE_PATH || process.argv[2] || '.'),
spa: process.env.PM2_SERVE_SPA === 'true',
homepage: process.env.PM2_SERVE_HOMEPAGE || '/index.html',
basic_auth: process.env.PM2_SERVE_BASIC_AUTH === 'true' ? {
username: process.env.PM2_SERVE_BASIC_AUTH_USERNAME,
password: process.env.PM2_SERVE_BASIC_AUTH_PASSWORD
} : null,
monitor: process.env.PM2_SERVE_MONITOR
};
if (typeof options.port === 'string') {
options.port = parseInt(options.port) || 8080
}
if (typeof options.monitor === 'string' && options.monitor !== '') {
try {
let fileContent = fs.readFileSync(path.join(process.env.PM2_HOME, 'agent.json5')).toString()
// Handle old configuration with json5
fileContent = fileContent.replace(/\s(\w+):/g, '"$1":')
// parse
let conf = JSON.parse(fileContent)
options.monitorBucket = conf.public_key
} catch (e) {
console.log('Interaction file does not exist')
}
}
// start an HTTP server
http.createServer(function (request, response) {
if (options.basic_auth) {
if (!request.headers.authorization || request.headers.authorization.indexOf('Basic ') === -1) {
return sendBasicAuthResponse(response)
}
var user = parseBasicAuth(request.headers.authorization)
if (user.username !== options.basic_auth.username || user.password !== options.basic_auth.password) {
return sendBasicAuthResponse(response)
}
}
serveFile(request.url, request, response);
}).listen(options.port, options.host, function (err) {
if (err) {
console.error(err);
process.exit(1);
}
console.log('Exposing %s directory on %s:%d', options.path, options.host, options.port);
});
function serveFile(uri, request, response) {
var file = decodeURIComponent(url.parse(uri || request.url).pathname);
if (file === '/' || file === '') {
file = options.homepage;
request.wantHomepage = true;
}
var filePath = path.resolve(options.path + file);
// since we call filesystem directly so we need to verify that the
// url doesn't go outside the serve path
if (filePath.indexOf(options.path) !== 0) {
response.writeHead(403, { 'Content-Type': 'text/html' });
return response.end('403 Forbidden');
}
var contentType = contentTypes[filePath.split('.').pop().toLowerCase()] || 'text/plain';
fs.readFile(filePath, function (error, content) {
if (error) {
if ((!options.spa || file === options.homepage)) {
console.error('[%s] Error while serving %s with content-type %s : %s',
new Date(), filePath, contentType, error.message || error);
}
errorMeter.mark();
if (error.code === 'ENOENT') {
if (options.spa && !request.wantHomepage) {
request.wantHomepage = true;
return serveFile(`/${path.basename(file)}`, request, response);
} else if (options.spa && file !== options.homepage) {
return serveFile(options.homepage, request, response);
}
fs.readFile(options.path + '/404.html', function (err, content) {
content = err ? '404 Not Found' : content;
response.writeHead(404, { 'Content-Type': 'text/html' });
return response.end(content, 'utf-8');
});
return;
}
response.writeHead(500);
return response.end('Sorry, check with the site admin for error: ' + error.code + ' ..\n');
}
// Add CORS headers to allow browsers to fetch data directly
response.writeHead(200, {
'Content-Type': contentType,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET'
});
if (options.monitorBucket && contentType === 'text/html') {
content = content.toString().replace('</body>', `
<script>
;(function (b,e,n,o,i,t) {
b[o]=b[o]||function(f){(b[o].c=b[o].c||[]).push(f)};
t=e.createElement(i);e=e.getElementsByTagName(i)[0];
t.async=1;t.src=n;e.parentNode.insertBefore(t,e);
}(window,document,'https://apm.pm2.io/pm2-io-apm-browser.v1.js','pm2Ready','script'))
pm2Ready(function(apm) {
apm.setBucket('${options.monitorBucket}')
apm.setApplication('${options.monitor}')
apm.reportTimings()
apm.reportIssues()
})
</script>
</body>
`);
}
response.end(content, 'utf-8');
debug('[%s] Serving %s with content-type %s', Date.now(), filePath, contentType);
});
}
function parseBasicAuth(auth) {
// auth is like `Basic Y2hhcmxlczoxMjM0NQ==`
var tmp = auth.split(' ');
var buf = Buffer.from(tmp[1], 'base64');
var plain = buf.toString();
var creds = plain.split(':');
return {
username: creds[0],
password: creds[1]
}
}
function sendBasicAuthResponse(response) {
response.writeHead(401, {
'Content-Type': 'text/html',
'WWW-Authenticate': 'Basic realm="Authentication service"'
});
return response.end('401 Unauthorized');
}

616
api.hyungi.net/node_modules/pm2/lib/API/Startup.js generated vendored Normal file
View File

@@ -0,0 +1,616 @@
/**
* Copyright 2013-2022 the PM2 project authors. All rights reserved.
* Use of this source code is governed by a license that
* can be found in the LICENSE file.
*/
var chalk = require('chalk');
var path = require('path');
var fs = require('fs');
var forEachLimit = require('async/forEachLimit');
var eachLimit = require('async/eachLimit');
var Common = require('../Common.js');
var cst = require('../../constants.js');
var util = require('util');
var tmpPath = require('os').tmpdir;
var which = require('../tools/which.js');
var sexec = require('../tools/sexec')
module.exports = function(CLI) {
/**
* If command is launched without root right
* Display helper
*/
function isNotRoot(startup_mode, platform, opts, cb) {
Common.printOut(`${cst.PREFIX_MSG}To ${startup_mode} the Startup Script, copy/paste the following command:`);
if (opts.user) {
console.log('sudo env PATH=$PATH:' + path.dirname(process.execPath) + ' pm2 ' + opts.args[1].name() + ' ' + platform + ' -u ' + opts.user + ' --hp ' + process.env.HOME);
return cb(new Error('You have to run this with elevated rights'));
}
return sexec('whoami', {silent: true}, function(err, stdout, stderr) {
console.log('sudo env PATH=$PATH:' + path.dirname(process.execPath) + ' ' + require.main.filename + ' ' + opts.args[1].name() + ' ' + platform + ' -u ' + stdout.trim() + ' --hp ' + process.env.HOME);
return cb(new Error('You have to run this with elevated rights'));
});
}
/**
* Detect running init system
*/
function detectInitSystem() {
var hash_map = {
'systemctl' : 'systemd',
'update-rc.d': 'upstart',
'chkconfig' : 'systemv',
'rc-update' : 'openrc',
'launchctl' : 'launchd',
'sysrc' : 'rcd',
'rcctl' : 'rcd-openbsd',
'svcadm' : 'smf'
};
var init_systems = Object.keys(hash_map);
for (var i = 0; i < init_systems.length; i++) {
if (which(init_systems[i]) != null) {
break;
}
}
if (i >= init_systems.length) {
Common.printError(cst.PREFIX_MSG_ERR + 'Init system not found');
return null;
}
Common.printOut(cst.PREFIX_MSG + 'Init System found: ' + chalk.bold(hash_map[init_systems[i]]));
return hash_map[init_systems[i]];
}
CLI.prototype.uninstallStartup = function(platform, opts, cb) {
var commands;
var that = this;
var actual_platform = detectInitSystem();
var user = opts.user || process.env.USER || process.env.LOGNAME; // Use LOGNAME on Solaris-like systems
var service_name = (opts.serviceName || 'pm2-' + user);
var openrc_service_name = 'pm2';
var launchd_service_name = (opts.serviceName || 'pm2.' + user);
if (!platform)
platform = actual_platform;
else if (actual_platform && actual_platform !== platform) {
Common.printOut('-----------------------------------------------------------')
Common.printOut(' PM2 detected ' + actual_platform + ' but you precised ' + platform)
Common.printOut(' Please verify that your choice is indeed your init system')
Common.printOut(' If you arent sure, just run : pm2 startup')
Common.printOut('-----------------------------------------------------------')
}
if (platform === null)
throw new Error('Init system not found')
if (!cb) {
cb = function(err, data) {
if (err)
return that.exitCli(cst.ERROR_EXIT);
return that.exitCli(cst.SUCCESS_EXIT);
}
}
if (process.getuid() != 0) {
return isNotRoot('unsetup', platform, opts, cb);
}
if (fs.existsSync('/etc/init.d/pm2-init.sh')) {
platform = 'oldsystem';
}
switch(platform) {
case 'systemd':
commands = [
'systemctl stop ' + service_name,
'systemctl disable ' + service_name,
'rm /etc/systemd/system/' + service_name + '.service'
];
break;
case 'systemv':
commands = [
'chkconfig ' + service_name + ' off',
'rm /etc/init.d/' + service_name
];
break;
case 'oldsystem':
Common.printOut(cst.PREFIX_MSG + 'Disabling and deleting old startup system');
commands = [
'update-rc.d pm2-init.sh disable',
'update-rc.d -f pm2-init.sh remove',
'rm /etc/init.d/pm2-init.sh'
];
break;
case 'openrc':
service_name = openrc_service_name;
commands = [
'/etc/init.d/' + service_name + ' stop',
'rc-update delete ' + service_name + ' default',
'rm /etc/init.d/' + service_name
];
break;
case 'upstart':
commands = [
'update-rc.d ' + service_name + ' disable',
'update-rc.d -f ' + service_name + ' remove',
'rm /etc/init.d/' + service_name
];
break;
case 'launchd':
var destination = path.join(process.env.HOME, 'Library/LaunchAgents/' + launchd_service_name + '.plist');
commands = [
'launchctl remove ' + launchd_service_name + ' || true',
'rm ' + destination
];
break;
case 'rcd':
service_name = (opts.serviceName || 'pm2_' + user);
commands = [
'/usr/local/etc/rc.d/' + service_name + ' stop',
'sysrc -x ' + service_name + '_enable',
'rm /usr/local/etc/rc.d/' + service_name
];
break;
case 'rcd-openbsd':
service_name = (opts.serviceName || 'pm2_' + user);
var destination = path.join('/etc/rc.d', service_name);
commands = [
'rcctl stop ' + service_name,
'rcctl disable ' + service_name,
'rm ' + destination
];
break;
case 'smf':
service_name = (opts.serviceName || 'pm2_' + user);
commands = [
'svcadm disable ' + service_name,
'svccfg delete -f ' + service_name
]
};
sexec(commands.join('&& '), function(code, stdout, stderr) {
Common.printOut(stdout);
Common.printOut(stderr);
if (code == 0) {
Common.printOut(cst.PREFIX_MSG + chalk.bold('Init file disabled.'));
} else {
Common.printOut(cst.ERROR_MSG + chalk.bold('Return code : ' + code));
}
cb(null, {
commands : commands,
platform : platform
});
});
};
/**
* Startup script generation
* @method startup
* @param {string} platform type (centos|redhat|amazon|gentoo|systemd|smf)
*/
CLI.prototype.startup = function(platform, opts, cb) {
var that = this;
var actual_platform = detectInitSystem();
var user = (opts.user || process.env.USER || process.env.LOGNAME); // Use LOGNAME on Solaris-like systems
var service_name = (opts.serviceName || 'pm2-' + user);
var openrc_service_name = 'pm2';
var launchd_service_name = (opts.serviceName || 'pm2.' + user);
if (!platform)
platform = actual_platform;
else if (actual_platform && actual_platform !== platform) {
Common.printOut('-----------------------------------------------------------')
Common.printOut(' PM2 detected ' + actual_platform + ' but you precised ' + platform)
Common.printOut(' Please verify that your choice is indeed your init system')
Common.printOut(' If you arent sure, just run : pm2 startup')
Common.printOut('-----------------------------------------------------------')
}
if (platform == null)
throw new Error('Init system not found');
if (!cb) {
cb = function(err, data) {
if (err)
return that.exitCli(cst.ERROR_EXIT);
return that.exitCli(cst.SUCCESS_EXIT);
}
}
if (process.getuid() != 0) {
return isNotRoot('setup', platform, opts, cb);
}
var destination;
var commands;
var template;
function getTemplate(type) {
return fs.readFileSync(path.join(__dirname, '..', 'templates/init-scripts', type + '.tpl'), {encoding: 'utf8'});
}
switch(platform) {
case 'ubuntu':
case 'centos':
case 'arch':
case 'oracle':
case 'systemd':
if (opts.waitIp)
template = getTemplate('systemd-online');
else
template = getTemplate('systemd');
destination = '/etc/systemd/system/' + service_name + '.service';
commands = [
'systemctl enable ' + service_name
];
break;
case 'ubuntu14':
case 'ubuntu12':
case 'upstart':
template = getTemplate('upstart');
destination = '/etc/init.d/' + service_name;
commands = [
'chmod +x ' + destination,
'mkdir -p /var/lock/subsys',
'touch /var/lock/subsys/' + service_name,
'update-rc.d ' + service_name + ' defaults'
];
break;
case 'systemv':
case 'amazon':
case 'centos6':
template = getTemplate('upstart');
destination = '/etc/init.d/' + service_name;
commands = [
'chmod +x ' + destination,
'mkdir -p /var/lock/subsys',
'touch /var/lock/subsys/' + service_name,
'chkconfig --add ' + service_name,
'chkconfig ' + service_name + ' on',
'initctl list'
];
break;
case 'macos':
case 'darwin':
case 'launchd':
template = getTemplate('launchd');
destination = path.join(process.env.HOME, 'Library/LaunchAgents/' + launchd_service_name + '.plist');
commands = [
'mkdir -p ' + path.join(process.env.HOME, 'Library/LaunchAgents'),
'launchctl load -w ' + destination
]
break;
case 'freebsd':
case 'rcd':
template = getTemplate('rcd');
service_name = (opts.serviceName || 'pm2_' + user);
destination = '/usr/local/etc/rc.d/' + service_name;
commands = [
'chmod 755 ' + destination,
'sysrc ' + service_name + '_enable=YES'
];
break;
case 'openbsd':
case 'rcd-openbsd':
template = getTemplate('rcd-openbsd');
service_name = (opts.serviceName || 'pm2_' + user);
destination = path.join('/etc/rc.d/', service_name);
commands = [
'chmod 755 ' + destination,
'rcctl enable ' + service_name,
'rcctl start ' + service_name
];
break;
case 'openrc':
template = getTemplate('openrc');
service_name = openrc_service_name;
destination = '/etc/init.d/' + service_name;
commands = [
'chmod +x ' + destination,
'rc-update add ' + service_name + ' default'
];
break;
case 'smf':
case 'sunos':
case 'solaris':
template = getTemplate('smf');
service_name = (opts.serviceName || 'pm2_' + user);
destination = path.join(tmpPath(), service_name + '.xml');
commands = [
'svccfg import ' + destination,
'svcadm enable ' + service_name
];
break;
default:
throw new Error('Unknown platform / init system name');
}
/**
* 4# Replace template variable value
*/
var envPath
if (cst.HAS_NODE_EMBEDDED == true)
envPath = util.format('%s:%s', process.env.PATH || '', path.dirname(process.execPath))
else if (new RegExp(path.dirname(process.execPath)).test(process.env.PATH))
envPath = process.env.PATH
else
envPath = util.format('%s:%s', process.env.PATH || '', path.dirname(process.execPath))
template = template.replace(/%PM2_PATH%/g, process.mainModule.filename)
.replace(/%NODE_PATH%/g, envPath)
.replace(/%USER%/g, user)
.replace(/%HOME_PATH%/g, opts.hp ? path.resolve(opts.hp, '.pm2') : cst.PM2_ROOT_PATH)
.replace(/%SERVICE_NAME%/g, service_name);
Common.printOut(chalk.bold('Platform'), platform);
Common.printOut(chalk.bold('Template'));
Common.printOut(template);
Common.printOut(chalk.bold('Target path'));
Common.printOut(destination);
Common.printOut(chalk.bold('Command list'));
Common.printOut(commands);
Common.printOut(cst.PREFIX_MSG + 'Writing init configuration in ' + destination);
try {
fs.writeFileSync(destination, template);
} catch (e) {
console.error(cst.PREFIX_MSG_ERR + 'Failure when trying to write startup script');
console.error(e.message || e);
return cb(e);
}
Common.printOut(cst.PREFIX_MSG + 'Making script booting at startup...');
forEachLimit(commands, 1, function(command, next) {
Common.printOut(cst.PREFIX_MSG + '[-] Executing: %s...', chalk.bold(command));
sexec(command, function(code, stdout, stderr) {
if (code === 0) {
Common.printOut(cst.PREFIX_MSG + chalk.bold('[v] Command successfully executed.'));
return next();
} else {
Common.printOut(chalk.red('[ERROR] Exit code : ' + code))
return next(new Error(command + ' failed, see error above.'));
}
})
}, function(err) {
if (err) {
console.error(cst.PREFIX_MSG_ERR + (err.message || err));
return cb(err);
}
Common.printOut(chalk.bold.blue('+---------------------------------------+'));
Common.printOut(chalk.bold.blue((cst.PREFIX_MSG + 'Freeze a process list on reboot via:' )));
Common.printOut(chalk.bold('$ pm2 save'));
Common.printOut('');
Common.printOut(chalk.bold.blue(cst.PREFIX_MSG + 'Remove init script via:'));
Common.printOut(chalk.bold('$ pm2 unstartup ' + platform));
return cb(null, {
destination : destination,
template : template
});
});
};
/**
* DISABLED FEATURE
* KEEPING METHOD FOR BACKWARD COMPAT
*/
CLI.prototype.autodump = function(cb) {
return cb()
}
/**
* Dump current processes managed by pm2 into DUMP_FILE_PATH file
* @method dump
* @param {} cb
* @return
*/
CLI.prototype.dump = function(force, cb) {
var env_arr = [];
var that = this;
if (typeof(force) === 'function') {
cb = force
force = false
}
if (!cb)
Common.printOut(cst.PREFIX_MSG + 'Saving current process list...');
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
Common.printError('Error retrieving process list: ' + err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
/**
* Description
* @method fin
* @param {} err
* @return
*/
function fin(err) {
// try to fix issues with empty dump file
// like #3485
if (!force && env_arr.length === 0 && !process.env.FORCE) {
// fix : if no dump file, no process, only module and after pm2 update
if (!fs.existsSync(cst.DUMP_FILE_PATH)) {
that.clearDump(function(){});
}
// if no process in list don't modify dump file
// process list should not be empty
if (cb) {
return cb(new Error('Process list empty, cannot save empty list'));
} else {
Common.printOut(cst.PREFIX_MSG_WARNING + 'PM2 is not managing any process, skipping save...');
Common.printOut(cst.PREFIX_MSG_WARNING + 'To force saving use: pm2 save --force');
that.exitCli(cst.SUCCESS_EXIT);
return;
}
}
// Back up dump file
try {
if (fs.existsSync(cst.DUMP_FILE_PATH)) {
fs.writeFileSync(cst.DUMP_BACKUP_FILE_PATH, fs.readFileSync(cst.DUMP_FILE_PATH));
}
} catch (e) {
console.error(e.stack || e);
Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to back up dump file in %s', cst.DUMP_BACKUP_FILE_PATH);
}
// Overwrite dump file, delete if broken and exit
try {
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify(env_arr, '', 2));
} catch (e) {
console.error(e.stack || e);
try {
// try to backup file
if (fs.existsSync(cst.DUMP_BACKUP_FILE_PATH)) {
fs.writeFileSync(cst.DUMP_FILE_PATH, fs.readFileSync(cst.DUMP_BACKUP_FILE_PATH));
}
} catch (e) {
// don't keep broken file
fs.unlinkSync(cst.DUMP_FILE_PATH);
console.error(e.stack || e);
}
Common.printOut(cst.PREFIX_MSG_ERR + 'Failed to save dump file in %s', cst.DUMP_FILE_PATH);
return that.exitCli(cst.ERROR_EXIT);
}
if (cb) return cb(null, {success:true});
Common.printOut(cst.PREFIX_MSG + 'Successfully saved in %s', cst.DUMP_FILE_PATH);
return that.exitCli(cst.SUCCESS_EXIT);
}
(function ex(apps) {
if (!apps[0]) return fin(null);
delete apps[0].pm2_env.instances;
delete apps[0].pm2_env.pm_id;
delete apps[0].pm2_env.prev_restart_delay;
if (!apps[0].pm2_env.pmx_module)
env_arr.push(apps[0].pm2_env);
apps.shift();
return ex(apps);
})(list);
});
};
/**
* Remove DUMP_FILE_PATH file and DUMP_BACKUP_FILE_PATH file
* @method dump
* @param {} cb
* @return
*/
CLI.prototype.clearDump = function(cb) {
fs.writeFileSync(cst.DUMP_FILE_PATH, JSON.stringify([]));
if(cb && typeof cb === 'function') return cb();
Common.printOut(cst.PREFIX_MSG + 'Successfully created %s', cst.DUMP_FILE_PATH);
return this.exitCli(cst.SUCCESS_EXIT);
};
/**
* Resurrect processes
* @method resurrect
* @param {} cb
* @return
*/
CLI.prototype.resurrect = function(cb) {
var apps = {};
var that = this;
var processes;
function readDumpFile(dumpFilePath) {
Common.printOut(cst.PREFIX_MSG + 'Restoring processes located in %s', dumpFilePath);
try {
var apps = fs.readFileSync(dumpFilePath);
} catch (e) {
Common.printError(cst.PREFIX_MSG_ERR + 'Failed to read dump file in %s', dumpFilePath);
throw e;
}
return apps;
}
function parseDumpFile(dumpFilePath, apps) {
try {
var processes = Common.parseConfig(apps, 'none');
} catch (e) {
Common.printError(cst.PREFIX_MSG_ERR + 'Failed to parse dump file in %s', dumpFilePath);
try {
fs.unlinkSync(dumpFilePath);
} catch (e) {
console.error(e.stack || e);
}
throw e;
}
return processes;
}
// Read dump file, fall back to backup, delete if broken
try {
apps = readDumpFile(cst.DUMP_FILE_PATH);
processes = parseDumpFile(cst.DUMP_FILE_PATH, apps);
} catch(e) {
try {
apps = readDumpFile(cst.DUMP_BACKUP_FILE_PATH);
processes = parseDumpFile(cst.DUMP_BACKUP_FILE_PATH, apps);
} catch(e) {
Common.printError(cst.PREFIX_MSG_ERR + 'No processes saved; DUMP file doesn\'t exist');
// if (cb) return cb(Common.retErr(e));
// else return that.exitCli(cst.ERROR_EXIT);
return that.speedList();
}
}
that.Client.executeRemote('getMonitorData', {}, function(err, list) {
if (err) {
Common.printError(err);
return that.exitCli(1);
}
var current = [];
var target = [];
list.forEach(function(app) {
if (!current[app.name])
current[app.name] = 0;
current[app.name]++;
});
processes.forEach(function(app) {
if (!target[app.name])
target[app.name] = 0;
target[app.name]++;
});
var tostart = Object.keys(target).filter(function(i) {
return Object.keys(current).indexOf(i) < 0;
})
eachLimit(processes, cst.CONCURRENT_ACTIONS, function(app, next) {
if (tostart.indexOf(app.name) == -1)
return next();
that.Client.executeRemote('prepare', app, function(err, dt) {
if (err)
Common.printError(err);
else
Common.printOut(cst.PREFIX_MSG + 'Process %s restored', app.pm_exec_path);
next();
});
}, function(err) {
return cb ? cb(null, apps) : that.speedList();
});
});
};
}

213
api.hyungi.net/node_modules/pm2/lib/API/UX/helpers.js generated vendored Normal file
View File

@@ -0,0 +1,213 @@
const chalk = require('chalk')
const Helpers = {}
/**
* Converts Byte to Human readable size
* @method bytesToSize
* @param {} bytes
* @param {} precision
* @return
*/
Helpers.bytesToSize = function(bytes, precision) {
var kilobyte = 1024
var megabyte = kilobyte * 1024
var gigabyte = megabyte * 1024
var terabyte = gigabyte * 1024
if ((bytes >= 0) && (bytes < kilobyte)) {
return bytes + 'b '
} else if ((bytes >= kilobyte) && (bytes < megabyte)) {
return (bytes / kilobyte).toFixed(precision) + 'kb '
} else if ((bytes >= megabyte) && (bytes < gigabyte)) {
return (bytes / megabyte).toFixed(precision) + 'mb '
} else if ((bytes >= gigabyte) && (bytes < terabyte)) {
return (bytes / gigabyte).toFixed(precision) + 'gb '
} else if (bytes >= terabyte) {
return (bytes / terabyte).toFixed(precision) + 'tb '
} else {
return bytes + 'b '
}
}
/**
* Color Process state
* @method colorStatus
* @param {} status
* @return
*/
Helpers.colorStatus = function(status) {
switch (status) {
case 'online':
return chalk.green.bold('online')
break
case 'running':
return chalk.green.bold('online')
break
case 'restarting':
return chalk.yellow.bold('restart')
break
case 'created':
return chalk.yellow.bold('created')
break
case 'launching':
return chalk.blue.bold('launching')
break
default:
return chalk.red.bold(status)
}
}
/**
* Safe Push
*/
Helpers.safe_push = function() {
var argv = arguments
var table = argv[0]
for (var i = 1; i < argv.length; ++i) {
var elem = argv[i]
if (elem[Object.keys(elem)[0]] === undefined
|| elem[Object.keys(elem)[0]] === null) {
elem[Object.keys(elem)[0]] = 'N/A'
}
else if (Array.isArray(elem[Object.keys(elem)[0]])) {
elem[Object.keys(elem)[0]].forEach(function(curr, j) {
if (curr === undefined || curr === null)
elem[Object.keys(elem)[0]][j] = 'N/A'
})
}
table.push(elem)
}
}
/**
* Description
* @method timeSince
* @param {} date
* @return BinaryExpression
*/
Helpers.timeSince = function(date) {
var seconds = Math.floor((new Date() - date) / 1000)
var interval = Math.floor(seconds / 31536000)
if (interval > 1) {
return interval + 'Y'
}
interval = Math.floor(seconds / 2592000)
if (interval > 1) {
return interval + 'M'
}
interval = Math.floor(seconds / 86400)
if (interval > 1) {
return interval + 'D'
}
interval = Math.floor(seconds / 3600)
if (interval > 1) {
return interval + 'h'
}
interval = Math.floor(seconds / 60)
if (interval > 1) {
return interval + 'm'
}
return Math.floor(seconds) + 's'
}
/**
* Colorize Metrics
*
* @param {Number} value current value
* @param {Number} warn value threshold
* @param {Number} alert value threshold
* @param {String} prefix value prefix
* @return {String} value
*/
Helpers.colorizedMetric = function(value, warn, alert, prefix) {
var inverted = false
if (alert < warn)
inverted = true
if (!prefix) prefix = ''
if (isNaN(value) === true)
return 'N/A'
if (value == 0)
return 0 + prefix
if (inverted == true) {
if (value > warn)
return chalk.green(value + prefix)
if (value <= warn && value >= alert)
return chalk.bold.yellow(value + prefix)
return chalk.bold.red(value + prefix)
}
if (value < warn)
return chalk.green(value + prefix)
if (value >= warn && value <= alert)
return chalk.bold.yellow(value + prefix)
return chalk.bold.red(value + prefix)
}
/**
* Get nested property
*
* @param {String} propertyName
* @param {Object} obj
* @returns {String} property value
*/
Helpers.getNestedProperty = function(propertyName, obj) {
var parts = propertyName.split('.'),
length = parts.length,
property = obj || {}
for (var i = 0; i < length; i++ ) {
property = property[parts[i]]
}
return property
}
Helpers.openEditor = function (file, opts, cb) {
var spawn = require('child_process').spawn
if (typeof opts === 'function') {
cb = opts
opts = {}
}
if (!opts) opts = {}
var ed = /^win/.test(process.platform) ? 'notepad' : 'vim'
var editor = opts.editor || process.env.VISUAL || process.env.EDITOR || ed
var args = editor.split(/\s+/)
var bin = args.shift()
var ps = spawn(bin, args.concat([ file ]), {
windowsHide: true,
stdio: 'inherit'
})
ps.on('exit', function (code, sig) {
if (typeof cb === 'function') cb(code, sig)
})
}
Helpers.dispKeys = function(kv, target_module) {
Object.keys(kv).forEach(function(key) {
if (target_module != null && target_module != key)
return false
if (typeof(kv[key]) == 'object') {
var obj = {}
console.log(chalk.bold('Module: ') + chalk.bold.blue(key))
Object.keys(kv[key]).forEach(function(sub_key) {
console.log(`$ pm2 set ${key}:${sub_key} ${kv[key][sub_key]}`)
})
}
})
}
module.exports = Helpers

9
api.hyungi.net/node_modules/pm2/lib/API/UX/index.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
const UX = {
helpers: require('./helpers.js'),
describe: require('./pm2-describe.js'),
list: require('./pm2-ls.js'),
list_min: require('./pm2-ls-minimal.js')
}
module.exports = UX

View File

@@ -0,0 +1,193 @@
const Table = require('cli-tableau')
const chalk = require('chalk')
const UxHelpers = require('./helpers.js')
const Common = require('../../Common.js')
var postModuleInfos = function(module_name, human_info) {
var table = new Table({
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
var disp = {}
human_info.unshift(['Module name', module_name])
human_info.forEach(function(info) {
var obj = {}
obj[chalk.bold.cyan(info[0])] = info[1]
table.push(obj)
})
console.log()
console.log(chalk.bold.inverse(' Module %s infos '), module_name)
console.log(table.toString())
}
/**
* Description
* @method describeTable
* @param {Object} proc process list
*/
module.exports = function(proc) {
var table = new Table({
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
var pm2_env = proc.pm2_env
var created_at = 'N/A'
if (pm2_env.axm_options && pm2_env.axm_options.human_info) {
postModuleInfos(pm2_env.name, pm2_env.axm_options.human_info)
}
try {
if (pm2_env.created_at != null)
created_at = new Date(pm2_env.created_at).toISOString()
} catch (e) {
}
console.log(chalk.bold.inverse(' Describing process with id %d - name %s '), pm2_env.pm_id, pm2_env.name)
UxHelpers.safe_push(table,
{ 'status' : UxHelpers.colorStatus(pm2_env.status) },
{ 'name': pm2_env.name },
{ 'namespace': pm2_env.namespace },
{ 'version': pm2_env.version },
{ 'restarts' : pm2_env.restart_time },
{ 'uptime' : (pm2_env.pm_uptime && pm2_env.status == 'online') ? UxHelpers.timeSince(pm2_env.pm_uptime) : 0 },
{ 'script path' : pm2_env.pm_exec_path },
{ 'script args' : pm2_env.args ? (typeof pm2_env.args == 'string' ? JSON.parse(pm2_env.args.replace(/'/g, '"')):pm2_env.args).join(' ') : null },
{ 'error log path' : pm2_env.pm_err_log_path },
{ 'out log path' : pm2_env.pm_out_log_path },
{ 'pid path' : pm2_env.pm_pid_path },
{ 'interpreter' : pm2_env.exec_interpreter },
{ 'interpreter args' : pm2_env.node_args.length != 0 ? pm2_env.node_args : null },
{ 'script id' : pm2_env.pm_id },
{ 'exec cwd' : pm2_env.pm_cwd },
{ 'exec mode' : pm2_env.exec_mode },
{ 'node.js version' : pm2_env.node_version },
{ 'node env': pm2_env.env.NODE_ENV },
{ 'watch & reload' : pm2_env.watch ? chalk.green.bold('✔') : '✘' },
{ 'unstable restarts' : pm2_env.unstable_restarts },
{ 'created at' : created_at }
)
if ('pm_log_path' in pm2_env){
table.splice(6, 0, {'entire log path': pm2_env.pm_log_path})
}
if ('cron_restart' in pm2_env){
table.splice(5, 0, {'cron restart': pm2_env.cron_restart})
}
console.log(table.toString())
/**
* Module conf display
*/
if (pm2_env.axm_options &&
pm2_env.axm_options.module_conf &&
Object.keys(pm2_env.axm_options.module_conf).length > 0) {
var table_conf = new Table({
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
console.log('Process configuration')
Object.keys(pm2_env.axm_options.module_conf).forEach(function(key) {
var tmp = {}
tmp[key] = pm2_env.axm_options.module_conf[key]
UxHelpers.safe_push(table_conf, tmp)
})
console.log(table_conf.toString())
}
/**
* Versioning metadata
*/
if (pm2_env.versioning) {
var table2 = new Table({
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
console.log(chalk.inverse.bold(' Revision control metadata '))
UxHelpers.safe_push(table2,
{ 'revision control' : pm2_env.versioning.type },
{ 'remote url' : pm2_env.versioning.url },
{ 'repository root' : pm2_env.versioning.repo_path },
{ 'last update' : pm2_env.versioning.update_time },
{ 'revision' : pm2_env.versioning.revision },
{ 'comment' : pm2_env.versioning.comment ? pm2_env.versioning.comment.trim().slice(0, 60) : '' },
{ 'branch' : pm2_env.versioning.branch }
)
console.log(table2.toString())
}
if (pm2_env.axm_actions && Object.keys(pm2_env.axm_actions).length > 0) {
var table_actions = new Table({
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
console.log(chalk.inverse.bold(' Actions available '))
pm2_env.axm_actions.forEach(function(action_set) {
UxHelpers.safe_push(table_actions, [action_set.action_name])
})
console.log(table_actions.toString())
Common.printOut(chalk.white.italic(' Trigger via: pm2 trigger %s <action_name>\n'), pm2_env.name)
}
if (pm2_env.axm_monitor && Object.keys(pm2_env.axm_monitor).length > 0) {
var table_probes = new Table({
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
console.log(chalk.inverse.bold(' Code metrics value '))
Object.keys(pm2_env.axm_monitor).forEach(function(key) {
var obj = {}
var metric_name = pm2_env.axm_monitor[key].hasOwnProperty("value") ? pm2_env.axm_monitor[key].value : pm2_env.axm_monitor[key]
var metric_unit = pm2_env.axm_monitor[key].hasOwnProperty("unit") ? pm2_env.axm_monitor[key].unit : ''
var value = `${metric_name} ${metric_unit}`
obj[key] = value
UxHelpers.safe_push(table_probes, obj)
})
console.log(table_probes.toString())
}
var table_env = new Table({
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
console.log(chalk.inverse.bold(' Divergent env variables from local env '))
var _env = Common.safeExtend({}, pm2_env)
var diff_env = {}
Object.keys(process.env).forEach(k => {
if (!_env[k] || _env[k] != process.env[k]) {
diff_env[k] = process.env[k]
}
})
Object.keys(diff_env).forEach(function(key) {
var obj = {}
if (_env[key]) {
// 1. fix env value is not a String and slice is undeinfed
// 2. fix process.stdout.columns is undefined and causes empty string output
// 3. columns defaults to 300 - same as specified in pm2-ls
obj[key] = String(_env[key]).slice(0, (process.stdout.columns || 300) - 60)
UxHelpers.safe_push(table_env, obj)
}
})
console.log(table_env.toString())
console.log()
Common.printOut(chalk.white.italic(' Add your own code metrics: http://bit.ly/code-metrics'))
Common.printOut(chalk.white.italic(' Use `pm2 logs %s [--lines 1000]` to display logs'), pm2_env.name)
Common.printOut(chalk.white.italic(' Use `pm2 env %s` to display environment variables'), pm2_env.pm_id)
Common.printOut(chalk.white.italic(' Use `pm2 monit` to monitor CPU and Memory usage'), pm2_env.name)
}

View File

@@ -0,0 +1,31 @@
const UxHelpers = require('./helpers.js')
const p = require('path')
/**
* Minimal display via pm2 ls -m
* @method miniDisplay
* @param {Object} list process list
*/
module.exports = function(list) {
list.forEach(function(l) {
var mode = l.pm2_env.exec_mode.split('_mode')[0]
var status = l.pm2_env.status
var key = l.pm2_env.name || p.basename(l.pm2_env.pm_exec_path.script)
console.log('+--- %s', key)
console.log('namespace : %s', l.pm2_env.namespace)
console.log('version : %s', l.pm2_env.version)
console.log('pid : %s', l.pid)
console.log('pm2 id : %s', l.pm2_env.pm_id)
console.log('status : %s', status)
console.log('mode : %s', mode)
console.log('restarted : %d', l.pm2_env.restart_time ? l.pm2_env.restart_time : 0)
console.log('uptime : %s', (l.pm2_env.pm_uptime && status == 'online') ? UxHelpers.timeSince(l.pm2_env.pm_uptime) : 0)
console.log('memory usage : %s', l.monit ? UxHelpers.bytesToSize(l.monit.memory, 1) : '')
console.log('error log : %s', l.pm2_env.pm_err_log_path)
console.log('watching : %s', l.pm2_env.watch ? 'yes' : 'no')
console.log('PID file : %s\n', l.pm2_env.pm_pid_path)
})
}

482
api.hyungi.net/node_modules/pm2/lib/API/UX/pm2-ls.js generated vendored Normal file
View File

@@ -0,0 +1,482 @@
const cst = require('../../../constants')
const Common = require('../../Common')
const Configuration = require('../../Configuration')
const UxHelpers = require('./helpers.js')
const chalk = require('chalk')
const Table = require('cli-tableau')
const Passwd = require('../../tools/passwd.js')
const List = {}
const CONDENSED_MODE = (process.stdout.columns || 300) < 134
/**
* Check if dump file contains same apps that the one managed by PM2
*/
function checkIfProcessAreDumped(list) {
try {
var dump_raw = require('fs').readFileSync(cst.DUMP_FILE_PATH)
var dump = JSON.parse(dump_raw)
var apps_dumped = dump.map(proc => proc.name)
var apps_running = list
.filter(proc => proc.pm2_env.pmx_module != true)
.map(proc => proc.name)
var diff = apps_dumped.filter(a => !apps_running.includes(a))
if (diff.length > 0) {
Common.warn(`Current process list is not synchronized with saved list. App ${chalk.bold(diff.join(' '))} differs. Type 'pm2 save' to synchronize.`)
}
else if (apps_dumped.length != apps_running.length) {
Common.warn(`Current process list is not synchronized with saved list. Type 'pm2 save' to synchronize.`)
}
} catch(e) {
}
}
var proc_id = 0
/**
* List Applications and Modules managed by PM2
*/
function listModulesAndAppsManaged(list, commander) {
var name_col_size = 11
if (list && list.length > 0)
name_col_size = (list.reduce((p, c) => (p.name.length > c.name.length) ? p : c)).name.length + 5
var id_width = Math.max(
2 + (Math.max(...list.map((l) => String(l.pm2_env.pm_id || 0).length)) || 0),
4
);
var app_head = {
id: id_width,
name: name_col_size,
namespace: 13,
version: 9,
mode: 9,
pid: 10,
uptime: 8,
'↺': 6,
status: 11,
cpu: 10,
mem: 10,
user: 10,
watching: 10
}
var mod_head = {
id: id_width,
module: 30,
version: 15,
pid: 10,
status: 10,
'↺': 6,
cpu: 10,
mem: 10,
user: 10
}
if (CONDENSED_MODE) {
app_head = {
id: id_width,
name: 20,
mode: 10,
'↺': 6,
status: 11,
cpu: 10,
memory: 10
}
mod_head = {
id: id_width,
name: 20,
status: 10,
cpu: 10,
mem: 10
}
}
var app_table = new Table({
head : Object.keys(app_head),
colWidths: Object.keys(app_head).map(k => app_head[k]),
colAligns : ['left'],
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
var module_table = new Table({
head : Object.keys(mod_head),
colWidths: Object.keys(mod_head).map(k => mod_head[k]),
colAligns : ['left'],
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
var sortField = 'name', sortOrder = 'asc', sort,
fields = {
name: 'pm2_env.name',
namespace: 'pm2_env.namespace',
pid: 'pid',
id: 'pm_id',
cpu: 'monit.cpu',
memory: 'monit.memory',
uptime: 'pm2_env.pm_uptime',
status: 'pm2_env.status'
}
if (commander && commander.sort) {
sort = commander.sort.split(':');
if(fields[sort[0].toLowerCase()]) {
sortField = sort[0].toLowerCase();
sortOrder = sort.length === 2 ? sort[1] : 'asc';
}
}
list.sort(function(a, b) {
var fieldA = UxHelpers.getNestedProperty(fields[sortField], a)
var fieldB = UxHelpers.getNestedProperty(fields[sortField], b)
if (sortOrder === 'desc') {
if (fieldA > fieldB)
return -1
if (fieldA < fieldB)
return 1
} else {
if (fieldA < fieldB)
return -1
if (fieldA > fieldB)
return 1
}
return 0
})
list.forEach(function(l) {
var obj = {}
if (l.pm2_env.pm_id > proc_id) {
proc_id = l.pm2_env.pm_id
}
var mode = l.pm2_env.exec_mode
var status = l.pm2_env.status
var key = l.pm2_env.pm_id
key = chalk.bold.cyan(key)
if (l.pm2_env.axm_options) {
var is_tracing_enabled = false
if (l.pm2_env.axm_options.tracing &&
typeof(l.pm2_env.axm_options.tracing) == 'boolean' &&
l.pm2_env.axm_options.tracing == true)
is_tracing_enabled = true
if (l.pm2_env.axm_options.tracing &&
l.pm2_env.axm_options.tracing.enabled &&
typeof(l.pm2_env.axm_options.tracing.enabled) == 'boolean' &&
l.pm2_env.axm_options.tracing.enabled == true)
is_tracing_enabled = true
if (is_tracing_enabled == true)
l.pm2_env.name = chalk.green('☵') + ' ' + l.pm2_env.name
if (l.pm2_env._km_monitored)
l.pm2_env.name = chalk.bold.green('◉') + ' ' + l.pm2_env.name
}
if (l.pm2_env.pmx_module == true) {
if (l.pm2_env.name == 'pm2-sysmonit') return
// pm2 ls for Modules
obj[key] = []
obj[key].push(l.name)
// Module version + PID
if (!CONDENSED_MODE) {
var pid = l.pm2_env.axm_options.pid ? l.pm2_env.axm_options.pid : l.pid
obj[key].push(l.pm2_env.version || 'N/A', pid)
}
// Status
obj[key].push(UxHelpers.colorStatus(status))
// Restart
if (!CONDENSED_MODE)
obj[key].push(l.pm2_env.restart_time ? l.pm2_env.restart_time : 0)
// CPU + Memory
obj[key].push(l.monit ? (l.monit.cpu + '%') : 'N/A', l.monit ? UxHelpers.bytesToSize(l.monit.memory, 1) : 'N/A' )
// User
if (!CONDENSED_MODE) {
if (l.pm2_env.uid && typeof(l.pm2_env.uid) == 'number') {
// Resolve user id to username
let users = Passwd.getUsers()
Object.keys(users).forEach(function(username) {
var user = users[username]
if (user.userId == l.pm2_env.uid) {
l.pm2_env.uid = user.username
}
})
}
obj[key].push(chalk.bold(l.pm2_env.uid || l.pm2_env.username))
}
UxHelpers.safe_push(module_table, obj)
}
else {
// pm2 ls for Applications
obj[key] = []
// PM2 ID
obj[key].push(l.pm2_env.name)
// Namespace
if (!CONDENSED_MODE)
obj[key].push(l.pm2_env.namespace)
// Version
if (!CONDENSED_MODE)
obj[key].push(l.pm2_env.version)
// Exec mode
obj[key].push(mode == 'fork_mode' ? chalk.inverse.bold('fork') : chalk.blue.bold('cluster'))
// PID
if (!CONDENSED_MODE)
obj[key].push(l.pid)
// Uptime
if (!CONDENSED_MODE)
obj[key].push((l.pm2_env.pm_uptime && status == 'online') ? UxHelpers.timeSince(l.pm2_env.pm_uptime) : 0)
// Restart
obj[key].push(l.pm2_env.restart_time ? l.pm2_env.restart_time : 0)
// Status
obj[key].push(UxHelpers.colorStatus(status))
// CPU
obj[key].push(l.monit ? l.monit.cpu + '%' : 'N/A')
// Memory
obj[key].push(l.monit ? UxHelpers.bytesToSize(l.monit.memory, 1) : 'N/A')
// User
if (!CONDENSED_MODE) {
if (l.pm2_env.uid && typeof(l.pm2_env.uid) == 'number') {
// Resolve user id to username
let users = Passwd.getUsers()
Object.keys(users).forEach(function(username) {
var user = users[username]
if (user.userId == l.pm2_env.uid) {
l.pm2_env.uid = user.username
}
})
}
obj[key].push(chalk.bold(l.pm2_env.uid || l.pm2_env.username))
}
// Watch status
if (!CONDENSED_MODE)
obj[key].push(l.pm2_env.watch ? chalk.green.bold('enabled') : chalk.grey('disabled'))
UxHelpers.safe_push(app_table, obj)
}
})
// Print Applications Managed
console.log(app_table.toString())
// Print Modules Managed
if (module_table.length > 0) {
console.log(chalk.bold(`Module${module_table.length > 1 ? 's' : ''}`))
console.log(module_table.toString())
}
proc_id++
}
// Container display
function containersListing(sys_infos) {
var stacked_docker = (process.stdout.columns || 100) < 140
var docker_head = {
id: 4,
image: 50,
status: 10,
'↺': 6,
cpu: 10,
mem: 10,
'net I/O ⇵': 11,
'fs I/O ⇵': 11
}
if (stacked_docker) {
docker_head = {
id: 4,
image: 25,
status: 10,
cpu: 10,
mem: 10
}
}
var docker_table = new Table({
colWidths: Object.keys(docker_head).map(k => docker_head[k]),
head : Object.keys(docker_head),
colAligns : ['left'],
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
sys_infos.containers.forEach((c) => {
var cpu = c.stats.cpu_percent
var mem = c.stats.mem_percent == 0 ? '0' : c.stats.mem_percent
var id = chalk.bold.cyan(proc_id++)
var state = UxHelpers.colorStatus(c.state)
if (stacked_docker)
docker_table.push([id, c.image, state, `${cpu}%`, `${mem}mb`])
else {
docker_table.push([
id,
c.image,
state,
c.restartCount,
`${cpu == 0 ? '0' : cpu}%`,
`${mem}mb`,
`${c.stats.netIO.rx}/${isNaN(c.stats.netIO.tx) == true ? '0.0' : c.stats.netIO.tx}`,
`${c.stats.blockIO.r}/${c.stats.blockIO.w}`
])
}
})
console.log(chalk.bold(`Container${sys_infos.containers.length > 1 ? 's' : ''}`))
console.log(docker_table.toString())
}
/**
* High resource processes
*/
function listHighResourcesProcesses(sys_infos) {
const CPU_MIN_SHOW = 60
const MEM_MIN_SHOW = 30
var sys_proc_head = ['id', 'cmd', 'pid', 'cpu', 'mem', 'uid']
var sys_proc_table = new Table({
colWidths: [4, CONDENSED_MODE ? 29 : 77, 10, 10, 10, 8],
head : sys_proc_head,
colAligns : ['left'],
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true}
})
sys_infos.processes.cpu_sorted = sys_infos.processes.cpu_sorted.filter((proc) => {
return proc.cpu > CPU_MIN_SHOW && proc.cmd.includes('node') === false &&
proc.cmd.includes('God Daemon') === false
})
sys_infos.processes.cpu_sorted.forEach(proc => {
var cpu = `${UxHelpers.colorizedMetric(proc.cpu, 40, 70, '%')}`
var mem = `${UxHelpers.colorizedMetric(proc.memory, 40, 70, '%')}`
var cmd = proc.cmd
sys_proc_table.push([chalk.bold.cyan(proc_id++), cmd, proc.pid, cpu, mem, proc.uid])
})
sys_infos.processes.mem_sorted = sys_infos.processes.mem_sorted.filter((proc) => {
return proc.memory > MEM_MIN_SHOW && proc.cmd.includes('node') == false
})
sys_infos.processes.mem_sorted.forEach((proc) => {
var cpu = `${UxHelpers.colorizedMetric(proc.cpu, 40, 70, '%')}`
var mem = `${UxHelpers.colorizedMetric(proc.memory, 40, 70, '%')}`
var cmd = proc.cmd
// if (proc.cmd.length > 50)
// cmd = '…' + proc.cmd.slice(proc.cmd.length - 48, proc.cmd.length)
sys_proc_table.push([chalk.bold.cyan(proc_id++), cmd, proc.pid, cpu, mem, proc.uid])
})
if (sys_infos.processes.cpu_sorted.length >= 1 || sys_infos.processes.mem_sorted.length >= 1) {
console.log(chalk.bold('Intensive Processes'))
console.log(sys_proc_table.toString())
}
}
/**
* Sys info line
*/
function miniMonitBar(sys_infos) {
let sys_metrics = sys_infos.pm2_env.axm_monitor
let cpu = sys_metrics['CPU Usage']
if (typeof(cpu) == 'undefined') return
var sys_summary_line = `${chalk.bold.cyan('host metrics')} `
sys_summary_line += `| ${chalk.bold('cpu')}: ${UxHelpers.colorizedMetric(cpu.value, 40, 70, '%')}`
let temp = sys_metrics['CPU Temperature'].value
if (temp && temp != '-1') {
sys_summary_line += ` ${UxHelpers.colorizedMetric(temp, 50, 70, 'º')}`
}
let mem_total = sys_metrics['RAM Total'].value
let mem_available = sys_metrics['RAM Available'].value
if (mem_total) {
var perc_mem_usage = (((mem_available) / mem_total) * 100).toFixed(1)
sys_summary_line += ` | ${chalk.bold('mem free')}: ${UxHelpers.colorizedMetric(perc_mem_usage, 30, 10, '%')} `
}
let interfaces = Object.keys(sys_metrics).filter(m => m.includes('net') && m != 'net:default').map(i => i.split(':')[2]).filter((iface, i, self) => self.indexOf(iface) === i)
interfaces.forEach(iface => {
if (!sys_metrics[`net:rx_5:${iface}`]) return
sys_summary_line += `| ${chalk.bold(iface)}: `
sys_summary_line += `${UxHelpers.colorizedMetric(sys_metrics[`net:rx_5:${iface}`].value, 10, 20, 'mb/s')} `
sys_summary_line += `${UxHelpers.colorizedMetric(sys_metrics[`net:tx_5:${iface}`].value, 10, 20, 'mb/s')} `
})
if (CONDENSED_MODE == false) {
let read = sys_metrics['Disk Reads'].value
let write = sys_metrics['Disk Writes'].value
sys_summary_line += `| ${chalk.bold('disk')}: ⇓ ${UxHelpers.colorizedMetric(read, 10, 20, 'mb/s')}`
sys_summary_line += `${UxHelpers.colorizedMetric(write, 10, 20, 'mb/s')} `
let disks = Object.keys(sys_metrics).filter(m => m.includes('fs:')).map(i => i.split(':')[2]).filter((iface, i, self) => self.indexOf(iface) === i)
var disk_nb = 0
disks.forEach(fs => {
let use = sys_metrics[`fs:use:${fs}`].value
if (use > 60)
sys_summary_line += `${chalk.grey(fs)} ${UxHelpers.colorizedMetric(use, 80, 90, '%')} `
})
}
sys_summary_line += '|'
console.log(sys_summary_line)
}
/**
* pm2 ls
* @method dispAsTable
* @param {Object} list
* @param {Object} system informations (via pm2 sysmonit/pm2 sysinfos)
*/
module.exports = function(list, commander) {
var pm2_conf = Configuration.getSync('pm2')
if (!list)
return console.log('list empty')
listModulesAndAppsManaged(list, commander)
let sysmonit = list.filter(proc => proc.name == 'pm2-sysmonit')
if (sysmonit && sysmonit[0])
miniMonitBar(sysmonit[0])
checkIfProcessAreDumped(list)
}

382
api.hyungi.net/node_modules/pm2/lib/API/Version.js generated vendored Normal file
View File

@@ -0,0 +1,382 @@
var cst = require('../../constants.js');
var Common = require('../Common.js');
var fs = require('fs');
var eachSeries = require('async/eachSeries');
var child = require('child_process');
var printError = Common.printError;
var printOut = Common.printOut;
module.exports = function(CLI) {
var EXEC_TIMEOUT = 60000; // Default: 1 min
CLI.prototype._pull = function(opts, cb) {
var that = this;
var process_name = opts.process_name;
var reload_type = opts.action;
printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name);
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
if (err || processes.length === 0) {
printError('No processes with this name or id : %s', process_name);
return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
}
var proc = processes[0];
if (!proc.pm2_env.versioning) {
printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
return cb ? cb({success:false, msg: 'No versioning system found for process'}) : that.exitCli(cst.SUCCESS_EXIT);
}
require('vizion').update({
folder: proc.pm2_env.versioning.repo_path
}, function(err, meta) {
if (err !== null) {
return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT);
}
if (meta.success === true) {
getPostUpdateCmds(proc.pm2_env.versioning.repo_path, process_name, function (command_list) {
execCommands(proc.pm2_env.versioning.repo_path, command_list, function(err, res) {
if (err !== null) {
printError(err);
return cb ? cb({msg: meta.output + err}) : that.exitCli(cst.ERROR_EXIT);
}
else {
printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
printOut(cst.PREFIX_MSG + 'Current commit %s', meta.current_revision);
return that[reload_type](process_name, function(err, procs) {
if (err && cb) return cb(err);
if (err) console.error(err);
return cb ? cb(null, meta.output + res) : that.exitCli(cst.SUCCESS_EXIT);
});
}
});
});
}
else {
printOut(cst.PREFIX_MSG + 'Already up-to-date or an error occured for app: %s', process_name);
return cb ? cb({success:false, msg : 'Already up to date'}) : that.exitCli(cst.SUCCESS_EXIT);
}
return false;
});
return false;
});
};
/**
* CLI method for updating a repository to a specific commit id
* @method pullCommitId
* @param {string} process_name
* @param {string} commit_id
* @return
*/
CLI.prototype.pullCommitId = function(process_name, commit_id, cb) {
var reload_type = 'reload';
var that = this;
printOut(cst.PREFIX_MSG + 'Updating repository for process name %s', process_name);
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
if (err || processes.length === 0) {
printError('No processes with this name or id : %s', process_name);
return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
}
var proc = processes[0];
if (proc.pm2_env.versioning) {
require('vizion').isUpToDate({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) {
if (err !== null)
return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT);
require('vizion').revertTo(
{revision: commit_id,
folder: proc.pm2_env.versioning.repo_path},
function(err2, meta2) {
if (!err2 && meta2.success) {
getPostUpdateCmds(proc.pm2_env.versioning.repo_path, process_name, function (command_list) {
execCommands(proc.pm2_env.versioning.repo_path, command_list, function(err, res) {
if (err !== null)
{
printError(err);
return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT);
}
else {
printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
printOut(cst.PREFIX_MSG + 'Current commit %s', commit_id);
return that[reload_type](process_name, cb);
}
});
});
}
else {
printOut(cst.PREFIX_MSG + 'Already up-to-date or an error occured: %s', process_name);
return cb ? cb(null, {success:meta.success}) : that.exitCli(cst.SUCCESS_EXIT);
}
});
});
}
else {
printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
return cb ? cb(null, {success:false}) : that.exitCli(cst.SUCCESS_EXIT);
}
});
};
/**
* CLI method for downgrading a repository to the previous commit (older)
* @method backward
* @param {string} process_name
* @return
*/
CLI.prototype.backward = function(process_name, cb) {
var that = this;
printOut(cst.PREFIX_MSG + 'Downgrading to previous commit repository for process name %s', process_name);
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
if (err || processes.length === 0) {
printError('No processes with this name or id : %s', process_name);
return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
}
var proc = processes[0];
// in case user searched by id/pid
process_name = proc.name;
if (proc.pm2_env.versioning === undefined ||
proc.pm2_env.versioning === null)
return cb({msg : 'Versioning unknown'});
require('vizion').prev({
folder: proc.pm2_env.versioning.repo_path
}, function(err, meta) {
if (err)
return cb ? cb({msg:err, data : meta}) : that.exitCli(cst.ERROR_EXIT);
if (meta.success !== true) {
printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
return cb ? cb({msg:err, data : meta}) : that.exitCli(cst.ERROR_EXIT);
}
getPostUpdateCmds(proc.pm2_env.versioning.repo_path, process_name, function (command_list) {
execCommands(proc.pm2_env.versioning.repo_path, command_list, function(err, res) {
if (err !== null) {
require('vizion').next({folder: proc.pm2_env.versioning.repo_path}, function(err2, meta2) {
printError(err);
return cb ? cb({msg: meta.output + err}) : that.exitCli(cst.ERROR_EXIT);
});
return false;
}
printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
printOut(cst.PREFIX_MSG + 'Current commit %s', meta.current_revision);
that.reload(process_name, function(err, procs) {
if (err) return cb(err);
return cb ? cb(null, meta.output + res) : that.exitCli(cst.SUCCESS_EXIT);
});
});
});
});
});
};
/**
* CLI method for updating a repository to the next commit (more recent)
* @method forward
* @param {string} process_name
* @return
*/
CLI.prototype.forward = function(process_name, cb) {
var that = this;
printOut(cst.PREFIX_MSG + 'Updating to next commit repository for process name %s', process_name);
that.Client.getProcessByNameOrId(process_name, function (err, processes) {
if (err || processes.length === 0) {
printError('No processes with this name or id: %s', process_name);
return cb ? cb({msg: 'Process not found: ' + process_name}) : that.exitCli(cst.ERROR_EXIT);
}
var proc = processes[0];
// in case user searched by id/pid
process_name = proc.name;
if (proc.pm2_env.versioning) {
require('vizion').next({folder: proc.pm2_env.versioning.repo_path}, function(err, meta) {
if (err !== null)
return cb ? cb({msg:err}) : that.exitCli(cst.ERROR_EXIT);
if (meta.success === true) {
getPostUpdateCmds(proc.pm2_env.versioning.repo_path, process_name, function (command_list) {
execCommands(proc.pm2_env.versioning.repo_path, command_list, function(err, res) {
if (err !== null)
{
require('vizion').prev({folder: proc.pm2_env.versioning.repo_path}, function(err2, meta2) {
printError(err);
return cb ? cb({msg:meta.output + err}) : that.exitCli(cst.ERROR_EXIT);
});
}
else {
printOut(cst.PREFIX_MSG + 'Process successfully updated %s', process_name);
printOut(cst.PREFIX_MSG + 'Current commit %s', meta.current_revision);
that.reload(process_name, function(err, procs) {
if (err) return cb(err);
return cb ? cb(null, meta.output + res) : that.exitCli(cst.SUCCESS_EXIT);
});
}
});
});
}
else {
printOut(cst.PREFIX_MSG + 'Already up-to-date or an error occured: %s', process_name);
return cb ? cb(null, {success:meta.success}) : that.exitCli(cst.SUCCESS_EXIT);
}
});
}
else {
printOut(cst.PREFIX_MSG + 'No versioning system found for process %s', process_name);
return cb ? cb({success:false, msg: 'No versioning system found'}) : that.exitCli(cst.SUCCESS_EXIT);
}
});
};
var exec = function (cmd, callback) {
var output = '';
var c = child.exec(cmd, {
env: process.env,
maxBuffer: 3*1024*1024,
timeout: EXEC_TIMEOUT
}, function(err) {
if (callback)
callback(err ? err.code : 0, output);
});
c.stdout.on('data', function(data) {
output += data;
});
c.stderr.on('data', function(data) {
output += data;
});
};
/**
*
* @method execCommands
* @param {string} repo_path
* @param {object} command_list
* @return
*/
var execCommands = function(repo_path, command_list, cb) {
var stdout = '';
eachSeries(command_list, function(command, callback) {
stdout += '\n' + command;
exec('cd '+repo_path+';'+command,
function(code, output) {
stdout += '\n' + output;
if (code === 0)
callback();
else
callback('`'+command+'` failed');
});
}, function(err) {
if (err)
return cb(stdout + '\n' + err);
return cb(null, stdout);
});
}
/**
* Description Search process.json for post-update commands
* @method getPostUpdateCmds
* @param {string} repo_path
* @param {string} proc_name
* @return
*/
var getPostUpdateCmds = function(repo_path, proc_name, cb) {
if (typeof repo_path !== 'string')
return cb([]);
if (repo_path[repo_path.length - 1] !== '/')
repo_path += '/';
var searchForCommands = function(file, callback) {
fs.exists(repo_path+file, function(exists) {
if (exists) {
try {
var conf_string = fs.readFileSync(repo_path + file);
var data = Common.parseConfig(conf_string, repo_path + file);
} catch (e) {
console.error(e.message || e);
}
if (data && data.apps) {
eachSeries(data.apps, function(item, callb) {
if (item.name && item.name === proc_name) {
if (item.post_update && typeof(item.post_update) === 'object') {
if (item.exec_timeout)
EXEC_TIMEOUT = parseInt(item.exec_timeout);
return callb(item.post_update);
}
else {
return callb();
}
}
else
return callb();
}, function(final) {
return callback(final);
});
}
else {
return callback();
}
}
else {
return callback();
}
});
};
eachSeries(['ecosystem.json', 'process.json', 'package.json'], searchForCommands,
function(final) {
return cb(final ? final : []);
});
};
/**
* CLI method for updating a repository
* @method pullAndRestart
* @param {string} process_name name of processes to pull
* @return
*/
CLI.prototype.pullAndRestart = function (process_name, cb) {
this._pull({process_name: process_name, action: 'reload'}, cb);
};
/**
* CLI method for updating a repository
* @method pullAndReload
* @param {string} process_name name of processes to pull
* @return
*/
CLI.prototype.pullAndReload = function (process_name, cb) {
this._pull({process_name: process_name, action: 'reload'}, cb);
};
/**
* CLI method for updating a repository to a specific commit id
* @method pullCommitId
* @param {object} opts
* @return
*/
CLI.prototype._pullCommitId = function (opts, cb) {
this.pullCommitId(opts.pm2_name, opts.commit_id, cb);
};
}

View File

@@ -0,0 +1,12 @@
{
".sh" : "bash",
".py" : "python",
".rb" : "ruby",
".php" : "php",
".pl" : "perl",
".js" : "node",
".coffee" : "coffee",
".ls" : "lsc",
".ts" : "bun",
".tsx" : "bun"
}

View File

@@ -0,0 +1,372 @@
'use strict'
var cst = require('../../../constants.js');
const chalk = require('chalk');
const path = require('path');
const fs = require('fs');
const Table = require('cli-tableau');
const pkg = require('../../../package.json')
const IOAPI = require('@pm2/js-api')
const promptly = require('promptly')
var CLIStrategy = require('./auth-strategies/CliAuth')
var WebStrategy = require('./auth-strategies/WebAuth')
const exec = require('child_process').exec
const OAUTH_CLIENT_ID_WEB = '138558311'
const OAUTH_CLIENT_ID_CLI = '0943857435'
module.exports = class PM2ioHandler {
static usePM2Client (instance) {
this.pm2 = instance
}
static strategy () {
switch (process.platform) {
case 'darwin': {
return new WebStrategy({
client_id: OAUTH_CLIENT_ID_WEB
})
}
case 'win32': {
return new WebStrategy({
client_id: OAUTH_CLIENT_ID_WEB
})
}
case 'linux': {
const isDesktop = process.env.XDG_CURRENT_DESKTOP || process.env.XDG_SESSION_DESKTOP || process.env.DISPLAY
const isSSH = process.env.SSH_TTY || process.env.SSH_CONNECTION
if (isDesktop && !isSSH) {
return new WebStrategy({
client_id: OAUTH_CLIENT_ID_WEB
})
} else {
return new CLIStrategy({
client_id: OAUTH_CLIENT_ID_CLI
})
}
}
default: {
return new CLIStrategy({
client_id: OAUTH_CLIENT_ID_CLI
})
}
}
}
static init () {
this._strategy = this.strategy()
/**
* If you are using a local backend you should give those options :
* {
* services: {
* API: 'http://localhost:3000',
* OAUTH: 'http://localhost:3100'
* }
* }
*/
this.io = new IOAPI().use(this._strategy)
}
static launch (command, opts) {
// first init the strategy and the io client
this.init()
switch (command) {
case 'connect' :
case 'login' :
case 'register' :
case undefined :
case 'authenticate' : {
this.authenticate()
break
}
case 'validate' : {
this.validateAccount(opts)
break
}
case 'help' :
case 'welcome': {
var dt = fs.readFileSync(path.join(__dirname, './pres/welcome'));
console.log(dt.toString());
return process.exit(0)
}
case 'logout': {
this._strategy.isAuthenticated().then(isConnected => {
// try to kill the agent anyway
this.pm2.killAgent(err => {})
if (isConnected === false) {
console.log(`${cst.PM2_IO_MSG} Already disconnected`)
return process.exit(0)
}
this._strategy._retrieveTokens((err, tokens) => {
if (err) {
console.log(`${cst.PM2_IO_MSG} Successfully disconnected`)
return process.exit(0)
}
this._strategy.deleteTokens(this.io).then(_ => {
console.log(`${cst.PM2_IO_MSG} Successfully disconnected`)
return process.exit(0)
}).catch(err => {
console.log(`${cst.PM2_IO_MSG_ERR} Unexpected error: ${err.message}`)
return process.exit(1)
})
})
}).catch(err => {
console.error(`${cst.PM2_IO_MSG_ERR} Failed to logout: ${err.message}`)
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
})
break
}
case 'create': {
this._strategy.isAuthenticated().then(res => {
// if the user isn't authenticated, we make them do the whole flow
if (res !== true) {
this.authenticate()
} else {
this.createBucket(this.createBucketHandler.bind(this))
}
}).catch(err => {
console.error(`${cst.PM2_IO_MSG_ERR} Failed to create to the bucket: ${err.message}`)
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
})
break
}
case 'web': {
this._strategy.isAuthenticated().then(res => {
// if the user isn't authenticated, we make them do the whole flow
if (res === false) {
console.error(`${cst.PM2_IO_MSG_ERR} You need to be authenticated to do that, please use: pm2 plus login`)
return process.exit(1)
}
this._strategy._retrieveTokens(() => {
return this.openUI()
})
}).catch(err => {
console.error(`${cst.PM2_IO_MSG_ERR} Failed to open the UI: ${err.message}`)
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
})
break
}
default : {
console.log(`${cst.PM2_IO_MSG_ERR} Invalid command ${command}, available : login,register,validate,connect or web`)
process.exit(1)
}
}
}
static openUI () {
this.io.bucket.retrieveAll().then(res => {
const buckets = res.data
if (buckets.length === 0) {
return this.createBucket((err, bucket) => {
if (err) {
console.error(`${cst.PM2_IO_MSG_ERR} Failed to connect to the bucket: ${err.message}`)
if (bucket) {
console.error(`${cst.PM2_IO_MSG_ERR} You can retry using: pm2 plus link ${bucket.secret_id} ${bucket.public_id}`)
}
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
return process.exit(0)
}
const targetURL = `https://app.pm2.io/#/bucket/${bucket._id}`
console.log(`${cst.PM2_IO_MSG} Please follow the popup or go to this URL :`, '\n', ' ', targetURL)
this.open(targetURL)
return process.exit(0)
})
}
var table = new Table({
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true},
head : ['Bucket name', 'Plan type']
})
buckets.forEach(function(bucket) {
table.push([bucket.name, bucket.credits.offer_type])
})
console.log(table.toString())
console.log(`${cst.PM2_IO_MSG} If you don't want to open the UI to a bucket, type 'none'`)
const choices = buckets.map(bucket => bucket.name)
choices.push('none')
promptly.choose(`${cst.PM2_IO_MSG} Type the name of the bucket you want to connect to :`, choices, (err, value) => {
if (value === 'none') process.exit(0)
const bucket = buckets.find(bucket => bucket.name === value)
if (bucket === undefined) return process.exit(0)
const targetURL = `https://app.pm2.io/#/bucket/${bucket._id}`
console.log(`${cst.PM2_IO_MSG} Please follow the popup or go to this URL :`, '\n', ' ', targetURL)
this.open(targetURL)
return process.exit(0)
})
})
}
static validateAccount (token) {
this.io.auth.validEmail(token)
.then(res => {
console.log(`${cst.PM2_IO_MSG} Email succesfully validated.`)
console.log(`${cst.PM2_IO_MSG} You can now proceed and use: pm2 plus connect`)
return process.exit(0)
}).catch(err => {
if (err.status === 401) {
console.error(`${cst.PM2_IO_MSG_ERR} Invalid token`)
return process.exit(1)
} else if (err.status === 301) {
console.log(`${cst.PM2_IO_MSG} Email succesfully validated.`)
console.log(`${cst.PM2_IO_MSG} You can now proceed and use: pm2 plus connect`)
return process.exit(0)
}
const msg = err.data ? err.data.error_description || err.data.msg : err.message
console.error(`${cst.PM2_IO_MSG_ERR} Failed to validate your email: ${msg}`)
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
return process.exit(1)
})
}
static createBucketHandler (err, bucket) {
if (err) {
console.trace(`${cst.PM2_IO_MSG_ERR} Failed to connect to the bucket: ${err.message}`)
if (bucket) {
console.error(`${cst.PM2_IO_MSG_ERR} You can retry using: pm2 plus link ${bucket.secret_id} ${bucket.public_id}`)
}
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
return process.exit(0)
}
if (bucket === undefined) {
return process.exit(0)
}
console.log(`${cst.PM2_IO_MSG} Successfully connected to bucket ${bucket.name}`)
var targetURL = `https://app.pm2.io/#/bucket/${bucket._id}`
console.log(`${cst.PM2_IO_MSG} You can use the web interface over there: ${targetURL}`)
this.open(targetURL)
return process.exit(0)
}
static createBucket (cb) {
console.log(`${cst.PM2_IO_MSG} By default we allow you to trial PM2 Plus for 14 days without any credit card.`)
this.io.bucket.create({
name: 'PM2 Plus Monitoring'
}).then(res => {
const bucket = res.data.bucket
console.log(`${cst.PM2_IO_MSG} Successfully created the bucket`)
this.pm2.link({
public_key: bucket.public_id,
secret_key: bucket.secret_id,
pm2_version: pkg.version
}, (err) => {
if (err) {
return cb(new Error('Failed to connect your local PM2 to your bucket'), bucket)
} else {
return cb(null, bucket)
}
})
}).catch(err => {
return cb(new Error(`Failed to create a bucket: ${err.message}`))
})
}
/**
* Connect the local agent to a specific bucket
* @param {Function} cb
*/
static connectToBucket (cb) {
this.io.bucket.retrieveAll().then(res => {
const buckets = res.data
if (buckets.length === 0) {
return this.createBucket(cb)
}
var table = new Table({
style : {'padding-left' : 1, head : ['cyan', 'bold'], compact : true},
head : ['Bucket name', 'Plan type']
})
buckets.forEach(function(bucket) {
table.push([bucket.name, bucket.payment.offer_type])
})
console.log(table.toString())
console.log(`${cst.PM2_IO_MSG} If you don't want to connect to a bucket, type 'none'`)
const choices = buckets.map(bucket => bucket.name)
choices.push('none')
promptly.choose(`${cst.PM2_IO_MSG} Type the name of the bucket you want to connect to :`, choices, (err, value) => {
if (value === 'none') return cb()
const bucket = buckets.find(bucket => bucket.name === value)
if (bucket === undefined) return cb()
this.pm2.link({
public_key: bucket.public_id,
secret_key: bucket.secret_id,
pm2_version: pkg.version
}, (err) => {
return err ? cb(err) : cb(null, bucket)
})
})
})
}
/**
* Authenticate the user with either of the strategy
* @param {Function} cb
*/
static authenticate () {
this._strategy._retrieveTokens((err, tokens) => {
if (err) {
const msg = err.data ? err.data.error_description || err.data.msg : err.message
console.log(`${cst.PM2_IO_MSG_ERR} Unexpected error : ${msg}`)
return process.exit(1)
}
console.log(`${cst.PM2_IO_MSG} Successfully authenticated`)
this.io.user.retrieve().then(res => {
const user = res.data
this.io.user.retrieve().then(res => {
const tmpUser = res.data
console.log(`${cst.PM2_IO_MSG} Successfully validated`)
this.connectToBucket(this.createBucketHandler.bind(this))
})
})
})
}
static open (target, appName, callback) {
let opener
const escape = function (s) {
return s.replace(/"/g, '\\"')
}
if (typeof (appName) === 'function') {
callback = appName
appName = null
}
switch (process.platform) {
case 'darwin': {
opener = appName ? `open -a "${escape(appName)}"` : `open`
break
}
case 'win32': {
opener = appName ? `start "" ${escape(appName)}"` : `start ""`
break
}
default: {
opener = appName ? escape(appName) : `xdg-open`
break
}
}
if (process.env.SUDO_USER) {
opener = 'sudo -u ' + process.env.SUDO_USER + ' ' + opener
}
return exec(`${opener} "${escape(target)}"`, callback)
}
}

View File

@@ -0,0 +1,288 @@
'use strict'
const AuthStrategy = require('@pm2/js-api/src/auth_strategies/strategy')
const querystring = require('querystring');
const http = require('http')
const fs = require('fs')
const url = require('url')
const exec = require('child_process').exec
const tryEach = require('async/tryEach')
const path = require('path')
const os = require('os')
const needle = require('needle')
const chalk = require('chalk')
const cst = require('../../../../constants.js')
const promptly = require('promptly')
module.exports = class CliStrategy extends AuthStrategy {
// the client will try to call this but we handle this part ourselves
retrieveTokens (km, cb) {
this.authenticated = false
this.callback = cb
this.km = km
this.BASE_URI = 'https://id.keymetrics.io';
}
// so the cli know if we need to tell user to login/register
isAuthenticated () {
return new Promise((resolve, reject) => {
if (this.authenticated) return resolve(true)
let tokensPath = cst.PM2_IO_ACCESS_TOKEN
fs.readFile(tokensPath, (err, tokens) => {
if (err && err.code === 'ENOENT') return resolve(false)
if (err) return reject(err)
// verify that the token is valid
try {
tokens = JSON.parse(tokens || '{}')
} catch (err) {
fs.unlinkSync(tokensPath)
return resolve(false)
}
// if the refresh tokens is here, the user could be automatically authenticated
return resolve(typeof tokens.refresh_token === 'string')
})
})
}
verifyToken (refresh) {
return this.km.auth.retrieveToken({
client_id: this.client_id,
refresh_token: refresh
})
}
// called when we are sure the user asked to be logged in
_retrieveTokens (optionalCallback) {
const km = this.km
const cb = this.callback
tryEach([
// try to find the token via the environment
(next) => {
if (!process.env.PM2_IO_TOKEN) {
return next(new Error('No token in env'))
}
this.verifyToken(process.env.PM2_IO_TOKEN)
.then((res) => {
return next(null, res.data)
}).catch(next)
},
// try to find it in the file system
(next) => {
fs.readFile(cst.PM2_IO_ACCESS_TOKEN, (err, tokens) => {
if (err) return next(err)
// verify that the token is valid
tokens = JSON.parse(tokens || '{}')
if (new Date(tokens.expire_at) > new Date(new Date().toISOString())) {
return next(null, tokens)
}
this.verifyToken(tokens.refresh_token)
.then((res) => {
return next(null, res.data)
}).catch(next)
})
},
// otherwise make the whole flow
(next) => {
return this.authenticate((err, data) => {
if (err instanceof Error) return next(err)
// verify that the token is valid
this.verifyToken(data.refresh_token)
.then((res) => {
return next(null, res.data)
}).catch(next)
})
}
], (err, result) => {
// if present run the optional callback
if (typeof optionalCallback === 'function') {
optionalCallback(err, result)
}
if (result.refresh_token) {
this.authenticated = true
let file = cst.PM2_IO_ACCESS_TOKEN
fs.writeFile(file, JSON.stringify(result), () => {
return cb(err, result)
})
} else {
return cb(err, result)
}
})
}
authenticate (cb) {
console.log(`${cst.PM2_IO_MSG} Using non-browser authentication.`)
promptly.confirm(`${cst.PM2_IO_MSG} Do you have a pm2.io account? (y/n)`, (err, answer) => {
// Either login or register
return answer === true ? this.login(cb) : this.register(cb)
})
}
login (cb) {
let retry = () => {
promptly.prompt(`${cst.PM2_IO_MSG} Your username or email: `, (err, username) => {
if (err) return retry();
promptly.password(`${cst.PM2_IO_MSG} Your password: `, { replace : '*' }, (err, password) => {
if (err) return retry();
console.log(`${cst.PM2_IO_MSG} Authenticating ...`)
this._loginUser({
username: username,
password: password
}, (err, data) => {
if (err) {
console.error(`${cst.PM2_IO_MSG_ERR} Failed to authenticate: ${err.message}`)
return retry()
}
return cb(null, data)
})
})
})
}
retry()
}
register (cb) {
console.log(`${cst.PM2_IO_MSG} No problem ! We just need few informations to create your account`)
var retry = () => {
promptly.prompt(`${cst.PM2_IO_MSG} Please choose an username :`, {
validator : this._validateUsername,
retry : true
}, (err, username) => {
promptly.prompt(`${cst.PM2_IO_MSG} Please choose an email :`, {
validator : this._validateEmail,
retry : true
},(err, email) => {
promptly.password(`${cst.PM2_IO_MSG} Please choose a password :`, { replace : '*' }, (err, password) => {
promptly.confirm(`${cst.PM2_IO_MSG} Do you accept the terms and privacy policy (https://pm2.io/legals/terms_conditions.pdf) ? (y/n)`, (err, answer) => {
if (err) {
console.error(chalk.bold.red(err));
return retry()
} else if (answer === false) {
console.error(`${cst.PM2_IO_MSG_ERR} You must accept the terms and privacy policy to contiue.`)
return retry()
}
this._registerUser({
email : email,
password : password,
username : username
}, (err, data) => {
console.log('\n')
if (err) {
console.error(`${cst.PM2_IO_MSG_ERR} Unexpect error: ${err.message}`)
console.error(`${cst.PM2_IO_MSG_ERR} You can also contact us to get help: contact@pm2.io`)
return process.exit(1)
}
return cb(undefined, data)
})
})
})
})
})
}
retry()
}
/**
* Register function
* @param opts.username
* @param opts.password
* @param opts.email
*/
_registerUser (opts, cb) {
const data = Object.assign(opts, {
password_confirmation: opts.password,
accept_terms: true
})
needle.post(this.BASE_URI + '/api/oauth/register', data, {
json: true,
headers: {
'X-Register-Provider': 'pm2-register',
'x-client-id': this.client_id
}
}, function (err, res, body) {
if (err) return cb(err)
if (body.email && body.email.message) return cb(new Error(body.email.message))
if (body.username && body.username.message) return cb(new Error(body.username.message))
if (!body.access_token) return cb(new Error(body.msg))
return cb(null, {
refresh_token : body.refresh_token.token,
access_token : body.access_token.token
})
});
}
_loginUser (user_info, cb) {
const URL_AUTH = '/api/oauth/authorize?response_type=token&scope=all&client_id=' +
this.client_id + '&redirect_uri=http://localhost:43532';
needle.get(this.BASE_URI + URL_AUTH, (err, res) => {
if (err) return cb(err);
var cookie = res.cookies;
needle.post(this.BASE_URI + '/api/oauth/login', user_info, {
cookies : cookie
}, (err, resp, body) => {
if (err) return cb(err)
if (resp.statusCode != 200) return cb('Wrong credentials')
var location = resp.headers['x-redirect']
needle.get(this.BASE_URI + location, {
cookies : cookie
}, (err, res) => {
if (err) return cb(err);
var refresh_token = querystring.parse(url.parse(res.headers.location).query).access_token;
needle.post(this.BASE_URI + '/api/oauth/token', {
client_id : this.client_id,
grant_type : 'refresh_token',
refresh_token : refresh_token,
scope : 'all'
}, (err, res, body) => {
if (err) return cb(err)
return cb(null, body)
})
})
})
})
}
_validateEmail (email) {
var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
if (re.test(email) == false)
throw new Error('Not an email');
return email;
}
_validateUsername (value) {
if (value.length < 6) {
throw new Error('Min length of 6');
}
return value;
};
deleteTokens (km) {
return new Promise((resolve, reject) => {
// revoke the refreshToken
km.auth.revoke()
.then(res => {
// remove the token from the filesystem
let file = cst.PM2_IO_ACCESS_TOKEN
fs.unlinkSync(file)
return resolve(res)
}).catch(reject)
})
}
}

View File

@@ -0,0 +1,187 @@
'use strict'
const cst = require('../../../../constants.js');
const AuthStrategy = require('@pm2/js-api/src/auth_strategies/strategy')
const http = require('http')
const fs = require('fs')
const url = require('url')
const exec = require('child_process').exec
const tryEach = require('async/tryEach');
module.exports = class WebStrategy extends AuthStrategy {
// the client will try to call this but we handle this part ourselves
retrieveTokens (km, cb) {
this.authenticated = false
this.callback = cb
this.km = km
}
// so the cli know if we need to tell user to login/register
isAuthenticated () {
return new Promise((resolve, reject) => {
if (this.authenticated) return resolve(true)
let tokensPath = cst.PM2_IO_ACCESS_TOKEN
fs.readFile(tokensPath, (err, tokens) => {
if (err && err.code === 'ENOENT') return resolve(false)
if (err) return reject(err)
// verify that the token is valid
try {
tokens = JSON.parse(tokens || '{}')
} catch (err) {
fs.unlinkSync(tokensPath)
return resolve(false)
}
// if the refresh tokens is here, the user could be automatically authenticated
return resolve(typeof tokens.refresh_token === 'string')
})
})
}
// called when we are sure the user asked to be logged in
_retrieveTokens (optionalCallback) {
const km = this.km
const cb = this.callback
let verifyToken = (refresh) => {
return km.auth.retrieveToken({
client_id: this.client_id,
refresh_token: refresh
})
}
tryEach([
// try to find the token via the environment
(next) => {
if (!process.env.PM2_IO_TOKEN) {
return next(new Error('No token in env'))
}
verifyToken(process.env.PM2_IO_TOKEN)
.then((res) => {
return next(null, res.data)
}).catch(next)
},
// try to find it in the file system
(next) => {
fs.readFile(cst.PM2_IO_ACCESS_TOKEN, (err, tokens) => {
if (err) return next(err)
// verify that the token is valid
tokens = JSON.parse(tokens || '{}')
if (new Date(tokens.expire_at) > new Date(new Date().toISOString())) {
return next(null, tokens)
}
verifyToken(tokens.refresh_token)
.then((res) => {
return next(null, res.data)
}).catch(next)
})
},
// otherwise make the whole flow
(next) => {
return this.loginViaWeb((data) => {
// verify that the token is valid
verifyToken(data.access_token)
.then((res) => {
return next(null, res.data)
}).catch(err => next(err))
})
}
], (err, result) => {
// if present run the optional callback
if (typeof optionalCallback === 'function') {
optionalCallback(err, result)
}
if (result.refresh_token) {
this.authenticated = true
let file = cst.PM2_IO_ACCESS_TOKEN
fs.writeFile(file, JSON.stringify(result), () => {
return cb(err, result)
})
} else {
return cb(err, result)
}
})
}
loginViaWeb (cb) {
const redirectURL = `${this.oauth_endpoint}${this.oauth_query}`
console.log(`${cst.PM2_IO_MSG} Please follow the popup or go to this URL :`, '\n', ' ', redirectURL)
let shutdown = false
let server = http.createServer((req, res) => {
// only handle one request
if (shutdown === true) return res.end()
shutdown = true
let query = url.parse(req.url, true).query
res.write(`
<head>
<script>
</script>
</head>
<body>
<h2 style="text-align: center">
You can go back to your terminal now :)
</h2>
</body>`)
res.end()
server.close()
return cb(query)
})
server.listen(43532, () => {
this.open(redirectURL)
})
}
deleteTokens (km) {
return new Promise((resolve, reject) => {
// revoke the refreshToken
km.auth.revoke()
.then(res => {
// remove the token from the filesystem
let file = cst.PM2_IO_ACCESS_TOKEN
fs.unlinkSync(file)
return resolve(res)
}).catch(reject)
})
}
open (target, appName, callback) {
let opener
const escape = function (s) {
return s.replace(/"/g, '\\"')
}
if (typeof (appName) === 'function') {
callback = appName
appName = null
}
switch (process.platform) {
case 'darwin': {
opener = appName ? `open -a "${escape(appName)}"` : `open`
break
}
case 'win32': {
opener = appName ? `start "" ${escape(appName)}"` : `start ""`
break
}
default: {
opener = appName ? escape(appName) : `xdg-open`
break
}
}
if (process.env.SUDO_USER) {
opener = 'sudo -u ' + process.env.SUDO_USER + ' ' + opener
}
return exec(`${opener} "${escape(target)}"`, callback)
}
}

View File

@@ -0,0 +1,97 @@
var cst = require('../../../constants.js');
var Common = require('../../Common.js');
const chalk = require('chalk');
const forEach = require('async/forEach');
const open = require('../../tools/open.js');
const Modules = require('../Modules');
function processesAreAlreadyMonitored(CLI, cb) {
CLI.Client.executeRemote('getMonitorData', {}, function(err, list) {
if (err) return cb(false);
var l = list.filter(l => l.pm2_env.km_link == true)
var l2 = list.filter(l => l.name == 'pm2-server-monit')
return cb(l.length > 0 && l2.length > 0 ? true : false)
})
}
module.exports = function(CLI) {
CLI.prototype.openDashboard = function() {
if (!this.gl_interact_infos) {
Common.printError(chalk.bold.white('Agent if offline, type `$ pm2 plus` to log in'));
return this.exitCli(cst.ERROR_EXIT);
}
var uri = `https://app.pm2.io/#/r/${this.gl_interact_infos.public_key}`
console.log(cst.PM2_IO_MSG + ` Opening ${uri}`)
open(uri);
setTimeout(_ => {
this.exitCli();
}, 200);
};
CLI.prototype.clearSetup = function (opts, cb) {
const modules = ['event-loop-inspector']
this.gl_is_km_linked = false
forEach(modules, (_module, next) => {
Modules.uninstall(this, _module, () => {
next()
});
}, (err) => {
this.reload('all', () => {
return cb()
})
})
}
/**
* Install required package and enable flags for current running processes
*/
CLI.prototype.minimumSetup = function (opts, cb) {
var self = this;
this.gl_is_km_linked = true
function install(cb) {
var modules = []
if (opts.type === 'enterprise' || opts.type === 'plus') {
modules = ['pm2-logrotate', 'pm2-server-monit']
if (opts.type === 'enterprise') {
modules.push('deep-metrics')
}
}
forEach(modules, (_module, next) => {
Modules.install(self, _module, {}, () => {
next()
});
}, (err) => {
self.reload('all', () => {
return cb()
})
})
}
processesAreAlreadyMonitored(self, (already_monitored) => {
if (already_monitored) {
console.log(cst.PM2_IO_MSG + ` PM2 ${opts.type || ''} bundle already installed`);
return cb()
}
if (opts.installAll)
return install(cb)
// promptly.confirm(chalk.bold('Install all pm2 plus dependencies ? (y/n)'), (err, answer) => {
// if (!err && answer === true)
return install(cb)
// self.reload('all', () => {
// return cb()
// })
// });
})
}
}

View File

@@ -0,0 +1,126 @@
var cst = require('../../../constants.js');
var Common = require('../../Common.js');
var chalk = require('chalk');
var fs = require('fs');
var KMDaemon = require('@pm2/agent/src/InteractorClient');
var pkg = require('../../../package.json')
module.exports = function(CLI) {
CLI.prototype.linkManagement = function(cmd, public_key, machine, opts, cb) {
var that = this;
// pm2 link stop || kill
if (cmd == 'stop' || cmd == 'kill') {
that.gl_is_km_linked = false
console.log(cst.PM2_IO_MSG + ' Stopping agent...');
return that.killAgent(function(err) {
if (err) {
Common.printError(err);
return process.exit(cst.ERROR_EXIT);
}
console.log(cst.PM2_IO_MSG + ' Stopped');
that.reload('all', () => {
return process.exit(cst.SUCCESS_EXIT);
})
});
}
// pm2 link info
if (cmd == 'info') {
console.log(cst.PM2_IO_MSG + ' Getting agent information...');
that.agentInfos(function(err, infos) {
if (err) {
console.error(cst.PM2_IO_MSG_ERR + ' ' + err.message);
return that.exitCli(cst.ERROR_EXIT);
}
console.log(infos);
return that.exitCli(cst.SUCCESS_EXIT);
});
return false;
}
// pm2 link delete
if (cmd == 'delete') {
that.gl_is_km_linked = false
console.log(cst.PM2_IO_MSG + ' Permanently disable agent...');
that.killAgent(function(err) {
try {
fs.unlinkSync(cst.INTERACTION_CONF);
} catch(e) {
console.log(cst.PM2_IO_MSG + ' No interaction config file found');
return process.exit(cst.SUCCESS_EXIT);
}
console.log(cst.PM2_IO_MSG + ' Agent interaction ended');
if (!cb)
return process.exit(cst.SUCCESS_EXIT);
return cb()
});
return false;
}
if (cmd && !public_key) {
console.error(cst.PM2_IO_MSG + ' Command [%s] unknown or missing public key', cmd);
return process.exit(cst.ERROR_EXIT);
}
// pm2 link xxx yyy
var infos;
if (!cmd) {
infos = null;
}
else
infos = {
public_key : public_key,
secret_key : cmd,
machine_name : machine,
info_node : opts.infoNode || null,
pm2_version: pkg.version
}
that.link(infos, cb)
};
CLI.prototype.link = function(infos, cb) {
var that = this;
process.env.WS_JSON_PATCH = true
KMDaemon.launchAndInteract(cst, infos, function(err, dt) {
if (err) {
Common.printError(cst.PM2_IO_MSG + ' Run `$ pm2 plus` to connect')
return that.exitCli(cst.ERROR_EXIT);
}
console.log(chalk.bold.green('[+] PM2+ activated!'))
if (!cb) {
return that.exitCli(cst.SUCCESS_EXIT);
}
return cb(null, dt)
});
};
CLI.prototype.agentInfos = function(cb) {
KMDaemon.getInteractInfo(this._conf, function(err, data) {
if (err)
return cb(Common.retErr(err));
return cb(null, data);
});
};
CLI.prototype.killAgent = function(cb) {
var that = this;
KMDaemon.killInteractorDaemon(that._conf, function(err) {
if (err)
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.SUCCESS_EXIT);
return cb ? cb(null) : that.exitCli(cst.SUCCESS_EXIT);
});
};
CLI.prototype.unlink = function(cb) {
this.linkManagement('delete', cb);
};
};

View File

@@ -0,0 +1,16 @@
██████╗ ███╗ ███╗██████╗ ██╗ ██╗ ██████╗
██╔══██╗████╗ ████║╚════██╗ ██║ ██╔╝██╔═══██╗
██████╔╝██╔████╔██║ █████╔╝ ██║ ██╔╝ ██║ ██║
██╔═══╝ ██║╚██╔╝██║██╔═══╝ ██║ ██╔╝ ██║ ██║
██║ ██║ ╚═╝ ██║███████╗ ██║██╔╝ ╚██████╔╝
╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝╚═╝ ╚═════╝
https://pm2.io/
Harden your Node.js Production Environment
- Real-time Monitoring Web Interface
- Pro Active Alerting System
- Production Profiling for Memory and CPU
- PM2 Runtime High Availability Fallback

View File

@@ -0,0 +1,26 @@
-------------
██████╗ ███╗ ███╗██████╗ ██╗ ██╗ ██████╗
██╔══██╗████╗ ████║╚════██╗ ██║ ██╔╝██╔═══██╗
██████╔╝██╔████╔██║ █████╔╝ ██║ ██╔╝ ██║ ██║
██╔═══╝ ██║╚██╔╝██║██╔═══╝ ██║ ██╔╝ ██║ ██║
██║ ██║ ╚═╝ ██║███████╗ ██║██╔╝ ╚██████╔╝
╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝╚═╝ ╚═════╝
https://pm2.io/
Harden your Node.js Production Environment
- Real-time Monitoring Web Interface
- Pro Active Alerting System
- Production Profiling for Memory and CPU
- PM2 Runtime High Availability Fallback
Start using it by typing:
$ pm2 plus
-------------

View File

@@ -0,0 +1,28 @@
-------------
PM2 Plus Edition
PM2 Plus is a monitoring dashboard
specialized for Node.js Apps.
Create an account:
$ pm2 plus register
Connect your local PM2 to the PM2 Plus servers:
$ pm2 plus connect
See our UI with your own realtime dashboard:
$ pm2 plus web
More details available there:
http://pm2.io/plus
-------------
Having complex or specific needs?
You can also checkout our enterprise offer at:
http://pm2.io/enterprise
-------------

View File

@@ -0,0 +1,52 @@
const fs = require('fs');
const forEachLimit = require('async/forEachLimit');
var cst = require('../../../constants.js');
var Common = require('../../Common.js');
module.exports = function(CLI) {
/**
* Monitor Selectively Processes (auto filter in interaction)
* @param String state 'monitor' or 'unmonitor'
* @param String target <pm_id|name|all>
* @param Function cb callback
*/
CLI.prototype.monitorState = function(state, target, cb) {
var that = this;
if (!target) {
Common.printError(cst.PREFIX_MSG_ERR + 'Please specify an <app_name|pm_id>');
return cb ? cb(new Error('argument missing')) : that.exitCli(cst.ERROR_EXIT);
}
function monitor (pm_id, cb) {
// State can be monitor or unmonitor
that.Client.executeRemote(state, pm_id, cb);
}
if (target === 'all') {
that.Client.getAllProcessId(function (err, procs) {
if (err) {
Common.printError(err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
forEachLimit(procs, 1, monitor, function (err, res) {
return typeof cb === 'function' ? cb(err, res) : that.speedList();
});
});
} else if (!Number.isInteger(parseInt(target))) {
this.Client.getProcessIdByName(target, true, function (err, procs) {
if (err) {
Common.printError(err);
return cb ? cb(Common.retErr(err)) : that.exitCli(cst.ERROR_EXIT);
}
forEachLimit(procs, 1, monitor, function (err, res) {
return typeof cb === 'function' ? cb(err, res) : that.speedList();
});
});
} else {
monitor(parseInt(target), function (err, res) {
return typeof cb === 'function' ? cb(err, res) : that.speedList();
});
}
};
}

375
api.hyungi.net/node_modules/pm2/lib/API/schema.json generated vendored Normal file
View File

@@ -0,0 +1,375 @@
{
"script": {
"type": "string",
"require": true,
"alias" : "exec",
"docDescription": "Path of the script to launch, required field"
},
"name": {
"type": "string",
"docDefault": "Script filename without the extension (app for app.js)",
"docDescription": "Process name in the process list"
},
"name_prefix": {
"type": "string"
},
"filter_env": {
"type": [
"boolean",
"array",
"string"
],
"docDefault": false,
"docDescription": "Enable filtering global environments"
},
"namespace": {
"type": "string",
"docDefault": "default",
"docDescription": "Process namespace"
},
"install_url": {
"type": "string"
},
"cwd": {
"type": "string",
"docDefault": "CWD of the current environment (from your shell)",
"docDescription": "Current working directory to start the process with"
},
"args": {
"type": [
"array",
"string"
],
"docDescription": "Arguments to pass to the script"
},
"exec_interpreter": {
"type": "string",
"alias": "interpreter",
"docDefault": "node",
"docDescription": "Interpreter absolute path"
},
"node_args": {
"type": [
"array",
"string"
],
"alias": ["interpreterArgs", "interpreter_args"],
"docDescription": "Arguments to pass to the interpreter"
},
"out_file": {
"type": "string",
"alias": ["out", "output", "out_log"],
"docDefault": "~/.pm2/logs/<app_name>-out.log",
"docDescription": "File path for stdout (each line is appended to this file)"
},
"error_file": {
"type": "string",
"alias": ["error", "err", "err_file", "err_log"],
"docDefault": "~/.pm2/logs/<app_name>-error.err",
"docDescription": "File path for stderr (each line is appended to this file)"
},
"log_file": {
"type": [
"boolean",
"string"
],
"alias": "log",
"docDefault": "/dev/null",
"docDescription": "File path for combined stdout and stderr (each line is appended to this file)"
},
"disable_logs": {
"type": "boolean",
"docDefault": false,
"docDescription": "Disable all logs storage"
},
"log_type": {
"type": "string",
"docDescription": "Define a specific log output type, possible value: json"
},
"log_date_format": {
"type": "string",
"docDescription": "Format for log timestamps in day.js format (eg YYYY-MM-DD HH:mm Z)"
},
"time": {
"type": "boolean"
},
"env": {
"type": [
"object",
"string"
],
"docDescription": "Specify environment variables to be injected"
},
"^env_\\S*$": {
"type": [
"object",
"string"
],
"docDescription": "Specify environment variables to be injected when using --env <env_name>"
},
"max_memory_restart": {
"type": [
"string",
"number"
],
"regex": "^\\d+(G|M|K)?$",
"ext_type": "sbyte",
"desc": "it should be a NUMBER - byte, \"[NUMBER]G\"(Gigabyte), \"[NUMBER]M\"(Megabyte) or \"[NUMBER]K\"(Kilobyte)",
"docDescription": "Restart the app if an amount of memory is exceeded (format: /[0-9](K&#124;M&#124;G)?/ K for KB, 'M' for MB, 'G' for GB, default to B)"
},
"pid_file": {
"type": "string",
"alias": "pid",
"docDefault": "~/.pm2/pids/app_name-id.pid",
"docDescription": "File path where the pid of the started process is written by pm2"
},
"restart_delay": {
"type" : "number",
"docDefault": 0,
"docDescription": "Time in ms to wait before restarting a crashing app"
},
"exp_backoff_restart_delay": {
"type": "number",
"docDefault": 0,
"docDescription": "Restart Time in ms to wait before restarting a crashing app"
},
"source_map_support": {
"type": "boolean",
"docDefault": true,
"docDescription": "Enable or disable the source map support"
},
"disable_source_map_support": {
"type": "boolean",
"docDefault": false,
"docDescription": "Enable or disable the source map support"
},
"wait_ready": {
"type": "boolean",
"docDefault": false,
"docDescription": "Make the process wait for a process.send('ready')"
},
"instances": {
"type": "number",
"docDefault": 1,
"docDescription": "Number of instances to be started in cluster mode"
},
"kill_timeout": {
"type": "number",
"docDefault": 1600,
"docDescription": "Time in ms before sending the final SIGKILL signal after SIGINT"
},
"shutdown_with_message": {
"type": "boolean",
"docDefault": false,
"docDescription": "Shutdown an application with process.send('shutdown') instead of process.kill(pid, SIGINT)"
},
"listen_timeout": {
"type": "number",
"docDescription": "Time in ms before forcing a reload if app is still not listening/has still note sent ready"
},
"cron_restart": {
"type": [
"string",
"number"
],
"alias": "cron",
"docDescription": "A cron pattern to restart your app"
},
"merge_logs": {
"type": "boolean",
"alias" : "combine_logs",
"docDefault": false,
"docDescription": "In cluster mode, merge each type of logs into a single file (instead of having one for each cluster)"
},
"vizion": {
"type": "boolean",
"default" : true,
"docDefault" : "True",
"docDescription": "Enable or disable the versioning metadatas (vizion library)"
},
"autostart": {
"type": "boolean",
"default": true,
"docDefault": "True",
"docDescription": "Enable or disable auto start when adding process"
},
"autorestart": {
"type": "boolean",
"default": true,
"docDefault": "True",
"docDescription": "Enable or disable auto restart after process failure"
},
"stop_exit_codes": {
"type": [
"array",
"number"
],
"docDescription": "List of exit codes that should allow the process to stop (skip autorestart)."
},
"watch_delay": {
"type": "number",
"docDefault": "True",
"docDescription": "Restart delay on file change detected"
},
"watch": {
"type": [
"boolean",
"array",
"string"
],
"docDefault": false,
"docDescription": "Enable or disable the watch mode"
},
"ignore_watch": {
"type": [
"array",
"string"
],
"docDescription": "List of paths to ignore (regex)"
},
"watch_options": {
"type": "object",
"docDescription": "Object that will be used as an options with chokidar (refer to chokidar documentation)"
},
"min_uptime": {
"type": [
"number",
"string"
],
"regex": "^\\d+(h|m|s)?$",
"desc": "it should be a NUMBER - milliseconds, \"[NUMBER]h\"(hours), \"[NUMBER]m\"(minutes) or \"[NUMBER]s\"(seconds)",
"min": 100,
"ext_type": "stime",
"docDefault": 1000,
"docDescription": "Minimum uptime of the app to be considered started (format is /[0-9]+(h&#124;m&#124;s)?/, for hours, minutes, seconds, docDefault to ms)"
},
"max_restarts": {
"type": "number",
"min": 0,
"docDefault": 16,
"docDescription": "Number of times a script is restarted when it exits in less than min_uptime"
},
"execute_command": {
"type": "boolean"
},
"exec_mode": {
"type": "string",
"regex": "^(cluster|fork)(_mode)?$",
"desc": "it should be \"cluster\"(\"cluster_mode\") or \"fork\"(\"fork_mode\") only",
"docDefault": "fork",
"docDescription": "Set the execution mode, possible values: fork&#124;cluster"
},
"force": {
"type": "boolean",
"docDefault": false,
"docDescription": "Start a script even if it is already running (only the script path is considered)"
},
"append_env_to_name": {
"type": "boolean",
"docDefault": false,
"docDescription": "Append the environment name to the app name"
},
"post_update": {
"type": "array",
"docDescription": "List of commands executed after a pull/upgrade operation performed from Keymetrics dashboard"
},
"trace": {
"type": [
"boolean"
],
"docDefault": false,
"docDescription": "Enable or disable the transaction tracing"
},
"disable_trace": {
"type": [
"boolean"
],
"docDefault": true,
"docDescription": "Enable or disable the transaction tracing"
},
"v8": {
"type": [
"boolean"
]
},
"event_loop_inspector": {
"type": [
"boolean"
]
},
"deep_monitoring": {
"type": [
"boolean"
]
},
"increment_var": {
"type": "string",
"docDescription": "Specify the name of an environment variable to inject which increments for each cluster"
},
"instance_var": {
"type": "string",
"default": "NODE_APP_INSTANCE",
"docDefault": "NODE_APP_INSTANCE",
"docDescription": "Rename the NODE_APP_INSTANCE environment variable"
},
"pmx": {
"type": ["boolean", "string"],
"default": true,
"docDefault": "True",
"docDescription": "Enable or disable pmx wrapping"
},
"automation": {
"type": "boolean",
"default": true,
"docDefault": "True",
"docDescription": "Enable or disable pmx wrapping"
},
"treekill": {
"type": "boolean",
"default": true,
"docDefault": "True",
"docDescription": "Only kill the main process, not detached children"
},
"port": {
"type": "number",
"docDescription": "Shortcut to inject a PORT environment variable"
},
"username" : {
"type": "string",
"docDescription": "Current user that started the process"
},
"uid": {
"type" : [
"number",
"string"
],
"alias": "user",
"docDefault": "Current user uid",
"docDescription": "Set user id"
},
"gid": {
"type" : [
"number",
"string"
],
"docDefault": "Current user gid",
"docDescription": "Set group id"
},
"windowsHide": {
"type": "boolean",
"docDefault": "True",
"docDescription": "Enable or disable the Windows popup when starting an app",
"default": true
},
"kill_retry_time": {
"type": "number",
"default" : 100
},
"write": {
"type": "boolean"
},
"io": {
"type": "object",
"docDescription": "Specify apm values and configuration"
}
}