UNPKG

standalone-toolbar-service

Version:

独立的Stagewise工具栏服务 - 支持SRPC通信和WebSocket广播,可与MCP反馈收集器集成

143 lines (142 loc) 5.41 kB
import { WebSocketServer } from 'ws'; export class SRPCWebSocketBridge { constructor(server) { this.connections = new Map(); this.methods = {}; this.wss = new WebSocketServer({ server }); this.wss.on('connection', (ws) => { const connectionId = `conn_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; console.log(`[SRPC] WebSocket client connected: ${connectionId}`); this.connections.set(connectionId, ws); this.setupWebSocketHandlers(ws, connectionId); ws.on('close', () => { console.log(`[SRPC] WebSocket client disconnected: ${connectionId}`); this.connections.delete(connectionId); }); }); } register(methodHandlers) { Object.entries(methodHandlers).forEach(([methodName, handler]) => { this.methods[methodName] = { handler }; console.log(`[SRPC] Registered RPC method: ${methodName}`); }); } setupWebSocketHandlers(ws, connectionId) { ws.on('message', (data) => { try { const message = JSON.parse(data.toString()); console.log(`[SRPC] Received message from ${connectionId}:`, message); this.handleMessage(message, ws, connectionId); } catch (error) { console.error(`[SRPC] Error handling WebSocket message from ${connectionId}:`, error); } }); ws.on('error', (error) => { console.error(`[SRPC] WebSocket error for ${connectionId}:`, error); }); } handleMessage(message, ws, connectionId) { const { messageType } = message; switch (messageType) { case 'request': this.handleRequest(message, ws, connectionId); break; case 'response': console.log(`[SRPC] Received response from ${connectionId}:`, message); break; case 'update': console.log(`[SRPC] Received update from ${connectionId}:`, message); break; case 'error': console.error(`[SRPC] Received error from ${connectionId}:`, message); break; default: console.warn(`[SRPC] Unknown message type from ${connectionId}: ${messageType}`); } } async handleRequest(message, ws, connectionId) { const { id, method, payload } = message; if (!method) { this.sendError(id, 'Method name is required', ws, connectionId); return; } const methodDef = this.methods[method]; if (!methodDef) { this.sendError(id, `Method not found: ${method}`, ws, connectionId); return; } try { console.log(`[SRPC] Calling method: ${method} with payload from ${connectionId}:`, payload); const sendUpdate = (update) => { this.sendUpdate(id, method, update, ws, connectionId); }; const result = await methodDef.handler(payload, sendUpdate); this.sendResponse(id, method, result, ws, connectionId); } catch (error) { this.sendError(id, error instanceof Error ? error.message : String(error), ws, connectionId); } } sendResponse(id, method, payload, ws, connectionId) { if (!ws || ws.readyState !== ws.OPEN) { throw new Error(`WebSocket connection ${connectionId} is not open`); } const responseMessage = { id, messageType: 'response', method, payload, }; console.log(`[SRPC] Sending response to ${connectionId}:`, responseMessage); ws.send(JSON.stringify(responseMessage)); } sendUpdate(id, method, payload, ws, connectionId) { if (!ws || ws.readyState !== ws.OPEN) { throw new Error(`WebSocket connection ${connectionId} is not open`); } const updateMessage = { id, messageType: 'update', method, payload, }; console.log(`[SRPC] Sending update to ${connectionId}:`, updateMessage); ws.send(JSON.stringify(updateMessage)); } sendError(id, errorMessage, ws, connectionId) { if (!ws || ws.readyState !== ws.OPEN) { throw new Error(`WebSocket connection ${connectionId} is not open`); } const errorResponse = { id, messageType: 'error', error: { message: errorMessage, }, }; console.log(`[SRPC] Sending error to ${connectionId}:`, errorResponse); ws.send(JSON.stringify(errorResponse)); } isConnected() { return this.connections.size > 0; } getConnectionCount() { return this.connections.size; } getRegisteredMethods() { return Object.keys(this.methods); } close() { console.log('[SRPC] Closing WebSocket server'); this.wss.close(); this.connections.forEach((ws, connectionId) => { console.log(`[SRPC] Closing connection: ${connectionId}`); ws.close(); }); this.connections.clear(); } } export function createSRPCBridge(server) { return new SRPCWebSocketBridge(server); }