From 6dee0fa0b498d82c3666898b557c601aa560301d Mon Sep 17 00:00:00 2001 From: Denis Shatskiy Date: Tue, 5 Aug 2025 21:39:58 +0700 Subject: [PATCH] feat: Refactor S3 last modified endpoint and Dashboard data fetching to handle errors gracefully --- backend/server.js | 38 +++++++++++++++++++++++++-------- frontend/src/Dashboard.jsx | 43 +++++++++++++++++++++++++++----------- 2 files changed, 60 insertions(+), 21 deletions(-) diff --git a/backend/server.js b/backend/server.js index b42aef3..b574b0a 100644 --- a/backend/server.js +++ b/backend/server.js @@ -436,22 +436,42 @@ app.post('/api/filters', async (req, res) => { // Новый эндпоинт для получения дат последнего изменения файлов S3 app.get('/api/s3/last-modified', async (req, res) => { try { - const [domainsHead, domainsNewHead, asnsHead, serversHead, filtersHead] = await Promise.all([ + const results = await Promise.allSettled([ s3.headObject({ Bucket: BUCKET_NAME, Key: 'bgp_data/domains.txt' }).promise(), s3.headObject({ Bucket: BUCKET_NAME, Key: 'bgp_data/domains_community.txt' }).promise(), s3.headObject({ Bucket: BUCKET_NAME, Key: 'bgp_data/asns.txt' }).promise(), s3.headObject({ Bucket: BUCKET_NAME, Key: 'servers.json' }).promise(), s3.headObject({ Bucket: BUCKET_NAME, Key: 'filters.json' }).promise() ]); - res.json({ - domainsLastModified: domainsHead.LastModified ? domainsHead.LastModified.toISOString() : null, - domainsNewLastModified: domainsNewHead.LastModified ? domainsNewHead.LastModified.toISOString() : null, - asnsLastModified: asnsHead.LastModified ? asnsHead.LastModified.toISOString() : null, - serversLastModified: serversHead.LastModified ? serversHead.LastModified.toISOString() : null, - filtersLastModified: filtersHead.LastModified ? filtersHead.LastModified.toISOString() : null - }); + + const response = { + domainsLastModified: null, + domainsNewLastModified: null, + asnsLastModified: null, + serversLastModified: null, + filtersLastModified: null + }; + + // Обрабатываем результаты + if (results[0].status === 'fulfilled') { + response.domainsLastModified = results[0].value.LastModified ? results[0].value.LastModified.toISOString() : null; + } + if (results[1].status === 'fulfilled') { + response.domainsNewLastModified = results[1].value.LastModified ? results[1].value.LastModified.toISOString() : null; + } + if (results[2].status === 'fulfilled') { + response.asnsLastModified = results[2].value.LastModified ? results[2].value.LastModified.toISOString() : null; + } + if (results[3].status === 'fulfilled') { + response.serversLastModified = results[3].value.LastModified ? results[3].value.LastModified.toISOString() : null; + } + if (results[4].status === 'fulfilled') { + response.filtersLastModified = results[4].value.LastModified ? results[4].value.LastModified.toISOString() : null; + } + + res.json(response); } catch (error) { - console.error(error); + console.error('Error fetching last modified dates from S3:', error); res.status(500).send('Error fetching last modified dates from S3'); } }); diff --git a/frontend/src/Dashboard.jsx b/frontend/src/Dashboard.jsx index d37296f..081d29d 100644 --- a/frontend/src/Dashboard.jsx +++ b/frontend/src/Dashboard.jsx @@ -78,7 +78,8 @@ function Dashboard() { setLoading(true); setError(null); try { - const [domainsRes, ipRangesRes, asnsRes, serversRes, s3Res] = await Promise.all([ + // Загружаем данные с обработкой ошибок для каждого endpoint + const results = await Promise.allSettled([ axios.get('/api/domains'), axios.get('/api/ip-ranges'), axios.get('/api/asns'), @@ -86,25 +87,43 @@ function Dashboard() { axios.get('/api/s3/last-modified') ]); - // Подсчет уникальных стран и провайдеров из серверов - const servers = serversRes.data; + // Обрабатываем результаты + const domainsRes = results[0]; + const ipRangesRes = results[1]; + const asnsRes = results[2]; + const serversRes = results[3]; + const s3Res = results[4]; + + // Получаем данные серверов для подсчета дополнительной статистики + const servers = serversRes.status === 'fulfilled' ? serversRes.value.data : []; const countries = new Set(servers.map(server => server.country).filter(Boolean)); const providers = new Set(servers.map(server => server.provider).filter(Boolean)); const onlineServers = servers.filter(server => server.status === 'Онлайн').length; + // Получаем дату последнего обновления + const lastModified = s3Res.status === 'fulfilled' && s3Res.value.data?.domainsLastModified + ? new Date(s3Res.value.data.domainsLastModified).toLocaleString() + : new Date().toLocaleString(); + setStats({ - domainsCount: domainsRes.data.length, - ipRangesCount: ipRangesRes.data.length, - asnsCount: asnsRes.data.length, + domainsCount: domainsRes.status === 'fulfilled' ? domainsRes.value.data.length : 0, + ipRangesCount: ipRangesRes.status === 'fulfilled' ? ipRangesRes.value.data.length : 0, + asnsCount: asnsRes.status === 'fulfilled' ? asnsRes.value.data.length : 0, serversCount: servers.length, - lastModified: s3Res.data?.domainsLastModified || null, + lastModified, countriesCount: countries.size, providersCount: providers.size, onlineServers, totalServers: servers.length }); + + // Проверяем, есть ли ошибки + const errors = results.filter(result => result.status === 'rejected'); + if (errors.length > 0) { + console.warn('Некоторые API недоступны:', errors.map(e => e.reason?.message)); + } } catch (e) { - console.error('Ошибка загрузки статистики:', e); + console.error('Критическая ошибка загрузки статистики:', e); setError('Не удалось загрузить статистику'); setStats({ domainsCount: null, @@ -250,11 +269,11 @@ function Dashboard() {