UNPKG

ms-analysis-reports-mcp-server

Version:

PMS analysis reports server handling maintenance reports, equipment analysis, compliance tracking, and performance metrics with ERP access for data extraction

231 lines 8.19 kB
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; import { MongoClient } from 'mongodb'; import { logger } from '../index.js'; // ============================================================================ // 🔧 DOMAIN-SPECIFIC CONFIGURATION - CUSTOMIZE FOR NEW MCP SERVERS // ============================================================================ /** * Companies that should skip validation entirely * CUSTOMIZE: Add your development/test company names here */ const SKIP_VALIDATION_COMPANIES = ['synergy', 'development', 'test']; /** * Database collection and field names for your authorization system * CUSTOMIZE: Change these to match your database schema */ const IMO_COLLECTION_NAME = 'common_group_details'; const IMO_FIELD_NAME = 'imoList'; const COMPANY_FIELD_NAME = 'groupName'; const DATABASE_NAME = 'syia-etl-dev'; /** * Cache file configuration * CUSTOMIZE: Change cache file name if needed */ const CACHE_FILENAME = 'company-imos.json'; // ============================================================================ // END CUSTOMIZABLE SECTION // ============================================================================ // File path setup const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const DATA_DIR = join(__dirname, '../../data'); const CACHE_FILE = join(DATA_DIR, CACHE_FILENAME); // In-memory storage let companyImoCache = null; // MongoDB connection options for better performance const MONGO_OPTIONS = { maxPoolSize: 1, minPoolSize: 0, maxIdleTimeMS: 30000, serverSelectionTimeoutMS: 10000, connectTimeoutMS: 10000, }; /** * Ensure data directory exists */ function ensureDataDirectory() { if (!existsSync(DATA_DIR)) { mkdirSync(DATA_DIR, { recursive: true }); logger.debug('Created data directory for IMO cache'); } } /** * Fetch IMO numbers for a company from MongoDB */ async function fetchCompanyImoNumbers(companyName) { let client = null; try { logger.info(`Fetching IMO numbers for company: ${companyName}`); if (!process.env.MONGODB_ETL_DEV_DATA_URI) { throw new Error('MONGODB_ETL_DEV_DATA_URI environment variable is required'); } // Create optimized MongoDB client client = new MongoClient(process.env.MONGODB_ETL_DEV_DATA_URI, MONGO_OPTIONS); await client.connect(); const db = client.db(DATABASE_NAME); const collection = db.collection(IMO_COLLECTION_NAME); // Query with timeout for reliability const result = await collection.findOne({ [COMPANY_FIELD_NAME]: companyName }, { projection: { imoList: 1, _id: 0 }, maxTimeMS: 10000 // 10 second timeout }); if (!result?.[IMO_FIELD_NAME] || !Array.isArray(result[IMO_FIELD_NAME])) { logger.warn(`No IMO numbers found for company: ${companyName}`); return []; } // Convert and validate IMO numbers const imoNumbers = result[IMO_FIELD_NAME] .filter(imo => typeof imo === 'number' && imo > 0) .map(imo => imo.toString()); logger.info(`Found ${imoNumbers.length} valid IMO numbers for company: ${companyName}`); // Update in-memory cache companyImoCache = { companyName, imoNumbers, lastUpdated: new Date().toISOString() }; return imoNumbers; } catch (error) { logger.error(`Error fetching IMO numbers for company ${companyName}:`, error); throw error; } finally { // Always close connection if (client) { try { await client.close(); } catch (closeError) { logger.warn('Error closing MongoDB connection:', closeError); } } } } /** * Get cached company IMO numbers from memory */ function getCompanyImoNumbers() { return companyImoCache?.imoNumbers || []; } /** * Load cached IMO numbers from file */ export function loadCachedImos() { try { if (!existsSync(CACHE_FILE)) { logger.debug('IMO cache file does not exist'); return []; } const data = readFileSync(CACHE_FILE, 'utf8'); const cacheData = JSON.parse(data); // Validate cache structure if (!cacheData?.imoNumbers || !Array.isArray(cacheData.imoNumbers)) { logger.warn('Invalid cache file structure, ignoring cached data'); return []; } // Update in-memory cache if valid companyImoCache = cacheData; logger.debug(`Loaded ${cacheData.imoNumbers.length} IMO numbers from cache file`); return cacheData.imoNumbers; } catch (error) { logger.warn('Failed to load cached IMOs, cache file may be corrupted:', error); return []; } } /** * Save IMO numbers to cache file */ export function saveCachedImos(imos, companyName) { try { ensureDataDirectory(); const cacheData = { companyName, imoNumbers: imos, lastUpdated: new Date().toISOString() }; writeFileSync(CACHE_FILE, JSON.stringify(cacheData, null, 2), 'utf8'); logger.info(`Successfully cached ${imos.length} IMO numbers to file`); } catch (error) { logger.error('Failed to save IMO cache to file:', error); } } /** * Check if company should skip IMO validation (e.g., for development/testing) */ export function shouldSkipImoValidation(companyName) { return SKIP_VALIDATION_COMPANIES.includes(companyName.toLowerCase()); } /** * Initialize IMO cache for the specified company */ export async function initializeImoCache(companyName) { try { logger.info(`Initializing IMO cache for company: "${companyName}"`); // Skip IMO initialization for special companies if (shouldSkipImoValidation(companyName)) { logger.info(`Skipping IMO cache initialization for company: "${companyName}" (no IMO validation required)`); clearCache(); // Clear any existing cache return; } // Clear existing cache to ensure fresh start clearCache(); // Fetch fresh data from MongoDB const imos = await fetchCompanyImoNumbers(companyName); if (imos.length > 0) { // Save to file cache for persistence saveCachedImos(imos, companyName); logger.info(`Successfully initialized IMO cache with ${imos.length} numbers for: "${companyName}"`); } else { logger.warn(`No IMO numbers found for company: "${companyName}". Cache remains empty.`); } } catch (error) { logger.error(`Failed to initialize IMO cache for company "${companyName}":`, error); // Try to load from file cache as fallback const cachedImos = loadCachedImos(); if (cachedImos.length > 0) { logger.info(`Using cached IMO data as fallback (${cachedImos.length} IMOs)`); } } } /** * Get company IMOs with intelligent fallback strategy */ export function getCompanyImosWithFallback() { // Try in-memory cache first (fastest) let imos = getCompanyImoNumbers(); // Fallback to file cache if memory is empty if (imos.length === 0) { imos = loadCachedImos(); if (imos.length > 0) { logger.info(`Using cached IMO numbers from file (${imos.length} IMOs)`); } } return imos; } /** * Get cache status for monitoring/debugging */ export function getCacheStatus() { return { inMemory: companyImoCache !== null, inMemoryCount: companyImoCache?.imoNumbers?.length || 0, fileExists: existsSync(CACHE_FILE), lastUpdated: companyImoCache?.lastUpdated, companyName: companyImoCache?.companyName }; } /** * Clear all cached data (for testing/reset purposes) */ export function clearCache() { companyImoCache = null; logger.debug('Cleared in-memory IMO cache'); } //# sourceMappingURL=imoCache.js.map