@lvce-editor/process-explorer 3.1.0 → 3.3.0

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 (2) hide show
  1. package/dist/index.js +190 -118
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1,18 +1,16 @@
1
1
  import { ElectronMessagePortRpcClient, WebSocketRpcParent, NodeWebSocketRpcClient, NodeWorkerRpcClient, NodeForkedProcessRpcClient, ElectronUtilityProcessRpcClient } from '@lvce-editor/rpc';
2
2
  import { object, number, string } from '@lvce-editor/assert';
3
- import { RpcId, MainProcess, set as set$1 } from '@lvce-editor/rpc-registry';
3
+ import { RpcId, MainProcess, set as set$2 } from '@lvce-editor/rpc-registry';
4
+ import { execFile as execFile$2 } from 'node:child_process';
5
+ import { promisify } from 'node:util';
4
6
  import { VError } from '@lvce-editor/verror';
5
7
  import { readFile } from 'node:fs/promises';
6
8
  import { join } from 'node:path';
7
- import { execFile as execFile$1 } from 'node:child_process';
8
- import { promisify } from 'node:util';
9
9
 
10
10
  const state = {
11
11
  commandMap: {}
12
12
  };
13
- const set = commandMap => {
14
- state.commandMap = commandMap;
15
- };
13
+
16
14
  const get = () => {
17
15
  return state.commandMap;
18
16
  };
@@ -21,6 +19,14 @@ const requiresSocket = () => {
21
19
  return false;
22
20
  };
23
21
 
22
+ const createMessagePortRpc = async (create, messagePort) => {
23
+ return create({
24
+ commandMap: get(),
25
+ messagePort,
26
+ requiresSocket: requiresSocket
27
+ });
28
+ };
29
+
24
30
  const setRpc = (rpc, rpcId) => {
25
31
  if (typeof rpcId !== 'number') {
26
32
  return;
@@ -29,16 +35,9 @@ const setRpc = (rpc, rpcId) => {
29
35
  MainProcess.set(rpc);
30
36
  return;
31
37
  }
32
- set$1(rpcId, rpc);
38
+ set$2(rpcId, rpc);
33
39
  };
34
40
 
35
- const createMessagePortRpc = async (create, messagePort) => {
36
- return create({
37
- commandMap: get(),
38
- messagePort,
39
- requiresSocket: requiresSocket
40
- });
41
- };
42
41
  const handleMessagePort = async (messagePort, rpcId) => {
43
42
  object(messagePort);
44
43
  const rpc = await createMessagePortRpc(ElectronMessagePortRpcClient.create, messagePort);
@@ -55,12 +54,31 @@ const createSocketRpc = async (create, webSocket) => {
55
54
  webSocket
56
55
  });
57
56
  };
57
+
58
58
  const handleSocket = async (webSocket, rpcId) => {
59
59
  object(webSocket);
60
60
  const rpc = await createSocketRpc(WebSocketRpcParent.create, webSocket);
61
61
  setRpc(rpc, rpcId);
62
62
  };
63
63
 
64
+ const createWebSocketRpc = async (create, handle, request) => {
65
+ return create({
66
+ commandMap: get(),
67
+ handle,
68
+ request,
69
+ requiresSocket: requiresSocket
70
+ });
71
+ };
72
+ const handleWebSocket = async (handle, request, rpcId) => {
73
+ if (!handle || !request) {
74
+ return;
75
+ }
76
+ object(handle);
77
+ object(request);
78
+ const rpc = await createWebSocketRpc(NodeWebSocketRpcClient.create, handle, request);
79
+ setRpc(rpc, rpcId);
80
+ };
81
+
64
82
  const isWindows = process.platform === 'win32';
65
83
 
66
84
  const getModule$1 = async () => {
@@ -69,24 +87,71 @@ const getModule$1 = async () => {
69
87
  }
70
88
  return Promise.resolve().then(function () { return ListProcessesWithMemoryUsageUnix; });
71
89
  };
