-
Notifications
You must be signed in to change notification settings - Fork 835
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
v1ll4n
committed
Jan 13, 2022
1 parent
33e8c5f
commit 3de1155
Showing
2 changed files
with
165 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
'use strict'; | ||
const util = require('util'); | ||
const path = require('path'); | ||
const childProcess = require('child_process'); | ||
|
||
const TEN_MEGABYTES = 1000 * 1000 * 10; | ||
const execFile = util.promisify(childProcess.execFile); | ||
|
||
const windows = async () => { | ||
// Source: https://github.com/MarkTiedemann/fastlist | ||
let bin; | ||
switch (process.arch) { | ||
case 'x64': | ||
bin = 'fastlist-0.3.0-x64.exe'; | ||
break; | ||
case 'ia32': | ||
bin = 'fastlist-0.3.0-x86.exe'; | ||
break; | ||
default: | ||
throw new Error(`Unsupported architecture: ${process.arch}`); | ||
} | ||
|
||
const binPath = path.join(__dirname, 'vendor', bin); | ||
const {stdout} = await execFile(binPath, { | ||
maxBuffer: TEN_MEGABYTES, | ||
windowsHide: true | ||
}); | ||
|
||
return stdout | ||
.trim() | ||
.split('\r\n') | ||
.map(line => line.split('\t')) | ||
.map(([pid, ppid, name]) => ({ | ||
pid: Number.parseInt(pid, 10), | ||
ppid: Number.parseInt(ppid, 10), | ||
name | ||
})); | ||
}; | ||
|
||
const nonWindowsMultipleCalls = async (options = {}) => { | ||
const flags = (options.all === false ? '' : 'a') + 'wwxo'; | ||
const ret = {}; | ||
|
||
await Promise.all(['comm', 'args', 'ppid', 'uid', '%cpu', '%mem'].map(async cmd => { | ||
const {stdout} = await execFile('ps', [flags, `pid,${cmd}`], {maxBuffer: TEN_MEGABYTES}); | ||
|
||
for (let line of stdout.trim().split('\n').slice(1)) { | ||
line = line.trim(); | ||
const [pid] = line.split(' ', 1); | ||
const val = line.slice(pid.length + 1).trim(); | ||
|
||
if (ret[pid] === undefined) { | ||
ret[pid] = {}; | ||
} | ||
|
||
ret[pid][cmd] = val; | ||
} | ||
})); | ||
|
||
// Filter out inconsistencies as there might be race | ||
// issues due to differences in `ps` between the spawns | ||
return Object.entries(ret) | ||
.filter(([, value]) => value.comm && value.args && value.ppid && value.uid && value['%cpu'] && value['%mem']) | ||
.map(([key, value]) => ({ | ||
pid: Number.parseInt(key, 10), | ||
name: path.basename(value.comm), | ||
cmd: value.args, | ||
ppid: Number.parseInt(value.ppid, 10), | ||
uid: Number.parseInt(value.uid, 10), | ||
cpu: Number.parseFloat(value['%cpu']), | ||
memory: Number.parseFloat(value['%mem']) | ||
})); | ||
}; | ||
|
||
const ERROR_MESSAGE_PARSING_FAILED = 'ps output parsing failed'; | ||
|
||
const psFields = 'pid,ppid,uid,%cpu,%mem,comm,args'; | ||
|
||
// TODO: Use named capture groups when targeting Node.js 10 | ||
const psOutputRegex = /^[ \t]*(?<pid>\d+)[ \t]+(?<ppid>\d+)[ \t]+(?<uid>\d+)[ \t]+(?<cpu>\d+\.\d+)[ \t]+(?<memory>\d+\.\d+)[ \t]+/; | ||
|
||
const nonWindowsSingleCall = async (options = {}) => { | ||
const flags = options.all === false ? 'wwxo' : 'awwxo'; | ||
|
||
// TODO: Use the promise version of `execFile` when https://github.com/nodejs/node/issues/28244 is fixed. | ||
const [psPid, stdout] = await new Promise((resolve, reject) => { | ||
const child = childProcess.execFile('ps', [flags, psFields], {maxBuffer: TEN_MEGABYTES}, (error, stdout) => { | ||
if (error === null) { | ||
resolve([child.pid, stdout]); | ||
} else { | ||
reject(error); | ||
} | ||
}); | ||
}); | ||
|
||
const lines = stdout.trim().split('\n'); | ||
lines.shift(); | ||
|
||
let psIndex; | ||
let commPosition; | ||
let argsPosition; | ||
|
||
const processes = lines.map((line, index) => { | ||
const match = psOutputRegex.exec(line); | ||
if (match === null) { | ||
throw new Error(ERROR_MESSAGE_PARSING_FAILED); | ||
} | ||
|
||
const {pid, ppid, uid, cpu, memory} = match.groups; | ||
|
||
const processInfo = { | ||
pid: Number.parseInt(pid, 10), | ||
ppid: Number.parseInt(ppid, 10), | ||
uid: Number.parseInt(uid, 10), | ||
cpu: Number.parseFloat(cpu), | ||
memory: Number.parseFloat(memory), | ||
name: undefined, | ||
cmd: undefined | ||
}; | ||
|
||
if (processInfo.pid === psPid) { | ||
psIndex = index; | ||
commPosition = line.indexOf('ps', match[0].length); | ||
argsPosition = line.indexOf('ps', commPosition + 2); | ||
} | ||
|
||
return processInfo; | ||
}); | ||
|
||
if (psIndex === undefined || commPosition === -1 || argsPosition === -1) { | ||
throw new Error(ERROR_MESSAGE_PARSING_FAILED); | ||
} | ||
|
||
const commLength = argsPosition - commPosition; | ||
for (const [index, line] of lines.entries()) { | ||
processes[index].name = line.slice(commPosition, commPosition + commLength).trim(); | ||
processes[index].cmd = line.slice(argsPosition).trim(); | ||
} | ||
|
||
processes.splice(psIndex, 1); | ||
return processes; | ||
}; | ||
|
||
const nonWindows = async (options = {}) => { | ||
try { | ||
return await nonWindowsSingleCall(options); | ||
} catch (_) { // If the error is not a parsing error, it should manifest itself in multicall version too. | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
console.info("111111111111111111111111111111111") | ||
return nonWindowsMultipleCalls(options); | ||
} | ||
}; | ||
|
||
module.exports = process.platform === 'win32' ? windows : nonWindows; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters