feat(flowEditor): 添加流程运行功能及WebSocket支持
- 在ActionBar组件中增加运行/停止按钮及状态控制 - 实现流程运行时的WebSocket连接管理 - 添加useWebSocket自定义hook处理WebSocket通信- 支持运行状态切换和实时消息处理 - 集成用户令牌认证和WebSocket地址配置 - 提供运行启动和停止的完整生命周期管理production
parent
11c796aa75
commit
0230119987
@ -0,0 +1,131 @@
|
|||||||
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
|
|
||||||
|
interface WebSocketOptions {
|
||||||
|
reconnectInterval?: number;
|
||||||
|
maxReconnectAttempts?: number;
|
||||||
|
onOpen?: (event: Event) => void;
|
||||||
|
onClose?: (event: CloseEvent) => void;
|
||||||
|
onError?: (event: Event) => void;
|
||||||
|
onMessage?: (event: MessageEvent) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WebSocketHook {
|
||||||
|
connect: (url: string) => void;
|
||||||
|
disconnect: () => void;
|
||||||
|
sendMessage: (message: string | object) => void;
|
||||||
|
readyState: number;
|
||||||
|
isConnected: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const useWebSocket = (options: WebSocketOptions = {}): WebSocketHook => {
|
||||||
|
const {
|
||||||
|
reconnectInterval = 3000,
|
||||||
|
maxReconnectAttempts = 0,
|
||||||
|
onOpen,
|
||||||
|
onClose,
|
||||||
|
onError,
|
||||||
|
onMessage
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const [readyState, setReadyState] = useState<number>(WebSocket.CLOSED);
|
||||||
|
const [isConnected, setIsConnected] = useState<boolean>(false);
|
||||||
|
const wsRef = useRef<WebSocket | null>(null);
|
||||||
|
const reconnectAttemptsRef = useRef<number>(0);
|
||||||
|
const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
const urlRef = useRef<string>('');
|
||||||
|
|
||||||
|
// 清理重连定时器
|
||||||
|
const clearReconnectTimeout = useCallback(() => {
|
||||||
|
if (reconnectTimeoutRef.current) {
|
||||||
|
clearTimeout(reconnectTimeoutRef.current);
|
||||||
|
reconnectTimeoutRef.current = null;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 断开连接
|
||||||
|
const disconnect = useCallback(() => {
|
||||||
|
clearReconnectTimeout();
|
||||||
|
if (wsRef.current) {
|
||||||
|
wsRef.current.close();
|
||||||
|
wsRef.current = null;
|
||||||
|
}
|
||||||
|
setReadyState(WebSocket.CLOSED);
|
||||||
|
setIsConnected(false);
|
||||||
|
}, [clearReconnectTimeout]);
|
||||||
|
|
||||||
|
// 发送消息
|
||||||
|
const sendMessage = useCallback((message: string | object) => {
|
||||||
|
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
|
||||||
|
const messageStr = typeof message === 'string' ? message : JSON.stringify(message);
|
||||||
|
wsRef.current.send(messageStr);
|
||||||
|
} else {
|
||||||
|
console.warn('WebSocket is not connected. Cannot send message.');
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 连接WebSocket
|
||||||
|
const connect = useCallback((url: string) => {
|
||||||
|
// 先断开现有连接
|
||||||
|
disconnect();
|
||||||
|
|
||||||
|
urlRef.current = url;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const ws = new WebSocket(url);
|
||||||
|
wsRef.current = ws;
|
||||||
|
|
||||||
|
ws.onopen = (event) => {
|
||||||
|
setReadyState(WebSocket.OPEN);
|
||||||
|
setIsConnected(true);
|
||||||
|
reconnectAttemptsRef.current = 0;
|
||||||
|
onOpen?.(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = (event) => {
|
||||||
|
setReadyState(WebSocket.CLOSED);
|
||||||
|
setIsConnected(false);
|
||||||
|
onClose?.(event);
|
||||||
|
|
||||||
|
// 处理重连
|
||||||
|
if (reconnectAttemptsRef.current < maxReconnectAttempts) {
|
||||||
|
reconnectAttemptsRef.current++;
|
||||||
|
reconnectTimeoutRef.current = setTimeout(() => {
|
||||||
|
connect(url);
|
||||||
|
}, reconnectInterval);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = (event) => {
|
||||||
|
setIsConnected(false);
|
||||||
|
onError?.(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
onMessage?.(event);
|
||||||
|
};
|
||||||
|
|
||||||
|
setReadyState(WebSocket.CONNECTING);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to create WebSocket connection:', error);
|
||||||
|
setIsConnected(false);
|
||||||
|
setReadyState(WebSocket.CLOSED);
|
||||||
|
}
|
||||||
|
}, [disconnect, maxReconnectAttempts, onOpen, onClose, onError, onMessage, reconnectInterval]);
|
||||||
|
|
||||||
|
// 组件卸载时清理
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
disconnect();
|
||||||
|
};
|
||||||
|
}, [disconnect]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
connect,
|
||||||
|
disconnect,
|
||||||
|
sendMessage,
|
||||||
|
readyState,
|
||||||
|
isConnected
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useWebSocket;
|
||||||
Loading…
Reference in New Issue