modified: backend/src/services/ScriptExecutor.ts modified: backend/src/types/index.ts modified: frontend/src/components/CodeEditor.tsx modified: frontend/src/components/EndpointModal.tsx deleted: frontend/src/pages/Databases.tsx modified: frontend/src/pages/Settings.tsx modified: frontend/src/types/index.ts
181 lines
5.0 KiB
TypeScript
181 lines
5.0 KiB
TypeScript
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: 20, // Увеличено количество соединений
|
|
idleTimeoutMillis: 60000, // 60 секунд
|
|
connectionTimeoutMillis: 10000, // 10 секунд (было 2 секунды)
|
|
keepAlive: true, // Поддерживать соединения активными
|
|
keepAliveInitialDelayMillis: 10000, // Начать keepAlive через 10 секунд
|
|
});
|
|
|
|
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 getDatabaseConfig(databaseId: string): Promise<DatabaseConfig | null> {
|
|
try {
|
|
const result = await mainPool.query(
|
|
'SELECT * FROM databases WHERE id = $1',
|
|
[databaseId]
|
|
);
|
|
if (result.rows.length === 0) {
|
|
return null;
|
|
}
|
|
const row = result.rows[0];
|
|
return {
|
|
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,
|
|
aql_base_url: row.aql_base_url,
|
|
aql_auth_type: row.aql_auth_type,
|
|
aql_auth_value: row.aql_auth_value,
|
|
aql_headers: row.aql_headers,
|
|
};
|
|
} catch (error) {
|
|
console.error('Error fetching database config:', error);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
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();
|