@zappinginc/zm2 6.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/.gitattributes +4 -0
  3. package/.mocharc.js +14 -0
  4. package/CHANGELOG.md +2416 -0
  5. package/CLAUDE.md +84 -0
  6. package/CONTRIBUTING.md +124 -0
  7. package/GNU-AGPL-3.0.txt +665 -0
  8. package/LICENSE +1 -0
  9. package/README.md +248 -0
  10. package/bin/zm2 +3 -0
  11. package/bin/zm2-dev +3 -0
  12. package/bin/zm2-docker +3 -0
  13. package/bin/zm2-runtime +3 -0
  14. package/bin/zm2-windows +3 -0
  15. package/bin/zm2.ps1 +3 -0
  16. package/bun.lock +421 -0
  17. package/constants.js +114 -0
  18. package/index.js +13 -0
  19. package/lib/API/Configuration.js +212 -0
  20. package/lib/API/Containerizer.js +335 -0
  21. package/lib/API/Dashboard.js +459 -0
  22. package/lib/API/Deploy.js +117 -0
  23. package/lib/API/Extra.js +775 -0
  24. package/lib/API/ExtraMgmt/Docker.js +30 -0
  25. package/lib/API/Log.js +315 -0
  26. package/lib/API/LogManagement.js +371 -0
  27. package/lib/API/Modules/LOCAL.js +122 -0
  28. package/lib/API/Modules/Modularizer.js +148 -0
  29. package/lib/API/Modules/NPM.js +445 -0
  30. package/lib/API/Modules/TAR.js +362 -0
  31. package/lib/API/Modules/flagExt.js +46 -0
  32. package/lib/API/Modules/index.js +120 -0
  33. package/lib/API/Monit.js +247 -0
  34. package/lib/API/Serve.js +343 -0
  35. package/lib/API/Startup.js +629 -0
  36. package/lib/API/UX/helpers.js +213 -0
  37. package/lib/API/UX/index.js +9 -0
  38. package/lib/API/UX/pm2-describe.js +193 -0
  39. package/lib/API/UX/pm2-ls-minimal.js +31 -0
  40. package/lib/API/UX/pm2-ls.js +483 -0
  41. package/lib/API/Version.js +382 -0
  42. package/lib/API/interpreter.json +12 -0
  43. package/lib/API/pm2-plus/PM2IO.js +372 -0
  44. package/lib/API/pm2-plus/auth-strategies/CliAuth.js +288 -0
  45. package/lib/API/pm2-plus/auth-strategies/WebAuth.js +187 -0
  46. package/lib/API/pm2-plus/helpers.js +97 -0
  47. package/lib/API/pm2-plus/link.js +126 -0
  48. package/lib/API/pm2-plus/pres/motd +16 -0
  49. package/lib/API/pm2-plus/pres/motd.update +26 -0
  50. package/lib/API/pm2-plus/pres/welcome +28 -0
  51. package/lib/API/pm2-plus/process-selector.js +52 -0
  52. package/lib/API/schema.json +379 -0
  53. package/lib/API.js +1931 -0
  54. package/lib/Client.js +776 -0
  55. package/lib/Common.js +911 -0
  56. package/lib/Configuration.js +304 -0
  57. package/lib/Daemon.js +456 -0
  58. package/lib/Event.js +37 -0
  59. package/lib/God/ActionMethods.js +909 -0
  60. package/lib/God/ClusterMode.js +97 -0
  61. package/lib/God/ForkMode.js +297 -0
  62. package/lib/God/Methods.js +265 -0
  63. package/lib/God/Reload.js +240 -0
  64. package/lib/God.js +632 -0
  65. package/lib/HttpInterface.js +76 -0
  66. package/lib/ProcessContainer.js +305 -0
  67. package/lib/ProcessContainerBun.js +360 -0
  68. package/lib/ProcessContainerFork.js +42 -0
  69. package/lib/ProcessContainerForkBun.js +33 -0
  70. package/lib/ProcessUtils.js +55 -0
  71. package/lib/TreeKill.js +118 -0
  72. package/lib/Utility.js +430 -0
  73. package/lib/VersionCheck.js +46 -0
  74. package/lib/Watcher.js +117 -0
  75. package/lib/Worker.js +169 -0
  76. package/lib/binaries/CLI.js +1041 -0
  77. package/lib/binaries/DevCLI.js +183 -0
  78. package/lib/binaries/Runtime.js +101 -0
  79. package/lib/binaries/Runtime4Docker.js +192 -0
  80. package/lib/completion.js +229 -0
  81. package/lib/completion.sh +40 -0
  82. package/lib/motd +36 -0
  83. package/lib/templates/Dockerfiles/Dockerfile-java.tpl +7 -0
  84. package/lib/templates/Dockerfiles/Dockerfile-nodejs.tpl +8 -0
  85. package/lib/templates/Dockerfiles/Dockerfile-ruby.tpl +7 -0
  86. package/lib/templates/ecosystem-es.tpl +24 -0
  87. package/lib/templates/ecosystem-simple-es.tpl +8 -0
  88. package/lib/templates/ecosystem-simple.tpl +6 -0
  89. package/lib/templates/ecosystem.tpl +22 -0
  90. package/lib/templates/init-scripts/launchd.tpl +35 -0
  91. package/lib/templates/init-scripts/openrc.tpl +52 -0
  92. package/lib/templates/init-scripts/pm2-init-amazon.sh +86 -0
  93. package/lib/templates/init-scripts/rcd-openbsd.tpl +41 -0
  94. package/lib/templates/init-scripts/rcd.tpl +44 -0
  95. package/lib/templates/init-scripts/smf.tpl +43 -0
  96. package/lib/templates/init-scripts/systemd-online.tpl +22 -0
  97. package/lib/templates/init-scripts/systemd.tpl +22 -0
  98. package/lib/templates/init-scripts/upstart.tpl +103 -0
  99. package/lib/templates/logrotate.d/pm2 +10 -0
  100. package/lib/templates/sample-apps/http-server/README.md +14 -0
  101. package/lib/templates/sample-apps/http-server/api.js +9 -0
  102. package/lib/templates/sample-apps/http-server/ecosystem.config.js +14 -0
  103. package/lib/templates/sample-apps/http-server/package.json +11 -0
  104. package/lib/templates/sample-apps/pm2-plus-metrics-actions/README.md +45 -0
  105. package/lib/templates/sample-apps/pm2-plus-metrics-actions/custom-metrics.js +66 -0
  106. package/lib/templates/sample-apps/pm2-plus-metrics-actions/ecosystem.config.js +12 -0
  107. package/lib/templates/sample-apps/pm2-plus-metrics-actions/package.json +11 -0
  108. package/lib/templates/sample-apps/python-app/README.md +4 -0
  109. package/lib/templates/sample-apps/python-app/echo.py +7 -0
  110. package/lib/templates/sample-apps/python-app/ecosystem.config.js +12 -0
  111. package/lib/templates/sample-apps/python-app/package.json +11 -0
  112. package/lib/tools/Config.js +248 -0
  113. package/lib/tools/IsAbsolute.js +20 -0
  114. package/lib/tools/copydirSync.js +101 -0
  115. package/lib/tools/deleteFolderRecursive.js +19 -0
  116. package/lib/tools/find-package-json.js +74 -0
  117. package/lib/tools/fmt.js +72 -0
  118. package/lib/tools/isbinaryfile.js +94 -0
  119. package/lib/tools/json5.js +752 -0
  120. package/lib/tools/open.js +63 -0
  121. package/lib/tools/passwd.js +58 -0
  122. package/lib/tools/promise.min.js +1 -0
  123. package/lib/tools/sexec.js +55 -0
  124. package/lib/tools/treeify.js +113 -0
  125. package/lib/tools/which.js +120 -0
  126. package/lib/tools/xdg-open +861 -0
  127. package/package.json +219 -0
  128. package/paths.js +93 -0
  129. package/pm2 +11 -0
  130. package/preinstall.js +24 -0
  131. package/run.sh +9 -0
  132. package/types/index.d.ts +722 -0
  133. package/types/tsconfig.json +14 -0
