new file: .claude/settings.local.json
new file: .gitignore new file: backend/.env.example new file: backend/.gitignore new file: backend/ecosystem.config.js new file: backend/nodemon.json new file: backend/package-lock.json new file: backend/package.json new file: backend/src/config/database.ts new file: backend/src/config/dynamicSwagger.ts new file: backend/src/config/environment.ts new file: backend/src/config/swagger.ts new file: backend/src/controllers/apiKeyController.ts new file: backend/src/controllers/authController.ts new file: backend/src/controllers/databaseController.ts new file: backend/src/controllers/databaseManagementController.ts new file: backend/src/controllers/dynamicApiController.ts new file: backend/src/controllers/endpointController.ts new file: backend/src/controllers/folderController.ts new file: backend/src/controllers/logsController.ts new file: backend/src/controllers/userController.ts new file: backend/src/middleware/apiKey.ts new file: backend/src/middleware/auth.ts new file: backend/src/middleware/logging.ts new file: backend/src/migrations/001_initial_schema.sql new file: backend/src/migrations/002_add_logging.sql new file: backend/src/migrations/003_add_scripting.sql new file: backend/src/migrations/004_add_superadmin.sql new file: backend/src/migrations/run.ts new file: backend/src/migrations/seed.ts new file: backend/src/routes/apiKeys.ts new file: backend/src/routes/auth.ts new file: backend/src/routes/databaseManagement.ts new file: backend/src/routes/databases.ts new file: backend/src/routes/dynamic.ts new file: backend/src/routes/endpoints.ts new file: backend/src/routes/folders.ts new file: backend/src/routes/logs.ts new file: backend/src/routes/users.ts new file: backend/src/server.ts new file: backend/src/services/DatabasePoolManager.ts new file: backend/src/services/ScriptExecutor.ts new file: backend/src/services/SqlExecutor.ts new file: backend/src/types/index.ts new file: backend/tsconfig.json new file: frontend/.gitignore new file: frontend/index.html new file: frontend/nginx.conf new file: frontend/package-lock.json new file: frontend/package.json new file: frontend/postcss.config.js new file: frontend/src/App.tsx new file: frontend/src/components/CodeEditor.tsx
This commit is contained in:
146
backend/src/services/DatabasePoolManager.ts
Normal file
146
backend/src/services/DatabasePoolManager.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import { Pool } from 'pg';
|
||||
import { DatabaseConfig } from '../types';
|
||||
import { mainPool } from '../config/database';
|
||||
|
||||
class DatabasePoolManager {
|
||||
private pools: Map<string, Pool> = new Map();
|
||||
|
||||
async initialize() {
|
||||
// Load databases from DB instead of env
|
||||
await this.loadDatabasesFromDB();
|
||||
}
|
||||
|
||||
private async loadDatabasesFromDB() {
|
||||
try {
|
||||
const result = await mainPool.query(
|
||||
'SELECT * FROM databases WHERE is_active = true'
|
||||
);
|
||||
|
||||
for (const row of result.rows) {
|
||||
const dbConfig: DatabaseConfig = {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
type: row.type,
|
||||
host: row.host,
|
||||
port: row.port,
|
||||
database_name: row.database_name,
|
||||
username: row.username,
|
||||
password: row.password,
|
||||
ssl: row.ssl,
|
||||
is_active: row.is_active,
|
||||
};
|
||||
|
||||
this.addPool(dbConfig);
|
||||
}
|
||||
|
||||
console.log(`✅ Loaded ${result.rows.length} database connection(s) from DB`);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed to load databases from DB:', error);
|
||||
}
|
||||
}
|
||||
|
||||
addPool(dbConfig: DatabaseConfig) {
|
||||
if (this.pools.has(dbConfig.id)) {
|
||||
console.warn(`Pool with id ${dbConfig.id} already exists. Skipping.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const pool = new Pool({
|
||||
host: dbConfig.host,
|
||||
port: dbConfig.port,
|
||||
database: dbConfig.database_name,
|
||||
user: dbConfig.username,
|
||||
password: dbConfig.password,
|
||||
ssl: dbConfig.ssl ? { rejectUnauthorized: false } : false,
|
||||
max: 10,
|
||||
idleTimeoutMillis: 30000,
|
||||
connectionTimeoutMillis: 2000,
|
||||
});
|
||||
|
||||
pool.on('error', (err) => {
|
||||
console.error(`Database pool error for ${dbConfig.id}:`, err);
|
||||
});
|
||||
|
||||
this.pools.set(dbConfig.id, pool);
|
||||
console.log(`✅ Pool created for database: ${dbConfig.name} (${dbConfig.id})`);
|
||||
}
|
||||
|
||||
removePool(databaseId: string) {
|
||||
const pool = this.pools.get(databaseId);
|
||||
if (pool) {
|
||||
pool.end();
|
||||
this.pools.delete(databaseId);
|
||||
console.log(`Pool removed for database: ${databaseId}`);
|
||||
}
|
||||
}
|
||||
|
||||
getPool(databaseId: string): Pool | undefined {
|
||||
return this.pools.get(databaseId);
|
||||
}
|
||||
|
||||
async getAllDatabaseConfigs(): Promise<DatabaseConfig[]> {
|
||||
try {
|
||||
const result = await mainPool.query(
|
||||
'SELECT id, name, type, host, port, database_name, is_active FROM databases WHERE is_active = true'
|
||||
);
|
||||
return result.rows;
|
||||
} catch (error) {
|
||||
console.error('Error fetching databases:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async testConnection(databaseId: string): Promise<boolean> {
|
||||
const pool = this.getPool(databaseId);
|
||||
if (!pool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const client = await pool.connect();
|
||||
client.release();
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error(`Connection test failed for ${databaseId}:`, error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async reloadPool(databaseId: string) {
|
||||
// Remove old pool
|
||||
this.removePool(databaseId);
|
||||
|
||||
// Load new config from DB
|
||||
const result = await mainPool.query(
|
||||
'SELECT * FROM databases WHERE id = $1 AND is_active = true',
|
||||
[databaseId]
|
||||
);
|
||||
|
||||
if (result.rows.length > 0) {
|
||||
const row = result.rows[0];
|
||||
const dbConfig: DatabaseConfig = {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
type: row.type,
|
||||
host: row.host,
|
||||
port: row.port,
|
||||
database_name: row.database_name,
|
||||
username: row.username,
|
||||
password: row.password,
|
||||
ssl: row.ssl,
|
||||
is_active: row.is_active,
|
||||
};
|
||||
|
||||
this.addPool(dbConfig);
|
||||
}
|
||||
}
|
||||
|
||||
async closeAll() {
|
||||
const promises = Array.from(this.pools.values()).map((pool) => pool.end());
|
||||
await Promise.all(promises);
|
||||
this.pools.clear();
|
||||
console.log('All database pools closed');
|
||||
}
|
||||
}
|
||||
|
||||
export const databasePoolManager = new DatabasePoolManager();
|
||||
Reference in New Issue
Block a user