diff --git a/src/Charts2/Components/metricsService.jsx b/src/Charts2/Components/metricsService.jsx
index 644c14a..4a0dd48 100644
--- a/src/Charts2/Components/metricsService.jsx
+++ b/src/Charts2/Components/metricsService.jsx
@@ -2,125 +2,102 @@ import { io } from 'socket.io-client';
class MetricsService {
constructor(baseUrl) {
- console.log('MetricsService constructor');
this.baseUrl = baseUrl || window.location.origin;
this.socket = null;
this.subscriptions = new Map();
+ this.pendingRequests = new Map();
}
- // HTTP методы - адаптированы под ваш бэкенд
- async fetchMetricsRange(metric, start, end, step = 15) {
- try {
- // Формируем URL согласно вашему API
- const url = new URL(`${this.baseUrl}/api/metrics`);
- url.searchParams.append('metric', metric);
- url.searchParams.append('start', start);
- url.searchParams.append('end', end);
- url.searchParams.append('step', step);
-
- console.log('Fetching metrics range from:', url.toString());
-
- const response = await fetch(url.toString());
-
- if (!response.ok) {
- const errorText = await response.text();
- throw new Error(`HTTP ${response.status}: ${errorText}`);
- }
-
- const data = await response.json();
-
- // Проверяем формат данных
- if (!Array.isArray(data)) {
- console.error('Unexpected data format:', data);
- throw new Error('Invalid data format: expected array');
- }
-
- return data;
- } catch (error) {
- console.error('Error in fetchMetricsRange:', error);
- throw error;
- }
- }
-
- async fetchMetrics(metric) {
- try {
- // Формируем URL для текущих метрик
- const url = new URL(`${this.baseUrl}/api/metrics`);
- url.searchParams.append('metric', metric);
-
- console.log('Fetching current metrics from:', url.toString());
-
- const response = await fetch(url.toString());
-
- if (!response.ok) {
- const errorText = await response.text();
- throw new Error(`HTTP ${response.status}: ${errorText}`);
- }
-
- const data = await response.json();
-
- // Проверяем формат данных
- if (!Array.isArray(data)) {
- console.error('Unexpected data format:', data);
- throw new Error('Invalid data format: expected array');
- }
-
- return data;
- } catch (error) {
- console.error('Error in fetchMetrics:', error);
- throw error;
- }
- }
-
- // WebSocket методы - остаются без изменений
+ // Инициализация WebSocket соединения
connectWebSocket() {
if (this.socket && this.socket.connected) return;
- console.trace('connectWebSocket called');
- this.socket = io(`${this.baseUrl}/api/metrics-ws`, {
+
+ this.socket = io(`${this.baseUrl.replace('http', 'ws')}/api/metrics-ws`, {
transports: ['websocket'],
withCredentials: true,
});
-
+
this.socket.on('connect', () => {
- console.log('Socket.IO connected');
- // Подписаться заново на все метрики
- for (const [metric, callbacks] of this.subscriptions.entries()) {
+ console.log('WebSocket connected');
+ // Восстанавливаем подписки при переподключении
+ this.subscriptions.forEach((_, metric) => {
this.socket.emit('subscribe-metric', { metric });
- }
+ });
});
-
+
this.socket.on('disconnect', () => {
- console.log('Socket.IO disconnected');
+ console.log('WebSocket disconnected');
});
-
- this.socket.on('metrics-data', ({ metric, data }) => {
+
+ this.socket.on('metrics-data', ({ metric, data, requestId }) => {
+ // Обработка исторических данных
+ if (requestId && this.pendingRequests.has(requestId)) {
+ const { resolve } = this.pendingRequests.get(requestId);
+ resolve(data);
+ this.pendingRequests.delete(requestId);
+ return;
+ }
+
+ // Обработка реального времени
const callbacks = this.subscriptions.get(metric) || [];
callbacks.forEach(cb => cb(data));
});
-
- this.socket.on('metrics-error', payload => {
- console.error('Metrics error:', payload);
+
+ this.socket.on('metrics-error', ({ error, requestId }) => {
+ if (requestId && this.pendingRequests.has(requestId)) {
+ const { reject } = this.pendingRequests.get(requestId);
+ reject(new Error(error));
+ this.pendingRequests.delete(requestId);
+ }
});
}
+ // Запрос исторических данных через WebSocket
+ async fetchMetricsRange(metric, start, end, step = 15) {
+ return new Promise((resolve, reject) => {
+ this.connectWebSocket();
+
+ const requestId = `range-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
+ this.pendingRequests.set(requestId, { resolve, reject });
+
+ this.socket.emit('get-metrics', {
+ metric,
+ start,
+ end,
+ step,
+ isRangeQuery: true,
+ requestId
+ });
+
+ // Таймаут запроса
+ setTimeout(() => {
+ if (this.pendingRequests.has(requestId)) {
+ this.pendingRequests.delete(requestId);
+ reject(new Error('Request timeout'));
+ }
+ }, 30000);
+ });
+ }
+
+ // Подписка на обновления в реальном времени
subscribeToMetric(metric, callback, interval = 5000) {
this.connectWebSocket();
-
+
if (!this.subscriptions.has(metric)) {
this.subscriptions.set(metric, []);
this.socket.emit('subscribe-metric', { metric, interval });
}
-
+
this.subscriptions.get(metric).push(callback);
-
+
return () => this.unsubscribeFromMetric(metric, callback);
}
-
+ // Отписка от метрики
unsubscribeFromMetric(metric, callback) {
const callbacks = this.subscriptions.get(metric) || [];
const filtered = callbacks.filter(cb => cb !== callback);
-
+
if (filtered.length === 0) {
this.subscriptions.delete(metric);
if (this.socket && this.socket.connected) {
@@ -130,8 +107,8 @@ class MetricsService {
this.subscriptions.set(metric, filtered);
}
}
-
+ // Закрытие соединения
disconnectWebSocket() {
if (this.socket) {
this.socket.close();
diff --git a/src/Components/Layout/SidebarMenu.jsx b/src/Components/Layout/SidebarMenu.jsx
index f0ba272..0735dda 100644
--- a/src/Components/Layout/SidebarMenu.jsx
+++ b/src/Components/Layout/SidebarMenu.jsx
@@ -19,6 +19,7 @@ import {
import MenuItem from "./SidebarMenuComponents/MenuItem";
import SidebarFooter from "./SidebarMenuComponents/SidebarFooter";
import { statusManager1 } from "../TreeChart/dataUtils";
+import tabContent from "../TreeChart/tabContent";
const SidebarResizer = styled('div')(({ theme }) => ({
diff --git a/src/Components/TreeChart/tabContent.jsx b/src/Components/TreeChart/tabContent.jsx
index 8b6ce63..6021f3a 100755
--- a/src/Components/TreeChart/tabContent.jsx
+++ b/src/Components/TreeChart/tabContent.jsx
@@ -5,7 +5,6 @@ import Box from '@mui/material/Box';
const PrometheusChart = lazy(() => import('../../Charts2/PrometheusChart'));
import LazyChartBatchRenderer from "../hooks/LazyChartBatchRender";
-// Функция для генерации названия метрики на основе id
const getMetricName = (id) => {
return `zvks_apiforsnmp_measure_${id}`;
};
@@ -13,11 +12,11 @@ const getMetricName = (id) => {
const getAllChildIds = (node) => {
let ids = [];
if (node.id) {
- ids.push(node.id);
+ ids.push(node.id);
}
if (node.items && node.items.length > 0) {
node.items.forEach((child) => {
- ids = ids.concat(getAllChildIds(child));
+ ids = ids.concat(getAllChildIds(child));
});
}
return ids;
@@ -26,8 +25,8 @@ const getAllChildIds = (node) => {
// Компонент Skeleton для графика
const ChartSkeleton = () => (
-
-
+
+
);
@@ -35,7 +34,7 @@ const ChartSkeleton = () => (
const ContainerSkeleton = () => (
{/* Заголовок */}
-
+
{[...Array(3)].map((_, i) => (