import { Meteor } from 'meteor/meteor'; import { DDP } from 'meteor/ddp'; import { mongodbConnectionManager } from './mongodbConnectionManager'; import { mongodbDriverManager } from './mongodbDriverManager'; /** * Meteor MongoDB Integration * * This module integrates the MongoDB driver manager with Meteor's * built-in MongoDB connection system to provide automatic driver * selection and version detection. * * Features: * - Hooks into Meteor's MongoDB connection process * - Automatic driver selection based on detected version * - Fallback mechanism for connection failures * - Integration with Meteor's DDP and reactive systems */ class MeteorMongoIntegration { constructor() { this.originalMongoConnect = null; this.originalMongoCollection = null; this.isInitialized = false; this.connectionString = null; this.customConnection = null; } /** * Initialize the integration * @param {string} connectionString - MongoDB connection string */ initialize(connectionString) { if (this.isInitialized) { console.log('Meteor MongoDB Integration already initialized'); return; } this.connectionString = connectionString; console.log('Initializing Meteor MongoDB Integration...'); // Store original methods this.originalMongoConnect = Meteor.connect; this.originalMongoCollection = Mongo.Collection; // Override Meteor's connection method this.overrideMeteorConnection(); // Override Mongo.Collection to use our connection manager this.overrideMongoCollection(); this.isInitialized = true; // Meteor MongoDB Integration initialized successfully (status available in Admin Panel) } /** * Override Meteor's connection method */ overrideMeteorConnection() { const self = this; // Override Meteor.connect if it exists if (typeof Meteor.connect === 'function') { Meteor.connect = async function(url, options) { try { console.log('Meteor.connect called, using custom MongoDB connection manager'); return await self.createCustomConnection(url, options); } catch (error) { console.error('Custom connection failed, falling back to original method:', error.message); return self.originalMongoConnect.call(this, url, options); } }; } } /** * Override Mongo.Collection to use our connection manager */ overrideMongoCollection() { const self = this; const originalCollection = Mongo.Collection; // Override Mongo.Collection constructor Mongo.Collection = function(name, options = {}) { // If we have a custom connection, use it if (self.customConnection) { options.connection = self.customConnection; } // Create the collection with original constructor const collection = new originalCollection(name, options); // Add our custom methods self.enhanceCollection(collection); return collection; }; // Copy static methods from original constructor Object.setPrototypeOf(Mongo.Collection, originalCollection); Object.assign(Mongo.Collection, originalCollection); } /** * Create a custom MongoDB connection * @param {string} url - MongoDB connection URL * @param {Object} options - Connection options * @returns {Promise} - MongoDB connection object */ async createCustomConnection(url, options = {}) { try { console.log('Creating custom MongoDB connection...'); // Use our connection manager const connection = await mongodbConnectionManager.createConnection(url, options); // Store the custom connection this.customConnection = connection; // Create a Meteor-compatible connection object const meteorConnection = this.createMeteorCompatibleConnection(connection); console.log('Custom MongoDB connection created successfully'); return meteorConnection; } catch (error) { console.error('Failed to create custom MongoDB connection:', error.message); throw error; } } /** * Create a Meteor-compatible connection object * @param {Object} connection - MongoDB connection object * @returns {Object} - Meteor-compatible connection */ createMeteorCompatibleConnection(connection) { const self = this; return { // Basic connection properties _driver: connection, _name: 'custom-mongodb-connection', // Collection creation method createCollection: function(name, options = {}) { const db = connection.db(); return db.collection(name); }, // Database access db: function(name = 'meteor') { return connection.db(name); }, // Connection status status: function() { return { status: 'connected', connected: true, retryCount: 0 }; }, // Close connection close: async function() { try { await connection.close(); self.customConnection = null; console.log('Meteor-compatible connection closed'); } catch (error) { console.error('Error closing Meteor-compatible connection:', error.message); } }, // Raw connection access rawConnection: connection }; } /** * Enhance a collection with additional methods * @param {Object} collection - Mongo.Collection instance */ enhanceCollection(collection) { const self = this; // Add connection info method collection.getConnectionInfo = function() { if (self.customConnection) { const stats = mongodbConnectionManager.getConnectionStats(); const driverStats = mongodbDriverManager.getConnectionStats(); return { connectionType: 'custom', driver: driverStats.currentDriver, version: driverStats.detectedVersion, connectionStats: stats, driverStats: driverStats }; } return { connectionType: 'default', driver: 'meteor-default', version: 'unknown' }; }; // Add version detection method collection.detectMongoDBVersion = async function() { try { if (self.customConnection) { const admin = self.customConnection.db().admin(); const buildInfo = await admin.buildInfo(); return buildInfo.version; } return null; } catch (error) { console.error('Error detecting MongoDB version:', error.message); return null; } }; } /** * Get connection statistics * @returns {Object} - Connection statistics */ getStats() { return { isInitialized: this.isInitialized, hasCustomConnection: !!this.customConnection, connectionString: this.connectionString, connectionStats: mongodbConnectionManager.getConnectionStats(), driverStats: mongodbDriverManager.getConnectionStats() }; } /** * Reset the integration */ reset() { if (this.originalMongoConnect) { Meteor.connect = this.originalMongoConnect; } if (this.originalMongoCollection) { Mongo.Collection = this.originalMongoCollection; } this.isInitialized = false; this.connectionString = null; this.customConnection = null; mongodbConnectionManager.reset(); mongodbDriverManager.reset(); console.log('Meteor MongoDB Integration reset'); } /** * Test the connection * @returns {Promise} - Test results */ async testConnection() { try { if (!this.customConnection) { throw new Error('No custom connection available'); } const db = this.customConnection.db(); const result = await db.admin().ping(); return { success: true, result, driver: mongodbDriverManager.selectedDriver, version: mongodbDriverManager.detectedVersion }; } catch (error) { return { success: false, error: error.message, driver: mongodbDriverManager.selectedDriver, version: mongodbDriverManager.detectedVersion }; } } } // Create singleton instance const meteorMongoIntegration = new MeteorMongoIntegration(); // Export for use in other modules export { meteorMongoIntegration, MeteorMongoIntegration }; // Auto-initialize if MONGO_URL is available if (Meteor.isServer && process.env.MONGO_URL) { // Auto-initializing Meteor MongoDB Integration with MONGO_URL (status available in Admin Panel) meteorMongoIntegration.initialize(process.env.MONGO_URL); } // Meteor MongoDB Integration module loaded (status available in Admin Panel)