Skip to content

Commit 91ebf9a

Browse files
committed
1.0.3打包测试
1 parent 62a5f94 commit 91ebf9a

2 files changed

Lines changed: 184 additions & 51 deletions

File tree

src/win/conpty_console_list.cc

Lines changed: 146 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,129 @@
11
/**
22
* Copyright (c) 2019, Microsoft Corporation (MIT License).
33
*/
4-
5-
#define NODE_ADDON_API_DISABLE_DEPRECATED
4+
#include <iostream>
65
#include <napi.h>
7-
#include <windows.h>
6+
#include <ostream>
7+
8+
#ifdef _WIN32
9+
// Windows 平台
10+
#define NODE_ADDON_API_DISABLE_DEPRECATED
11+
#include <windows.h>
12+
#include <tlhelp32.h>
13+
#include <stdio.h>
14+
void ListChildProcesses(DWORD pid,std::vector<DWORD> &children_clist) {
15+
PROCESSENTRY32 pe32;
16+
HANDLE hProcessSnap;
17+
// 设置 PROCESSENTRY32 结构体的大小
18+
pe32.dwSize = sizeof(PROCESSENTRY32);
19+
// 创建进程快照
20+
hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
21+
if (hProcessSnap == INVALID_HANDLE_VALUE) {
22+
return;
23+
}
24+
// 遍历所有进程
25+
if (Process32First(hProcessSnap, &pe32)) {
26+
do {
27+
// 如果该进程的父进程 ID (PPID) 是指定的 PID,则认为它是子进程
28+
if (pe32.th32ParentProcessID == pid) {
29+
children_clist.push_back(pe32.th32ProcessID);
30+
}
31+
} while (Process32Next(hProcessSnap, &pe32)); // 继续遍历下一个进程
32+
}
33+
// 关闭快照句柄
34+
CloseHandle(hProcessSnap);
35+
}
36+
#elif defined(__linux__)
37+
#include <vector>
38+
#include <dirent.h>
39+
#include <fstream>
40+
#include <sstream>
41+
#include <string>
42+
#include <iostream>
43+
// Linux 平台
44+
void ListChildProcesses(pid_t pid, std::vector<pid_t>& children_clist) {
45+
DIR* dir = opendir("/proc");
46+
if (dir == nullptr) {
47+
std::cerr << "Failed to open /proc directory" << std::endl;
48+
return;
49+
}
50+
struct dirent* entry;
51+
while ((entry = readdir(dir)) != nullptr) {
52+
// 跳过非数字目录
53+
if (!isdigit(entry->d_name[0])) {
54+
continue;
55+
}
56+
pid_t current_pid = std::stoi(entry->d_name); // 当前进程 PID
57+
// 打开该进程的 stat 文件,获取父进程 PID (PPID)
58+
std::string stat_path = std::string("/proc/") + entry->d_name + "/stat";
59+
std::ifstream stat_file(stat_path);
60+
if (stat_file.is_open()) {
61+
std::string line;
62+
std::getline(stat_file, line);
63+
std::istringstream ss(line);
64+
65+
pid_t ppid;
66+
ss >> current_pid; // 当前进程 PID
67+
ss.ignore(256, ' '); // 跳过进程名称部分
68+
ss >> ppid; // 获取父进程 PID
69+
if (ppid == pid) {
70+
// 如果父进程 PID 匹配,则将当前进程的 PID 添加到子进程列表
71+
children_clist.push_back(current_pid);
72+
}
73+
}
74+
}
75+
closedir(dir); // 关闭 /proc 目录
76+
}
77+
#elif defined(__APPLE__) && defined(__MACH__)
78+
// macOS 平台
79+
#include <iostream>
80+
#include <vector>
81+
#include <sys/types.h>
82+
#include <dirent.h>
83+
#include <unistd.h>
84+
#include <sys/proc_info.h>
85+
#include <sys/sysctl.h>
86+
#include <cstring>
87+
// 获取进程的父进程 PID
88+
pid_t GetParentPid(pid_t pid) {
89+
struct proc_bsdinfo info;
90+
size_t len = sizeof(info);
91+
int ret = proc_pidinfo(pid, PROC_PIDTBSDINFO, 0, &info, len);
92+
93+
if (ret < 0) {
94+
std::cerr << "Failed to get parent PID for " << pid << std::endl;
95+
return -1;
96+
}
97+
98+
return info.pbi_ppid; // 返回父进程 PID
99+
}
100+
101+
// 获取指定进程的所有子进程
102+
void ListChildProcesses(pid_t pid, std::vector<pid_t>& children_clist) {
103+
DIR* dir = opendir("/proc");
104+
if (dir == nullptr) {
105+
std::cerr << "Failed to open /proc directory" << std::endl;
106+
return;
107+
}
108+
struct dirent* entry;
109+
while ((entry = readdir(dir)) != nullptr) {
110+
// 跳过非数字目录
111+
if (!isdigit(entry->d_name[0])) {
112+
continue;
113+
}
114+
pid_t current_pid = std::stoi(entry->d_name); // 当前进程 PID
115+
// 获取当前进程的父进程 PID
116+
pid_t ppid = GetParentPid(current_pid);
117+
if (ppid == pid) {
118+
// 如果父进程 PID 匹配,则将当前进程的 PID 添加到子进程列表
119+
children_clist.push_back(current_pid);
120+
}
121+
}
122+
closedir(dir); // 关闭 /proc 目录
123+
}
124+
#else
125+
// 不支持的平台
126+
#endif
8127

