Files
DLE/backend/services/deploymentWebSocketService.js

301 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* WebSocket сервис для отслеживания деплоя модулей
* Обеспечивает реальное время обновления статуса деплоя
*/
const WebSocket = require('ws');
class DeploymentWebSocketService {
constructor() {
this.wss = null;
this.clients = new Map(); // Map для хранения клиентов по dleAddress
this.deploymentSessions = new Map(); // Map для хранения сессий деплоя
}
/**
* Инициализация WebSocket сервера
*/
initialize(server) {
// Теперь мы не создаем отдельный WebSocket сервер,
// а работаем с основным WebSocket сервером через wsHub
console.log('[DeploymentWS] WebSocket сервис для деплоя инициализирован');
}
/**
* Обработка входящих сообщений
*/
handleMessage(ws, data) {
switch (data.type) {
case 'subscribe':
this.subscribeToDeployment(ws, data.dleAddress);
break;
case 'unsubscribe':
this.unsubscribeFromDeployment(ws, data.dleAddress);
break;
default:
this.sendError(ws, 'Неизвестный тип сообщения');
}
}
/**
* Подписка на деплой для конкретного DLE
*/
subscribeToDeployment(ws, dleAddress) {
if (!dleAddress) {
this.sendError(ws, 'Адрес DLE обязателен');
return;
}
console.log(`[DeploymentWS] Подписка на деплой DLE: ${dleAddress}`);
// Сохраняем клиента
ws.dleAddress = dleAddress;
if (!this.clients.has(dleAddress)) {
this.clients.set(dleAddress, new Set());
}
this.clients.get(dleAddress).add(ws);
// Отправляем подтверждение подписки
this.sendToClient(ws, {
type: 'subscribed',
dleAddress: dleAddress,
message: 'Подписка на деплой активирована'
});
// Если есть активная сессия деплоя, отправляем текущий статус
if (this.deploymentSessions.has(dleAddress)) {
const session = this.deploymentSessions.get(dleAddress);
this.sendToClient(ws, {
type: 'deployment_status',
dleAddress: dleAddress,
...session
});
}
}
/**
* Отписка от деплоя
*/
unsubscribeFromDeployment(ws, dleAddress) {
if (ws.dleAddress === dleAddress) {
this.removeClient(ws);
}
}
/**
* Удаление клиента из всех подписок
*/
removeClient(ws) {
if (ws.dleAddress && this.clients.has(ws.dleAddress)) {
this.clients.get(ws.dleAddress).delete(ws);
if (this.clients.get(ws.dleAddress).size === 0) {
this.clients.delete(ws.dleAddress);
// Очищаем сессию деплоя если нет активных клиентов
if (this.deploymentSessions.has(ws.dleAddress)) {
console.log(`[DeploymentWS] Очистка сессии деплоя для DLE: ${ws.dleAddress}`);
this.deploymentSessions.delete(ws.dleAddress);
}
}
}
}
/**
* Начало сессии деплоя
*/
startDeploymentSession(dleAddress, moduleType) {
const session = {
dleAddress: dleAddress,
moduleType: moduleType,
status: 'starting',
progress: 0,
step: 0,
message: 'Инициализация деплоя...',
logs: [],
startTime: new Date().toISOString()
};
this.deploymentSessions.set(dleAddress, session);
console.log(`[DeploymentWS] Начало деплоя: ${moduleType} для DLE ${dleAddress}`);
this.broadcastToDLE(dleAddress, {
type: 'deployment_started',
...session
});
return session;
}
/**
* Обновление статуса деплоя
*/
updateDeploymentStatus(dleAddress, updates) {
const session = this.deploymentSessions.get(dleAddress);
if (!session) {
console.warn(`[DeploymentWS] Сессия деплоя не найдена для DLE: ${dleAddress}`);
return;
}
// Обновляем сессию
Object.assign(session, updates);
session.lastUpdate = new Date().toISOString();
console.log(`[DeploymentWS] Обновление статуса деплоя DLE ${dleAddress}:`, updates);
this.broadcastToDLE(dleAddress, {
type: 'deployment_status',
...session
});
}
/**
* Добавление лога в сессию деплоя
*/
addDeploymentLog(dleAddress, logType, message) {
const session = this.deploymentSessions.get(dleAddress);
if (!session) {
console.warn(`[DeploymentWS] Сессия деплоя не найдена для DLE: ${dleAddress}`);
return;
}
const logEntry = {
type: logType,
message: message,
timestamp: new Date().toISOString()
};
session.logs.push(logEntry);
console.log(`[DeploymentWS] Лог деплоя DLE ${dleAddress}:`, logEntry);
this.broadcastToDLE(dleAddress, {
type: 'deployment_log',
dleAddress: dleAddress,
log: logEntry
});
}
/**
* Завершение сессии деплоя
*/
finishDeploymentSession(dleAddress, success, message = null) {
const session = this.deploymentSessions.get(dleAddress);
if (!session) {
console.warn(`[DeploymentWS] Сессия деплоя не найдена для DLE: ${dleAddress}`);
return;
}
session.status = success ? 'completed' : 'failed';
session.progress = success ? 100 : session.progress;
session.endTime = new Date().toISOString();
session.message = message || (success ? 'Деплой завершен успешно' : 'Деплой завершен с ошибкой');
console.log(`[DeploymentWS] Завершение деплоя DLE ${dleAddress}: ${session.status}`);
this.broadcastToDLE(dleAddress, {
type: 'deployment_finished',
...session
});
// Удаляем сессию через 30 секунд
setTimeout(() => {
this.deploymentSessions.delete(dleAddress);
}, 30000);
}
/**
* Отправка сообщения конкретному клиенту
*/
sendToClient(ws, message) {
if (ws && ws.readyState === WebSocket.OPEN) {
try {
ws.send(JSON.stringify(message));
} catch (error) {
console.error('[DeploymentWS] Ошибка отправки сообщения клиенту:', error);
}
}
}
/**
* Отправка сообщения всем клиентам конкретного DLE
*/
broadcastToDLE(dleAddress, message) {
const clients = this.clients.get(dleAddress);
if (clients) {
clients.forEach(ws => {
this.sendToClient(ws, message);
});
}
}
/**
* Отправка ошибки клиенту
*/
sendError(ws, errorMessage) {
this.sendToClient(ws, {
type: 'error',
message: errorMessage
});
}
/**
* Уведомление об обновлении модулей
*/
notifyModulesUpdated(dleAddress) {
console.log(`[DeploymentWS] Уведомление об обновлении модулей для DLE: ${dleAddress}`);
this.broadcastToDLE(dleAddress, {
type: 'modules_updated',
dleAddress: dleAddress,
timestamp: new Date().toISOString()
});
}
/**
* Уведомление о верификации модуля
*/
notifyModuleVerified(dleAddress, moduleType, networkName) {
console.log(`[DeploymentWS] Уведомление о верификации модуля ${moduleType} в сети ${networkName} для DLE: ${dleAddress}`);
this.broadcastToDLE(dleAddress, {
type: 'module_verified',
dleAddress: dleAddress,
moduleType: moduleType,
networkName: networkName,
timestamp: new Date().toISOString()
});
}
/**
* Уведомление об изменении статуса модуля
*/
notifyModuleStatusChanged(dleAddress, moduleType, status) {
console.log(`[DeploymentWS] Уведомление об изменении статуса модуля ${moduleType} на ${status} для DLE: ${dleAddress}`);
this.broadcastToDLE(dleAddress, {
type: 'module_status_changed',
dleAddress: dleAddress,
moduleType: moduleType,
status: status,
timestamp: new Date().toISOString()
});
}
/**
* Получение статистики
*/
getStats() {
const totalClients = Array.from(this.clients.values()).reduce((sum, clients) => sum + clients.size, 0);
return {
activeConnections: totalClients,
activeSessions: this.deploymentSessions.size,
subscriptions: this.clients.size
};
}
}
// Создаем единственный экземпляр сервиса
const deploymentWebSocketService = new DeploymentWebSocketService();
module.exports = deploymentWebSocketService;