@yinzhouzhi/mcp-filesystem-server
Version:
本地文件系统操作服务器 - 基于STDIO通信的MCP服务,支持文件和目录操作
450 lines (380 loc) • 13.1 kB
JavaScript
/**
* 监控器数量管理池
* 用于管理系统中所有文件和目录监控器数量,防止资源泄漏
*/
const path = require('path');
const logger = require('./logging');
const config = require('../config/defaults');
// 监控器池配置
const MONITOR_POOL = {
// 监控器集合
watchers: new Map(), // 所有活跃的监控器
pathToId: new Map(), // 路径到ID的映射
// 监控器限制
maxWatchers: config.watchPool?.maxWatchers || 200, // 最大监控器数量
maxPerPath: config.watchPool?.maxPerPath || 5, // 每个路径最大监控器数量
maxPerProcess: config.watchPool?.maxPerProcess || 50, // 每个进程最大监控器数量
// 监控器使用统计
stats: {
created: 0, // 创建的总数
closed: 0, // 关闭的总数
rejected: 0, // 被拒绝的请求数
activeCount: 0, // 当前活跃数量
processMap: new Map(), // 进程ID到监控数量的映射
},
// 过期清理
cleanupInterval: config.watchPool?.cleanupInterval || 3600000, // 默认1小时检查一次
maxIdleTime: config.watchPool?.maxIdleTime || 7200000, // 默认最大闲置时间2小时
cleanupTimer: null, // 清理定时器引用
};
/**
* 初始化监控器池
*/
function initMonitorPool() {
logger.info('初始化文件监控管理池');
// 设置定期清理任务
MONITOR_POOL.cleanupTimer = setInterval(() => {
cleanupIdleWatchers();
}, MONITOR_POOL.cleanupInterval);
// 防止定时器引用导致进程无法退出
MONITOR_POOL.cleanupTimer.unref();
// 进程退出时清理资源
process.on('exit', () => {
logger.info(`进程退出,关闭所有监控器: ${MONITOR_POOL.watchers.size}个`);
closeAllWatchers();
});
// 异常退出时也清理资源
process.on('SIGINT', () => {
logger.info('接收到SIGINT信号,关闭所有监控器');
closeAllWatchers();
process.exit();
});
process.on('SIGTERM', () => {
logger.info('接收到SIGTERM信号,关闭所有监控器');
closeAllWatchers();
process.exit();
});
process.on('uncaughtException', (error) => {
logger.error('未捕获的异常,关闭所有监控器', { error });
closeAllWatchers();
process.exit(1);
});
}
/**
* 添加监控器到池中
* @param {string} targetPath 监控路径
* @param {object} watcher 监控器实例
* @param {object} options 监控选项
* @param {string} type 监控类型 (file|directory)
* @param {string} processId 请求进程ID
* @returns {object} 监控器信息对象或null
*/
function addWatcher(targetPath, watcher, options, type, processId = 'main') {
// 验证参数
if (!targetPath || !watcher) {
logger.error('添加监控器失败: 参数无效');
return null;
}
// 标准化路径
targetPath = path.normalize(targetPath);
// 检查是否超过系统总监控数量限制
if (MONITOR_POOL.watchers.size >= MONITOR_POOL.maxWatchers) {
logger.warn(`监控器数量已达上限 (${MONITOR_POOL.maxWatchers}),拒绝新监控请求`);
MONITOR_POOL.stats.rejected++;
// 尝试关闭最早创建的监控器为新监控腾出空间
removeOldestWatcher();
}
// 检查当前路径的监控器数量
let pathWatcherCount = 0;
if (MONITOR_POOL.pathToId.has(targetPath)) {
pathWatcherCount = MONITOR_POOL.pathToId.get(targetPath).size;
}
if (pathWatcherCount >= MONITOR_POOL.maxPerPath) {
logger.warn(`路径 ${targetPath} 的监控器数量已达上限 (${MONITOR_POOL.maxPerPath}),拒绝新监控请求`);
MONITOR_POOL.stats.rejected++;
return null;
}
// 检查进程的监控器数量
let processWatcherCount = MONITOR_POOL.stats.processMap.get(processId) || 0;
if (processWatcherCount >= MONITOR_POOL.maxPerProcess) {
logger.warn(`进程 ${processId} 的监控器数量已达上限 (${MONITOR_POOL.maxPerProcess}),拒绝新监控请求`);
MONITOR_POOL.stats.rejected++;
return null;
}
// 生成唯一ID
const watcherId = generateWatcherId();
// 记录监控器信息
const watcherInfo = {
id: watcherId,
path: targetPath,
instance: watcher,
options,
type,
processId,
createdAt: Date.now(),
lastUsedAt: Date.now(),
useCount: 0
};
// 添加到集合
MONITOR_POOL.watchers.set(watcherId, watcherInfo);
// 更新路径到ID的映射
if (!MONITOR_POOL.pathToId.has(targetPath)) {
MONITOR_POOL.pathToId.set(targetPath, new Set());
}
MONITOR_POOL.pathToId.get(targetPath).add(watcherId);
// 更新进程监控计数
MONITOR_POOL.stats.processMap.set(processId, processWatcherCount + 1);
// 更新统计信息
MONITOR_POOL.stats.created++;
MONITOR_POOL.stats.activeCount = MONITOR_POOL.watchers.size;
logger.info(`监控器已添加: ${targetPath} (${type}), ID: ${watcherId}, 进程: ${processId}`);
return watcherInfo;
}
/**
* 从池中移除监控器
* @param {string} watcherId 监控器ID
* @returns {boolean} 是否成功移除
*/
function removeWatcher(watcherId) {
if (!MONITOR_POOL.watchers.has(watcherId)) {
logger.warn(`尝试移除不存在的监控器: ${watcherId}`);
return false;
}
const watcherInfo = MONITOR_POOL.watchers.get(watcherId);
try {
// 关闭监控器
if (watcherInfo.instance && typeof watcherInfo.instance.close === 'function') {
watcherInfo.instance.close();
}
// 更新路径到ID的映射
if (MONITOR_POOL.pathToId.has(watcherInfo.path)) {
MONITOR_POOL.pathToId.get(watcherInfo.path).delete(watcherId);
if (MONITOR_POOL.pathToId.get(watcherInfo.path).size === 0) {
MONITOR_POOL.pathToId.delete(watcherInfo.path);
}
}
// 更新进程监控计数
const processId = watcherInfo.processId;
const processCount = MONITOR_POOL.stats.processMap.get(processId) || 0;
if (processCount > 1) {
MONITOR_POOL.stats.processMap.set(processId, processCount - 1);
} else {
MONITOR_POOL.stats.processMap.delete(processId);
}
// 从集合移除
MONITOR_POOL.watchers.delete(watcherId);
// 更新统计
MONITOR_POOL.stats.closed++;
MONITOR_POOL.stats.activeCount = MONITOR_POOL.watchers.size;
logger.info(`监控器已移除: ${watcherInfo.path}, ID: ${watcherId}`);
return true;
} catch (error) {
logger.error(`移除监控器失败: ${watcherId}`, { error });
return false;
}
}
/**
* 根据路径查找监控器
* @param {string} targetPath 监控路径
* @param {string} type 监控类型 (file|directory),可选
* @returns {Array} 匹配的监控器信息数组
*/
function findWatchersByPath(targetPath, type = null) {
const results = [];
// 标准化路径
targetPath = path.normalize(targetPath);
// 检查路径到ID的映射
if (MONITOR_POOL.pathToId.has(targetPath)) {
for (const watcherId of MONITOR_POOL.pathToId.get(targetPath)) {
const watcherInfo = MONITOR_POOL.watchers.get(watcherId);
// 如果指定了类型,则进行过滤
if (type && watcherInfo.type !== type) {
continue;
}
results.push(watcherInfo);
}
}
return results;
}
/**
* 使用监控器(更新最后使用时间)
* @param {string} watcherId 监控器ID
*/
function useWatcher(watcherId) {
if (MONITOR_POOL.watchers.has(watcherId)) {
const watcherInfo = MONITOR_POOL.watchers.get(watcherId);
watcherInfo.lastUsedAt = Date.now();
watcherInfo.useCount++;
}
}
/**
* 清理长时间未使用的监控器
*/
function cleanupIdleWatchers() {
const now = Date.now();
const idleThreshold = now - MONITOR_POOL.maxIdleTime;
let cleanupCount = 0;
// 找出所有超过闲置时间的监控器
const idleWatchers = [];
for (const [watcherId, info] of MONITOR_POOL.watchers.entries()) {
if (info.lastUsedAt < idleThreshold) {
idleWatchers.push(watcherId);
}
}
// 关闭闲置监控器
for (const watcherId of idleWatchers) {
const removed = removeWatcher(watcherId);
if (removed) {
cleanupCount++;
}
}
if (cleanupCount > 0) {
logger.info(`定期清理: 已关闭 ${cleanupCount} 个闲置监控器`);
}
return cleanupCount;
}
/**
* 移除最早创建的监控器
*/
function removeOldestWatcher() {
if (MONITOR_POOL.watchers.size === 0) {
return false;
}
let oldestTime = Date.now();
let oldestId = null;
// 查找最早创建的监控器
for (const [watcherId, info] of MONITOR_POOL.watchers.entries()) {
if (info.createdAt < oldestTime) {
oldestTime = info.createdAt;
oldestId = watcherId;
}
}
if (oldestId) {
const oldestInfo = MONITOR_POOL.watchers.get(oldestId);
logger.info(`资源回收: 移除最早创建的监控器 (${oldestInfo.path}), 创建时间: ${new Date(oldestTime).toISOString()}`);
return removeWatcher(oldestId);
}
return false;
}
/**
* 关闭所有监控器
*/
function closeAllWatchers() {
let closedCount = 0;
for (const watcherId of MONITOR_POOL.watchers.keys()) {
const removed = removeWatcher(watcherId);
if (removed) {
closedCount++;
}
}
logger.info(`已关闭所有监控器: ${closedCount}个`);
// 重置其他集合和统计
MONITOR_POOL.pathToId.clear();
MONITOR_POOL.stats.processMap.clear();
MONITOR_POOL.stats.activeCount = 0;
// 清除清理定时器
if (MONITOR_POOL.cleanupTimer) {
clearInterval(MONITOR_POOL.cleanupTimer);
MONITOR_POOL.cleanupTimer = null;
}
return closedCount;
}
/**
* 生成唯一的监控器ID
* @returns {string} 监控器ID
*/
function generateWatcherId() {
const timestamp = Date.now();
const random = Math.floor(Math.random() * 10000);
return `watcher_${timestamp}_${random}`;
}
/**
* 获取监控器池状态
* @returns {object} 监控器池状态信息
*/
function getPoolStatus() {
return {
activeWatchers: MONITOR_POOL.watchers.size,
maxWatchers: MONITOR_POOL.maxWatchers,
maxPerPath: MONITOR_POOL.maxPerPath,
maxPerProcess: MONITOR_POOL.maxPerProcess,
stats: {
created: MONITOR_POOL.stats.created,
closed: MONITOR_POOL.stats.closed,
rejected: MONITOR_POOL.stats.rejected,
activeCount: MONITOR_POOL.stats.activeCount,
processCount: MONITOR_POOL.stats.processMap.size,
uniquePathsCount: MONITOR_POOL.pathToId.size
},
cleanupSettings: {
cleanupInterval: MONITOR_POOL.cleanupInterval,
maxIdleTime: MONITOR_POOL.maxIdleTime
}
};
}
/**
* 设置监控器池配置
* @param {object} options 配置选项
*/
function setPoolConfig(options) {
if (!options) return;
// 更新配置
if (typeof options.maxWatchers === 'number' && options.maxWatchers > 0) {
MONITOR_POOL.maxWatchers = options.maxWatchers;
}
if (typeof options.maxPerPath === 'number' && options.maxPerPath > 0) {
MONITOR_POOL.maxPerPath = options.maxPerPath;
}
if (typeof options.maxPerProcess === 'number' && options.maxPerProcess > 0) {
MONITOR_POOL.maxPerProcess = options.maxPerProcess;
}
if (typeof options.cleanupInterval === 'number' && options.cleanupInterval > 0) {
// 更新清理间隔
MONITOR_POOL.cleanupInterval = options.cleanupInterval;
// 重置清理定时器
if (MONITOR_POOL.cleanupTimer) {
clearInterval(MONITOR_POOL.cleanupTimer);
MONITOR_POOL.cleanupTimer = setInterval(() => {
cleanupIdleWatchers();
}, MONITOR_POOL.cleanupInterval);
MONITOR_POOL.cleanupTimer.unref();
}
}
if (typeof options.maxIdleTime === 'number' && options.maxIdleTime > 0) {
MONITOR_POOL.maxIdleTime = options.maxIdleTime;
}
logger.info('已更新监控器池配置', { newConfig: getPoolStatus() });
}
/**
* 获取所有监控器
* @returns {Array} 所有活跃的监控器信息数组
*/
function getAllWatchers() {
const watchers = [];
for (const [id, watcherInfo] of MONITOR_POOL.watchers.entries()) {
watchers.push({
id: id,
path: watcherInfo.path,
type: watcherInfo.type,
instance: watcherInfo.instance,
processId: watcherInfo.processId,
createdAt: watcherInfo.createdAt,
lastUsedAt: watcherInfo.lastUsedAt,
useCount: watcherInfo.useCount
});
}
return watchers;
}
// 导出监控器池模块
module.exports = {
initMonitorPool,
addWatcher,
removeWatcher,
findWatchersByPath,
useWatcher,
cleanupIdleWatchers,
closeAllWatchers,
getPoolStatus,
setPoolConfig,
getAllWatchers
};