badmfck-api-server 4.1.53 → 4.1.58

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 (39) hide show
  1. package/dist/apiServer/APIService.d.ts +3 -4
  2. package/dist/apiServer/APIService.js +19 -9
  3. package/dist/apiServer/BaseEndpoint.d.ts +2 -2
  4. package/dist/apiServer/LocalRequest.d.ts +1 -1
  5. package/dist/apiServer/LogService.js +17 -7
  6. package/dist/apiServer/MonitorService.d.ts +0 -1
  7. package/dist/apiServer/MonitorService.js +17 -7
  8. package/dist/apiServer/MysqlService.d.ts +1 -2
  9. package/dist/apiServer/MysqlService.js +17 -7
  10. package/dist/apiServer/TimeframeService.js +17 -7
  11. package/dist/apiServer/db/MysqlAdapter.d.ts +1 -1
  12. package/dist/apiServer/db/MysqlAdapter.js +37 -12
  13. package/dist/apiServer/deployment/Activate.js +1 -2
  14. package/dist/apiServer/deployment/ConfigService.d.ts +26 -26
  15. package/dist/apiServer/deployment/ConfigService.js +17 -7
  16. package/dist/apiServer/deployment/Deploy.js +1 -2
  17. package/dist/apiServer/deployment/DeployerService.d.ts +10 -9
  18. package/dist/apiServer/deployment/DeployerService.js +18 -1
  19. package/dist/apiServer/deployment/cli.js +37 -14
  20. package/dist/apiServer/deployment/resolveConfig.js +2 -3
  21. package/dist/apiServer/documentation/index.html +25 -25
  22. package/dist/apiServer/external/ExternalService.js +17 -7
  23. package/dist/apiServer/external/MicroserviceClient.js +17 -7
  24. package/dist/apiServer/external/MicroserviceHost.js +17 -7
  25. package/dist/apiServer/external/MicroserviceHostController.js +17 -7
  26. package/dist/apiServer/helper/JSONStableStringify.js +1 -2
  27. package/dist/apiServer/helper/YYYYMMDDHH.js +2 -3
  28. package/dist/apiServer/helper/ZipUtils.d.ts +0 -2
  29. package/dist/apiServer/monitor/Monitor.d.ts +9 -1
  30. package/dist/apiServer/monitor/Monitor.js +28 -2
  31. package/dist/apiServer/monitor/ProcessMonitor.d.ts +61 -1
  32. package/dist/apiServer/monitor/ProcessMonitor.js +160 -0
  33. package/dist/apiServer/monitor/SystemInfo.d.ts +7 -8
  34. package/dist/apiServer/monitor/SystemInfo.js +1 -2
  35. package/dist/apiServer/monitor/index.html +53 -53
  36. package/dist/apiServer/structures/Interfaces.d.ts +0 -1
  37. package/dist/index.d.ts +3 -2
  38. package/dist/index.js +4 -1
  39. package/package.json +1 -1
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
25
35
  Object.defineProperty(exports, "__esModule", { value: true });
26
36
  exports.MicroserviceHostController = void 0;
