mirror of
https://github.com/schlagmichdoch/PairDrop.git
synced 2025-04-20 15:06:15 -04:00
Refactor file transfer
This commit is contained in:
parent
19d33e11d8
commit
902b5c6b8f
1 changed files with 58 additions and 82 deletions
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue