Created a new chart

pull/40/head
DmitriyA 2025-05-22 06:29:58 -04:00
parent 4dfd972615
commit 2b79159d35
3 changed files with 69 additions and 92 deletions

View File

@ -2,107 +2,84 @@ 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();
@ -116,7 +93,7 @@ class MetricsService {
return () => this.unsubscribeFromMetric(metric, callback);
}
// Отписка от метрики
unsubscribeFromMetric(metric, callback) {
const callbacks = this.subscriptions.get(metric) || [];
const filtered = callbacks.filter(cb => cb !== callback);
@ -131,7 +108,7 @@ class MetricsService {
}
}
// Закрытие соединения
disconnectWebSocket() {
if (this.socket) {
this.socket.close();

View File

@ -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 }) => ({

View File

@ -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}`;
};