mongodbDriverManager.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. import { Meteor } from 'meteor/meteor';
  2. /**
  3. * MongoDB Driver Manager
  4. *
  5. * This module provides automatic MongoDB version detection and driver selection
  6. * to support MongoDB versions 3.0 through 8.0 with compatible Node.js drivers.
  7. *
  8. * Features:
  9. * - Automatic MongoDB version detection from wire protocol errors
  10. * - Dynamic driver selection based on detected version
  11. * - Fallback mechanism for unsupported versions
  12. * - Connection retry with different drivers
  13. */
  14. // MongoDB driver compatibility matrix
  15. const DRIVER_COMPATIBILITY = {
  16. '3.0': { driver: 'mongodb3legacy', version: '3.7.4', minServer: '3.0', maxServer: '3.6' },
  17. '3.2': { driver: 'mongodb3legacy', version: '3.7.4', minServer: '3.0', maxServer: '3.6' },
  18. '3.4': { driver: 'mongodb3legacy', version: '3.7.4', minServer: '3.0', maxServer: '3.6' },
  19. '3.6': { driver: 'mongodb3legacy', version: '3.7.4', minServer: '3.0', maxServer: '3.6' },
  20. '4.0': { driver: 'mongodb4legacy', version: '4.17.2', minServer: '4.0', maxServer: '4.4' },
  21. '4.2': { driver: 'mongodb4legacy', version: '4.17.2', minServer: '4.0', maxServer: '4.4' },
  22. '4.4': { driver: 'mongodb4legacy', version: '4.17.2', minServer: '4.0', maxServer: '4.4' },
  23. '5.0': { driver: 'mongodb5legacy', version: '5.9.2', minServer: '5.0', maxServer: '5.0' },
  24. '6.0': { driver: 'mongodb6legacy', version: '6.3.0', minServer: '6.0', maxServer: '6.0' },
  25. '7.0': { driver: 'mongodb7legacy', version: '7.0.1', minServer: '7.0', maxServer: '7.0' },
  26. '8.0': { driver: 'mongodb8legacy', version: '6.9.0', minServer: '8.0', maxServer: '8.0' }
  27. };
  28. // Wire protocol error patterns for version detection
  29. const VERSION_ERROR_PATTERNS = {
  30. // MongoDB 3.x wire protocol errors
  31. '3.0': [
  32. /unsupported wire protocol version/i,
  33. /wire protocol version 0/i,
  34. /protocol version 0/i
  35. ],
  36. '3.2': [
  37. /wire protocol version 1/i,
  38. /protocol version 1/i
  39. ],
  40. '3.4': [
  41. /wire protocol version 2/i,
  42. /protocol version 2/i
  43. ],
  44. '3.6': [
  45. /wire protocol version 3/i,
  46. /protocol version 3/i
  47. ],
  48. // MongoDB 4.x wire protocol errors
  49. '4.0': [
  50. /wire protocol version 4/i,
  51. /protocol version 4/i
  52. ],
  53. '4.2': [
  54. /wire protocol version 5/i,
  55. /protocol version 5/i
  56. ],
  57. '4.4': [
  58. /wire protocol version 6/i,
  59. /protocol version 6/i
  60. ],
  61. // MongoDB 5.x wire protocol errors
  62. '5.0': [
  63. /wire protocol version 7/i,
  64. /protocol version 7/i
  65. ],
  66. // MongoDB 6.x wire protocol errors
  67. '6.0': [
  68. /wire protocol version 8/i,
  69. /protocol version 8/i
  70. ],
  71. // MongoDB 7.x wire protocol errors
  72. '7.0': [
  73. /wire protocol version 9/i,
  74. /protocol version 9/i
  75. ],
  76. // MongoDB 8.x wire protocol errors
  77. '8.0': [
  78. /wire protocol version 10/i,
  79. /protocol version 10/i
  80. ]
  81. };
  82. // Generic error patterns that might indicate version incompatibility
  83. const GENERIC_VERSION_ERRORS = [
  84. /unsupported wire protocol/i,
  85. /wire protocol version/i,
  86. /protocol version/i,
  87. /unsupported server version/i,
  88. /server version/i,
  89. /incompatible wire protocol/i,
  90. /wire protocol mismatch/i
  91. ];
  92. class MongoDBDriverManager {
  93. constructor() {
  94. this.detectedVersion = null;
  95. this.selectedDriver = null;
  96. this.connectionAttempts = [];
  97. this.fallbackDrivers = ['mongodb6legacy', 'mongodb4legacy', 'mongodb3legacy'];
  98. }
  99. /**
  100. * Detect MongoDB version from wire protocol errors
  101. * @param {Error} error - The connection error
  102. * @returns {string|null} - Detected MongoDB version or null
  103. */
  104. detectVersionFromError(error) {
  105. if (!error || !error.message) {
  106. return null;
  107. }
  108. const errorMessage = error.message.toLowerCase();
  109. // Check specific version patterns
  110. for (const [version, patterns] of Object.entries(VERSION_ERROR_PATTERNS)) {
  111. for (const pattern of patterns) {
  112. if (pattern.test(errorMessage)) {
  113. console.log(`MongoDB version detected from error: ${version}`);
  114. return version;
  115. }
  116. }
  117. }
  118. // Check for generic version errors
  119. for (const pattern of GENERIC_VERSION_ERRORS) {
  120. if (pattern.test(errorMessage)) {
  121. console.log('Generic MongoDB version error detected, will try fallback drivers');
  122. return 'unknown';
  123. }
  124. }
  125. return null;
  126. }
  127. /**
  128. * Get the appropriate driver for a MongoDB version
  129. * @param {string} version - MongoDB version
  130. * @returns {string} - Driver package name
  131. */
  132. getDriverForVersion(version) {
  133. if (DRIVER_COMPATIBILITY[version]) {
  134. return DRIVER_COMPATIBILITY[version].driver;
  135. }
  136. // Fallback logic for unknown versions
  137. if (version === 'unknown') {
  138. return this.fallbackDrivers[0]; // Start with most recent fallback
  139. }
  140. // Try to determine from version string
  141. const majorVersion = version.split('.')[0];
  142. if (majorVersion === '3') {
  143. return 'mongodb3legacy';
  144. } else if (majorVersion === '4') {
  145. return 'mongodb4legacy';
  146. } else if (majorVersion === '5') {
  147. return 'mongodb5legacy';
  148. } else if (majorVersion === '6') {
  149. return 'mongodb6legacy';
  150. } else if (majorVersion === '7') {
  151. return 'mongodb7legacy';
  152. } else if (majorVersion === '8') {
  153. return 'mongodb8legacy';
  154. }
  155. return this.fallbackDrivers[0];
  156. }
  157. /**
  158. * Get the next fallback driver
  159. * @returns {string|null} - Next fallback driver or null if none left
  160. */
  161. getNextFallbackDriver() {
  162. const currentIndex = this.fallbackDrivers.indexOf(this.selectedDriver);
  163. if (currentIndex >= 0 && currentIndex < this.fallbackDrivers.length - 1) {
  164. return this.fallbackDrivers[currentIndex + 1];
  165. }
  166. return null;
  167. }
  168. /**
  169. * Record a connection attempt
  170. * @param {string} driver - Driver used
  171. * @param {string} version - MongoDB version attempted
  172. * @param {boolean} success - Whether connection was successful
  173. * @param {Error} error - Error if connection failed
  174. */
  175. recordConnectionAttempt(driver, version, success, error = null) {
  176. this.connectionAttempts.push({
  177. driver,
  178. version,
  179. success,
  180. error: error ? error.message : null,
  181. timestamp: new Date()
  182. });
  183. if (success) {
  184. this.selectedDriver = driver;
  185. this.detectedVersion = version;
  186. console.log(`Successfully connected using ${driver} for MongoDB ${version}`);
  187. }
  188. }
  189. /**
  190. * Get connection statistics
  191. * @returns {Object} - Connection statistics
  192. */
  193. getConnectionStats() {
  194. const total = this.connectionAttempts.length;
  195. const successful = this.connectionAttempts.filter(attempt => attempt.success).length;
  196. const failed = total - successful;
  197. return {
  198. total,
  199. successful,
  200. failed,
  201. currentDriver: this.selectedDriver,
  202. detectedVersion: this.detectedVersion,
  203. attempts: this.connectionAttempts
  204. };
  205. }
  206. /**
  207. * Reset connection state
  208. */
  209. reset() {
  210. this.detectedVersion = null;
  211. this.selectedDriver = null;
  212. this.connectionAttempts = [];
  213. }
  214. /**
  215. * Get driver information
  216. * @param {string} driver - Driver package name
  217. * @returns {Object} - Driver information
  218. */
  219. getDriverInfo(driver) {
  220. for (const [version, info] of Object.entries(DRIVER_COMPATIBILITY)) {
  221. if (info.driver === driver) {
  222. return { version, ...info };
  223. }
  224. }
  225. return null;
  226. }
  227. /**
  228. * Get all supported MongoDB versions
  229. * @returns {Array} - Array of supported versions
  230. */
  231. getSupportedVersions() {
  232. return Object.keys(DRIVER_COMPATIBILITY);
  233. }
  234. /**
  235. * Check if a MongoDB version is supported
  236. * @param {string} version - MongoDB version to check
  237. * @returns {boolean} - Whether version is supported
  238. */
  239. isVersionSupported(version) {
  240. return version in DRIVER_COMPATIBILITY;
  241. }
  242. }
  243. // Create singleton instance
  244. const mongodbDriverManager = new MongoDBDriverManager();
  245. // Export for use in other modules
  246. export { mongodbDriverManager, MongoDBDriverManager };
  247. // MongoDB Driver Manager initialized (status available in Admin Panel)