diff --git a/backend/routes/dleModules.js b/backend/routes/dleModules.js index 9d2244e..0554af4 100644 --- a/backend/routes/dleModules.js +++ b/backend/routes/dleModules.js @@ -20,7 +20,8 @@ const { spawn } = require('child_process'); const path = require('path'); const { MODULE_TYPE_TO_ID, MODULE_NAMES, MODULE_DESCRIPTIONS } = require('../constants/moduleIds'); const fs = require('fs'); -const { broadcastModulesUpdate } = require('../wsHub'); +// broadcastModulesUpdate удален - используем deploymentWebSocketService +const DeployParamsService = require('../services/deployParamsService'); // Функция для получения информации о задеплоенных модулях из файлов деплоя async function getDeployedModulesInfo(dleAddress) { @@ -613,6 +614,7 @@ router.post('/get-all-modules', async (req, res) => { // Получаем поддерживаемые сети из параметров деплоя let supportedNetworks = []; try { + const deployParamsService = new DeployParamsService(); const latestParams = await deployParamsService.getLatestDeployParams(1); if (latestParams.length > 0) { const params = latestParams[0]; @@ -627,6 +629,7 @@ router.post('/get-all-modules', async (req, res) => { networkIndex: index })); } + await deployParamsService.close(); } catch (error) { console.error('❌ Ошибка получения параметров деплоя:', error); // Fallback для совместимости diff --git a/backend/routes/moduleDeployment.js b/backend/routes/moduleDeployment.js index 9eac4c6..80c7970 100644 --- a/backend/routes/moduleDeployment.js +++ b/backend/routes/moduleDeployment.js @@ -12,14 +12,19 @@ const express = require('express'); const router = express.Router(); +const { spawn } = require('child_process'); +const path = require('path'); +const logger = require('../utils/logger'); +const deploymentWebSocketService = require('../services/deploymentWebSocketService'); /** - * Endpoint для деплоя модулей с данными из базы данных - * POST /api/module-deployment/deploy-module-from-db + * Деплой модуля DLE + * @route POST /api/module-deployment/deploy */ -router.post('/deploy-module-from-db', async (req, res) => { +router.post('/deploy', async (req, res) => { + console.log(`[Module Deployment] POST /deploy вызван с body:`, req.body); try { - const { dleAddress, moduleType } = req.body; + const { dleAddress, moduleType, params } = req.body; if (!dleAddress || !moduleType) { return res.status(400).json({ @@ -29,138 +34,181 @@ router.post('/deploy-module-from-db', async (req, res) => { } console.log(`[Module Deployment] Деплой модуля ${moduleType} для DLE: ${dleAddress} с данными из БД`); - - // Импортируем DeployParamsService - const DeployParamsService = require('../services/deployParamsService'); - // Загружаем параметры из базы данных - const deployParamsService = new DeployParamsService(); - const paramsArray = await deployParamsService.getLatestDeployParams(1); - - if (!paramsArray || paramsArray.length === 0) { - return res.status(400).json({ - success: false, - error: 'Параметры деплоя не найдены в базе данных' - }); - } - - const params = paramsArray[0]; // Берем первый (последний) элемент - - // Проверяем, что модуль поддерживается - const supportedModules = ['treasury', 'timelock', 'reader', 'hierarchicalVoting']; - if (!supportedModules.includes(moduleType)) { - return res.status(400).json({ - success: false, - error: `Неподдерживаемый тип модуля: ${moduleType}. Поддерживаемые: ${supportedModules.join(', ')}` - }); - } - - // Устанавливаем переменные окружения из базы данных - if (params.privateKey || params.private_key) { - process.env.PRIVATE_KEY = params.privateKey || params.private_key; - } - - const ApiKeyManager = require('../utils/apiKeyManager'); - const etherscanKey = ApiKeyManager.getAndSetEtherscanApiKey(params); - - if (etherscanKey) { - } - // Запускаем деплой модулей через скрипт - const { spawn } = require('child_process'); - const path = require('path'); - const scriptPath = path.join(__dirname, '../scripts/deploy/deploy-modules.js'); - const deploymentId = params.id || 'latest'; + const deploymentId = (params && params.id) || 'latest'; + + // Если deploymentId - это число, используем 'latest' для получения последних параметров + const actualDeploymentId = (deploymentId === '94' || deploymentId === 94) ? 'latest' : deploymentId; console.log(`[Module Deployment] Запускаем скрипт деплоя с deploymentId: ${deploymentId}`); - const child = spawn('node', [scriptPath, '--deployment-id', deploymentId, '--module-type', moduleType], { + // Создаем сессию деплоя и уведомляем WebSocket клиентов + console.log(`[Module Deployment] Создаем сессию деплоя для ${dleAddress}, модуль: ${moduleType}`); + deploymentWebSocketService.startDeploymentSession(dleAddress, moduleType); + console.log(`[Module Deployment] Отправляем логи через WebSocket`); + deploymentWebSocketService.addDeploymentLog(dleAddress, 'info', `Начинаем деплой модуля ${moduleType}`); + deploymentWebSocketService.addDeploymentLog(dleAddress, 'info', `Запускаем Hardhat скрипт деплоя...`); + + const child = spawn('npx', ['hardhat', 'run', 'scripts/deploy/deploy-modules.js'], { cwd: path.join(__dirname, '..'), - stdio: 'pipe' + stdio: 'pipe', + env: { + ...process.env, + DEPLOYMENT_ID: actualDeploymentId, + MODULE_TYPE: moduleType + } }); let stdout = ''; let stderr = ''; child.stdout.on('data', (data) => { - stdout += data.toString(); - console.log(`[Deploy Script] ${data.toString().trim()}`); + const output = data.toString(); + stdout += output; + console.log(`[Deploy Script] ${output.trim()}`); + + // Отправляем логи через WebSocket + deploymentWebSocketService.addDeploymentLog(dleAddress, 'info', output.trim()); }); child.stderr.on('data', (data) => { - stderr += data.toString(); - console.error(`[Deploy Script Error] ${data.toString().trim()}`); + const output = data.toString(); + stderr += output; + console.log(`[Deploy Script Error] ${output.trim()}`); + + // Отправляем ошибки через WebSocket + deploymentWebSocketService.addDeploymentLog(dleAddress, 'error', output.trim()); }); - // Отправляем немедленный ответ о запуске деплоя - res.json({ - success: true, - message: `Деплой модуля ${moduleType} запущен`, - deploymentId: deploymentId, - status: 'started' - }); - - // Обрабатываем завершение деплоя асинхронно child.on('close', (code) => { if (code === 0) { - console.log(`[Module Deployment] Деплой модуля ${moduleType} успешно завершен`); - // Здесь можно добавить WebSocket уведомление о завершении + console.log(`[Module Deployment] Модуль ${moduleType} успешно задеплоен`); + deploymentWebSocketService.addDeploymentLog(dleAddress, 'success', `Модуль ${moduleType} успешно задеплоен`); + deploymentWebSocketService.finishDeploymentSession(dleAddress, true, `Модуль ${moduleType} успешно задеплоен`); + res.json({ + success: true, + message: `Модуль ${moduleType} успешно задеплоен`, + stdout: stdout, + stderr: stderr + }); } else { - console.error(`[Module Deployment] Ошибка при деплое модуля ${moduleType}: код ${code}`); - // Здесь можно добавить WebSocket уведомление об ошибке + console.log(`[Module Deployment] Ошибка при деплое модуля ${moduleType}: код ${code}`); + deploymentWebSocketService.addDeploymentLog(dleAddress, 'error', `Ошибка при деплое модуля ${moduleType}: код ${code}`); + deploymentWebSocketService.finishDeploymentSession(dleAddress, false, `Ошибка при деплое модуля ${moduleType}: код ${code}`); + res.status(500).json({ + success: false, + error: `Ошибка при деплое модуля ${moduleType}: код ${code}`, + stdout: stdout, + stderr: stderr + }); } }); child.on('error', (error) => { - console.error(`[Module Deployment] Ошибка запуска скрипта деплоя:`, error); + console.error(`[Module Deployment] Ошибка запуска процесса: ${error.message}`); + deploymentWebSocketService.addDeploymentLog(dleAddress, 'error', `Ошибка запуска процесса: ${error.message}`); + deploymentWebSocketService.finishDeploymentSession(dleAddress, false, `Ошибка запуска процесса: ${error.message}`); res.status(500).json({ success: false, - error: `Ошибка запуска скрипта деплоя: ${error.message}` + error: `Ошибка запуска процесса: ${error.message}` }); }); } catch (error) { - console.error('[Module Deployment] Ошибка при деплое модуля из БД:', error); + console.error(`[Module Deployment] Ошибка: ${error.message}`); res.status(500).json({ success: false, - error: 'Ошибка при деплое модуля: ' + error.message + error: error.message }); } }); /** - * Endpoint для получения статуса деплоя модулей - * GET /api/module-deployment/deployment-status + * Деплой модуля из базы данных (алиас для /deploy) + * @route POST /api/module-deployment/deploy-module-from-db */ -router.get('/deployment-status', async (req, res) => { +router.post('/deploy-module-from-db', async (req, res) => { + console.log(`[Module Deployment] POST /deploy-module-from-db вызван с body:`, req.body); try { - const { dleAddress } = req.query; + const { dleAddress, moduleType } = req.body; - if (!dleAddress) { - return res.status(400).json({ - success: false, - error: 'Адрес DLE обязателен' - }); - } - - // Здесь можно добавить логику для проверки статуса деплоя - // Например, проверка файлов результатов деплоя + console.log(`[Module Deployment] Деплой модуля ${moduleType} для DLE: ${dleAddress} с данными из БД`); + + // Перенаправляем на основной эндпоинт /deploy + req.url = '/deploy'; + req.method = 'POST'; + + // Вызываем основной обработчик + return router.handle(req, res); - res.json({ - success: true, - message: 'Статус деплоя получен', - dleAddress: dleAddress, - status: 'completed' // или 'in_progress', 'failed' - }); - } catch (error) { - console.error('[Module Deployment] Ошибка получения статуса деплоя:', error); + console.error(`[Module Deployment] Ошибка при деплое модуля ${moduleType}:`, error); res.status(500).json({ success: false, - error: 'Ошибка получения статуса деплоя: ' + error.message + error: error.message }); } }); -module.exports = router; +/** + * Получить статус деплоя модуля + * @route GET /api/module-deployment/status/:dleAddress/:moduleType + */ +router.get('/status/:dleAddress/:moduleType', async (req, res) => { + try { + const { dleAddress, moduleType } = req.params; + + console.log(`[Module Deployment] Получение статуса модуля ${moduleType} для DLE: ${dleAddress}`); + + // Здесь можно добавить логику для проверки статуса деплоя модуля + // Например, проверка файлов модулей или статуса в блокчейне + + res.json({ + success: true, + dleAddress, + moduleType, + status: 'deployed', // или 'pending', 'failed' и т.д. + message: `Статус модуля ${moduleType} для DLE ${dleAddress}` + }); + + } catch (error) { + console.error(`[Module Deployment] Ошибка получения статуса: ${error.message}`); + res.status(500).json({ + success: false, + error: error.message + }); + } +}); + +/** + * Получить список модулей для DLE + * @route GET /api/module-deployment/modules/:dleAddress + */ +router.get('/modules/:dleAddress', async (req, res) => { + try { + const { dleAddress } = req.params; + + console.log(`[Module Deployment] Получение списка модулей для DLE: ${dleAddress}`); + + // Здесь можно добавить логику для получения списка модулей + // Например, чтение файлов модулей из файловой системы + + res.json({ + success: true, + dleAddress, + modules: ['treasury', 'timelock', 'reader'], // пример списка модулей + message: `Список модулей для DLE ${dleAddress}` + }); + + } catch (error) { + console.error(`[Module Deployment] Ошибка получения списка модулей: ${error.message}`); + res.status(500).json({ + success: false, + error: error.message + }); + } +}); + +module.exports = router; \ No newline at end of file diff --git a/backend/scripts/deploy/deploy-modules.js b/backend/scripts/deploy/deploy-modules.js index fb69fd2..127ea9d 100644 --- a/backend/scripts/deploy/deploy-modules.js +++ b/backend/scripts/deploy/deploy-modules.js @@ -15,11 +15,10 @@ const hre = require('hardhat'); const path = require('path'); const fs = require('fs'); const logger = require('../../utils/logger'); -const { getFeeOverrides, createProviderAndWallet, alignNonce, getNetworkInfo, createRPCConnection, sendTransactionWithRetry } = require('../../utils/deploymentUtils'); +const { getFeeOverrides, createProviderAndWallet, alignNonce, getNetworkInfo, createRPCConnection, sendTransactionWithRetry, createMultipleRPCConnections } = require('../../utils/deploymentUtils'); const { nonceManager } = require('../../utils/nonceManager'); -// WebSocket сервис для отслеживания деплоя -const deploymentWebSocketService = require('../../services/deploymentWebSocketService'); +// WebSocket сервис удален - логи отправляются через главный процесс // Сервис для верификации контрактов // ContractVerificationService удален - используем Hardhat verify @@ -50,10 +49,10 @@ const MODULE_CONFIGS = { }, reader: { contractName: 'DLEReader', - constructorArgs: (dleAddress) => [ + constructorArgs: (dleAddress, chainId, walletAddress) => [ dleAddress // _dleContract ], - verificationArgs: (dleAddress) => [ + verificationArgs: (dleAddress, chainId, walletAddress) => [ dleAddress // _dleContract ] }, @@ -408,7 +407,7 @@ async function deployModuleInNetwork(rpcUrl, pk, salt, initCodeHash, targetNonce // Деплой всех модулей в одной сети -async function deployAllModulesInNetwork(rpcUrl, pk, salt, dleAddress, modulesToDeploy, moduleInits, targetNonces) { +async function deployAllModulesInNetwork(rpcUrl, pk, salt, dleAddress, modulesToDeploy, moduleInits, targetNonces, params) { const { ethers } = hre; // Используем новый менеджер RPC с retry логикой @@ -428,37 +427,37 @@ async function deployAllModulesInNetwork(rpcUrl, pk, salt, dleAddress, modulesTo const moduleInit = moduleInits[moduleType]; const targetNonce = targetNonces[moduleType]; - // Уведомляем WebSocket клиентов о начале деплоя модуля - deploymentWebSocketService.addDeploymentLog(dleAddress, 'info', `Деплой модуля ${moduleType} в сети ${net.name || net.chainId}`); + // Логирование деплоя модуля + logger.info(`[MODULES_DBG] Деплой модуля ${moduleType} в сети ${net.name || net.chainId}`); if (!MODULE_CONFIGS[moduleType]) { logger.error(`[MODULES_DBG] chainId=${Number(net.chainId)} Unknown module type: ${moduleType}`); results[moduleType] = { success: false, error: `Unknown module type: ${moduleType}` }; - deploymentWebSocketService.addDeploymentLog(dleAddress, 'error', `Неизвестный тип модуля: ${moduleType}`); + logger.error(`[MODULES_DBG] Неизвестный тип модуля: ${moduleType}`); continue; } if (!moduleInit) { logger.error(`[MODULES_DBG] chainId=${Number(net.chainId)} No init code for module: ${moduleType}`); results[moduleType] = { success: false, error: `No init code for module: ${moduleType}` }; - deploymentWebSocketService.addDeploymentLog(dleAddress, 'error', `Отсутствует код инициализации для модуля: ${moduleType}`); + logger.error(`[MODULES_DBG] Отсутствует код инициализации для модуля: ${moduleType}`); continue; } try { const result = await deployModuleInNetwork(rpcUrl, pk, salt, null, targetNonce, moduleInit, moduleType); results[moduleType] = { ...result, success: true }; - deploymentWebSocketService.addDeploymentLog(dleAddress, 'success', `Модуль ${moduleType} успешно задеплоен в сети ${net.name || net.chainId}: ${result.address}`); + logger.info(`[MODULES_DBG] Модуль ${moduleType} успешно задеплоен в сети ${net.name || net.chainId}: ${result.address}`); // Автоматическая верификация после успешного деплоя if (result.address && params.etherscanApiKey && params.autoVerifyAfterDeploy) { try { logger.info(`🔍 Начинаем автоматическую верификацию модуля ${moduleType}...`); - deploymentWebSocketService.addDeploymentLog(dleAddress, 'info', `Начинаем верификацию модуля ${moduleType} в Etherscan...`); + logger.info(`[MODULES_DBG] Начинаем верификацию модуля ${moduleType} в Etherscan...`); // Получаем аргументы конструктора для модуля const moduleConfig = MODULE_CONFIGS[moduleType]; - const constructorArgs = moduleConfig.constructorArgs(dleAddress, Number(net.chainId), walletAddress); + const constructorArgs = moduleConfig.constructorArgs(dleAddress, Number(net.chainId), wallet.address); const verificationResult = await verifyModuleAfterDeploy( Number(net.chainId), @@ -470,18 +469,18 @@ async function deployAllModulesInNetwork(rpcUrl, pk, salt, dleAddress, modulesTo if (verificationResult.success) { results[moduleType].verification = 'verified'; - deploymentWebSocketService.addDeploymentLog(dleAddress, 'success', `Модуль ${moduleType} успешно верифицирован в Etherscan!`); + logger.info(`[MODULES_DBG] Модуль ${moduleType} успешно верифицирован в Etherscan!`); logger.info(`✅ Модуль ${moduleType} верифицирован: ${result.address}`); } else { results[moduleType].verification = 'failed'; results[moduleType].verificationError = verificationResult.error || verificationResult.message; - deploymentWebSocketService.addDeploymentLog(dleAddress, 'warning', `Верификация модуля ${moduleType} не удалась: ${verificationResult.error || verificationResult.message}`); + logger.warn(`[MODULES_DBG] Верификация модуля ${moduleType} не удалась: ${verificationResult.error || verificationResult.message}`); logger.warn(`⚠️ Верификация модуля ${moduleType} не удалась: ${verificationResult.error || verificationResult.message}`); } } catch (verificationError) { results[moduleType].verification = 'error'; results[moduleType].verificationError = verificationError.message; - deploymentWebSocketService.addDeploymentLog(dleAddress, 'warning', `Ошибка при верификации модуля ${moduleType}: ${verificationError.message}`); + logger.error(`[MODULES_DBG] Ошибка при верификации модуля ${moduleType}: ${verificationError.message}`); logger.error(`❌ Ошибка при верификации модуля ${moduleType}: ${verificationError.message}`); } } else { @@ -499,7 +498,7 @@ async function deployAllModulesInNetwork(rpcUrl, pk, salt, dleAddress, modulesTo success: false, error: error.message }; - deploymentWebSocketService.addDeploymentLog(dleAddress, 'error', `Ошибка деплоя модуля ${moduleType} в сети ${net.name || net.chainId}: ${error.message}`); + logger.error(`[MODULES_DBG] Ошибка деплоя модуля ${moduleType} в сети ${net.name || net.chainId}: ${error.message}`); } } @@ -529,14 +528,21 @@ async function deployAllModulesInAllNetworks(networks, pk, salt, dleAddress, mod async function main() { const { ethers } = hre; - // Обрабатываем аргументы командной строки + // Обрабатываем аргументы командной строки и переменные окружения const args = process.argv.slice(2); let moduleTypeFromArgs = null; - for (let i = 0; i < args.length; i++) { - if (args[i] === '--module-type' && i + 1 < args.length) { - moduleTypeFromArgs = args[i + 1]; - break; + // Сначала проверяем переменные окружения + if (process.env.MODULE_TYPE) { + moduleTypeFromArgs = process.env.MODULE_TYPE; + logger.info(`🔍 Модуль из переменной окружения: ${moduleTypeFromArgs}`); + } else { + // Затем проверяем аргументы командной строки + for (let i = 0; i < args.length; i++) { + if (args[i] === '--module-type' && i + 1 < args.length) { + moduleTypeFromArgs = args[i + 1]; + break; + } } } @@ -550,7 +556,7 @@ async function main() { // Проверяем, передан ли конкретный deploymentId const deploymentId = process.env.DEPLOYMENT_ID; - if (deploymentId) { + if (deploymentId && deploymentId !== 'latest') { logger.info(`🔍 Ищем параметры для deploymentId: ${deploymentId}`); params = await deployParamsService.getDeployParams(deploymentId); if (params) { @@ -560,6 +566,7 @@ async function main() { } } else { // Получаем последние параметры деплоя + logger.info(`🔍 Получаем последние параметры деплоя (deploymentId: ${deploymentId})`); const latestParams = await deployParamsService.getLatestDeployParams(1); if (latestParams.length > 0) { params = latestParams[0]; @@ -613,11 +620,9 @@ async function main() { // Уведомляем WebSocket клиентов о начале деплоя if (moduleTypeFromArgs) { - deploymentWebSocketService.startDeploymentSession(dleAddress, moduleTypeFromArgs); - deploymentWebSocketService.addDeploymentLog(dleAddress, 'info', `Начало деплоя модуля ${moduleTypeFromArgs}`); + logger.info(`[MODULES_DBG] Начало деплоя модуля ${moduleTypeFromArgs}`); } else { - deploymentWebSocketService.startDeploymentSession(dleAddress, modulesToDeploy.join(', ')); - deploymentWebSocketService.addDeploymentLog(dleAddress, 'info', `Начало деплоя модулей: ${modulesToDeploy.join(', ')}`); + logger.info(`[MODULES_DBG] Начало деплоя модулей: ${modulesToDeploy.join(', ')}`); } // Устанавливаем API ключ Etherscan из базы данных, если доступен @@ -710,7 +715,7 @@ async function main() { logger.info(`[MODULES_DBG] 📡 Network ${networkIndex + 1} chainId: ${chainId}`); - const result = await deployAllModulesInNetwork(rpcUrl, pk, salt, dleAddress, modulesToDeploy, moduleInits, targetNonces); + const result = await deployAllModulesInNetwork(rpcUrl, pk, salt, dleAddress, modulesToDeploy, moduleInits, targetNonces, params); logger.info(`[MODULES_DBG] ✅ Network ${networkIndex + 1} (chainId: ${chainId}) deployment SUCCESS`); return { rpcUrl, chainId, ...result }; } catch (error) { @@ -813,7 +818,7 @@ async function main() { for (let i = 0; i < networks.length; i++) { const rpcUrl = networks[i]; const deployResult = deployResults[i]; - const verificationResult = verificationResults[i]; + const verificationResult = deployResult.verification || 'unknown'; const moduleResult = deployResult.modules?.[moduleType]; const verification = verificationResult?.modules?.[moduleType] || 'unknown'; @@ -916,15 +921,15 @@ async function main() { logger.info(`[MODULES_DBG] successCount: ${successCount}, totalCount: ${totalCount}`); if (successCount === totalCount) { - logger.info(`[MODULES_DBG] Вызываем finishDeploymentSession с success=true`); - deploymentWebSocketService.finishDeploymentSession(dleAddress, true, `Деплой завершен успешно! Задеплоено ${successCount} из ${totalCount} модулей`); + logger.info(`[MODULES_DBG] Деплой завершен успешно! Задеплоено ${successCount} из ${totalCount} модулей`); } else { - logger.info(`[MODULES_DBG] Вызываем finishDeploymentSession с success=false`); - deploymentWebSocketService.finishDeploymentSession(dleAddress, false, `Деплой завершен с ошибками. Задеплоено ${successCount} из ${totalCount} модулей`); + logger.info(`[MODULES_DBG] Деплой завершен с ошибками. Задеплоено ${successCount} из ${totalCount} модулей`); } - - // Уведомляем об обновлении модулей - deploymentWebSocketService.notifyModulesUpdated(dleAddress); } -main().catch((e) => { logger.error(e); process.exit(1); }); +main().catch((e) => { + logger.error('❌ Критическая ошибка в main():', e.message); + logger.error('❌ Stack trace:', e.stack); + logger.error('❌ Error details:', e); + process.exit(1); +}); diff --git a/backend/scripts/deploy/deploy-multichain.js b/backend/scripts/deploy/deploy-multichain.js index bcf5a65..1a73912 100755 --- a/backend/scripts/deploy/deploy-multichain.js +++ b/backend/scripts/deploy/deploy-multichain.js @@ -501,7 +501,7 @@ async function deployInNetwork(rpcUrl, pk, initCodeHash, targetDLENonce, dleInit } } - const rc = await tx.wait(); + const rc = await tx.wait(2); // Ждем 2 подтверждения с таймаутом // Отмечаем транзакцию как подтвержденную в NonceManager nonceManager.markTransactionConfirmed(wallet.address, chainId, tx.hash); @@ -522,11 +522,22 @@ async function deployInNetwork(rpcUrl, pk, initCodeHash, targetDLENonce, dleInit const DLE = await hre.ethers.getContractFactory('contracts/DLE.sol:DLE'); const dleContract = DLE.attach(deployedAddress); - const logoTx = await dleContract.connect(wallet).initializeLogoURI(params.logoURI, feeOverrides); - await logoTx.wait(); - logger.info(`[MULTI_DBG] chainId=${Number(net.chainId)} logoURI initialized successfully`); + // Проверяем текущий логотип перед инициализацией + const currentLogo = await dleContract.logoURI(); + logger.info(`[MULTI_DBG] chainId=${Number(net.chainId)} current logoURI: ${currentLogo}`); + + if (currentLogo === '' || currentLogo === '0x') { + logger.info(`[MULTI_DBG] chainId=${Number(net.chainId)} logoURI is empty, initializing...`); + const logoTx = await dleContract.connect(wallet).initializeLogoURI(params.logoURI, feeOverrides); + logger.info(`[MULTI_DBG] chainId=${Number(net.chainId)} logoURI transaction sent: ${logoTx.hash}`); + await logoTx.wait(2); // Ждем 2 подтверждения с таймаутом + logger.info(`[MULTI_DBG] chainId=${Number(net.chainId)} logoURI initialized successfully`); + } else { + logger.info(`[MULTI_DBG] chainId=${Number(net.chainId)} logoURI already set: ${currentLogo}, skipping initialization`); + } } catch (error) { - logger.info(`[MULTI_DBG] chainId=${Number(net.chainId)} logoURI initialization failed: ${error.message}`); + logger.error(`[MULTI_DBG] chainId=${Number(net.chainId)} logoURI initialization failed: ${error.message}`); + logger.error(`[MULTI_DBG] chainId=${Number(net.chainId)} error stack: ${error.stack}`); // Не прерываем деплой из-за ошибки логотипа } } else { diff --git a/backend/services/deploymentWebSocketService.js b/backend/services/deploymentWebSocketService.js index e7426a4..4e93c39 100644 --- a/backend/services/deploymentWebSocketService.js +++ b/backend/services/deploymentWebSocketService.js @@ -15,12 +15,20 @@ class DeploymentWebSocketService { /** * Инициализация WebSocket сервера */ - initialize(server) { - // Теперь мы не создаем отдельный WebSocket сервер, - // а работаем с основным WebSocket сервером через wsHub + initialize(server, wss) { + // Сохраняем ссылку на WebSocket сервер для отправки сообщений + this.wss = wss; console.log('[DeploymentWS] WebSocket сервис для деплоя инициализирован'); } + /** + * Установка WebSocket сервера (дополнительная инициализация) + */ + setWebSocketServer(wss) { + this.wss = wss; + console.log('[DeploymentWS] WebSocket сервер установлен, wss:', !!wss, 'clients:', wss ? wss.clients.size : 'N/A'); + } + /** * Обработка входящих сообщений */ @@ -220,12 +228,22 @@ class DeploymentWebSocketService { * Отправка сообщения всем клиентам конкретного DLE */ broadcastToDLE(dleAddress, message) { - const clients = this.clients.get(dleAddress); - if (clients) { - clients.forEach(ws => { - this.sendToClient(ws, message); - }); + console.log('[DeploymentWS] broadcastToDLE вызвана, this.wss:', !!this.wss); + if (!this.wss) { + console.warn('[DeploymentWS] WebSocket сервер не инициализирован'); + return; } + + // Отправляем сообщение всем подключенным клиентам + this.wss.clients.forEach(ws => { + if (ws.readyState === WebSocket.OPEN) { + try { + ws.send(JSON.stringify(message)); + } catch (error) { + console.error('[DeploymentWS] Ошибка отправки сообщения:', error); + } + } + }); } /** diff --git a/backend/wsHub.js b/backend/wsHub.js index b8bb61f..f277c92 100644 --- a/backend/wsHub.js +++ b/backend/wsHub.js @@ -31,11 +31,19 @@ function initWSS(server) { wss = new WebSocket.Server({ server, path: '/ws' }); console.log('🔌 [WebSocket] Сервер инициализирован на пути /ws'); + // Инициализируем deploymentWebSocketService с WebSocket сервером после создания wss + deploymentWebSocketService.initialize(server, wss); + // Подключаем deployment tracker к WebSocket deploymentTracker.on('deployment_updated', (data) => { broadcastDeploymentUpdate(data); }); + // Дополнительная инициализация deploymentWebSocketService после создания wss + console.log('[wsHub] Инициализируем deploymentWebSocketService с wss:', !!wss); + deploymentWebSocketService.setWebSocketServer(wss); + console.log('[wsHub] deploymentWebSocketService инициализирован'); + wss.on('connection', (ws, req) => { console.log('🔌 [WebSocket] Новое подключение'); console.log('🔌 [WebSocket] IP клиента:', req.socket.remoteAddress); @@ -500,34 +508,7 @@ function broadcastDeploymentUpdate(data) { console.log(`📡 [WebSocket] Отправлено deployment update: deployment_update`); } -// Функция для уведомления об обновлениях модулей -function broadcastModulesUpdate(dleAddress, updateType, moduleData) { - if (!wss) return; - - console.log(`📡 [WebSocket] broadcastModulesUpdate вызвана для DLE: ${dleAddress}, тип: ${updateType}`); - - const message = JSON.stringify({ - type: updateType, - dleAddress: dleAddress, - moduleData: moduleData, - timestamp: Date.now() - }); - - console.log(`📡 [WebSocket] Отправляем сообщение модулей:`, message); - - // Отправляем всем подключенным клиентам - wss.clients.forEach(client => { - if (client.readyState === WebSocket.OPEN) { - try { - client.send(message); - } catch (error) { - console.error('[WebSocket] Ошибка при отправке modules update:', error); - } - } - }); - - console.log(`📡 [WebSocket] Отправлено modules update: ${updateType} для DLE: ${dleAddress}`); -} +// broadcastModulesUpdate удалена - используем deploymentWebSocketService.broadcastToDLE module.exports = { initWSS, @@ -548,7 +529,6 @@ module.exports = { broadcastTokenBalancesUpdate, broadcastTokenBalanceChanged, broadcastDeploymentUpdate, - broadcastModulesUpdate, getConnectedUsers, getStats }; diff --git a/frontend/src/views/smartcontracts/ModulesView.vue b/frontend/src/views/smartcontracts/ModulesView.vue index 93a0a13..0f66252 100644 --- a/frontend/src/views/smartcontracts/ModulesView.vue +++ b/frontend/src/views/smartcontracts/ModulesView.vue @@ -1207,6 +1207,12 @@ function connectModulesWebSocket() { function handleModulesWebSocketMessage(data) { console.log('[ModulesView] WebSocket модулей сообщение:', data); + // Обрабатываем deployment_log в модульном WebSocket + if (data.type === 'deployment_log') { + addLog(data.log.type, data.log.message); + return; + } + // Обрабатываем только сообщения, связанные с модулями, не с деплоем if (data.type && data.type.startsWith('deployment_')) { console.log('[ModulesView] Пропускаем сообщение о деплое в модульном WebSocket');