@lvce-editor/shared-process 0.15.27 → 0.15.28
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.
- package/mocks/windows-process-tree.js +1 -0
- package/package.json +5 -5
- package/src/parts/CreatePidMap/CreatePidMap.js +6 -0
- package/src/parts/ErrorCodes/ErrorCodes.js +1 -0
- package/src/parts/ErrorType/ErrorType.js +4 -0
- package/src/parts/GetAccurateMemoryUsage/GetAccurateMemoryUsage.js +38 -0
- package/src/parts/GetElectronRebuildPath/GetElectronRebuildPath.js +6 -0
- package/src/parts/GetErrorConstructor/GetErrorConstructor.js +28 -0
- package/src/parts/GetPsOutput/GetPsOutput.js +20 -0
- package/src/parts/JsonRpc/JsonRpc.js +9 -4
- package/src/parts/ListProcessGetName/ListProcessGetName.js +54 -0
- package/src/parts/ListProcessesWithMemoryUsage/ListProcessesWithMemoryUsage.ipc.js +7 -0
- package/src/parts/ListProcessesWithMemoryUsage/ListProcessesWithMemoryUsage.js +13 -0
- package/src/parts/ListProcessesWithMemoryUsageUnix/ListProcessesWithMemoryUsageUnix.js +32 -0
- package/src/parts/ListProcessesWithMemoryUsageWindows/ListProcessesWithMemoryUsageWindows.js +51 -0
- package/src/parts/LoadWindowsProcessTree/LoadWindowsProcessTree.js +16 -0
- package/src/parts/Module/Module.js +2 -0
- package/src/parts/ModuleId/ModuleId.js +1 -0
- package/src/parts/ModuleMap/ModuleMap.js +3 -0
- package/src/parts/ParentIpc/ParentIpc.js +8 -0
- package/src/parts/ParsePsOutput/ParsePsOutput.js +50 -0
- package/src/parts/Process/Process.ipc.js +1 -0
- package/src/parts/RebuildNodePty/RebuildNodePty.js +11 -10
- package/src/parts/RestoreJsonRpcError/RestoreJsonRpcError.js +79 -0
- package/src/parts/UnwrapJsonRpcResult/UnwrapJsonRpcResult.js +13 -0
- package/src/parts/WindowsProcessTree/WindowsProcessTree.js +26 -0
- package/src/parts/WindowsProcessTreeDataFlag/WindowsProcessTreeDataFlag.js +3 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lvce-editor/shared-process",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.28",
|
|
4
4
|
"description": "Utility package for @lvce-editor/server",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
"node": ">=16"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@babel/code-frame": "^7.
|
|
20
|
-
"@lvce-editor/extension-host": "0.15.
|
|
21
|
-
"@lvce-editor/extension-host-helper-process": "0.15.
|
|
22
|
-
"@lvce-editor/pty-host": "0.15.
|
|
19
|
+
"@babel/code-frame": "^7.22.5",
|
|
20
|
+
"@lvce-editor/extension-host": "0.15.28",
|
|
21
|
+
"@lvce-editor/extension-host-helper-process": "0.15.28",
|
|
22
|
+
"@lvce-editor/pty-host": "0.15.28",
|
|
23
23
|
"debug": "^4.3.4",
|
|
24
24
|
"execa": "^7.1.1",
|
|
25
25
|
"exit-hook": "^3.2.0",
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { join } from 'node:path'
|
|
2
|
+
import { readFile } from 'node:fs/promises'
|
|
3
|
+
import { VError } from '../VError/VError.js'
|
|
4
|
+
import * as Assert from '../Assert/Assert.js'
|
|
5
|
+
import * as EncodingType from '../EncodingType/EncodingType.js'
|
|
6
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
7
|
+
|
|
8
|
+
export const getAccurateMemoryUsage = async (pid) => {
|
|
9
|
+
Assert.number(pid)
|
|
10
|
+
try {
|
|
11
|
+
const filePath = join('/proc', `${pid}`, 'statm')
|
|
12
|
+
let content
|
|
13
|
+
try {
|
|
14
|
+
content = await readFile(filePath, EncodingType.Utf8)
|
|
15
|
+
} catch (error) {
|
|
16
|
+
if (
|
|
17
|
+
error &&
|
|
18
|
+
// @ts-ignore
|
|
19
|
+
(error.code === ErrorCodes.ENOENT ||
|
|
20
|
+
// @ts-ignore
|
|
21
|
+
error.code === ErrorCodes.ESRCH)
|
|
22
|
+
) {
|
|
23
|
+
return -1
|
|
24
|
+
}
|
|
25
|
+
throw error
|
|
26
|
+
}
|
|
27
|
+
const trimmedContent = content.trim()
|
|
28
|
+
const numberBlocks = trimmedContent.split(' ')
|
|
29
|
+
const pageSize = 4096
|
|
30
|
+
const rss = Number.parseInt(numberBlocks[1]) * pageSize
|
|
31
|
+
const shared = Number.parseInt(numberBlocks[2]) * pageSize
|
|
32
|
+
const memory = rss - shared
|
|
33
|
+
return memory
|
|
34
|
+
} catch (error) {
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
throw new VError(error, 'Failed to get accurate memory usage')
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as ErrorType from '../ErrorType/ErrorType.js'
|
|
2
|
+
|
|
3
|
+
export const getErrorConstructor = (message, type) => {
|
|
4
|
+
if (type) {
|
|
5
|
+
switch (type) {
|
|
6
|
+
case ErrorType.DomException:
|
|
7
|
+
return DOMException
|
|
8
|
+
case ErrorType.TypeError:
|
|
9
|
+
return TypeError
|
|
10
|
+
case ErrorType.SyntaxError:
|
|
11
|
+
return SyntaxError
|
|
12
|
+
case ErrorType.ReferenceError:
|
|
13
|
+
return ReferenceError
|
|
14
|
+
default:
|
|
15
|
+
return Error
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (message.startsWith('TypeError: ')) {
|
|
19
|
+
return TypeError
|
|
20
|
+
}
|
|
21
|
+
if (message.startsWith('SyntaxError: ')) {
|
|
22
|
+
return SyntaxError
|
|
23
|
+
}
|
|
24
|
+
if (message.startsWith('ReferenceError: ')) {
|
|
25
|
+
return ReferenceError
|
|
26
|
+
}
|
|
27
|
+
return Error
|
|
28
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { VError } from '../VError/VError.js'
|
|
2
|
+
import { execFile as _execFile } from 'node:child_process'
|
|
3
|
+
import * as Signal from '../Signal/Signal.js'
|
|
4
|
+
import { promisify } from 'node:util'
|
|
5
|
+
|
|
6
|
+
const execFile = promisify(_execFile)
|
|
7
|
+
|
|
8
|
+
export const getPsOutput = async () => {
|
|
9
|
+
try {
|
|
10
|
+
const { stdout } = await execFile('ps', ['-ax', '-o', 'pid=,ppid=,pcpu=,pmem=,command='])
|
|
11
|
+
return stdout.trim()
|
|
12
|
+
} catch (error) {
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
if (error && error.signal === Signal.SIGINT) {
|
|
15
|
+
return ''
|
|
16
|
+
}
|
|
17
|
+
// @ts-ignore
|
|
18
|
+
throw new VError(error, `Failed to execute ps`)
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Callback from '../Callback/Callback.js'
|
|
2
2
|
import * as JsonRpcVersion from '../JsonRpcVersion/JsonRpcVersion.js'
|
|
3
|
+
import * as UnwrapJsonRpcResult from '../UnwrapJsonRpcResult/UnwrapJsonRpcResult.js'
|
|
3
4
|
|
|
4
5
|
export const send = (transport, method, ...params) => {
|
|
5
6
|
transport.send({
|
|
@@ -9,7 +10,7 @@ export const send = (transport, method, ...params) => {
|
|
|
9
10
|
})
|
|
10
11
|
}
|
|
11
12
|
|
|
12
|
-
export const invoke = (ipc, method, ...params) => {
|
|
13
|
+
export const invoke = async (ipc, method, ...params) => {
|
|
13
14
|
const { id, promise } = Callback.registerPromise()
|
|
14
15
|
ipc.send({
|
|
15
16
|
jsonrpc: JsonRpcVersion.Two,
|
|
@@ -17,10 +18,12 @@ export const invoke = (ipc, method, ...params) => {
|
|
|
17
18
|
params,
|
|
18
19
|
id,
|
|
19
20
|
})
|
|
20
|
-
|
|
21
|
+
const responseMessage = await promise
|
|
22
|
+
const result = UnwrapJsonRpcResult.unwrapJsonRpcResult(responseMessage)
|
|
23
|
+
return result
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
export const invokeAndTransfer = (ipc, handle, method, ...params) => {
|
|
26
|
+
export const invokeAndTransfer = async (ipc, handle, method, ...params) => {
|
|
24
27
|
const { id, promise } = Callback.registerPromise()
|
|
25
28
|
ipc.sendAndTransfer(
|
|
26
29
|
{
|
|
@@ -31,5 +34,7 @@ export const invokeAndTransfer = (ipc, handle, method, ...params) => {
|
|
|
31
34
|
},
|
|
32
35
|
handle
|
|
33
36
|
)
|
|
34
|
-
|
|
37
|
+
const responseMessage = await promise
|
|
38
|
+
const result = UnwrapJsonRpcResult.unwrapJsonRpcResult(responseMessage)
|
|
39
|
+
return result
|
|
35
40
|
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import * as Assert from '../Assert/Assert.js'
|
|
2
|
+
|
|
3
|
+
export const getName = (pid, cmd, rootPid, pidMap) => {
|
|
4
|
+
Assert.number(pid)
|
|
5
|
+
Assert.string(cmd)
|
|
6
|
+
Assert.number(rootPid)
|
|
7
|
+
Assert.object(pidMap)
|
|
8
|
+
if (pid === rootPid) {
|
|
9
|
+
return 'main'
|
|
10
|
+
}
|
|
11
|
+
if (cmd.includes('--type=zygote')) {
|
|
12
|
+
return 'zygote'
|
|
13
|
+
}
|
|
14
|
+
if (cmd.includes('--type=gpu-process')) {
|
|
15
|
+
return 'gpu-process'
|
|
16
|
+
}
|
|
17
|
+
if (cmd.includes('extensionHostMain.js')) {
|
|
18
|
+
return 'extension-host'
|
|
19
|
+
}
|
|
20
|
+
if (cmd.includes('ptyHostMain.js')) {
|
|
21
|
+
return 'pty-host'
|
|
22
|
+
}
|
|
23
|
+
if (cmd.includes('--lvce-window-kind=process-explorer')) {
|
|
24
|
+
return 'process-explorer'
|
|
25
|
+
}
|
|
26
|
+
if (pid in pidMap) {
|
|
27
|
+
return pidMap[pid] || `<unknown>`
|
|
28
|
+
}
|
|
29
|
+
if (cmd.includes('--type=renderer')) {
|
|
30
|
+
return `renderer`
|
|
31
|
+
}
|
|
32
|
+
if (cmd.includes('--type=utility')) {
|
|
33
|
+
return 'utility'
|
|
34
|
+
}
|
|
35
|
+
if (cmd.includes('typescript/lib/tsserver.js')) {
|
|
36
|
+
return 'tsserver.js'
|
|
37
|
+
}
|
|
38
|
+
if (cmd.includes('typescript/lib/typingsInstaller.js')) {
|
|
39
|
+
return 'typingsInstaller.js'
|
|
40
|
+
}
|
|
41
|
+
if (cmd.includes('extensionHostHelperProcessMain.js')) {
|
|
42
|
+
return 'extension-host-helper-process'
|
|
43
|
+
}
|
|
44
|
+
if (cmd.includes('/bin/rg')) {
|
|
45
|
+
return 'ripgrep'
|
|
46
|
+
}
|
|
47
|
+
if (cmd.startsWith('bash')) {
|
|
48
|
+
return 'bash'
|
|
49
|
+
}
|
|
50
|
+
if (cmd.startsWith(`/opt/sublime_text/sublime_text `)) {
|
|
51
|
+
return 'sublime-text'
|
|
52
|
+
}
|
|
53
|
+
return `${cmd}`
|
|
54
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as Platform from '../Platform/Platform.js'
|
|
2
|
+
|
|
3
|
+
const getModule = () => {
|
|
4
|
+
if (Platform.isWindows) {
|
|
5
|
+
return import('../ListProcessesWithMemoryUsageWindows/ListProcessesWithMemoryUsageWindows.js')
|
|
6
|
+
}
|
|
7
|
+
return import('../ListProcessesWithMemoryUsageUnix/ListProcessesWithMemoryUsageUnix.js')
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const listProcessesWithMemoryUsage = async (rootPid) => {
|
|
11
|
+
const module = await getModule()
|
|
12
|
+
return module.listProcessesWithMemoryUsage(rootPid)
|
|
13
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as CreatePidMap from '../CreatePidMap/CreatePidMap.js'
|
|
2
|
+
import * as GetAccurateMemoryUsage from '../GetAccurateMemoryUsage/GetAccurateMemoryUsage.js'
|
|
3
|
+
import * as GetPsOutput from '../GetPsOutput/GetPsOutput.js'
|
|
4
|
+
import * as ParsePsOutput from '../ParsePsOutput/ParsePsOutput.js'
|
|
5
|
+
|
|
6
|
+
const addAccurateMemoryUsage = async (process) => {
|
|
7
|
+
const accurateMemoryUsage = await GetAccurateMemoryUsage.getAccurateMemoryUsage(process.pid)
|
|
8
|
+
return {
|
|
9
|
+
...process,
|
|
10
|
+
memory: accurateMemoryUsage,
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const hasPositiveMemoryUsage = (process) => {
|
|
15
|
+
return process.memory >= 0
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export const listProcessesWithMemoryUsage = async (rootPid) => {
|
|
19
|
+
// console.time('getPsOutput')
|
|
20
|
+
const stdout = await GetPsOutput.getPsOutput()
|
|
21
|
+
const pidMap = await CreatePidMap.createPidMap()
|
|
22
|
+
// console.log({ stdout })
|
|
23
|
+
// console.timeEnd('getPsOutput')
|
|
24
|
+
// console.time('parsePsOutput')
|
|
25
|
+
const parsed = ParsePsOutput.parsePsOutput(stdout, rootPid, pidMap)
|
|
26
|
+
// console.timeEnd('parsePsOutput')
|
|
27
|
+
// console.time('addAccurateMemoryUsage')
|
|
28
|
+
const parsedWithAccurateMemoryUsage = await Promise.all(parsed.map(addAccurateMemoryUsage))
|
|
29
|
+
// console.timeEnd('addAccurateMemoryUsage')
|
|
30
|
+
const filtered = parsedWithAccurateMemoryUsage.filter(hasPositiveMemoryUsage)
|
|
31
|
+
return filtered
|
|
32
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// listProcesses windows implementation based on https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/node/ps.ts (License MIT)
|
|
2
|
+
|
|
3
|
+
import { VError } from '../VError/VError.js'
|
|
4
|
+
import * as ListProcessGetName from '../ListProcessGetName/ListProcessGetName.js'
|
|
5
|
+
import * as WindowsProcessTree from '../WindowsProcessTree/WindowsProcessTree.js'
|
|
6
|
+
import * as WindowsProcessTreeDataFlag from '../WindowsProcessTreeDataFlag/WindowsProcessTreeDataFlag.js'
|
|
7
|
+
import * as CreatePidMap from '../CreatePidMap/CreatePidMap.js'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {import('@vscode/windows-process-tree').IProcessCpuInfo} item
|
|
11
|
+
* @param {number} rootPid
|
|
12
|
+
* @param {object} pidMap
|
|
13
|
+
*/
|
|
14
|
+
const toResultItem = (item, rootPid, pidMap) => {
|
|
15
|
+
return {
|
|
16
|
+
name: ListProcessGetName.getName(item.pid, item.commandLine, rootPid, pidMap),
|
|
17
|
+
pid: item.pid,
|
|
18
|
+
ppid: item.ppid,
|
|
19
|
+
memory: item.memory,
|
|
20
|
+
cmd: item.commandLine,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @param {import('@vscode/windows-process-tree').IProcessCpuInfo[]} completeProcessList
|
|
27
|
+
* @param {number} rootPid
|
|
28
|
+
*/
|
|
29
|
+
const toResult = (completeProcessList, rootPid, pidMap) => {
|
|
30
|
+
const results = []
|
|
31
|
+
for (const item of completeProcessList) {
|
|
32
|
+
results.push(toResultItem(item, rootPid, pidMap))
|
|
33
|
+
}
|
|
34
|
+
return results
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const listProcessesWithMemoryUsage = async (rootPid) => {
|
|
38
|
+
try {
|
|
39
|
+
const processList = await WindowsProcessTree.getProcessList(rootPid, WindowsProcessTreeDataFlag.CommandLine | WindowsProcessTreeDataFlag.Memory)
|
|
40
|
+
if (!processList) {
|
|
41
|
+
throw new VError(`Root process ${rootPid} not found`)
|
|
42
|
+
}
|
|
43
|
+
const pidMap = await CreatePidMap.createPidMap()
|
|
44
|
+
const completeProcessList = await WindowsProcessTree.addCpuUsage(processList)
|
|
45
|
+
const result = toResult(completeProcessList, rootPid, pidMap)
|
|
46
|
+
return result
|
|
47
|
+
} catch (error) {
|
|
48
|
+
// @ts-ignore
|
|
49
|
+
throw new VError(error, `Failed to list processes`)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { VError } from '../VError/VError.js'
|
|
2
|
+
import * as ErrorCodes from '../ErrorCodes/ErrorCodes.js'
|
|
3
|
+
|
|
4
|
+
export const loadWindowProcessTree = async () => {
|
|
5
|
+
try {
|
|
6
|
+
// @ts-ignore
|
|
7
|
+
return await import('@vscode/windows-process-tree')
|
|
8
|
+
} catch (error) {
|
|
9
|
+
if (error && error instanceof Error && 'code' in error && error.code === ErrorCodes.ERR_DLOPEN_FAILED) {
|
|
10
|
+
throw new VError(
|
|
11
|
+
`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`
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
throw new VError(error, `Failed to load windows process tree`)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -70,6 +70,8 @@ export const load = (moduleId) => {
|
|
|
70
70
|
return import('../GetTerminalSpawnOptions/GetTerminalSpawnOptions.ipc.js')
|
|
71
71
|
case ModuleId.HandleCliArgs:
|
|
72
72
|
return import('../HandleCliArgs/HandleCliArgs.ipc.js')
|
|
73
|
+
case ModuleId.ListProcessesWithMemoryUsage:
|
|
74
|
+
return import('../ListProcessesWithMemoryUsage/ListProcessesWithMemoryUsage.ipc.js')
|
|
73
75
|
default:
|
|
74
76
|
throw new Error(`module ${moduleId} not found`)
|
|
75
77
|
}
|
|
@@ -168,6 +168,7 @@ export const getModuleId = (commandId) => {
|
|
|
168
168
|
case 'RebuildNodePty.rebuildNodePty':
|
|
169
169
|
return ModuleId.RebuildNodePty
|
|
170
170
|
case 'Process.getPid':
|
|
171
|
+
case 'Process.kill':
|
|
171
172
|
return ModuleId.Process
|
|
172
173
|
case 'HandleNodeMessagePort.handleNodeMessagePort':
|
|
173
174
|
return ModuleId.HandleNodeMessagePort
|
|
@@ -177,6 +178,8 @@ export const getModuleId = (commandId) => {
|
|
|
177
178
|
return ModuleId.GetTerminalSpawnOptions
|
|
178
179
|
case 'HandleCliArgs.handleCliArgs':
|
|
179
180
|
return ModuleId.HandleCliArgs
|
|
181
|
+
case 'ListProcessesWithMemoryUsage.listProcessesWithMemoryUsage':
|
|
182
|
+
return ModuleId.ListProcessesWithMemoryUsage
|
|
180
183
|
default:
|
|
181
184
|
throw new CommandNotFoundError(commandId)
|
|
182
185
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as HandleIpc from '../HandleIpc/HandleIpc.js'
|
|
2
2
|
import * as IpcChild from '../IpcChild/IpcChild.js'
|
|
3
3
|
import * as IpcChildType from '../IpcChildType/IpcChildType.js'
|
|
4
|
+
import * as JsonRpc from '../JsonRpc/JsonRpc.js'
|
|
4
5
|
|
|
5
6
|
// TODO add tests for this
|
|
6
7
|
|
|
@@ -10,6 +11,7 @@ import * as IpcChildType from '../IpcChildType/IpcChildType.js'
|
|
|
10
11
|
|
|
11
12
|
export const state = {
|
|
12
13
|
electronPortMap: new Map(),
|
|
14
|
+
ipc: undefined,
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
// TODO maybe rename to hydrate
|
|
@@ -19,4 +21,10 @@ export const listen = async () => {
|
|
|
19
21
|
method,
|
|
20
22
|
})
|
|
21
23
|
HandleIpc.handleIpc(ipc)
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
state.ipc = ipc
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const invoke = (method, ...params) => {
|
|
29
|
+
return JsonRpc.invoke(state.ipc, method, ...params)
|
|
22
30
|
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// parse ps output based on vscode https://github.com/microsoft/vscode/blob/c0769274fa136b45799edeccc0d0a2f645b75caf/src/vs/base/node/ps.ts (License MIT)
|
|
2
|
+
|
|
3
|
+
import * as Assert from '../Assert/Assert.js'
|
|
4
|
+
import * as ListProcessGetName from '../ListProcessGetName/ListProcessGetName.js'
|
|
5
|
+
import * as SplitLines from '../SplitLines/SplitLines.js'
|
|
6
|
+
|
|
7
|
+
const PID_CMD = /^\s*(\d+)\s+(\d+)\s+([\d.]+)\s+([\d.]+)\s+(.+)$/s
|
|
8
|
+
|
|
9
|
+
const parsePsOutputLine = (line) => {
|
|
10
|
+
Assert.string(line)
|
|
11
|
+
const matches = PID_CMD.exec(line.trim())
|
|
12
|
+
if (matches && matches.length === 6) {
|
|
13
|
+
return {
|
|
14
|
+
pid: Number.parseInt(matches[1]),
|
|
15
|
+
ppid: Number.parseInt(matches[2]),
|
|
16
|
+
cmd: matches[5],
|
|
17
|
+
// load: parseInt(matches[3]),
|
|
18
|
+
// mem: parseInt(matches[4]),
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
throw new Error(`line could not be parsed: ${line}`)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const parsePsOutput = (stdout, rootPid, pidMap) => {
|
|
25
|
+
Assert.string(stdout)
|
|
26
|
+
Assert.number(rootPid)
|
|
27
|
+
Assert.object(pidMap)
|
|
28
|
+
if (stdout === '') {
|
|
29
|
+
return []
|
|
30
|
+
}
|
|
31
|
+
const lines = SplitLines.splitLines(stdout)
|
|
32
|
+
const result = []
|
|
33
|
+
const depthMap = Object.create(null)
|
|
34
|
+
depthMap[rootPid] = 1
|
|
35
|
+
const parsedLines = lines.map(parsePsOutputLine)
|
|
36
|
+
for (const parsedLine of parsedLines) {
|
|
37
|
+
const { pid, ppid, cmd } = parsedLine
|
|
38
|
+
const depth = pid === rootPid ? 1 : depthMap[ppid]
|
|
39
|
+
if (!depth) {
|
|
40
|
+
continue
|
|
41
|
+
}
|
|
42
|
+
result.push({
|
|
43
|
+
...parsedLine,
|
|
44
|
+
depth,
|
|
45
|
+
name: ListProcessGetName.getName(pid, cmd, rootPid, pidMap),
|
|
46
|
+
})
|
|
47
|
+
depthMap[pid] = depth + 1
|
|
48
|
+
}
|
|
49
|
+
return result
|
|
50
|
+
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process'
|
|
2
|
+
import * as GetElectronRebuildPath from '../GetElectronRebuildPath/GetElectronRebuildPath.js'
|
|
2
3
|
import * as IsElectron from '../IsElectron/IsElectron.js'
|
|
3
4
|
import * as Path from '../Path/Path.js'
|
|
4
5
|
import * as Root from '../Root/Root.js'
|
|
5
6
|
import { VError } from '../VError/VError.js'
|
|
6
7
|
|
|
7
|
-
const getElectronRebuildPath = () => {
|
|
8
|
-
return Path.join(Root.root, 'packages', 'main-process', 'node_modules', '.bin', 'electron-rebuild')
|
|
9
|
-
}
|
|
10
|
-
|
|
11
8
|
const getPtyHostPath = () => {
|
|
12
9
|
return Path.join(Root.root, 'packages', 'pty-host')
|
|
13
10
|
}
|
|
@@ -16,7 +13,7 @@ const getPtyHostPath = () => {
|
|
|
16
13
|
* @param {string} cwd
|
|
17
14
|
*/
|
|
18
15
|
const rebuildNodePtyElectron = async (cwd) => {
|
|
19
|
-
const electronRebuildPath = getElectronRebuildPath()
|
|
16
|
+
const electronRebuildPath = GetElectronRebuildPath.getElectronRebuildPath()
|
|
20
17
|
const childProcess = spawn(electronRebuildPath, [], {
|
|
21
18
|
cwd,
|
|
22
19
|
stdio: 'inherit',
|
|
@@ -34,14 +31,18 @@ const rebuildNodePtyNode = async (cwd) => {
|
|
|
34
31
|
})
|
|
35
32
|
}
|
|
36
33
|
|
|
34
|
+
const getFn = () => {
|
|
35
|
+
if (IsElectron.isElectron()) {
|
|
36
|
+
return rebuildNodePtyElectron
|
|
37
|
+
}
|
|
38
|
+
return rebuildNodePtyNode
|
|
39
|
+
}
|
|
40
|
+
|
|
37
41
|
export const rebuildNodePty = async () => {
|
|
38
42
|
try {
|
|
39
43
|
const ptyHostPath = getPtyHostPath()
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
} else {
|
|
43
|
-
await rebuildNodePtyNode(ptyHostPath)
|
|
44
|
-
}
|
|
44
|
+
const rebuild = getFn()
|
|
45
|
+
await rebuild(ptyHostPath)
|
|
45
46
|
} catch (error) {
|
|
46
47
|
throw new VError(error, `Failed to rebuild node-pty`)
|
|
47
48
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as Character from '../Character/Character.js'
|
|
2
|
+
import * as GetErrorConstructor from '../GetErrorConstructor/GetErrorConstructor.js'
|
|
3
|
+
import * as JoinLines from '../JoinLines/JoinLines.js'
|
|
4
|
+
import { JsonRpcError } from '../JsonRpcError/JsonRpcError.js'
|
|
5
|
+
import * as JsonRpcErrorCode from '../JsonRpcErrorCode/JsonRpcErrorCode.js'
|
|
6
|
+
import * as SplitLines from '../SplitLines/SplitLines.js'
|
|
7
|
+
|
|
8
|
+
const constructError = (message, type, name) => {
|
|
9
|
+
const ErrorConstructor = GetErrorConstructor.getErrorConstructor(message, type)
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
if (ErrorConstructor === DOMException && name) {
|
|
12
|
+
return new ErrorConstructor(message, name)
|
|
13
|
+
}
|
|
14
|
+
if (ErrorConstructor === Error) {
|
|
15
|
+
const error = new Error(message)
|
|
16
|
+
if (name && name !== 'VError') {
|
|
17
|
+
error.name = name
|
|
18
|
+
}
|
|
19
|
+
return error
|
|
20
|
+
}
|
|
21
|
+
return new ErrorConstructor(message)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const recreateStack = (message, stack) => {
|
|
25
|
+
if (message && !stack.includes(message)) {
|
|
26
|
+
return message + Character.NewLine + stack
|
|
27
|
+
}
|
|
28
|
+
return stack
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const getErrorType = (error) => {
|
|
32
|
+
if (error && error.type) {
|
|
33
|
+
return error.type
|
|
34
|
+
}
|
|
35
|
+
if (error && error.data && error.data.type) {
|
|
36
|
+
return error.data.type
|
|
37
|
+
}
|
|
38
|
+
return ''
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export const restoreJsonRpcError = (error) => {
|
|
42
|
+
if (error && error instanceof Error) {
|
|
43
|
+
return error
|
|
44
|
+
}
|
|
45
|
+
if (error && error.code && error.code === JsonRpcErrorCode.MethodNotFound) {
|
|
46
|
+
const restoredError = new JsonRpcError(error.message)
|
|
47
|
+
restoredError.stack = error.stack || error.data || ''
|
|
48
|
+
return restoredError
|
|
49
|
+
}
|
|
50
|
+
if (error && error.message) {
|
|
51
|
+
const type = getErrorType(error)
|
|
52
|
+
const restoredError = constructError(error.message, type, error.name)
|
|
53
|
+
const currentStack = JoinLines.joinLines(SplitLines.splitLines(new Error().stack).slice(1))
|
|
54
|
+
if (error.data) {
|
|
55
|
+
if (error.data.stack && type && error.message) {
|
|
56
|
+
restoredError.stack = type + ': ' + error.message + Character.NewLine + error.data.stack + Character.NewLine + currentStack
|
|
57
|
+
} else if (error.data.stack) {
|
|
58
|
+
restoredError.stack = recreateStack(error.message, error.data.stack) + Character.NewLine + currentStack
|
|
59
|
+
}
|
|
60
|
+
if (error.data.codeFrame) {
|
|
61
|
+
// @ts-ignore
|
|
62
|
+
restoredError.codeFrame = error.data.codeFrame
|
|
63
|
+
}
|
|
64
|
+
if (error.data.code) {
|
|
65
|
+
// @ts-ignore
|
|
66
|
+
restoredError.code = error.data.code
|
|
67
|
+
}
|
|
68
|
+
} else if (error.stack) {
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
restoredError.stack = recreateStack(error.message, error.stack) + Character.NewLine + currentStack
|
|
71
|
+
}
|
|
72
|
+
return restoredError
|
|
73
|
+
}
|
|
74
|
+
if (typeof error === 'string') {
|
|
75
|
+
return new Error(`JsonRpc Error: ${error}`)
|
|
76
|
+
}
|
|
77
|
+
console.log({ error })
|
|
78
|
+
return new Error(`JsonRpc Error: Unknown Error`)
|
|
79
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { JsonRpcError } from '../JsonRpcError/JsonRpcError.js'
|
|
2
|
+
import * as RestoreJsonRpcError from '../RestoreJsonRpcError/RestoreJsonRpcError.js'
|
|
3
|
+
|
|
4
|
+
export const unwrapJsonRpcResult = (responseMessage) => {
|
|
5
|
+
if ('error' in responseMessage) {
|
|
6
|
+
const restoredError = RestoreJsonRpcError.restoreJsonRpcError(responseMessage.error)
|
|
7
|
+
throw restoredError
|
|
8
|
+
}
|
|
9
|
+
if ('result' in responseMessage) {
|
|
10
|
+
return responseMessage.result
|
|
11
|
+
}
|
|
12
|
+
throw new JsonRpcError('unexpected response message')
|
|
13
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as LoadWindowsProcessTree from '../LoadWindowsProcessTree/LoadWindowsProcessTree.js'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {number} rootPid
|
|
6
|
+
* @param {WindowsProcessTree.ProcessDataFlag} flags
|
|
7
|
+
* @returns {Promise<WindowsProcessTree.IProcessInfo[] | undefined>}
|
|
8
|
+
*/
|
|
9
|
+
export const getProcessList = async (rootPid, flags) => {
|
|
10
|
+
const WindowsProcessTree = await LoadWindowsProcessTree.loadWindowProcessTree()
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
WindowsProcessTree.getProcessList(rootPid, resolve, flags)
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
*
|
|
18
|
+
* @param {WindowsProcessTree.IProcessInfo[]} processList
|
|
19
|
+
* @returns Promise< WindowsProcessTree.IProcessCpuInfo[]>
|
|
20
|
+
*/
|
|
21
|
+
export const addCpuUsage = async (processList) => {
|
|
22
|
+
const WindowsProcessTree = await LoadWindowsProcessTree.loadWindowProcessTree()
|
|
23
|
+
return new Promise((resolve) => {
|
|
24
|
+
WindowsProcessTree.getProcessCpuUsage(processList, resolve)
|
|
25
|
+
})
|
|
26
|
+
}
|