@ufdevsllc/authme2.0
Version:
SDK for license management and remote monitoring with automatic system tracking, license validation, and remote control capabilities
299 lines (269 loc) • 10.6 kB
JavaScript
import mongoose from 'mongoose';
class DatabaseManager {
constructor(errorHandler = null) {
this.monitoringConnection = null;
this.isConnected = false;
this.connectionString = process.env.MONGODB_URI || 'mongodb+srv://incrypto09:VcFzmdvSgSbqHx5m@transcoding.jcngo.mongodb.net/?retryWrites=true&w=majority&appName=transcoding';
this.databaseName = process.env.MONGODB_DB_NAME || 'authme20';
this.maxRetries = 5;
this.retryDelay = 1000; // Start with 1 second
this.errorHandler = errorHandler;
}
/**
* Initialize connection to monitoring database
* @returns {Promise<void>}
*/
async initMonitoringConnection() {
if (this.isConnected && this.monitoringConnection) {
return;
}
let retries = 0;
while (retries < this.maxRetries) {
try {
// Create a new connection for monitoring database
this.monitoringConnection = mongoose.createConnection(this.connectionString, {
dbName: this.databaseName,
maxPoolSize: 10,
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
bufferCommands: false
});
// Wait for connection to be established
await new Promise((resolve, reject) => {
this.monitoringConnection.once('open', resolve);
this.monitoringConnection.once('error', reject);
});
this.isConnected = true;
// Set up connection event handlers
this.setupConnectionHandlers();
if (this.errorHandler) {
await this.errorHandler.logInfo('Successfully connected to monitoring database', {
component: 'database-manager',
operation: 'init-connection',
database: this.databaseName
});
} else {
console.log('Successfully connected to monitoring database');
}
return;
} catch (error) {
retries++;
if (this.errorHandler) {
await this.errorHandler.handleDatabaseError(error, {
type: 'connection',
database: this.databaseName
}, retries);
} else {
console.error(`Database connection attempt ${retries} failed:`, error.message);
}
if (retries >= this.maxRetries) {
throw new Error(`Failed to connect to monitoring database after ${this.maxRetries} attempts: ${error.message}`);
}
// Exponential backoff
const delay = this.retryDelay * Math.pow(2, retries - 1);
if (this.errorHandler) {
await this.errorHandler.logWarn(`Retrying connection in ${delay}ms...`, {
component: 'database-manager',
operation: 'retry-connection',
attempt: retries,
delay
});
} else {
console.log(`Retrying connection in ${delay}ms...`);
}
await this.sleep(delay);
}
}
}
/**
* Set up connection event handlers for monitoring and reconnection
*/
setupConnectionHandlers() {
if (!this.monitoringConnection) return;
this.monitoringConnection.on('error', async (error) => {
if (this.errorHandler) {
await this.errorHandler.handleDatabaseError(error, {
type: 'connection-error',
database: this.databaseName
});
} else {
console.error('Monitoring database connection error:', error);
}
this.isConnected = false;
});
this.monitoringConnection.on('disconnected', async () => {
if (this.errorHandler) {
await this.errorHandler.logWarn('Monitoring database disconnected', {
component: 'database-manager',
operation: 'connection-lost',
database: this.databaseName
});
} else {
console.warn('Monitoring database disconnected');
}
this.isConnected = false;
// Attempt to reconnect
this.handleReconnection();
});
this.monitoringConnection.on('reconnected', async () => {
if (this.errorHandler) {
await this.errorHandler.logInfo('Monitoring database reconnected', {
component: 'database-manager',
operation: 'reconnection-success',
database: this.databaseName
});
} else {
console.log('Monitoring database reconnected');
}
this.isConnected = true;
});
}
/**
* Handle reconnection logic
*/
async handleReconnection() {
if (this.isConnected) return;
try {
await this.initMonitoringConnection();
} catch (error) {
if (this.errorHandler) {
await this.errorHandler.handleDatabaseError(error, {
type: 'reconnection-failed',
database: this.databaseName
});
} else {
console.error('Failed to reconnect to monitoring database:', error.message);
}
// Schedule another reconnection attempt
setTimeout(() => this.handleReconnection(), 10000); // Try again in 10 seconds
}
}
/**
* Get the monitoring database connection
* @returns {mongoose.Connection}
*/
getMonitoringDB() {
if (!this.isConnected || !this.monitoringConnection) {
const error = new Error('Monitoring database not connected. Call initMonitoringConnection() first.');
if (this.errorHandler) {
this.errorHandler.handleError(error, {
component: 'database-manager',
operation: 'get-connection',
connectionState: this.isConnected ? 'connected' : 'disconnected'
});
}
throw error;
}
return this.monitoringConnection;
}
/**
* Save user data to monitoring database
* @param {string} collectionName - Name of the collection
* @param {Object} data - Data to save
* @returns {Promise<Object>}
*/
async saveUserData(collectionName, data) {
// Validate inputs
if (this.errorHandler) {
const validation = this.errorHandler.validateInput(collectionName, {
type: 'string',
required: true,
minLength: 1,
maxLength: 100
}, { field: 'collectionName' });
if (!validation.isValid) {
const error = new Error(`Invalid collection name: ${validation.errors.join(', ')}`);
await this.errorHandler.handleError(error, {
component: 'database-manager',
operation: 'save-user-data',
collectionName,
validationErrors: validation.errors
});
throw error;
}
}
if (!this.isConnected) {
const error = new Error('Monitoring database not connected');
if (this.errorHandler) {
await this.errorHandler.handleDatabaseError(error, {
type: 'save-operation',
collection: collectionName
});
}
throw error;
}
const context = {
component: 'database-manager',
operation: 'save-user-data',
collection: collectionName
};
try {
const collection = this.monitoringConnection.collection(collectionName);
const result = await collection.insertOne({
...data,
timestamp: new Date(),
_createdAt: new Date()
});
if (this.errorHandler) {
await this.errorHandler.logInfo(`Successfully saved data to collection: ${collectionName}`, context);
}
return result;
} catch (error) {
if (this.errorHandler) {
await this.errorHandler.handleDatabaseError(error, {
type: 'save-operation',
collection: collectionName
});
}
throw error;
}
}
/**
* Check if monitoring database is connected
* @returns {boolean}
*/
isMonitoringConnected() {
return this.isConnected && this.monitoringConnection && this.monitoringConnection.readyState === 1;
}
/**
* Close the monitoring database connection
* @returns {Promise<void>}
*/
async closeConnection() {
if (this.monitoringConnection) {
const context = {
component: 'database-manager',
operation: 'close-connection',
database: this.databaseName
};
try {
await this.monitoringConnection.close();
this.isConnected = false;
if (this.errorHandler) {
await this.errorHandler.logInfo('Monitoring database connection closed', context);
} else {
console.log('Monitoring database connection closed');
}
} catch (error) {
if (this.errorHandler) {
await this.errorHandler.handleDatabaseError(error, {
type: 'close-connection',
database: this.databaseName
});
} else {
console.error('Error closing monitoring database connection:', error);
}
throw error;
}
}
}
/**
* Utility function for sleep/delay
* @param {number} ms - Milliseconds to sleep
* @returns {Promise<void>}
*/
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
export default DatabaseManager;