From 2d1815517848f234b1724f217cbdfa1f9942ad8c Mon Sep 17 00:00:00 2001 From: lazorfuzz <leontosy@gmail.com> Date: Thu, 18 Oct 2018 18:33:51 -0700 Subject: [PATCH] Fix reconnection when dropped below minPeers --- README.md | 2 +- src/PeerGraph.js | 3 +++ src/PeerOptimizer.js | 24 ++++++++++++-------- src/liowebrtc.js | 52 ++++++++++++++++++++++++-------------------- src/peer.js | 3 --- 5 files changed, 47 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index fa1b385..6892133 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ const webrtc = new LioWebRTC({ ``` ### Partial mesh network -Peers only form direct connections with a maximum of maxPeers and a minimum of minPeers. shout()ing still works because peers wil re-propagate messages to other peers. +Peers only form direct connections with a maximum of maxPeers and a minimum of minPeers. shout()ing still works because peers wil re-propagate messages to other peers. Note: partial mesh networks only work if you're only using data channels. ```js const webrtc = new LioWebRTC({ dataOnly: true, diff --git a/src/PeerGraph.js b/src/PeerGraph.js index 470f7b4..7523538 100644 --- a/src/PeerGraph.js +++ b/src/PeerGraph.js @@ -69,6 +69,9 @@ export default class PeerGraph { } deleteEdge(edge) { + if (!edge) { + return; + } if (this.edges[edge.getId()]) { delete this.edges[edge.getId()]; } diff --git a/src/PeerOptimizer.js b/src/PeerOptimizer.js index 81b7db6..936c68f 100644 --- a/src/PeerOptimizer.js +++ b/src/PeerOptimizer.js @@ -13,9 +13,6 @@ export function addConnection(node1Id, node2Id, latency = 0) { const nodeA = Graph.getNodeById(node1Id) || new PeerNode(node1Id); const nodeB = Graph.getNodeById(node2Id) || new PeerNode(node2Id); const edgeAB = new Edge(nodeA, nodeB, latency); - console.log('ADDED CONNECTION', node1Id, node2Id, latency); - console.log(Graph.nodes); - console.log(Graph.edges); return Graph.addEdge(edgeAB); } @@ -25,6 +22,21 @@ export function removeConnection(node1Id, node2Id) { if (nodeA && nodeB) Graph.deleteEdge(Graph.findEdge(nodeA, nodeB)); } +export function getNeighbors(nodeId) { + const node = Graph.getNodeById(nodeId); + const neighbors = node.getNeighbors(); + return neighbors.map(n => n.getId()); +} + +export function isNeighbor(node1Id, node2Id) { + const nodeA = Graph.getNodeById(node1Id) || new PeerNode(node1Id); + const nodeB = Graph.getNodeById(node2Id) || new PeerNode(node2Id); + if (nodeA.hasNeighbor(nodeB)) { + return true; + } + return false; +} + export function getPeerLatencies(nodeId) { const node = Graph.findNodeById(nodeId); if (node) { @@ -39,12 +51,6 @@ export function getPeerLatencies(nodeId) { } } -export function getConnectedPeers(nodeId) { - const node = Graph.getNodeById(nodeId); - const neighbors = node.getNeighbors(); - return neighbors.map(n => n.getId()); -} - export function average(vals) { const total = vals.reduce((sum, val) => val + sum); return total / vals.length; diff --git a/src/liowebrtc.js b/src/liowebrtc.js index aeef1b8..3ebac7f 100644 --- a/src/liowebrtc.js +++ b/src/liowebrtc.js @@ -4,7 +4,7 @@ import mockconsole from 'mockconsole'; import WebRTC from './webrtc'; import webrtcSupport from './webrtcsupport'; import SocketIoConnection from './socketioconnection'; -import { Graph, addNode, addConnection, getConnectedPeers, getDroppablePeers } from './PeerOptimizer'; +import { Graph, addNode, addConnection, removeConnection, getNeighbors, isNeighbor, getDroppablePeers } from './PeerOptimizer'; import { inheritedMethods, defaultConfig, defaultChannel } from './constants'; class LioWebRTC extends WildEmitter { @@ -70,7 +70,7 @@ class LioWebRTC extends WildEmitter { }); // if (!peer) peer = peers[0]; // fallback for old protocol versions } - if (this.config.network.maxPeers > 0 && totalPeers >= this.config.network.maxPeers) { + if (this.config.dataOnly && this.config.network.maxPeers > 0 && totalPeers >= this.config.network.maxPeers) { return; } if (!peer) { @@ -168,6 +168,16 @@ class LioWebRTC extends WildEmitter { self.webrtc.sendToAll('mute', { name: 'video' }); }); + self.on('removedPeer', (peer) => { + if (peer.id) { + removeConnection(this.id, peer.id); + } + + if (this.config.dataOnly && this.config.network.maxPeers > 0 && getNeighbors(this.id).length < this.config.network.minPeers) { + this.connectToRandomPeer(); + } + }); + this.webrtc.on('channelMessage', (peer, label, data) => { if (data.payload._id && this.peerDataCache[data.payload._id]) { return; @@ -251,7 +261,6 @@ class LioWebRTC extends WildEmitter { } sendPing(peer, peerId, firstPing = false, channel = defaultChannel) { - console.log('SENDING PING', peer); const self = this; if (firstPing) peer.start(); setTimeout(() => { @@ -260,28 +269,24 @@ class LioWebRTC extends WildEmitter { if (firstPing) this.emit('createdPeer', peer); } else { // The channel is closed, remove the peer - console.log('removing peer, ping failed', peerId); + // console.log('removing peer, ping failed', peerId); self.unconnectivePeers[peerId] = true; peer.end(); - this.getClients((err, clients) => { - console.log('CLIENT RESULTS', clients); - const ids = Object.keys(clients).filter((c) => { - if (self.unconnectivePeers[c] === true || c === this.id) { - return false; - } - return true; - }); - console.log('IDS', ids, self.unconnectivePeers); - if (!ids.length) { - return; - } - const randId = ids[Math.floor(Math.random() * ids.length)]; - this.connectToPeer(randId, clients[randId]); - }); + this.connectToRandomPeer(); } }, 1000); } + connectToRandomPeer() { + this.getClients((err, clients) => { + const ids = Object.keys(clients).filter(c => !(this.unconnectivePeers[c] === true || c === this.id || isNeighbor(this.id, c))); + if (ids.length) { + const randId = ids[Math.floor(Math.random() * ids.length)]; + this.connectToPeer(randId, clients[randId]); + } + }); + } + sendConnections(peer, channel = defaultChannel) { if (peer.sendDirectly('_connections', this.getPeers().map((p) => { const edge = Graph.findEdge(this.id, p.id); @@ -382,15 +387,16 @@ class LioWebRTC extends WildEmitter { let peer; this.roomCount = Object.keys(roomDescription.clients).length; - console.log(roomDescription); + // console.log(roomDescription); this.id = roomDescription.you; + addNode(this.id); this.unconnectivePeers[this.id] = true; for (id of Object.keys(roomDescription.clients).reverse().filter(item => item !== this.id)) { client = roomDescription.clients[id]; for (type in client) { if (client[type]) { const peerCount = this.webrtc.getPeers().length; - if (this.config.network.maxPeers > 0 && (peerCount >= this.config.network.minPeers || peerCount >= this.config.network.maxPeers)) { + if (this.config.dataOnly && this.config.network.maxPeers > 0 && (peerCount >= this.config.network.minPeers || peerCount >= this.config.network.maxPeers)) { break; } peer = self.webrtc.createPeer({ @@ -460,7 +466,6 @@ class LioWebRTC extends WildEmitter { } connectToPeer(peerId, client) { - console.log('CONNECTING TO', peerId); let type; let peer; for (type in client) { @@ -470,7 +475,7 @@ class LioWebRTC extends WildEmitter { break; } peer = this.webrtc.createPeer({ - peerId, + id: peerId, type, enableDataChannels: this.config.enableDataChannels && type !== 'screen', receiveMedia: { @@ -478,7 +483,6 @@ class LioWebRTC extends WildEmitter { offerToReceiveVideo: !this.config.dataOnly && this.config.receiveMedia.offerToReceiveVideo ? 1 : 0, }, }); - console.log('ABOUT TO SEND PING', peer); this.sendPing(peer, peerId, true); } } diff --git a/src/peer.js b/src/peer.js index eb07b47..1f04f1d 100644 --- a/src/peer.js +++ b/src/peer.js @@ -2,7 +2,6 @@ import PeerConnection from 'rtcpeerconnection'; import WildEmitter from 'wildemitter'; import FileTransfer from 'filetransfer'; import webrtcSupport from './webrtcsupport'; -import { removeConnection } from './PeerOptimizer'; function isAllTracksEnded(stream) { let isAllTracksEnded = true; @@ -63,7 +62,6 @@ class Peer extends WildEmitter { case 'closed': this.handleStreamRemoved(false); self.parent.emit('removedPeer', self); - removeConnection(self.parent.id, this.id); break; default: break; @@ -192,7 +190,6 @@ class Peer extends WildEmitter { // if we don't have one by this label, create it channel = this.channels[name] = this.pc.createDataChannel(name, opts); this._observeDataChannel(channel); - console.log('CHANNEL', channel); return channel; } -- GitLab