UNPKG

plugin-postgresql-connector

Version:

NocoBase plugin for connecting to external PostgreSQL databases

210 lines 7.38 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.ConnectionManager = void 0; const pg_1 = require("pg"); const crypto_js_1 = __importDefault(require("crypto-js")); class ConnectionManager { constructor() { this.pools = new Map(); this.encryptionKey = process.env.ENCRYPTION_KEY || 'default-key-change-in-production'; this.maxConnections = parseInt(process.env.POSTGRESQL_CONNECTOR_MAX_CONNECTIONS || '10'); this.connectionTimeout = parseInt(process.env.POSTGRESQL_CONNECTOR_CONNECTION_TIMEOUT || '5000'); this.idleTimeout = parseInt(process.env.POSTGRESQL_CONNECTOR_IDLE_TIMEOUT || '30000'); if (this.encryptionKey === 'default-key-change-in-production') { console.warn('WARNING: Using default encryption key. Please set ENCRYPTION_KEY environment variable.'); } } /** * Create a new connection pool and test the connection */ async createConnection(connectionConfig) { const connectionId = this.generateConnectionId(); try { // Create connection pool configuration const poolConfig = { host: connectionConfig.host, port: connectionConfig.port, database: connectionConfig.database, user: connectionConfig.username, password: connectionConfig.password, max: this.maxConnections, idleTimeoutMillis: this.idleTimeout, connectionTimeoutMillis: this.connectionTimeout, ssl: connectionConfig.ssl ? { rejectUnauthorized: false } : false, ...connectionConfig.connectionOptions, }; // Create pool const pool = new pg_1.Pool(poolConfig); // Test connection const client = await pool.connect(); try { await client.query('SELECT NOW()'); console.log(`Connection ${connectionId} established successfully`); } finally { client.release(); } // Store pool this.pools.set(connectionId, pool); return { success: true, connectionId, }; } catch (error) { console.error(`Connection ${connectionId} failed:`, error); return { success: false, error: error instanceof Error ? error.message : 'Unknown connection error', }; } } /** * Get a client from the connection pool */ async getConnection(connectionId) { const pool = this.pools.get(connectionId); if (!pool) { throw new Error(`Connection ${connectionId} not found`); } try { return await pool.connect(); } catch (error) { console.error(`Failed to get connection from pool ${connectionId}:`, error); throw new Error(`Failed to get connection: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Close a specific connection pool */ async closeConnection(connectionId) { const pool = this.pools.get(connectionId); if (pool) { try { await pool.end(); this.pools.delete(connectionId); console.log(`Connection ${connectionId} closed successfully`); } catch (error) { console.error(`Error closing connection ${connectionId}:`, error); throw error; } } } /** * Close all connection pools */ async closeAllConnections() { const closePromises = Array.from(this.pools.keys()).map(connectionId => this.closeConnection(connectionId)); await Promise.all(closePromises); console.log('All connections closed'); } /** * Test connection without creating a pool */ async testConnection(connectionConfig) { const poolConfig = { host: connectionConfig.host, port: connectionConfig.port, database: connectionConfig.database, user: connectionConfig.username, password: connectionConfig.password, max: 1, // Only one connection for testing idleTimeoutMillis: 1000, connectionTimeoutMillis: this.connectionTimeout, ssl: connectionConfig.ssl ? { rejectUnauthorized: false } : false, }; const pool = new pg_1.Pool(poolConfig); try { const client = await pool.connect(); try { await client.query('SELECT NOW()'); return { success: true }; } finally { client.release(); } } catch (error) { return { success: false, error: error instanceof Error ? error.message : 'Connection test failed', }; } finally { await pool.end(); } } /** * Get connection pool statistics */ getConnectionStats(connectionId) { const pool = this.pools.get(connectionId); if (!pool) { return null; } return { totalCount: pool.totalCount, idleCount: pool.idleCount, waitingCount: pool.waitingCount, }; } /** * Get all active connection IDs */ getActiveConnections() { return Array.from(this.pools.keys()); } /** * Encrypt password for storage */ encryptPassword(password) { try { return crypto_js_1.default.AES.encrypt(password, this.encryptionKey).toString(); } catch (error) { console.error('Password encryption failed:', error); throw new Error('Failed to encrypt password'); } } /** * Decrypt password from storage */ decryptPassword(encryptedPassword) { try { const bytes = crypto_js_1.default.AES.decrypt(encryptedPassword, this.encryptionKey); const decrypted = bytes.toString(crypto_js_1.default.enc.Utf8); if (!decrypted) { throw new Error('Failed to decrypt password - invalid key or corrupted data'); } return decrypted; } catch (error) { console.error('Password decryption failed:', error); throw new Error('Failed to decrypt password'); } } /** * Generate unique connection ID */ generateConnectionId() { const timestamp = Date.now(); const random = Math.random().toString(36).substr(2, 9); return `conn_${timestamp}_${random}`; } /** * Cleanup method for graceful shutdown */ async destroy() { console.log('ConnectionManager: Starting cleanup...'); await this.closeAllConnections(); console.log('ConnectionManager: Cleanup completed'); } } exports.ConnectionManager = ConnectionManager; exports.default = ConnectionManager; //# sourceMappingURL=ConnectionManager.js.map