mirror of
https://github.com/MatrixSeven/file-transfer-go.git
synced 2026-02-04 03:25:03 +08:00
feat:添加stun服务,修复文字房间无限尝试加入bug
This commit is contained in:
@@ -15,25 +15,26 @@ interface WebRTCTextReceiverProps {
|
||||
onRestart?: () => void;
|
||||
}
|
||||
|
||||
export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
initialCode = '',
|
||||
export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
initialCode = '',
|
||||
onPreviewImage,
|
||||
onRestart
|
||||
}) => {
|
||||
const { showToast } = useToast();
|
||||
|
||||
|
||||
// 状态管理
|
||||
const [pickupCode, setPickupCode] = useState('');
|
||||
const [inputCode, setInputCode] = useState(initialCode);
|
||||
const [receivedText, setReceivedText] = useState(''); // 实时接收的文本内容
|
||||
const [receivedImages, setReceivedImages] = useState<Array<{id: string, content: string, fileName?: string}>>([]);
|
||||
const [receivedImages, setReceivedImages] = useState<Array<{ id: string, content: string, fileName?: string }>>([]);
|
||||
const [isTyping, setIsTyping] = useState(false);
|
||||
const [isValidating, setIsValidating] = useState(false);
|
||||
|
||||
|
||||
|
||||
|
||||
// 创建共享连接 [需要优化]
|
||||
const connection = useSharedWebRTCManager();
|
||||
|
||||
|
||||
// 使用共享连接创建业务层
|
||||
const textTransfer = useTextTransferBusiness(connection);
|
||||
const fileTransfer = useFileTransferBusiness(connection);
|
||||
@@ -49,10 +50,11 @@ export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
|
||||
// 是否有任何连接
|
||||
const hasAnyConnection = textTransfer.isConnected || fileTransfer.isConnected;
|
||||
|
||||
|
||||
// 是否正在连接
|
||||
const isAnyConnecting = textTransfer.isConnecting || fileTransfer.isConnecting;
|
||||
|
||||
|
||||
// 是否有任何错误
|
||||
const hasAnyError = textTransfer.connectionError || fileTransfer.connectionError;
|
||||
|
||||
@@ -60,20 +62,20 @@ export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
const validatePickupCode = async (code: string): Promise<boolean> => {
|
||||
try {
|
||||
setIsValidating(true);
|
||||
|
||||
|
||||
console.log('开始验证取件码:', code);
|
||||
const response = await fetch(`/api/room-info?code=${code}`);
|
||||
const data = await response.json();
|
||||
|
||||
|
||||
console.log('验证响应:', { status: response.status, data });
|
||||
|
||||
|
||||
if (!response.ok || !data.success) {
|
||||
const errorMessage = data.message || '取件码验证失败';
|
||||
showToast(errorMessage, 'error');
|
||||
console.log('验证失败:', errorMessage);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
console.log('取件码验证成功:', data.room);
|
||||
return true;
|
||||
} catch (error) {
|
||||
@@ -93,11 +95,11 @@ export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
setReceivedText('');
|
||||
setReceivedImages([]);
|
||||
setIsTyping(false);
|
||||
|
||||
|
||||
// 断开连接
|
||||
textTransfer.disconnect();
|
||||
fileTransfer.disconnect();
|
||||
|
||||
|
||||
if (onRestart) {
|
||||
onRestart();
|
||||
}
|
||||
@@ -106,7 +108,7 @@ export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
// 加入房间
|
||||
const joinRoom = useCallback(async (code: string) => {
|
||||
const trimmedCode = code.trim().toUpperCase();
|
||||
|
||||
|
||||
if (!trimmedCode || trimmedCode.length !== 6) {
|
||||
showToast('请输入正确的6位取件码', "error");
|
||||
return;
|
||||
@@ -124,15 +126,15 @@ export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
|
||||
try {
|
||||
console.log('=== 开始验证和连接房间 ===', trimmedCode);
|
||||
|
||||
|
||||
const isValid = await validatePickupCode(trimmedCode);
|
||||
if (!isValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
setPickupCode(trimmedCode);
|
||||
await connectAll(trimmedCode, 'receiver');
|
||||
|
||||
|
||||
console.log('=== 房间连接成功 ===', trimmedCode);
|
||||
showToast(`成功加入消息房间: ${trimmedCode}`, "success");
|
||||
} catch (error) {
|
||||
@@ -185,16 +187,23 @@ export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
if (initialCode && initialCode.length === 6 && !hasAnyConnection && !isAnyConnecting) {
|
||||
console.log('=== 自动连接初始代码 ===', initialCode);
|
||||
setInputCode(initialCode);
|
||||
|
||||
|
||||
const timeoutId = setTimeout(() => {
|
||||
console.log('=== setTimeout 触发,检查最新状态 ===');
|
||||
|
||||
if (!hasAnyConnection && !isAnyConnecting) {
|
||||
console.log('=== 最新状态检查通过,调用 joinRoom ===', initialCode);
|
||||
joinRoom(initialCode);
|
||||
}
|
||||
}, 500);
|
||||
|
||||
return () => clearTimeout(timeoutId);
|
||||
return () => {
|
||||
console.log('=== 清理 setTimeout ===');
|
||||
clearTimeout(timeoutId);
|
||||
};
|
||||
}
|
||||
}, [initialCode, hasAnyConnection, isAnyConnecting, joinRoom]);
|
||||
// 注意:这里故意不包含 joinRoom 作为依赖,
|
||||
// 因为我们要的是"一次性"的自动连接行为
|
||||
}, [initialCode, hasAnyConnection, isAnyConnecting]);
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -298,7 +307,7 @@ export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div className="relative">
|
||||
<textarea
|
||||
value={receivedText}
|
||||
@@ -316,7 +325,7 @@ export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
{/* 打字状态提示 */}
|
||||
{isTyping && (
|
||||
<div className="flex items-center space-x-2 mt-3 text-sm text-slate-500">
|
||||
@@ -352,7 +361,7 @@ export const WebRTCTextReceiver: React.FC<WebRTCTextReceiverProps> = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { UrlSource } from './../../../node_modules/lightningcss/node/ast.d';
|
||||
import { useState, useRef, useCallback } from 'react';
|
||||
import { config } from '@/lib/config';
|
||||
|
||||
@@ -27,21 +28,21 @@ export interface WebRTCConnection {
|
||||
isConnecting: boolean;
|
||||
isWebSocketConnected: boolean;
|
||||
error: string | null;
|
||||
|
||||
|
||||
// 操作方法
|
||||
connect: (roomCode: string, role: 'sender' | 'receiver') => Promise<void>;
|
||||
disconnect: () => void;
|
||||
sendMessage: (message: WebRTCMessage, channel?: string) => boolean;
|
||||
sendData: (data: ArrayBuffer) => boolean;
|
||||
|
||||
|
||||
// 处理器注册
|
||||
registerMessageHandler: (channel: string, handler: MessageHandler) => () => void;
|
||||
registerDataHandler: (channel: string, handler: DataHandler) => () => void;
|
||||
|
||||
|
||||
// 工具方法
|
||||
getChannelState: () => RTCDataChannelState;
|
||||
isConnectedToRoom: (roomCode: string, role: 'sender' | 'receiver') => boolean;
|
||||
|
||||
|
||||
// 当前房间信息
|
||||
currentRoom: { code: string; role: 'sender' | 'receiver' } | null;
|
||||
}
|
||||
@@ -72,6 +73,7 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
|
||||
// STUN 服务器配置
|
||||
const STUN_SERVERS = [
|
||||
{ urls: 'stun:stun.chat.bilibili.com' },
|
||||
{ urls: 'stun:stun.l.google.com:19302' },
|
||||
{ urls: 'stun:stun.miwifi.com' },
|
||||
{ urls: 'stun:turn.cloudflare.com:3478' },
|
||||
@@ -114,9 +116,9 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
offerToReceiveAudio: false,
|
||||
offerToReceiveVideo: false,
|
||||
});
|
||||
|
||||
|
||||
await pc.setLocalDescription(offer);
|
||||
|
||||
|
||||
const iceTimeout = setTimeout(() => {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify({ type: 'offer', payload: pc.localDescription }));
|
||||
@@ -153,7 +155,7 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
try {
|
||||
const message = JSON.parse(event.data) as WebRTCMessage;
|
||||
console.log('[SharedWebRTC] 收到消息:', message.type, message.channel || 'default');
|
||||
|
||||
|
||||
// 根据通道分发消息
|
||||
if (message.channel) {
|
||||
const handler = messageHandlers.current.get(message.channel);
|
||||
@@ -169,7 +171,7 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
}
|
||||
} else if (event.data instanceof ArrayBuffer) {
|
||||
console.log('[SharedWebRTC] 收到数据:', event.data.byteLength, 'bytes');
|
||||
|
||||
|
||||
// 数据优先发给文件传输处理器
|
||||
const fileHandler = dataHandlers.current.get('file-transfer');
|
||||
if (fileHandler) {
|
||||
@@ -351,7 +353,7 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
|
||||
// 数据通道处理
|
||||
if (role === 'sender') {
|
||||
const dataChannel = pc.createDataChannel('shared-channel', {
|
||||
const dataChannel = pc.createDataChannel('shared-channel', {
|
||||
ordered: true,
|
||||
maxRetransmits: 3
|
||||
});
|
||||
@@ -371,7 +373,7 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
pc.ondatachannel = (event) => {
|
||||
const dataChannel = event.channel;
|
||||
dcRef.current = dataChannel;
|
||||
|
||||
|
||||
dataChannel.onopen = () => {
|
||||
console.log('[SharedWebRTC] 数据通道已打开 (接收方)');
|
||||
};
|
||||
@@ -387,9 +389,9 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
|
||||
} catch (error) {
|
||||
console.error('[SharedWebRTC] 连接失败:', error);
|
||||
updateState({
|
||||
updateState({
|
||||
error: error instanceof Error ? error.message : '连接失败',
|
||||
isConnecting: false
|
||||
isConnecting: false
|
||||
});
|
||||
}
|
||||
}, [updateState, cleanup, createOffer, handleDataChannelMessage, state.isConnecting, state.isConnected]);
|
||||
@@ -447,7 +449,7 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
const registerMessageHandler = useCallback((channel: string, handler: MessageHandler) => {
|
||||
console.log('[SharedWebRTC] 注册消息处理器:', channel);
|
||||
messageHandlers.current.set(channel, handler);
|
||||
|
||||
|
||||
return () => {
|
||||
console.log('[SharedWebRTC] 取消注册消息处理器:', channel);
|
||||
messageHandlers.current.delete(channel);
|
||||
@@ -458,7 +460,7 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
const registerDataHandler = useCallback((channel: string, handler: DataHandler) => {
|
||||
console.log('[SharedWebRTC] 注册数据处理器:', channel);
|
||||
dataHandlers.current.set(channel, handler);
|
||||
|
||||
|
||||
return () => {
|
||||
console.log('[SharedWebRTC] 取消注册数据处理器:', channel);
|
||||
dataHandlers.current.delete(channel);
|
||||
@@ -472,9 +474,9 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
|
||||
// 检查是否已连接到指定房间
|
||||
const isConnectedToRoom = useCallback((roomCode: string, role: 'sender' | 'receiver') => {
|
||||
return currentRoom.current?.code === roomCode &&
|
||||
currentRoom.current?.role === role &&
|
||||
state.isConnected;
|
||||
return currentRoom.current?.code === roomCode &&
|
||||
currentRoom.current?.role === role &&
|
||||
state.isConnected;
|
||||
}, [state.isConnected]);
|
||||
|
||||
return {
|
||||
@@ -497,7 +499,7 @@ export function useSharedWebRTCManager(): WebRTCConnection {
|
||||
// 工具方法
|
||||
getChannelState,
|
||||
isConnectedToRoom,
|
||||
|
||||
|
||||
// 当前房间信息
|
||||
currentRoom: currentRoom.current,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user