ваше сообщение коммита
This commit is contained in:
295
backend/services/deploymentWebSocketService.js
Normal file
295
backend/services/deploymentWebSocketService.js
Normal file
@@ -0,0 +1,295 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Начало сессии деплоя
|
||||
*/
|
||||
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;
|
||||
Reference in New Issue
Block a user