27
37
  const BaseEndpoint_1 = require("../BaseEndpoint");
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.JSONStableStringify = void 0;
3
+ exports.JSONStableStringify = JSONStableStringify;
4
4
  function JSONStableStringify(obj) {
5
5
  if (obj === null || typeof obj !== "object") {
6
6
  return JSON.stringify(obj);
@@ -13,4 +13,3 @@ function JSONStableStringify(obj) {
13
13
  keys.map(k => JSON.stringify(k) + ":" + JSONStableStringify(obj[k])).join(",") +
14
14
  "}");
15
15
  }
16
- exports.JSONStableStringify = JSONStableStringify;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.YYYYMMDDHH_toDate = exports.YYYYMMDDHH = void 0;
3
+ exports.YYYYMMDDHH = YYYYMMDDHH;
4
+ exports.YYYYMMDDHH_toDate = YYYYMMDDHH_toDate;
4
5
  function YYYYMMDDHH(date, format = "yyyymmddhh") {
5
6
  const year = date.getFullYear();
6
7
  const month = String(date.getMonth() + 1).padStart(2, "0");
@@ -20,7 +21,6 @@ function YYYYMMDDHH(date, format = "yyyymmddhh") {
20
21
  return `${year}${month}${day}${hours}`;
21
22
  }
22
23
  }
23
- exports.YYYYMMDDHH = YYYYMMDDHH;
24
24
  function YYYYMMDDHH_toDate(yyyymmddhh) {
25
25
  const str = String(yyyymmddhh);
26
26
  const year = parseInt(str.slice(0, 4), 10);
@@ -29,4 +29,3 @@ function YYYYMMDDHH_toDate(yyyymmddhh) {
29
29
  const hours = parseInt(str.slice(8, 10), 10);
30
30
  return new Date(year, month, day, hours);
31
31
  }
32
- exports.YYYYMMDDHH_toDate = YYYYMMDDHH_toDate;
@@ -1,5 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
1
  export declare class ZipUtils {
4
2
  static zipBufferToBase64: (input: Buffer) => string;
5
3
  static unzipBase64ToBuffer: (base64: string) => Buffer;
@@ -6,6 +6,12 @@ export interface IUserAction {
6
6
  action: string;
7
7
  }
8
8
  export declare const S_MONITOR_REGISTRATE_ACTION: Signal<IUserAction>;
9
+ export interface IRestartRequest {
10
+ by: string;
11
+ name: string | null;
12
+ pmId: string | null;
13
+ }
14
+ export declare const S_MONITOR_RESTART_REQUESTED: Signal<IRestartRequest>;
9
15
  export declare class Monitor extends BaseEndpoint {
10
16
  ignoreHttpLogging: boolean;
11
17
  ignoreInDocumentation: boolean;
@@ -23,10 +29,12 @@ export declare class Monitor extends BaseEndpoint {
23
29
  outgoingNetlog(req: HTTPRequestVO): Promise<TransferPacketVO>;
24
30
  sysinfo(req: HTTPRequestVO): Promise<TransferPacketVO>;
25
31
  procinfo(req: HTTPRequestVO): Promise<TransferPacketVO>;
32
+ fdreport(req: HTTPRequestVO): Promise<TransferPacketVO>;
33
+ restart(req: HTTPRequestVO): Promise<TransferPacketVO>;
26
34
  httpstats(req: HTTPRequestVO): Promise<TransferPacketVO>;
27
35
  inventory(req: HTTPRequestVO): Promise<TransferPacketVO>;
28
36
  metrics(req: HTTPRequestVO): Promise<TransferPacketVO>;
29
37
  connections(req: HTTPRequestVO): Promise<TransferPacketVO>;
30
38
  db(req: HTTPRequestVO): Promise<TransferPacketVO>;
31
- checkAuthentication(req: HTTPRequestVO): Promise<void>;
39
+ checkAuthentication(req: HTTPRequestVO): Promise<string>;
32
40
  }
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Monitor = exports.S_MONITOR_REGISTRATE_ACTION = void 0;
6
+ exports.Monitor = exports.S_MONITOR_RESTART_REQUESTED = exports.S_MONITOR_REGISTRATE_ACTION = void 0;
7
7
  const badmfck_signal_1 = require("badmfck-signal");
8
8
  const APIService_1 = require("../APIService");
9
9
  const BaseEndpoint_1 = require("../BaseEndpoint");
@@ -19,6 +19,7 @@ const DBService_1 = require("../DBService");
19
19
  const SystemInfo_1 = require("./SystemInfo");
20
20
  const ProcessMonitor_1 = require("./ProcessMonitor");
21
21
  exports.S_MONITOR_REGISTRATE_ACTION = new badmfck_signal_1.Signal();
22
+ exports.S_MONITOR_RESTART_REQUESTED = new badmfck_signal_1.Signal();
22
23
  const logMap = {
23
24
  ALL: 10,
24
25
  API: 19,
@@ -45,6 +46,10 @@ class Monitor extends BaseEndpoint_1.BaseEndpoint {
45
46
  { ignoreInterceptor: true, endpoint: "outgoingnetlog", handler: this.outgoingNetlog },
46
47
  { ignoreInterceptor: true, endpoint: "sysinfo", handler: this.sysinfo },
47
48
  { ignoreInterceptor: true, endpoint: "procinfo", handler: this.procinfo },
49
+ { ignoreInterceptor: true, endpoint: "fdreport", handler: this.fdreport },
50
+ { ignoreInterceptor: true, endpoint: "restart", handler: this.restart, validationModel: {
51
+ confirm: ""
52
+ } },
48
53
  { ignoreInterceptor: true, endpoint: "inventory", handler: this.inventory },
49
54
  { ignoreInterceptor: true, endpoint: "httpstats", handler: this.httpstats },
50
55
  { ignoreInterceptor: true, endpoint: "metrics", handler: this.metrics, validationModel: {
@@ -140,6 +145,27 @@ class Monitor extends BaseEndpoint_1.BaseEndpoint {
140
145
  await this.checkAuthentication(req);
141
146
  return { data: await ProcessMonitor_1.ProcessMonitor.getSnapshot() };
142
147
  }
148
+ async fdreport(req) {
149
+ await this.checkAuthentication(req);
150
+ return { data: await ProcessMonitor_1.ProcessMonitor.getFdReport() };
151
+ }
152
+ async restart(req) {
153
+ const login = await this.checkAuthentication(req);
154
+ const id = ProcessMonitor_1.ProcessMonitor.getPm2Identity();
155
+ if (!id.managed)
156
+ throw { ...DefaultErrors_1.default.BAD_REQUEST, details: "Process is not managed by pm2 (no pm_id in env) — refusing to exit, nothing would restart it." };
157
+ if (req.data.confirm !== id.name)
158
+ throw { ...DefaultErrors_1.default.BAD_REQUEST, details: `Confirmation mismatch. To restart send { "confirm": "${id.name}" }.` };
159
+ exports.S_MONITOR_RESTART_REQUESTED.invoke({ by: login, name: id.name, pmId: id.pmId });
160
+ exports.S_MONITOR_REGISTRATE_ACTION.invoke({ action: `restart requested by "${login}" for pm2 "${id.name}" (id ${id.pmId})` });
161
+ (0, LogService_1.logInfo)(`Restart requested via monitor by "${login}" for pm2 process "${id.name}" (id ${id.pmId})`, "Monitor");
162
+ const graceMs = 750;
163
+ setTimeout(() => {
164
+ (0, LogService_1.logInfo)(`Exiting now for pm2 restart (requested by "${login}")`, "Monitor");
165
+ process.exit(0);
166
+ }, graceMs);
167
+ return { data: { restarting: true, name: id.name, pmId: id.pmId, by: login, graceMs } };
168
+ }
143
169
  async httpstats(req) {
144
170
  await this.checkAuthentication(req);
145
171
  return { data: Http_1.Http.getHttpStats() };
@@ -196,7 +222,7 @@ class Monitor extends BaseEndpoint_1.BaseEndpoint {
196
222
  for (let i of users) {
197
223
  const hash = crypto_1.default.createHash("sha256").update(i.login + ":" + i.password).digest("hex");
198
224
  if (hash === header) {
199
- return;
225
+ return i.login;
200
226
  }
201
227
  }
202
228
  throw { ...DefaultErrors_1.default.UNAUTHORIZED, details: "Invalid user" };
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  export declare class ProcessMonitor {
3
2
  private static _inited;
4
3
  private static _eld;
@@ -10,7 +9,11 @@ export declare class ProcessMonitor {
10
9
  private static _eluPrev;
11
10
  private static _elu;
12
11
  private static _processStartedAt;
12
+ private static _fdHistory;
13
+ private static _fdHistoryMax;
14
+ private static _fdSampleEveryMs;
13
15
  static init(): void;
16
+ private static _sampleFdSeries;
14
17
  private static _sampleCpu;
15
18
  private static _sampleELU;
16
19
  private static _mapGcKind;
@@ -34,6 +37,14 @@ export declare class ProcessMonitor {
34
37
  startedAtUnix: number;
35
38
  uptimeSec: number;
36
39
  availableParallelism: number;
40
+ pm2: {
41
+ managed: boolean;
42
+ name: string | null;
43
+ pmId: string | null;
44
+ instanceId: string | null;
45
+ execPath: string | null;
46
+ cwd: string | null;
47
+ };
37
48
  };
38
49
  memory: {
39
50
  rss: number;
@@ -99,6 +110,14 @@ export declare class ProcessMonitor {
99
110
  limitSoft: number | null;
100
111
  limitHard: number | null;
101
112
  };
113
+ sockets: {
114
+ total: number;
115
+ byState: Record<string, number>;
116
+ topRemotes: Array<{
117
+ host: string;
118
+ established: number;
119
+ }>;
120
+ } | null;
102
121
  io: Record<string, number> | null;
103
122
  limits: Record<string, {
104
123
  soft: string;
@@ -106,10 +125,51 @@ export declare class ProcessMonitor {
106
125
  unit: string;
107
126
  }> | null;
108
127
  }>;
128
+ static getPm2Identity(): {
129
+ managed: boolean;
130
+ name: string | null;
131
+ pmId: string | null;
132
+ instanceId: string | null;
133
+ execPath: string | null;
134
+ cwd: string | null;
135
+ };
136
+ static getFdReport(): Promise<{
137
+ now: {
138
+ ts: number;
139
+ fdOpen: number | null;
140
+ limitSoft: number | null;
141
+ limitHard: number | null;
142
+ sockets: {
143
+ total: number;
144
+ byState: Record<string, number>;
145
+ topRemotes: Array<{
146
+ host: string;
147
+ established: number;
148
+ }>;
149
+ } | null;
150
+ };
151
+ sampleEveryMs: number;
152
+ historyMax: number;
153
+ history: {
154
+ ts: number;
155
+ fdOpen: number | null;
156
+ fdSoftLimit: number | null;
157
+ socketTotal: number | null;
158
+ byState: Record<string, number>;
159
+ topRemote: {
160
+ host: string;
161
+ established: number;
162
+ } | null;
163
+ rss: number;
164
+ }[];
165
+ }>;
109
166
  private static _readProcStatus;
110
167
  private static _readProcIo;
111
168
  private static _readProcLimits;
112
169
  private static _countFds;
170
+ private static _readSocketBreakdown;
171
+ private static _tcpState;
172
+ private static _parseHexAddr;
113
173
  private static _parseLimitValue;
114
174
  private static _toMsFinite;
115
175
  private static _safePercentileMs;
@@ -25,6 +25,9 @@ class ProcessMonitor {
25
25
  static _eluPrev = perf_hooks_1.performance.eventLoopUtilization();
26
26
  static _elu = { idle: 0, active: 0, utilizationPct: 0 };
27
27
  static _processStartedAt = Date.now() - process.uptime() * 1000;
28
+ static _fdHistory = [];
29
+ static _fdHistoryMax = 300;
30
+ static _fdSampleEveryMs = Math.max(1, parseInt(process.env.MONITOR_FD_SAMPLE_MINUTES || "10", 10) || 10) * 60 * 1000;
28
31
  static init() {
29
32
  if (this._inited)
30
33
  return;
@@ -62,6 +65,28 @@ class ProcessMonitor {
62
65
  const eluTimer = setInterval(() => this._sampleELU(), 5000);
63
66
  if (eluTimer.unref)
64
67
  eluTimer.unref();
68
+ this._sampleFdSeries().catch(() => { });
69
+ const fdTimer = setInterval(() => this._sampleFdSeries().catch(() => { }), this._fdSampleEveryMs);
70
+ if (fdTimer.unref)
71
+ fdTimer.unref();
72
+ }
73
+ static async _sampleFdSeries() {
74
+ const fdOpen = await this._countFds();
75
+ const sockets = await this._readSocketBreakdown();
76
+ const limits = await this._readProcLimits();
77
+ const softRaw = limits?.["Max open files"]?.soft;
78
+ const mem = process.memoryUsage();
79
+ this._fdHistory.push({
80
+ ts: Date.now(),
81
+ fdOpen,
82
+ fdSoftLimit: softRaw ? this._parseLimitValue(softRaw) : null,
83
+ socketTotal: sockets ? sockets.total : null,
84
+ byState: sockets ? sockets.byState : {},
85
+ topRemote: sockets && sockets.topRemotes.length > 0 ? sockets.topRemotes[0] : null,
86
+ rss: mem.rss,
87
+ });
88
+ if (this._fdHistory.length > this._fdHistoryMax)
89
+ this._fdHistory.shift();
65
90
  }
66
91
  static _sampleCpu() {
67
92
  const now = process.cpuUsage();
@@ -137,6 +162,7 @@ class ProcessMonitor {
137
162
  const fdOpen = await this._countFds();
138
163
  const fdSoft = limitsParsed?.["Max open files"]?.soft;
139
164
  const fdHard = limitsParsed?.["Max open files"]?.hard;
165
+ const sockets = await this._readSocketBreakdown();
140
166
  const h = this._eld;
141
167
  const eventLoop = h ? {
142
168
  minMs: this._toMsFinite(h.min),
@@ -172,6 +198,7 @@ class ProcessMonitor {
172
198
  availableParallelism: typeof os_1.default.availableParallelism === "function"
173
199
  ? os_1.default.availableParallelism()
174
200
  : os_1.default.cpus().length,
201
+ pm2: this.getPm2Identity(),
175
202
  },
176
203
  memory: {
177
204
  rss: mem.rss,
@@ -212,10 +239,44 @@ class ProcessMonitor {
212
239
  limitSoft: fdSoft ? this._parseLimitValue(fdSoft) : null,
213
240
  limitHard: fdHard ? this._parseLimitValue(fdHard) : null,
214
241
  },
242
+ sockets,
215
243
  io,
216
244
  limits: limitsParsed,
217
245
  };
218
246
  }
247
+ static getPm2Identity() {
248
+ const env = process.env;
249
+ const pmId = env.pm_id ?? null;
250
+ return {
251
+ managed: pmId !== null && pmId !== "",
252
+ name: env.name ?? null,
253
+ pmId,
254
+ instanceId: env.NODE_APP_INSTANCE ?? null,
255
+ execPath: env.pm_exec_path ?? null,
256
+ cwd: env.pm_cwd ?? null,
257
+ };
258
+ }
259
+ static async getFdReport() {
260
+ const [sockets, limits, fdOpen] = await Promise.all([
261
+ this._readSocketBreakdown(),
262
+ this._readProcLimits(),
263
+ this._countFds(),
264
+ ]);
265
+ const softRaw = limits?.["Max open files"]?.soft;
266
+ const hardRaw = limits?.["Max open files"]?.hard;
267
+ return {
268
+ now: {
269
+ ts: Date.now(),
270
+ fdOpen,
271
+ limitSoft: softRaw ? this._parseLimitValue(softRaw) : null,
272
+ limitHard: hardRaw ? this._parseLimitValue(hardRaw) : null,
273
+ sockets,
274
+ },
275
+ sampleEveryMs: this._fdSampleEveryMs,
276
+ historyMax: this._fdHistoryMax,
277
+ history: this._fdHistory,
278
+ };
279
+ }
219
280
  static async _readProcStatus() {
220
281
  try {
221
282
  const txt = await promises_1.default.readFile(`/proc/${process.pid}/status`, "utf-8");
@@ -278,6 +339,105 @@ class ProcessMonitor {
278
339
  return null;
279
340
  }
280
341
  }
342
+ static async _readSocketBreakdown() {
343
+ try {
344
+ const fdDir = `/proc/${process.pid}/fd`;
345
+ const fds = await promises_1.default.readdir(fdDir);
346
+ const inodes = new Set();
347
+ await Promise.all(fds.map(async (fd) => {
348
+ try {
349
+ const link = await promises_1.default.readlink(`${fdDir}/${fd}`);
350
+ const m = link.match(/^socket:\[(\d+)\]$/);
351
+ if (m)
352
+ inodes.add(m[1]);
353
+ }
354
+ catch { }
355
+ }));
356
+ if (inodes.size === 0)
357
+ return { total: 0, byState: {}, topRemotes: [] };
358
+ const byState = {};
359
+ const remoteEstab = {};
360
+ let total = 0;
361
+ for (const [file, isV6] of [["/proc/net/tcp", false], ["/proc/net/tcp6", true]]) {
362
+ let txt;
363
+ try {
364
+ txt = await promises_1.default.readFile(file, "utf-8");
365
+ }
366
+ catch {
367
+ continue;
368
+ }
369
+ for (const line of txt.split("\n").slice(1)) {
370
+ const parts = line.trim().split(/\s+/);
371
+ if (parts.length < 10)
372
+ continue;
373
+ const inode = parts[9];
374
+ if (!inodes.has(inode))
375
+ continue;
376
+ total++;
377
+ const state = this._tcpState(parts[3]);
378
+ byState[state] = (byState[state] ?? 0) + 1;
379
+ if (state === "ESTABLISHED") {
380
+ const host = this._parseHexAddr((parts[2] ?? "").split(":")[0], isV6);
381
+ remoteEstab[host] = (remoteEstab[host] ?? 0) + 1;
382
+ }
383
+ }
384
+ }
385
+ const topRemotes = Object.entries(remoteEstab)
386
+ .map(([host, established]) => ({ host, established }))
387
+ .sort((a, b) => b.established - a.established)
388
+ .slice(0, 10);
389
+ return { total, byState, topRemotes };
390
+ }
391
+ catch {
392
+ return null;
393
+ }
394
+ }
395
+ static _tcpState(hex) {
396
+ switch ((hex || "").toUpperCase()) {
397
+ case "01": return "ESTABLISHED";
398
+ case "02": return "SYN_SENT";
399
+ case "03": return "SYN_RECV";
400
+ case "04": return "FIN_WAIT1";
401
+ case "05": return "FIN_WAIT2";
402
+ case "06": return "TIME_WAIT";
403
+ case "07": return "CLOSE";
404
+ case "08": return "CLOSE_WAIT";
405
+ case "09": return "LAST_ACK";
406
+ case "0A": return "LISTEN";
407
+ case "0B": return "CLOSING";
408
+ case "0C": return "NEW_SYN_RECV";
409
+ default: return "UNKNOWN(" + hex + ")";
410
+ }
411
+ }
412
+ static _parseHexAddr(hex, isV6) {
413
+ try {
414
+ if (!isV6) {
415
+ if (hex.length !== 8)
416
+ return hex;
417
+ return [
418
+ parseInt(hex.slice(6, 8), 16),
419
+ parseInt(hex.slice(4, 6), 16),
420
+ parseInt(hex.slice(2, 4), 16),
421
+ parseInt(hex.slice(0, 2), 16),
422
+ ].join(".");
423
+ }
424
+ if (hex.length !== 32)
425
+ return hex;
426
+ const bytes = [];
427
+ for (let w = 0; w < 4; w++) {
428
+ const word = hex.slice(w * 8, w * 8 + 8);
429
+ for (let b = 3; b >= 0; b--)
430
+ bytes.push(parseInt(word.slice(b * 2, b * 2 + 2), 16));
431
+ }
432
+ const hextets = [];
433
+ for (let i = 0; i < 16; i += 2)
434
+ hextets.push((((bytes[i] << 8) | bytes[i + 1]) >>> 0).toString(16));
435
+ return hextets.join(":");
436
+ }
437
+ catch {
438
+ return hex;
439
+ }
440
+ }
281
441
  static _parseLimitValue(v) {
282
442
  if (v === "unlimited")
283
443
  return -1;
@@ -1,18 +1,17 @@
1
- /// <reference types="node" />
2
1
  export declare function collectSystemInfo(): Promise<{
3
2
  cpu: {
4
- usage: {
5
- userPct: number;
6
- systemPct: number;
7
- idlePct: number;
8
- iowaitPct: number;
9
- } | null;
10
3
  count: number;
11
4
  models: Record<string, number>;
12
5
  loadAvg: number[];
13
6
  platform: NodeJS.Platform;
14
7
  arch: NodeJS.Architecture;
15
8
  uptimeSec: number;
9
+ usage: {
10
+ userPct: number;
11
+ systemPct: number;
12
+ idlePct: number;
13
+ iowaitPct: number;
14
+ } | null;
16
15
  };
17
16
  memory: {
18
17
  total: number;
@@ -61,9 +60,9 @@ export declare function collectSystemInfo(): Promise<{
61
60
  error: string;
62
61
  processes?: undefined;
63
62
  } | {
63
+ error?: undefined;
64
64
  installed: boolean;
65
65
  processes: any;
66
- error?: undefined;
67
66
  } | {
68
67
  installed: boolean;
69
68
  error: string;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.collectSystemInfo = void 0;
6
+ exports.collectSystemInfo = collectSystemInfo;
7
7
  const os_1 = __importDefault(require("os"));
8
8
  const child_process_1 = require("child_process");
9
9
  const util_1 = require("util");
@@ -215,4 +215,3 @@ async function collectSystemInfo() {
215
215
  pm2: pm2Data,
216
216
  };
217
217
  }
218
- exports.collectSystemInfo = collectSystemInfo;