fix:Fix the incomplete cleanup issue when the receiver exits the room
This commit is contained in:
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user