NapCatQQ/packages/napcat-shell/process-api.ts
手瓜一十雪 7216755430 Refactor process management and improve shutdown logic
Removed excessive logging and streamlined process restart and shutdown flows in napcat.ts. Added isShuttingDown flag to prevent unintended worker restarts during shutdown. Improved forceKillProcess to handle Windows-specific process termination. Updated IWorkerProcess interface and implementations to include the 'off' event method for better event management.
2026-01-18 12:10:14 +08:00

191 lines
4.9 KiB
TypeScript

import type { Readable } from 'stream';
import type { fork as forkType } from 'child_process';
// 扩展 Process 类型以支持 parentPort
declare global {
namespace NodeJS {
interface Process {
parentPort?: {
on (event: 'message', listener: (e: { data: unknown; }) => void): void;
postMessage (message: unknown): void;
};
}
}
}
/**
* 统一的进程接口
*/
export interface IWorkerProcess {
readonly pid: number | undefined;
readonly stdout: Readable | null;
readonly stderr: Readable | null;
postMessage (message: unknown): void;
kill (): boolean;
on (event: string, listener: (...args: unknown[]) => void): void;
once (event: string, listener: (...args: unknown[]) => void): void;
off (event: string, listener: (...args: unknown[]) => void): void;
}
/**
* 进程创建选项
*/
export interface ProcessOptions {
env: NodeJS.ProcessEnv;
stdio: 'pipe' | 'ignore' | 'inherit' | Array<'pipe' | 'ignore' | 'inherit' | 'ipc'>;
}
/**
* 进程管理器接口
*/
export interface IProcessManager {
createWorker (modulePath: string, args: string[], options: ProcessOptions): IWorkerProcess;
onParentMessage (handler: (message: unknown) => void): void;
sendToParent (message: unknown): boolean;
}
/**
* Electron utilityProcess 包装器
*/
class ElectronProcessManager implements IProcessManager {
private utilityProcess: {
fork (modulePath: string, args: string[], options: unknown): unknown;
};
constructor (utilityProcess: { fork (modulePath: string, args: string[], options: unknown): unknown; }) {
this.utilityProcess = utilityProcess;
}
createWorker (modulePath: string, args: string[], options: ProcessOptions): IWorkerProcess {
const child: any = this.utilityProcess.fork(modulePath, args, options);
return {
get pid () { return child.pid as number | undefined; },
stdout: child.stdout as Readable | null,
stderr: child.stderr as Readable | null,
postMessage (message: unknown): void {
child.postMessage(message);
},
kill (): boolean {
return child.kill() as boolean;
},
on (event: string, listener: (...args: unknown[]) => void): void {
child.on(event, listener);
},
once (event: string, listener: (...args: unknown[]) => void): void {
child.once(event, listener);
},
off (event: string, listener: (...args: unknown[]) => void): void {
child.off(event, listener);
},
};
}
onParentMessage (handler: (message: unknown) => void): void {
if (process.parentPort) {
process.parentPort.on('message', (e: { data: unknown; }) => {
handler(e.data);
});
}
}
sendToParent (message: unknown): boolean {
if (process.parentPort) {
process.parentPort.postMessage(message);
return true;
}
return false;
}
}
/**
* Node.js child_process 包装器
*/
class NodeProcessManager implements IProcessManager {
private forkFn: typeof forkType;
constructor (forkFn: typeof forkType) {
this.forkFn = forkFn;
}
createWorker (modulePath: string, args: string[], options: ProcessOptions): IWorkerProcess {
const child = this.forkFn(modulePath, args, options as any);
return {
get pid () { return child.pid; },
stdout: child.stdout,
stderr: child.stderr,
postMessage (message: unknown): void {
if (child.send) {
child.send(message as any);
}
},
kill (): boolean {
return child.kill();
},
on (event: string, listener: (...args: unknown[]) => void): void {
child.on(event, listener);
},
once (event: string, listener: (...args: unknown[]) => void): void {
child.once(event, listener);
},
off (event: string, listener: (...args: unknown[]) => void): void {
child.off(event, listener);
},
};
}
onParentMessage (handler: (message: unknown) => void): void {
process.on('message', (message: unknown) => {
handler(message);
});
}
sendToParent (message: unknown): boolean {
if (process.send) {
process.send(message as any);
return true;
}
return false;
}
}
/**
* 检测运行环境并创建对应的进程管理器
*/
export async function createProcessManager (): Promise<{
manager: IProcessManager;
isElectron: boolean;
}> {
const isElectron = typeof process.versions['electron'] !== 'undefined';
if (isElectron) {
// @ts-ignore - electron 运行时存在但类型声明可能缺失
const electron = await import('electron');
if (electron.app && !electron.app.isReady()) {
await electron.app.whenReady();
}
return {
manager: new ElectronProcessManager(electron.utilityProcess),
isElectron: true,
};
} else {
const { fork } = await import('child_process');
return {
manager: new NodeProcessManager(fork),
isElectron: false,
};
}
}