NapCatQQ/packages/napcat-shell/pipe.ts
手瓜一十雪 ad4a108781 feat: 大规模去耦合
Moved various helper, event, and utility files from napcat-common to napcat-core/helper for better modularity and separation of concerns. Updated imports across packages to reflect new file locations. Removed unused dependencies from napcat-common and added them to napcat-core where needed. Also consolidated type definitions and cleaned up tsconfig settings for improved compatibility.
2025-11-15 13:36:33 +08:00

123 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { LogWrapper } from 'napcat-core/helper/log';
import * as net from 'net';
import * as process from 'process';
import { Writable } from 'stream';
/**
* 连接到命名管道并重定向stdout
* @param logger 日志记录器
* @param timeoutMs 连接超时时间(毫秒)默认5000ms
* @returns Promise连接成功时resolve失败时reject
*/
export function connectToNamedPipe (logger: LogWrapper, timeoutMs: number = 5000): Promise<{ disconnect: () => void }> {
return new Promise((resolve, reject) => {
if (process.platform !== 'win32') {
// 非Windows平台不reject而是返回一个空的disconnect函数
return resolve({ disconnect: () => { } });
}
const pid = process.pid;
const pipePath = `\\\\.\\pipe\\NapCat_${pid}`;
// 设置连接超时
const timeoutId = setTimeout(() => {
reject(new Error(`连接命名管道超时: ${pipePath}`));
}, timeoutMs);
try {
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
const pipeSocket = net.connect(pipePath, () => {
// 清除超时
clearTimeout(timeoutId);
// 优化网络性能设置
pipeSocket.setNoDelay(true); // 减少延迟
// 设置更高的高水位线,允许更多数据缓冲
logger.log(`[StdOut] 已重定向到命名管道: ${pipePath}`);
// 创建拥有更优雅背压处理的 Writable 流
const pipeWritable = new Writable({
highWaterMark: 1024 * 64, // 64KB 高水位线
write (chunk, encoding, callback) {
if (!pipeSocket.writable) {
// 如果管道不可写退回到原始stdout
logger.log('[StdOut] 管道不可写,回退到控制台输出');
return originalStdoutWrite(chunk, encoding, callback);
}
// 尝试写入数据到管道
const canContinue = pipeSocket.write(chunk, encoding, () => {
// 数据已被发送或放入内部缓冲区
});
if (canContinue) {
// 如果返回true表示可以继续写入更多数据
// 立即通知写入流可以继续
process.nextTick(callback);
} else {
// 如果返回false表示内部缓冲区已满
// 等待drain事件再恢复写入
pipeSocket.once('drain', () => {
callback();
});
}
// 明确返回true表示写入已处理
return true;
},
});
// 重定向stdout
process.stdout.write = (
chunk: any,
encoding?: BufferEncoding | (() => void),
cb?: () => void
): boolean => {
if (typeof encoding === 'function') {
cb = encoding;
encoding = undefined;
}
// 使用优化的writable流处理写入
return pipeWritable.write(chunk, encoding as BufferEncoding, cb as () => void);
};
// 提供断开连接的方法
const disconnect = () => {
process.stdout.write = originalStdoutWrite;
pipeSocket.end();
logger.log(`已手动断开命名管道连接: ${pipePath}`);
};
// 返回成功和断开连接的方法
resolve({ disconnect });
});
// 管道错误处理
pipeSocket.on('error', (err) => {
clearTimeout(timeoutId);
process.stdout.write = originalStdoutWrite;
logger.log(`连接命名管道 ${pipePath} 时出错:`, err);
reject(err);
});
// 管道关闭处理
pipeSocket.on('end', () => {
process.stdout.write = originalStdoutWrite;
logger.log('命名管道连接已关闭');
});
// 确保在连接意外关闭时恢复stdout
pipeSocket.on('close', () => {
process.stdout.write = originalStdoutWrite;
logger.log('命名管道连接已关闭');
});
} catch (error) {
clearTimeout(timeoutId);
logger.log(`尝试连接命名管道 ${pipePath} 时发生异常:`, error);
reject(error);
}
});
}