Skip to content

chore: add discovery example with relay and pubsub discovery #855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,13 @@ jobs:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- connection-encryption
test-discovery-mechanisms-example:
needs: check
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- discovery-mechanisms
test-echo-example:
needs: check
runs-on: ubuntu-latest
Expand All @@ -93,13 +100,6 @@ jobs:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- libp2p-in-the-browser
test-discovery-mechanisms-example:
needs: check
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- discovery-mechanisms
test-peer-and-content-routing-example:
needs: check
runs-on: ubuntu-latest
Expand Down
68 changes: 68 additions & 0 deletions examples/discovery-mechanisms/3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* eslint-disable no-console */
'use strict'

const Libp2p = require('../../')
const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex')
const { NOISE } = require('libp2p-noise')
const Gossipsub = require('libp2p-gossipsub')
const Bootstrap = require('libp2p-bootstrap')
const PubsubPeerDiscovery = require('libp2p-pubsub-peer-discovery')

const createRelayServer = require('libp2p-relay-server')

const createNode = async (bootstrapers) => {
const node = await Libp2p.create({
addresses: {
listen: ['/ip4/0.0.0.0/tcp/0']
},
modules: {
transport: [TCP],
streamMuxer: [Mplex],
connEncryption: [NOISE],
pubsub: Gossipsub,
peerDiscovery: [Bootstrap, PubsubPeerDiscovery]
},
config: {
peerDiscovery: {
[PubsubPeerDiscovery.tag]: {
interval: 1000,
enabled: true
},
[Bootstrap.tag]: {
enabled: true,
list: bootstrapers
}
}
}
})

return node
}

;(async () => {
const relay = await createRelayServer({
listenAddresses: ['/ip4/0.0.0.0/tcp/0']
})
console.log(`libp2p relay starting with id: ${relay.peerId.toB58String()}`)
await relay.start()
const relayMultiaddrs = relay.multiaddrs.map((m) => `${m.toString()}/p2p/${relay.peerId.toB58String()}`)

const [node1, node2] = await Promise.all([
createNode(relayMultiaddrs),
createNode(relayMultiaddrs)
])

node1.on('peer:discovery', (peerId) => {
console.log(`Peer ${node1.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
})
node2.on('peer:discovery', (peerId) => {
console.log(`Peer ${node2.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
})

;[node1, node2].forEach((node, index) => console.log(`Node ${index} starting with id: ${node.peerId.toB58String()}`))
await Promise.all([
node1.start(),
node2.start()
])
})();
95 changes: 94 additions & 1 deletion examples/discovery-mechanisms/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,100 @@ Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m
Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ
```

## 3. Where to find other Peer Discovery Mechanisms
## 3. Pubsub based Peer Discovery

For this example, we need [`libp2p-pubsub-peer-discovery`](https://github.com/libp2p/js-libp2p-pubsub-peer-discovery/), go ahead and `npm install` it. You also need to spin up a set of [`libp2p-relay-servers`](https://github.com/libp2p/js-libp2p-relay-server). These servers act as relay servers and a peer discovery source.

In the context of this example, we will create and run the `libp2p-relay-server` in the same code snippet. You can find the complete solution at [3.js](./3.js).

You can create your libp2p nodes as follows:

```js
const Libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex')
const { NOISE } = require('libp2p-noise')
const Gossipsub = require('libp2p-gossipsub')
const Bootstrap = require('libp2p-bootstrap')
const PubsubPeerDiscovery = require('libp2p-pubsub-peer-discovery')

const createNode = async (bootstrapers) => {
const node = await Libp2p.create({
addresses: {
listen: ['/ip4/0.0.0.0/tcp/0']
},
modules: {
transport: [TCP],
streamMuxer: [Mplex],
connEncryption: [NOISE],
pubsub: Gossipsub,
peerDiscovery: [Bootstrap, PubsubPeerDiscovery]
},
config: {
peerDiscovery: {
[PubsubPeerDiscovery.tag]: {
interval: 1000,
enabled: true
},
[Bootstrap.tag]: {
enabled: true,
list: bootstrapers
}
}
}
})

return node
}
```

We will use the `libp2p-relay-server` as bootstrap nodes for the libp2p nodes, so that they establish a connection with the relay after starting. As a result, after they establish a connection with the relay, the pubsub discovery will kick in an the relay will advertise them.

```js
const relay = await createRelayServer({
listenAddresses: ['/ip4/0.0.0.0/tcp/0']
})
console.log(`libp2p relay starting with id: ${relay.peerId.toB58String()}`)
await relay.start()
const relayMultiaddrs = relay.multiaddrs.map((m) => `${m.toString()}/p2p/${relay.peerId.toB58String()}`)

const [node1, node2] = await Promise.all([
createNode(relayMultiaddrs),
createNode(relayMultiaddrs)
])

node1.on('peer:discovery', (peerId) => {
console.log(`Peer ${node1.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
})
node2.on('peer:discovery', (peerId) => {
console.log(`Peer ${node2.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
})

;[node1, node2].forEach((node, index) => console.log(`Node ${index} starting with id: ${node.peerId.toB58String()}`))
await Promise.all([
node1.start(),
node2.start()
])
```

If you run this example, you will see the other peers being discovered.

```bash
> node 3.js
libp2p relay starting with id: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
Node 0 starting with id: QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N
Node 1 starting with id: QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv
Peer QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N discovered: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
Peer QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv discovered: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
Peer QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv discovered: QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N
Peer QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N discovered: QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv
```

Taking into account the output, after the relay and both libp2p nodes start, both libp2p nodes will discover the bootstrap node (relay) and connect with it. After establishing a connection with the relay, they will discover each other.

This is really useful when running libp2p in constrained environments like a browser. You can run a set of `libp2p-relay-server` nodes that will be responsible for both relaying websocket connections between browser nodes and for discovering other browser peers.

## 4. Where to find other Peer Discovery Mechanisms

There are plenty more Peer Discovery Mechanisms out there, you can:

Expand Down
35 changes: 35 additions & 0 deletions examples/discovery-mechanisms/test-3.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict'

const path = require('path')
const execa = require('execa')
const pWaitFor = require('p-wait-for')
const uint8ArrayToString = require('uint8arrays/to-string')

const discoveredCopy = 'discovered:'

async function test() {
let discoverCount = 0

process.stdout.write('3.js\n')

const proc = execa('node', [path.join(__dirname, '3.js')], {
cwd: path.resolve(__dirname),
all: true
})

proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)

// Discovered or Connected
if (line.includes(discoveredCopy)) {
discoverCount++
}
})

await pWaitFor(() => discoverCount === 4)

proc.kill()
}

module.exports = test
2 changes: 2 additions & 0 deletions examples/discovery-mechanisms/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

const test1 = require('./test-1')
const test2 = require('./test-2')
const test3 = require('./test-3')

async function test () {
await test1()
await test2()
await test3()
}

module.exports = test
2 changes: 2 additions & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
"dependencies": {
"execa": "^2.1.0",
"fs-extra": "^8.1.0",
"libp2p-pubsub-peer-discovery": "^3.0.0",
"libp2p-relay-server": "^0.1.2",
"p-defer": "^3.0.0",
"which": "^2.0.1"
},
Expand Down