chore:Use English comments instead of Chinese
This commit is contained in:
@@ -18,7 +18,7 @@ export function useFileTransferHandler({
|
||||
messages,
|
||||
putMessageInMs,
|
||||
}: UseFileTransferHandlerProps) {
|
||||
// 从 store 中获取状态
|
||||
// Get state from store
|
||||
const {
|
||||
shareContent,
|
||||
sendFiles,
|
||||
@@ -100,11 +100,11 @@ export function useFileTransferHandler({
|
||||
}
|
||||
} else {
|
||||
let retryCount = 0;
|
||||
const maxRetries = 3; // 重试次数
|
||||
const maxRetries = 3; // Retry count
|
||||
|
||||
const findAndDownload = async (): Promise<boolean> => {
|
||||
retryCount++;
|
||||
// 🔧 关键修复:使用最新的Store状态,而不是闭包中的旧状态
|
||||
// 🔧 Key fix: Use the latest Store state instead of the old state in the closure
|
||||
const { retrievedFiles: latestRetrievedFiles } =
|
||||
useFileTransferStore.getState();
|
||||
const fileToDownload = latestRetrievedFiles.find(
|
||||
@@ -119,20 +119,20 @@ export function useFileTransferHandler({
|
||||
return false;
|
||||
};
|
||||
|
||||
// 首次尝试
|
||||
// First attempt
|
||||
const found = await findAndDownload();
|
||||
|
||||
if (!found) {
|
||||
// 如果没找到,启动重试机制
|
||||
// If not found, start retry mechanism
|
||||
const retryWithDelay = async (): Promise<void> => {
|
||||
while (retryCount < maxRetries) {
|
||||
await new Promise((resolve) => setTimeout(resolve, 50)); // 固定50ms延迟,因为现在状态应该很快同步
|
||||
await new Promise((resolve) => setTimeout(resolve, 50)); // Fixed 50ms delay, as the state should sync quickly now
|
||||
const foundInRetry = await findAndDownload();
|
||||
if (foundInRetry) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// 所有重试都失败了
|
||||
// All retries failed
|
||||
putMessageInMs(
|
||||
messages.text.ClipboardApp.fileNotFoundMsg ||
|
||||
`File '${meta.name}' not found for download.`,
|
||||
@@ -140,12 +140,12 @@ export function useFileTransferHandler({
|
||||
);
|
||||
};
|
||||
|
||||
// 异步执行重试,不阻塞主线程
|
||||
// Execute retry asynchronously without blocking the main thread
|
||||
retryWithDelay().catch(console.error);
|
||||
}
|
||||
}
|
||||
},
|
||||
[messages, putMessageInMs] // 🔧 移除retrievedFiles依赖,因为我们现在直接从Store获取最新状态
|
||||
[messages, putMessageInMs] // 🔧 Remove retrievedFiles dependency as we now get the latest state directly from Store
|
||||
);
|
||||
|
||||
// Reset function specifically for receiver state (for leave room functionality)
|
||||
|
||||
@@ -9,7 +9,7 @@ function format_peopleMsg(template: string, peerCount: number) {
|
||||
return template.replace("{peerCount}", peerCount.toString());
|
||||
}
|
||||
|
||||
// 移除所有 WebRTC 相关的 props 依赖
|
||||
// Remove all WebRTC related props dependencies
|
||||
interface UseRoomManagerProps {
|
||||
messages: Messages | null;
|
||||
putMessageInMs: (
|
||||
@@ -23,7 +23,7 @@ export function useRoomManager({
|
||||
messages,
|
||||
putMessageInMs,
|
||||
}: UseRoomManagerProps) {
|
||||
// 从 store 获取状态
|
||||
// Get state from store
|
||||
const {
|
||||
shareRoomId,
|
||||
initShareRoomId,
|
||||
@@ -45,13 +45,13 @@ export function useRoomManager({
|
||||
resetSenderApp,
|
||||
} = useFileTransferStore();
|
||||
|
||||
// 加入房间方法 - 直接使用 webrtcService
|
||||
// Join room method - directly use webrtcService
|
||||
const joinRoom = useCallback(
|
||||
async (isSenderSide: boolean, roomId: string) => {
|
||||
if (!messages) return;
|
||||
|
||||
try {
|
||||
// 如果是发送方且房间ID不是初始ID,需要先创建房间
|
||||
// If it's the sender side and the room ID is not the initial ID, need to create the room first
|
||||
if (
|
||||
isSenderSide &&
|
||||
activeTab === "send" &&
|
||||
@@ -77,7 +77,7 @@ export function useRoomManager({
|
||||
}
|
||||
}
|
||||
|
||||
// 确定实际要加入的房间ID
|
||||
// Determine the actual room ID to join
|
||||
const actualRoomId =
|
||||
isSenderSide && roomId !== initShareRoomId
|
||||
? roomId
|
||||
@@ -85,7 +85,7 @@ export function useRoomManager({
|
||||
? shareRoomId
|
||||
: roomId;
|
||||
|
||||
// 直接调用 service 方法,无需依赖注入
|
||||
// Directly call the service method without dependency injection
|
||||
await webrtcService.joinRoom(actualRoomId, isSenderSide);
|
||||
|
||||
putMessageInMs(
|
||||
@@ -94,7 +94,7 @@ export function useRoomManager({
|
||||
6000
|
||||
);
|
||||
|
||||
// 更新分享链接
|
||||
// Update share link
|
||||
if (isSenderSide) {
|
||||
const link = `${window.location.origin}${window.location.pathname}?roomId=${actualRoomId}`;
|
||||
setShareLink(link);
|
||||
@@ -103,7 +103,7 @@ export function useRoomManager({
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[RoomManager] 加入房间失败:", error);
|
||||
console.error("[RoomManager] Failed to join room:", error);
|
||||
let errorMsg = messages.text.ClipboardApp.joinRoom.failMsg;
|
||||
if (error instanceof Error) {
|
||||
errorMsg =
|
||||
@@ -125,7 +125,7 @@ export function useRoomManager({
|
||||
]
|
||||
);
|
||||
|
||||
// 生成分享链接并广播
|
||||
// Generate share link and broadcast
|
||||
const generateShareLinkAndBroadcast = useCallback(async () => {
|
||||
if (!messages || !shareRoomId) return;
|
||||
|
||||
@@ -133,25 +133,25 @@ export function useRoomManager({
|
||||
if (sharePeerCount === 0) {
|
||||
putMessageInMs(messages.text.ClipboardApp.waitting_tips, true);
|
||||
} else {
|
||||
// 直接调用 service 的广播方法
|
||||
// Directly call the service's broadcast method
|
||||
await webrtcService.broadcastDataToAllPeers();
|
||||
}
|
||||
|
||||
// 更新分享链接
|
||||
// Update share link
|
||||
const link = `${window.location.origin}${window.location.pathname}?roomId=${shareRoomId}`;
|
||||
setShareLink(link);
|
||||
} catch (error) {
|
||||
console.error("[RoomManager] 生成分享链接失败:", error);
|
||||
putMessageInMs("生成分享链接失败", true);
|
||||
console.error("[RoomManager] Failed to generate share link:", error);
|
||||
putMessageInMs("Failed to generate share link", true);
|
||||
}
|
||||
}, [messages, putMessageInMs, shareRoomId, sharePeerCount, setShareLink]);
|
||||
|
||||
// 接收方离开房间
|
||||
// Receiver leave room
|
||||
const handleLeaveReceiverRoom = useCallback(async () => {
|
||||
if (!messages) return;
|
||||
|
||||
try {
|
||||
// 调用后端 API 离开房间
|
||||
// Call backend API to leave room
|
||||
if (webrtcService.receiver.roomId && webrtcService.receiver.peerId) {
|
||||
await leaveRoom(
|
||||
webrtcService.receiver.roomId,
|
||||
@@ -161,42 +161,42 @@ export function useRoomManager({
|
||||
|
||||
putMessageInMs(messages.text.ClipboardApp.roomStatus.leftRoomMsg, false);
|
||||
|
||||
// 重置接收方状态
|
||||
// Reset receiver state
|
||||
resetReceiverState();
|
||||
|
||||
// 清理 WebRTC 连接
|
||||
// Clean up WebRTC connection
|
||||
await webrtcService.leaveRoom(false);
|
||||
} catch (error) {
|
||||
console.error("[RoomManager] 接收方离开房间失败:", error);
|
||||
putMessageInMs("离开房间失败", true);
|
||||
console.error("[RoomManager] Receiver failed to leave room:", error);
|
||||
putMessageInMs("Failed to leave room", true);
|
||||
}
|
||||
}, [messages, putMessageInMs, resetReceiverState]);
|
||||
|
||||
// 发送方重置应用状态
|
||||
// Sender reset app state
|
||||
const resetSenderAppState = useCallback(async () => {
|
||||
try {
|
||||
// 1. 清理 WebRTC 连接
|
||||
// 1. Clean up WebRTC connection
|
||||
await webrtcService.leaveRoom(true);
|
||||
|
||||
// 2. 清除分享链接和进度
|
||||
// 2. Clear share link and progress
|
||||
resetSenderApp();
|
||||
|
||||
// 3. 从后端获取新的房间ID
|
||||
// 3. Fetch new room ID from backend
|
||||
const newRoomId = await fetchRoom();
|
||||
setShareRoomId(newRoomId || "");
|
||||
setInitShareRoomId(newRoomId || "");
|
||||
} catch (error) {
|
||||
console.error("[RoomManager] 重置发送方状态失败:", error);
|
||||
putMessageInMs("重置发送方状态失败", true);
|
||||
console.error("[RoomManager] Failed to reset sender state:", error);
|
||||
putMessageInMs("Failed to reset sender state", true);
|
||||
}
|
||||
}, [putMessageInMs, resetSenderApp, setShareRoomId, setInitShareRoomId]);
|
||||
|
||||
// 发送方离开房间
|
||||
// Sender leave room
|
||||
const handleLeaveSenderRoom = useCallback(async () => {
|
||||
if (!messages) return;
|
||||
|
||||
try {
|
||||
// 调用后端 API 离开房间
|
||||
// Call backend API to leave room
|
||||
if (webrtcService.sender.roomId && webrtcService.sender.peerId) {
|
||||
await leaveRoom(
|
||||
webrtcService.sender.roomId,
|
||||
@@ -206,42 +206,52 @@ export function useRoomManager({
|
||||
|
||||
putMessageInMs(messages.text.ClipboardApp.roomStatus.leftRoomMsg, true);
|
||||
|
||||
// 重置发送方状态并获取新房间ID
|
||||
// Reset sender state and get new room ID
|
||||
await resetSenderAppState();
|
||||
} catch (error) {
|
||||
console.error("[RoomManager] 发送方离开房间失败:", error);
|
||||
putMessageInMs("离开房间失败", true);
|
||||
console.error("[RoomManager] Sender failed to leave room:", error);
|
||||
putMessageInMs("Failed to leave room", true);
|
||||
}
|
||||
}, [messages, putMessageInMs, resetSenderAppState]);
|
||||
|
||||
// 房间ID输入处理
|
||||
// Room ID input processing
|
||||
const processRoomIdInput = useCallback(
|
||||
debounce(async (input: string) => {
|
||||
if (!input.trim() || !messages) return;
|
||||
console.log("🔍 processRoomIdInput called with:", input);
|
||||
|
||||
if (!input.trim() || !messages) {
|
||||
console.log("❌ Input empty or no messages, returning");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
console.log("🌐 Calling checkRoom API for:", input);
|
||||
const isValid = await checkRoom(input);
|
||||
console.log("📋 checkRoom result:", isValid, "for input:", input);
|
||||
|
||||
if (isValid) {
|
||||
console.log("✅ Room is valid, setting shareRoomId to:", input);
|
||||
setShareRoomId(input);
|
||||
putMessageInMs(
|
||||
messages.text.ClipboardApp.roomCheck.available_msg,
|
||||
true
|
||||
);
|
||||
} else {
|
||||
console.log("❌ Room is not valid:", input);
|
||||
putMessageInMs(
|
||||
messages.text.ClipboardApp.roomCheck.notAvailable_msg,
|
||||
true
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[RoomManager] 验证房间失败:", error);
|
||||
putMessageInMs("验证房间失败", true);
|
||||
console.error("[RoomManager] Failed to validate room:", error);
|
||||
putMessageInMs("Failed to validate room", true);
|
||||
}
|
||||
}, 750),
|
||||
[messages, putMessageInMs, setShareRoomId]
|
||||
);
|
||||
|
||||
// 初始化发送方房间ID
|
||||
// Initialize sender room ID
|
||||
useEffect(() => {
|
||||
if (
|
||||
messages &&
|
||||
@@ -255,9 +265,10 @@ export function useRoomManager({
|
||||
setShareRoomId(newRoomId || "");
|
||||
setInitShareRoomId(newRoomId || "");
|
||||
} catch (err) {
|
||||
console.error("[RoomManager] 获取初始房间失败:", err);
|
||||
console.error("[RoomManager] Failed to fetch initial room:", err);
|
||||
const errorMsg =
|
||||
messages.text?.ClipboardApp?.fetchRoom_err || "获取房间ID失败";
|
||||
messages.text?.ClipboardApp?.fetchRoom_err ||
|
||||
"Failed to fetch room ID";
|
||||
putMessageInMs(errorMsg, true);
|
||||
}
|
||||
};
|
||||
@@ -272,7 +283,7 @@ export function useRoomManager({
|
||||
setInitShareRoomId,
|
||||
]);
|
||||
|
||||
// 房间状态文本更新
|
||||
// Room status text update
|
||||
useEffect(() => {
|
||||
if (!messages) {
|
||||
if (activeTab === "send") setShareRoomStatusText("");
|
||||
@@ -317,7 +328,7 @@ export function useRoomManager({
|
||||
]);
|
||||
|
||||
return {
|
||||
// 状态
|
||||
// State
|
||||
shareRoomId,
|
||||
initShareRoomId,
|
||||
shareLink,
|
||||
@@ -329,7 +340,7 @@ export function useRoomManager({
|
||||
isSenderInRoom,
|
||||
isReceiverInRoom,
|
||||
|
||||
// 方法
|
||||
// Methods
|
||||
processRoomIdInput,
|
||||
joinRoom,
|
||||
generateShareLinkAndBroadcast,
|
||||
|
||||
@@ -3,7 +3,7 @@ import { webrtcService } from "@/lib/webrtcService";
|
||||
import { useFileTransferStore } from "@/stores/fileTransferStore";
|
||||
import type { Messages } from "@/types/messages";
|
||||
|
||||
// 保留类型定义以保持兼容性
|
||||
// Retain type definitions for compatibility
|
||||
export type PeerProgressDetails = { progress: number; speed: number };
|
||||
export type FileProgressPeers = { [peerId: string]: PeerProgressDetails };
|
||||
export type ProgressState = { [fileId: string]: FileProgressPeers };
|
||||
@@ -21,7 +21,7 @@ export function useWebRTCConnection({
|
||||
messages,
|
||||
putMessageInMs,
|
||||
}: UseWebRTCConnectionProps) {
|
||||
// 从 store 获取状态
|
||||
// Get state from store
|
||||
const {
|
||||
sharePeerCount,
|
||||
retrievePeerCount,
|
||||
@@ -31,7 +31,7 @@ export function useWebRTCConnection({
|
||||
setIsAnyFileTransferring,
|
||||
} = useFileTransferStore();
|
||||
|
||||
// 计算是否有文件正在传输
|
||||
// Calculate if any file is being transferred
|
||||
const isAnyFileTransferring = useMemo(() => {
|
||||
const allProgress = [
|
||||
...Object.values(sendProgress),
|
||||
@@ -49,14 +49,14 @@ export function useWebRTCConnection({
|
||||
}, [isAnyFileTransferring, setIsAnyFileTransferring]);
|
||||
|
||||
return {
|
||||
// 状态从 store 获取
|
||||
// State obtained from store
|
||||
sharePeerCount,
|
||||
retrievePeerCount,
|
||||
senderDisconnected,
|
||||
sendProgress,
|
||||
receiveProgress,
|
||||
|
||||
// 方法直接从 service 暴露
|
||||
// Methods exposed directly from service
|
||||
broadcastDataToAllPeers:
|
||||
webrtcService.broadcastDataToAllPeers.bind(webrtcService),
|
||||
requestFile: webrtcService.requestFile.bind(webrtcService),
|
||||
@@ -66,11 +66,11 @@ export function useWebRTCConnection({
|
||||
getReceiverSaveType: webrtcService.getReceiverSaveType.bind(webrtcService),
|
||||
manualSafeSave: webrtcService.manualSafeSave.bind(webrtcService),
|
||||
|
||||
// 重置连接方法
|
||||
// Reset connection methods
|
||||
resetSenderConnection: () => webrtcService.leaveRoom(true),
|
||||
resetReceiverConnection: () => webrtcService.leaveRoom(false),
|
||||
|
||||
// 为了兼容性,保留这些属性(但实际上不再需要)
|
||||
// For compatibility, retain these properties (but they are no longer needed)
|
||||
sender: webrtcService.sender,
|
||||
receiver: webrtcService.receiver,
|
||||
};
|
||||
|
||||
@@ -294,7 +294,7 @@ class FileReceiver {
|
||||
await handler(parsedData, peerId);
|
||||
} else {
|
||||
console.warn(
|
||||
`[DEBUG] ⚠️ FileReceiver 未找到处理器: ${parsedData.type}`
|
||||
`[DEBUG] ⚠️ FileReceiver Handler not found: ${parsedData.type}`
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -316,7 +316,7 @@ class FileReceiver {
|
||||
private handleFileMetadata(metadata: fileMetadata): void {
|
||||
if (this.pendingFilesMeta.has(metadata.fileId)) {
|
||||
console.log(
|
||||
`[DEBUG] 📥 FileReceiver 文件元数据已存在,忽略: ${metadata.fileId}`
|
||||
`[DEBUG] 📥 FileReceiver File metadata already exists, ignoring: ${metadata.fileId}`
|
||||
);
|
||||
return; // Ignore if already received.
|
||||
}
|
||||
@@ -326,7 +326,7 @@ class FileReceiver {
|
||||
if (this.onFileMetaReceived) {
|
||||
this.onFileMetaReceived(metadata);
|
||||
} else {
|
||||
console.error(`[DEBUG] ❌ FileReceiver onFileMetaReceived 回调不存在!`);
|
||||
console.error(`[DEBUG] ❌ FileReceiver onFileMetaReceived callback does not exist!`);
|
||||
}
|
||||
// Record the file size for folder progress calculation.
|
||||
if (metadata.folderName) {
|
||||
@@ -376,19 +376,19 @@ class FileReceiver {
|
||||
return;
|
||||
}
|
||||
|
||||
// 🔧 关键修复:先完成文件处理,确保文件添加到Store
|
||||
// 🔧 Key fix: Complete file processing first to ensure the file is added to Store
|
||||
await this.finalizeFileReceive();
|
||||
|
||||
// 🏗️ 架构重构:确保Store状态完全同步后再触发进度回调
|
||||
// 🏗️ Architecture refactor: Ensure Store state is fully synchronized before triggering progress callback
|
||||
if (!this.currentFolderName) {
|
||||
// 🔧 优化的异步确保机制 - 确保Store状态完全同步
|
||||
await Promise.resolve(); // 确保当前执行栈完成
|
||||
// 🔧 Optimized async ensure mechanism - ensure Store state is fully synchronized
|
||||
await Promise.resolve(); // Ensure current execution stack is completed
|
||||
await new Promise<void>((resolve) => {
|
||||
// 使用更长的延迟确保Store状态完全更新
|
||||
// Use longer delay to ensure Store state is fully updated
|
||||
setTimeout(() => {
|
||||
this.progressCallback?.(reception.meta.fileId, 1, 0);
|
||||
resolve();
|
||||
}, 10); // 增加到10ms确保Store状态完全同步
|
||||
}, 10); // Increase to 10ms to ensure Store state is fully synchronized
|
||||
});
|
||||
}
|
||||
|
||||
@@ -554,11 +554,11 @@ class FileReceiver {
|
||||
}) as CustomFile;
|
||||
|
||||
if (this.onFileReceived) {
|
||||
// 🔧 关键修复:确保 onFileReceived 回调完全同步执行完成
|
||||
// 🔧 Key fix: Ensure onFileReceived callback is fully synchronized
|
||||
await this.onFileReceived(customFile);
|
||||
// 🔧 多重确认机制:确保 Store 状态完全同步
|
||||
await Promise.resolve(); // 第一层确认
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 0)); // 第二层确认
|
||||
// 🔧 Multiple confirmation mechanism: Ensure Store state is fully synchronized
|
||||
await Promise.resolve(); // First layer confirmation
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 0)); // Second layer confirmation
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
@@ -586,7 +586,7 @@ class FileReceiver {
|
||||
});
|
||||
}
|
||||
|
||||
// 🔧 清理所有内部状态,确保重新连接时能正确接收文件元数据
|
||||
// 🔧 Clean up all internal states to ensure correct file metadata reception upon reconnection
|
||||
this.pendingFilesMeta.clear();
|
||||
this.folderProgresses = {};
|
||||
this.saveType = {};
|
||||
|
||||
+62
-62
@@ -25,24 +25,24 @@ class FileSender {
|
||||
private pendingFolerMeta: Record<string, FolderMeta>;
|
||||
private speedCalculator: SpeedCalculator;
|
||||
|
||||
// 自适应性能监控
|
||||
// Adaptive performance monitoring
|
||||
private networkPerformance: Map<
|
||||
string,
|
||||
{
|
||||
avgClearingRate: number; // 平均网络清理速度 KB/s
|
||||
optimalThreshold: number; // 动态优化的阈值
|
||||
avgWaitTime: number; // 平均等待时间
|
||||
sampleCount: number; // 采样次数
|
||||
avgClearingRate: number; // Average network clearing speed KB/s
|
||||
optimalThreshold: number; // Dynamically optimized threshold
|
||||
avgWaitTime: number; // Average wait time
|
||||
sampleCount: number; // Sample count
|
||||
}
|
||||
> = new Map();
|
||||
|
||||
// 混合优化配置 - FileReader大块 + 网络小包策略(修复sendData failed)
|
||||
// Hybrid optimization configuration - FileReader large chunks + network small packets strategy (fixes sendData failed)
|
||||
private static readonly OPTIMIZED_CONFIG = {
|
||||
CHUNK_SIZE: 4194304, // 4MB - 极致大块,最大化减少FileReader调用次数
|
||||
BATCH_SIZE: 8, // 8块批量 - 32MB批次处理成功
|
||||
NETWORK_CHUNK_SIZE: 65536, // 64KB - WebRTC安全发送大小,修复sendData failed
|
||||
BUFFER_THRESHOLD: 3145728, // 3MB - 阈值
|
||||
BACKPRESSURE_TIMEOUT: 2000, // 2秒超时 - 为大块处理预留更多时间
|
||||
CHUNK_SIZE: 4194304, // 4MB - Extreme large chunks, maximally reduce FileReader calls
|
||||
BATCH_SIZE: 8, // 8 chunks batch - 32MB batch processing success
|
||||
NETWORK_CHUNK_SIZE: 65536, // 64KB - WebRTC safe sending size, fixes sendData failed
|
||||
BUFFER_THRESHOLD: 3145728, // 3MB - Threshold
|
||||
BACKPRESSURE_TIMEOUT: 2000, // 2 second timeout - reserves more time for large chunk processing
|
||||
} as const;
|
||||
|
||||
constructor(WebRTC_initiator: WebRTC_Initiator) {
|
||||
@@ -51,7 +51,7 @@ class FileSender {
|
||||
// Maintain independent sending states for each receiver
|
||||
this.peerStates = new Map(); // Map<peerId, PeerState>
|
||||
|
||||
// 统一使用优化参数 - 所有设备共享最佳配置
|
||||
// Uniformly use optimized parameters - all devices share the best configuration
|
||||
this.chunkSize = FileSender.OPTIMIZED_CONFIG.CHUNK_SIZE;
|
||||
this.pendingFiles = new Map(); // All files pending to be sent (by reference) {fileId: CustomFile}
|
||||
|
||||
@@ -331,7 +331,7 @@ class FileSender {
|
||||
const speed = this.speedCalculator.getSendSpeed(peerId);
|
||||
const progress = totalSize > 0 ? currentBytes / totalSize : 0;
|
||||
|
||||
// 持续更新网络性能(从传输速度学习)
|
||||
// Continuously update network performance (learn from transfer speed)
|
||||
this.updateNetworkFromSpeed(peerId);
|
||||
|
||||
peerState.progressCallback?.(progressFileId, progress, speed);
|
||||
@@ -346,16 +346,16 @@ class FileSender {
|
||||
throw new Error("Data channel not found");
|
||||
}
|
||||
|
||||
// 对于ArrayBuffer,如果超过64KB需要分片发送(修复sendData failed)
|
||||
// For ArrayBuffer, if it exceeds 64KB, it needs to be sent in fragments (fixes sendData failed)
|
||||
if (data instanceof ArrayBuffer) {
|
||||
await this.sendLargeArrayBuffer(data, peerId);
|
||||
} else {
|
||||
// 字符串直接发送
|
||||
// Send string directly
|
||||
await this.sendSingleData(data, peerId);
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:分片发送大ArrayBuffer
|
||||
// New: Send large ArrayBuffer in fragments
|
||||
private async sendLargeArrayBuffer(
|
||||
data: ArrayBuffer,
|
||||
peerId: string
|
||||
@@ -363,13 +363,13 @@ class FileSender {
|
||||
const networkChunkSize = FileSender.OPTIMIZED_CONFIG.NETWORK_CHUNK_SIZE;
|
||||
const totalSize = data.byteLength;
|
||||
|
||||
// 如果数据小于64KB,直接发送
|
||||
// If data is less than 64KB, send directly
|
||||
if (totalSize <= networkChunkSize) {
|
||||
await this.sendSingleData(data, peerId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 分片发送大块
|
||||
// Send large chunks in fragments
|
||||
let offset = 0;
|
||||
let fragmentIndex = 0;
|
||||
|
||||
@@ -377,7 +377,7 @@ class FileSender {
|
||||
const chunkSize = Math.min(networkChunkSize, totalSize - offset);
|
||||
const chunk = data.slice(offset, offset + chunkSize);
|
||||
|
||||
// 发送分片
|
||||
// Send fragment
|
||||
await this.sendSingleData(chunk, peerId);
|
||||
|
||||
offset += chunkSize;
|
||||
@@ -385,7 +385,7 @@ class FileSender {
|
||||
}
|
||||
}
|
||||
|
||||
// 新增:单个数据包发送含主动轮询背压控制
|
||||
// New: Send single data packet with active polling backpressure control
|
||||
private async sendSingleData(
|
||||
data: string | ArrayBuffer,
|
||||
peerId: string
|
||||
@@ -394,29 +394,29 @@ class FileSender {
|
||||
if (!dataChannel) {
|
||||
throw new Error("Data channel not found");
|
||||
}
|
||||
// 智能发送控制 - 根据缓冲区状态决定发送策略
|
||||
// Intelligent send control - decide sending strategy based on buffer status
|
||||
await this.smartBufferControl(dataChannel, peerId);
|
||||
|
||||
// 发送数据
|
||||
// Send data
|
||||
if (!this.webrtcConnection.sendData(data, peerId)) {
|
||||
throw new Error("sendData failed");
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化网络性能监控(传输开始时调用)
|
||||
// Initialize network performance monitoring (called at the start of transfer)
|
||||
private initializeNetworkPerformance(peerId: string): void {
|
||||
if (!this.networkPerformance.has(peerId)) {
|
||||
// 使用保守的初始值
|
||||
// Use conservative initial values
|
||||
this.networkPerformance.set(peerId, {
|
||||
avgClearingRate: 5000, // 5MB/s初始估计
|
||||
avgClearingRate: 5000, // 5MB/s initial estimate
|
||||
optimalThreshold: FileSender.OPTIMIZED_CONFIG.BUFFER_THRESHOLD,
|
||||
avgWaitTime: 50, // 50ms初始估计
|
||||
avgWaitTime: 50, // 50ms initial estimate
|
||||
sampleCount: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 从SpeedCalculator获取当前传输速度并更新网络性能
|
||||
// Get current transfer speed from SpeedCalculator and update network performance
|
||||
private updateNetworkFromSpeed(peerId: string): void {
|
||||
const currentSpeed = this.speedCalculator.getSendSpeed(peerId); // KB/s
|
||||
if (currentSpeed > 0) {
|
||||
@@ -425,7 +425,7 @@ class FileSender {
|
||||
perf.avgClearingRate = currentSpeed;
|
||||
perf.sampleCount++;
|
||||
|
||||
// 每10次速度更新时调整阈值
|
||||
// Adjust threshold every 10 speed updates
|
||||
if (perf.sampleCount % 10 === 0) {
|
||||
this.adjustOptimalThreshold(perf);
|
||||
}
|
||||
@@ -433,7 +433,7 @@ class FileSender {
|
||||
}
|
||||
}
|
||||
|
||||
// 调整最优阈值的共用逻辑
|
||||
// Shared logic for adjusting optimal threshold
|
||||
private adjustOptimalThreshold(perf: {
|
||||
avgClearingRate: number;
|
||||
optimalThreshold: number;
|
||||
@@ -441,16 +441,16 @@ class FileSender {
|
||||
sampleCount: number;
|
||||
}): void {
|
||||
if (perf.avgClearingRate > 8000) {
|
||||
// >8MB/s网络很好
|
||||
// >8MB/s network is good
|
||||
perf.optimalThreshold = Math.max(
|
||||
FileSender.OPTIMIZED_CONFIG.BUFFER_THRESHOLD,
|
||||
6291456
|
||||
); // 6MB
|
||||
} else if (perf.avgClearingRate > 4000) {
|
||||
// >4MB/s网络一般
|
||||
// >4MB/s network is average
|
||||
perf.optimalThreshold = FileSender.OPTIMIZED_CONFIG.BUFFER_THRESHOLD; // 3MB
|
||||
} else {
|
||||
// 网络较差
|
||||
// Poor network
|
||||
perf.optimalThreshold = Math.min(
|
||||
FileSender.OPTIMIZED_CONFIG.BUFFER_THRESHOLD,
|
||||
1572864
|
||||
@@ -458,7 +458,7 @@ class FileSender {
|
||||
}
|
||||
}
|
||||
|
||||
// 自适应网络性能学习(从背压等待中学习)
|
||||
// Adaptive network performance learning (learn from backpressure waiting)
|
||||
private updateNetworkPerformance(
|
||||
peerId: string,
|
||||
clearingRate: number,
|
||||
@@ -470,16 +470,16 @@ class FileSender {
|
||||
|
||||
const perf = this.networkPerformance.get(peerId)!;
|
||||
perf.sampleCount++;
|
||||
// 指数移动平均,新数据权重更高
|
||||
// Exponential moving average, with higher weight for new data
|
||||
const alpha = 0.3;
|
||||
perf.avgClearingRate =
|
||||
perf.avgClearingRate * (1 - alpha) + clearingRate * alpha;
|
||||
perf.avgWaitTime = perf.avgWaitTime * (1 - alpha) + waitTime * alpha;
|
||||
// 调整最优阈值
|
||||
// Adjust optimal threshold
|
||||
this.adjustOptimalThreshold(perf);
|
||||
}
|
||||
|
||||
// 获取自适应阈值
|
||||
// Get adaptive threshold
|
||||
private getAdaptiveThreshold(peerId: string): number {
|
||||
const perf = this.networkPerformance.get(peerId);
|
||||
return perf
|
||||
@@ -487,7 +487,7 @@ class FileSender {
|
||||
: FileSender.OPTIMIZED_CONFIG.BUFFER_THRESHOLD;
|
||||
}
|
||||
|
||||
// 自适应智能发送控制策略
|
||||
// Adaptive intelligent send control strategy
|
||||
private async intelligentSendControl(
|
||||
dataChannel: RTCDataChannel,
|
||||
peerId: string
|
||||
@@ -496,7 +496,7 @@ class FileSender {
|
||||
const adaptiveThreshold = this.getAdaptiveThreshold(peerId);
|
||||
const utilizationRate = bufferedAmount / adaptiveThreshold;
|
||||
|
||||
// 动态调整策略阈值:基于网络性能
|
||||
// Dynamically adjust strategy thresholds: based on network performance
|
||||
const perf = this.networkPerformance.get(peerId);
|
||||
const networkQuality = perf
|
||||
? perf.avgClearingRate > 6000
|
||||
@@ -509,14 +509,14 @@ class FileSender {
|
||||
let cautiousThreshold = 0.9;
|
||||
|
||||
if (networkQuality === "good") {
|
||||
// 网络好:更激进的策略
|
||||
aggressiveThreshold = 0.4; // 40%以下积极发送
|
||||
normalThreshold = 0.7; // 70%以下正常发送
|
||||
// Good network: more aggressive strategy
|
||||
aggressiveThreshold = 0.4; // Actively send below 40%
|
||||
normalThreshold = 0.7; // Normal send below 70%
|
||||
} else if (networkQuality === "poor") {
|
||||
// 网络差:更保守的策略
|
||||
aggressiveThreshold = 0.2; // 20%以下才积极发送
|
||||
normalThreshold = 0.5; // 50%以下正常发送
|
||||
cautiousThreshold = 0.8; // 80%以上就要等待
|
||||
// Poor network: more conservative strategy
|
||||
aggressiveThreshold = 0.2; // Actively send only below 20%
|
||||
normalThreshold = 0.5; // Normal send below 50%
|
||||
cautiousThreshold = 0.8; // Wait above 80%
|
||||
}
|
||||
if (utilizationRate < aggressiveThreshold) {
|
||||
return "AGGRESSIVE";
|
||||
@@ -529,7 +529,7 @@ class FileSender {
|
||||
}
|
||||
}
|
||||
|
||||
// 智能等待策略 - 根据缓冲区状态调整发送控制
|
||||
// Intelligent waiting strategy - adjust send control based on buffer status
|
||||
private async smartBufferControl(
|
||||
dataChannel: RTCDataChannel,
|
||||
peerId: string
|
||||
@@ -537,19 +537,19 @@ class FileSender {
|
||||
const strategy = await this.intelligentSendControl(dataChannel, peerId);
|
||||
|
||||
if (strategy === "AGGRESSIVE") {
|
||||
// 积极模式:无需等待,立即发送
|
||||
// Aggressive mode: no need to wait, send immediately
|
||||
return;
|
||||
} else if (strategy === "NORMAL") {
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, 5));
|
||||
// 正常模式:少许等待
|
||||
// Normal mode: slight wait
|
||||
return;
|
||||
} else if (strategy === "CAUTIOUS") {
|
||||
// 谨慎模式:短暂等待让网络消费一些数据
|
||||
// Cautious mode: brief wait to let the network consume some data
|
||||
await new Promise<void>((resolve) => setTimeout(resolve, 10));
|
||||
return;
|
||||
}
|
||||
|
||||
// WAIT模式:需要主动轮询等待
|
||||
// WAIT mode: requires active polling wait
|
||||
const POLLING_INTERVAL = 5;
|
||||
const MAX_WAIT_TIME = 3000;
|
||||
const startTime = Date.now();
|
||||
@@ -574,20 +574,20 @@ class FileSender {
|
||||
);
|
||||
}
|
||||
|
||||
// 记录等待结束状态
|
||||
// Record wait end status
|
||||
const waitTime = Date.now() - startTime;
|
||||
const finalBuffered = dataChannel.bufferedAmount;
|
||||
const clearedBytes = initialBuffered - finalBuffered;
|
||||
const clearingRate =
|
||||
waitTime > 0 ? clearedBytes / 1024 / (waitTime / 1000) : 0;
|
||||
|
||||
// 更新网络性能学习
|
||||
// Update network performance learning
|
||||
if (clearingRate > 0) {
|
||||
this.updateNetworkPerformance(peerId, clearingRate, waitTime);
|
||||
}
|
||||
}
|
||||
|
||||
// 读取单个文件块的优化方法
|
||||
// Optimized method for reading a single file chunk
|
||||
private readSingleChunk(
|
||||
fileReader: FileReader,
|
||||
file: CustomFile,
|
||||
@@ -609,7 +609,7 @@ class FileSender {
|
||||
});
|
||||
}
|
||||
|
||||
// 批量读取多个文件块,提升I/O性能
|
||||
// Batch read multiple file chunks to improve I/O performance
|
||||
private async readMultipleChunks(
|
||||
fileReader: FileReader,
|
||||
file: CustomFile,
|
||||
@@ -641,7 +641,7 @@ class FileSender {
|
||||
return chunks;
|
||||
}
|
||||
|
||||
// 统一优化版本 - 使用批量读取+循环,适用于所有设备
|
||||
// Unified optimized version - uses batch reading + loop, suitable for all devices
|
||||
private async processSendQueue(
|
||||
file: CustomFile,
|
||||
peerId: string
|
||||
@@ -653,14 +653,14 @@ class FileSender {
|
||||
let offset = peerState.readOffset || 0;
|
||||
const batchSize = FileSender.OPTIMIZED_CONFIG.BATCH_SIZE;
|
||||
|
||||
// 初始化网络性能监控
|
||||
// Initialize network performance monitoring
|
||||
this.initializeNetworkPerformance(peerId);
|
||||
|
||||
try {
|
||||
// 使用批量读取+循环替代传统递归,大幅提升性能
|
||||
// Use batch reading + loop instead of traditional recursion to greatly improve performance
|
||||
while (offset < file.size && peerState.isSending) {
|
||||
|
||||
// 批量读取多个大块 - 充分利用内存优势
|
||||
// Batch read multiple large chunks - fully utilize memory advantages
|
||||
const chunks = await this.readMultipleChunks(
|
||||
fileReader,
|
||||
file,
|
||||
@@ -673,14 +673,14 @@ class FileSender {
|
||||
|
||||
for (const chunk of chunks) {
|
||||
if (!peerState.isSending || offset >= file.size) break;
|
||||
// 使用标准的智能控制发送
|
||||
// Use standard intelligent control sending
|
||||
await this.sendWithBackpressure(chunk, peerId);
|
||||
|
||||
// 更新进度
|
||||
// Update progress
|
||||
offset += chunk.byteLength;
|
||||
peerState.readOffset = offset;
|
||||
|
||||
// 更新文件和文件夹进度
|
||||
// Update file and folder progress
|
||||
await this.updateProgress(
|
||||
chunk.byteLength,
|
||||
fileId,
|
||||
@@ -689,7 +689,7 @@ class FileSender {
|
||||
);
|
||||
}
|
||||
}
|
||||
// 文件发送完毕
|
||||
// File sending completed
|
||||
if (offset >= file.size && !peerState.currentFolderName) {
|
||||
peerState.progressCallback?.(fileId, 1, 0);
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class WebRTCService {
|
||||
}
|
||||
|
||||
private initializeEventHandlers(): void {
|
||||
// 发送方事件处理
|
||||
// Sender event handling
|
||||
this.sender.onConnectionStateChange = (state, peerId) => {
|
||||
useFileTransferStore.getState().setShareConnectionState(state as any);
|
||||
useFileTransferStore
|
||||
@@ -59,7 +59,7 @@ class WebRTCService {
|
||||
|
||||
this.sender.onDataChannelOpen = (peerId) => {
|
||||
useFileTransferStore.getState().setIsSenderInRoom(true);
|
||||
// 自动广播当前内容
|
||||
// Automatically broadcast current content
|
||||
this.broadcastDataToAllPeers();
|
||||
};
|
||||
|
||||
@@ -72,10 +72,10 @@ class WebRTCService {
|
||||
};
|
||||
|
||||
this.sender.onError = (error) => {
|
||||
console.error("[WebRTC Service] 发送方错误:", error.message);
|
||||
console.error("[WebRTC Service] Sender error:", error.message);
|
||||
};
|
||||
|
||||
// 接收方事件处理
|
||||
// Receiver event handling
|
||||
this.receiver.onConnectionStateChange = (state, peerId) => {
|
||||
useFileTransferStore.getState().setRetrieveConnectionState(state as any);
|
||||
useFileTransferStore
|
||||
@@ -123,10 +123,10 @@ class WebRTCService {
|
||||
};
|
||||
|
||||
this.fileReceiver.onFileReceived = async (file) => {
|
||||
// 🔧 增强修复:确保Store状态更新完全同步,使用多重验证
|
||||
// 🔧 Enhanced fix: Ensure Store state updates are fully synchronized with multiple verifications
|
||||
const store = useFileTransferStore.getState();
|
||||
|
||||
// 检查文件是否已经存在,避免重复添加
|
||||
// Check if file already exists to avoid duplicates
|
||||
const existingFile = store.retrievedFiles.find(
|
||||
(f) => f.name === file.name && f.size === file.size
|
||||
);
|
||||
@@ -135,7 +135,7 @@ class WebRTCService {
|
||||
store.addRetrievedFile(file);
|
||||
}
|
||||
|
||||
// 🔧 额外确保:立即验证状态更新是否成功,并重试机制
|
||||
// 🔧 Additional ensure: Immediately verify if state update was successful with retry mechanism
|
||||
let verificationAttempts = 0;
|
||||
const maxVerificationAttempts = 3;
|
||||
|
||||
@@ -152,12 +152,12 @@ class WebRTCService {
|
||||
}
|
||||
};
|
||||
|
||||
// 立即进行第一次验证
|
||||
// Perform first verification immediately
|
||||
verifyFileAdded();
|
||||
};
|
||||
}
|
||||
|
||||
// 业务方法
|
||||
// Business methods
|
||||
public async joinRoom(roomId: string, isSender: boolean): Promise<void> {
|
||||
const peer = isSender ? this.sender : this.receiver;
|
||||
await peer.joinRoom(roomId, isSender);
|
||||
@@ -184,7 +184,7 @@ class WebRTCService {
|
||||
const { shareContent, sendFiles } = useFileTransferStore.getState();
|
||||
const peerIds = Array.from(this.sender.peerConnections.keys());
|
||||
if (peerIds.length === 0) {
|
||||
console.warn("[WebRTC Service] 没有连接的对等端进行广播");
|
||||
console.warn("[WebRTC Service] No connected peers to broadcast to");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -201,7 +201,7 @@ class WebRTCService {
|
||||
);
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error("[WebRTC Service] 广播失败:", error);
|
||||
console.error("[WebRTC Service] Broadcast failed:", error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -229,15 +229,15 @@ class WebRTCService {
|
||||
}
|
||||
|
||||
public async cleanup(): Promise<void> {
|
||||
console.log("[WebRTC Service] 开始清理...");
|
||||
console.log("[WebRTC Service] Starting cleanup...");
|
||||
try {
|
||||
await Promise.all([
|
||||
this.sender.cleanUpBeforeExit(),
|
||||
this.receiver.cleanUpBeforeExit(),
|
||||
]);
|
||||
console.log("[WebRTC Service] 清理完成");
|
||||
console.log("[WebRTC Service] Cleanup completed");
|
||||
} catch (error) {
|
||||
console.error("[WebRTC Service] 清理过程中出错:", error);
|
||||
console.error("[WebRTC Service] Error during cleanup:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export default class WebRTC_Initiator extends BaseWebRTC {
|
||||
});
|
||||
// this.log('log', `Created data channel for peer ${peerId}`);
|
||||
|
||||
dataChannel.bufferedAmountLowThreshold = 262144; //256 KB -- 可以根据需要调整
|
||||
dataChannel.bufferedAmountLowThreshold = 262144; //256 KB -- Can be adjusted as needed
|
||||
this.setupDataChannel(dataChannel, peerId);
|
||||
this.dataChannels.set(peerId, dataChannel);
|
||||
} catch (error) {
|
||||
|
||||
@@ -2,14 +2,14 @@ import { create } from "zustand";
|
||||
import { CustomFile, FileMeta } from "@/types/webrtc";
|
||||
|
||||
interface FileTransferState {
|
||||
// 房间相关状态
|
||||
// Room-related state
|
||||
shareRoomId: string;
|
||||
initShareRoomId: string;
|
||||
shareLink: string;
|
||||
shareRoomStatusText: string;
|
||||
retrieveRoomStatusText: string;
|
||||
|
||||
// WebRTC 连接状态 - 发送方
|
||||
// WebRTC connection state - Sender
|
||||
shareConnectionState:
|
||||
| "idle"
|
||||
| "connecting"
|
||||
@@ -19,7 +19,7 @@ interface FileTransferState {
|
||||
isSenderInRoom: boolean;
|
||||
sharePeerCount: number;
|
||||
|
||||
// WebRTC 连接状态 - 接收方
|
||||
// WebRTC connection state - Receiver
|
||||
retrieveConnectionState:
|
||||
| "idle"
|
||||
| "connecting"
|
||||
@@ -30,36 +30,36 @@ interface FileTransferState {
|
||||
retrievePeerCount: number;
|
||||
senderDisconnected: boolean;
|
||||
|
||||
// 文件传输状态
|
||||
// File transfer state
|
||||
shareContent: string;
|
||||
sendFiles: CustomFile[];
|
||||
retrievedContent: string;
|
||||
retrievedFiles: CustomFile[];
|
||||
retrievedFileMetas: FileMeta[];
|
||||
|
||||
// 传输进度状态
|
||||
// Transfer progress state
|
||||
sendProgress: Record<string, any>;
|
||||
receiveProgress: Record<string, any>;
|
||||
isAnyFileTransferring: boolean;
|
||||
|
||||
// UI 状态
|
||||
// UI state
|
||||
activeTab: "send" | "retrieve";
|
||||
retrieveRoomIdInput: string;
|
||||
isDragging: boolean;
|
||||
|
||||
// 消息状态
|
||||
// Message state
|
||||
shareMessage: string;
|
||||
retrieveMessage: string;
|
||||
|
||||
// Actions
|
||||
// 房间相关 actions
|
||||
// Room-related actions
|
||||
setShareRoomId: (id: string) => void;
|
||||
setInitShareRoomId: (id: string) => void;
|
||||
setShareLink: (link: string) => void;
|
||||
setShareRoomStatusText: (text: string) => void;
|
||||
setRetrieveRoomStatusText: (text: string) => void;
|
||||
|
||||
// WebRTC 连接相关 actions
|
||||
// WebRTC connection-related actions
|
||||
setShareConnectionState: (
|
||||
state: "idle" | "connecting" | "connected" | "disconnected" | "failed"
|
||||
) => void;
|
||||
@@ -72,7 +72,7 @@ interface FileTransferState {
|
||||
setRetrievePeerCount: (count: number) => void;
|
||||
setSenderDisconnected: (disconnected: boolean) => void;
|
||||
|
||||
// 文件传输相关 actions
|
||||
// File transfer-related actions
|
||||
setShareContent: (content: string) => void;
|
||||
setSendFiles: (files: CustomFile[]) => void;
|
||||
addSendFiles: (files: CustomFile[]) => void;
|
||||
@@ -82,7 +82,7 @@ interface FileTransferState {
|
||||
setRetrievedFileMetas: (metas: FileMeta[]) => void;
|
||||
addRetrievedFile: (file: CustomFile) => void;
|
||||
|
||||
// 传输进度相关 actions
|
||||
// Transfer progress-related actions
|
||||
setSendProgress: (progress: Record<string, any>) => void;
|
||||
setReceiveProgress: (progress: Record<string, any>) => void;
|
||||
updateSendProgress: (
|
||||
@@ -99,23 +99,23 @@ interface FileTransferState {
|
||||
clearReceiveProgress: (fileId: string, peerId: string) => void;
|
||||
setIsAnyFileTransferring: (transferring: boolean) => void;
|
||||
|
||||
// UI 状态相关 actions
|
||||
// UI state-related actions
|
||||
setActiveTab: (tab: "send" | "retrieve") => void;
|
||||
setRetrieveRoomIdInput: (input: string) => void;
|
||||
setIsDragging: (dragging: boolean) => void;
|
||||
|
||||
// 消息相关 actions
|
||||
// Message-related actions
|
||||
setShareMessage: (message: string) => void;
|
||||
setRetrieveMessage: (message: string) => void;
|
||||
setRetrieveRoomId: (input: string) => void;
|
||||
|
||||
// 重置相关 actions
|
||||
// Reset-related actions
|
||||
resetReceiverState: () => void;
|
||||
resetSenderApp: () => void;
|
||||
}
|
||||
|
||||
export const useFileTransferStore = create<FileTransferState>()((set, get) => ({
|
||||
// 初始状态
|
||||
// Initial state
|
||||
shareRoomId: "",
|
||||
initShareRoomId: "",
|
||||
shareLink: "",
|
||||
@@ -142,14 +142,14 @@ export const useFileTransferStore = create<FileTransferState>()((set, get) => ({
|
||||
shareMessage: "",
|
||||
retrieveMessage: "",
|
||||
|
||||
// Actions 实现
|
||||
// Actions implementation
|
||||
setShareRoomId: (id) => set({ shareRoomId: id }),
|
||||
setInitShareRoomId: (id) => set({ initShareRoomId: id }),
|
||||
setShareLink: (link) => set({ shareLink: link }),
|
||||
setShareRoomStatusText: (text) => set({ shareRoomStatusText: text }),
|
||||
setRetrieveRoomStatusText: (text) => set({ retrieveRoomStatusText: text }),
|
||||
|
||||
// WebRTC 连接相关 actions
|
||||
// WebRTC connection-related actions
|
||||
setShareConnectionState: (state) => set({ shareConnectionState: state }),
|
||||
setIsSenderInRoom: (isInRoom) => set({ isSenderInRoom: isInRoom }),
|
||||
setSharePeerCount: (count) => set({ sharePeerCount: count }),
|
||||
@@ -238,18 +238,18 @@ export const useFileTransferStore = create<FileTransferState>()((set, get) => ({
|
||||
setRetrieveMessage: (message) => set({ retrieveMessage: message }),
|
||||
|
||||
resetReceiverState: () => {
|
||||
// 🔧 清理 FileReceiver 的内部状态(通过 Service 层)
|
||||
// 🔧 Clean up FileReceiver's internal state (via Service layer)
|
||||
try {
|
||||
const { webrtcService } = require("@/lib/webrtcService");
|
||||
webrtcService.fileReceiver.gracefulShutdown();
|
||||
} catch (error) {
|
||||
console.warn(`[DEBUG] ⚠️ 清理 FileReceiver 状态失败:`, error);
|
||||
console.warn(`[DEBUG] ⚠️ Failed to clean up FileReceiver state:`, error);
|
||||
}
|
||||
|
||||
set({
|
||||
retrievedContent: "",
|
||||
retrievedFiles: [],
|
||||
retrievedFileMetas: [], // 清空 Store 中的文件元数据
|
||||
retrievedFileMetas: [], // Clear file metadata in Store
|
||||
retrievePeerCount: 0,
|
||||
senderDisconnected: false,
|
||||
receiveProgress: {},
|
||||
|
||||
Reference in New Issue
Block a user