-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: add libp2p factory config option with example #1470
Changes from 4 commits
06a6f2f
6ec62a5
3417b6f
289b12e
bf92fb3
6480119
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# Customizing the libp2p node | ||
|
||
This example shows you how to make full use of the ipfs configuration to create a libp2p factory function. As IPFS applications become more complex, their needs for a custom libp2p node also grow. Instead of fighting with configuration options, you can use your own libp2p factory to get exactly what you need. This example shows you how. | ||
|
||
## Run this example | ||
|
||
Running this example should result in metrics being logged out to the console every few seconds. | ||
|
||
``` | ||
> npm install | ||
> npm start | ||
``` | ||
|
||
## Play with the configuration! | ||
|
||
With the metrics for peers and bandwidth stats being logged out, try playing around with the nodes configuration to see what kind of metrics you can get. How many peers are you getting? What does your bandwidth look like? | ||
|
||
This is also a good opportunity to explore the various stats that ipfs offers! Not seeing a statistic you think would be useful? We'd love to have you [contribute](https://github.com/ipfs/js-ipfs/blob/master/CONTRIBUTING.md)! |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
'use strict' | ||
|
||
const Libp2p = require('libp2p') | ||
const IPFS = require('ipfs') | ||
const TCP = require('libp2p-tcp') | ||
const MulticastDNS = require('libp2p-mdns') | ||
const WebSocketStar = require('libp2p-websocket-star') | ||
const Bootstrap = require('libp2p-railing') | ||
const SPDY = require('libp2p-spdy') | ||
const KadDHT = require('libp2p-kad-dht') | ||
const MPLEX = require('libp2p-mplex') | ||
const SECIO = require('libp2p-secio') | ||
const assert = require('assert') | ||
|
||
/** | ||
* Options for the libp2p factory | ||
* @typedef {Object} libp2pFactory~options | ||
* @property {PeerInfo} peerInfo - The PeerInfo of the IPFS node | ||
* @property {PeerBook} peerBook - The PeerBook of the IPFS node | ||
* @property {Object} config - The config of the IPFS node | ||
* @property {Object} options - The options given to the IPFS node | ||
*/ | ||
|
||
/** | ||
* This is the factory we will use to create our fully customized libp2p node. | ||
* | ||
* @param {libp2pFactory~options} opts The options to use when generating the libp2p node | ||
* @returns {Libp2p} Our new libp2p node | ||
*/ | ||
const libp2pFactory = (opts) => { | ||
// Set convenience variables to clearly showcase some of the useful things that are available | ||
const peerInfo = opts.peerInfo | ||
const peerBook = opts.peerBook | ||
const bootstrapList = opts.config.Bootstrap | ||
|
||
// Create our WebSocketStar transport and give it our PeerId, straight from the ipfs node | ||
const wsstar = new WebSocketStar({ | ||
id: peerInfo.id | ||
}) | ||
|
||
// Build and return our libp2p node | ||
return new Libp2p({ | ||
peerInfo, | ||
peerBook, | ||
// Lets limit the connection managers peers and have it check peer health less frequently | ||
connectionManager: { | ||
maxPeers: 25, | ||
pollInterval: 5000 | ||
}, | ||
modules: { | ||
transport: [ | ||
TCP, | ||
wsstar | ||
], | ||
streamMuxer: [ | ||
MPLEX, | ||
SPDY | ||
], | ||
connEncryption: [ | ||
SECIO | ||
], | ||
peerDiscovery: [ | ||
MulticastDNS, | ||
Bootstrap, | ||
wsstar.discovery | ||
], | ||
dht: KadDHT | ||
}, | ||
config: { | ||
peerDiscovery: { | ||
mdns: { | ||
interval: 10000, | ||
enabled: true | ||
}, | ||
bootstrap: { | ||
interval: 10000, | ||
enabled: true, | ||
list: bootstrapList | ||
} | ||
}, | ||
// Turn on relay with hop active so we can connect to more peers | ||
relay: { | ||
enabled: true, | ||
hop: { | ||
enabled: true, | ||
active: true | ||
} | ||
}, | ||
dht: { | ||
kBucketSize: 20 | ||
}, | ||
EXPERIMENTAL: { | ||
dht: true, | ||
pubsub: true | ||
} | ||
} | ||
}) | ||
} | ||
|
||
// Now that we have our custom factory, let's start up the ipfs node! | ||
const node = new IPFS({ | ||
libp2p: libp2pFactory | ||
}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of calling it Factory, let's just reuse the wording around libp2p bundles (used in https://github.com/libp2p/js-libp2p#creating-your-own-libp2p-bundle, the website, slidedecks and other places). Also, it would be great that instead of passing a factory, we could pass the libp2p instance itself. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can switch up the wording to be libp2p bundle compliant. For passing the libp2p instance, we can't currently do that due to needing the PeerInfo on creation, which is created on ipfs pre-start. When libp2p gets its state machine update we could make creation and startup more flexible so that PeerInfo could be provided to libp2p before it is started and then it could in turn bootstrap (either directly or via event hooks) all of its dependents that require PeerInfo of PeerId data. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated the language to be more bundle centric, and added a link to the example in the main examples readme since it wasn't there yet. |
||
|
||
// Listen for the node to start, so we can log out some metrics | ||
node.once('start', (err) => { | ||
assert.ifError(err, 'Should startup without issue') | ||
|
||
// Lets log out the number of peers we have every 2 seconds | ||
setInterval(() => { | ||
node.swarm.peers((err, peers) => { | ||
if (err) { | ||
console.log('An error occurred trying to check our peers:', err) | ||
process.exit(1) | ||
} | ||
console.log(`The node now has ${peers.length} peers.`) | ||
}) | ||
}, 2000) | ||
|
||
// Log out the bandwidth stats every 4 seconds so we can see how our configuration is doing | ||
setInterval(() => { | ||
node.stats.bw((err, stats) => { | ||
if (err) { | ||
console.log('An error occurred trying to check our stats:', err) | ||
} | ||
console.log(`\nBandwidth Stats: ${JSON.stringify(stats, null, 2)}\n`) | ||
}) | ||
}, 4000) | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
{ | ||
"name": "custom-libp2p", | ||
"version": "0.1.0", | ||
"description": "Customizing your libp2p node", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"start": "node index.js" | ||
}, | ||
"license": "MIT", | ||
"dependencies": { | ||
"ipfs": "file:../../", | ||
"libp2p": "~0.22.0", | ||
"libp2p-kad-dht": "~0.10.1", | ||
"libp2p-mdns": "~0.12.0", | ||
"libp2p-mplex": "~0.8.0", | ||
"libp2p-railing": "~0.9.2", | ||
"libp2p-secio": "~0.10.0", | ||
"libp2p-spdy": "~0.12.1", | ||
"libp2p-tcp": "~0.12.0", | ||
"libp2p-websocket-star": "~0.8.1" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Was leaving the word
factory
here intentional?