fix:Fix the incomplete cleanup issue when the receiver exits the room

This commit is contained in:
david_bai
2025-08-17 23:56:09 +08:00
parent caa861f1bb
commit bb21c90a4e
8 changed files with 231 additions and 192 deletions
+133 -92
View File
@@ -12,10 +12,17 @@ function format_peopleMsg(template: string, peerCount: number) {
// 移除所有 WebRTC 相关的 props 依赖
interface UseRoomManagerProps {
messages: Messages | null;
putMessageInMs: (message: string, isShareEnd?: boolean, displayTimeMs?: number) => void;
putMessageInMs: (
message: string,
isShareEnd?: boolean,
displayTimeMs?: number
) => void;
}
export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps) {
export function useRoomManager({
messages,
putMessageInMs,
}: UseRoomManagerProps) {
// 从 store 获取状态
const {
shareRoomId,
@@ -39,65 +46,84 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
} = useFileTransferStore();
// 加入房间方法 - 直接使用 webrtcService
const joinRoom = useCallback(async (isSenderSide: boolean, roomId: string) => {
if (!messages) return;
const joinRoom = useCallback(
async (isSenderSide: boolean, roomId: string) => {
if (!messages) return;
try {
console.log(`[RoomManager] 正在加入房间: ${roomId} (${isSenderSide ? '发送方' : '接收方'})`);
// 如果是发送方且房间ID不是初始ID,需要先创建房间
if (isSenderSide && activeTab === "send" && roomId !== initShareRoomId) {
try {
const success = await createRoom(roomId);
if (!success) {
putMessageInMs(messages.text.ClipboardApp.joinRoom.DuplicateMsg, isSenderSide);
try {
// 如果是发送方且房间ID不是初始ID,需要先创建房间
if (
isSenderSide &&
activeTab === "send" &&
roomId !== initShareRoomId
) {
try {
const success = await createRoom(roomId);
if (!success) {
putMessageInMs(
messages.text.ClipboardApp.joinRoom.DuplicateMsg,
isSenderSide
);
return;
}
setShareRoomId(roomId);
} catch (error) {
putMessageInMs(
messages.text.ClipboardApp.joinRoom.failMsg +
` (Create room error)`,
isSenderSide
);
return;
}
setShareRoomId(roomId);
} catch (error) {
putMessageInMs(
messages.text.ClipboardApp.joinRoom.failMsg + ` (Create room error)`,
isSenderSide
);
return;
}
}
// 确定实际要加入的房间ID
const actualRoomId = isSenderSide && roomId !== initShareRoomId
? roomId
: isSenderSide
? shareRoomId
: roomId;
// 直接调用 service 方法,无需依赖注入
await webrtcService.joinRoom(actualRoomId, isSenderSide);
putMessageInMs(messages.text.ClipboardApp.joinRoom.successMsg, isSenderSide, 6000);
// 更新分享链接
if (isSenderSide) {
const link = `${window.location.origin}${window.location.pathname}?roomId=${actualRoomId}`;
setShareLink(link);
if (actualRoomId !== shareRoomId) {
setShareRoomId(actualRoomId);
// 确定实际要加入的房间ID
const actualRoomId =
isSenderSide && roomId !== initShareRoomId
? roomId
: isSenderSide
? shareRoomId
: roomId;
// 直接调用 service 方法,无需依赖注入
await webrtcService.joinRoom(actualRoomId, isSenderSide);
putMessageInMs(
messages.text.ClipboardApp.joinRoom.successMsg,
isSenderSide,
6000
);
// 更新分享链接
if (isSenderSide) {
const link = `${window.location.origin}${window.location.pathname}?roomId=${actualRoomId}`;
setShareLink(link);
if (actualRoomId !== shareRoomId) {
setShareRoomId(actualRoomId);
}
}
} catch (error) {
console.error("[RoomManager] 加入房间失败:", error);
let errorMsg = messages.text.ClipboardApp.joinRoom.failMsg;
if (error instanceof Error) {
errorMsg =
error.message === "Room does not exist"
? messages.text.ClipboardApp.joinRoom.notExist
: `${messages.text.ClipboardApp.joinRoom.failMsg} ${error.message}`;
}
putMessageInMs(errorMsg, isSenderSide);
}
console.log(`[RoomManager] 成功加入房间: ${actualRoomId}`);
// 注意:广播逻辑已经在 webrtcService 的 onDataChannelOpen 事件中自动处理
} catch (error) {
console.error("[RoomManager] 加入房间失败:", error);
let errorMsg = messages.text.ClipboardApp.joinRoom.failMsg;
if (error instanceof Error) {
errorMsg = error.message === "Room does not exist"
? messages.text.ClipboardApp.joinRoom.notExist
: `${messages.text.ClipboardApp.joinRoom.failMsg} ${error.message}`;
}
putMessageInMs(errorMsg, isSenderSide);
}
}, [messages, putMessageInMs, activeTab, initShareRoomId, shareRoomId, setShareRoomId, setShareLink]);
},
[
messages,
putMessageInMs,
activeTab,
initShareRoomId,
shareRoomId,
setShareRoomId,
setShareLink,
]
);
// 生成分享链接并广播
const generateShareLinkAndBroadcast = useCallback(async () => {
@@ -114,8 +140,6 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
// 更新分享链接
const link = `${window.location.origin}${window.location.pathname}?roomId=${shareRoomId}`;
setShareLink(link);
console.log("[RoomManager] 分享链接已生成并广播");
} catch (error) {
console.error("[RoomManager] 生成分享链接失败:", error);
putMessageInMs("生成分享链接失败", true);
@@ -127,22 +151,21 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
if (!messages) return;
try {
console.log("[RoomManager] 接收方离开房间");
// 调用后端 API 离开房间
if (webrtcService.receiver.roomId && webrtcService.receiver.peerId) {
await leaveRoom(webrtcService.receiver.roomId, webrtcService.receiver.peerId);
await leaveRoom(
webrtcService.receiver.roomId,
webrtcService.receiver.peerId
);
}
putMessageInMs(messages.text.ClipboardApp.roomStatus.leftRoomMsg, false);
// 重置接收方状态
resetReceiverState();
// 清理 WebRTC 连接
await webrtcService.leaveRoom(false);
console.log("[RoomManager] 接收方已离开房间并重置状态");
} catch (error) {
console.error("[RoomManager] 接收方离开房间失败:", error);
putMessageInMs("离开房间失败", true);
@@ -152,8 +175,6 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
// 发送方重置应用状态
const resetSenderAppState = useCallback(async () => {
try {
console.log("[RoomManager] 重置发送方应用状态");
// 1. 清理 WebRTC 连接
await webrtcService.leaveRoom(true);
@@ -164,8 +185,6 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
const newRoomId = await fetchRoom();
setShareRoomId(newRoomId || "");
setInitShareRoomId(newRoomId || "");
console.log("[RoomManager] 发送方状态重置完成,新房间ID:", newRoomId);
} catch (error) {
console.error("[RoomManager] 重置发送方状态失败:", error);
putMessageInMs("重置发送方状态失败", true);
@@ -177,15 +196,16 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
if (!messages) return;
try {
console.log("[RoomManager] 发送方离开房间");
// 调用后端 API 离开房间
if (webrtcService.sender.roomId && webrtcService.sender.peerId) {
await leaveRoom(webrtcService.sender.roomId, webrtcService.sender.peerId);
await leaveRoom(
webrtcService.sender.roomId,
webrtcService.sender.peerId
);
}
putMessageInMs(messages.text.ClipboardApp.roomStatus.leftRoomMsg, true);
// 重置发送方状态并获取新房间ID
await resetSenderAppState();
} catch (error) {
@@ -198,15 +218,20 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
const processRoomIdInput = useCallback(
debounce(async (input: string) => {
if (!input.trim() || !messages) return;
try {
const isValid = await checkRoom(input);
if (isValid) {
console.log(`[RoomManager] 房间 ${input} 验证成功`);
setShareRoomId(input);
putMessageInMs(messages.text.ClipboardApp.roomCheck.available_msg, true);
putMessageInMs(
messages.text.ClipboardApp.roomCheck.available_msg,
true
);
} else {
putMessageInMs(messages.text.ClipboardApp.roomCheck.notAvailable_msg, true);
putMessageInMs(
messages.text.ClipboardApp.roomCheck.notAvailable_msg,
true
);
}
} catch (error) {
console.error("[RoomManager] 验证房间失败:", error);
@@ -218,7 +243,12 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
// 初始化发送方房间ID
useEffect(() => {
if (messages && putMessageInMs && !initShareRoomId && activeTab === "send") {
if (
messages &&
putMessageInMs &&
!initShareRoomId &&
activeTab === "send"
) {
const initNewRoom = async () => {
try {
const newRoomId = await fetchRoom();
@@ -226,13 +256,21 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
setInitShareRoomId(newRoomId || "");
} catch (err) {
console.error("[RoomManager] 获取初始房间失败:", err);
const errorMsg = messages.text?.ClipboardApp?.fetchRoom_err || "获取房间ID失败";
const errorMsg =
messages.text?.ClipboardApp?.fetchRoom_err || "获取房间ID失败";
putMessageInMs(errorMsg, true);
}
};
initNewRoom();
}
}, [messages, putMessageInMs, initShareRoomId, activeTab, setShareRoomId, setInitShareRoomId]);
}, [
messages,
putMessageInMs,
initShareRoomId,
activeTab,
setShareRoomId,
setInitShareRoomId,
]);
// 房间状态文本更新
useEffect(() => {
@@ -243,22 +281,25 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
}
const isInRoom = activeTab === "send" ? isSenderInRoom : isReceiverInRoom;
const currentPeerCount = activeTab === "send" ? sharePeerCount : retrievePeerCount;
const currentPeerCount =
activeTab === "send" ? sharePeerCount : retrievePeerCount;
let statusText = "";
if (!isInRoom) {
statusText = activeTab === "retrieve"
? messages.text.ClipboardApp.roomStatus.receiverEmptyMsg
: messages.text.ClipboardApp.roomStatus.senderEmptyMsg;
statusText =
activeTab === "retrieve"
? messages.text.ClipboardApp.roomStatus.receiverEmptyMsg
: messages.text.ClipboardApp.roomStatus.senderEmptyMsg;
} else if (currentPeerCount === 0) {
statusText = messages.text.ClipboardApp.roomStatus.onlyOneMsg;
} else {
statusText = activeTab === "send"
? format_peopleMsg(
messages.text.ClipboardApp.roomStatus.peopleMsg_template,
currentPeerCount + 1
)
: messages.text.ClipboardApp.roomStatus.connected_dis;
statusText =
activeTab === "send"
? format_peopleMsg(
messages.text.ClipboardApp.roomStatus.peopleMsg_template,
currentPeerCount + 1
)
: messages.text.ClipboardApp.roomStatus.connected_dis;
}
if (activeTab === "send") setShareRoomStatusText(statusText);
@@ -287,7 +328,7 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
senderDisconnected,
isSenderInRoom,
isReceiverInRoom,
// 方法
processRoomIdInput,
joinRoom,
@@ -295,4 +336,4 @@ export function useRoomManager({ messages, putMessageInMs }: UseRoomManagerProps
handleLeaveReceiverRoom,
handleLeaveSenderRoom,
};
}
}
+20 -20
View File
@@ -1,6 +1,6 @@
import { useEffect, useMemo } from 'react';
import { webrtcService } from '@/lib/webrtcService';
import { useFileTransferStore } from '@/stores/fileTransferStore';
import { useEffect, useMemo } from "react";
import { webrtcService } from "@/lib/webrtcService";
import { useFileTransferStore } from "@/stores/fileTransferStore";
import type { Messages } from "@/types/messages";
// 保留类型定义以保持兼容性
@@ -10,10 +10,17 @@ export type ProgressState = { [fileId: string]: FileProgressPeers };
interface UseWebRTCConnectionProps {
messages: Messages | null;
putMessageInMs: (message: string, isShareEnd?: boolean, displayTimeMs?: number) => void;
putMessageInMs: (
message: string,
isShareEnd?: boolean,
displayTimeMs?: number
) => void;
}
export function useWebRTCConnection({ messages, putMessageInMs }: UseWebRTCConnectionProps) {
export function useWebRTCConnection({
messages,
putMessageInMs,
}: UseWebRTCConnectionProps) {
// 从 store 获取状态
const {
sharePeerCount,
@@ -41,15 +48,6 @@ export function useWebRTCConnection({ messages, putMessageInMs }: UseWebRTCConne
setIsAnyFileTransferring(isAnyFileTransferring);
}, [isAnyFileTransferring, setIsAnyFileTransferring]);
// 确保服务在 React 生命周期内被初始化
useEffect(() => {
console.log('[useWebRTCConnection] WebRTC 服务已初始化');
return () => {
console.log('[useWebRTCConnection] Hook 清理');
};
}, []);
return {
// 状态从 store 获取
sharePeerCount,
@@ -57,21 +55,23 @@ export function useWebRTCConnection({ messages, putMessageInMs }: UseWebRTCConne
senderDisconnected,
sendProgress,
receiveProgress,
// 方法直接从 service 暴露
broadcastDataToAllPeers: webrtcService.broadcastDataToAllPeers.bind(webrtcService),
broadcastDataToAllPeers:
webrtcService.broadcastDataToAllPeers.bind(webrtcService),
requestFile: webrtcService.requestFile.bind(webrtcService),
requestFolder: webrtcService.requestFolder.bind(webrtcService),
setReceiverDirectoryHandle: webrtcService.setReceiverDirectoryHandle.bind(webrtcService),
setReceiverDirectoryHandle:
webrtcService.setReceiverDirectoryHandle.bind(webrtcService),
getReceiverSaveType: webrtcService.getReceiverSaveType.bind(webrtcService),
manualSafeSave: webrtcService.manualSafeSave.bind(webrtcService),
// 重置连接方法
resetSenderConnection: () => webrtcService.leaveRoom(true),
resetReceiverConnection: () => webrtcService.leaveRoom(false),
// 为了兼容性,保留这些属性(但实际上不再需要)
sender: webrtcService.sender,
receiver: webrtcService.receiver,
};
}
}