mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 23:40:13 +01:00
Add support for MongoDB 3-8, detecting which one is in use.
Thanks to xet7 !
This commit is contained in:
parent
1f5a549589
commit
74ccfea570
11 changed files with 1650 additions and 7 deletions
306
models/lib/meteorMongoIntegration.js
Normal file
306
models/lib/meteorMongoIntegration.js
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
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;
|
||||
console.log('Meteor MongoDB Integration initialized successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<Object>} - 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<Object>} - 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) {
|
||||
console.log('Auto-initializing Meteor MongoDB Integration with MONGO_URL');
|
||||
meteorMongoIntegration.initialize(process.env.MONGO_URL);
|
||||
}
|
||||
|
||||
// Log initialization
|
||||
if (Meteor.isServer) {
|
||||
console.log('Meteor MongoDB Integration module loaded');
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue