1
Fork 0
mirror of https://github.com/jech/galene.git synced 2024-11-26 02:25:58 +01:00

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.
This commit is contained in:
Juliusz Chroboczek 2022-02-01 13:33:02 +01:00
parent 6d250bfa98
commit 60ba4aa727

View file

@ -2163,7 +2163,7 @@ async function gotJoined(kind, group, perms, status, data, message) {
* @property {number} size * @property {number} size
* @property {string} type * @property {string} type
* @property {Array<RTCIceCandidateInit>} [candidates] * @property {Array<RTCIceCandidateInit>} [candidates]
* @property {Array<Uint8Array>} [data] * @property {Array<Blob|ArrayBuffer>} [data]
* @property {number} [datalen] * @property {number} [datalen]
* @property {boolean} [done] * @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} username
* @param {string} id * @param {string} id
@ -2374,11 +2386,24 @@ async function getFile(id, fileid) {
f.data = []; f.data = [];
f.datalen = 0; f.datalen = 0;
dc.onclose = function(e) { dc.onclose = function(e) {
closeReceiveFileData(id, fileid, f); try {
} closeReceiveFileData(id, fileid, f);
} catch(e) {
failFile(false, id, fileid, e);
}
};
dc.onmessage = function(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(); let offer = await pc.createOffer();
if(!offer) if(!offer)
throw new Error("Couldn't create offer"); throw new Error("Couldn't create offer");
@ -2433,16 +2458,27 @@ async function sendFile(id, fileid, sdp) {
}; };
let file = f.file; let file = f.file;
pc.ondatachannel = function(e) { pc.ondatachannel = function(e) {
e.channel.onopen = function(e) { let dc = /** @type{RTCDataChannel} */(e.channel);
let dc = /** @type{RTCDataChannel} */(e.target); dc.onclose = function(e) {
dc.onmessage = function(e) { try {
ackSendFileData(id, fileid, f, e.data);
}
dc.onclose = function(e) {
closeSendFileData(id, fileid, f); 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({ await pc.setRemoteDescription({
@ -2552,11 +2588,19 @@ function closeSendFileData(id, fileid, f) {
* @param {string} fileid * @param {string} fileid
* @param {transferredFile} f * @param {transferredFile} f
* @param {RTCDataChannel} dc * @param {RTCDataChannel} dc
* @param {Uint8Array} data * @param {Blob|ArrayBuffer} data
*/ */
function receiveFileData(id, fileid, f, dc, data) { function receiveFileData(id, fileid, f, dc, data) {
f.data.push(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( setFileStatus(
false, id, fileid, `Downloading... ${f.datalen}/${f.size}`, true, false, id, fileid, `Downloading... ${f.datalen}/${f.size}`, true,
); );
@ -2570,6 +2614,9 @@ function receiveFileData(id, fileid, f, dc, data) {
return; return;
} }
dc.onmessage = null;
dc.onerror = null;
dc.send('done'); dc.send('done');
setFileStatus(false, id, fileid, 'Done.', true, true); setFileStatus(false, id, fileid, 'Done.', true, true);