From 06a6f2f7666dd020b1b36783df1986389c7d109c Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Thu, 26 Jul 2018 19:40:57 +0200 Subject: [PATCH 1/6] feat: add libp2p generator config option with example --- README.md | 5 +- examples/custom-libp2p/README.md | 18 +++ examples/custom-libp2p/index.js | 121 ++++++++++++++++ examples/custom-libp2p/package.json | 23 +++ src/core/components/libp2p.js | 82 ++++++----- src/core/config.js | 9 +- test/core/config.spec.js | 1 + test/core/libp2p.spec.js | 211 ++++++++++++++++++++++++++++ 8 files changed, 430 insertions(+), 40 deletions(-) create mode 100644 examples/custom-libp2p/README.md create mode 100644 examples/custom-libp2p/index.js create mode 100644 examples/custom-libp2p/package.json create mode 100644 test/core/libp2p.spec.js diff --git a/README.md b/README.md index 2a363398cb..c4d62b7080 100644 --- a/README.md +++ b/README.md @@ -301,8 +301,11 @@ Modify the default IPFS node config. This object will be *merged* with the defau | Type | Default | |------|---------| | object | [`libp2p-nodejs.js`](https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/libp2p-nodejs.js) in Node.js, [`libp2p-browser.js`](https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/libp2p-browser.js) in browsers | +| function | [`libp2p generator`](examples/custom-libp2p) | -Add custom modules to the libp2p stack of your node. +The libp2p option allows you to build your libp2p node by configuration, or via a generator. If you are looking to just modify the below options, using the object format is the quickest way to get the default features of libp2p. If you need to create a more customized libp2p node, such as with custom transports or peer/content routers that need some of the ipfs data on startup, a generator is a great way to achieve this. + +You can see the generator in action in the [custom libp2p example](examples/custom-libp2p). - `modules` (object): - `transport` (Array<[libp2p.Transport](https://github.com/libp2p/interface-transport)>): An array of Libp2p transport classes/instances to use _instead_ of the defaults. See [libp2p/interface-transport](https://github.com/libp2p/interface-transport) for details. diff --git a/examples/custom-libp2p/README.md b/examples/custom-libp2p/README.md new file mode 100644 index 0000000000..05c2e5e63c --- /dev/null +++ b/examples/custom-libp2p/README.md @@ -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 generator 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 generator 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)! diff --git a/examples/custom-libp2p/index.js b/examples/custom-libp2p/index.js new file mode 100644 index 0000000000..89aca1b72d --- /dev/null +++ b/examples/custom-libp2p/index.js @@ -0,0 +1,121 @@ +'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') + +/** + * This is the generator we will use to generate our fully customized libp2p node. + * + * @param {*} _ipfsNode The ipfs node. This houses the PeerInfo and PeerBook that modules may need + * @param {*} _ipfsConfig The config that is fetched from the ipfs-repo + * @returns {Libp2p} Our new libp2p node + */ +const libp2pGenerator = (_ipfsNode, _ipfsConfig) => { + // Set convenience variables to clearly showcase some of the useful things that are available + const peerInfo = _ipfsNode._peerInfo + const peerBook = _ipfsNode._peerBook + const bootstrapList = _ipfsConfig.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 generator, let's start up the ipfs node! +const node = new IPFS({ + libp2p: libp2pGenerator +}) + +// 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) +}) diff --git a/examples/custom-libp2p/package.json b/examples/custom-libp2p/package.json new file mode 100644 index 0000000000..8e28bc66e3 --- /dev/null +++ b/examples/custom-libp2p/package.json @@ -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" + } +} diff --git a/src/core/components/libp2p.js b/src/core/components/libp2p.js index 1ad0d1ecac..6080da25d3 100644 --- a/src/core/components/libp2p.js +++ b/src/core/components/libp2p.js @@ -16,49 +16,59 @@ module.exports = function libp2p (self) { return callback(err) } - const libp2pDefaults = { - peerInfo: self._peerInfo, - peerBook: self._peerInfoBook, - config: { - peerDiscovery: { - mdns: { - enabled: get(self._options, 'config.Discovery.MDNS.Enabled', - get(config, 'Discovery.MDNS.Enabled', true)) + const defaultGenerator = (_ipfs, _config) => { + const libp2pDefaults = { + peerInfo: _ipfs._peerInfo, + peerBook: _ipfs._peerInfoBook, + config: { + peerDiscovery: { + mdns: { + enabled: get(_ipfs._options, 'config.Discovery.MDNS.Enabled', + get(_config, 'Discovery.MDNS.Enabled', true)) + }, + webRTCStar: { + enabled: get(_ipfs._options, 'config.Discovery.webRTCStar.Enabled', + get(_config, 'Discovery.webRTCStar.Enabled', true)) + }, + bootstrap: { + list: get(_ipfs._options, 'config.Bootstrap', + get(_config, 'Bootstrap', [])) + } }, - webRTCStar: { - enabled: get(self._options, 'config.Discovery.webRTCStar.Enabled', - get(config, 'Discovery.webRTCStar.Enabled', true)) + relay: { + enabled: get(_ipfs._options, 'relay.enabled', + get(_config, 'relay.enabled', false)), + hop: { + enabled: get(_ipfs._options, 'relay.hop.enabled', + get(_config, 'relay.hop.enabled', false)), + active: get(_ipfs._options, 'relay.hop.active', + get(_config, 'relay.hop.active', false)) + } }, - bootstrap: { - list: get(self._options, 'config.Bootstrap', - get(config, 'Bootstrap', [])) + EXPERIMENTAL: { + dht: get(_ipfs._options, 'EXPERIMENTAL.dht', false), + pubsub: get(_ipfs._options, 'EXPERIMENTAL.pubsub', false) } }, - relay: { - enabled: get(self._options, 'relay.enabled', - get(config, 'relay.enabled', false)), - hop: { - enabled: get(self._options, 'relay.hop.enabled', - get(config, 'relay.hop.enabled', false)), - active: get(self._options, 'relay.hop.active', - get(config, 'relay.hop.active', false)) - } - }, - EXPERIMENTAL: { - dht: get(self._options, 'EXPERIMENTAL.dht', false), - pubsub: get(self._options, 'EXPERIMENTAL.pubsub', false) - } - }, - connectionManager: get(self._options, 'connectionManager', - get(config, 'connectionManager', {})) + connectionManager: get(_ipfs._options, 'connectionManager', + get(_config, 'connectionManager', {})) + } + + const libp2pOptions = defaultsDeep( + get(self._options, 'libp2p', {}), + libp2pDefaults + ) + + return new Node(libp2pOptions) } - const libp2pOptions = defaultsDeep( - get(self._options, 'libp2p', {}), - libp2pDefaults - ) + // Always create libp2p via a generator + let libp2pGenerator = get(self._options, 'libp2p', null) + if (typeof libp2pGenerator !== 'function') { + libp2pGenerator = defaultGenerator + } - self._libp2pNode = new Node(libp2pOptions) + self._libp2pNode = libp2pGenerator(self, config) self._libp2pNode.on('peer:discovery', (peerInfo) => { const dial = () => { diff --git a/src/core/config.js b/src/core/config.js index 7b16c17d06..9b27b14de5 100644 --- a/src/core/config.js +++ b/src/core/config.js @@ -48,9 +48,12 @@ const schema = Joi.object().keys({ }).allow(null), Bootstrap: Joi.array().items(Joi.multiaddr().IPFS().options({ convert: false })) }).allow(null), - libp2p: Joi.object().keys({ - modules: Joi.object().allow(null) // TODO: schemas for libp2p modules? - }).allow(null) + libp2p: Joi.alternatives().try( + Joi.func(), + Joi.object().keys({ + modules: Joi.object().allow(null) // TODO: schemas for libp2p modules? + }) + ).allow(null) }).options({ allowUnknown: true }) module.exports.validate = (config) => Joi.attempt(config, schema) diff --git a/test/core/config.spec.js b/test/core/config.spec.js index 1946801dde..3250c5b9d4 100644 --- a/test/core/config.spec.js +++ b/test/core/config.spec.js @@ -226,6 +226,7 @@ describe('config', () => { { libp2p: { modules: null } }, { libp2p: { modules: undefined } }, { libp2p: { unknown: 'value' } }, + { libp2p: () => {} }, { libp2p: null }, { libp2p: undefined } ] diff --git a/test/core/libp2p.spec.js b/test/core/libp2p.spec.js new file mode 100644 index 0000000000..0b503c7387 --- /dev/null +++ b/test/core/libp2p.spec.js @@ -0,0 +1,211 @@ +/* eslint max-nested-callbacks: ["error", 8] */ +/* eslint-env mocha */ +'use strict' + +const chai = require('chai') +const dirtyChai = require('dirty-chai') +const expect = chai.expect +chai.use(dirtyChai) + +const PeerInfo = require('peer-info') +const PeerBook = require('peer-book') +const WebSocketStar = require('libp2p-websocket-star') +const Multiplex = require('libp2p-mplex') +const SECIO = require('libp2p-secio') +const Libp2p = require('libp2p') + +const libp2pComponent = require('../../src/core/components/libp2p') + +describe('libp2p customization', function () { + // Provide some extra time for ci since we're starting libp2p nodes in each test + this.timeout(15 * 1000) + + let peerInfo + let peerBook + let mockConfig + let _libp2p + + before((done) => { + mockConfig = { + get: (callback) => { + callback(null, { + Addresses: { + Swarm: ['/ip4/0.0.0.0/tcp/4002'], + API: '/ip4/127.0.0.1/tcp/5002', + Gateway: '/ip4/127.0.0.1/tcp/9090' + }, + Discovery: { + MDNS: { + Enabled: false + }, + webRTCStar: { + Enabled: false + } + }, + EXPERIMENTAL: { + dht: false, + pubsub: false + } + }) + } + } + peerBook = new PeerBook() + PeerInfo.create((err, pi) => { + peerInfo = pi + done(err) + }) + }) + + afterEach((done) => { + if (!_libp2p) return done() + + _libp2p.stop(() => { + _libp2p = null + done() + }) + }) + + describe('generator', () => { + it('should allow for using a libp2p generator', (done) => { + const ipfs = { + _peerInfo: peerInfo, + _peerBook: peerBook, + config: mockConfig, + _options: { + libp2p: (_ipfs, _ipfsConfig) => { + const wsstar = new WebSocketStar({id: _ipfs._peerInfo.id}) + + return new Libp2p({ + peerInfo: _ipfs._peerInfo, + peerBook: _ipfs._peerBook, + modules: { + transport: [ + wsstar + ], + streamMuxer: [ + Multiplex + ], + connEncryption: [ + SECIO + ], + peerDiscovery: [ + wsstar.discovery + ] + } + }) + } + } + } + + _libp2p = libp2pComponent(ipfs) + + _libp2p.start((err) => { + expect(err).to.not.exist() + expect(ipfs._libp2pNode._config).to.not.have.property('peerDiscovery') + expect(ipfs._libp2pNode._transport).to.have.length(1) + done() + }) + }) + }) + + describe('options', () => { + it('should use options by default', (done) => { + const ipfs = { + _peerInfo: peerInfo, + _peerBook: peerBook, + config: mockConfig + } + + _libp2p = libp2pComponent(ipfs) + + _libp2p.start((err) => { + expect(err).to.not.exist() + expect(ipfs._libp2pNode._config).to.deep.include({ + peerDiscovery: { + bootstrap: { + enabled: true, + list: [] + }, + mdns: { + enabled: false + }, + webRTCStar: { + enabled: false + }, + websocketStar: { + enabled: true + } + }, + EXPERIMENTAL: { + dht: false, + pubsub: false + } + }) + expect(ipfs._libp2pNode._transport).to.have.length(3) + done() + }) + }) + + it('should allow for overriding via options', (done) => { + const wsstar = new WebSocketStar({id: peerInfo.id}) + + const ipfs = { + _peerInfo: peerInfo, + _peerBook: peerBook, + config: mockConfig, + _options: { + config: { + Discovery: { + MDNS: { + Enabled: true + } + } + }, + EXPERIMENTAL: { + dht: false, + pubsub: true + }, + libp2p: { + modules: { + transport: [ + wsstar + ], + peerDiscovery: [ + wsstar.discovery + ] + } + } + } + } + + _libp2p = libp2pComponent(ipfs) + + _libp2p.start((err) => { + expect(err).to.not.exist() + expect(ipfs._libp2pNode._config).to.deep.include({ + peerDiscovery: { + bootstrap: { + enabled: true, + list: [] + }, + mdns: { + enabled: true + }, + webRTCStar: { + enabled: false + }, + websocketStar: { + enabled: true + } + }, + EXPERIMENTAL: { + dht: false, + pubsub: true + } + }) + expect(ipfs._libp2pNode._transport).to.have.length(1) + done() + }) + }) + }) +}) From 6ec62a543b60d0905abf3899c8d347572c7cf7bd Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Mon, 30 Jul 2018 16:18:08 +0200 Subject: [PATCH 2/6] docs: factory instead of generator --- examples/custom-libp2p/README.md | 2 +- examples/custom-libp2p/index.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/custom-libp2p/README.md b/examples/custom-libp2p/README.md index 05c2e5e63c..b42037606c 100644 --- a/examples/custom-libp2p/README.md +++ b/examples/custom-libp2p/README.md @@ -1,6 +1,6 @@ # Customizing the libp2p node -This example shows you how to make full use of the ipfs configuration to create a libp2p generator 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 generator to get exactly what you need. This example shows you how. +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 diff --git a/examples/custom-libp2p/index.js b/examples/custom-libp2p/index.js index 89aca1b72d..e8ebe3d761 100644 --- a/examples/custom-libp2p/index.js +++ b/examples/custom-libp2p/index.js @@ -13,13 +13,13 @@ const SECIO = require('libp2p-secio') const assert = require('assert') /** - * This is the generator we will use to generate our fully customized libp2p node. + * This is the factory we will use to create our fully customized libp2p node. * * @param {*} _ipfsNode The ipfs node. This houses the PeerInfo and PeerBook that modules may need * @param {*} _ipfsConfig The config that is fetched from the ipfs-repo * @returns {Libp2p} Our new libp2p node */ -const libp2pGenerator = (_ipfsNode, _ipfsConfig) => { +const libp2pFactory = (_ipfsNode, _ipfsConfig) => { // Set convenience variables to clearly showcase some of the useful things that are available const peerInfo = _ipfsNode._peerInfo const peerBook = _ipfsNode._peerBook @@ -89,9 +89,9 @@ const libp2pGenerator = (_ipfsNode, _ipfsConfig) => { }) } -// Now that we have our custom generator, let's start up the ipfs node! +// Now that we have our custom factory, let's start up the ipfs node! const node = new IPFS({ - libp2p: libp2pGenerator + libp2p: libp2pFactory }) // Listen for the node to start, so we can log out some metrics From 3417b6fcc286a766668e35956b31bfe72c8f2a36 Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Mon, 30 Jul 2018 16:24:42 +0200 Subject: [PATCH 3/6] feat: create getters for peerInfo and peerBook --- examples/custom-libp2p/index.js | 4 ++-- src/core/index.js | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/examples/custom-libp2p/index.js b/examples/custom-libp2p/index.js index e8ebe3d761..4bd8330d5b 100644 --- a/examples/custom-libp2p/index.js +++ b/examples/custom-libp2p/index.js @@ -21,8 +21,8 @@ const assert = require('assert') */ const libp2pFactory = (_ipfsNode, _ipfsConfig) => { // Set convenience variables to clearly showcase some of the useful things that are available - const peerInfo = _ipfsNode._peerInfo - const peerBook = _ipfsNode._peerBook + const peerInfo = _ipfsNode.peerInfo + const peerBook = _ipfsNode.peerBook const bootstrapList = _ipfsConfig.Bootstrap // Create our WebSocketStar transport and give it our PeerId, straight from the ipfs node diff --git a/src/core/index.js b/src/core/index.js index 52266b7b41..89f90f9589 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -153,6 +153,20 @@ class IPFS extends EventEmitter { boot(this) } + + /** + * @type {PeerBook} + */ + get peerBook () { + return this._peerInfoBook + } + + /** + * @type {PeerInfo} + */ + get peerInfo () { + return this._peerInfo + } } exports = module.exports = IPFS From 289b12ed57a17b1956924abdd879292d3a61fa1b Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Thu, 9 Aug 2018 19:49:39 +0200 Subject: [PATCH 4/6] refactor: dont expose new getters, use options refactor: generator to factory --- README.md | 6 ++-- examples/custom-libp2p/index.js | 20 +++++++++---- src/core/components/libp2p.js | 53 ++++++++++++++++++--------------- src/core/index.js | 14 --------- test/core/libp2p.spec.js | 12 ++++---- 5 files changed, 52 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index c4d62b7080..af5ae24b88 100644 --- a/README.md +++ b/README.md @@ -301,11 +301,11 @@ Modify the default IPFS node config. This object will be *merged* with the defau | Type | Default | |------|---------| | object | [`libp2p-nodejs.js`](https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/libp2p-nodejs.js) in Node.js, [`libp2p-browser.js`](https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/libp2p-browser.js) in browsers | -| function | [`libp2p generator`](examples/custom-libp2p) | +| function | [`libp2p factory`](examples/custom-libp2p) | -The libp2p option allows you to build your libp2p node by configuration, or via a generator. If you are looking to just modify the below options, using the object format is the quickest way to get the default features of libp2p. If you need to create a more customized libp2p node, such as with custom transports or peer/content routers that need some of the ipfs data on startup, a generator is a great way to achieve this. +The libp2p option allows you to build your libp2p node by configuration, or via a factory. If you are looking to just modify the below options, using the object format is the quickest way to get the default features of libp2p. If you need to create a more customized libp2p node, such as with custom transports or peer/content routers that need some of the ipfs data on startup, a factory is a great way to achieve this. -You can see the generator in action in the [custom libp2p example](examples/custom-libp2p). +You can see the factory in action in the [custom libp2p example](examples/custom-libp2p). - `modules` (object): - `transport` (Array<[libp2p.Transport](https://github.com/libp2p/interface-transport)>): An array of Libp2p transport classes/instances to use _instead_ of the defaults. See [libp2p/interface-transport](https://github.com/libp2p/interface-transport) for details. diff --git a/examples/custom-libp2p/index.js b/examples/custom-libp2p/index.js index 4bd8330d5b..f777e3b093 100644 --- a/examples/custom-libp2p/index.js +++ b/examples/custom-libp2p/index.js @@ -12,18 +12,26 @@ 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 {*} _ipfsNode The ipfs node. This houses the PeerInfo and PeerBook that modules may need - * @param {*} _ipfsConfig The config that is fetched from the ipfs-repo + * @param {libp2pFactory~options} opts The options to use when generating the libp2p node * @returns {Libp2p} Our new libp2p node */ -const libp2pFactory = (_ipfsNode, _ipfsConfig) => { +const libp2pFactory = (opts) => { // Set convenience variables to clearly showcase some of the useful things that are available - const peerInfo = _ipfsNode.peerInfo - const peerBook = _ipfsNode.peerBook - const bootstrapList = _ipfsConfig.Bootstrap + 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({ diff --git a/src/core/components/libp2p.js b/src/core/components/libp2p.js index 6080da25d3..29e5271358 100644 --- a/src/core/components/libp2p.js +++ b/src/core/components/libp2p.js @@ -16,42 +16,42 @@ module.exports = function libp2p (self) { return callback(err) } - const defaultGenerator = (_ipfs, _config) => { + const defaultFactory = (opts) => { const libp2pDefaults = { - peerInfo: _ipfs._peerInfo, - peerBook: _ipfs._peerInfoBook, + peerInfo: opts.peerInfo, + peerBook: opts.peerBook, config: { peerDiscovery: { mdns: { - enabled: get(_ipfs._options, 'config.Discovery.MDNS.Enabled', - get(_config, 'Discovery.MDNS.Enabled', true)) + enabled: get(opts.options, 'config.Discovery.MDNS.Enabled', + get(opts.config, 'Discovery.MDNS.Enabled', true)) }, webRTCStar: { - enabled: get(_ipfs._options, 'config.Discovery.webRTCStar.Enabled', - get(_config, 'Discovery.webRTCStar.Enabled', true)) + enabled: get(opts.options, 'config.Discovery.webRTCStar.Enabled', + get(opts.config, 'Discovery.webRTCStar.Enabled', true)) }, bootstrap: { - list: get(_ipfs._options, 'config.Bootstrap', - get(_config, 'Bootstrap', [])) + list: get(opts.options, 'config.Bootstrap', + get(opts.config, 'Bootstrap', [])) } }, relay: { - enabled: get(_ipfs._options, 'relay.enabled', - get(_config, 'relay.enabled', false)), + enabled: get(opts.options, 'relay.enabled', + get(opts.config, 'relay.enabled', false)), hop: { - enabled: get(_ipfs._options, 'relay.hop.enabled', - get(_config, 'relay.hop.enabled', false)), - active: get(_ipfs._options, 'relay.hop.active', - get(_config, 'relay.hop.active', false)) + enabled: get(opts.options, 'relay.hop.enabled', + get(opts.config, 'relay.hop.enabled', false)), + active: get(opts.options, 'relay.hop.active', + get(opts.config, 'relay.hop.active', false)) } }, EXPERIMENTAL: { - dht: get(_ipfs._options, 'EXPERIMENTAL.dht', false), - pubsub: get(_ipfs._options, 'EXPERIMENTAL.pubsub', false) + dht: get(opts.options, 'EXPERIMENTAL.dht', false), + pubsub: get(opts.options, 'EXPERIMENTAL.pubsub', false) } }, - connectionManager: get(_ipfs._options, 'connectionManager', - get(_config, 'connectionManager', {})) + connectionManager: get(opts.options, 'connectionManager', + get(opts.config, 'connectionManager', {})) } const libp2pOptions = defaultsDeep( @@ -62,13 +62,18 @@ module.exports = function libp2p (self) { return new Node(libp2pOptions) } - // Always create libp2p via a generator - let libp2pGenerator = get(self._options, 'libp2p', null) - if (typeof libp2pGenerator !== 'function') { - libp2pGenerator = defaultGenerator + // Always create libp2p via a factory + let libp2pFactory = get(self._options, 'libp2p', null) + if (typeof libp2pFactory !== 'function') { + libp2pFactory = defaultFactory } - self._libp2pNode = libp2pGenerator(self, config) + self._libp2pNode = libp2pFactory({ + options: self._options, + config: config, + peerInfo: self._peerInfo, + peerBook: self._peerInfoBook + }) self._libp2pNode.on('peer:discovery', (peerInfo) => { const dial = () => { diff --git a/src/core/index.js b/src/core/index.js index 89f90f9589..52266b7b41 100644 --- a/src/core/index.js +++ b/src/core/index.js @@ -153,20 +153,6 @@ class IPFS extends EventEmitter { boot(this) } - - /** - * @type {PeerBook} - */ - get peerBook () { - return this._peerInfoBook - } - - /** - * @type {PeerInfo} - */ - get peerInfo () { - return this._peerInfo - } } exports = module.exports = IPFS diff --git a/test/core/libp2p.spec.js b/test/core/libp2p.spec.js index 0b503c7387..9dfbc82f7c 100644 --- a/test/core/libp2p.spec.js +++ b/test/core/libp2p.spec.js @@ -65,19 +65,19 @@ describe('libp2p customization', function () { }) }) - describe('generator', () => { - it('should allow for using a libp2p generator', (done) => { + describe('factory', () => { + it('should allow for using a libp2p factory', (done) => { const ipfs = { _peerInfo: peerInfo, _peerBook: peerBook, config: mockConfig, _options: { - libp2p: (_ipfs, _ipfsConfig) => { - const wsstar = new WebSocketStar({id: _ipfs._peerInfo.id}) + libp2p: (opts) => { + const wsstar = new WebSocketStar({id: opts.peerInfo.id}) return new Libp2p({ - peerInfo: _ipfs._peerInfo, - peerBook: _ipfs._peerBook, + peerInfo: opts.peerInfo, + peerBook: opts.peerBook, modules: { transport: [ wsstar From bf92fb321a66651a63a8b9cc81112f149573826a Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Wed, 22 Aug 2018 16:43:37 +0200 Subject: [PATCH 5/6] docs: update libp2p example to use bundle language --- examples/README.md | 1 + examples/custom-libp2p/README.md | 4 ++-- examples/custom-libp2p/index.js | 14 +++++++------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/examples/README.md b/examples/README.md index 14a4c49d97..b7b587eeb5 100644 --- a/examples/README.md +++ b/examples/README.md @@ -23,6 +23,7 @@ Let us know if you find any issue or if you want to contribute and add a new tut - [js-ipfs in electron](./run-in-electron) - [Using streams to add a directory of files to ipfs](./browser-add-readable-stream) - [Customizing the ipfs repository](./custom-ipfs-repo) +- [Customizing your libp2p bundle](./custom-libp2p) - [Streaming video from ipfs to the browser using `ReadableStream`s](./browser-readablestream) - [The Mutable File System in the browser](./browser-mfs) diff --git a/examples/custom-libp2p/README.md b/examples/custom-libp2p/README.md index b42037606c..ff4b376f6d 100644 --- a/examples/custom-libp2p/README.md +++ b/examples/custom-libp2p/README.md @@ -1,6 +1,6 @@ -# Customizing the libp2p node +# Customizing your libp2p bundle -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. +This example shows you how to make full use of the ipfs configuration to create a libp2p bundle function. As IPFS applications become more complex, their needs for a custom libp2p bundle also grow. Instead of fighting with configuration options, you can use your own libp2p bundle function to get exactly what you need. ## Run this example diff --git a/examples/custom-libp2p/index.js b/examples/custom-libp2p/index.js index f777e3b093..f033b5fc1c 100644 --- a/examples/custom-libp2p/index.js +++ b/examples/custom-libp2p/index.js @@ -13,8 +13,8 @@ const SECIO = require('libp2p-secio') const assert = require('assert') /** - * Options for the libp2p factory - * @typedef {Object} libp2pFactory~options + * Options for the libp2p bundle + * @typedef {Object} libp2pBundle~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 @@ -22,12 +22,12 @@ const assert = require('assert') */ /** - * This is the factory we will use to create our fully customized libp2p node. + * This is the factory we will use to create our fully customized libp2p bundle. * - * @param {libp2pFactory~options} opts The options to use when generating the libp2p node + * @param {libp2pBundle~options} opts The options to use when generating the libp2p node * @returns {Libp2p} Our new libp2p node */ -const libp2pFactory = (opts) => { +const libp2pBundle = (opts) => { // Set convenience variables to clearly showcase some of the useful things that are available const peerInfo = opts.peerInfo const peerBook = opts.peerBook @@ -97,9 +97,9 @@ const libp2pFactory = (opts) => { }) } -// Now that we have our custom factory, let's start up the ipfs node! +// Now that we have our custom libp2p bundle, let's start up the ipfs node! const node = new IPFS({ - libp2p: libp2pFactory + libp2p: libp2pBundle }) // Listen for the node to start, so we can log out some metrics From 6480119fc53aa8a0b4dd77bc9952672d3195253e Mon Sep 17 00:00:00 2001 From: Jacob Heun Date: Mon, 27 Aug 2018 14:31:52 +0200 Subject: [PATCH 6/6] docs: update language from factory to bundle --- README.md | 6 +++--- examples/custom-libp2p/index.js | 2 +- src/core/components/libp2p.js | 12 ++++++------ test/core/libp2p.spec.js | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index af5ae24b88..412b911c15 100644 --- a/README.md +++ b/README.md @@ -301,11 +301,11 @@ Modify the default IPFS node config. This object will be *merged* with the defau | Type | Default | |------|---------| | object | [`libp2p-nodejs.js`](https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/libp2p-nodejs.js) in Node.js, [`libp2p-browser.js`](https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/libp2p-browser.js) in browsers | -| function | [`libp2p factory`](examples/custom-libp2p) | +| function | [`libp2p bundle`](examples/custom-libp2p) | -The libp2p option allows you to build your libp2p node by configuration, or via a factory. If you are looking to just modify the below options, using the object format is the quickest way to get the default features of libp2p. If you need to create a more customized libp2p node, such as with custom transports or peer/content routers that need some of the ipfs data on startup, a factory is a great way to achieve this. +The libp2p option allows you to build your libp2p node by configuration, or via a bundle function. If you are looking to just modify the below options, using the object format is the quickest way to get the default features of libp2p. If you need to create a more customized libp2p node, such as with custom transports or peer/content routers that need some of the ipfs data on startup, a custom bundle is a great way to achieve this. -You can see the factory in action in the [custom libp2p example](examples/custom-libp2p). +You can see the bundle in action in the [custom libp2p example](examples/custom-libp2p). - `modules` (object): - `transport` (Array<[libp2p.Transport](https://github.com/libp2p/interface-transport)>): An array of Libp2p transport classes/instances to use _instead_ of the defaults. See [libp2p/interface-transport](https://github.com/libp2p/interface-transport) for details. diff --git a/examples/custom-libp2p/index.js b/examples/custom-libp2p/index.js index f033b5fc1c..ede982a2d3 100644 --- a/examples/custom-libp2p/index.js +++ b/examples/custom-libp2p/index.js @@ -22,7 +22,7 @@ const assert = require('assert') */ /** - * This is the factory we will use to create our fully customized libp2p bundle. + * This is the bundle we will use to create our fully customized libp2p bundle. * * @param {libp2pBundle~options} opts The options to use when generating the libp2p node * @returns {Libp2p} Our new libp2p node diff --git a/src/core/components/libp2p.js b/src/core/components/libp2p.js index 29e5271358..c07e7b79f0 100644 --- a/src/core/components/libp2p.js +++ b/src/core/components/libp2p.js @@ -16,7 +16,7 @@ module.exports = function libp2p (self) { return callback(err) } - const defaultFactory = (opts) => { + const defaultBundle = (opts) => { const libp2pDefaults = { peerInfo: opts.peerInfo, peerBook: opts.peerBook, @@ -62,13 +62,13 @@ module.exports = function libp2p (self) { return new Node(libp2pOptions) } - // Always create libp2p via a factory - let libp2pFactory = get(self._options, 'libp2p', null) - if (typeof libp2pFactory !== 'function') { - libp2pFactory = defaultFactory + // Always create libp2p via a bundle function + let libp2pBundle = get(self._options, 'libp2p', null) + if (typeof libp2pBundle !== 'function') { + libp2pBundle = defaultBundle } - self._libp2pNode = libp2pFactory({ + self._libp2pNode = libp2pBundle({ options: self._options, config: config, peerInfo: self._peerInfo, diff --git a/test/core/libp2p.spec.js b/test/core/libp2p.spec.js index 9dfbc82f7c..135a6870ac 100644 --- a/test/core/libp2p.spec.js +++ b/test/core/libp2p.spec.js @@ -65,8 +65,8 @@ describe('libp2p customization', function () { }) }) - describe('factory', () => { - it('should allow for using a libp2p factory', (done) => { + describe('bundle', () => { + it('should allow for using a libp2p bundle', (done) => { const ipfs = { _peerInfo: peerInfo, _peerBook: peerBook,