const express = require('express'); const router = express.Router(); const { requireAdmin } = require('../middleware/auth'); const logger = require('../utils/logger'); const { ethers } = require('ethers'); const rpcProviderService = require('../services/rpcProviderService'); const authTokenService = require('../services/authTokenService'); // Логируем версию ethers для отладки logger.info(`Ethers version: ${ethers.version || 'unknown'}`); // Получение RPC настроек router.get('/rpc', requireAdmin, async (req, res) => { try { const rpcConfigs = await rpcProviderService.getAllRpcProviders(); res.json({ success: true, data: rpcConfigs }); } catch (error) { logger.error('Ошибка при получении RPC настроек:', error); res.status(500).json({ success: false, error: 'Ошибка сервера при получении настроек RPC' }); } }); // Добавление/обновление одного или нескольких RPC router.post('/rpc', requireAdmin, async (req, res) => { try { // Если пришёл массив rpcConfigs — bulk-режим if (Array.isArray(req.body.rpcConfigs)) { const rpcConfigs = req.body.rpcConfigs; if (!rpcConfigs.length) { return res.status(400).json({ success: false, error: 'rpcConfigs не может быть пустым массивом' }); } await rpcProviderService.saveAllRpcProviders(rpcConfigs); return res.json({ success: true, message: 'RPC провайдеры успешно сохранены (bulk)' }); } // Иначе — одиночный режим (старый) const { networkId, rpcUrl, chainId } = req.body; if (!networkId || !rpcUrl) { return res.status(400).json({ success: false, error: 'networkId и rpcUrl обязательны' }); } await rpcProviderService.upsertRpcProvider({ networkId, rpcUrl, chainId }); res.json({ success: true, message: 'RPC провайдер сохранён' }); } catch (error) { logger.error('Ошибка при сохранении RPC:', error); res.status(500).json({ success: false, error: 'Ошибка сервера при сохранении RPC' }); } }); // Удаление одного RPC router.delete('/rpc/:networkId', requireAdmin, async (req, res) => { try { const { networkId } = req.params; await rpcProviderService.deleteRpcProvider(networkId); res.json({ success: true, message: 'RPC провайдер удалён' }); } catch (error) { logger.error('Ошибка при удалении RPC:', error); res.status(500).json({ success: false, error: 'Ошибка сервера при удалении RPC' }); } }); // Получение токенов для аутентификации router.get('/auth-tokens', requireAdmin, async (req, res) => { try { const authTokens = await authTokenService.getAllAuthTokens(); res.json({ success: true, data: authTokens }); } catch (error) { logger.error('Ошибка при получении токенов аутентификации:', error); res.status(500).json({ success: false, error: 'Ошибка сервера при получении токенов аутентификации' }); } }); // Сохранение токенов для аутентификации router.post('/auth-tokens', requireAdmin, async (req, res) => { try { const { authTokens } = req.body; if (!Array.isArray(authTokens)) { return res.status(400).json({ success: false, error: 'Неверный формат данных' }); } await authTokenService.saveAllAuthTokens(authTokens); res.json({ success: true, message: 'Токены аутентификации успешно сохранены' }); } catch (error) { logger.error('Ошибка при сохранении токенов аутентификации:', error); res.status(500).json({ success: false, error: 'Ошибка сервера при сохранении токенов аутентификации' }); } }); // Добавление/обновление одного токена router.post('/auth-token', requireAdmin, async (req, res) => { try { const { name, address, network, minBalance } = req.body; if (!name || !address || !network) { return res.status(400).json({ success: false, error: 'name, address и network обязательны' }); } await authTokenService.upsertAuthToken({ name, address, network, minBalance }); res.json({ success: true, message: 'Токен аутентификации сохранён' }); } catch (error) { logger.error('Ошибка при сохранении токена аутентификации:', error); res.status(500).json({ success: false, error: 'Ошибка сервера при сохранении токена' }); } }); // Удаление одного токена router.delete('/auth-token/:address/:network', requireAdmin, async (req, res) => { try { const { address, network } = req.params; await authTokenService.deleteAuthToken(address, network); res.json({ success: true, message: 'Токен аутентификации удалён' }); } catch (error) { logger.error('Ошибка при удалении токена аутентификации:', error); res.status(500).json({ success: false, error: 'Ошибка сервера при удалении токена' }); } }); // Тестирование RPC соединения router.post('/rpc-test', requireAdmin, async (req, res) => { try { const { rpcUrl, networkId } = req.body; if (!rpcUrl || !networkId) { return res.status(400).json({ success: false, error: 'Необходимо указать URL и ID сети' }); } logger.info(`Тестирование RPC для ${networkId}: ${rpcUrl}`); try { // Пробуем создать провайдера и получить номер последнего блока (обновлено для ethers v6) let provider; if (rpcUrl.startsWith('ws://') || rpcUrl.startsWith('wss://')) { provider = new ethers.WebSocketProvider(rpcUrl); } else { provider = new ethers.JsonRpcProvider(rpcUrl); } // Устанавливаем таймаут для соединения const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error('Таймаут соединения')), 10000) ); // Пробуем получить номер последнего блока с таймаутом const blockNumber = await Promise.race([ provider.getBlockNumber(), timeoutPromise ]); logger.info(`Успешное тестирование RPC для ${networkId}: ${rpcUrl}, номер блока: ${blockNumber}`); res.json({ success: true, message: `Успешное соединение с ${networkId}`, blockNumber }); } catch (providerError) { logger.error(`Ошибка провайдера при тестировании RPC для ${networkId}: ${providerError.message}`); res.status(500).json({ success: false, error: providerError.message || 'Не удалось подключиться к RPC провайдеру' }); } } catch (error) { logger.error(`Неожиданная ошибка при тестировании RPC: ${error.message}`); res.status(500).json({ success: false, error: error.message || 'Неизвестная ошибка сервера' }); } }); module.exports = router;