From 6b69d35a20cc7f8124b854e7b77900747f4541f0 Mon Sep 17 00:00:00 2001 From: MatrixSeven Date: Sun, 24 Aug 2025 15:41:58 +0800 Subject: [PATCH] =?UTF-8?q?feat:=E5=A4=84=E7=90=86=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E5=AF=BC=E8=87=B4=E9=87=8D=E5=A4=8D=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E4=BA=8B=E4=BB=B6=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/WebRTCFileTransfer.tsx | 7 ++-- .../hooks/webrtc/useFileTransferBusiness.ts | 37 +++++++++++-------- .../hooks/webrtc/useSharedWebRTCManager.ts | 24 +++++++++--- 3 files changed, 44 insertions(+), 24 deletions(-) diff --git a/chuan-next/src/components/WebRTCFileTransfer.tsx b/chuan-next/src/components/WebRTCFileTransfer.tsx index 330fb21..0e7067d 100644 --- a/chuan-next/src/components/WebRTCFileTransfer.tsx +++ b/chuan-next/src/components/WebRTCFileTransfer.tsx @@ -1,6 +1,6 @@ "use client"; -import React, { useState, useEffect, useRef, useCallback } from 'react'; +import React, { useState, useEffect, useRef, useCallback, useMemo } from 'react'; import { useSearchParams, useRouter } from 'next/navigation'; import { useSharedWebRTCManager } from '@/hooks/webrtc/useSharedWebRTCManager'; import { useFileTransferBusiness } from '@/hooks/webrtc/useFileTransferBusiness'; @@ -42,8 +42,9 @@ export const WebRTCFileTransfer: React.FC = () => { const urlProcessedRef = useRef(false); // 使用 ref 防止重复处理 URL const fileInputRef = useRef(null); - // 创建共享连接 + // 创建共享连接 - 使用 useMemo 稳定引用 const connection = useSharedWebRTCManager(); + const stableConnection = useMemo(() => connection, [connection.isConnected, connection.isConnecting, connection.isWebSocketConnected, connection.error]); // 使用共享连接创建业务层 const { @@ -60,7 +61,7 @@ export const WebRTCFileTransfer: React.FC = () => { onFileListReceived, onFileRequested, onFileProgress - } = useFileTransferBusiness(connection); + } = useFileTransferBusiness(stableConnection); // 加入房间 (接收模式) - 提前定义以供 useEffect 使用 const joinRoom = useCallback(async (code: string) => { diff --git a/chuan-next/src/hooks/webrtc/useFileTransferBusiness.ts b/chuan-next/src/hooks/webrtc/useFileTransferBusiness.ts index fedd73b..add79aa 100644 --- a/chuan-next/src/hooks/webrtc/useFileTransferBusiness.ts +++ b/chuan-next/src/hooks/webrtc/useFileTransferBusiness.ts @@ -342,7 +342,7 @@ export function useFileTransferBusiness(connection: WebRTCConnection) { } }, [updateState, connection]); - // 设置处理器 + // 设置处理器 - 使用稳定的引用避免反复注册 useEffect(() => { // 使用共享连接的注册方式 const unregisterMessage = connection.registerMessageHandler(CHANNEL_NAME, handleMessage); @@ -352,7 +352,7 @@ export function useFileTransferBusiness(connection: WebRTCConnection) { unregisterMessage(); unregisterData(); }; - }, [handleMessage, handleData]); + }, [connection]); // 只依赖 connection 对象,不依赖处理函数 // 监听连接状态变化 (直接使用 connection 的状态) useEffect(() => { @@ -564,22 +564,27 @@ export function useFileTransferBusiness(connection: WebRTCConnection) { // 发送文件列表 const sendFileList = useCallback((fileList: FileInfo[]) => { - if (!connection.isPeerConnected) { + // 检查连接状态 - 优先检查数据通道状态,因为 P2P 连接可能已经建立但状态未及时更新 + const channelState = connection.getChannelState(); + const peerConnected = connection.isPeerConnected; + + console.log('发送文件列表检查:', { + channelState, + peerConnected, + fileListLength: fileList.length + }); + + // 如果数据通道已打开或者 P2P 已连接,就可以发送文件列表 + if (channelState === 'open' || peerConnected) { + console.log('发送文件列表:', fileList); + + connection.sendMessage({ + type: 'file-list', + payload: fileList + }, CHANNEL_NAME); + } else { console.log('P2P连接未建立,等待连接后再发送文件列表'); - return; } - - if (connection.getChannelState() !== 'open') { - console.error('数据通道未准备就绪,无法发送文件列表'); - return; - } - - console.log('发送文件列表:', fileList); - - connection.sendMessage({ - type: 'file-list', - payload: fileList - }, CHANNEL_NAME); }, [connection]); // 请求文件 diff --git a/chuan-next/src/hooks/webrtc/useSharedWebRTCManager.ts b/chuan-next/src/hooks/webrtc/useSharedWebRTCManager.ts index 63688b0..5474d32 100644 --- a/chuan-next/src/hooks/webrtc/useSharedWebRTCManager.ts +++ b/chuan-next/src/hooks/webrtc/useSharedWebRTCManager.ts @@ -289,11 +289,25 @@ export function useSharedWebRTCManager(): WebRTCConnection { case 'answer': console.log('[SharedWebRTC] 📬 处理answer...'); - if (pc.signalingState === 'have-local-offer') { - await pc.setRemoteDescription(new RTCSessionDescription(message.payload)); - console.log('[SharedWebRTC] ✅ answer 处理完成'); - } else { - console.warn('[SharedWebRTC] ⚠️ PeerConnection状态不是have-local-offer:', pc.signalingState); + try { + if (pc.signalingState === 'have-local-offer') { + await pc.setRemoteDescription(new RTCSessionDescription(message.payload)); + console.log('[SharedWebRTC] ✅ answer 处理完成'); + } else { + console.warn('[SharedWebRTC] ⚠️ PeerConnection状态不是have-local-offer:', pc.signalingState); + // 如果状态不对,尝试重新创建 offer + if (pc.connectionState === 'connected' || pc.connectionState === 'connecting') { + console.log('[SharedWebRTC] 🔄 连接状态正常但信令状态异常,尝试重新创建offer'); + // 这里不直接处理,让连接自然建立 + } + } + } catch (error) { + console.error('[SharedWebRTC] ❌ 处理answer失败:', error); + if (error instanceof Error && error.message.includes('Failed to set local answer sdp')) { + console.warn('[SharedWebRTC] ⚠️ Answer处理失败,可能是连接状态变化导致的'); + // 清理连接状态,让客户端重新连接 + updateState({ error: 'WebRTC连接状态异常,请重新连接', isPeerConnected: false }); + } } break;