Refactor file transfer

This commit is contained in:
schlagmichdoch 2024-02-08 04:03:02 +01:00
parent 19d33e11d8
commit 902b5c6b8f

View file

@ -472,8 +472,9 @@ class Peer {
let totalSize = 0; let totalSize = 0;
let imagesOnly = true let imagesOnly = true
this._state = 'prepare'; this._state = 'prepare';
Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'prepare'});
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
Events.fire('set-progress', {peerId: this._peerId, progress: 0.8*i/files.length, status: 'prepare'})
header.push({ header.push({
name: files[i].name, name: files[i].name,
mime: files[i].type, mime: files[i].type,
@ -483,8 +484,6 @@ class Peer {
if (files[i].type.split('/')[0] !== 'image') imagesOnly = false; if (files[i].type.split('/')[0] !== 'image') imagesOnly = false;
} }
Events.fire('set-progress', {peerId: this._peerId, progress: 0.8, status: 'prepare'})
let dataUrl = ''; let dataUrl = '';
if (files[0].type.split('/')[0] === 'image') { if (files[0].type.split('/')[0] === 'image') {
try { try {
@ -498,7 +497,7 @@ class Peer {
this._filesRequested = files; this._filesRequested = files;
this._sendMessage({type: 'request', this._sendMessage({type: 'transfer-request',
header: header, header: header,
totalSize: totalSize, totalSize: totalSize,
imagesOnly: imagesOnly, imagesOnly: imagesOnly,
@ -525,7 +524,7 @@ class Peer {
_sendHeader(file) { _sendHeader(file) {
this._sendMessage({ this._sendMessage({
type: 'header', type: 'transfer-header',
size: file.size, size: file.size,
name: file.name, name: file.name,
mime: file.type mime: file.type
@ -554,7 +553,7 @@ class Peer {
} }
_sendProgress(progress) { _sendProgress(progress) {
this._sendMessage({ type: 'progress', progress: progress }); this._sendMessage({ type: 'receive-progress', progress: progress });
} }
_onData(data) { _onData(data) {
@ -563,14 +562,20 @@ class Peer {
_onMessage(message) { _onMessage(message) {
switch (message.type) { switch (message.type) {
case 'request': case 'state':
this._onFilesTransferRequest(message); this._onReceiveState(message.state);
break; break;
case 'header': case 'transfer-request':
this._onHeader(message); this._onTransferRequest(message);
break; break;
case 'progress': case 'transfer-response':
this._onProgress(message.progress); this._onTransferResponse(message);
break;
case 'transfer-header':
this._onTransferHeader(message);
break;
case 'receive-progress':
this._onReceiveProgress(message.progress);
break; break;
case 'receive-confirmation': case 'receive-confirmation':
this._onReceiveConfirmation(message.bytesReceived); this._onReceiveConfirmation(message.bytesReceived);
@ -578,33 +583,27 @@ class Peer {
case 'resend-request': case 'resend-request':
this._onResendRequest(message.offset); this._onResendRequest(message.offset);
break; break;
case 'files-transfer-response':
this._onFileTransferRequestResponded(message);
break;
case 'file-transfer-complete': case 'file-transfer-complete':
this._onFileTransferComplete(message); this._onFileTransferComplete(message);
break; break;
case 'message-transfer-complete':
this._onMessageTransferCompleted();
break;
case 'text': case 'text':
this._onTextReceived(message); this._onTextReceived(message);
break; break;
case 'text-sent':
this._onTextSent();
break;
case 'display-name-changed': case 'display-name-changed':
this._onDisplayNameChanged(message); this._onDisplayNameChanged(message);
break; break;
case 'state':
this._onReceiveState(message.state);
break;
default: default:
Logger.warn('RTC: Unknown message type:', message.type); Logger.warn('RTC: Unknown message type:', message.type);
} }
} }
_onFilesTransferRequest(request) { _onTransferRequest(request) {
if (this._pendingRequest) { if (this._pendingRequest) {
// Only accept one request at a time per peer // Only accept one request at a time per peer
this._sendMessage({type: 'files-transfer-response', accepted: false}); this._sendMessage({type: 'transfer-response', accepted: false});
return; return;
} }
@ -624,29 +623,35 @@ class Peer {
} }
_respondToFileTransferRequest(accepted) { _respondToFileTransferRequest(accepted) {
this._sendMessage({type: 'files-transfer-response', accepted: accepted}); this._sendMessage({type: 'transfer-response', accepted: accepted});
if (accepted) { if (accepted) {
this._acceptedRequest = this._pendingRequest; this._state = 'receive';
this._totalBytesReceived = 0;
this._busy = true; this._busy = true;
this._acceptedRequest = this._pendingRequest;
this._lastProgress = 0;
this._totalBytesReceived = 0;
this._filesReceived = []; this._filesReceived = [];
} }
this._pendingRequest = null; this._pendingRequest = null;
} }
_onHeader(header) { _onTransferHeader(header) {
if (!this._acceptedRequest || !this._acceptedRequest.header.length) { if (this._state !== "receive") {
this._sendTransferAbortion(); this._sendCurrentState();
return; return;
} }
this._state = 'receive';
this._lastProgress = 0;
this._timeStart = Date.now(); this._timeStart = Date.now();
this._addFileDigester(header); this._addFileDigester(header);
} }
_addFileDigester(header) {} _addFileDigester(header) {
this._digester = new FileDigester({size: header.size, name: header.name, mime: header.mime},
this._acceptedRequest.totalSize,
fileBlob => this._fileReceived(fileBlob),
bytesReceived => this._sendReceiveConfirmation(bytesReceived)
);
}
_sendReceiveConfirmation(bytesReceived) { _sendReceiveConfirmation(bytesReceived) {
this._sendMessage({type: 'receive-confirmation', bytesReceived: bytesReceived}); this._sendMessage({type: 'receive-confirmation', bytesReceived: bytesReceived});
@ -661,6 +666,7 @@ class Peer {
this._acceptedRequest = null; this._acceptedRequest = null;
this._digester = null; this._digester = null;
this._filesReceived = []; this._filesReceived = [];
this._totalBytesReceived = 0;
} }
_onChunkReceived(chunk) { _onChunkReceived(chunk) {
@ -671,7 +677,9 @@ class Peer {
this._digester.unchunk(chunk); this._digester.unchunk(chunk);
const progress = this._digester.progress; let progress = (this._totalBytesReceived + this._digester._bytesReceived) / this._acceptedRequest.totalSize;
if (isNaN(progress)) progress = 1
if (progress > 1) { if (progress > 1) {
this._abortTransfer(); this._abortTransfer();
@ -679,10 +687,6 @@ class Peer {
return; return;
} }
if (progress === 1) {
this._digester = null;
}
Events.fire('set-progress', {peerId: this._peerId, progress: progress, status: 'receive'}); Events.fire('set-progress', {peerId: this._peerId, progress: progress, status: 'receive'});
// occasionally notify sender about our progress // occasionally notify sender about our progress
@ -692,7 +696,7 @@ class Peer {
} }
} }
_onProgress(progress) { _onReceiveProgress(progress) {
if (this._state !== 'transfer') { if (this._state !== 'transfer') {
this._sendCurrentState(); this._sendCurrentState();
return; return;
@ -722,12 +726,17 @@ class Peer {
return sameSize && sameName; return sameSize && sameName;
} }
_logTransferSpeed(size, duration, speed) { _singleFileTransferComplete(file) {
Logger.log(`File received.\n\nSize: ${size} MB\tDuration: ${duration} s\tSpeed: ${speed} MB/s`); this._digester = null;
}
_singleFileTransferComplete(file, duration, size, speed) {
this._totalBytesReceived += file.size; this._totalBytesReceived += file.size;
const duration = (Date.now() - this._timeStart) / 1000; // s
const size = Math.round(10 * file.size / 1e6) / 10; // MB
const speed = Math.round(100 * size / duration) / 100; // MB/s
// Log speed from request to receive
Logger.log(`File received.\n\nSize: ${size} MB\tDuration: ${duration} s\tSpeed: ${speed} MB/s`);
this._sendMessage({type: 'file-transfer-complete', success: true, duration: duration, size: size, speed: speed}); this._sendMessage({type: 'file-transfer-complete', success: true, duration: duration, size: size, speed: speed});
// include for compatibility with 'Snapdrop & PairDrop for Android' app // include for compatibility with 'Snapdrop & PairDrop for Android' app
@ -750,11 +759,6 @@ class Peer {
} }
async _fileReceived(file) { async _fileReceived(file) {
if (this._state !== "receive") {
this._sendCurrentState();
return;
}
if (!this._fitsHeader(file)) { if (!this._fitsHeader(file)) {
this._abortTransfer(); this._abortTransfer();
Events.fire('notify-user', Localization.getTranslation("notifications.files-incorrect")); Events.fire('notify-user', Localization.getTranslation("notifications.files-incorrect"));
@ -762,15 +766,8 @@ class Peer {
return; return;
} }
const duration = (Date.now() - this._timeStart) / 1000;
const size = Math.round(10 * file.size / 1000000) / 10;
const speed = Math.round(100 * file.size / 1000000 / duration) / 100;
// Log speed
this._logTransferSpeed(duration, size, speed);
// File transfer complete // File transfer complete
this._singleFileTransferComplete(file, duration, size, speed); this._singleFileTransferComplete(file);
if (this._acceptedRequest.header.length) return; if (this._acceptedRequest.header.length) return;
@ -810,7 +807,7 @@ class Peer {
Events.fire('files-sent'); // used by 'Snapdrop & PairDrop for Android' app Events.fire('files-sent'); // used by 'Snapdrop & PairDrop for Android' app
} }
_onFileTransferRequestResponded(message) { _onTransferResponse(message) {
if (this._state !== 'wait') { if (this._state !== 'wait') {
this._sendCurrentState(); this._sendCurrentState();
return; return;
@ -829,7 +826,7 @@ class Peer {
this.sendFiles(); this.sendFiles();
} }
_onMessageTransferCompleted() { _onTextSent() {
if (this._state !== 'text-sent') { if (this._state !== 'text-sent') {
this._sendCurrentState(); this._sendCurrentState();
return; return;
@ -849,7 +846,7 @@ class Peer {
try { try {
const escaped = decodeURIComponent(escape(atob(message.text))); const escaped = decodeURIComponent(escape(atob(message.text)));
Events.fire('text-received', { text: escaped, peerId: this._peerId }); Events.fire('text-received', { text: escaped, peerId: this._peerId });
this._sendMessage({ type: 'message-transfer-complete' }); this._sendMessage({ type: 'text-sent' });
} }
catch (e) { catch (e) {
Logger.error(e); Logger.error(e);
@ -1251,14 +1248,6 @@ class RTCPeer extends Peer {
super._onMessage(message); super._onMessage(message);
} }
_addFileDigester(header) {
this._digester = new FileDigester({size: header.size, name: header.name, mime: header.mime},
this._acceptedRequest.totalSize,
this._totalBytesReceived,
fileBlob => this._fileReceived(fileBlob)
);
}
getConnectionHash() { getConnectionHash() {
const localDescriptionLines = this._conn.localDescription.sdp.split("\r\n"); const localDescriptionLines = this._conn.localDescription.sdp.split("\r\n");
const remoteDescriptionLines = this._conn.remoteDescription.sdp.split("\r\n"); const remoteDescriptionLines = this._conn.remoteDescription.sdp.split("\r\n");
@ -1352,15 +1341,6 @@ class WSPeer extends Peer {
super._onMessage(message); super._onMessage(message);
} }
_addFileDigester(header) {
this._digester = new FileDigester({size: header.size, name: header.name, mime: header.mime},
this._acceptedRequest.totalSize,
this._totalBytesReceived,
fileBlob => this._fileReceived(fileBlob),
bytesReceived => this._sendReceiveConfirmation(bytesReceived)
);
}
_onWsRelay(message) { _onWsRelay(message) {
try { try {
message = JSON.parse(message).message; message = JSON.parse(message).message;
@ -1759,7 +1739,7 @@ class FileChunkerWS extends FileChunker {
class FileDigester { class FileDigester {
constructor(meta, totalSize, totalBytesReceived, fileCompleteCallback, receiveConfirmationCallback = null) { constructor(meta, totalSize, fileCompleteCallback, receiveConfirmationCallback = null) {
this._buffer = []; this._buffer = [];
this._bytesReceived = 0; this._bytesReceived = 0;
this._bytesReceivedSinceLastTime = 0; this._bytesReceivedSinceLastTime = 0;
@ -1768,7 +1748,6 @@ class FileDigester {
this._name = meta.name; this._name = meta.name;
this._mime = meta.mime; this._mime = meta.mime;
this._totalSize = totalSize; this._totalSize = totalSize;
this._totalBytesReceived = totalBytesReceived;
this._fileCompleteCallback = fileCompleteCallback; this._fileCompleteCallback = fileCompleteCallback;
this._receiveConfimationCallback = receiveConfirmationCallback; this._receiveConfimationCallback = receiveConfirmationCallback;
} }
@ -1784,9 +1763,6 @@ class FileDigester {
this._bytesReceivedSinceLastTime = 0; this._bytesReceivedSinceLastTime = 0;
} }
this.progress = (this._totalBytesReceived + this._bytesReceived) / this._totalSize;
if (isNaN(this.progress)) this.progress = 1
if (this._bytesReceived < this._size) return; if (this._bytesReceived < this._size) return;
// we are done // we are done