Client.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. /**
  2. * Copyright 2013-2022 the PM2 project authors. All rights reserved.
  3. * Use of this source code is governed by a license that
  4. * can be found in the LICENSE file.
  5. */
  6. var debug = require('debug')('pm2:client');
  7. var Common = require('./Common.js');
  8. var KMDaemon = require('@pm2/agent/src/InteractorClient');
  9. var rpc = require('pm2-axon-rpc');
  10. var forEach = require('async/forEach');
  11. var axon = require('pm2-axon');
  12. var util = require('util');
  13. var fs = require('fs');
  14. var path = require('path');
  15. var pkg = require('../package.json');
  16. var which = require('./tools/which.js');
  17. function noop() {}
  18. var Client = module.exports = function(opts) {
  19. if (!opts) opts = {};
  20. if (!opts.conf)
  21. this.conf = require('../constants.js');
  22. else {
  23. this.conf = opts.conf;
  24. }
  25. this.daemon_mode = typeof(opts.daemon_mode) === 'undefined' ? true : opts.daemon_mode;
  26. this.pm2_home = this.conf.PM2_ROOT_PATH;
  27. this.secret_key = opts.secret_key;
  28. this.public_key = opts.public_key;
  29. this.machine_name = opts.machine_name;
  30. // Create all folders and files needed
  31. // Client depends to that to interact with PM2 properly
  32. this.initFileStructure(this.conf);
  33. debug('Using RPC file %s', this.conf.DAEMON_RPC_PORT);
  34. debug('Using PUB file %s', this.conf.DAEMON_PUB_PORT);
  35. this.rpc_socket_file = this.conf.DAEMON_RPC_PORT;
  36. this.pub_socket_file = this.conf.DAEMON_PUB_PORT;
  37. };
  38. // @breaking change (noDaemonMode has been drop)
  39. // @todo ret err
  40. Client.prototype.start = function(cb) {
  41. var that = this;
  42. this.pingDaemon(function(daemonAlive) {
  43. if (daemonAlive === true)
  44. return that.launchRPC(function(err, meta) {
  45. return cb(null, {
  46. daemon_mode : that.conf.daemon_mode,
  47. new_pm2_instance : false,
  48. rpc_socket_file : that.rpc_socket_file,
  49. pub_socket_file : that.pub_socket_file,
  50. pm2_home : that.pm2_home
  51. });
  52. });
  53. /**
  54. * No Daemon mode
  55. */
  56. if (that.daemon_mode === false) {
  57. var Daemon = require('./Daemon.js');
  58. var daemon = new Daemon({
  59. pub_socket_file : that.conf.DAEMON_PUB_PORT,
  60. rpc_socket_file : that.conf.DAEMON_RPC_PORT,
  61. pid_file : that.conf.PM2_PID_FILE_PATH,
  62. ignore_signals : true
  63. });
  64. console.log('Launching in no daemon mode');
  65. daemon.innerStart(function() {
  66. KMDaemon.launchAndInteract(that.conf, {
  67. machine_name : that.machine_name,
  68. public_key : that.public_key,
  69. secret_key : that.secret_key,
  70. pm2_version : pkg.version
  71. }, function(err, data, interactor_proc) {
  72. that.interactor_process = interactor_proc;
  73. });
  74. that.launchRPC(function(err, meta) {
  75. return cb(null, {
  76. daemon_mode : that.conf.daemon_mode,
  77. new_pm2_instance : true,
  78. rpc_socket_file : that.rpc_socket_file,
  79. pub_socket_file : that.pub_socket_file,
  80. pm2_home : that.pm2_home
  81. });
  82. });
  83. });
  84. return false;
  85. }
  86. /**
  87. * Daemon mode
  88. */
  89. that.launchDaemon(function(err, child) {
  90. if (err) {
  91. Common.printError(err);
  92. return cb ? cb(err) : process.exit(that.conf.ERROR_EXIT);
  93. }
  94. if (!process.env.PM2_DISCRETE_MODE)
  95. Common.printOut(that.conf.PREFIX_MSG + 'PM2 Successfully daemonized');
  96. that.launchRPC(function(err, meta) {
  97. return cb(null, {
  98. daemon_mode : that.conf.daemon_mode,
  99. new_pm2_instance : true,
  100. rpc_socket_file : that.rpc_socket_file,
  101. pub_socket_file : that.pub_socket_file,
  102. pm2_home : that.pm2_home
  103. });
  104. });
  105. });
  106. });
  107. };
  108. // Init file structure of pm2_home
  109. // This includes
  110. // - pm2 pid and log path
  111. // - rpc and pub socket for command execution
  112. Client.prototype.initFileStructure = function (opts) {
  113. if (!fs.existsSync(opts.DEFAULT_LOG_PATH)) {
  114. try {
  115. require('mkdirp').sync(opts.DEFAULT_LOG_PATH);
  116. } catch (e) {
  117. console.error(e.stack || e);
  118. }
  119. }
  120. if (!fs.existsSync(opts.DEFAULT_PID_PATH)) {
  121. try {
  122. require('mkdirp').sync(opts.DEFAULT_PID_PATH);
  123. } catch (e) {
  124. console.error(e.stack || e);
  125. }
  126. }
  127. if (!fs.existsSync(opts.PM2_MODULE_CONF_FILE)) {
  128. try {
  129. fs.writeFileSync(opts.PM2_MODULE_CONF_FILE, "{}");
  130. } catch (e) {
  131. console.error(e.stack || e);
  132. }
  133. }
  134. if (!fs.existsSync(opts.DEFAULT_MODULE_PATH)) {
  135. try {
  136. require('mkdirp').sync(opts.DEFAULT_MODULE_PATH);
  137. } catch (e) {
  138. console.error(e.stack || e);
  139. }
  140. }
  141. if (process.env.PM2_DISCRETE_MODE) {
  142. try {
  143. fs.writeFileSync(path.join(opts.PM2_HOME, 'touch'), Date.now().toString());
  144. } catch(e) {
  145. debug(e.stack || e);
  146. }
  147. }
  148. if (!process.env.PM2_PROGRAMMATIC && !fs.existsSync(path.join(opts.PM2_HOME, 'touch'))) {
  149. var vCheck = require('./VersionCheck.js')
  150. vCheck({
  151. state: 'install',
  152. version: pkg.version
  153. })
  154. var dt = fs.readFileSync(path.join(__dirname, opts.PM2_BANNER));
  155. console.log(dt.toString());
  156. try {
  157. fs.writeFileSync(path.join(opts.PM2_HOME, 'touch'), Date.now().toString());
  158. } catch(e) {
  159. debug(e.stack || e);
  160. }
  161. }
  162. };
  163. Client.prototype.close = function(cb) {
  164. var that = this;
  165. forEach([
  166. that.disconnectRPC.bind(that),
  167. that.disconnectBus.bind(that)
  168. ], function(fn, next) {
  169. fn(next)
  170. }, cb);
  171. };
  172. /**
  173. * Launch the Daemon by forking this same file
  174. * The method Client.remoteWrapper will be called
  175. *
  176. * @method launchDaemon
  177. * @param {Object} opts
  178. * @param {Object} [opts.interactor=true] allow to disable interaction on launch
  179. */
  180. Client.prototype.launchDaemon = function(opts, cb) {
  181. if (typeof(opts) == 'function') {
  182. cb = opts;
  183. opts = {
  184. interactor : true
  185. };
  186. }
  187. var that = this
  188. var ClientJS = path.resolve(path.dirname(module.filename), 'Daemon.js');
  189. var node_args = [];
  190. var out, err;
  191. // if (process.env.TRAVIS) {
  192. // // Redirect PM2 internal err and out to STDERR STDOUT when running with Travis
  193. // out = 1;
  194. // err = 2;
  195. // }
  196. // else {
  197. out = fs.openSync(that.conf.PM2_LOG_FILE_PATH, 'a'),
  198. err = fs.openSync(that.conf.PM2_LOG_FILE_PATH, 'a');
  199. //}
  200. if (this.conf.LOW_MEMORY_ENVIRONMENT) {
  201. var os = require('os');
  202. node_args.push('--gc-global'); // Does full GC (smaller memory footprint)
  203. node_args.push('--max-old-space-size=' + Math.floor(os.totalmem() / 1024 / 1024));
  204. }
  205. // Node.js tuning for better performance
  206. //node_args.push('--expose-gc'); // Allows manual GC in the code
  207. /**
  208. * Add node [arguments] depending on PM2_NODE_OPTIONS env variable
  209. */
  210. if (process.env.PM2_NODE_OPTIONS)
  211. node_args = node_args.concat(process.env.PM2_NODE_OPTIONS.split(' '));
  212. node_args.push(ClientJS);
  213. if (!process.env.PM2_DISCRETE_MODE)
  214. Common.printOut(that.conf.PREFIX_MSG + 'Spawning PM2 daemon with pm2_home=' + this.pm2_home);
  215. var interpreter = 'node';
  216. if (which('node') == null)
  217. interpreter = process.execPath;
  218. var child = require('child_process').spawn(interpreter, node_args, {
  219. detached : true,
  220. cwd : that.conf.cwd || process.cwd(),
  221. windowsHide: true,
  222. env : Object.assign({
  223. 'SILENT' : that.conf.DEBUG ? !that.conf.DEBUG : true,
  224. 'PM2_HOME' : that.pm2_home
  225. }, process.env),
  226. stdio : ['ipc', out, err]
  227. });
  228. function onError(e) {
  229. console.error(e.message || e);
  230. return cb ? cb(e.message || e) : false;
  231. }
  232. child.once('error', onError);
  233. child.unref();
  234. child.once('message', function(msg) {
  235. debug('PM2 daemon launched with return message: ', msg);
  236. child.removeListener('error', onError);
  237. child.disconnect();
  238. if (opts && opts.interactor == false)
  239. return cb(null, child);
  240. if (process.env.PM2_NO_INTERACTION == 'true')
  241. return cb(null, child);
  242. /**
  243. * Here the Keymetrics agent is launched automaticcaly if
  244. * it has been already configured before (via pm2 link)
  245. */
  246. KMDaemon.launchAndInteract(that.conf, {
  247. machine_name : that.machine_name,
  248. public_key : that.public_key,
  249. secret_key : that.secret_key,
  250. pm2_version : pkg.version
  251. }, function(err, data, interactor_proc) {
  252. that.interactor_process = interactor_proc;
  253. return cb(null, child);
  254. });
  255. });
  256. };
  257. /**
  258. * Ping the daemon to know if it alive or not
  259. * @api public
  260. * @method pingDaemon
  261. * @param {} cb
  262. * @return
  263. */
  264. Client.prototype.pingDaemon = function pingDaemon(cb) {
  265. var req = axon.socket('req');
  266. var client = new rpc.Client(req);
  267. var that = this;
  268. debug('[PING PM2] Trying to connect to server');
  269. client.sock.once('reconnect attempt', function() {
  270. client.sock.close();
  271. debug('Daemon not launched');
  272. process.nextTick(function() {
  273. return cb(false);
  274. });
  275. });
  276. client.sock.once('error', function(e) {
  277. if (e.code === 'EACCES') {
  278. fs.stat(that.conf.DAEMON_RPC_PORT, function(e, stats) {
  279. if (stats.uid === 0) {
  280. console.error(that.conf.PREFIX_MSG_ERR + 'Permission denied, to give access to current user:');
  281. console.log('$ sudo chown ' + process.env.USER + ':' + process.env.USER + ' ' + that.conf.DAEMON_RPC_PORT + ' ' + that.conf.DAEMON_PUB_PORT);
  282. }
  283. else
  284. console.error(that.conf.PREFIX_MSG_ERR + 'Permission denied, check permissions on ' + that.conf.DAEMON_RPC_PORT);
  285. process.exit(1);
  286. });
  287. }
  288. else
  289. console.error(e.message || e);
  290. });
  291. client.sock.once('connect', function() {
  292. client.sock.once('close', function() {
  293. return cb(true);
  294. });
  295. client.sock.close();
  296. debug('Daemon alive');
  297. });
  298. req.connect(this.rpc_socket_file);
  299. };
  300. /**
  301. * Methods to interact with the Daemon via RPC
  302. * This method wait to be connected to the Daemon
  303. * Once he's connected it trigger the command parsing (on ./bin/pm2 file, at the end)
  304. * @method launchRPC
  305. * @params {function} [cb]
  306. * @return
  307. */
  308. Client.prototype.launchRPC = function launchRPC(cb) {
  309. var self = this;
  310. debug('Launching RPC client on socket file %s', this.rpc_socket_file);
  311. var req = axon.socket('req');
  312. this.client = new rpc.Client(req);
  313. var connectHandler = function() {
  314. self.client.sock.removeListener('error', errorHandler);
  315. debug('RPC Connected to Daemon');
  316. if (cb) {
  317. setTimeout(function() {
  318. cb(null);
  319. }, 4);
  320. }
  321. };
  322. var errorHandler = function(e) {
  323. self.client.sock.removeListener('connect', connectHandler);
  324. if (cb) {
  325. return cb(e);
  326. }
  327. };
  328. this.client.sock.once('connect', connectHandler);
  329. this.client.sock.once('error', errorHandler);
  330. this.client_sock = req.connect(this.rpc_socket_file);
  331. };
  332. /**
  333. * Methods to close the RPC connection
  334. * @callback cb
  335. */
  336. Client.prototype.disconnectRPC = function disconnectRPC(cb) {
  337. var that = this;
  338. if (!cb) cb = noop;
  339. if (!this.client_sock || !this.client_sock.close) {
  340. this.client = null;
  341. return process.nextTick(function() {
  342. cb(new Error('SUB connection to PM2 is not launched'));
  343. });
  344. }
  345. if (this.client_sock.connected === false ||
  346. this.client_sock.closing === true) {
  347. this.client = null;
  348. return process.nextTick(function() {
  349. cb(new Error('RPC already being closed'));
  350. });
  351. }
  352. try {
  353. var timer;
  354. that.client_sock.once('close', function() {
  355. clearTimeout(timer);
  356. that.client = null;
  357. debug('PM2 RPC cleanly closed');
  358. return cb(null, { msg : 'RPC Successfully closed' });
  359. });
  360. timer = setTimeout(function() {
  361. if (that.client_sock.destroy)
  362. that.client_sock.destroy();
  363. that.client = null;
  364. return cb(null, { msg : 'RPC Successfully closed via timeout' });
  365. }, 200);
  366. that.client_sock.close();
  367. } catch(e) {
  368. debug('Error while disconnecting RPC PM2', e.stack || e);
  369. return cb(e);
  370. }
  371. return false;
  372. };
  373. Client.prototype.launchBus = function launchEventSystem(cb) {
  374. var self = this;
  375. this.sub = axon.socket('sub-emitter');
  376. this.sub_sock = this.sub.connect(this.pub_socket_file);
  377. this.sub_sock.once('connect', function() {
  378. return cb(null, self.sub, self.sub_sock);
  379. });
  380. };
  381. Client.prototype.disconnectBus = function disconnectBus(cb) {
  382. if (!cb) cb = noop;
  383. var that = this;
  384. if (!this.sub_sock || !this.sub_sock.close) {
  385. that.sub = null;
  386. return process.nextTick(function() {
  387. cb(null, { msg : 'bus was not connected'});
  388. });
  389. }
  390. if (this.sub_sock.connected === false ||
  391. this.sub_sock.closing === true) {
  392. that.sub = null;
  393. return process.nextTick(function() {
  394. cb(new Error('SUB connection is already being closed'));
  395. });
  396. }
  397. try {
  398. var timer;
  399. that.sub_sock.once('close', function() {
  400. that.sub = null;
  401. clearTimeout(timer);
  402. debug('PM2 PUB cleanly closed');
  403. return cb();
  404. });
  405. timer = setTimeout(function() {
  406. if (Client.sub_sock.destroy)
  407. that.sub_sock.destroy();
  408. return cb();
  409. }, 200);
  410. this.sub_sock.close();
  411. } catch(e) {
  412. return cb(e);
  413. }
  414. };
  415. /**
  416. * Description
  417. * @method gestExposedMethods
  418. * @param {} cb
  419. * @return
  420. */
  421. Client.prototype.getExposedMethods = function getExposedMethods(cb) {
  422. this.client.methods(cb);
  423. };
  424. /**
  425. * Description
  426. * @method executeRemote
  427. * @param {} method
  428. * @param {} env
  429. * @param {} fn
  430. * @return
  431. */
  432. Client.prototype.executeRemote = function executeRemote(method, app_conf, fn) {
  433. var self = this;
  434. // stop watch on stop | env is the process id
  435. if (method.indexOf('stop') !== -1) {
  436. this.stopWatch(method, app_conf);
  437. }
  438. // stop watching when process is deleted
  439. else if (method.indexOf('delete') !== -1) {
  440. this.stopWatch(method, app_conf);
  441. }
  442. // stop everything on kill
  443. else if (method.indexOf('kill') !== -1) {
  444. this.stopWatch('deleteAll', app_conf);
  445. }
  446. else if (method.indexOf('restartProcessId') !== -1 && process.argv.indexOf('--watch') > -1) {
  447. delete app_conf.env.current_conf.watch;
  448. this.toggleWatch(method, app_conf);
  449. }
  450. if (!this.client || !this.client.call) {
  451. this.start(function(error) {
  452. if (error) {
  453. if (fn)
  454. return fn(error);
  455. console.error(error);
  456. return process.exit(0);
  457. }
  458. if (self.client) {
  459. return self.client.call(method, app_conf, fn);
  460. }
  461. });
  462. return false;
  463. }
  464. debug('Calling daemon method pm2:%s on rpc socket:%s', method, this.rpc_socket_file);
  465. return this.client.call(method, app_conf, fn);
  466. };
  467. Client.prototype.notifyGod = function(action_name, id, cb) {
  468. this.executeRemote('notifyByProcessId', {
  469. id : id,
  470. action_name : action_name,
  471. manually : true
  472. }, function() {
  473. debug('God notified');
  474. return cb ? cb() : false;
  475. });
  476. };
  477. Client.prototype.killDaemon = function killDaemon(fn) {
  478. var timeout;
  479. var that = this;
  480. function quit() {
  481. that.close(function() {
  482. return fn ? fn(null, {success:true}) : false;
  483. });
  484. }
  485. // under unix, we listen for signal (that is send by daemon to notify us that its shuting down)
  486. if (process.platform !== 'win32' && process.platform !== 'win64') {
  487. process.once('SIGQUIT', function() {
  488. debug('Received SIGQUIT from pm2 daemon');
  489. clearTimeout(timeout);
  490. quit();
  491. });
  492. }
  493. else {
  494. // if under windows, try to ping the daemon to see if it still here
  495. setTimeout(function() {
  496. that.pingDaemon(function(alive) {
  497. if (!alive) {
  498. clearTimeout(timeout);
  499. return quit();
  500. }
  501. });
  502. }, 250)
  503. }
  504. timeout = setTimeout(function() {
  505. quit();
  506. }, 3000);
  507. // Kill daemon
  508. this.executeRemote('killMe', {pid : process.pid});
  509. };
  510. /**
  511. * Description
  512. * @method toggleWatch
  513. * @param {String} pm2 method name
  514. * @param {Object} application environment, should include id
  515. * @param {Function} callback
  516. */
  517. Client.prototype.toggleWatch = function toggleWatch(method, env, fn) {
  518. debug('Calling toggleWatch');
  519. this.client.call('toggleWatch', method, env, function() {
  520. return fn ? fn() : false;
  521. });
  522. };
  523. /**
  524. * Description
  525. * @method startWatch
  526. * @param {String} pm2 method name
  527. * @param {Object} application environment, should include id
  528. * @param {Function} callback
  529. */
  530. Client.prototype.startWatch = function restartWatch(method, env, fn) {
  531. debug('Calling startWatch');
  532. this.client.call('startWatch', method, env, function() {
  533. return fn ? fn() : false;
  534. });
  535. };
  536. /**
  537. * Description
  538. * @method stopWatch
  539. * @param {String} pm2 method name
  540. * @param {Object} application environment, should include id
  541. * @param {Function} callback
  542. */
  543. Client.prototype.stopWatch = function stopWatch(method, env, fn) {
  544. debug('Calling stopWatch');
  545. this.client.call('stopWatch', method, env, function() {
  546. return fn ? fn() : false;
  547. });
  548. };
  549. Client.prototype.getAllProcess = function(cb) {
  550. var found_proc = [];
  551. this.executeRemote('getMonitorData', {}, function(err, procs) {
  552. if (err) {
  553. Common.printError('Error retrieving process list: ' + err);
  554. return cb(err);
  555. }
  556. return cb(null, procs);
  557. });
  558. };
  559. Client.prototype.getAllProcessId = function(cb) {
  560. var found_proc = [];
  561. this.executeRemote('getMonitorData', {}, function(err, procs) {
  562. if (err) {
  563. Common.printError('Error retrieving process list: ' + err);
  564. return cb(err);
  565. }
  566. return cb(null, procs.map(proc => proc.pm_id));
  567. });
  568. };
  569. Client.prototype.getAllProcessIdWithoutModules = function(cb) {
  570. var found_proc = [];
  571. this.executeRemote('getMonitorData', {}, function(err, procs) {
  572. if (err) {
  573. Common.printError('Error retrieving process list: ' + err);
  574. return cb(err);
  575. }
  576. var proc_ids = procs
  577. .filter(proc => !proc.pm2_env.pmx_module)
  578. .map(proc => proc.pm_id)
  579. return cb(null, proc_ids);
  580. });
  581. };
  582. Client.prototype.getProcessIdByName = function(name, force_all, cb) {
  583. var found_proc = [];
  584. var full_details = {};
  585. if (typeof(cb) === 'undefined') {
  586. cb = force_all;
  587. force_all = false;
  588. }
  589. if (typeof(name) == 'number')
  590. name = name.toString();
  591. this.executeRemote('getMonitorData', {}, function(err, list) {
  592. if (err) {
  593. Common.printError('Error retrieving process list: ' + err);
  594. return cb(err);
  595. }
  596. list.forEach(function(proc) {
  597. if (proc.pm2_env.name == name || proc.pm2_env.pm_exec_path == path.resolve(name)) {
  598. found_proc.push(proc.pm_id);
  599. full_details[proc.pm_id] = proc;
  600. }
  601. });
  602. return cb(null, found_proc, full_details);
  603. });
  604. };
  605. Client.prototype.getProcessIdsByNamespace = function(namespace, force_all, cb) {
  606. var found_proc = [];
  607. var full_details = {};
  608. if (typeof(cb) === 'undefined') {
  609. cb = force_all;
  610. force_all = false;
  611. }
  612. if (typeof(namespace) == 'number')
  613. namespace = namespace.toString();
  614. this.executeRemote('getMonitorData', {}, function(err, list) {
  615. if (err) {
  616. Common.printError('Error retrieving process list: ' + err);
  617. return cb(err);
  618. }
  619. list.forEach(function(proc) {
  620. if (proc.pm2_env.namespace == namespace) {
  621. found_proc.push(proc.pm_id);
  622. full_details[proc.pm_id] = proc;
  623. }
  624. });
  625. return cb(null, found_proc, full_details);
  626. });
  627. };
  628. Client.prototype.getProcessByName = function(name, cb) {
  629. var found_proc = [];
  630. this.executeRemote('getMonitorData', {}, function(err, list) {
  631. if (err) {
  632. Common.printError('Error retrieving process list: ' + err);
  633. return cb(err);
  634. }
  635. list.forEach(function(proc) {
  636. if (proc.pm2_env.name == name ||
  637. proc.pm2_env.pm_exec_path == path.resolve(name)) {
  638. found_proc.push(proc);
  639. }
  640. });
  641. return cb(null, found_proc);
  642. });
  643. };
  644. Client.prototype.getProcessByNameOrId = function (nameOrId, cb) {
  645. var foundProc = [];
  646. this.executeRemote('getMonitorData', {}, function (err, list) {
  647. if (err) {
  648. Common.printError('Error retrieving process list: ' + err);
  649. return cb(err);
  650. }
  651. list.forEach(function (proc) {
  652. if (proc.pm2_env.name === nameOrId ||
  653. proc.pm2_env.pm_exec_path === path.resolve(nameOrId) ||
  654. proc.pid === parseInt(nameOrId) ||
  655. proc.pm2_env.pm_id === parseInt(nameOrId)) {
  656. foundProc.push(proc);
  657. }
  658. });
  659. return cb(null, foundProc);
  660. });
  661. };