From d4dcfbc1b7acee3f0c1054c9ff0e9b186c4e8f28 Mon Sep 17 00:00:00 2001 From: schlagmichdoch Date: Mon, 23 Jan 2023 04:51:22 +0100 Subject: [PATCH] After successfully creating peer to peer connection, transferring files/messages now work completely independent of the PairDrop server. Transfers are not aborted and dialogs are not closed when the client has only lost connection to the PairDrop server or when 'peer-left' but only when the corresponding peer is disconnected. --- public/index.html | 2 +- public/scripts/network.js | 51 ++++++++++++++----------------- public/scripts/ui.js | 63 ++++++++++++++------------------------- public/service-worker.js | 34 ++++++++++++--------- public/styles.css | 6 ++++ 5 files changed, 72 insertions(+), 84 deletions(-) diff --git a/public/index.html b/public/index.html index cf286cc..290fd01 100644 --- a/public/index.html +++ b/public/index.html @@ -216,7 +216,7 @@
- File Transfer Completed +
diff --git a/public/scripts/network.js b/public/scripts/network.js index 55bce53..6ccbf17 100644 --- a/public/scripts/network.js +++ b/public/scripts/network.js @@ -12,7 +12,7 @@ class ServerConnection { Events.on('beforeunload', _ => this._disconnect()); Events.on('pagehide', _ => this._disconnect()); document.addEventListener('visibilitychange', _ => this._onVisibilityChange()); - if (navigator.connection) navigator.connection.addEventListener('change', _ => this._disconnect()); + if (navigator.connection) navigator.connection.addEventListener('change', _ => this._reconnect()); Events.on('reconnect', _ => this._reconnect()); Events.on('room-secrets', e => this._sendRoomSecrets(e.detail)); Events.on('room-secret-deleted', e => this.send({ type: 'room-secret-deleted', roomSecret: e.detail})); @@ -152,9 +152,10 @@ class ServerConnection { _onDisconnect() { console.log('WS: server disconnected'); - Events.fire('notify-user', 'Connection lost. Retrying...'); + Events.fire('notify-user', 'Server connection lost. Retrying...'); clearTimeout(this._reconnectTimer); - this._reconnectTimer = setTimeout(_ => this._connect(), 1000); + this._reconnectTimer = setTimeout(_ => this._connect(), 5000); + this._connect(); Events.fire('ws-disconnected'); } @@ -298,8 +299,6 @@ class Peer { } async sendFiles() { - console.debug("sendFiles") - console.debug(this.zipFileRequested); this._filesQueue.push({zipFile: this.zipFileRequested, fileHeader: this._fileHeaderRequested}); this._fileHeaderRequested = null if (this._busy) return; @@ -429,7 +428,7 @@ class Peer { } async _onFileReceived(zipBlob, fileHeader) { - Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'wait'}); + Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'process'}); this._busy = false; this.sendJSON({type: 'file-transfer-complete'}); @@ -563,9 +562,17 @@ class RTCPeer extends Peer { channel.binaryType = 'arraybuffer'; channel.onmessage = e => this._onMessage(e.data); channel.onclose = _ => this._onChannelClosed(); + Events.on('beforeunload', _ => this._closeChannel()); + Events.on('pagehide', _ => this._closeChannel()); this._channel = channel; } + _closeChannel() { + this._channel.onclose = null; + this._conn.close(); + this._conn = null; + } + _onChannelClosed() { console.log('RTC: channel closed', this._peerId); Events.fire('peer-disconnected', this._peerId); @@ -603,7 +610,7 @@ class RTCPeer extends Peer { } _send(message) { - if (!this._channel) return this.refresh(); + if (!this._channel) this.refresh(); this._channel.send(message); } @@ -617,8 +624,6 @@ class RTCPeer extends Peer { refresh() { // check if channel is open. otherwise create one - console.debug("refresh:"); - console.debug(this._conn); if (this._isConnected() || this._isConnecting()) return; this._connect(this._peerId, this._isCaller); } @@ -652,8 +657,7 @@ class PeersManager { Events.on('respond-to-files-transfer-request', e => this._onRespondToFileTransferRequest(e.detail)) Events.on('send-text', e => this._onSendText(e.detail)); Events.on('peer-joined', e => this._onPeerJoined(e.detail)); - Events.on('peer-left', e => this._onPeerLeft(e.detail)); - Events.on('ws-disconnected', _ => this._clearPeers()); + Events.on('peer-disconnected', e => this._onPeerLeft(e.detail)); Events.on('secret-room-deleted', e => this._onSecretRoomDeleted(e.detail)); } @@ -699,20 +703,15 @@ class PeersManager { } _onFilesSelected(message) { - const files = this._addTypeIfMissing(message.files); - this.peers[message.to].requestFileTransfer(files); - } - - _addTypeIfMissing(files) { - let filesWithType = [], file; - for (let i=0; i this._onPeerLeft(peerId)); - } - } - _onSecretRoomDeleted(roomSecret) { for (const peerId in this.peers) { const peer = this.peers[peerId]; diff --git a/public/scripts/ui.js b/public/scripts/ui.js index 558affa..d18794e 100644 --- a/public/scripts/ui.js +++ b/public/scripts/ui.js @@ -19,14 +19,12 @@ class PeersUI { constructor() { Events.on('peer-joined', e => this._onPeerJoined(e.detail)); - Events.on('peer-left', e => this._onPeerLeft(e.detail)); Events.on('peer-connected', e => this._onPeerConnected(e.detail)); Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail)); Events.on('peers', e => this._onPeers(e.detail)); Events.on('set-progress', e => this._onSetProgress(e.detail)); Events.on('paste', e => this._onPaste(e)); - Events.on('ws-disconnected', _ => this._clearPeers()); - Events.on('secret-room-deleted', _ => this._clearPeers('secret')); + Events.on('secret-room-deleted', e => this._onSecretRoomDeleted(e.detail)); Events.on('activate-paste-mode', e => this._activatePasteMode(e.detail.files, e.detail.text)); this.peers = {}; @@ -88,16 +86,11 @@ class PeersUI { if ($$('x-peers:empty')) setTimeout(_ => window.animateBackground(true), 1750); // Start animation again } - _onPeerLeft(peerId) { - this._onPeerDisconnected(peerId); - delete this.peers[peerId]; - } - _onSecretRoomDeleted(roomSecret) { for (const peerId in this.peers) { const peer = this.peers[peerId]; if (peer.roomSecret === roomSecret) { - this._onPeerLeft(peerId); + this._onPeerDisconnected(peerId); } } } @@ -108,16 +101,6 @@ class PeersUI { $peer.ui.setProgress(progress.progress, progress.status) } - _clearPeers(roomType = 'all') { - for (const peerId in this.peers) { - if (roomType === 'all' || this.peers[peerId].roomType === roomType) { - const peerNode = $(peerId); - if(peerNode) peerNode.remove(); - delete this.peers[peerId]; - } - } - } - _onDrop(e) { e.preventDefault(); if (!$$('x-peer') || !$$('x-peer').contains(e.target)) { @@ -429,7 +412,7 @@ class Dialog { this.$el = $(id); this.$el.querySelectorAll('[close]').forEach(el => el.addEventListener('click', _ => this.hide())) this.$autoFocus = this.$el.querySelector('[autofocus]'); - if (hideOnDisconnect) Events.on('ws-disconnected', _ => this.hide()); + if (hideOnDisconnect) Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail)); } show() { @@ -445,6 +428,14 @@ class Dialog { } document.title = 'PairDrop'; document.changeFavicon("images/favicon-96x96.png"); + if (this.correspondingPeerId) setTimeout(_ => this.correspondingPeerId = undefined, 300); + } + + _onPeerDisconnected(peerId) { + if (this.correspondingPeerId && this.correspondingPeerId === peerId) { + this.hide(); + Events.fire('notify-user', 'Selected peer left.') + } } } @@ -600,7 +591,7 @@ class ReceiveFileDialog extends ReceiveDialog { Events.fire('set-progress', { peerId: peerId, progress: 1, - status: 'wait' + status: 'process' }) this.$shareOrDownloadBtn.click(); }).catch(r => console.error(r)); @@ -631,8 +622,6 @@ class ReceiveRequestDialog extends ReceiveDialog { this.$declineRequestBtn.addEventListener('click', _ => this._respondToFileTransferRequest(false)); Events.on('files-transfer-request', e => this._onRequestFileTransfer(e.detail.request, e.detail.peerId)) - Events.on('peer-left', e => this._onPeerDisconnectedOrLeft(e.detail)) - Events.on('peer-disconnected', e => this._onPeerDisconnectedOrLeft(e.detail)) Events.on('keydown', e => this._onKeyDown(e)); } @@ -643,15 +632,8 @@ class ReceiveRequestDialog extends ReceiveDialog { } } - _onPeerDisconnectedOrLeft(peerId) { - if (peerId === this.requestingPeerId) { - this._respondToFileTransferRequest(false) - this.hide(); - } - } - _onRequestFileTransfer(request, peerId) { - this.requestingPeerId = peerId; + this.correspondingPeerId = peerId; this.requestedHeader = request.header; const peer = $(peerId); @@ -693,13 +675,12 @@ class ReceiveRequestDialog extends ReceiveDialog { _respondToFileTransferRequest(accepted) { Events.fire('respond-to-files-transfer-request', { - to: this.requestingPeerId, + to: this.correspondingPeerId, header: this.requestedHeader, accepted: accepted }) - this.requestingPeerId = null; if (accepted) { - Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'wait'}); + Events.fire('set-progress', {peerId: this.correspondingPeerId, progress: 0, status: 'wait'}); NoSleepUI.enable(); } } @@ -732,6 +713,7 @@ class PairDeviceDialog extends Dialog { Events.on('keydown', e => this._onKeyDown(e)); Events.on('ws-connected', _ => this._onWsConnected()); + Events.on('ws-disconnected', _ => this.hide()); Events.on('pair-device-initiated', e => this._pairDeviceInitiated(e.detail)); Events.on('pair-device-joined', e => this._pairDeviceJoined(e.detail)); Events.on('pair-device-join-key-invalid', _ => this._pairDeviceJoinKeyInvalid()); @@ -976,8 +958,8 @@ class SendTextDialog extends Dialog { } } - _onRecipient(recipient) { - this._recipient = recipient; + _onRecipient(peerId) { + this.correspondingPeerId = peerId; this.show(); const range = document.createRange(); @@ -991,7 +973,7 @@ class SendTextDialog extends Dialog { _send() { Events.fire('send-text', { - to: this._recipient, + to: this.correspondingPeerId, text: this.$text.innerText }); this.$text.value = ""; @@ -1096,13 +1078,14 @@ class Base64ZipDialog extends Dialog { class Toast extends Dialog { constructor() { super('toast'); - Events.on('notify-user', e => this._onNotifiy(e.detail)); + Events.on('notify-user', e => this._onNotify(e.detail)); } - _onNotifiy(message) { + _onNotify(message) { + if (this.hideTimeout) clearTimeout(this.hideTimeout); this.$el.textContent = message; this.show(); - setTimeout(_ => this.hide(), 3000); + this.hideTimeout = setTimeout(_ => this.hide(), 3000); } } diff --git a/public/service-worker.js b/public/service-worker.js index 3870f54..2f22f8e 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -1,17 +1,23 @@ -var CACHE_NAME = 'pairdrop-cache-v4'; -var urlsToCache = [ - 'index.html', - './', - 'styles.css', - 'scripts/network.js', - 'scripts/ui.js', - 'scripts/util.js', - 'scripts/qrcode.js', - 'scripts/zip.min.js', - 'scripts/NoSleep.min.js', - 'scripts/theme.js', - 'sounds/blop.mp3', - 'images/favicon-96x96.png' +const CACHE_NAME = 'pairdrop-cache-v4'; +const urlsToCache = [ + 'index.html', + './', + 'styles.css', + 'scripts/network.js', + 'scripts/ui.js', + 'scripts/util.js', + 'scripts/qrcode.js', + 'scripts/zip.min.js', + 'scripts/NoSleep.min.js', + 'scripts/theme.js', + 'sounds/blop.mp3', + 'images/favicon-96x96.png', + 'images/favicon-96x96-notification.png', + 'images/android-chrome-192x192.png', + 'images/android-chrome-192x192-maskable.png', + 'images/android-chrome-512x512.png', + 'images/android-chrome-512x512-maskable.png', + 'images/apple-touch-icon.png', ]; self.addEventListener('install', function(event) { diff --git a/public/styles.css b/public/styles.css index 78e44f4..a2289a4 100644 --- a/public/styles.css +++ b/public/styles.css @@ -320,6 +320,10 @@ x-peer[status=wait] .status:before { content: 'Waiting...'; } +x-peer[status=process] .status:before { + content: 'Processing...'; +} + x-peer:not([status]) .status, x-peer[status] .device-name { display: none; @@ -527,6 +531,8 @@ x-dialog .row-reverse { max-width: 80%; overflow: hidden; text-overflow: ellipsis; + word-break: break-all; + max-height: 1rem; } .file-size{