fenghuo/packages/client/src/websocket/useWebSocket.ts

190 lines
3.8 KiB
TypeScript

import { useCallback, useEffect, useState } from 'react';
import { wsClient } from './client';
import { WSMessage, WSMessageParams, MessageType } from './type';
interface UseWebSocketReturn {
// 状态
messages: WSMessage[];
currentRoom: string | null;
connecting: boolean;
// 方法
joinRoom: (roomId: string) => Promise<boolean>;
leaveRoom: () => Promise<boolean>;
sendMessage: (messageParams: WSMessageParams) => Promise<boolean>;
// 工具方法
clearMessages: () => void;
}
export const useWebSocket = (): UseWebSocketReturn => {
const [messages, setMessages] = useState<WSMessage[]>([]);
const [currentRoom, setCurrentRoom] = useState<string | null>(null);
const [connecting, setConnecting] = useState(false);
// 消息处理器
const messageHandler = useCallback((message: WSMessage) => {
setMessages((prev) => [...prev, message]);
}, []);
// 初始化 WebSocket 连接
useEffect(() => {
const initConnection = async () => {
try {
setConnecting(true);
await wsClient.connect();
const unsubscribe = wsClient.onMessage(messageHandler);
return unsubscribe;
} catch (error) {
console.error('连接失败:', error);
setMessages((prev) => [
...prev,
{
action: 'error',
data: {
text: '连接失败,请刷新页面重试',
type: MessageType.TEXT,
},
},
]);
} finally {
setConnecting(false);
}
};
const unsubscribePromise = initConnection();
return () => {
unsubscribePromise.then((unsubscribe) => unsubscribe?.());
wsClient.disconnect();
};
}, [messageHandler]);
// 加入房间
const joinRoom = async (roomId: string): Promise<boolean> => {
// 验证房间ID
if (!roomId.trim()) {
setMessages((prev) => [
...prev,
{
action: 'error',
data: {
text: '请输入有效的房间ID',
type: MessageType.TEXT,
},
},
]);
return false;
}
// 检查是否正在连接
if (connecting) {
return false;
}
try {
setConnecting(true);
await wsClient.joinRoom(roomId.trim());
setCurrentRoom(roomId.trim());
setMessages([]); // 清空消息历史
return true;
} catch (error) {
console.error('加入房间失败:', error);
setMessages((prev) => [
...prev,
{
action: 'error',
data: {
text: '加入房间失败,请重试',
type: MessageType.TEXT,
},
},
]);
return false;
} finally {
setConnecting(false);
}
};
// 离开房间
const leaveRoom = async (): Promise<boolean> => {
if (connecting) {
return false;
}
try {
await wsClient.disconnect();
setCurrentRoom(null);
setMessages([]); // 清空消息历史
return true;
} catch (error) {
console.error('离开房间失败:', error);
return false;
}
};
// 发送消息
const sendMessage = async (messageParams: WSMessageParams): Promise<boolean> => {
// 验证消息内容
if (!messageParams.text?.trim() && !messageParams.fileUri) {
return false;
}
// 检查房间状态
if (!currentRoom) {
setMessages((prev) => [
...prev,
{
action: 'error',
data: {
text: '请先加入房间',
type: MessageType.TEXT,
},
},
]);
return false;
}
// 检查连接状态
if (connecting) {
return false;
}
try {
await wsClient.sendMessage(messageParams);
return true;
} catch (error) {
console.error('发送消息失败:', error);
setMessages((prev) => [
...prev,
{
action: 'error',
data: {
text: '发送消息失败,请重试',
type: MessageType.TEXT,
},
},
]);
return false;
}
};
// 清空消息
const clearMessages = useCallback(() => {
setMessages([]);
}, []);
return {
// 状态
messages,
currentRoom,
connecting,
// 方法
joinRoom,
leaveRoom,
sendMessage,
// 工具方法
clearMessages,
};
};