72
- const listProcessesWithMemoryUsage$2 = async rootPid => {
90
+
91
+ const listProcessesWithMemoryUsage$2 = async (rootPid, includeElectronData = true) => {
73
92
  const module = await getModule$1();
74
- return module.listProcessesWithMemoryUsage(rootPid);
93
+ return module.listProcessesWithMemoryUsage(rootPid, includeElectronData);
75
94
  };
76
95
 
77
- const getMainProcessId = () => {
78
- return process.ppid;
96
+ const execFile$1 = promisify(execFile$2);
97
+ const parseProcessId = stdout => {
98
+ const parentProcessId = Number(stdout.trim());
99
+ if (!Number.isFinite(parentProcessId) || parentProcessId <= 0) {
100
+ return 0;
101
+ }
102
+ return parentProcessId;
103
+ };
104
+ const getParentProcessIdUnix = async pid => {
105
+ const {
106
+ stdout
107
+ } = await execFile$1('ps', ['-o', 'ppid=', '-p', String(pid)]);
108
+ return parseProcessId(stdout);
109
+ };
110
+ const getParentProcessIdWindows = async pid => {
111
+ const {
112
+ stdout
113
+ } = await execFile$1('powershell.exe', ['-NoProfile', '-Command', `(Get-CimInstance Win32_Process -Filter "ProcessId = ${pid}").ParentProcessId`]);
114
+ return parseProcessId(stdout);
115
+ };
116
+ const getParentProcessId = async pid => {
117
+ if (process.platform === 'win32') {
118
+ return getParentProcessIdWindows(pid);
119
+ }
120
+ return getParentProcessIdUnix(pid);
121
+ };
122
+ const getRemoteRootProcessId = async (childProcessId = process.ppid) => {
123
+ try {
124
+ const parentProcessId = await getParentProcessId(childProcessId);
125
+ return parentProcessId || process.ppid;
126
+ } catch {
127
+ return process.ppid;
128
+ }
129
+ };
130
+ const getMainProcessId = (includeElectronData = true, childProcessId = process.ppid) => {
131
+ if (includeElectronData) {
132
+ return Promise.resolve(process.ppid);
133
+ }
134
+ return getRemoteRootProcessId(childProcessId);
79
135
  };
80
136
 
81
137
  const commandMap = {
82
138
  'HandleElectronMessagePort.handleElectronMessagePort': handleElectronMessagePort,
83
139
  'HandleMessagePort.handleMessagePort': handleMessagePort,
84
140
  'HandleSocket.handleSocket': handleSocket,
141
+ 'HandleWebSocket.handleWebSocket': handleWebSocket,
85
142
  'ListProcessesWithMemoryUsage.listProcessesWithMemoryUsage': listProcessesWithMemoryUsage$2,
86
143
  'ProcessId.getMainProcessId': getMainProcessId
87
144
  // 'ElectronContextMenu.openContextMenu': ElectronWebContentsView.handleContextMenu,
88
145
  };
89
146
 
147
+ const set$1 = commandMap => {
148
+ state.commandMap = commandMap;
149
+ };
150
+
151
+ const set = commandMap => {
152
+ set$1(commandMap);
153
+ };
154
+
90
155
  const NodeWorker = 1;
91
156
  const NodeForkedProcess = 2;
92
157
  const ElectronUtilityProcess = 3;
@@ -148,26 +213,56 @@ const main = async () => {
148
213
 
149
214
  main();
150
215
 
216
+ const ENOENT = 'ENOENT';
217
+ const ERR_DLOPEN_FAILED = 'ERR_DLOPEN_FAILED';
218
+ const ESRCH = 'ESRCH';
219
+
220
+ const isDlOpenError = error => {
221
+ return error instanceof Error && 'code' in error && error.code === ERR_DLOPEN_FAILED;
222
+ };
223
+
224
+ const loadWindowProcessTree = async () => {
225
+ try {
226
+ return await import('@vscode/windows-process-tree');
227
+ } catch (error) {
228
+ if (isDlOpenError(error)) {
229
+ throw new VError(`Failed to load windows process tree: The native module "@vscode/windows-process-tree" is not compatible with this node version and must be compiled against a matching electron version using electron-rebuild`);
230
+ }
231
+ throw new VError(error, `Failed to load windows process tree`);
232
+ }
233
+ };
234
+
235
+ const withResolvers = () => {
236
+ return Promise.withResolvers();
237
+ };
238
+
239
+ const addCpuUsage = async processList => {
240
+ const WindowsProcessTree = await loadWindowProcessTree();
241
+ const {
242
+ promise,
243
+ resolve
244
+ } = withResolvers();
245
+ const mutableProcessList = processList.map(process => ({
246
+ ...process
247
+ }));
248
+ WindowsProcessTree.getProcessCpuUsage(mutableProcessList, resolve);
249
+ return promise;
250
+ };
251
+
151
252
  const createPidMap = async () => {
152
253
  return MainProcess.invoke('CreatePidMap.createPidMap');
153
254
  };
154
255
 
155
- const processNamePatterns = [{
156
- matches: cmd => cmd.includes('--type=zygote'),
157
- name: 'zygote'
158
- }, {
159
- matches: cmd => cmd.includes('--type=gpu-process'),
160
- name: 'gpu-process'
161
- }, {
162
- matches: cmd => cmd.includes('extensionHostMain.js'),
163
- name: 'extension-host'
164
- }, {
165
- matches: cmd => cmd.includes('ptyHostMain.js'),
166
- name: 'pty-host'
167
- }, {
168
- matches: cmd => cmd.includes('--lvce-window-kind=process-explorer'),
169
- name: 'process-explorer'
170
- }];
256
+ const getProcessList = async (rootPid, flags) => {
257
+ const WindowsProcessTree = await loadWindowProcessTree();
258
+ const {
259
+ promise,
260
+ resolve
261
+ } = withResolvers();
262
+ WindowsProcessTree.getProcessList(rootPid, resolve, flags);
263
+ return promise;
264
+ };
265
+
171
266
  const fallbackProcessNamePatterns = [{
172
267
  matches: cmd => cmd.includes('--type=renderer'),
173
268
  name: 'renderer'
@@ -196,12 +291,32 @@ const fallbackProcessNamePatterns = [{
196
291
  matches: cmd => cmd.includes('\\conhost.exe'),
197
292
  name: 'conhost.exe'
198
293
  }];
199
- const getPatternName = cmd => {
200
- return processNamePatterns.find(pattern => pattern.matches(cmd))?.name || '';
201
- };
294
+
202
295
  const getFallbackPatternName = cmd => {
203
296
  return fallbackProcessNamePatterns.find(pattern => pattern.matches(cmd))?.name || '';
204
297
  };
298
+
299
+ const processNamePatterns = [{
300
+ matches: cmd => cmd.includes('--type=zygote'),
301
+ name: 'zygote'
302
+ }, {
303
+ matches: cmd => cmd.includes('--type=gpu-process'),
304
+ name: 'gpu-process'
305
+ }, {
306
+ matches: cmd => cmd.includes('extensionHostMain.js'),
307
+ name: 'extension-host'
308
+ }, {
309
+ matches: cmd => cmd.includes('ptyHostMain.js'),
310
+ name: 'pty-host'
311
+ }, {
312
+ matches: cmd => cmd.includes('--lvce-window-kind=process-explorer'),
313
+ name: 'process-explorer'
314
+ }];
315
+
316
+ const getPatternName = cmd => {
317
+ return processNamePatterns.find(pattern => pattern.matches(cmd))?.name || '';
318
+ };
319
+
205
320
  const getName = (pid, cmd, rootPid, pidMap) => {
206
321
  number(pid);
207
322
  string(cmd);
@@ -224,61 +339,6 @@ const getName = (pid, cmd, rootPid, pidMap) => {
224
339
  return cmd;
225
340
  };
226
341
 
227
- const ENOENT = 'ENOENT';
228
- const ERR_DLOPEN_FAILED = 'ERR_DLOPEN_FAILED';
229
- const ESRCH = 'ESRCH';
230
-
231
- const isDlOpenError = error => {
232
- return error instanceof Error && 'code' in error && error.code === ERR_DLOPEN_FAILED;
233
- };
234
-
235
- const loadWindowProcessTree = async () => {
236
- try {
237
- return await import('@vscode/windows-process-tree');
238
- } catch (error) {
239
- if (isDlOpenError(error)) {
240
- throw new VError(`Failed to load windows process tree: The native module "@vscode/windows-process-tree" is not compatible with this node version and must be compiled against a matching electron version using electron-rebuild`);
241
- }
242
- throw new VError(error, `Failed to load windows process tree`);
243
- }
244
- };
245
-
246
- const withResolvers = () => {
247
- return Promise.withResolvers();
248
- };
249
-
250
- const getProcessList = async (rootPid, flags) => {
251
- const WindowsProcessTree = await loadWindowProcessTree();
252
- const {
253
- promise,
254
- resolve
255
- } = withResolvers();
256
- WindowsProcessTree.getProcessList(rootPid, resolve, flags);
257
- return promise;
258
- };
259
- const addCpuUsage = async processList => {
260
- const WindowsProcessTree = await loadWindowProcessTree();
261
- const {
262
- promise,
263
- resolve
264
- } = withResolvers();
265
- const mutableProcessList = processList.map(process => ({
266
- ...process
267
- }));
268
- WindowsProcessTree.getProcessCpuUsage(mutableProcessList, resolve);
269
- return promise;
270
- };
271
-
272
- const Memory = 1;
273
- const CommandLine = 2;
274
-
275
- // listProcesses windows implementation based on https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/node/ps.ts (License MIT)
276
-
277
- /**
278
- * @param {import('@vscode/windows-process-tree').IProcessCpuInfo} item
279
- * @param {number} rootPid
280
- * @param {object} pidMap
281
- */
282
342
  const toResultItem = (item, rootPid, pidMap) => {
283
343
  return {
284
344
  cmd: item.commandLine,
@@ -288,17 +348,24 @@ const toResultItem = (item, rootPid, pidMap) => {
288
348
  ppid: item.ppid
289
349
  };
290
350
  };
351
+
291
352
  const toResult = (completeProcessList, rootPid, pidMap) => {
292
353
  const results = Array.from(completeProcessList, item => toResultItem(item, rootPid, pidMap));
293
354
  return results;
294
355
  };
295
- const listProcessesWithMemoryUsage$1 = async rootPid => {
356
+
357
+ const Memory = 1;
358
+ const CommandLine = 2;
359
+
360
+ // listProcesses windows implementation based on https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/node/ps.ts (License MIT)
361
+
362
+ const listProcessesWithMemoryUsage$1 = async (rootPid, includeElectronData = true) => {
296
363
  try {
297
364
  const processList = await getProcessList(rootPid, CommandLine | Memory);
298
365
  if (!processList) {
299
366
  throw new VError(`Root process ${rootPid} not found`);
300
367
  }
301
- const pidMap = await createPidMap();
368
+ const pidMap = includeElectronData ? await createPidMap() : {};
302
369
  const completeProcessList = await addCpuUsage(processList);
303
370
  const result = toResult(completeProcessList, rootPid, pidMap);
304
371
  return result;
@@ -315,13 +382,14 @@ const ListProcessesWithMemoryUsageWindows = {
315
382
 
316
383
  const Utf8 = 'utf8';
317
384
 
385
+ const isEnoentErrorLinux = error => {
386
+ return error.code === ENOENT;
387
+ };
388
+
318
389
  const isEnoentErrorWindows = error => {
319
390
  return error && error.message && error.message.includes('The system cannot find the path specified.');
320
391
  };
321
392
 
322
- const isEnoentErrorLinux = error => {
323
- return error.code === ENOENT;
324
- };
325
393
  const isEnoentError = error => {
326
394
  if (!error) {
327
395
  return false;
@@ -333,6 +401,19 @@ const isEsrchError = error => {
333
401
  return error && error.code === ESRCH;
334
402
  };
335
403
 
404
+ const getContent = async pid => {
405
+ try {
406
+ const filePath = join('/proc', String(pid), 'statm');
407
+ const content = await readFile(filePath, Utf8);
408
+ return content;
409
+ } catch (error) {
410
+ if (isEnoentError(error) || isEsrchError(error)) {
411
+ return '';
412
+ }
413
+ throw error;
414
+ }
415
+ };
416
+
336
417
  const isMacOs = process.platform === 'darwin';
337
418
 
338
419
  const EmptyString = '';
@@ -349,18 +430,6 @@ const parseMemory = content => {
349
430
  return memory;
350
431
  };
351
432
 
352
- const getContent = async pid => {
353
- try {
354
- const filePath = join('/proc', String(pid), 'statm');
355
- const content = await readFile(filePath, Utf8);
356
- return content;
357
- } catch (error) {
358
- if (isEnoentError(error) || isEsrchError(error)) {
359
- return '';
360
- }
361
- throw error;
362
- }
363
- };
364
433
  const getAccurateMemoryUsage = async pid => {
365
434
  try {
366
435
  number(pid);
@@ -388,7 +457,7 @@ const addAccurateMemoryUsage = async process => {
388
457
 
389
458
  const SIGINT = 'SIGINT';
390
459
 
391
- const execFile = promisify(execFile$1);
460
+ const execFile = promisify(execFile$2);
392
461
  const getPsOutput = async () => {
393
462
  try {
394
463
  const {
@@ -408,15 +477,10 @@ const hasPositiveMemoryUsage = process => {
408
477
  return process.memory >= 0;
409
478
  };
410
479
 
411
- const splitLines = lines => {
412
- return lines.split(NewLine);
413
- };
414
-
415
- // parse ps output based on vscode https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/node/ps.ts (License MIT)
416
-
417
480
  const isSpace = character => {
418
481
  return character === ' ' || character === '\t';
419
482
  };
483
+
420
484
  const readField = (line, startIndex) => {
421
485
  let start = startIndex;
422
486
  while (start < line.length && isSpace(line[start])) {
@@ -431,6 +495,7 @@ const readField = (line, startIndex) => {
431
495
  value: line.slice(start, end)
432
496
  };
433
497
  };
498
+
434
499
  const parsePsOutputLine = line => {
435
500
  string(line);
436
501
  const trimmedLine = line.trim();
@@ -448,6 +513,13 @@ const parsePsOutputLine = line => {
448
513
  }
449
514
  throw new Error(`line could not be parsed: ${line}`);
450
515
  };
516
+
517
+ const splitLines = lines => {
518
+ return lines.split(NewLine);
519
+ };
520
+
521
+ // parse ps output based on vscode https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/node/ps.ts (License MIT)
522
+
451
523
  const parsePsOutput = (stdout, rootPid, pidMap) => {
452
524
  string(stdout);
453
525
  number(rootPid);
@@ -480,10 +552,10 @@ const parsePsOutput = (stdout, rootPid, pidMap) => {
480
552
  return result;
481
553
  };
482
554
 
483
- const listProcessesWithMemoryUsage = async rootPid => {
555
+ const listProcessesWithMemoryUsage = async (rootPid, includeElectronData = true) => {
484
556
  // console.time('getPsOutput')
485
557
  const stdout = await getPsOutput();
486
- const pidMap = await createPidMap();
558
+ const pidMap = includeElectronData ? await createPidMap() : {};
487
559
  // console.log({ stdout })
488
560
  // console.timeEnd('getPsOutput')
489
561
  // console.time('parsePsOutput')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvce-editor/process-explorer",
3
- "version": "3.1.0",
3
+ "version": "3.3.0",
4
4
  "description": "Process Explorer",
5
5
  "main": "dist/index.js",
6
6
  "bin": "bin/processExplorer.js",
@@ -20,7 +20,7 @@
20
20
  "dependencies": {
21
21
  "@lvce-editor/assert": "^1.5.1",
22
22
  "@lvce-editor/rpc": "^6.4.0",
23
- "@lvce-editor/rpc-registry": "^9.27.0",
23
+ "@lvce-editor/rpc-registry": "^9.28.0",
24
24
  "@lvce-editor/verror": "^1.7.0"
25
25
  },
26
26
  "optionalDependencies": {