mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-12-19 13:10:16 +08:00
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.
123 lines
4.1 KiB
TypeScript
123 lines
4.1 KiB
TypeScript
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);
|
||
}
|
||
});
|
||
}
|