121 lines
3.3 KiB
JavaScript
121 lines
3.3 KiB
JavaScript
import { io } from 'socket.io-client';
|
|
|
|
class WebSocketManager {
|
|
constructor() {
|
|
this.socket = null;
|
|
this.subscribers = new Map();
|
|
this.connectionStatus = 'disconnected';
|
|
this.connectionCallbacks = new Set();
|
|
this.connecting = false;
|
|
}
|
|
|
|
connect() {
|
|
if (this.socket?.connected || this.connecting) {
|
|
return this.socket;
|
|
}
|
|
|
|
this.connecting = true;
|
|
|
|
this.socket = io(`${import.meta.env.VITE_BACK_WS_URL}/api/metrics-ws`, {
|
|
transports: ['websocket'],
|
|
reconnection: true,
|
|
reconnectionAttempts: Infinity,
|
|
reconnectionDelay: 1000,
|
|
reconnectionDelayMax: 5000,
|
|
});
|
|
|
|
this.socket.on('connect', () => {
|
|
this.connectionStatus = 'connected';
|
|
this.connecting = false;
|
|
this.notifyConnectionStatus();
|
|
});
|
|
|
|
this.socket.on('disconnect', (reason) => {
|
|
this.connectionStatus = 'disconnected';
|
|
this.connecting = false;
|
|
this.notifyConnectionStatus();
|
|
if (reason === 'io server disconnect') this.socket.connect();
|
|
});
|
|
|
|
this.socket.on('connect_error', (error) => {
|
|
this.connectionStatus = 'error';
|
|
this.notifyConnectionStatus();
|
|
setTimeout(() => this.socket.connect(), 1000);
|
|
});
|
|
|
|
this.socket.on('metrics-data', (response) => {
|
|
const callbacks = this.subscribers.get(response.metric);
|
|
if (callbacks) {
|
|
callbacks.forEach(callback => callback(response.data));
|
|
}
|
|
});
|
|
|
|
return this.socket;
|
|
}
|
|
|
|
subscribe(metricName, callback) {
|
|
if (!this.socket?.connected) {
|
|
this.connect();
|
|
}
|
|
|
|
if (!this.subscribers.has(metricName)) {
|
|
this.subscribers.set(metricName, new Set());
|
|
this.socket.emit('subscribe-metric', {
|
|
metric: metricName,
|
|
isSubscription: true // Флаг для подписки
|
|
});
|
|
}
|
|
|
|
this.subscribers.get(metricName).add(callback);
|
|
|
|
return () => this.unsubscribe(metricName, callback);
|
|
}
|
|
|
|
unsubscribe(metricName, callback) {
|
|
const callbacks = this.subscribers.get(metricName);
|
|
if (callbacks) {
|
|
callbacks.delete(callback);
|
|
if (callbacks.size === 0) {
|
|
this.subscribers.delete(metricName);
|
|
this.socket.emit('unsubscribe-metric', { metric: metricName });
|
|
}
|
|
}
|
|
}
|
|
|
|
getMetricsRange(metricName, start, end, step) {
|
|
return new Promise((resolve, reject) => {
|
|
const timer = setTimeout(() => {
|
|
reject(new Error('Timeout while waiting for metrics data'));
|
|
}, 10000);
|
|
|
|
// Временный обработчик для разового запроса
|
|
const tempHandler = (data) => {
|
|
clearTimeout(timer);
|
|
this.socket.off(`metrics-range-${metricName}`, tempHandler);
|
|
resolve(data);
|
|
};
|
|
|
|
this.socket.on(`metrics-range-${metricName}`, tempHandler);
|
|
this.socket.emit('get-metrics', {
|
|
metric: metricName,
|
|
start,
|
|
end,
|
|
step,
|
|
isRangeQuery: true // Флаг для разового запроса
|
|
});
|
|
});
|
|
}
|
|
|
|
onConnectionStatusChange(callback) {
|
|
this.connectionCallbacks.add(callback);
|
|
callback(this.connectionStatus);
|
|
return () => this.connectionCallbacks.delete(callback);
|
|
}
|
|
|
|
notifyConnectionStatus() {
|
|
this.connectionCallbacks.forEach(callback => callback(this.connectionStatus));
|
|
}
|
|
}
|
|
|
|
|
|
export const webSocketManager = new WebSocketManager(); |