From 60ba4aa7279627945037ea58dd425e7d2784c109 Mon Sep 17 00:00:00 2001 From: Juliusz Chroboczek Date: Tue, 1 Feb 2022 13:33:02 +0100 Subject: [PATCH] Fix file transfer for Firefox. Firefox implements the spec correctly by encapsulatings received data in a blob by default. Handle both blobs and ArrayBuffers. Also improve error handling. --- static/galene.js | 75 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 14 deletions(-) diff --git a/static/galene.js b/static/galene.js index 28945a4..3ed2343 100644 --- a/static/galene.js +++ b/static/galene.js @@ -2163,7 +2163,7 @@ async function gotJoined(kind, group, perms, status, data, message) { * @property {number} size * @property {string} type * @property {Array} [candidates] - * @property {Array} [data] + * @property {Array} [data] * @property {number} [datalen] * @property {boolean} [done] */ @@ -2302,6 +2302,18 @@ function setFileStatus(up, id, fileid, status, delyes, delno) { } } +/** + * @param {boolean} up + * @param {string} id + * @param {string} fileid + * @param {any} message + */ +function failFile(up, id, fileid, message) { + console.error('File transfer failed:', message); + setFileStatus(up, id, fileid, message ? `Failed: ${message}` : 'Failed.'); + deleteTransferredFile(true, id, fileid); +} + /** * @param {string} username * @param {string} id @@ -2374,11 +2386,24 @@ async function getFile(id, fileid) { f.data = []; f.datalen = 0; dc.onclose = function(e) { - closeReceiveFileData(id, fileid, f); - } + try { + closeReceiveFileData(id, fileid, f); + } catch(e) { + failFile(false, id, fileid, e); + } + }; dc.onmessage = function(e) { - receiveFileData(id, fileid, f, dc, e.data); - } + try { + receiveFileData(id, fileid, f, dc, e.data); + } catch(e) { + failFile(false, id, fileid, e); + } + }; + dc.onerror = function(e) { + /** @ts-ignore */ + let err = e.error; + failFile(false, id, fileid, err); + }; let offer = await pc.createOffer(); if(!offer) throw new Error("Couldn't create offer"); @@ -2433,16 +2458,27 @@ async function sendFile(id, fileid, sdp) { }; let file = f.file; pc.ondatachannel = function(e) { - e.channel.onopen = function(e) { - let dc = /** @type{RTCDataChannel} */(e.target); - dc.onmessage = function(e) { - ackSendFileData(id, fileid, f, e.data); - } - dc.onclose = function(e) { + let dc = /** @type{RTCDataChannel} */(e.channel); + dc.onclose = function(e) { + try { closeSendFileData(id, fileid, f); + } catch(e) { + failFile(true, id, fileid, e); } - sendFileData(id, fileid, f, dc, file); + }; + dc.onerror = function(e) { + /** @ts-ignore */ + let err = e.error; + failFile(true, id, fileid, err); } + dc.onmessage = function(e) { + try { + ackSendFileData(id, fileid, f, e.data); + } catch(e) { + failFile(true, id, fileid, e); + } + }; + sendFileData(id, fileid, f, dc, file); }; await pc.setRemoteDescription({ @@ -2552,11 +2588,19 @@ function closeSendFileData(id, fileid, f) { * @param {string} fileid * @param {transferredFile} f * @param {RTCDataChannel} dc - * @param {Uint8Array} data + * @param {Blob|ArrayBuffer} data */ function receiveFileData(id, fileid, f, dc, data) { f.data.push(data); - f.datalen += data.byteLength; + if(data instanceof Blob) { + f.datalen += data.size; + } else if(data instanceof ArrayBuffer) { + f.datalen += data.byteLength; + } else { + console.error('Unexpeced type for received data', data); + throw new Error('unexpected type for received data'); + } + setFileStatus( false, id, fileid, `Downloading... ${f.datalen}/${f.size}`, true, ); @@ -2570,6 +2614,9 @@ function receiveFileData(id, fileid, f, dc, data) { return; } + dc.onmessage = null; + dc.onerror = null; + dc.send('done'); setFileStatus(false, id, fileid, 'Done.', true, true);