Easy serverless swarms of WebRTC peers over WebTorrent
Connect peers together based on a shared topic and send direct or broadcast messages using a gossip protocol.
- Partial mesh network
- Automatic peer rebalancing
- Self-healing
- Logically unlimited peers per mesh
Works in both node and the browser!
Due to an unresolvble issue with the node-wrtc library (inexplicable segmentation faults), the node instances are now headless instances of a browser. Modifications to the API code are done in
examples\server\public\index.html
.
The current version has introduced a number of improvements as well as changes to usage. An update to API documentation is forthcoming.
npm i easypeers
Run a local node peer
> npm start
This creates a an express server which serves up the files in examples/server/public
. The instance also acts as a peer on the network.
Use the terminal to send messages and recieve messages between peers.
Once a node peer is running you may connect to it in the browser with http://localhost:3000
.
Alternatively, you may create a non-peer node instance that your browser can talk to on port 3000 by using npm run serve
.
Note, if you are running a node peer already, the instance will crash because port 3000 will already be in use on that node peer instance.
Then, use the browser developer tools console to send messages: easypeers.send('your message')
Alternatively, you may also add the CDN script tag to your html file, which works without the need to host on a server.
<script src='https://cdn.jsdelivr.net/gh/draeder/easypeers/dist/easypeers.dist.js'></script>
A partial mesh helps minimize peer connections per peer. This reduces load.
Configuring the opts.maxPeers
value limits the number of peer connections per peer instance. Depending on your usecase, opts.maxPeers = 6
appears to keep the network in tact through automatic peer rebalancing and network self-healing.
A gossip protocol is needed in partial mesh networks for peers to reach other peers they are not directly connected to.
Easypeers does this by having each peer route the message to all peers it knows about. It performs message deduplication by taking a sha1 hash of the message itself plus a random number which becomes the message ID. It further deduplicates messages by adding which peer IDs have already received the message to the message. In this way, peers gossip the message to their own known peers (except those that already recieved it), ultimately reaching full network saturation.
Object ish messages are tricky because of using puppeteer
To send a message that you want to later be serialized as a parsable object, you will need to wrap the object with backticks like
`[]`
Then remove the backticks on the receiving peer(s). From there you may use JSON.parse()
.
Direct messaging is now fully functional and uses peer ID hash "closeness" to create a shortest path through the partial mesh.
Broadcast messaging also now works with shortest path routing. By adjusting the coverage ratio, it is possible to have full mesh or partial mesh, and even what amounts to token ring networking.
Easypeers is not secure in its current revision
As it is now, any peer can potentially both see and alter any message, including in ways that cause network flooding, effectively DDoS'ing the entire mesh. This is under review.
If you use this library, it is important to understand that it is experimental and currently designed for use as a raw protocol. You might consider applying your own security/encryption, or submitting a PR to help with Easypeers.
Easypeers now uses Zero Knowledge Proof for swarm identification, sender authenticity verification and message integrity. If proof fails at any state of message propagation on any peer, the peer will cease propagating the message.
The native
node-webrtc
library used by webtorrent and simple-peer may cause segmentation fault errors. Check out the nodepeer.js example inexamples/nodepeer.js
for a workaround.
const Easypeers = require('easypeers')
const easypeers = new Easypeers('Some unique topic', {
maxPeers: 6,
coverage: 0.33,
bitLength: 64,
tracker: 'ws://localhost:8000',
debug: false,
})
easypeers.on('message', data => {
if(!data) return
console.log(data.message.toString().trim())
// console.log(JSON.stringify(data))
// console.log(Object.keys(data.has).length)
// if(easypeers.isValidJSON(data.message)) {
// let dataObj = JSON.parse(data.message)
// console.log(dataObj)
// }
})
easypeers.once('connect', peer => {
// Do something with connect events like:
console.log('Peer connected!', peer, '\r\nWires:', easypeers.wireCount)
console.log("Swarm id: " + easypeers.identifier)
console.log('My address: ' + easypeers.address)
console.log('Connected to Easypeers')
})
easypeers.on('disconnect', peer => {
// Do something with disconnect events like:
// console.log('Peer disconnected!', peer)
})
<script src='https://cdn.jsdelivr.net/gh/draeder/easypeers/dist/easypeers.dist.js'></script>
<script>
const easypeers = new Easypeers('Some unique topic', {
maxPeers: 6,
coverage: 0.33,
bitLength: 64,
tracker: 'ws://localhost:8000',
debug: false,
})
easypeers.on('message', data => {
if(!data) return
console.log(data.message.toString().trim())
// console.log(JSON.stringify(data))
// console.log(Object.keys(data.has).length)
// if(easypeers.isValidJSON(data.message)) {
// let dataObj = JSON.parse(data.message)
// console.log(dataObj)
// }
})
easypeers.once('connect', peer => {
// Do something with connect events like:
console.log('Peer connected!', peer, '\r\nWires:', easypeers.wireCount)
console.log("Swarm id: " + easypeers.identifier)
console.log('My address: ' + easypeers.address)
console.log('Connected to Easypeers')
})
easypeers.on('disconnect', peer => {
// Do something with disconnect events like:
// console.log('Peer disconnected!', peer)
})
</script>
Send message to all peers in the mesh with hearest address routing
Send direct message to destination address address with nearest address routing
Returns the peer address of every newly connected peer
Returns the peer address of only the first connected peer, but peers will continue to connect/rebalance
Stops listening for new peer events, but peers will continue to connect/rebalance
Returns new messages from peers
Returns a message only once, then stops listening for new messages
Stops listening for new messages
Set or return the configured swarm identifier. This must be a sha1 hash and is created by default from the passed in topic string
Set or return the configured peer ID. This must be a sha1 hash and is created by default
Set or return the configured maxPeers. The default is 6.
Set or return the reannouce timeout in milliseconds. The default is 30 * 1000 (30 seconds).