It is found that the order of data packets received by Firefox is disordered
This commit is contained in:
+114
-77
@@ -1,5 +1,5 @@
|
||||
// 🚀 新流程 - 接收端主导的文件传输:
|
||||
// 1. 接收文件元数据 (fileMetadata)
|
||||
// 1. 接收文件元数据 (fileMetadata)
|
||||
// 2. 用户点击下载,发送文件请求 (fileRequest)
|
||||
// 3. 接收所有数据块,自动检测完整性
|
||||
// 4. 完成Store同步后,主动发送完成确认 (fileReceiveComplete/folderReceiveComplete)
|
||||
@@ -187,7 +187,7 @@ class FileReceiver {
|
||||
|
||||
const receptionPromise = new Promise<void>((resolve, reject) => {
|
||||
const expectedChunksCount = Math.ceil((fileInfo.size - offset) / 65536); // 计算预期chunk数量
|
||||
|
||||
|
||||
this.activeFileReception = {
|
||||
meta: fileInfo,
|
||||
chunks: [],
|
||||
@@ -284,7 +284,7 @@ class FileReceiver {
|
||||
|
||||
// 🚀 新流程:发送文件夹接收完成确认
|
||||
// 收集所有成功完成的文件ID
|
||||
const completedFileIds = folderProgress.fileIds.filter(fileId => {
|
||||
const completedFileIds = folderProgress.fileIds.filter((fileId) => {
|
||||
// 这里可以添加更复杂的验证逻辑,现在简单假设都成功了
|
||||
return true;
|
||||
});
|
||||
@@ -299,21 +299,23 @@ class FileReceiver {
|
||||
// endregion
|
||||
|
||||
// region WebRTC Data Handlers
|
||||
|
||||
|
||||
/**
|
||||
* 将各种二进制数据格式转换为ArrayBuffer
|
||||
* 支持Firefox的Blob、Uint8Array等格式
|
||||
*/
|
||||
private async convertToArrayBuffer(data: any): Promise<ArrayBuffer | null> {
|
||||
const originalType = Object.prototype.toString.call(data);
|
||||
|
||||
|
||||
if (data instanceof ArrayBuffer) {
|
||||
return data;
|
||||
} else if (data instanceof Blob) {
|
||||
try {
|
||||
const arrayBuffer = await data.arrayBuffer();
|
||||
if (data.size !== arrayBuffer.byteLength) {
|
||||
postLogToBackend(`[DEBUG] ⚠️ Blob size mismatch: ${data.size}→${arrayBuffer.byteLength}`);
|
||||
postLogToBackend(
|
||||
`[DEBUG] ⚠️ Blob size mismatch: ${data.size}→${arrayBuffer.byteLength}`
|
||||
);
|
||||
}
|
||||
return arrayBuffer;
|
||||
} catch (error) {
|
||||
@@ -322,9 +324,10 @@ class FileReceiver {
|
||||
}
|
||||
} else if (data instanceof Uint8Array || ArrayBuffer.isView(data)) {
|
||||
try {
|
||||
const uint8Array = data instanceof Uint8Array
|
||||
? data
|
||||
: new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
||||
const uint8Array =
|
||||
data instanceof Uint8Array
|
||||
? data
|
||||
: new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
||||
const newArrayBuffer = new ArrayBuffer(uint8Array.length);
|
||||
new Uint8Array(newArrayBuffer).set(uint8Array);
|
||||
return newArrayBuffer;
|
||||
@@ -333,7 +336,9 @@ class FileReceiver {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
postLogToBackend(`[DEBUG] ❌ Unknown data type: ${Object.prototype.toString.call(data)}`);
|
||||
postLogToBackend(
|
||||
`[DEBUG] ❌ Unknown data type: ${Object.prototype.toString.call(data)}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -363,13 +368,8 @@ class FileReceiver {
|
||||
} else {
|
||||
// 处理各种格式的二进制数据 - Firefox兼容性修复
|
||||
const arrayBuffer = await this.convertToArrayBuffer(data);
|
||||
|
||||
if (arrayBuffer) {
|
||||
// 调试日志:记录接收到二进制数据
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] Received binary data - originalType: ${Object.prototype.toString.call(data)}, convertedSize: ${arrayBuffer.byteLength}, peerId: ${peerId}`
|
||||
);
|
||||
|
||||
if (arrayBuffer) {
|
||||
if (!this.activeFileReception) {
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] ERROR: Received file chunk but no active file reception!`
|
||||
@@ -381,9 +381,6 @@ class FileReceiver {
|
||||
return;
|
||||
}
|
||||
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] Processing chunk for file: ${this.activeFileReception.meta.name}`
|
||||
);
|
||||
this.updateProgress(arrayBuffer.byteLength);
|
||||
await this.handleFileChunk(arrayBuffer);
|
||||
} else {
|
||||
@@ -392,7 +389,7 @@ class FileReceiver {
|
||||
);
|
||||
this.fireError("Received unsupported binary data format", {
|
||||
dataType: Object.prototype.toString.call(data),
|
||||
peerId
|
||||
peerId,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -460,35 +457,49 @@ class FileReceiver {
|
||||
|
||||
// 🐛 DEBUG: 记录接收到的原始chunk信息
|
||||
const currentChunkIndex = this.activeFileReception.receivedChunksCount;
|
||||
postLogToBackend(
|
||||
`[DEBUG] 📥 RECEIVE chunk#${currentChunkIndex} - size: ${chunk.byteLength} bytes`
|
||||
);
|
||||
|
||||
// 更新统计信息
|
||||
this.activeFileReception.receivedChunksCount++;
|
||||
this.activeFileReception.lastChunkIndex = Math.max(this.activeFileReception.lastChunkIndex, currentChunkIndex);
|
||||
|
||||
this.activeFileReception.lastChunkIndex = Math.max(
|
||||
this.activeFileReception.lastChunkIndex,
|
||||
currentChunkIndex
|
||||
);
|
||||
|
||||
// 更新进度统计
|
||||
this.updateProgress(chunk.byteLength);
|
||||
|
||||
|
||||
if (this.activeFileReception.writeStream) {
|
||||
await this.writeLargeFileChunk(chunk);
|
||||
} else {
|
||||
// 存储chunk到内存
|
||||
this.activeFileReception.chunks.push(chunk);
|
||||
|
||||
|
||||
// 🐛 DEBUG: 验证存储结果
|
||||
const storedChunk = this.activeFileReception.chunks[this.activeFileReception.chunks.length - 1];
|
||||
const currentTotalSize = this.activeFileReception.chunks.reduce((sum, c) => sum + (c?.byteLength || 0), 0);
|
||||
|
||||
postLogToBackend(
|
||||
`[DEBUG] 📦 STORED chunk#${currentChunkIndex} - original: ${chunk.byteLength}, stored: ${storedChunk?.byteLength || 'null'}, total: ${currentTotalSize}`
|
||||
const storedChunk =
|
||||
this.activeFileReception.chunks[
|
||||
this.activeFileReception.chunks.length - 1
|
||||
];
|
||||
const currentTotalSize = this.activeFileReception.chunks.reduce(
|
||||
(sum, c) => sum + (c?.byteLength || 0),
|
||||
0
|
||||
);
|
||||
|
||||
|
||||
postLogToBackend(
|
||||
`[DEBUG] 📦 STORED chunk#${currentChunkIndex} - original: ${
|
||||
chunk.byteLength
|
||||
}, stored: ${
|
||||
storedChunk?.byteLength || "null"
|
||||
}, total: ${currentTotalSize}`
|
||||
);
|
||||
|
||||
// 🐛 DEBUG: 特别关注最后几个chunks
|
||||
if (currentChunkIndex >= 65) {
|
||||
postLogToBackend(
|
||||
`[DEBUG] 🔍 CRITICAL_CHUNK#${currentChunkIndex} - input: ${chunk.byteLength}, stored: ${storedChunk?.byteLength}, isLast: ${currentChunkIndex >= 67}`
|
||||
`[DEBUG] 🔍 CRITICAL_CHUNK#${currentChunkIndex} - input: ${
|
||||
chunk.byteLength
|
||||
}, stored: ${storedChunk?.byteLength}, isLast: ${
|
||||
currentChunkIndex >= 67
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -506,44 +517,41 @@ class FileReceiver {
|
||||
const reception = this.activeFileReception;
|
||||
const receivedChunks = reception.receivedChunksCount;
|
||||
const expectedChunks = reception.expectedChunksCount;
|
||||
|
||||
|
||||
// 计算当前实际接收的总大小
|
||||
const currentTotalSize = reception.chunks.reduce((sum, chunk) => {
|
||||
return sum + (chunk instanceof ArrayBuffer ? chunk.byteLength : 0);
|
||||
}, 0);
|
||||
const expectedSize = reception.meta.size;
|
||||
|
||||
const chunksComplete = (receivedChunks >= expectedChunks);
|
||||
const sizeComplete = (currentTotalSize >= expectedSize);
|
||||
|
||||
const chunksComplete = receivedChunks >= expectedChunks;
|
||||
const sizeComplete = currentTotalSize >= expectedSize;
|
||||
const isDataComplete = chunksComplete && sizeComplete;
|
||||
|
||||
// 🐛 DEBUG: 完成状态检查
|
||||
if (receivedChunks % 10 === 0 || receivedChunks >= expectedChunks - 5) {
|
||||
postLogToBackend(
|
||||
`[DEBUG] 🔄 Progress check - chunks: ${receivedChunks}/${expectedChunks}, size: ${currentTotalSize}/${expectedSize}, complete: ${isDataComplete}`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
postLogToBackend(
|
||||
`[DEBUG] 🔄 Progress check - chunks: ${receivedChunks}/${expectedChunks}, size: ${currentTotalSize}/${expectedSize}, complete: ${isDataComplete}, isFinalized:${reception.isFinalized}`
|
||||
);
|
||||
|
||||
// 防止重复finalize
|
||||
if (reception.isFinalized) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (isDataComplete) {
|
||||
postLogToBackend(
|
||||
`[DEBUG] 🎯 TRIGGERING finalize - chunks: ${receivedChunks}/${expectedChunks}, size: ${currentTotalSize}/${expectedSize}`
|
||||
);
|
||||
|
||||
|
||||
reception.isFinalized = true;
|
||||
|
||||
|
||||
try {
|
||||
await this.finalizeFileReceive();
|
||||
|
||||
|
||||
if (reception.completionNotifier) {
|
||||
reception.completionNotifier.resolve();
|
||||
}
|
||||
this.activeFileReception = null;
|
||||
|
||||
|
||||
postLogToBackend(`[DEBUG] ✅ Auto-finalize SUCCESS`);
|
||||
} catch (error) {
|
||||
postLogToBackend(`[DEBUG] ❌ Auto-finalize ERROR: ${error}`);
|
||||
@@ -693,56 +701,79 @@ class FileReceiver {
|
||||
let totalChunkSize = 0;
|
||||
let validChunks = 0;
|
||||
const chunkDetails: string[] = [];
|
||||
|
||||
|
||||
reception.chunks.forEach((chunk, index) => {
|
||||
if (chunk instanceof ArrayBuffer) {
|
||||
validChunks++;
|
||||
totalChunkSize += chunk.byteLength;
|
||||
|
||||
|
||||
// 🐛 DEBUG: 特别关注最后几个chunks
|
||||
if (index >= reception.chunks.length - 5) {
|
||||
chunkDetails.push(`chunk#${index}: ${chunk.byteLength}bytes`);
|
||||
postLogToBackend(
|
||||
`[DEBUG] 🔍 FINAL_CHUNK_ANALYSIS - index: ${index}, size: ${chunk.byteLength}, isLast: ${index === reception.chunks.length - 1}`
|
||||
`[DEBUG] 🔍 FINAL_CHUNK_ANALYSIS - index: ${index}, size: ${
|
||||
chunk.byteLength
|
||||
}, isLast: ${index === reception.chunks.length - 1}`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// 检测异常大小
|
||||
if (chunk.byteLength !== 65536 && index < reception.chunks.length - 1) {
|
||||
postLogToBackend(`[DEBUG] ⚠️ UNEXPECTED_SIZE - chunk#${index}: ${chunk.byteLength} (should be 65536)`);
|
||||
postLogToBackend(
|
||||
`[DEBUG] ⚠️ UNEXPECTED_SIZE - chunk#${index}: ${chunk.byteLength} (should be 65536)`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
postLogToBackend(`[DEBUG] ❌ INVALID_CHUNK - index: ${index}, type: ${Object.prototype.toString.call(chunk)}`);
|
||||
postLogToBackend(
|
||||
`[DEBUG] ❌ INVALID_CHUNK - index: ${index}, type: ${Object.prototype.toString.call(
|
||||
chunk
|
||||
)}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// 🐛 DEBUG: 总体分析
|
||||
postLogToBackend(
|
||||
`[DEBUG] 📊 CHUNK_SUMMARY - valid: ${validChunks}/${reception.chunks.length}, totalSize: ${totalChunkSize}, expected: ${reception.meta.size}, diff: ${reception.meta.size - totalChunkSize}`
|
||||
`[DEBUG] 📊 CHUNK_SUMMARY - valid: ${validChunks}/${
|
||||
reception.chunks.length
|
||||
}, totalSize: ${totalChunkSize}, expected: ${
|
||||
reception.meta.size
|
||||
}, diff: ${reception.meta.size - totalChunkSize}`
|
||||
);
|
||||
|
||||
|
||||
if (chunkDetails.length > 0) {
|
||||
postLogToBackend(`[DEBUG] 🔍 FINAL_CHUNKS: ${chunkDetails.join(', ')}`);
|
||||
postLogToBackend(`[DEBUG] 🔍 FINAL_CHUNKS: ${chunkDetails.join(", ")}`);
|
||||
}
|
||||
|
||||
// 最终验证
|
||||
const sizeDifference = reception.meta.size - totalChunkSize;
|
||||
if (sizeDifference !== 0) {
|
||||
postLogToBackend(`[DEBUG] ❌ SIZE_MISMATCH - missing: ${sizeDifference} bytes`);
|
||||
postLogToBackend(
|
||||
`[DEBUG] ❌ SIZE_MISMATCH - missing: ${sizeDifference} bytes`
|
||||
);
|
||||
} else {
|
||||
postLogToBackend(`[DEBUG] ✅ SIZE_VERIFIED - ${totalChunkSize} bytes`);
|
||||
}
|
||||
|
||||
|
||||
// 创建文件
|
||||
const fileBlob = new Blob(reception.chunks.filter(chunk => chunk instanceof ArrayBuffer) as ArrayBuffer[], {
|
||||
type: reception.meta.fileType,
|
||||
});
|
||||
|
||||
const fileBlob = new Blob(
|
||||
reception.chunks.filter(
|
||||
(chunk) => chunk instanceof ArrayBuffer
|
||||
) as ArrayBuffer[],
|
||||
{
|
||||
type: reception.meta.fileType,
|
||||
}
|
||||
);
|
||||
|
||||
const file = new File([fileBlob], reception.meta.name, {
|
||||
type: reception.meta.fileType,
|
||||
});
|
||||
|
||||
postLogToBackend(`[DEBUG] 📄 FILE_CREATED - size: ${file.size}, expected: ${reception.meta.size}, match: ${file.size === reception.meta.size}`);
|
||||
|
||||
postLogToBackend(
|
||||
`[DEBUG] 📄 FILE_CREATED - size: ${file.size}, expected: ${
|
||||
reception.meta.size
|
||||
}, match: ${file.size === reception.meta.size}`
|
||||
);
|
||||
|
||||
const customFile = Object.assign(file, {
|
||||
fullName: reception.meta.fullName,
|
||||
@@ -755,7 +786,7 @@ class FileReceiver {
|
||||
await Promise.resolve();
|
||||
await new Promise<void>((resolve) => setTimeout(() => resolve(), 0));
|
||||
storeUpdated = true;
|
||||
|
||||
|
||||
postLogToBackend(`[DEBUG] ✅ STORE_UPDATED - ${reception.meta.name}`);
|
||||
}
|
||||
|
||||
@@ -781,7 +812,7 @@ class FileReceiver {
|
||||
storeUpdated: boolean
|
||||
): void {
|
||||
if (!this.peerId) return;
|
||||
|
||||
|
||||
const completeMessage: FileReceiveComplete = {
|
||||
type: "fileReceiveComplete",
|
||||
fileId,
|
||||
@@ -789,9 +820,12 @@ class FileReceiver {
|
||||
receivedChunks,
|
||||
storeUpdated,
|
||||
};
|
||||
|
||||
const success = this.webrtcConnection.sendData(JSON.stringify(completeMessage), this.peerId);
|
||||
|
||||
|
||||
const success = this.webrtcConnection.sendData(
|
||||
JSON.stringify(completeMessage),
|
||||
this.peerId
|
||||
);
|
||||
|
||||
postLogToBackend(
|
||||
`[DEBUG] 📤 SENT fileReceiveComplete - size: ${receivedSize}, chunks: ${receivedChunks}, success: ${success}`
|
||||
);
|
||||
@@ -806,16 +840,19 @@ class FileReceiver {
|
||||
allStoreUpdated: boolean
|
||||
): void {
|
||||
if (!this.peerId) return;
|
||||
|
||||
|
||||
const completeMessage: FolderReceiveComplete = {
|
||||
type: "folderReceiveComplete",
|
||||
folderName,
|
||||
completedFileIds,
|
||||
allStoreUpdated,
|
||||
};
|
||||
|
||||
const success = this.webrtcConnection.sendData(JSON.stringify(completeMessage), this.peerId);
|
||||
|
||||
|
||||
const success = this.webrtcConnection.sendData(
|
||||
JSON.stringify(completeMessage),
|
||||
this.peerId
|
||||
);
|
||||
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] 📤 Sent folderReceiveComplete - folderName: ${folderName}, completedFiles: ${completedFileIds.length}, allStoreUpdated: ${allStoreUpdated}, success: ${success}`
|
||||
);
|
||||
|
||||
+39
-57
@@ -1,6 +1,6 @@
|
||||
// 🚀 新流程 - 接收端主导的文件传输:
|
||||
// 1. 发送文件元数据 (fileMetadata)
|
||||
// 2. 接收文件请求 (fileRequest)
|
||||
// 2. 接收文件请求 (fileRequest)
|
||||
// 3. 发送所有数据块,完成后等待接收端确认
|
||||
// 4. 收到接收端确认 (fileReceiveComplete/folderReceiveComplete) 后设置进度100%
|
||||
// 发送端不再主动发送完成信号,完全由接收端控制完成时机
|
||||
@@ -113,6 +113,7 @@ class FileSender {
|
||||
|
||||
private handleSignalingMessage(message: WebRTCMessage, peerId: string): void {
|
||||
const peerState = this.getPeerState(peerId);
|
||||
postLogToBackend(`debug Message:${message.type}`);
|
||||
switch (message.type) {
|
||||
case "fileRequest":
|
||||
this.handleFileRequest(message as FileRequest, peerId);
|
||||
@@ -121,7 +122,10 @@ class FileSender {
|
||||
this.handleFileReceiveComplete(message as FileReceiveComplete, peerId);
|
||||
break;
|
||||
case "folderReceiveComplete":
|
||||
this.handleFolderReceiveComplete(message as FolderReceiveComplete, peerId);
|
||||
this.handleFolderReceiveComplete(
|
||||
message as FolderReceiveComplete,
|
||||
peerId
|
||||
);
|
||||
break;
|
||||
default:
|
||||
this.log("warn", `Unknown signaling message type received`, {
|
||||
@@ -146,7 +150,7 @@ class FileSender {
|
||||
peerId: string
|
||||
): void {
|
||||
const peerState = this.getPeerState(peerId);
|
||||
|
||||
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] 📥 Received fileReceiveComplete - fileId: ${message.fileId}, receivedSize: ${message.receivedSize}, receivedChunks: ${message.receivedChunks}, storeUpdated: ${message.storeUpdated}`
|
||||
);
|
||||
@@ -181,7 +185,7 @@ class FileSender {
|
||||
peerId: string
|
||||
): void {
|
||||
const peerState = this.getPeerState(peerId);
|
||||
|
||||
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] 📥 Received folderReceiveComplete - folderName: ${message.folderName}, completedFiles: ${message.completedFileIds.length}, allStoreUpdated: ${message.allStoreUpdated}`
|
||||
);
|
||||
@@ -211,13 +215,15 @@ class FileSender {
|
||||
"log",
|
||||
`Handling file request for ${request.fileId} from ${peerId} with offset ${offset}`
|
||||
);
|
||||
|
||||
|
||||
// 🔧 Firefox兼容性修复:添加稍长延迟确保接收端完全准备好
|
||||
// 根据[[memory:7549586]],这个延迟解决了时序竞态条件
|
||||
await new Promise(resolve => setTimeout(resolve, 10));
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10));
|
||||
|
||||
if (file) {
|
||||
postLogToBackend(`[Firefox Debug] Starting file send - fileName: ${file.name}, fileSize: ${file.size}, offset: ${offset}`);
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] Starting file send - fileName: ${file.name}, fileSize: ${file.size}, offset: ${offset}`
|
||||
);
|
||||
await this.sendSingleFile(file, peerId, offset);
|
||||
} else {
|
||||
this.fireError(`File not found for request`, {
|
||||
@@ -317,7 +323,7 @@ class FileSender {
|
||||
|
||||
try {
|
||||
await this.processSendQueue(file, peerId);
|
||||
|
||||
|
||||
// 🚀 新流程:不再主动发送fileEnd,等待接收端的fileReceiveComplete确认
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] 📤 File sending completed, waiting for receiver confirmation - ${file.name}`
|
||||
@@ -459,7 +465,9 @@ class FileSender {
|
||||
|
||||
// Send fragment
|
||||
await this.sendSingleData(chunk, peerId);
|
||||
|
||||
postLogToBackend(
|
||||
`[sender Debug] chunk idx:${fragmentIndex} ,size:${chunkSize}`
|
||||
);
|
||||
offset += chunkSize;
|
||||
fragmentIndex++;
|
||||
}
|
||||
@@ -474,21 +482,27 @@ class FileSender {
|
||||
if (!dataChannel) {
|
||||
throw new Error("Data channel not found");
|
||||
}
|
||||
|
||||
|
||||
// Firefox兼容性调试:记录发送前的数据信息
|
||||
const dataType = typeof data === "string" ? "string" : data instanceof ArrayBuffer ? "ArrayBuffer" : "unknown";
|
||||
const dataSize = typeof data === "string" ? data.length : data instanceof ArrayBuffer ? data.byteLength : 0;
|
||||
|
||||
postLogToBackend(`[Firefox Debug] Sending data - type: ${dataType}, size: ${dataSize}, channelState: ${dataChannel.readyState}`);
|
||||
|
||||
const dataType =
|
||||
typeof data === "string"
|
||||
? "string"
|
||||
: data instanceof ArrayBuffer
|
||||
? "ArrayBuffer"
|
||||
: "unknown";
|
||||
const dataSize =
|
||||
typeof data === "string"
|
||||
? data.length
|
||||
: data instanceof ArrayBuffer
|
||||
? data.byteLength
|
||||
: 0;
|
||||
|
||||
// Intelligent send control - decide sending strategy based on buffer status
|
||||
await this.smartBufferControl(dataChannel, peerId);
|
||||
|
||||
// Send data
|
||||
const sendResult = this.webrtcConnection.sendData(data, peerId);
|
||||
|
||||
postLogToBackend(`[Firefox Debug] Data send result: ${sendResult ? 'success' : 'failed'} - type: ${dataType}, size: ${dataSize}`);
|
||||
|
||||
|
||||
if (!sendResult) {
|
||||
const errorMessage = `sendData failed for ${dataType} data of size ${dataSize}`;
|
||||
postLogToBackend(`[Firefox Debug] ❌ ${errorMessage}`);
|
||||
@@ -751,10 +765,6 @@ class FileSender {
|
||||
// Initialize network performance monitoring
|
||||
this.initializeNetworkPerformance(peerId);
|
||||
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] 🚀 processSendQueue started - fileName: ${file.name}, fileSize: ${file.size}, startOffset: ${offset}`
|
||||
);
|
||||
|
||||
try {
|
||||
let loopCount = 0;
|
||||
// Use batch reading + loop instead of traditional recursion to greatly improve performance
|
||||
@@ -772,23 +782,22 @@ class FileSender {
|
||||
|
||||
if (chunks.length === 0) break;
|
||||
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] 📦 Loop ${loopCount} - read ${chunks.length} chunks, totalSize: ${chunks.reduce((sum, c) => sum + c.byteLength, 0)}`
|
||||
);
|
||||
|
||||
for (const chunk of chunks) {
|
||||
if (!peerState.isSending || offset >= file.size) break;
|
||||
|
||||
|
||||
// 🔧 修复:检查发送是否成功
|
||||
let sendSuccessful = false;
|
||||
try {
|
||||
await this.sendWithBackpressure(chunk, peerId);
|
||||
sendSuccessful = true;
|
||||
|
||||
totalChunksSent++;
|
||||
totalBytesSentInLoop += chunk.byteLength;
|
||||
} catch (error) {
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] ❌ Failed to send chunk ${totalChunksSent + 1}: ${error}`
|
||||
`[Firefox Debug] ❌ Failed to send chunk ${
|
||||
totalChunksSent + 1
|
||||
}: ${error}`
|
||||
);
|
||||
sendSuccessful = false;
|
||||
// 不更新统计,但继续尝试发送下一个chunk
|
||||
@@ -807,14 +816,6 @@ class FileSender {
|
||||
peerId,
|
||||
true // 明确标记为发送成功
|
||||
);
|
||||
|
||||
// 每50个chunk记录一次进度
|
||||
if (totalChunksSent % 50 === 0) {
|
||||
const progress = ((offset / file.size) * 100).toFixed(2);
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] 📊 Progress: ${totalChunksSent} chunks sent, ${totalBytesSentInLoop} bytes, ${progress}% complete`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// 发送失败但不中止传输,记录失败信息
|
||||
postLogToBackend(
|
||||
@@ -823,25 +824,7 @@ class FileSender {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// File sending completed - final statistics using actual sent bytes
|
||||
const actualBytesSent = peerState.totalBytesSent[fileId] || 0;
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] 🏁 Send completed - totalChunks: ${totalChunksSent}, loopBytes: ${totalBytesSentInLoop}, actualBytes: ${actualBytesSent}, finalOffset: ${offset}, expected: ${file.size}`
|
||||
);
|
||||
|
||||
// 验证统计一致性
|
||||
if (totalBytesSentInLoop !== actualBytesSent) {
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] ⚠️ Statistics mismatch! Loop counted ${totalBytesSentInLoop} bytes but progress tracked ${actualBytesSent} bytes`
|
||||
);
|
||||
}
|
||||
|
||||
// 🚀 新流程:不再在这里设置进度100%,等待接收端确认
|
||||
// if (offset >= file.size && !peerState.currentFolderName) {
|
||||
// peerState.progressCallback?.(fileId, 1, 0);
|
||||
// }
|
||||
|
||||
|
||||
postLogToBackend(
|
||||
`[Firefox Debug] 🏁 All data sent, waiting for receiver to confirm completion...`
|
||||
);
|
||||
@@ -861,7 +844,6 @@ class FileSender {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private abortFileSend(fileId: string, peerId: string): void {
|
||||
this.log("warn", `Aborting file send for ${fileId} to ${peerId}`);
|
||||
const peerState = this.getPeerState(peerId);
|
||||
|
||||
Reference in New Issue
Block a user