refactor: examples/discovery-mechanisms (#498)

* refactor: examples-discovery-mechanisms

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: suggestion interval

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: add peer connected event

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
This commit is contained in:
Vasco Santos 2020-01-06 18:01:28 +01:00 committed by Jacob Heun
parent ba4681b312
commit efc96c2f19
3 changed files with 123 additions and 181 deletions

View File

@ -1,14 +1,11 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
'use strict' 'use strict'
const libp2p = require('../../') const Libp2p = require('../../')
const TCP = require('libp2p-tcp') const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex') const Mplex = require('libp2p-mplex')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info')
const Bootstrap = require('libp2p-bootstrap') const Bootstrap = require('libp2p-bootstrap')
const waterfall = require('async/waterfall')
const defaultsDeep = require('@nodeutils/defaults-deep')
// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-nodejs.json // Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-nodejs.json
const bootstrapers = [ const bootstrapers = [
@ -23,51 +20,35 @@ const bootstrapers = [
'/ip4/104.236.151.122/tcp/4001/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx' '/ip4/104.236.151.122/tcp/4001/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx'
] ]
class MyBundle extends libp2p { ;(async () => {
constructor (_options) { const node = await Libp2p.create({
const defaults = { modules: {
modules: { transport: [TCP],
transport: [ TCP ], streamMuxer: [Mplex],
streamMuxer: [ Mplex ], connEncryption: [SECIO],
connEncryption: [ SECIO ], peerDiscovery: [Bootstrap]
peerDiscovery: [ Bootstrap ] },
}, config: {
config: { peerDiscovery: {
peerDiscovery: { bootstrap: {
autoDial: true, interval: 60e3,
bootstrap: { enabled: true,
interval: 20e3, list: bootstrapers
enabled: true,
list: bootstrapers
}
} }
} }
} }
})
super(defaultsDeep(_options, defaults)) node.peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
}
}
let node node.on('peer:connect', (peer) => {
console.log('Connection established to:', peer.id.toB58String()) // Emitted when a peer has been found
waterfall([ })
(cb) => PeerInfo.create(cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
node = new MyBundle({
peerInfo
})
node.start(cb)
}
], (err) => {
if (err) { throw err }
node.on('peer:discovery', (peer) => { node.on('peer:discovery', (peer) => {
// No need to dial, autoDial is on // No need to dial, autoDial is on
console.log('Discovered:', peer.id.toB58String()) console.log('Discovered:', peer.id.toB58String())
}) })
node.on('peer:connect', (peer) => { await node.start()
console.log('Connection established to:', peer.id.toB58String()) })();
})
})

View File

@ -1,63 +1,45 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
'use strict' 'use strict'
const libp2p = require('../../') const Libp2p = require('../../')
const TCP = require('libp2p-tcp') const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex') const Mplex = require('libp2p-mplex')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info')
const MulticastDNS = require('libp2p-mdns') const MulticastDNS = require('libp2p-mdns')
const waterfall = require('async/waterfall')
const parallel = require('async/parallel')
const defaultsDeep = require('@nodeutils/defaults-deep')
class MyBundle extends libp2p { const createNode = async () => {
constructor (_options) { const node = await Libp2p.create({
const defaults = { modules: {
modules: { transport: [TCP],
transport: [ TCP ], streamMuxer: [Mplex],
streamMuxer: [ Mplex ], connEncryption: [SECIO],
connEncryption: [ SECIO ], peerDiscovery: [MulticastDNS]
peerDiscovery: [ MulticastDNS ] },
}, config: {
config: { peerDiscovery: {
peerDiscovery: { mdns: {
mdns: { interval: 20e3,
interval: 20e3, enabled: true
enabled: true
}
} }
} }
} }
})
node.peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
super(defaultsDeep(_options, defaults)) return node
}
} }
function createNode (callback) { ;(async () => {
let node const [node1, node2] = await Promise.all([
createNode(),
waterfall([ createNode()
(cb) => PeerInfo.create(cb), ])
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
node = new MyBundle({
peerInfo
})
node.start(cb)
}
], (err) => callback(err, node))
}
parallel([
(cb) => createNode(cb),
(cb) => createNode(cb)
], (err, nodes) => {
if (err) { throw err }
const node1 = nodes[0]
const node2 = nodes[1]
node1.on('peer:discovery', (peer) => console.log('Discovered:', peer.id.toB58String())) node1.on('peer:discovery', (peer) => console.log('Discovered:', peer.id.toB58String()))
node2.on('peer:discovery', (peer) => console.log('Discovered:', peer.id.toB58String())) node2.on('peer:discovery', (peer) => console.log('Discovered:', peer.id.toB58String()))
})
await Promise.all([
node1.start(),
node2.start()
])
})();

View File

@ -10,36 +10,32 @@ These mechanisms save configuration and enable a node to operate without any exp
For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, mplex and SECIO. You can see the complete example at [1.js](./1.js). For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, mplex and SECIO. You can see the complete example at [1.js](./1.js).
First, we create our libp2p bundle. First, we create our libp2p node.
```JavaScript ```JavaScript
const Bootstrap = require('libp2p-railing') const Libp2p = require('libp2p')
class MyBundle extends libp2p { const Bootstrap = require('libp2p-bootstrap')
constructor (peerInfo) {
const defaults = { const node = Libp2p.create({
modules: { modules: {
transport: [ TCP ], transport: [ TCP ],
streamMuxer: [ Mplex ], streamMuxer: [ Mplex ],
connEncryption: [ SECIO ], connEncryption: [ SECIO ],
peerDiscovery: [ Bootstrap ] peerDiscovery: [ Bootstrap ]
}, },
config: { config: {
peerDiscovery: { peerDiscovery: {
bootstrap: { bootstrap: {
interval: 2000, interval: 60e3,
enabled: true, enabled: true,
list: bootstrapers list: bootstrapers
}
}
} }
} }
super(defaultsDeep(_options, defaults))
} }
} })
``` ```
In this bundle, we use a `bootstrappers` array listing peers to connect _on boot_. Here is the list used by js-ipfs and go-ipfs. In this configuration, we use a `bootstrappers` array listing peers to connect _on boot_. Here is the list used by js-ipfs and go-ipfs.
```JavaScript ```JavaScript
const bootstrapers = [ const bootstrapers = [
@ -58,34 +54,37 @@ const bootstrapers = [
Now, once we create and start the node, we can listen for events such as `peer:discovery` and `peer:connect`, these events tell us when we found a peer, independently of the discovery mechanism used and when we actually dialed to that peer. Now, once we create and start the node, we can listen for events such as `peer:discovery` and `peer:connect`, these events tell us when we found a peer, independently of the discovery mechanism used and when we actually dialed to that peer.
```JavaScript ```JavaScript
let node const node = await Libp2p.create({
peerInfo,
waterfall([ modules: {
(cb) => PeerInfo.create(cb), transport: [ TCP ],
(peerInfo, cb) => { streamMuxer: [ Mplex ],
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0') connEncryption: [ SECIO ],
node = new MyBundle({ peerDiscovery: [ Bootstrap ]
peerInfo },
}) config: {
node.start(cb) peerDiscovery: {
bootstrap: {
interval: 60e3,
enabled: true,
list: bootstrapers
}
}
} }
], (err) => {
if (err) { throw err }
// Emitted when a peer has been found
node.on('peer:discovery', (peer) => {
console.log('Discovered:', peer.id.toB58String())
// Note how we need to dial, even if just to warm up the Connection (by not
// picking any protocol) in order to get a full Connection. The Peer Discovery
// doesn't make any decisions for you.
node.dial(peer, () => {})
})
// Once the dial is complete, this event is emitted.
node.on('peer:connect', (peer) => {
console.log('Connection established to:', peer.id.toB58String())
})
}) })
node.peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
node.on('peer:connect', (peer) => {
console.log('Connection established to:', peer.id.toB58String()) // Emitted when a peer has been found
})
// Emitted when a peer has been found
node.on('peer:discovery', (peer) => {
console.log('Discovered:', peer.id.toB58String())
})
await node.start()
``` ```
From running [1.js](./1.js), you should see the following: From running [1.js](./1.js), you should see the following:
@ -101,76 +100,56 @@ Discovered: QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64
Discovered: QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd Discovered: QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd
Discovered: QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3 Discovered: QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
Discovered: QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx Discovered: QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
Connection established to: QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
Connection established to: QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd
Connection established to: QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64
Connection established to: QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm
Connection established to: QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM
Connection established to: QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
Connection established to: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
Connection established to: QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z
Connection established to: QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu
``` ```
## 2. MulticastDNS to find other peers in the network ## 2. MulticastDNS to find other peers in the network
For this example, we need `libp2p-mdns`, go ahead and `npm install` it. You can find the complete solution at [2.js](./2.js). For this example, we need `libp2p-mdns`, go ahead and `npm install` it. You can find the complete solution at [2.js](./2.js).
Update your libp2p bundle to include MulticastDNS. Update your libp2p configuration to include MulticastDNS.
```JavaScript ```JavaScript
class MyBundle extends libp2p { const Libp2p = require('libp2p')
constructor (peerInfo) { const MulticastDNS = require('libp2p-mdns')
const defaults = {
modules: { const createNode = () => {
transport: [ TCP ], return Libp2p.create({
streamMuxer: [ Mplex ], modules: {
connEncryption: [ SECIO ], transport: [ TCP ],
peerDiscovery: [ MulticastDNS ] streamMuxer: [ Mplex ],
}, connEncryption: [ SECIO ],
config: { peerDiscovery: [ MulticastDNS ]
peerDiscovery: { },
mdns: { config: {
// Run at 1s so we can observe more quickly, default is 10s peerDiscovery: {
interval: 1000, mdns: {
enabled: true interval: 20e3,
} enabled: true
} }
} }
} }
})
super(defaultsDeep(_options, defaults))
}
} }
``` ```
To observe it working, spawn two nodes. To observe it working, spawn two nodes.
```JavaScript ```JavaScript
parallel([ const [node1, node2] = await Promise.all([
(cb) => createNode(cb), createNode(),
(cb) => createNode(cb) createNode()
], (err, nodes) => { ])
if (err) { throw err }
const node1 = nodes[0] node1.on('peer:discovery', (peer) => console.log('Discovered:', peer.id.toB58String()))
const node2 = nodes[1] node2.on('peer:discovery', (peer) => console.log('Discovered:', peer.id.toB58String()))
node1.on('peer:discovery', (peer) => console.log('Discovered:', peer.id.toB58String()))
node2.on('peer:discovery', (peer) => console.log('Discovered:', peer.id.toB58String()))
})
``` ```
If you run this example, you will see a continuous stream of each peer discovering each other. If you run this example, you will see the other peers being discovered.
```bash ```bash
> node 2.js > node 2.js
Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m
Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ
Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m
Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ
Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m
Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ
``` ```
## 3. Where to find other Peer Discovery Mechanisms ## 3. Where to find other Peer Discovery Mechanisms