Implement new status 'connecting', automatic reconnect on disconnect and auto resume of transfer + sending of queued messages. (fixes #260 and #247)
This commit is contained in:
		
							parent
							
								
									b36105b1cf
								
							
						
					
					
						commit
						f22abca783
					
				| 
						 | 
					@ -176,9 +176,11 @@
 | 
				
			||||||
        "click-to-send-share-mode": "Click to send {{descriptor}}",
 | 
					        "click-to-send-share-mode": "Click to send {{descriptor}}",
 | 
				
			||||||
        "click-to-send": "Click to send files or right click to send a message",
 | 
					        "click-to-send": "Click to send files or right click to send a message",
 | 
				
			||||||
        "connection-hash": "To verify the security of the end-to-end encryption, compare this security number on both devices",
 | 
					        "connection-hash": "To verify the security of the end-to-end encryption, compare this security number on both devices",
 | 
				
			||||||
 | 
					        "connecting": "Connecting…",
 | 
				
			||||||
        "preparing": "Preparing…",
 | 
					        "preparing": "Preparing…",
 | 
				
			||||||
        "waiting": "Waiting…",
 | 
					        "waiting": "Waiting…",
 | 
				
			||||||
        "processing": "Processing…",
 | 
					        "processing": "Processing…",
 | 
				
			||||||
        "transferring": "Transferring…"
 | 
					        "transferring": "Transferring…",
 | 
				
			||||||
 | 
					        "receiving": "Receiving…"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -88,7 +88,9 @@ class ServerConnection {
 | 
				
			||||||
    _onOpen() {
 | 
					    _onOpen() {
 | 
				
			||||||
        console.log('WS: server connected');
 | 
					        console.log('WS: server connected');
 | 
				
			||||||
        Events.fire('ws-connected');
 | 
					        Events.fire('ws-connected');
 | 
				
			||||||
        if (this._isReconnect) Events.fire('notify-user', Localization.getTranslation("notifications.connected"));
 | 
					        if (this._isReconnect) {
 | 
				
			||||||
 | 
					            Events.fire('notify-user', Localization.getTranslation("notifications.connected"));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPairDeviceInitiate() {
 | 
					    _onPairDeviceInitiate() {
 | 
				
			||||||
| 
						 | 
					@ -101,6 +103,7 @@ class ServerConnection {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPairDeviceJoin(pairKey) {
 | 
					    _onPairDeviceJoin(pairKey) {
 | 
				
			||||||
        if (!this._isConnected()) {
 | 
					        if (!this._isConnected()) {
 | 
				
			||||||
 | 
					            // Todo: instead use pending outbound ws queue
 | 
				
			||||||
            setTimeout(() => this._onPairDeviceJoin(pairKey), 1000);
 | 
					            setTimeout(() => this._onPairDeviceJoin(pairKey), 1000);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -336,6 +339,10 @@ class Peer {
 | 
				
			||||||
        this._evaluateAutoAccept();
 | 
					        this._evaluateAutoAccept();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _setIsCaller(isCaller) {
 | 
				
			||||||
 | 
					        this._isCaller = isCaller;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sendJSON(message) {
 | 
					    sendJSON(message) {
 | 
				
			||||||
        this._send(JSON.stringify(message));
 | 
					        this._send(JSON.stringify(message));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -433,6 +440,14 @@ class Peer {
 | 
				
			||||||
            : false;
 | 
					            : false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onPeerConnected() {
 | 
				
			||||||
 | 
					        if (this._digester) {
 | 
				
			||||||
 | 
					            // Reconnection during receiving of file. Send request for restart
 | 
				
			||||||
 | 
					            const offset = this._digester._bytesReceived;
 | 
				
			||||||
 | 
					            this._requestResendFromOffset(offset);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async requestFileTransfer(files) {
 | 
					    async requestFileTransfer(files) {
 | 
				
			||||||
        let header = [];
 | 
					        let header = [];
 | 
				
			||||||
        let totalSize = 0;
 | 
					        let totalSize = 0;
 | 
				
			||||||
| 
						 | 
					@ -472,8 +487,8 @@ class Peer {
 | 
				
			||||||
        Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'wait'})
 | 
					        Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'wait'})
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async sendFiles() {
 | 
					    sendFiles() {
 | 
				
			||||||
        for (let i=0; i<this._filesRequested.length; i++) {
 | 
					        for (let i = 0; i < this._filesRequested.length; i++) {
 | 
				
			||||||
            this._filesQueue.push(this._filesRequested[i]);
 | 
					            this._filesQueue.push(this._filesRequested[i]);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this._filesRequested = null
 | 
					        this._filesRequested = null
 | 
				
			||||||
| 
						 | 
					@ -487,7 +502,7 @@ class Peer {
 | 
				
			||||||
        this._sendFile(file);
 | 
					        this._sendFile(file);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async _sendFile(file) {
 | 
					    _sendFile(file) {
 | 
				
			||||||
        this.sendJSON({
 | 
					        this.sendJSON({
 | 
				
			||||||
            type: 'header',
 | 
					            type: 'header',
 | 
				
			||||||
            size: file.size,
 | 
					            size: file.size,
 | 
				
			||||||
| 
						 | 
					@ -508,11 +523,21 @@ class Peer {
 | 
				
			||||||
        this.sendJSON({ type: 'partition-received', offset: offset });
 | 
					        this.sendJSON({ type: 'partition-received', offset: offset });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _requestResendFromOffset(offset) {
 | 
				
			||||||
 | 
					        this.sendJSON({ type: 'request-resend-from-offset', offset: offset });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _sendNextPartition() {
 | 
					    _sendNextPartition() {
 | 
				
			||||||
        if (!this._chunker || this._chunker.isFileEnd()) return;
 | 
					        if (!this._chunker || this._chunker.isFileEnd()) return;
 | 
				
			||||||
        this._chunker.nextPartition();
 | 
					        this._chunker.nextPartition();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onRequestResendFromOffset(offset) {
 | 
				
			||||||
 | 
					        console.log("Restart requested from offset:", offset)
 | 
				
			||||||
 | 
					        if (!this._chunker) return;
 | 
				
			||||||
 | 
					        this._chunker._restartFromOffset(offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _sendProgress(progress) {
 | 
					    _sendProgress(progress) {
 | 
				
			||||||
        this.sendJSON({ type: 'progress', progress: progress });
 | 
					        this.sendJSON({ type: 'progress', progress: progress });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -522,25 +547,35 @@ class Peer {
 | 
				
			||||||
            this._onChunkReceived(message);
 | 
					            this._onChunkReceived(message);
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const messageJSON = JSON.parse(message);
 | 
					
 | 
				
			||||||
        switch (messageJSON.type) {
 | 
					        try {
 | 
				
			||||||
 | 
					            message = JSON.parse(message);
 | 
				
			||||||
 | 
					        } catch (e) {
 | 
				
			||||||
 | 
					            console.warn("Peer: Received JSON is malformed");
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (message.type) {
 | 
				
			||||||
            case 'request':
 | 
					            case 'request':
 | 
				
			||||||
                this._onFilesTransferRequest(messageJSON);
 | 
					                this._onFilesTransferRequest(message);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 'header':
 | 
					            case 'header':
 | 
				
			||||||
                this._onFileHeader(messageJSON);
 | 
					                this._onFileHeader(message);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 'partition':
 | 
					            case 'partition':
 | 
				
			||||||
                this._onReceivedPartitionEnd(messageJSON);
 | 
					                this._onReceivedPartitionEnd(message);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 'partition-received':
 | 
					            case 'partition-received':
 | 
				
			||||||
                this._sendNextPartition();
 | 
					                this._sendNextPartition();
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 'progress':
 | 
					            case 'progress':
 | 
				
			||||||
                this._onDownloadProgress(messageJSON.progress);
 | 
					                this._onProgress(message.progress);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'request-resend-from-offset':
 | 
				
			||||||
 | 
					                this._onRequestResendFromOffset(message.offset);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 'files-transfer-response':
 | 
					            case 'files-transfer-response':
 | 
				
			||||||
                this._onFileTransferRequestResponded(messageJSON);
 | 
					                this._onFileTransferRequestResponded(message);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 'file-transfer-complete':
 | 
					            case 'file-transfer-complete':
 | 
				
			||||||
                this._onFileTransferCompleted();
 | 
					                this._onFileTransferCompleted();
 | 
				
			||||||
| 
						 | 
					@ -549,10 +584,10 @@ class Peer {
 | 
				
			||||||
                this._onMessageTransferCompleted();
 | 
					                this._onMessageTransferCompleted();
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 'text':
 | 
					            case 'text':
 | 
				
			||||||
                this._onTextReceived(messageJSON);
 | 
					                this._onTextReceived(message);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
            case 'display-name-changed':
 | 
					            case 'display-name-changed':
 | 
				
			||||||
                this._onDisplayNameChanged(messageJSON);
 | 
					                this._onDisplayNameChanged(message);
 | 
				
			||||||
                break;
 | 
					                break;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -620,21 +655,28 @@ class Peer {
 | 
				
			||||||
        if(!this._digester || !(chunk.byteLength || chunk.size)) return;
 | 
					        if(!this._digester || !(chunk.byteLength || chunk.size)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._digester.unchunk(chunk);
 | 
					        this._digester.unchunk(chunk);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const progress = this._digester.progress;
 | 
					        const progress = this._digester.progress;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (progress > 1) {
 | 
					        if (progress > 1) {
 | 
				
			||||||
            this._abortTransfer();
 | 
					            this._abortTransfer();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._onDownloadProgress(progress);
 | 
					        if (progress === 1) {
 | 
				
			||||||
 | 
					            this._digester = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Events.fire('set-progress', {peerId: this._peerId, progress: progress, status: 'receive'});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // occasionally notify sender about our progress
 | 
					        // occasionally notify sender about our progress
 | 
				
			||||||
        if (progress - this._lastProgress < 0.005 && progress !== 1) return;
 | 
					        if (progress - this._lastProgress >= 0.005 || progress === 1) {
 | 
				
			||||||
        this._lastProgress = progress;
 | 
					            this._lastProgress = progress;
 | 
				
			||||||
        this._sendProgress(progress);
 | 
					            this._sendProgress(progress);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onDownloadProgress(progress) {
 | 
					    _onProgress(progress) {
 | 
				
			||||||
        Events.fire('set-progress', {peerId: this._peerId, progress: progress, status: 'transfer'});
 | 
					        Events.fire('set-progress', {peerId: this._peerId, progress: progress, status: 'transfer'});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -654,25 +696,33 @@ class Peer {
 | 
				
			||||||
        Events.fire('file-received', fileBlob);
 | 
					        Events.fire('file-received', fileBlob);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._filesReceived.push(fileBlob);
 | 
					        this._filesReceived.push(fileBlob);
 | 
				
			||||||
        if (!this._requestAccepted.header.length) {
 | 
					
 | 
				
			||||||
            this._busy = false;
 | 
					        if (this._requestAccepted.header.length) return;
 | 
				
			||||||
            Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'process'});
 | 
					
 | 
				
			||||||
            Events.fire('files-received', {peerId: this._peerId, files: this._filesReceived, imagesOnly: this._requestAccepted.imagesOnly, totalSize: this._requestAccepted.totalSize});
 | 
					        // We are done receiving
 | 
				
			||||||
            this._filesReceived = [];
 | 
					        this._busy = false;
 | 
				
			||||||
            this._requestAccepted = null;
 | 
					        Events.fire('set-progress', {peerId: this._peerId, progress: 0, status: 'process'});
 | 
				
			||||||
        }
 | 
					        Events.fire('files-received', {
 | 
				
			||||||
 | 
					            peerId: this._peerId,
 | 
				
			||||||
 | 
					            files: this._filesReceived,
 | 
				
			||||||
 | 
					            imagesOnly: this._requestAccepted.imagesOnly,
 | 
				
			||||||
 | 
					            totalSize: this._requestAccepted.totalSize
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        this._filesReceived = [];
 | 
				
			||||||
 | 
					        this._requestAccepted = null;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onFileTransferCompleted() {
 | 
					    _onFileTransferCompleted() {
 | 
				
			||||||
        this._chunker = null;
 | 
					        this._chunker = null;
 | 
				
			||||||
        if (!this._filesQueue.length) {
 | 
					        if (this._filesQueue.length) {
 | 
				
			||||||
            this._busy = false;
 | 
					 | 
				
			||||||
            Events.fire('notify-user', Localization.getTranslation("notifications.file-transfer-completed"));
 | 
					 | 
				
			||||||
            Events.fire('files-sent'); // used by 'Snapdrop & PairDrop for Android' app
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            this._dequeueFile();
 | 
					            this._dequeueFile();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // No more files in queue. Transfer is complete
 | 
				
			||||||
 | 
					        this._busy = false;
 | 
				
			||||||
 | 
					        Events.fire('notify-user', Localization.getTranslation("notifications.file-transfer-completed"));
 | 
				
			||||||
 | 
					        Events.fire('files-sent'); // used by 'Snapdrop & PairDrop for Android' app
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onFileTransferRequestResponded(message) {
 | 
					    _onFileTransferRequestResponded(message) {
 | 
				
			||||||
| 
						 | 
					@ -725,99 +775,293 @@ class RTCPeer extends Peer {
 | 
				
			||||||
        super(serverConnection, isCaller, peerId, roomType, roomId);
 | 
					        super(serverConnection, isCaller, peerId, roomType, roomId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.rtcSupported = true;
 | 
					        this.rtcSupported = true;
 | 
				
			||||||
        this.rtcConfig = rtcConfig
 | 
					        this.rtcConfig = rtcConfig;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.pendingInboundMessages = [];
 | 
				
			||||||
 | 
					        this.pendingOutboundMessages = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Events.on('beforeunload', e => this._onBeforeUnload(e));
 | 
				
			||||||
 | 
					        Events.on('pagehide', _ => this._onPageHide());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!this._isCaller) return; // we will listen for a caller
 | 
					 | 
				
			||||||
        this._connect();
 | 
					        this._connect();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _connect() {
 | 
					    _isConnected() {
 | 
				
			||||||
        if (!this._conn || this._conn.signalingState === "closed") this._openConnection();
 | 
					        return this._conn && this._conn.connectionState === 'connected';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (this._isCaller) {
 | 
					    _isConnecting() {
 | 
				
			||||||
            this._openChannel();
 | 
					        return this._conn
 | 
				
			||||||
        }
 | 
					            && (
 | 
				
			||||||
        else {
 | 
					                this._conn.connectionState === 'new'
 | 
				
			||||||
            this._conn.ondatachannel = e => this._onChannelOpened(e);
 | 
					                || this._conn.connectionState === 'connecting'
 | 
				
			||||||
        }
 | 
					            );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _isChannelOpen() {
 | 
				
			||||||
 | 
					        return this._channel && this._channel.readyState === 'open';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _isChannelConnecting() {
 | 
				
			||||||
 | 
					        return this._channel && this._channel.readyState === 'connecting';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _isStable() {
 | 
				
			||||||
 | 
					        return this._isChannelOpen() && this._isConnected();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _connect() {
 | 
				
			||||||
 | 
					        if (this._isStable()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Events.fire('peer-connecting', this._peerId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._openConnection();
 | 
				
			||||||
 | 
					        // TOdo: one channel for messages - one for data?
 | 
				
			||||||
 | 
					        this._openChannel();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _openConnection() {
 | 
					    _openConnection() {
 | 
				
			||||||
        this._conn = new RTCPeerConnection(this.rtcConfig);
 | 
					        const conn = new RTCPeerConnection(this.rtcConfig);
 | 
				
			||||||
        this._conn.onicecandidate = e => this._onIceCandidate(e);
 | 
					        conn.onnegotiationneeded = _ => this._onNegotiationNeeded();
 | 
				
			||||||
        this._conn.onicecandidateerror = e => this._onError(e);
 | 
					        conn.onsignalingstatechange = _ => this._onSignalingStateChanged();
 | 
				
			||||||
        this._conn.onconnectionstatechange = _ => this._onConnectionStateChange();
 | 
					        conn.oniceconnectionstatechange = _ => this._onIceConnectionStateChange();
 | 
				
			||||||
        this._conn.oniceconnectionstatechange = e => this._onIceConnectionStateChange(e);
 | 
					        conn.onicegatheringstatechange = _ => this._onIceGatheringStateChanged();
 | 
				
			||||||
 | 
					        conn.onconnectionstatechange = _ => this._onConnectionStateChange();
 | 
				
			||||||
 | 
					        conn.onicecandidate = e => this._onIceCandidate(e);
 | 
				
			||||||
 | 
					        conn.onicecandidateerror = e => this._onIceCandidateError(e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._conn = conn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._evaluatePendingInboundMessages()
 | 
				
			||||||
 | 
					            .then((count) => {
 | 
				
			||||||
 | 
					                if (count) {
 | 
				
			||||||
 | 
					                    console.log("Pending inbound messages evaluated.");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _openChannel() {
 | 
					    async _onNegotiationNeeded() {
 | 
				
			||||||
        if (!this._conn) return;
 | 
					        console.log('RTC: Negotiation needed');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const channel = this._conn.createDataChannel('data-channel', {
 | 
					        if (this._isCaller) {
 | 
				
			||||||
            ordered: true,
 | 
					            // Creating offer if required
 | 
				
			||||||
            reliable: true // Obsolete. See https://developer.mozilla.org/en-US/docs/Web/API/RTCDataChannel/reliable
 | 
					            console.log('RTC: Creating offer');
 | 
				
			||||||
        });
 | 
					            const description = await this._conn.createOffer();
 | 
				
			||||||
        channel.onopen = e => this._onChannelOpened(e);
 | 
					            await this._handleLocalDescription(description);
 | 
				
			||||||
        channel.onerror = e => this._onError(e);
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        this._conn
 | 
					 | 
				
			||||||
            .createOffer()
 | 
					 | 
				
			||||||
            .then(d => this._onDescription(d))
 | 
					 | 
				
			||||||
            .catch(e => this._onError(e));
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onDescription(description) {
 | 
					    _onSignalingStateChanged() {
 | 
				
			||||||
        // description.sdp = description.sdp.replace('b=AS:30', 'b=AS:1638400');
 | 
					        console.log('RTC: Signaling state changed:', this._conn.signalingState);
 | 
				
			||||||
        this._conn
 | 
					    }
 | 
				
			||||||
            .setLocalDescription(description)
 | 
					
 | 
				
			||||||
            .then(_ => this._sendSignal({ sdp: description }))
 | 
					    _onIceConnectionStateChange() {
 | 
				
			||||||
            .catch(e => this._onError(e));
 | 
					        console.log('RTC: ICE connection state changed:', this._conn.iceConnectionState);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onIceGatheringStateChanged() {
 | 
				
			||||||
 | 
					        console.log('RTC: ICE gathering state changed:', this._conn.iceConnectionState);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onConnectionStateChange() {
 | 
				
			||||||
 | 
					        console.log('RTC: Connection state changed:', this._conn.connectionState);
 | 
				
			||||||
 | 
					        switch (this._conn.connectionState) {
 | 
				
			||||||
 | 
					            case 'disconnected':
 | 
				
			||||||
 | 
					                this._refresh();
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'failed':
 | 
				
			||||||
 | 
					                console.warn('RTC connection failed');
 | 
				
			||||||
 | 
					                // TOdo: implement ws fallback as real fallback
 | 
				
			||||||
 | 
					                this._refresh();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onIceCandidate(event) {
 | 
					    _onIceCandidate(event) {
 | 
				
			||||||
        if (!event.candidate) return;
 | 
					        this._handleLocalCandidate(event.candidate);
 | 
				
			||||||
        this._sendSignal({ ice: event.candidate });
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    onServerMessage(message) {
 | 
					    _onIceCandidateError(error) {
 | 
				
			||||||
        if (!this._conn) this._connect();
 | 
					        console.error(error);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (message.sdp) {
 | 
					 | 
				
			||||||
            this._conn
 | 
					 | 
				
			||||||
                .setRemoteDescription(message.sdp)
 | 
					 | 
				
			||||||
                .then(_ => {
 | 
					 | 
				
			||||||
                    if (message.sdp.type === 'offer') {
 | 
					 | 
				
			||||||
                        return this._conn
 | 
					 | 
				
			||||||
                            .createAnswer()
 | 
					 | 
				
			||||||
                            .then(d => this._onDescription(d));
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                })
 | 
					 | 
				
			||||||
                .catch(e => this._onError(e));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else if (message.ice) {
 | 
					 | 
				
			||||||
            this._conn
 | 
					 | 
				
			||||||
                .addIceCandidate(new RTCIceCandidate(message.ice))
 | 
					 | 
				
			||||||
                .catch(e => this._onError(e));
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onChannelOpened(event) {
 | 
					    _openChannel() {
 | 
				
			||||||
        console.log('RTC: channel opened with', this._peerId);
 | 
					        const channel = this._conn.createDataChannel('data-channel', {
 | 
				
			||||||
        const channel = event.channel || event.target;
 | 
					            ordered: true,
 | 
				
			||||||
 | 
					            negotiated: true,
 | 
				
			||||||
 | 
					            id: 0
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
        channel.binaryType = 'arraybuffer';
 | 
					        channel.binaryType = 'arraybuffer';
 | 
				
			||||||
        channel.onmessage = e => this._onMessage(e.data);
 | 
					        channel.onopen = _ => this._onChannelOpened();
 | 
				
			||||||
        channel.onclose = _ => this._onChannelClosed();
 | 
					        channel.onclose = _ => this._onChannelClosed();
 | 
				
			||||||
 | 
					        channel.onerror = e => this._onChannelError(e);
 | 
				
			||||||
 | 
					        channel.onmessage = e => this._onMessage(e.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._channel = channel;
 | 
					        this._channel = channel;
 | 
				
			||||||
        Events.on('beforeunload', e => this._onBeforeUnload(e));
 | 
					 | 
				
			||||||
        Events.on('pagehide', _ => this._onPageHide());
 | 
					 | 
				
			||||||
        Events.fire('peer-connected', {peerId: this._peerId, connectionHash: this.getConnectionHash()});
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onMessage(message) {
 | 
					    _onChannelOpened() {
 | 
				
			||||||
        if (typeof message === 'string') {
 | 
					        console.log('RTC: Channel opened with', this._peerId);
 | 
				
			||||||
            console.log('RTC:', JSON.parse(message));
 | 
					        console.debug(this.getConnectionHash())
 | 
				
			||||||
 | 
					        console.debug(this._conn)
 | 
				
			||||||
 | 
					        console.debug(this._channel)
 | 
				
			||||||
 | 
					        Events.fire('peer-connected', {peerId: this._peerId, connectionHash: this.getConnectionHash()});
 | 
				
			||||||
 | 
					        super._onPeerConnected();
 | 
				
			||||||
 | 
					        while (this._isChannelOpen() && this.pendingOutboundMessages.length > 0) {
 | 
				
			||||||
 | 
					            this._sendViaChannel(this.pendingOutboundMessages.shift());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        super._onMessage(message);
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onChannelClosed() {
 | 
				
			||||||
 | 
					        console.log('RTC: Channel closed', this._peerId);
 | 
				
			||||||
 | 
					        this._refresh();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onChannelError(error) {
 | 
				
			||||||
 | 
					        console.error(error);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async _handleLocalDescription(localDescription) {
 | 
				
			||||||
 | 
					        await this._conn.setLocalDescription(localDescription);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        console.log("RTC: Sending local description");
 | 
				
			||||||
 | 
					        this._sendSignal({ signalType: 'description', description: localDescription });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async _handleRemoteDescription(remoteDescription) {
 | 
				
			||||||
 | 
					        console.log("RTC: Received remote description");
 | 
				
			||||||
 | 
					        await this._conn.setRemoteDescription(remoteDescription);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this._isCaller) {
 | 
				
			||||||
 | 
					            // Creating answer if required
 | 
				
			||||||
 | 
					            console.log('RTC: Creating answer');
 | 
				
			||||||
 | 
					            const localDescription = await this._conn.createAnswer();
 | 
				
			||||||
 | 
					            await this._handleLocalDescription(localDescription);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _handleLocalCandidate(candidate) {
 | 
				
			||||||
 | 
					        console.log("RTC: Sending local candidate");
 | 
				
			||||||
 | 
					        this._sendSignal({ signalType: 'candidate', candidate: candidate });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (candidate === null) {
 | 
				
			||||||
 | 
					            this.localIceCandidatesSent = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async _handleRemoteCandidate(candidate) {
 | 
				
			||||||
 | 
					        console.log("RTC: Received remote candidate");
 | 
				
			||||||
 | 
					        if (candidate !== null) {
 | 
				
			||||||
 | 
					            await this._conn.addIceCandidate(candidate);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            this.remoteIceCandidatesReceived = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async _evaluatePendingInboundMessages() {
 | 
				
			||||||
 | 
					        let inboundMessagesEvaluatedCount = 0;
 | 
				
			||||||
 | 
					        while (this.pendingInboundMessages.length > 0) {
 | 
				
			||||||
 | 
					            const message = this.pendingInboundMessages.shift();
 | 
				
			||||||
 | 
					            console.log("Evaluate pending inbound message:", message);
 | 
				
			||||||
 | 
					            await this.onServerMessage(message);
 | 
				
			||||||
 | 
					            inboundMessagesEvaluatedCount++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return inboundMessagesEvaluatedCount;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    async onServerMessage(message) {
 | 
				
			||||||
 | 
					        if (this._conn === null) {
 | 
				
			||||||
 | 
					            console.debug("Not ready yet. Pending needed indeed?")
 | 
				
			||||||
 | 
					            this.pendingInboundMessages.push(message);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        switch (message.signalType) {
 | 
				
			||||||
 | 
					            case 'description':
 | 
				
			||||||
 | 
					                await this._handleRemoteDescription(message.description);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            case 'candidate':
 | 
				
			||||||
 | 
					                await this._handleRemoteCandidate(message.candidate);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            default:
 | 
				
			||||||
 | 
					                console.warn(this.name, 'Unknown message type:', message.type);
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _disconnect() {
 | 
				
			||||||
 | 
					        Events.fire('peer-disconnected', this._peerId);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _refresh() {
 | 
				
			||||||
 | 
					        Events.fire('peer-connecting', this._peerId);
 | 
				
			||||||
 | 
					        this._closeChannelAndConnection();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._connect(); // reopen the channel
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _closeChannelAndConnection() {
 | 
				
			||||||
 | 
					        if (this._channel) {
 | 
				
			||||||
 | 
					            this._channel.onopen = null;
 | 
				
			||||||
 | 
					            this._channel.onclose = null;
 | 
				
			||||||
 | 
					            this._channel.onerror = null;
 | 
				
			||||||
 | 
					            this._channel.onmessage = null;
 | 
				
			||||||
 | 
					            this._channel.close();
 | 
				
			||||||
 | 
					            this._channel = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (this._conn) {
 | 
				
			||||||
 | 
					            this._conn.onnegotiationneeded = null;
 | 
				
			||||||
 | 
					            this._conn.onsignalingstatechange = null;
 | 
				
			||||||
 | 
					            this._conn.oniceconnectionstatechange = null;
 | 
				
			||||||
 | 
					            this._conn.onicegatheringstatechange = null;
 | 
				
			||||||
 | 
					            this._conn.onconnectionstatechange = null;
 | 
				
			||||||
 | 
					            this._conn.onicecandidate = null;
 | 
				
			||||||
 | 
					            this._conn.onicecandidateerror = null;
 | 
				
			||||||
 | 
					            this._conn.close();
 | 
				
			||||||
 | 
					            this._conn = null;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.localIceCandidatesSent = false;
 | 
				
			||||||
 | 
					        this.remoteIceCandidatesReceived = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onBeforeUnload(e) {
 | 
				
			||||||
 | 
					        if (this._busy) {
 | 
				
			||||||
 | 
					            e.preventDefault();
 | 
				
			||||||
 | 
					            return Localization.getTranslation("notifications.unfinished-transfers-warning");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onPageHide() {
 | 
				
			||||||
 | 
					        this._disconnect();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _send(message) {
 | 
				
			||||||
 | 
					        // Todo: if channel or connection is closed or disconnected: do not send
 | 
				
			||||||
 | 
					        //        put messages in queue and send after reconnection.
 | 
				
			||||||
 | 
					        //        this._pendingMessages[];
 | 
				
			||||||
 | 
					        if (!this._isStable() || this.pendingOutboundMessages.length > 0) {
 | 
				
			||||||
 | 
					            // queue messages if not connected OR if connected AND queue is not empty
 | 
				
			||||||
 | 
					            this.pendingOutboundMessages.push(message);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this._sendViaChannel(message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _sendViaChannel(message) {
 | 
				
			||||||
 | 
					        this._channel.send(message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _sendSignal(message) {
 | 
				
			||||||
 | 
					        message.type = 'signal';
 | 
				
			||||||
 | 
					        message.to = this._peerId;
 | 
				
			||||||
 | 
					        message.roomType = this._getRoomTypes()[0];
 | 
				
			||||||
 | 
					        message.roomId = this._roomIds[this._getRoomTypes()[0]];
 | 
				
			||||||
 | 
					        this._server.send(message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sendDisplayName(displayName) {
 | 
				
			||||||
 | 
					        super.sendDisplayName(displayName);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    getConnectionHash() {
 | 
					    getConnectionHash() {
 | 
				
			||||||
| 
						 | 
					@ -886,54 +1130,12 @@ class RTCPeer extends Peer {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onIceConnectionStateChange() {
 | 
					    _onMessage(message) {
 | 
				
			||||||
        switch (this._conn.iceConnectionState) {
 | 
					        if (typeof message === 'string') {
 | 
				
			||||||
            case 'failed':
 | 
					            // Todo: Test speed increase without prints? --> print only on debug mode via URL argument `?debug_mode=true`
 | 
				
			||||||
                this._onError('ICE Gathering failed');
 | 
					            console.log('RTC:', JSON.parse(message));
 | 
				
			||||||
                break;
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                console.log('ICE Gathering', this._conn.iceConnectionState);
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					        super._onMessage(message);
 | 
				
			||||||
 | 
					 | 
				
			||||||
    _onError(error) {
 | 
					 | 
				
			||||||
        console.error(error);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _send(message) {
 | 
					 | 
				
			||||||
        if (!this._channel) this.refresh();
 | 
					 | 
				
			||||||
        this._channel.send(message);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _sendSignal(signal) {
 | 
					 | 
				
			||||||
        signal.type = 'signal';
 | 
					 | 
				
			||||||
        signal.to = this._peerId;
 | 
					 | 
				
			||||||
        signal.roomType = this._getRoomTypes()[0];
 | 
					 | 
				
			||||||
        signal.roomId = this._roomIds[this._getRoomTypes()[0]];
 | 
					 | 
				
			||||||
        this._server.send(signal);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    refresh() {
 | 
					 | 
				
			||||||
        // check if channel is open. otherwise create one
 | 
					 | 
				
			||||||
        if (this._isConnected() || this._isConnecting()) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // only reconnect if peer is caller
 | 
					 | 
				
			||||||
        if (!this._isCaller) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this._connect();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _isConnected() {
 | 
					 | 
				
			||||||
        return this._channel && this._channel.readyState === 'open';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _isConnecting() {
 | 
					 | 
				
			||||||
        return this._channel && this._channel.readyState === 'connecting';
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sendDisplayName(displayName) {
 | 
					 | 
				
			||||||
        if (!this._isConnected()) return;
 | 
					 | 
				
			||||||
        super.sendDisplayName(displayName);
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1020,9 +1222,7 @@ class PeersManager {
 | 
				
			||||||
        this.peers[peerId].onServerMessage(message);
 | 
					        this.peers[peerId].onServerMessage(message);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _refreshPeer(peerId, roomType, roomId) {
 | 
					    _refreshPeer(isCaller, peerId, roomType, roomId) {
 | 
				
			||||||
        if (!this._peerExists(peerId)) return false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const peer = this.peers[peerId];
 | 
					        const peer = this.peers[peerId];
 | 
				
			||||||
        const roomTypesDiffer = Object.keys(peer._roomIds)[0] !== roomType;
 | 
					        const roomTypesDiffer = Object.keys(peer._roomIds)[0] !== roomType;
 | 
				
			||||||
        const roomIdsDiffer = peer._roomIds[roomType] !== roomId;
 | 
					        const roomIdsDiffer = peer._roomIds[roomType] !== roomId;
 | 
				
			||||||
| 
						 | 
					@ -1036,17 +1236,22 @@ class PeersManager {
 | 
				
			||||||
            return true;
 | 
					            return true;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        peer.refresh();
 | 
					        // reconnect peer - caller/waiter might be switched
 | 
				
			||||||
 | 
					        peer._setIsCaller(isCaller);
 | 
				
			||||||
 | 
					        peer._refresh();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _createOrRefreshPeer(isCaller, peerId, roomType, roomId, rtcSupported) {
 | 
					    _createOrRefreshPeer(isCaller, peerId, roomType, roomId, rtcSupported) {
 | 
				
			||||||
        if (this._peerExists(peerId)) {
 | 
					        if (this._peerExists(peerId)) {
 | 
				
			||||||
            this._refreshPeer(peerId, roomType, roomId);
 | 
					            this._refreshPeer(isCaller, peerId, roomType, roomId);
 | 
				
			||||||
            return;
 | 
					        } else {
 | 
				
			||||||
 | 
					            this.createPeer(isCaller, peerId, roomType, roomId, rtcSupported);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    createPeer(isCaller, peerId, roomType, roomId, rtcSupported) {
 | 
				
			||||||
        if (window.isRtcSupported && rtcSupported) {
 | 
					        if (window.isRtcSupported && rtcSupported) {
 | 
				
			||||||
            this.peers[peerId] = new RTCPeer(this._server, isCaller, peerId, roomType, roomId, this._wsConfig.rtcConfig);
 | 
					            this.peers[peerId] = new RTCPeer(this._server, isCaller, peerId, roomType, roomId, this._wsConfig.rtcConfig);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
| 
						 | 
					@ -1091,7 +1296,7 @@ class PeersManager {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPeerLeft(message) {
 | 
					    _onPeerLeft(message) {
 | 
				
			||||||
        if (this._peerExists(message.peerId) && this._webRtcSupported(message.peerId)) {
 | 
					        if (this._peerExists(message.peerId) && !this._webRtcSupported(message.peerId)) {
 | 
				
			||||||
            console.log('WSPeer left:', message.peerId);
 | 
					            console.log('WSPeer left:', message.peerId);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (message.disconnect === true) {
 | 
					        if (message.disconnect === true) {
 | 
				
			||||||
| 
						 | 
					@ -1136,11 +1341,10 @@ class PeersManager {
 | 
				
			||||||
    _onPeerDisconnected(peerId) {
 | 
					    _onPeerDisconnected(peerId) {
 | 
				
			||||||
        const peer = this.peers[peerId];
 | 
					        const peer = this.peers[peerId];
 | 
				
			||||||
        delete this.peers[peerId];
 | 
					        delete this.peers[peerId];
 | 
				
			||||||
        if (!peer || !peer._conn) return;
 | 
					
 | 
				
			||||||
        if (peer._channel) peer._channel.onclose = null;
 | 
					        if (!peer) return;
 | 
				
			||||||
        peer._conn.close();
 | 
					
 | 
				
			||||||
        peer._busy = false;
 | 
					        peer._closeChannelAndConnection();
 | 
				
			||||||
        peer._roomIds = {};
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onRoomSecretsDeleted(roomSecrets) {
 | 
					    _onRoomSecretsDeleted(roomSecrets) {
 | 
				
			||||||
| 
						 | 
					@ -1268,6 +1472,11 @@ class FileChunker {
 | 
				
			||||||
        this._readChunk();
 | 
					        this._readChunk();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _restartFromOffset(offset) {
 | 
				
			||||||
 | 
					        this._offset = offset;
 | 
				
			||||||
 | 
					        this.nextPartition();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    repeatPartition() {
 | 
					    repeatPartition() {
 | 
				
			||||||
        this._offset -= this._partitionSize;
 | 
					        this._offset -= this._partitionSize;
 | 
				
			||||||
        this.nextPartition();
 | 
					        this.nextPartition();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,7 +16,7 @@ class PeersUI {
 | 
				
			||||||
        this.$shareModeCancelBtn = $$('.shr-panel .cancel-btn');
 | 
					        this.$shareModeCancelBtn = $$('.shr-panel .cancel-btn');
 | 
				
			||||||
        this.$shareModeEditBtn = $$('.shr-panel .edit-btn');
 | 
					        this.$shareModeEditBtn = $$('.shr-panel .edit-btn');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.peers = {};
 | 
					        this.peerUIs = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.shareMode = {};
 | 
					        this.shareMode = {};
 | 
				
			||||||
        this.shareMode.active = false;
 | 
					        this.shareMode.active = false;
 | 
				
			||||||
| 
						 | 
					@ -24,9 +24,9 @@ class PeersUI {
 | 
				
			||||||
        this.shareMode.files = [];
 | 
					        this.shareMode.files = [];
 | 
				
			||||||
        this.shareMode.text = "";
 | 
					        this.shareMode.text = "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Events.on('peer-joined', e => this._onPeerJoined(e.detail));
 | 
					        Events.on('peer-joined', e => this._onPeerJoined(e.detail.peer, e.detail.roomType, e.detail.roomId));
 | 
				
			||||||
        Events.on('peer-added', _ => this._evaluateOverflowingPeers());
 | 
					 | 
				
			||||||
        Events.on('peer-connected', e => this._onPeerConnected(e.detail.peerId, e.detail.connectionHash));
 | 
					        Events.on('peer-connected', e => this._onPeerConnected(e.detail.peerId, e.detail.connectionHash));
 | 
				
			||||||
 | 
					        Events.on('peer-connecting', e => this._onPeerConnecting(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));
 | 
				
			||||||
| 
						 | 
					@ -47,17 +47,17 @@ class PeersUI {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.$shareModeCancelBtn.addEventListener('click', _ => this._deactivateShareMode());
 | 
					        this.$shareModeCancelBtn.addEventListener('click', _ => this._deactivateShareMode());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Events.on('peer-display-name-changed', e => this._onPeerDisplayNameChanged(e));
 | 
					        Events.on('peer-display-name-changed', e => this._onPeerDisplayNameChanged(e.detail.peerId, e.detail.displayName));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Events.on('ws-config', e => this._evaluateRtcSupport(e.detail))
 | 
					        Events.on('ws-config', e => this._evaluateRtcSupport(e.detail))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _evaluateRtcSupport(wsConfig) {
 | 
					    _evaluateRtcSupport(wsConfig) {
 | 
				
			||||||
        if (wsConfig.wsFallback) {
 | 
					        if (wsConfig.wsFallback) {
 | 
				
			||||||
            this.$wsFallbackWarning.hidden = false;
 | 
					            this.$wsFallbackWarning.removeAttribute("hidden");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            this.$wsFallbackWarning.hidden = true;
 | 
					            this.$wsFallbackWarning.setAttribute("hidden", true);
 | 
				
			||||||
            if (!window.isRtcSupported) {
 | 
					            if (!window.isRtcSupported) {
 | 
				
			||||||
                alert(Localization.getTranslation("instructions.webrtc-requirement"));
 | 
					                alert(Localization.getTranslation("instructions.webrtc-requirement"));
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
| 
						 | 
					@ -65,15 +65,17 @@ class PeersUI {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _changePeerDisplayName(peerId, displayName) {
 | 
					    _changePeerDisplayName(peerId, displayName) {
 | 
				
			||||||
        this.peers[peerId].name.displayName = displayName;
 | 
					        const peerUI = this.peerUIs[peerId];
 | 
				
			||||||
        const peerIdNode = $(peerId);
 | 
					
 | 
				
			||||||
        if (peerIdNode && displayName) peerIdNode.querySelector('.name').textContent = displayName;
 | 
					        if (!peerUI) return;
 | 
				
			||||||
        this._redrawPeerRoomTypes(peerId);
 | 
					
 | 
				
			||||||
 | 
					        peerUI._setDisplayName(displayName);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPeerDisplayNameChanged(e) {
 | 
					    _onPeerDisplayNameChanged(peerId, displayName) {
 | 
				
			||||||
        if (!e.detail.displayName) return;
 | 
					        if (!peerId || !displayName) return;
 | 
				
			||||||
        this._changePeerDisplayName(e.detail.peerId, e.detail.displayName);
 | 
					
 | 
				
			||||||
 | 
					        this._changePeerDisplayName(peerId, displayName);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    async _onKeyDown(e) {
 | 
					    async _onKeyDown(e) {
 | 
				
			||||||
| 
						 | 
					@ -89,50 +91,48 @@ class PeersUI {
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPeerJoined(msg) {
 | 
					    _onPeerJoined(peer, roomType, roomId) {
 | 
				
			||||||
        this._joinPeer(msg.peer, msg.roomType, msg.roomId);
 | 
					        this._joinPeer(peer, roomType, roomId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _joinPeer(peer, roomType, roomId) {
 | 
					    _joinPeer(peer, roomType, roomId) {
 | 
				
			||||||
        const existingPeer = this.peers[peer.id];
 | 
					        const existingPeerUI = this.peerUIs[peer.id];
 | 
				
			||||||
        if (existingPeer) {
 | 
					        if (existingPeerUI) {
 | 
				
			||||||
            // peer already exists. Abort but add roomType to GUI
 | 
					            // peerUI already exists. Abort but add roomType to GUI
 | 
				
			||||||
            existingPeer._roomIds[roomType] = roomId;
 | 
					            existingPeerUI._addRoomId(roomType, roomId);
 | 
				
			||||||
            this._redrawPeerRoomTypes(peer.id);
 | 
					 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        peer._isSameBrowser = () => BrowserTabsConnector.peerIsSameBrowser(peer.id);
 | 
					        const peerUI = new PeerUI(peer, roomType, roomId, {
 | 
				
			||||||
        peer._roomIds = {};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        peer._roomIds[roomType] = roomId;
 | 
					 | 
				
			||||||
        this.peers[peer.id] = peer;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    _onPeerConnected(peerId, connectionHash) {
 | 
					 | 
				
			||||||
        if (!this.peers[peerId] || $(peerId)) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const peer = this.peers[peerId];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        new PeerUI(peer, connectionHash, {
 | 
					 | 
				
			||||||
            active: this.shareMode.active,
 | 
					            active: this.shareMode.active,
 | 
				
			||||||
            descriptor: this.shareMode.descriptor,
 | 
					            descriptor: this.shareMode.descriptor,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					        this.peerUIs[peer.id] = peerUI;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _redrawPeerRoomTypes(peerId) {
 | 
					    _onPeerConnected(peerId, connectionHash) {
 | 
				
			||||||
        const peer = this.peers[peerId];
 | 
					        const peerUI = this.peerUIs[peerId];
 | 
				
			||||||
        const peerNode = $(peerId);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!peer || !peerNode) return;
 | 
					        if (!peerUI) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        peerNode.classList.remove('type-ip', 'type-secret', 'type-public-id', 'type-same-browser');
 | 
					        peerUI._peerConnected(true, connectionHash);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (peer._isSameBrowser()) {
 | 
					        this._addPeerUIIfMissing(peerUI);
 | 
				
			||||||
            peerNode.classList.add(`type-same-browser`);
 | 
					    }
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Object.keys(peer._roomIds).forEach(roomType => peerNode.classList.add(`type-${roomType}`));
 | 
					    _addPeerUIIfMissing(peerUI) {
 | 
				
			||||||
 | 
					        if (this.$xPeers.contains(peerUI.$el)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.$xPeers.appendChild(peerUI.$el);
 | 
				
			||||||
 | 
					        this._evaluateOverflowingPeers();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onPeerConnecting(peerId) {
 | 
				
			||||||
 | 
					        const peerUI = this.peerUIs[peerId];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!peerUI) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        peerUI._peerConnected(false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _evaluateOverflowingPeers() {
 | 
					    _evaluateOverflowingPeers() {
 | 
				
			||||||
| 
						 | 
					@ -149,26 +149,31 @@ class PeersUI {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPeerDisconnected(peerId) {
 | 
					    _onPeerDisconnected(peerId) {
 | 
				
			||||||
        const $peer = $(peerId);
 | 
					        const peerUI = this.peerUIs[peerId];
 | 
				
			||||||
        if (!$peer) return;
 | 
					
 | 
				
			||||||
        $peer.remove();
 | 
					        if (!peerUI) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        peerUI._removeDom();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        delete this.peerUIs[peerId];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._evaluateOverflowingPeers();
 | 
					        this._evaluateOverflowingPeers();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onRoomTypeRemoved(peerId, roomType) {
 | 
					    _onRoomTypeRemoved(peerId, roomType) {
 | 
				
			||||||
        const peer = this.peers[peerId];
 | 
					        const peerUI = this.peerUIs[peerId];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!peer) return;
 | 
					        if (!peerUI) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        delete peer._roomIds[roomType];
 | 
					        peerUI._removeRoomId(roomType);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        this._redrawPeerRoomTypes(peerId)
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onSetProgress(progress) {
 | 
					    _onSetProgress(progress) {
 | 
				
			||||||
        const $peer = $(progress.peerId);
 | 
					        const peerUI = this.peerUIs[progress.peerId];
 | 
				
			||||||
        if (!$peer) return;
 | 
					
 | 
				
			||||||
        $peer.ui.setProgress(progress.progress, progress.status)
 | 
					        if (!peerUI) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        peerUI.setProgress(progress.progress, progress.status);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onDrop(e) {
 | 
					    _onDrop(e) {
 | 
				
			||||||
| 
						 | 
					@ -392,35 +397,52 @@ class PeersUI {
 | 
				
			||||||
class PeerUI {
 | 
					class PeerUI {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static _badgeClassNames = ["badge-room-ip", "badge-room-secret", "badge-room-public-id"];
 | 
					    static _badgeClassNames = ["badge-room-ip", "badge-room-secret", "badge-room-public-id"];
 | 
				
			||||||
    static _shareMode = {
 | 
					 | 
				
			||||||
        active: false,
 | 
					 | 
				
			||||||
        descriptor: ""
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(peer, connectionHash, shareMode) {
 | 
					    constructor(peer, roomType, roomId, shareMode = {active: false, descriptor: ""}) {
 | 
				
			||||||
        this.$xInstructions = $$('x-instructions');
 | 
					        this.$xInstructions = $$('x-instructions');
 | 
				
			||||||
        this.$xPeers = $$('x-peers');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._peer = peer;
 | 
					        this._peer = peer;
 | 
				
			||||||
        this._connectionHash =
 | 
					        this._connectionHash = "";
 | 
				
			||||||
            `${connectionHash.substring(0, 4)} ${connectionHash.substring(4, 8)} ${connectionHash.substring(8, 12)} ${connectionHash.substring(12, 16)}`;
 | 
					        this._connected = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // This is needed if the ShareMode is started BEFORE the PeerUI is drawn.
 | 
					        this._roomIds = {}
 | 
				
			||||||
        PeerUI._shareMode = shareMode;
 | 
					        this._roomIds[roomType] = roomId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._shareMode = shareMode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._createCallbacks();
 | 
				
			||||||
        this._initDom();
 | 
					        this._initDom();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.$xPeers.appendChild(this.$el);
 | 
					 | 
				
			||||||
        Events.fire('peer-added');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // ShareMode
 | 
					        // ShareMode
 | 
				
			||||||
        Events.on('share-mode-changed', e => this._onShareModeChanged(e.detail.active, e.detail.descriptor));
 | 
					        Events.on('share-mode-changed', e => this._onShareModeChanged(e.detail.active, e.detail.descriptor));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _initDom() {
 | 
				
			||||||
 | 
					        this.$el = document.createElement('x-peer');
 | 
				
			||||||
 | 
					        this.$el.id = this._peer.id;
 | 
				
			||||||
 | 
					        this.$el.ui = this;
 | 
				
			||||||
 | 
					        this.$el.classList.add('center');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.html();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.$label = this.$el.querySelector('label');
 | 
				
			||||||
 | 
					        this.$input = this.$el.querySelector('input');
 | 
				
			||||||
 | 
					        this.$displayName = this.$el.querySelector('.name');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.updateTypesClassList();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.setStatus("connect");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._evaluateShareMode();
 | 
				
			||||||
 | 
					        this._bindListeners();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _removeDom() {
 | 
				
			||||||
 | 
					        this.$el.remove();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    html() {
 | 
					    html() {
 | 
				
			||||||
        let title= PeerUI._shareMode.active
 | 
					        let title= Localization.getTranslation("peer-ui.click-to-send");
 | 
				
			||||||
            ? Localization.getTranslation("peer-ui.click-to-send-share-mode", null, {descriptor: PeerUI._shareMode.descriptor})
 | 
					 | 
				
			||||||
            : Localization.getTranslation("peer-ui.click-to-send");
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.$el.innerHTML = `
 | 
					        this.$el.innerHTML = `
 | 
				
			||||||
            <label class="column center pointer" title="${title}">
 | 
					            <label class="column center pointer" title="${title}">
 | 
				
			||||||
| 
						 | 
					@ -449,41 +471,37 @@ class PeerUI {
 | 
				
			||||||
        this.$el.querySelector('svg use').setAttribute('xlink:href', this._icon());
 | 
					        this.$el.querySelector('svg use').setAttribute('xlink:href', this._icon());
 | 
				
			||||||
        this.$el.querySelector('.name').textContent = this._displayName();
 | 
					        this.$el.querySelector('.name').textContent = this._displayName();
 | 
				
			||||||
        this.$el.querySelector('.device-name').textContent = this._deviceName();
 | 
					        this.$el.querySelector('.device-name').textContent = this._deviceName();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.$label = this.$el.querySelector('label');
 | 
					 | 
				
			||||||
        this.$input = this.$el.querySelector('input');
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    addTypesToClassList() {
 | 
					    updateTypesClassList() {
 | 
				
			||||||
        if (this._peer._isSameBrowser()) {
 | 
					        // Remove all classes
 | 
				
			||||||
 | 
					        this.$el.classList.remove('type-ip', 'type-secret', 'type-public-id', 'type-same-browser', 'ws-peer');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add classes accordingly
 | 
				
			||||||
 | 
					        Object.keys(this._roomIds).forEach(roomType => this.$el.classList.add(`type-${roomType}`));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (BrowserTabsConnector.peerIsSameBrowser(this._peer.id)) {
 | 
				
			||||||
            this.$el.classList.add(`type-same-browser`);
 | 
					            this.$el.classList.add(`type-same-browser`);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Object.keys(this._peer._roomIds).forEach(roomType => this.$el.classList.add(`type-${roomType}`));
 | 
					        if (!this._peer.rtcSupported || !window.isRtcSupported) {
 | 
				
			||||||
 | 
					            this.$el.classList.add('ws-peer');
 | 
				
			||||||
        if (!this._peer.rtcSupported || !window.isRtcSupported) this.$el.classList.add('ws-peer');
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _initDom() {
 | 
					    _addRoomId(roomType, roomId) {
 | 
				
			||||||
        this.$el = document.createElement('x-peer');
 | 
					        this._roomIds[roomType] = roomId;
 | 
				
			||||||
        this.$el.id = this._peer.id;
 | 
					        this.updateTypesClassList();
 | 
				
			||||||
        this.$el.ui = this;
 | 
					    }
 | 
				
			||||||
        this.$el.classList.add('center');
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.addTypesToClassList();
 | 
					    _removeRoomId(roomType) {
 | 
				
			||||||
 | 
					        delete this._roomIds[roomType];
 | 
				
			||||||
        this.html();
 | 
					        this.updateTypesClassList();
 | 
				
			||||||
 | 
					 | 
				
			||||||
        this._createCallbacks();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this._evaluateShareMode();
 | 
					 | 
				
			||||||
        this._bindListeners();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onShareModeChanged(active = false, descriptor = "") {
 | 
					    _onShareModeChanged(active = false, descriptor = "") {
 | 
				
			||||||
        // This is needed if the ShareMode is started AFTER the PeerUI is drawn.
 | 
					        this._shareMode.active = active;
 | 
				
			||||||
        PeerUI._shareMode.active = active;
 | 
					        this._shareMode.descriptor = descriptor;
 | 
				
			||||||
        PeerUI._shareMode.descriptor = descriptor;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._evaluateShareMode();
 | 
					        this._evaluateShareMode();
 | 
				
			||||||
        this._bindListeners();
 | 
					        this._bindListeners();
 | 
				
			||||||
| 
						 | 
					@ -491,12 +509,12 @@ class PeerUI {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _evaluateShareMode() {
 | 
					    _evaluateShareMode() {
 | 
				
			||||||
        let title;
 | 
					        let title;
 | 
				
			||||||
        if (!PeerUI._shareMode.active) {
 | 
					        if (!this._shareMode.active) {
 | 
				
			||||||
            title = Localization.getTranslation("peer-ui.click-to-send");
 | 
					            title = Localization.getTranslation("peer-ui.click-to-send");
 | 
				
			||||||
            this.$input.removeAttribute('disabled');
 | 
					            this.$input.removeAttribute('disabled');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            title =  Localization.getTranslation("peer-ui.click-to-send-share-mode", null, {descriptor: PeerUI._shareMode.descriptor});
 | 
					            title =  Localization.getTranslation("peer-ui.click-to-send-share-mode", null, {descriptor: this._shareMode.descriptor});
 | 
				
			||||||
            this.$input.setAttribute('disabled', true);
 | 
					            this.$input.setAttribute('disabled', true);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        this.$label.setAttribute('title', title);
 | 
					        this.$label.setAttribute('title', title);
 | 
				
			||||||
| 
						 | 
					@ -517,7 +535,7 @@ class PeerUI {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _bindListeners() {
 | 
					    _bindListeners() {
 | 
				
			||||||
        if(!PeerUI._shareMode.active) {
 | 
					        if(!this._shareMode.active) {
 | 
				
			||||||
            // Remove Events Share mode
 | 
					            // Remove Events Share mode
 | 
				
			||||||
            this.$el.removeEventListener('pointerdown', this._callbackPointerDown);
 | 
					            this.$el.removeEventListener('pointerdown', this._callbackPointerDown);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -559,6 +577,37 @@ class PeerUI {
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _peerConnected(connected = true, connectionHash = "") {
 | 
				
			||||||
 | 
					        if (connected) {
 | 
				
			||||||
 | 
					            this._connected = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // on reconnect
 | 
				
			||||||
 | 
					            this.setStatus(this.oldStatus);
 | 
				
			||||||
 | 
					            this.oldStatus = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this._connectionHash = connectionHash;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            this._connected = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (!this.oldStatus && this.currentStatus !== "connect") {
 | 
				
			||||||
 | 
					                // save old status when reconnecting
 | 
				
			||||||
 | 
					                this.oldStatus = this.currentStatus;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.setStatus("connect");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this._connectionHash = "";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getConnectionHashWithSpaces()  {
 | 
				
			||||||
 | 
					        if (this._connectionHash.length !== 16) {
 | 
				
			||||||
 | 
					            return ""
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return `${this._connectionHash.substring(0, 4)} ${this._connectionHash.substring(4, 8)} ${this._connectionHash.substring(8, 12)} ${this._connectionHash.substring(12, 16)}`;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _displayName() {
 | 
					    _displayName() {
 | 
				
			||||||
        return this._peer.name.displayName;
 | 
					        return this._peer.name.displayName;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -567,13 +616,26 @@ class PeerUI {
 | 
				
			||||||
        return this._peer.name.deviceName;
 | 
					        return this._peer.name.deviceName;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _setDisplayName(displayName) {
 | 
				
			||||||
 | 
					        this._peer.name.displayName = displayName;
 | 
				
			||||||
 | 
					        this.$displayName.textContent = displayName;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _roomTypes() {
 | 
				
			||||||
 | 
					        return Object.keys(this._roomIds);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _badgeClassName() {
 | 
					    _badgeClassName() {
 | 
				
			||||||
        const roomTypes = Object.keys(this._peer._roomIds);
 | 
					        const roomTypes = this._roomTypes();
 | 
				
			||||||
        return roomTypes.includes('secret')
 | 
					        if (roomTypes.includes('secret')) {
 | 
				
			||||||
            ? 'badge-room-secret'
 | 
					            return 'badge-room-secret';
 | 
				
			||||||
            : roomTypes.includes('ip')
 | 
					        }
 | 
				
			||||||
                ? 'badge-room-ip'
 | 
					        else if (roomTypes.includes('ip')) {
 | 
				
			||||||
                : 'badge-room-public-id';
 | 
					            return 'badge-room-ip';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            return 'badge-room-public-id';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _icon() {
 | 
					    _icon() {
 | 
				
			||||||
| 
						 | 
					@ -590,6 +652,7 @@ class PeerUI {
 | 
				
			||||||
    _onFilesSelected(e) {
 | 
					    _onFilesSelected(e) {
 | 
				
			||||||
        const $input = e.target;
 | 
					        const $input = e.target;
 | 
				
			||||||
        const files = $input.files;
 | 
					        const files = $input.files;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Events.fire('files-selected', {
 | 
					        Events.fire('files-selected', {
 | 
				
			||||||
            files: files,
 | 
					            files: files,
 | 
				
			||||||
            to: this._peer.id
 | 
					            to: this._peer.id
 | 
				
			||||||
| 
						 | 
					@ -599,40 +662,54 @@ class PeerUI {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setProgress(progress, status) {
 | 
					    setProgress(progress, status) {
 | 
				
			||||||
        const $progress = this.$el.querySelector('.progress');
 | 
					        const $progress = this.$el.querySelector('.progress');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (0.5 < progress && progress < 1) {
 | 
					        if (0.5 < progress && progress < 1) {
 | 
				
			||||||
            $progress.classList.add('over50');
 | 
					            $progress.classList.add('over50');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            $progress.classList.remove('over50');
 | 
					            $progress.classList.remove('over50');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (progress < 1) {
 | 
					 | 
				
			||||||
            if (status !== this.currentStatus) {
 | 
					 | 
				
			||||||
                let statusName = {
 | 
					 | 
				
			||||||
                    "prepare": Localization.getTranslation("peer-ui.preparing"),
 | 
					 | 
				
			||||||
                    "transfer": Localization.getTranslation("peer-ui.transferring"),
 | 
					 | 
				
			||||||
                    "process": Localization.getTranslation("peer-ui.processing"),
 | 
					 | 
				
			||||||
                    "wait": Localization.getTranslation("peer-ui.waiting")
 | 
					 | 
				
			||||||
                }[status];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                this.$el.setAttribute('status', status);
 | 
					        if (progress === 1) {
 | 
				
			||||||
                this.$el.querySelector('.status').innerText = statusName;
 | 
					 | 
				
			||||||
                this.currentStatus = status;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        else {
 | 
					 | 
				
			||||||
            this.$el.removeAttribute('status');
 | 
					 | 
				
			||||||
            this.$el.querySelector('.status').innerHTML = '';
 | 
					 | 
				
			||||||
            progress = 0;
 | 
					            progress = 0;
 | 
				
			||||||
            this.currentStatus = null;
 | 
					            status = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.setStatus(status);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const degrees = `rotate(${360 * progress}deg)`;
 | 
					        const degrees = `rotate(${360 * progress}deg)`;
 | 
				
			||||||
        $progress.style.setProperty('--progress', degrees);
 | 
					        $progress.style.setProperty('--progress', degrees);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onDrop(e) {
 | 
					    setStatus(status) {
 | 
				
			||||||
        e.preventDefault();
 | 
					        if (!status) {
 | 
				
			||||||
 | 
					            this.$el.removeAttribute('status');
 | 
				
			||||||
 | 
					            this.$el.querySelector('.status').innerHTML = '';
 | 
				
			||||||
 | 
					            this.currentStatus = null;
 | 
				
			||||||
 | 
					            NoSleepUI.disableIfPeersIdle();
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (PeerUI._shareMode.active || Dialog.anyDialogShown()) return;
 | 
					        if (status === this.currentStatus) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let statusName = {
 | 
				
			||||||
 | 
					            "connect": Localization.getTranslation("peer-ui.connecting"),
 | 
				
			||||||
 | 
					            "prepare": Localization.getTranslation("peer-ui.preparing"),
 | 
				
			||||||
 | 
					            "transfer": Localization.getTranslation("peer-ui.transferring"),
 | 
				
			||||||
 | 
					            "receive": Localization.getTranslation("peer-ui.receiving"),
 | 
				
			||||||
 | 
					            "process": Localization.getTranslation("peer-ui.processing"),
 | 
				
			||||||
 | 
					            "wait": Localization.getTranslation("peer-ui.waiting")
 | 
				
			||||||
 | 
					        }[status];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.$el.setAttribute('status', status);
 | 
				
			||||||
 | 
					        this.$el.querySelector('.status').innerText = statusName;
 | 
				
			||||||
 | 
					        this.currentStatus = status;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _onDrop(e) {
 | 
				
			||||||
 | 
					        if (this._shareMode.active || Dialog.anyDialogShown()) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        e.preventDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (e.dataTransfer.files.length > 0) {
 | 
					        if (e.dataTransfer.files.length > 0) {
 | 
				
			||||||
            Events.fire('files-selected', {
 | 
					            Events.fire('files-selected', {
 | 
				
			||||||
| 
						 | 
					@ -1315,8 +1392,8 @@ class PairDeviceDialog extends Dialog {
 | 
				
			||||||
        Events.on('ws-disconnected', _ => this.hide());
 | 
					        Events.on('ws-disconnected', _ => this.hide());
 | 
				
			||||||
        Events.on('pair-device-initiated', e => this._onPairDeviceInitiated(e.detail));
 | 
					        Events.on('pair-device-initiated', e => this._onPairDeviceInitiated(e.detail));
 | 
				
			||||||
        Events.on('pair-device-joined', e => this._onPairDeviceJoined(e.detail.peerId, e.detail.roomSecret));
 | 
					        Events.on('pair-device-joined', e => this._onPairDeviceJoined(e.detail.peerId, e.detail.roomSecret));
 | 
				
			||||||
        Events.on('peers', e => this._onPeers(e.detail));
 | 
					        Events.on('peers', e => this._onPeers(e.detail.peers, e.detail.roomType, e.detail.roomId));
 | 
				
			||||||
        Events.on('peer-joined', e => this._onPeerJoined(e.detail));
 | 
					        Events.on('peer-joined', e => this._onPeerJoined(e.detail.peer, e.detail.roomType, e.detail.roomId));
 | 
				
			||||||
        Events.on('pair-device-join-key-invalid', _ => this._onPublicRoomJoinKeyInvalid());
 | 
					        Events.on('pair-device-join-key-invalid', _ => this._onPublicRoomJoinKeyInvalid());
 | 
				
			||||||
        Events.on('pair-device-canceled', e => this._onPairDeviceCanceled(e.detail));
 | 
					        Events.on('pair-device-canceled', e => this._onPairDeviceCanceled(e.detail));
 | 
				
			||||||
        Events.on('evaluate-number-room-secrets', _ => this._evaluateNumberRoomSecrets())
 | 
					        Events.on('evaluate-number-room-secrets', _ => this._evaluateNumberRoomSecrets())
 | 
				
			||||||
| 
						 | 
					@ -1426,18 +1503,19 @@ class PairDeviceDialog extends Dialog {
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPeers(message) {
 | 
					    _onPeers(peers, roomType, roomId) {
 | 
				
			||||||
        message.peers.forEach(messagePeer => {
 | 
					        peers.forEach(messagePeer => {
 | 
				
			||||||
            this._evaluateJoinedPeer(messagePeer.id, message.roomType, message.roomId);
 | 
					            this._evaluateJoinedPeer(messagePeer, roomType, roomId);
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPeerJoined(message) {
 | 
					    _onPeerJoined(peer, roomType, roomId) {
 | 
				
			||||||
        this._evaluateJoinedPeer(message.peer.id, message.roomType, message.roomId);
 | 
					        this._evaluateJoinedPeer(peer, roomType, roomId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _evaluateJoinedPeer(peerId, roomType, roomId) {
 | 
					    _evaluateJoinedPeer(peer, roomType, roomId) {
 | 
				
			||||||
        const noPairPeerSaved = !Object.keys(this.pairPeer);
 | 
					        const noPairPeerSaved = !Object.keys(this.pairPeer);
 | 
				
			||||||
 | 
					        const peerId = peer.id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!peerId || !roomType || !roomId || noPairPeerSaved) return;
 | 
					        if (!peerId || !roomType || !roomId || noPairPeerSaved) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1447,13 +1525,13 @@ class PairDeviceDialog extends Dialog {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!samePeerId || !sameRoomSecret || !typeIsSecret) return;
 | 
					        if (!samePeerId || !sameRoomSecret || !typeIsSecret) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._onPairPeerJoined(peerId, roomId);
 | 
					        this._onPairPeerJoined(peer, roomId);
 | 
				
			||||||
        this.pairPeer = {};
 | 
					        this.pairPeer = {};
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPairPeerJoined(peerId, roomSecret) {
 | 
					    _onPairPeerJoined(peer, roomSecret) {
 | 
				
			||||||
        // if devices are paired that are already connected we must save the names at this point
 | 
					        // if devices are paired that are already connected we must save the names at this point
 | 
				
			||||||
        const $peer = $(peerId);
 | 
					        const $peer = $(peer.id);
 | 
				
			||||||
        let displayName, deviceName;
 | 
					        let displayName, deviceName;
 | 
				
			||||||
        if ($peer) {
 | 
					        if ($peer) {
 | 
				
			||||||
            displayName = $peer.ui._peer.name.displayName;
 | 
					            displayName = $peer.ui._peer.name.displayName;
 | 
				
			||||||
| 
						 | 
					@ -1531,11 +1609,11 @@ class EditPairedDevicesDialog extends Dialog {
 | 
				
			||||||
        super('edit-paired-devices-dialog');
 | 
					        super('edit-paired-devices-dialog');
 | 
				
			||||||
        this.$pairedDevicesWrapper = this.$el.querySelector('.paired-devices-wrapper');
 | 
					        this.$pairedDevicesWrapper = this.$el.querySelector('.paired-devices-wrapper');
 | 
				
			||||||
        this.$footerBadgePairedDevices = $$('.discovery-wrapper .badge-room-secret');
 | 
					        this.$footerBadgePairedDevices = $$('.discovery-wrapper .badge-room-secret');
 | 
				
			||||||
 | 
					        this.$editPairedDevices = $('edit-paired-devices');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $('edit-paired-devices').addEventListener('click', _ => this._onEditPairedDevices());
 | 
					        this.$editPairedDevices.addEventListener('click', _ => this._onEditPairedDevices());
 | 
				
			||||||
        this.$footerBadgePairedDevices.addEventListener('click', _ => this._onEditPairedDevices());
 | 
					        this.$footerBadgePairedDevices.addEventListener('click', _ => this._onEditPairedDevices());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        Events.on('peer-display-name-changed', e => this._onPeerDisplayNameChanged(e));
 | 
					 | 
				
			||||||
        Events.on('keydown', e => this._onKeyDown(e));
 | 
					        Events.on('keydown', e => this._onKeyDown(e));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1641,23 +1719,6 @@ class EditPairedDevicesDialog extends Dialog {
 | 
				
			||||||
                    })
 | 
					                    })
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    _onPeerDisplayNameChanged(e) {
 | 
					 | 
				
			||||||
        const peerId = e.detail.peerId;
 | 
					 | 
				
			||||||
        const peerNode = $(peerId);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!peerNode) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const peer = peerNode.ui._peer;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (!peer || !peer._roomIds["secret"]) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        PersistentStorage
 | 
					 | 
				
			||||||
            .updateRoomSecretNames(peer._roomIds["secret"], peer.name.displayName, peer.name.deviceName)
 | 
					 | 
				
			||||||
            .then(roomSecretEntry => {
 | 
					 | 
				
			||||||
                console.log(`Successfully updated DisplayName and DeviceName for roomSecretEntry ${roomSecretEntry.key}`);
 | 
					 | 
				
			||||||
            })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PublicRoomDialog extends Dialog {
 | 
					class PublicRoomDialog extends Dialog {
 | 
				
			||||||
| 
						 | 
					@ -1692,7 +1753,7 @@ class PublicRoomDialog extends Dialog {
 | 
				
			||||||
        Events.on('keydown', e => this._onKeyDown(e));
 | 
					        Events.on('keydown', e => this._onKeyDown(e));
 | 
				
			||||||
        Events.on('public-room-created', e => this._onPublicRoomCreated(e.detail));
 | 
					        Events.on('public-room-created', e => this._onPublicRoomCreated(e.detail));
 | 
				
			||||||
        Events.on('peers', e => this._onPeers(e.detail));
 | 
					        Events.on('peers', e => this._onPeers(e.detail));
 | 
				
			||||||
        Events.on('peer-joined', e => this._onPeerJoined(e.detail));
 | 
					        Events.on('peer-joined', e => this._onPeerJoined(e.detail.peer, e.detail.roomId));
 | 
				
			||||||
        Events.on('public-room-id-invalid', e => this._onPublicRoomIdInvalid(e.detail));
 | 
					        Events.on('public-room-id-invalid', e => this._onPublicRoomIdInvalid(e.detail));
 | 
				
			||||||
        Events.on('public-room-left', _ => this._onPublicRoomLeft());
 | 
					        Events.on('public-room-left', _ => this._onPublicRoomLeft());
 | 
				
			||||||
        this.$el.addEventListener('paste', e => this._onPaste(e));
 | 
					        this.$el.addEventListener('paste', e => this._onPaste(e));
 | 
				
			||||||
| 
						 | 
					@ -1828,15 +1889,15 @@ class PublicRoomDialog extends Dialog {
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPeerJoined(message) {
 | 
					    _onPeerJoined(peer, roomId) {
 | 
				
			||||||
        this._evaluateJoinedPeer(message.peer.id, message.roomId);
 | 
					        this._evaluateJoinedPeer(peer.id, roomId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _evaluateJoinedPeer(peerId, roomId) {
 | 
					    _evaluateJoinedPeer(peerId, roomId) {
 | 
				
			||||||
        const isInitiatedRoomId = roomId === this.roomId;
 | 
					        const isInitiatedRoomId = roomId === this.roomId;
 | 
				
			||||||
        const isJoinedRoomId = roomId === this.roomIdJoin;
 | 
					        const isJoinedRoomId = roomId === this.roomIdJoin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (!peerId || !roomId || !(isInitiatedRoomId || isJoinedRoomId)) return;
 | 
					        if (!peerId || !roomId || (!isInitiatedRoomId && !isJoinedRoomId)) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.hide();
 | 
					        this.hide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2624,11 +2685,12 @@ class NoSleepUI {
 | 
				
			||||||
    static enable() {
 | 
					    static enable() {
 | 
				
			||||||
        if (!this._interval) {
 | 
					        if (!this._interval) {
 | 
				
			||||||
            NoSleepUI._nosleep.enable();
 | 
					            NoSleepUI._nosleep.enable();
 | 
				
			||||||
            NoSleepUI._interval = setInterval(() => NoSleepUI.disable(), 10000);
 | 
					            // Disable after 10s if all peers are idle
 | 
				
			||||||
 | 
					            NoSleepUI._interval = setInterval(() => NoSleepUI.disableIfPeersIdle(), 10000);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static disable() {
 | 
					    static disableIfPeersIdle() {
 | 
				
			||||||
        if ($$('x-peer[status]') === null) {
 | 
					        if ($$('x-peer[status]') === null) {
 | 
				
			||||||
            clearInterval(NoSleepUI._interval);
 | 
					            clearInterval(NoSleepUI._interval);
 | 
				
			||||||
            NoSleepUI._nosleep.disable();
 | 
					            NoSleepUI._nosleep.disable();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue