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); } }); }