package/lib/Client.js ADDED
@@ -0,0 +1,776 @@
1
+ /**
2
+ * Copyright 2013-2022 the ZM2 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
+
7
+ var debug = require('debug')('zm2:client');
8
+ var Common = require('./Common.js');
9
+ var KMDaemon = require('@pm2/agent/src/InteractorClient');
10
+ var rpc = require('pm2-axon-rpc');
11
+ var forEach = require('async/forEach');
12
+ var axon = require('pm2-axon');
13
+ var util = require('util');
14
+ var fs = require('fs');
15
+ var path = require('path');
16
+ var pkg = require('../package.json');
17
+ var which = require('./tools/which.js');
18
+
19
+ function noop() {}
20
+
21
+ var Client = module.exports = function(opts) {
22
+ if (!opts) opts = {};
23
+
24
+ if (!opts.conf)
25
+ this.conf = require('../constants.js');
26
+ else {
27
+ this.conf = opts.conf;
28
+ }
29
+
30
+ this.daemon_mode = typeof(opts.daemon_mode) === 'undefined' ? true : opts.daemon_mode;
31
+ this.pm2_home = this.conf.PM2_ROOT_PATH;
32
+ this.secret_key = opts.secret_key;
33
+ this.public_key = opts.public_key;
34
+ this.machine_name = opts.machine_name;
35
+
36
+ // Create all folders and files needed
37
+ // Client depends to that to interact with ZM2 properly
38
+ this.initFileStructure(this.conf);
39
+
40
+ debug('Using RPC file %s', this.conf.DAEMON_RPC_PORT);
41
+ debug('Using PUB file %s', this.conf.DAEMON_PUB_PORT);
42
+ this.rpc_socket_file = this.conf.DAEMON_RPC_PORT;
43
+ this.pub_socket_file = this.conf.DAEMON_PUB_PORT;
44
+ };
45
+
46
+ // @breaking change (noDaemonMode has been drop)
47
+ // @todo ret err
48
+ Client.prototype.start = function(cb) {
49
+ var that = this;
50
+
51
+ this.pingDaemon(function(daemonAlive) {
52
+ if (daemonAlive === true)
53
+ return that.launchRPC(function(err, meta) {
54
+ return cb(null, {
55
+ daemon_mode : that.conf.daemon_mode,
56
+ new_pm2_instance : false,
57
+ rpc_socket_file : that.rpc_socket_file,
58
+ pub_socket_file : that.pub_socket_file,
59
+ pm2_home : that.pm2_home
60
+ });
61
+ });
62
+
63
+ /**
64
+ * No Daemon mode
65
+ */
66
+ if (that.daemon_mode === false) {
67
+ var Daemon = require('./Daemon.js');
68
+
69
+ var daemon = new Daemon({
70
+ pub_socket_file : that.conf.DAEMON_PUB_PORT,
71
+ rpc_socket_file : that.conf.DAEMON_RPC_PORT,
72
+ pid_file : that.conf.PM2_PID_FILE_PATH,
73
+ ignore_signals : true
74
+ });
75
+
76
+ console.log('Launching in no daemon mode');
77
+
78
+ daemon.innerStart(function() {
79
+ KMDaemon.launchAndInteract(that.conf, {
80
+ machine_name : that.machine_name,
81
+ public_key : that.public_key,
82
+ secret_key : that.secret_key,
83
+ pm2_version : pkg.version
84
+ }, function(err, data, interactor_proc) {
85
+ that.interactor_process = interactor_proc;
86
+ });
87
+
88
+ that.launchRPC(function(err, meta) {
89
+ return cb(null, {
90
+ daemon_mode : that.conf.daemon_mode,
91
+ new_pm2_instance : true,
92
+ rpc_socket_file : that.rpc_socket_file,
93
+ pub_socket_file : that.pub_socket_file,
94
+ pm2_home : that.pm2_home
95
+ });
96
+ });
97
+ });
98
+ return false;
99
+ }
100
+
101
+ /**
102
+ * Daemon mode
103
+ */
104
+ that.launchDaemon(function(err, child) {
105
+ if (err) {
106
+ Common.printError(err);
107
+ return cb ? cb(err) : process.exit(that.conf.ERROR_EXIT);
108
+ }
109
+
110
+ if (!(process.env.ZM2_DISCRETE_MODE || process.env.PM2_DISCRETE_MODE))
111
+ Common.printOut(that.conf.PREFIX_MSG + 'ZM2 Successfully daemonized');
112
+
113
+ that.launchRPC(function(err, meta) {
114
+ return cb(null, {
115
+ daemon_mode : that.conf.daemon_mode,
116
+ new_pm2_instance : true,
117
+ rpc_socket_file : that.rpc_socket_file,
118
+ pub_socket_file : that.pub_socket_file,
119
+ pm2_home : that.pm2_home
120
+ });
121
+ });
122
+ });
123
+ });
124
+ };
125
+
126
+ // Init file structure of zm2_home
127
+ // This includes
128
+ // - zm2 pid and log path
129
+ // - rpc and pub socket for command execution
130
+ Client.prototype.initFileStructure = function (opts) {
131
+ if (!fs.existsSync(opts.DEFAULT_LOG_PATH)) {
132
+ try {
133
+ require('mkdirp').sync(opts.DEFAULT_LOG_PATH);
134
+ } catch (e) {
135
+ console.error(e.stack || e);
136
+ }
137
+ }
138
+
139
+ if (!fs.existsSync(opts.DEFAULT_PID_PATH)) {
140
+ try {
141
+ require('mkdirp').sync(opts.DEFAULT_PID_PATH);
142
+ } catch (e) {
143
+ console.error(e.stack || e);
144
+ }
145
+ }
146
+
147
+ if (!fs.existsSync(opts.PM2_MODULE_CONF_FILE)) {
148
+ try {
149
+ fs.writeFileSync(opts.PM2_MODULE_CONF_FILE, "{}");
150
+ } catch (e) {
151
+ console.error(e.stack || e);
152
+ }
153
+ }
154
+
155
+ if (!fs.existsSync(opts.DEFAULT_MODULE_PATH)) {
156
+ try {
157
+ require('mkdirp').sync(opts.DEFAULT_MODULE_PATH);
158
+ } catch (e) {
159
+ console.error(e.stack || e);
160
+ }
161
+ }
162
+
163
+ if (process.env.ZM2_DISCRETE_MODE || process.env.PM2_DISCRETE_MODE) {
164
+ try {
165
+ fs.writeFileSync(path.join(opts.PM2_HOME, 'touch'), Date.now().toString());
166
+ } catch(e) {
167
+ debug(e.stack || e);
168
+ }
169
+ }
170
+
171
+ if (!(process.env.ZM2_PROGRAMMATIC || process.env.PM2_PROGRAMMATIC) && !fs.existsSync(path.join(opts.PM2_HOME, 'touch'))) {
172
+
173
+ var vCheck = require('./VersionCheck.js')
174
+
175
+ vCheck({
176
+ state: 'install',
177
+ version: pkg.version
178
+ })
179
+
180
+ var dt = fs.readFileSync(path.join(__dirname, opts.PM2_BANNER));
181
+ console.log(dt.toString());
182
+ try {
183
+ fs.writeFileSync(path.join(opts.PM2_HOME, 'touch'), Date.now().toString());
184
+ } catch(e) {
185
+ debug(e.stack || e);
186
+ }
187
+ }
188
+ };
189
+
190
+ Client.prototype.close = function(cb) {
191
+ var that = this;
192
+
193
+ forEach([
194
+ that.disconnectRPC.bind(that),
195
+ that.disconnectBus.bind(that)
196
+ ], function(fn, next) {
197
+ fn(next)
198
+ }, cb);
199
+ };
200
+
201
+ /**
202
+ * Launch the Daemon by forking this same file
203
+ * The method Client.remoteWrapper will be called
204
+ *
205
+ * @method launchDaemon
206
+ * @param {Object} opts
207
+ * @param {Object} [opts.interactor=true] allow to disable interaction on launch
208
+ */
209
+ Client.prototype.launchDaemon = function(opts, cb) {
210
+ if (typeof(opts) == 'function') {
211
+ cb = opts;
212
+ opts = {
213
+ interactor : true
214
+ };
215
+ }
216
+
217
+ var that = this
218
+ var ClientJS = path.resolve(path.dirname(module.filename), 'Daemon.js');
219
+ var node_args = [];
220
+ var out, err;
221
+
222
+ // if (process.env.TRAVIS) {
223
+ // // Redirect ZM2 internal err and out to STDERR STDOUT when running with Travis
224
+ // out = 1;
225
+ // err = 2;
226
+ // }
227
+ // else {
228
+ out = fs.openSync(that.conf.PM2_LOG_FILE_PATH, 'a'),
229
+ err = fs.openSync(that.conf.PM2_LOG_FILE_PATH, 'a');
230
+ //}
231
+
232
+ if (this.conf.LOW_MEMORY_ENVIRONMENT) {
233
+ var os = require('os');
234
+ node_args.push('--gc-global'); // Does full GC (smaller memory footprint)
235
+ node_args.push('--max-old-space-size=' + Math.floor(os.totalmem() / 1024 / 1024));
236
+ }
237
+
238
+ // Node.js tuning for better performance
239
+ //node_args.push('--expose-gc'); // Allows manual GC in the code
240
+
241
+ /**
242
+ * Add node [arguments] depending on ZM2_NODE_OPTIONS env variable
243
+ */
244
+ if (process.env.ZM2_NODE_OPTIONS || process.env.PM2_NODE_OPTIONS)
245
+ node_args = node_args.concat((process.env.ZM2_NODE_OPTIONS || process.env.PM2_NODE_OPTIONS).split(' '));
246
+ node_args.push(ClientJS);
247
+
248
+ if (!(process.env.ZM2_DISCRETE_MODE || process.env.PM2_DISCRETE_MODE))
249
+ Common.printOut(that.conf.PREFIX_MSG + 'Spawning ZM2 daemon with zm2_home=' + this.pm2_home);
250
+
251
+ var interpreter = process.execPath;
252
+
253
+ var child = require('child_process').spawn(interpreter, node_args, {
254
+ detached : true,
255
+ cwd : that.conf.cwd || process.cwd(),
256
+ windowsHide: true,
257
+ env : Object.assign({
258
+ 'SILENT' : that.conf.DEBUG ? !that.conf.DEBUG : true,
259
+ 'PM2_HOME' : that.pm2_home
260
+ }, process.env),
261
+ stdio : [null, out, err, 'ipc']
262
+ });
263
+
264
+ function onError(e) {
265
+ console.error(e.message || e);
266
+ return cb ? cb(e.message || e) : false;
267
+ }
268
+
269
+ child.once('error', onError);
270
+
271
+ if (this.conf.IS_BUN === false)
272
+ child.unref();
273
+
274
+ child.once('message', function(msg) {
275
+ debug('ZM2 daemon launched with return message: ', msg);
276
+ child.removeListener('error', onError);
277
+ child.disconnect();
278
+ if (opts && opts.interactor == false)
279
+ return cb(null, child);
280
+
281
+ if (process.env.ZM2_NO_INTERACTION == 'true' || process.env.PM2_NO_INTERACTION == 'true')
282
+ return cb(null, child);
283
+
284
+ /**
285
+ * Here the Keymetrics agent is launched automaticcaly if
286
+ * it has been already configured before (via zm2 link)
287
+ */
288
+ KMDaemon.launchAndInteract(that.conf, {
289
+ machine_name : that.machine_name,
290
+ public_key : that.public_key,
291
+ secret_key : that.secret_key,
292
+ pm2_version : pkg.version
293
+ }, function(err, data, interactor_proc) {
294
+ that.interactor_process = interactor_proc;
295
+ return cb(null, child);
296
+ });
297
+ });
298
+ };
299
+
300
+ /**
301
+ * Ping the daemon to know if it alive or not
302
+ * @api public
303
+ * @method pingDaemon
304
+ * @param {} cb
305
+ * @return
306
+ */
307
+ Client.prototype.pingDaemon = function pingDaemon(cb) {
308
+ var req = axon.socket('req');
309
+ var client = new rpc.Client(req);
310
+ var that = this;
311
+
312
+ debug('[PING ZM2] Trying to connect to server');
313
+
314
+ client.sock.once('reconnect attempt', function() {
315
+ client.sock.close();
316
+ debug('Daemon not launched');
317
+ process.nextTick(function() {
318
+ return cb(false);
319
+ });
320
+ });
321
+
322
+ client.sock.once('error', function(e) {
323
+ if (e.code === 'EACCES') {
324
+ fs.stat(that.conf.DAEMON_RPC_PORT, function(e, stats) {
325
+ if (stats.uid === 0) {
326
+ console.error(that.conf.PREFIX_MSG_ERR + 'Permission denied, to give access to current user:');
327
+ console.log('$ sudo chown ' + process.env.USER + ':' + process.env.USER + ' ' + that.conf.DAEMON_RPC_PORT + ' ' + that.conf.DAEMON_PUB_PORT);
328
+ }
329
+ else
330
+ console.error(that.conf.PREFIX_MSG_ERR + 'Permission denied, check permissions on ' + that.conf.DAEMON_RPC_PORT);
331
+
332
+ process.exit(1);
333
+ });
334
+ }
335
+ else
336
+ console.error(e.message || e);
337
+ });
338
+
339
+ client.sock.once('connect', function() {
340
+ client.sock.once('close', function() {
341
+ return cb(true);
342
+ });
343
+ client.sock.close();
344
+ debug('Daemon alive');
345
+ });
346
+
347
+ req.connect(this.rpc_socket_file);
348
+ };
349
+
350
+ /**
351
+ * Methods to interact with the Daemon via RPC
352
+ * This method wait to be connected to the Daemon
353
+ * Once he's connected it trigger the command parsing (on ./bin/zm2 file, at the end)
354
+ * @method launchRPC
355
+ * @params {function} [cb]
356
+ * @return
357
+ */
358
+ Client.prototype.launchRPC = function launchRPC(cb) {
359
+ var self = this;
360
+ debug('Launching RPC client on socket file %s', this.rpc_socket_file);
361
+ var req = axon.socket('req');
362
+ this.client = new rpc.Client(req);
363
+
364
+ var connectHandler = function() {
365
+ self.client.sock.removeListener('error', errorHandler);
366
+ debug('RPC Connected to Daemon');
367
+ if (cb) {
368
+ setTimeout(function() {
369
+ cb(null);
370
+ }, 4);
371
+ }
372
+ };
373
+
374
+ var errorHandler = function(e) {
375
+ self.client.sock.removeListener('connect', connectHandler);
376
+ if (cb) {
377
+ return cb(e);
378
+ }
379
+ };
380
+
381
+ this.client.sock.once('connect', connectHandler);
382
+ this.client.sock.once('error', errorHandler);
383
+ this.client_sock = req.connect(this.rpc_socket_file);
384
+ };
385
+
386
+ /**
387
+ * Methods to close the RPC connection
388
+ * @callback cb
389
+ */
390
+ Client.prototype.disconnectRPC = function disconnectRPC(cb) {
391
+ var that = this;
392
+ if (!cb) cb = noop;
393
+
394
+ if (!this.client_sock || !this.client_sock.close) {
395
+ this.client = null;
396
+ return process.nextTick(function() {
397
+ cb(new Error('SUB connection to ZM2 is not launched'));
398
+ });
399
+ }
400
+
401
+ if (this.client_sock.connected === false ||
402
+ this.client_sock.closing === true) {
403
+ this.client = null;
404
+ return process.nextTick(function() {
405
+ cb(new Error('RPC already being closed'));
406
+ });
407
+ }
408
+
409
+ try {
410
+ var timer;
411
+
412
+ that.client_sock.once('close', function() {
413
+ clearTimeout(timer);
414
+ that.client = null;
415
+ debug('ZM2 RPC cleanly closed');
416
+ return cb(null, { msg : 'RPC Successfully closed' });
417
+ });
418
+
419
+ timer = setTimeout(function() {
420
+ if (that.client_sock.destroy)
421
+ that.client_sock.destroy();
422
+ that.client = null;
423
+ return cb(null, { msg : 'RPC Successfully closed via timeout' });
424
+ }, 200);
425
+
426
+ that.client_sock.close();
427
+ } catch(e) {
428
+ debug('Error while disconnecting RPC ZM2', e.stack || e);
429
+ return cb(e);
430
+ }
431
+ return false;
432
+ };
433
+
434
+ Client.prototype.launchBus = function launchEventSystem(cb) {
435
+ var self = this;
436
+ this.sub = axon.socket('sub-emitter');
437
+ this.sub_sock = this.sub.connect(this.pub_socket_file);
438
+
439
+ this.sub_sock.once('connect', function() {
440
+ return cb(null, self.sub, self.sub_sock);
441
+ });
442
+ };
443
+
444
+ Client.prototype.disconnectBus = function disconnectBus(cb) {
445
+ if (!cb) cb = noop;
446
+
447
+ var that = this;
448
+
449
+ if (!this.sub_sock || !this.sub_sock.close) {
450
+ that.sub = null;
451
+ return process.nextTick(function() {
452
+ cb(null, { msg : 'bus was not connected'});
453
+ });
454
+ }
455
+
456
+ if (this.sub_sock.connected === false ||
457
+ this.sub_sock.closing === true) {
458
+ that.sub = null;
459
+ return process.nextTick(function() {
460
+ cb(new Error('SUB connection is already being closed'));
461
+ });
462
+ }
463
+
464
+ try {
465
+ var timer;
466
+
467
+ that.sub_sock.once('close', function() {
468
+ that.sub = null;
469
+ clearTimeout(timer);
470
+ debug('ZM2 PUB cleanly closed');
471
+ return cb();
472
+ });
473
+
474
+ timer = setTimeout(function() {
475
+ if (Client.sub_sock.destroy)
476
+ that.sub_sock.destroy();
477
+ return cb();
478
+ }, 200);
479
+
480
+ this.sub_sock.close();
481
+ } catch(e) {
482
+ return cb(e);
483
+ }
484
+ };
485
+
486
+ /**
487
+ * Description
488
+ * @method gestExposedMethods
489
+ * @param {} cb
490
+ * @return
491
+ */
492
+ Client.prototype.getExposedMethods = function getExposedMethods(cb) {
493
+ this.client.methods(cb);
494
+ };
495
+
496
+ /**
497
+ * Description
498
+ * @method executeRemote
499
+ * @param {} method
500
+ * @param {} env
501
+ * @param {} fn
502
+ * @return
503
+ */
504
+ Client.prototype.executeRemote = function executeRemote(method, app_conf, fn) {
505
+ var self = this;
506
+
507
+ // stop watch on stop | env is the process id
508
+ if (method.indexOf('stop') !== -1) {
509
+ this.stopWatch(method, app_conf);
510
+ }
511
+ // stop watching when process is deleted
512
+ else if (method.indexOf('delete') !== -1) {
513
+ this.stopWatch(method, app_conf);
514
+ }
515
+ // stop everything on kill
516
+ else if (method.indexOf('kill') !== -1) {
517
+ this.stopWatch('deleteAll', app_conf);
518
+ }
519
+ else if (method.indexOf('restartProcessId') !== -1 && process.argv.indexOf('--watch') > -1) {
520
+ delete app_conf.env.current_conf.watch;
521
+ this.toggleWatch(method, app_conf);
522
+ }
523
+
524
+ if (!this.client || !this.client.call) {
525
+ this.start(function(error) {
526
+ if (error) {
527
+ if (fn)
528
+ return fn(error);
529
+ console.error(error);
530
+ return process.exit(0);
531
+ }
532
+ if (self.client) {
533
+ return self.client.call(method, app_conf, fn);
534
+ }
535
+ });
536
+ return false;
537
+ }
538
+
539
+ debug('Calling daemon method zm2:%s on rpc socket:%s', method, this.rpc_socket_file);
540
+ return this.client.call(method, app_conf, fn);
541
+ };
542
+
543
+ Client.prototype.notifyGod = function(action_name, id, cb) {
544
+ this.executeRemote('notifyByProcessId', {
545
+ id : id,
546
+ action_name : action_name,
547
+ manually : true
548
+ }, function() {
549
+ debug('God notified');
550
+ return cb ? cb() : false;
551
+ });
552
+ };
553
+
554
+ Client.prototype.killDaemon = function killDaemon(fn) {
555
+ var timeout;
556
+ var that = this;
557
+
558
+ function quit() {
559
+ that.close(function() {
560
+ return fn ? fn(null, {success:true}) : false;
561
+ });
562
+ }
563
+
564
+ // under unix, we listen for signal (that is send by daemon to notify us that its shuting down)
565
+ if (process.platform !== 'win32' && process.platform !== 'win64') {
566
+ process.once('SIGQUIT', function() {
567
+ debug('Received SIGQUIT from zm2 daemon');
568
+ clearTimeout(timeout);
569
+ quit();
570
+ });
571
+ }
572
+ else {
573
+ // if under windows, try to ping the daemon to see if it still here
574
+ setTimeout(function() {
575
+ that.pingDaemon(function(alive) {
576
+ if (!alive) {
577
+ clearTimeout(timeout);
578
+ return quit();
579
+ }
580
+ });
581
+ }, 250)
582
+ }
583
+
584
+ timeout = setTimeout(function() {
585
+ quit();
586
+ }, 3000);
587
+
588
+ // Kill daemon
589
+ this.executeRemote('killMe', {pid : process.pid});
590
+ };
591
+
592
+
593
+ /**
594
+ * Description
595
+ * @method toggleWatch
596
+ * @param {String} zm2 method name
597
+ * @param {Object} application environment, should include id
598
+ * @param {Function} callback
599
+ */
600
+ Client.prototype.toggleWatch = function toggleWatch(method, env, fn) {
601
+ debug('Calling toggleWatch');
602
+ this.client.call('toggleWatch', method, env, function() {
603
+ return fn ? fn() : false;
604
+ });
605
+ };
606
+
607
+ /**
608
+ * Description
609
+ * @method startWatch
610
+ * @param {String} zm2 method name
611
+ * @param {Object} application environment, should include id
612
+ * @param {Function} callback
613
+ */
614
+ Client.prototype.startWatch = function restartWatch(method, env, fn) {
615
+ debug('Calling startWatch');
616
+ this.client.call('startWatch', method, env, function() {
617
+ return fn ? fn() : false;
618
+ });
619
+ };
620
+
621
+ /**
622
+ * Description
623
+ * @method stopWatch
624
+ * @param {String} zm2 method name
625
+ * @param {Object} application environment, should include id
626
+ * @param {Function} callback
627
+ */
628
+ Client.prototype.stopWatch = function stopWatch(method, env, fn) {
629
+ debug('Calling stopWatch');
630
+ this.client.call('stopWatch', method, env, function() {
631
+ return fn ? fn() : false;
632
+ });
633
+ };
634
+
635
+ Client.prototype.getAllProcess = function(cb) {
636
+ var found_proc = [];
637
+
638
+ this.executeRemote('getMonitorData', {}, function(err, procs) {
639
+ if (err) {
640
+ Common.printError('Error retrieving process list: ' + err);
641
+ return cb(err);
642
+ }
643
+
644
+ return cb(null, procs);
645
+ });
646
+ };
647
+
648
+ Client.prototype.getAllProcessId = function(cb) {
649
+ var found_proc = [];
650
+
651
+ this.executeRemote('getMonitorData', {}, function(err, procs) {
652
+ if (err) {
653
+ Common.printError('Error retrieving process list: ' + err);
654
+ return cb(err);
655
+ }
656
+
657
+ return cb(null, procs.map(proc => proc.pm_id));
658
+ });
659
+ };
660
+
661
+ Client.prototype.getAllProcessIdWithoutModules = function(cb) {
662
+ var found_proc = [];
663
+
664
+ this.executeRemote('getMonitorData', {}, function(err, procs) {
665
+ if (err) {
666
+ Common.printError('Error retrieving process list: ' + err);
667
+ return cb(err);
668
+ }
669
+
670
+ var proc_ids = procs
671
+ .filter(proc => !proc.pm2_env.pmx_module)
672
+ .map(proc => proc.pm_id)
673
+
674
+ return cb(null, proc_ids);
675
+ });
676
+ };
677
+
678
+ Client.prototype.getProcessIdByName = function(name, force_all, cb) {
679
+ var found_proc = [];
680
+ var full_details = {};
681
+
682
+ if (typeof(cb) === 'undefined') {
683
+ cb = force_all;
684
+ force_all = false;
685
+ }
686
+
687
+ if (typeof(name) == 'number')
688
+ name = name.toString();
689
+
690
+ this.executeRemote('getMonitorData', {}, function(err, list) {
691
+ if (err) {
692
+ Common.printError('Error retrieving process list: ' + err);
693
+ return cb(err);
694
+ }
695
+
696
+ list.forEach(function(proc) {
697
+ if (proc.pm2_env.name == name || proc.pm2_env.pm_exec_path == path.resolve(name)) {
698
+ found_proc.push(proc.pm_id);
699
+ full_details[proc.pm_id] = proc;
700
+ }
701
+ });
702
+
703
+ return cb(null, found_proc, full_details);
704
+ });
705
+ };
706
+
707
+ Client.prototype.getProcessIdsByNamespace = function(namespace, force_all, cb) {
708
+ var found_proc = [];
709
+ var full_details = {};
710
+
711
+ if (typeof(cb) === 'undefined') {
712
+ cb = force_all;
713
+ force_all = false;
714
+ }
715
+
716
+ if (typeof(namespace) == 'number')
717
+ namespace = namespace.toString();
718
+
719
+ this.executeRemote('getMonitorData', {}, function(err, list) {
720
+ if (err) {
721
+ Common.printError('Error retrieving process list: ' + err);
722
+ return cb(err);
723
+ }
724
+
725
+ list.forEach(function(proc) {
726
+ if (proc.pm2_env.namespace == namespace) {
727
+ found_proc.push(proc.pm_id);
728
+ full_details[proc.pm_id] = proc;
729
+ }
730
+ });
731
+
732
+ return cb(null, found_proc, full_details);
733
+ });
734
+ };
735
+
736
+ Client.prototype.getProcessByName = function(name, cb) {
737
+ var found_proc = [];
738
+
739
+ this.executeRemote('getMonitorData', {}, function(err, list) {
740
+ if (err) {
741
+ Common.printError('Error retrieving process list: ' + err);
742
+ return cb(err);
743
+ }
744
+
745
+ list.forEach(function(proc) {
746
+ if (proc.pm2_env.name == name ||
747
+ proc.pm2_env.pm_exec_path == path.resolve(name)) {
748
+ found_proc.push(proc);
749
+ }
750
+ });
751
+
752
+ return cb(null, found_proc);
753
+ });
754
+ };
755
+
756
+ Client.prototype.getProcessByNameOrId = function (nameOrId, cb) {
757
+ var foundProc = [];
758
+
759
+ this.executeRemote('getMonitorData', {}, function (err, list) {
760
+ if (err) {
761
+ Common.printError('Error retrieving process list: ' + err);
762
+ return cb(err);
763
+ }
764
+
765
+ list.forEach(function (proc) {
766
+ if (proc.pm2_env.name === nameOrId ||
767
+ proc.pm2_env.pm_exec_path === path.resolve(nameOrId) ||
768
+ proc.pid === parseInt(nameOrId) ||
769
+ proc.pm2_env.pm_id === parseInt(nameOrId)) {
770
+ foundProc.push(proc);
771
+ }
772
+ });
773
+
774
+ return cb(null, foundProc);
775
+ });
776
+ };