9128
static Napi::Promise ApiConsoleProcessList(const Napi::CallbackInfo& info) {
10129
Napi::Env env(info.Env());
@@ -16,32 +135,30 @@ static Napi::Promise ApiConsoleProcessList(const Napi::CallbackInfo& info) {
16135
const DWORD pid = info[0].As<Napi::Number>().Uint32Value();
17136
// 创建一个 Promise 对象
18137
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
19-
if (!FreeConsole()) {
20-
deferred.Reject(Napi::String::New(deferred.Env(),"FreeConsole failed"));
21-
}
22-
if (!AttachConsole(pid)) { // todo 这都是操当前的,不太行
23-
deferred.Reject(Napi::String::New(deferred.Env(),"AttachConsole failed"));
24-
}
25-
std::thread([pid,deferred]() mutable {
26-
// 执行耗时任务
27-
try {
28-
29-
30-
auto processList = std::vector<DWORD>(64);
31-
auto processCount = GetConsoleProcessList(&processList[0], static_cast<DWORD>(processList.size()));
32-
if (processList.size() < processCount) {
33-
processList.resize(processCount);
34-
processCount = GetConsoleProcessList(&processList[0], static_cast<DWORD>(processList.size()));
35-
}
36-
FreeConsole();
37-
Napi::Array result = Napi::Array::New(deferred.Env());
38-
for (DWORD i = 0; i < processCount; i++) {
39-
result.Set(i, Napi::Number::New(deferred.Env(), processList[i]));
40-
}
41-
deferred.Resolve(result);
42-
} catch (const std::exception& e) {
43-
deferred.Reject(Napi::String::New(deferred.Env(), e.what()));
44-
}
138+
// 创建一个线程安全的函数,用于在主线程上执行
139+
Napi::ThreadSafeFunction tsfn = Napi::ThreadSafeFunction::New(
140+
env,
141+
Napi::Function::New(env, [deferred](const Napi::CallbackInfo& info) {
142+
auto list = info[0].As<Napi::Array>();
143+
deferred.Resolve(list);
144+
// return Napi::Object::New(info.Env());
145+
}),
146+
"ThreadSafeFunction",
147+
0, // no maximum queue size
148+
1 // only one worker thread
149+
);
150+
std::thread([pid,tsfn]() {
151+
auto processList = std::vector<DWORD>(0);
152+
ListChildProcesses(pid,processList);
153+
tsfn.BlockingCall([processList](Napi::Env env, Napi::Function jsCallback)
154+
{
155+
Napi::Array result = Napi::Array::New(env);
156+
for (DWORD i = 0; i < processList.size(); i++) {
157+
result.Set(i, Napi::Number::New(env, processList[i]));
158+
}
159+
jsCallback.Call({result});
160+
});
161+
tsfn.Release();
45162
}).detach(); // 分离线程,这样线程会在后台运行
46163
return deferred.Promise();
47164
}

src/windowsPtyAgent.ts

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
import * as fs from 'fs';
88
import * as os from 'os';
99
import * as path from 'path';
10-
import { Socket } from 'net';
11-
import { ArgvOrCommandLine } from './types';
12-
import { fork } from 'child_process';
13-
import { ConoutConnection } from './windowsConoutConnection';
10+
import {Socket} from 'net';
11+
import {ArgvOrCommandLine} from './types';
12+
import {fork} from 'child_process';
13+
import {ConoutConnection} from './windowsConoutConnection';
1414

1515
let conptyNative: IConptyNative;
1616
let winptyNative: IWinptyNative;
@@ -23,6 +23,7 @@ let winptyNative: IWinptyNative;
2323
const FLUSH_DATA_INTERVAL = 1000;
2424
// eslint-disable-next-line @typescript-eslint/naming-convention
2525
const __non_webpack_require__ = require;
26+
2627
/**
2728
* This agent sits between the WindowsTerminal class and provides a common interface for both conpty
2829
* and winpty.
@@ -40,11 +41,25 @@ export class WindowsPtyAgent {
4041
private _pty: number;
4142
private _ptyNative: IConptyNative | IWinptyNative;
4243

43-
public get inSocket(): Socket { return this._inSocket; }
44-
public get outSocket(): Socket { return this._outSocket; }
45-
public get fd(): any { return this._fd; }
46-
public get innerPid(): number { return this._innerPid; }
47-
public get pty(): number { return this._pty; }
44+
public get inSocket(): Socket {
45+
return this._inSocket;
46+
}
47+
48+
public get outSocket(): Socket {
49+
return this._outSocket;
50+
}
51+
52+
public get fd(): any {
53+
return this._fd;
54+
}
55+
56+
public get innerPid(): number {
57+
return this._innerPid;
58+
}
59+
60+
public get pty(): number {
61+
return this._pty;
62+
}
4863

4964
constructor(
5065
file: string,
@@ -102,9 +117,9 @@ export class WindowsPtyAgent {
102117
// Open pty session.
103118
let term: IConptyProcess | IWinptyProcess;
104119
if (this._useConpty) {
105-
term = (this._ptyNative as IConptyNative).startProcess(file, cols, rows, debug, this._generatePipeName(), conptyInheritCursor, this._useConptyDll,exePath);
120+
term = (this._ptyNative as IConptyNative).startProcess(file, cols, rows, debug, this._generatePipeName(), conptyInheritCursor, this._useConptyDll, exePath);
106121
} else {
107-
term = (this._ptyNative as IWinptyNative).startProcess(file, commandLine, env, cwd, cols, rows, debug,exePath);
122+
term = (this._ptyNative as IWinptyNative).startProcess(file, commandLine, env, cwd, cols, rows, debug, exePath);
108123
this._pid = (term as IWinptyProcess).pid;
109124
this._innerPid = (term as IWinptyProcess).innerPid;
110125
}
@@ -142,20 +157,20 @@ export class WindowsPtyAgent {
142157
}
143158
}
144159

145-
public resize(cols: number, rows: number,exePath: string = ''): void {
160+
public resize(cols: number, rows: number, exePath: string = ''): void {
146161
if (this._useConpty) {
147162
if (this._exitCode !== undefined) {
148163
throw new Error('Cannot resize a pty that has already exited');
149164
}
150-
(this._ptyNative as IConptyNative).resize(this._pty, cols, rows, this._useConptyDll,exePath);
165+
(this._ptyNative as IConptyNative).resize(this._pty, cols, rows, this._useConptyDll, exePath);
151166
return;
152167
}
153168
(this._ptyNative as IWinptyNative).resize(this._pid, cols, rows);
154169
}
155170

156171
public clear(exePath: string = ''): void {
157172
if (this._useConpty) {
158-
(this._ptyNative as IConptyNative).clear(this._pty, this._useConptyDll,exePath);
173+
(this._ptyNative as IConptyNative).clear(this._pty, this._useConptyDll, exePath);
159174
}
160175
}
161176

@@ -172,7 +187,7 @@ export class WindowsPtyAgent {
172187
// Ignore if process cannot be found (kill ESRCH error)
173188
}
174189
});
175-
(this._ptyNative as IConptyNative).kill(this._pty, this._useConptyDll,exePath);
190+
(this._ptyNative as IConptyNative).kill(this._pty, this._useConptyDll, exePath);
176191
});
177192
} else {
178193
// Because pty.kill closes the handle, it will kill most processes by itself.
@@ -195,6 +210,7 @@ export class WindowsPtyAgent {
195210
}
196211

197212
getConsoleProcessList: any;
213+
198214
private _getConsoleProcessList(): Promise<number[]> {
199215
try {
200216
if (!this.getConsoleProcessList) {
@@ -209,15 +225,15 @@ export class WindowsPtyAgent {
209225
// clearTimeout(timeout);
210226
// resolve(message.consoleProcessList);
211227
// });
212-
this.getConsoleProcessList(this._innerPid).then((consoleProcessList: number[] | PromiseLike<number[]> | undefined) => {
228+
this.getConsoleProcessList(this._innerPid).then((consoleProcessList: number[]) => {
213229
clearTimeout(timeout);
214-
resolve(consoleProcessList);
230+
resolve([this.innerPid, ...(consoleProcessList ?? [])]);
215231
}).catch((error: any) => {
216-
console.error('Error:', error); // 如果发生错误,会打印出来
217-
resolve([ this._innerPid ]);
232+
console.error('Error:', error); // 如果发生错误
233+
resolve([this._innerPid]);
218234
});
219235
const timeout = setTimeout(() => {
220-
resolve([ this._innerPid ]);
236+
resolve([this._innerPid]);
221237
}, 5000);
222238
});
223239
}
@@ -290,9 +306,9 @@ export function argsToCommandLine(file: string, args: ArgvOrCommandLine): string
290306
const quote =
291307
arg === '' ||
292308
(arg.indexOf(' ') !== -1 ||
293-
arg.indexOf('\t') !== -1) &&
309+
arg.indexOf('\t') !== -1) &&
294310
((arg.length > 1) &&
295-
(hasLopsidedEnclosingQuote || hasNoEnclosingQuotes));
311+
(hasLopsidedEnclosingQuote || hasNoEnclosingQuotes));
296312
if (quote) {
297313
result += '\"';
298314
}

0 commit comments

Comments
 (0)