172 lines
4.7 KiB
JavaScript
172 lines
4.7 KiB
JavaScript
/**
|
|
* websocket-client模块 - 与ComfyUI实例的WebSocket通信
|
|
*/
|
|
|
|
import WebSocket from 'ws';
|
|
import logger from '../logger/index.js';
|
|
import EventEmitter from 'events';
|
|
import comfyUIMonitor from '../comfyui-monitor/index.js';
|
|
|
|
class WebSocketClient extends EventEmitter {
|
|
constructor() {
|
|
super();
|
|
this.connections = new Map();
|
|
}
|
|
|
|
/**
|
|
* 连接到指定实例
|
|
* @param {string} instanceId - 实例ID
|
|
* @param {string} wsUrl - WebSocket地址
|
|
* @returns {Promise<WebSocket>} WebSocket连接
|
|
*/
|
|
connect(instanceId, wsUrl) {
|
|
return new Promise((resolve, reject) => {
|
|
if (this.connections.has(instanceId)) {
|
|
const conn = this.connections.get(instanceId);
|
|
if (conn.readyState === WebSocket.OPEN) {
|
|
resolve(conn);
|
|
return;
|
|
}
|
|
}
|
|
|
|
logger.info(`正在连接到实例 ${instanceId}: ${wsUrl}`);
|
|
|
|
const ws = new WebSocket(wsUrl);
|
|
|
|
ws.on('open', () => {
|
|
logger.info(`成功连接到实例 ${instanceId}`);
|
|
this.connections.set(instanceId, ws);
|
|
|
|
const stateChange = comfyUIMonitor.setInstanceState(instanceId, 'connected');
|
|
if (stateChange) {
|
|
const config = { wsUrl };
|
|
comfyUIMonitor.logConnectionStateChange(
|
|
instanceId,
|
|
stateChange.oldState,
|
|
'connected',
|
|
'WebSocket连接成功',
|
|
config
|
|
);
|
|
}
|
|
|
|
resolve(ws);
|
|
});
|
|
|
|
ws.on('message', (data) => {
|
|
try {
|
|
const message = JSON.parse(data.toString());
|
|
this.handleMessage(instanceId, message);
|
|
} catch (error) {
|
|
logger.error(`解析消息失败 (${instanceId}):`, error);
|
|
}
|
|
});
|
|
|
|
ws.on('error', (error) => {
|
|
logger.error(`WebSocket连接错误 (${instanceId}):`, error);
|
|
|
|
const config = { wsUrl };
|
|
comfyUIMonitor.logConnectionError(instanceId, error, config);
|
|
|
|
reject(error);
|
|
});
|
|
|
|
ws.on('close', (code, reason) => {
|
|
logger.warn(`与实例 ${instanceId} 的连接已关闭`);
|
|
|
|
const stateChange = comfyUIMonitor.setInstanceState(instanceId, 'disconnected');
|
|
if (stateChange) {
|
|
const disconnectReason = reason ? reason.toString() : `关闭代码: ${code}`;
|
|
const config = { wsUrl, closeCode: code };
|
|
comfyUIMonitor.logConnectionStateChange(
|
|
instanceId,
|
|
stateChange.oldState,
|
|
'disconnected',
|
|
disconnectReason,
|
|
config
|
|
);
|
|
}
|
|
|
|
this.connections.delete(instanceId);
|
|
this.emit('disconnected', { instanceId });
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 处理收到的消息
|
|
* @param {string} instanceId - 实例ID
|
|
* @param {object} message - 消息对象
|
|
*/
|
|
handleMessage(instanceId, message) {
|
|
this.emit('message', { instanceId, message });
|
|
|
|
switch (message.type) {
|
|
case 'status':
|
|
this.emit('status', { instanceId, status: message.data });
|
|
break;
|
|
case 'progress':
|
|
this.emit('progress', { instanceId, data: message.data });
|
|
break;
|
|
case 'execution_start':
|
|
this.emit('execution_start', { instanceId, promptId: message.data.prompt_id });
|
|
break;
|
|
case 'execution_cached':
|
|
this.emit('execution_cached', { instanceId, data: message.data });
|
|
break;
|
|
case 'executed':
|
|
this.emit('executed', { instanceId, data: message.data });
|
|
break;
|
|
case 'execution_error':
|
|
this.emit('execution_error', { instanceId, data: message.data });
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 发送消息到指定实例
|
|
* @param {string} instanceId - 实例ID
|
|
* @param {object} message - 消息对象
|
|
*/
|
|
send(instanceId, message) {
|
|
const ws = this.connections.get(instanceId);
|
|
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
throw new Error(`实例 ${instanceId} 未连接`);
|
|
}
|
|
ws.send(JSON.stringify(message));
|
|
}
|
|
|
|
/**
|
|
* 断开指定实例的连接
|
|
* @param {string} instanceId - 实例ID
|
|
*/
|
|
disconnect(instanceId) {
|
|
const ws = this.connections.get(instanceId);
|
|
if (ws) {
|
|
ws.close();
|
|
this.connections.delete(instanceId);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 断开所有连接
|
|
*/
|
|
disconnectAll() {
|
|
for (const [instanceId, ws] of this.connections) {
|
|
ws.close();
|
|
}
|
|
this.connections.clear();
|
|
}
|
|
|
|
/**
|
|
* 检查实例是否已连接
|
|
* @param {string} instanceId - 实例ID
|
|
* @returns {boolean} 连接状态
|
|
*/
|
|
isConnected(instanceId) {
|
|
const ws = this.connections.get(instanceId);
|
|
return ws && ws.readyState === WebSocket.OPEN;
|
|
}
|
|
}
|
|
|
|
export default new WebSocketClient();
|