mirror of
https://github.com/schlagmichdoch/PairDrop.git
synced 2025-04-21 15:26:17 -04:00
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.
This commit is contained in:
parent
d424a0294a
commit
d4dcfbc1b7
5 changed files with 72 additions and 84 deletions
|
@ -216,7 +216,7 @@
|
||||||
</x-dialog>
|
</x-dialog>
|
||||||
<!-- Toast -->
|
<!-- Toast -->
|
||||||
<div class="toast-container full center">
|
<div class="toast-container full center">
|
||||||
<x-toast class="row" shadow="1" id="toast">File Transfer Completed</x-toast>
|
<x-toast class="row" shadow="1" id="toast"></x-toast>
|
||||||
</div>
|
</div>
|
||||||
<!-- About Page -->
|
<!-- About Page -->
|
||||||
<x-about id="about" class="full center column">
|
<x-about id="about" class="full center column">
|
||||||
|
|
|
@ -12,7 +12,7 @@ class ServerConnection {
|
||||||
Events.on('beforeunload', _ => this._disconnect());
|
Events.on('beforeunload', _ => this._disconnect());
|
||||||
Events.on('pagehide', _ => this._disconnect());
|
Events.on('pagehide', _ => this._disconnect());
|
||||||
document.addEventListener('visibilitychange', _ => this._onVisibilityChange());
|
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('reconnect', _ => this._reconnect());
|
||||||
Events.on('room-secrets', e => this._sendRoomSecrets(e.detail));
|
Events.on('room-secrets', e => this._sendRoomSecrets(e.detail));
|
||||||
Events.on('room-secret-deleted', e => this.send({ type: 'room-secret-deleted', roomSecret: e.detail}));
|
Events.on('room-secret-deleted', e => this.send({ type: 'room-secret-deleted', roomSecret: e.detail}));
|
||||||
|
@ -152,9 +152,10 @@ class ServerConnection {
|
||||||
|
|
||||||
_onDisconnect() {
|
_onDisconnect() {
|
||||||
console.log('WS: server disconnected');
|
console.log('WS: server disconnected');
|
||||||
Events.fire('notify-user', 'Connection lost. Retrying...');
|
Events.fire('notify-user', 'Server connection lost. Retrying...');
|
||||||
clearTimeout(this._reconnectTimer);
|
clearTimeout(this._reconnectTimer);
|
||||||
this._reconnectTimer = setTimeout(_ => this._connect(), 1000);
|
this._reconnectTimer = setTimeout(_ => this._connect(), 5000);
|
||||||
|
this._connect();
|
||||||
Events.fire('ws-disconnected');
|
Events.fire('ws-disconnected');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,8 +299,6 @@ class Peer {
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendFiles() {
|
async sendFiles() {
|
||||||
console.debug("sendFiles")
|
|
||||||
console.debug(this.zipFileRequested);
|
|
||||||
this._filesQueue.push({zipFile: this.zipFileRequested, fileHeader: this._fileHeaderRequested});
|
this._filesQueue.push({zipFile: this.zipFileRequested, fileHeader: this._fileHeaderRequested});
|
||||||
this._fileHeaderRequested = null
|
this._fileHeaderRequested = null
|
||||||
if (this._busy) return;
|
if (this._busy) return;
|
||||||
|
@ -429,7 +428,7 @@ class Peer {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _onFileReceived(zipBlob, fileHeader) {
|
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._busy = false;
|
||||||
this.sendJSON({type: 'file-transfer-complete'});
|
this.sendJSON({type: 'file-transfer-complete'});
|
||||||
|
|
||||||
|
@ -563,9 +562,17 @@ class RTCPeer extends Peer {
|
||||||
channel.binaryType = 'arraybuffer';
|
channel.binaryType = 'arraybuffer';
|
||||||
channel.onmessage = e => this._onMessage(e.data);
|
channel.onmessage = e => this._onMessage(e.data);
|
||||||
channel.onclose = _ => this._onChannelClosed();
|
channel.onclose = _ => this._onChannelClosed();
|
||||||
|
Events.on('beforeunload', _ => this._closeChannel());
|
||||||
|
Events.on('pagehide', _ => this._closeChannel());
|
||||||
this._channel = channel;
|
this._channel = channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_closeChannel() {
|
||||||
|
this._channel.onclose = null;
|
||||||
|
this._conn.close();
|
||||||
|
this._conn = null;
|
||||||
|
}
|
||||||
|
|
||||||
_onChannelClosed() {
|
_onChannelClosed() {
|
||||||
console.log('RTC: channel closed', this._peerId);
|
console.log('RTC: channel closed', this._peerId);
|
||||||
Events.fire('peer-disconnected', this._peerId);
|
Events.fire('peer-disconnected', this._peerId);
|
||||||
|
@ -603,7 +610,7 @@ class RTCPeer extends Peer {
|
||||||
}
|
}
|
||||||
|
|
||||||
_send(message) {
|
_send(message) {
|
||||||
if (!this._channel) return this.refresh();
|
if (!this._channel) this.refresh();
|
||||||
this._channel.send(message);
|
this._channel.send(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -617,8 +624,6 @@ class RTCPeer extends Peer {
|
||||||
|
|
||||||
refresh() {
|
refresh() {
|
||||||
// check if channel is open. otherwise create one
|
// check if channel is open. otherwise create one
|
||||||
console.debug("refresh:");
|
|
||||||
console.debug(this._conn);
|
|
||||||
if (this._isConnected() || this._isConnecting()) return;
|
if (this._isConnected() || this._isConnecting()) return;
|
||||||
this._connect(this._peerId, this._isCaller);
|
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('respond-to-files-transfer-request', e => this._onRespondToFileTransferRequest(e.detail))
|
||||||
Events.on('send-text', e => this._onSendText(e.detail));
|
Events.on('send-text', e => this._onSendText(e.detail));
|
||||||
Events.on('peer-joined', e => this._onPeerJoined(e.detail));
|
Events.on('peer-joined', e => this._onPeerJoined(e.detail));
|
||||||
Events.on('peer-left', e => this._onPeerLeft(e.detail));
|
Events.on('peer-disconnected', e => this._onPeerLeft(e.detail));
|
||||||
Events.on('ws-disconnected', _ => this._clearPeers());
|
|
||||||
Events.on('secret-room-deleted', e => this._onSecretRoomDeleted(e.detail));
|
Events.on('secret-room-deleted', e => this._onSecretRoomDeleted(e.detail));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -699,20 +703,15 @@ class PeersManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
_onFilesSelected(message) {
|
_onFilesSelected(message) {
|
||||||
const files = this._addTypeIfMissing(message.files);
|
let files = [];
|
||||||
this.peers[message.to].requestFileTransfer(files);
|
for (let i=0; i<message.files.length; i++) {
|
||||||
}
|
|
||||||
|
|
||||||
_addTypeIfMissing(files) {
|
|
||||||
let filesWithType = [], file;
|
|
||||||
for (let i=0; i<files.length; i++) {
|
|
||||||
// when filename is empty guess via suffix
|
// when filename is empty guess via suffix
|
||||||
file = files[i].type
|
const file = message.files[i].type
|
||||||
? files[i]
|
? message.files[i]
|
||||||
: new File([files[i]], files[i].name, {type: mime.getMimeByFilename(files[i].name)});
|
: new File([message.files[i]], message.files[i].name, {type: mime.getMimeByFilename(message.files[i].name)});
|
||||||
filesWithType.push(file)
|
files.push(file)
|
||||||
}
|
}
|
||||||
return filesWithType;
|
this.peers[message.to].requestFileTransfer(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
_onSendText(message) {
|
_onSendText(message) {
|
||||||
|
@ -731,12 +730,6 @@ class PeersManager {
|
||||||
peer._conn.close();
|
peer._conn.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
_clearPeers() {
|
|
||||||
if (this.peers) {
|
|
||||||
Object.keys(this.peers).forEach(peerId => this._onPeerLeft(peerId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_onSecretRoomDeleted(roomSecret) {
|
_onSecretRoomDeleted(roomSecret) {
|
||||||
for (const peerId in this.peers) {
|
for (const peerId in this.peers) {
|
||||||
const peer = this.peers[peerId];
|
const peer = this.peers[peerId];
|
||||||
|
|
|
@ -19,14 +19,12 @@ class PeersUI {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
Events.on('peer-joined', e => this._onPeerJoined(e.detail));
|
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-connected', e => this._onPeerConnected(e.detail));
|
||||||
Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail));
|
Events.on('peer-disconnected', e => this._onPeerDisconnected(e.detail));
|
||||||
Events.on('peers', e => this._onPeers(e.detail));
|
Events.on('peers', e => this._onPeers(e.detail));
|
||||||
Events.on('set-progress', e => this._onSetProgress(e.detail));
|
Events.on('set-progress', e => this._onSetProgress(e.detail));
|
||||||
Events.on('paste', e => this._onPaste(e));
|
Events.on('paste', e => this._onPaste(e));
|
||||||
Events.on('ws-disconnected', _ => this._clearPeers());
|
Events.on('secret-room-deleted', e => this._onSecretRoomDeleted(e.detail));
|
||||||
Events.on('secret-room-deleted', _ => this._clearPeers('secret'));
|
|
||||||
Events.on('activate-paste-mode', e => this._activatePasteMode(e.detail.files, e.detail.text));
|
Events.on('activate-paste-mode', e => this._activatePasteMode(e.detail.files, e.detail.text));
|
||||||
this.peers = {};
|
this.peers = {};
|
||||||
|
|
||||||
|
@ -88,16 +86,11 @@ class PeersUI {
|
||||||
if ($$('x-peers:empty')) setTimeout(_ => window.animateBackground(true), 1750); // Start animation again
|
if ($$('x-peers:empty')) setTimeout(_ => window.animateBackground(true), 1750); // Start animation again
|
||||||
}
|
}
|
||||||
|
|
||||||
_onPeerLeft(peerId) {
|
|
||||||
this._onPeerDisconnected(peerId);
|
|
||||||
delete this.peers[peerId];
|
|
||||||
}
|
|
||||||
|
|
||||||
_onSecretRoomDeleted(roomSecret) {
|
_onSecretRoomDeleted(roomSecret) {
|
||||||
for (const peerId in this.peers) {
|
for (const peerId in this.peers) {
|
||||||
const peer = this.peers[peerId];
|
const peer = this.peers[peerId];
|
||||||
if (peer.roomSecret === roomSecret) {
|
if (peer.roomSecret === roomSecret) {
|
||||||
this._onPeerLeft(peerId);
|
this._onPeerDisconnected(peerId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,16 +101,6 @@ class PeersUI {
|
||||||
$peer.ui.setProgress(progress.progress, progress.status)
|
$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) {
|
_onDrop(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!$$('x-peer') || !$$('x-peer').contains(e.target)) {
|
if (!$$('x-peer') || !$$('x-peer').contains(e.target)) {
|
||||||
|
@ -429,7 +412,7 @@ class Dialog {
|
||||||
this.$el = $(id);
|
this.$el = $(id);
|
||||||
this.$el.querySelectorAll('[close]').forEach(el => el.addEventListener('click', _ => this.hide()))
|
this.$el.querySelectorAll('[close]').forEach(el => el.addEventListener('click', _ => this.hide()))
|
||||||
this.$autoFocus = this.$el.querySelector('[autofocus]');
|
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() {
|
show() {
|
||||||
|
@ -445,6 +428,14 @@ class Dialog {
|
||||||
}
|
}
|
||||||
document.title = 'PairDrop';
|
document.title = 'PairDrop';
|
||||||
document.changeFavicon("images/favicon-96x96.png");
|
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', {
|
Events.fire('set-progress', {
|
||||||
peerId: peerId,
|
peerId: peerId,
|
||||||
progress: 1,
|
progress: 1,
|
||||||
status: 'wait'
|
status: 'process'
|
||||||
})
|
})
|
||||||
this.$shareOrDownloadBtn.click();
|
this.$shareOrDownloadBtn.click();
|
||||||
}).catch(r => console.error(r));
|
}).catch(r => console.error(r));
|
||||||
|
@ -631,8 +622,6 @@ class ReceiveRequestDialog extends ReceiveDialog {
|
||||||
this.$declineRequestBtn.addEventListener('click', _ => this._respondToFileTransferRequest(false));
|
this.$declineRequestBtn.addEventListener('click', _ => this._respondToFileTransferRequest(false));
|
||||||
|
|
||||||
Events.on('files-transfer-request', e => this._onRequestFileTransfer(e.detail.request, e.detail.peerId))
|
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));
|
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) {
|
_onRequestFileTransfer(request, peerId) {
|
||||||
this.requestingPeerId = peerId;
|
this.correspondingPeerId = peerId;
|
||||||
this.requestedHeader = request.header;
|
this.requestedHeader = request.header;
|
||||||
|
|
||||||
const peer = $(peerId);
|
const peer = $(peerId);
|
||||||
|
@ -693,13 +675,12 @@ class ReceiveRequestDialog extends ReceiveDialog {
|
||||||
|
|
||||||
_respondToFileTransferRequest(accepted) {
|
_respondToFileTransferRequest(accepted) {
|
||||||
Events.fire('respond-to-files-transfer-request', {
|
Events.fire('respond-to-files-transfer-request', {
|
||||||
to: this.requestingPeerId,
|
to: this.correspondingPeerId,
|
||||||
header: this.requestedHeader,
|
header: this.requestedHeader,
|
||||||
accepted: accepted
|
accepted: accepted
|
||||||
})
|
})
|
||||||
this.requestingPeerId = null;
|
|
||||||
if (accepted) {
|
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();
|
NoSleepUI.enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -732,6 +713,7 @@ class PairDeviceDialog extends Dialog {
|
||||||
|
|
||||||
Events.on('keydown', e => this._onKeyDown(e));
|
Events.on('keydown', e => this._onKeyDown(e));
|
||||||
Events.on('ws-connected', _ => this._onWsConnected());
|
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-initiated', e => this._pairDeviceInitiated(e.detail));
|
||||||
Events.on('pair-device-joined', e => this._pairDeviceJoined(e.detail));
|
Events.on('pair-device-joined', e => this._pairDeviceJoined(e.detail));
|
||||||
Events.on('pair-device-join-key-invalid', _ => this._pairDeviceJoinKeyInvalid());
|
Events.on('pair-device-join-key-invalid', _ => this._pairDeviceJoinKeyInvalid());
|
||||||
|
@ -976,8 +958,8 @@ class SendTextDialog extends Dialog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_onRecipient(recipient) {
|
_onRecipient(peerId) {
|
||||||
this._recipient = recipient;
|
this.correspondingPeerId = peerId;
|
||||||
this.show();
|
this.show();
|
||||||
|
|
||||||
const range = document.createRange();
|
const range = document.createRange();
|
||||||
|
@ -991,7 +973,7 @@ class SendTextDialog extends Dialog {
|
||||||
|
|
||||||
_send() {
|
_send() {
|
||||||
Events.fire('send-text', {
|
Events.fire('send-text', {
|
||||||
to: this._recipient,
|
to: this.correspondingPeerId,
|
||||||
text: this.$text.innerText
|
text: this.$text.innerText
|
||||||
});
|
});
|
||||||
this.$text.value = "";
|
this.$text.value = "";
|
||||||
|
@ -1096,13 +1078,14 @@ class Base64ZipDialog extends Dialog {
|
||||||
class Toast extends Dialog {
|
class Toast extends Dialog {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('toast');
|
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.$el.textContent = message;
|
||||||
this.show();
|
this.show();
|
||||||
setTimeout(_ => this.hide(), 3000);
|
this.hideTimeout = setTimeout(_ => this.hide(), 3000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
var CACHE_NAME = 'pairdrop-cache-v4';
|
const CACHE_NAME = 'pairdrop-cache-v4';
|
||||||
var urlsToCache = [
|
const urlsToCache = [
|
||||||
'index.html',
|
'index.html',
|
||||||
'./',
|
'./',
|
||||||
'styles.css',
|
'styles.css',
|
||||||
|
@ -11,7 +11,13 @@ var urlsToCache = [
|
||||||
'scripts/NoSleep.min.js',
|
'scripts/NoSleep.min.js',
|
||||||
'scripts/theme.js',
|
'scripts/theme.js',
|
||||||
'sounds/blop.mp3',
|
'sounds/blop.mp3',
|
||||||
'images/favicon-96x96.png'
|
'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) {
|
self.addEventListener('install', function(event) {
|
||||||
|
|
|
@ -320,6 +320,10 @@ x-peer[status=wait] .status:before {
|
||||||
content: 'Waiting...';
|
content: 'Waiting...';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
x-peer[status=process] .status:before {
|
||||||
|
content: 'Processing...';
|
||||||
|
}
|
||||||
|
|
||||||
x-peer:not([status]) .status,
|
x-peer:not([status]) .status,
|
||||||
x-peer[status] .device-name {
|
x-peer[status] .device-name {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -527,6 +531,8 @@ x-dialog .row-reverse {
|
||||||
max-width: 80%;
|
max-width: 80%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
word-break: break-all;
|
||||||
|
max-height: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-size{
|
.file-size{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue