Files
DLE/backend/services/databaseConnectionManager.js
Alex de0f8aecf2 feat: Добавлены формы деплоя модулей DLE с полными настройками
- Создана форма деплоя TreasuryModule с детальными настройками казны
- Создана форма деплоя TimelockModule с настройками временных задержек
- Создана форма деплоя DLEReader с простой конфигурацией
- Добавлены маршруты и индексы для всех модулей
- Исправлены пути импорта BaseLayout
- Добавлены авторские права во все файлы
- Улучшена архитектура деплоя модулей отдельно от основного DLE
2025-09-23 02:57:59 +03:00

223 lines
6.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* Copyright (c) 2024-2025 Тарабанов Александр Викторович
* All rights reserved.
*
* This software is proprietary and confidential.
* Unauthorized copying, modification, or distribution is prohibited.
*
* For licensing inquiries: info@hb3-accelerator.com
* Website: https://hb3-accelerator.com
* GitHub: https://github.com/HB3-ACCELERATOR
*/
/**
* Сервис для динамического управления подключениями к базе данных
* Позволяет изменять настройки БД без перезапуска приложения
*/
const { Pool } = require('pg');
const logger = require('../utils/logger');
class DatabaseConnectionManager {
constructor() {
this.currentPool = null;
this.currentConfig = null;
this.connectionListeners = [];
this.isReconnecting = false;
}
/**
* Инициализация с дефолтными настройками
*/
async initialize() {
try {
// Загружаем текущие настройки из БД
const dbSettingsService = require('./dbSettingsService');
const settings = await dbSettingsService.getSettings();
if (settings) {
await this.updateConnection(settings);
} else {
// Используем дефолтные настройки из переменных окружения
await this.updateConnection({
db_host: process.env.DB_HOST || 'postgres',
db_port: parseInt(process.env.DB_PORT) || 5432,
db_name: process.env.DB_NAME || 'dapp_db',
db_user: process.env.DB_USER || 'dapp_user',
db_password: process.env.DB_PASSWORD || 'dapp_password'
});
}
logger.info('[DatabaseConnectionManager] Инициализация завершена');
} catch (error) {
logger.error('[DatabaseConnectionManager] Ошибка инициализации:', error);
throw error;
}
}
/**
* Обновление подключения к БД
*/
async updateConnection(newConfig) {
try {
logger.info('[DatabaseConnectionManager] Обновление подключения к БД...');
// Проверяем, изменились ли настройки
if (this.currentConfig && this.configsEqual(this.currentConfig, newConfig)) {
logger.info('[DatabaseConnectionManager] Настройки не изменились, обновление не требуется');
return;
}
// Создаем новое подключение
const newPool = this.createPool(newConfig);
// Тестируем новое подключение
await this.testConnection(newPool);
// Закрываем старое подключение
if (this.currentPool) {
await this.closePool(this.currentPool);
}
// Обновляем текущие настройки
this.currentPool = newPool;
this.currentConfig = { ...newConfig };
logger.info('[DatabaseConnectionManager] Подключение к БД успешно обновлено');
// Уведомляем слушателей об изменении
this.notifyConnectionChange();
} catch (error) {
logger.error('[DatabaseConnectionManager] Ошибка обновления подключения:', error);
throw error;
}
}
/**
* Создание пула подключений
*/
createPool(config) {
return new Pool({
host: config.db_host,
port: config.db_port,
database: config.db_name,
user: config.db_user,
password: config.db_password,
ssl: false,
max: 10,
min: 0,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
maxUses: 7500,
allowExitOnIdle: true,
maxLifetimeSeconds: 0
});
}
/**
* Тестирование подключения
*/
async testConnection(pool) {
const client = await pool.connect();
try {
await client.query('SELECT 1');
logger.info('[DatabaseConnectionManager] Тест подключения успешен');
} finally {
client.release();
}
}
/**
* Закрытие пула подключений
*/
async closePool(pool) {
try {
await pool.end();
logger.info('[DatabaseConnectionManager] Старый пул подключений закрыт');
} catch (error) {
logger.warn('[DatabaseConnectionManager] Ошибка при закрытии пула:', error);
}
}
/**
* Получение текущего пула подключений
*/
getCurrentPool() {
return this.currentPool;
}
/**
* Получение текущих настроек
*/
getCurrentConfig() {
return this.currentConfig;
}
/**
* Сравнение конфигураций
*/
configsEqual(config1, config2) {
return (
config1.db_host === config2.db_host &&
config1.db_port === config2.db_port &&
config1.db_name === config2.db_name &&
config1.db_user === config2.db_user &&
config1.db_password === config2.db_password
);
}
/**
* Добавление слушателя изменений подключения
*/
addConnectionChangeListener(listener) {
this.connectionListeners.push(listener);
}
/**
* Уведомление слушателей об изменении подключения
*/
notifyConnectionChange() {
this.connectionListeners.forEach(listener => {
try {
listener(this.currentConfig);
} catch (error) {
logger.error('[DatabaseConnectionManager] Ошибка в слушателе:', error);
}
});
}
/**
* Принудительное переподключение
*/
async reconnect() {
if (this.isReconnecting) {
logger.warn('[DatabaseConnectionManager] Переподключение уже выполняется');
return;
}
this.isReconnecting = true;
try {
if (this.currentConfig) {
await this.updateConnection(this.currentConfig);
}
} finally {
this.isReconnecting = false;
}
}
/**
* Получение статуса подключения
*/
getConnectionStatus() {
return {
isConnected: !!this.currentPool,
config: this.currentConfig,
isReconnecting: this.isReconnecting,
listenersCount: this.connectionListeners.length
};
}
}
module.exports = new DatabaseConnectionManager();