diff --git a/src/content-routing.js b/src/content-routing.js index 185865d8..d2989d81 100644 --- a/src/content-routing.js +++ b/src/content-routing.js @@ -18,111 +18,118 @@ const pAny = require('p-any') * @property {Uint8Array} val */ -module.exports = (node) => { - const routers = node._modules.contentRouting || [] - const dht = node._dht +class ContentRouting { + /** + * @class + * @param {import('./')} libp2p + */ + constructor (libp2p) { + this.libp2p = libp2p + this.routers = libp2p._modules.contentRouting || [] + this.dht = libp2p._dht - // If we have the dht, make it first - if (dht) { - routers.unshift(dht) - } - - return { - /** - * Iterates over all content routers in series to find providers of the given key. - * Once a content router succeeds, iteration will stop. - * - * @param {CID} key - The CID key of the content to find - * @param {object} [options] - * @param {number} [options.timeout] - How long the query should run - * @param {number} [options.maxNumProviders] - maximum number of providers to find - * @returns {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>} - */ - async * findProviders (key, options) { - if (!routers.length) { - throw errCode(new Error('No content routers available'), 'NO_ROUTERS_AVAILABLE') - } - - const result = await pAny( - routers.map(async (router) => { - const provs = await all(router.findProviders(key, options)) - - if (!provs || !provs.length) { - throw errCode(new Error('not found'), 'NOT_FOUND') - } - return provs - }) - ) - - for (const peer of result) { - yield peer - } - }, - - /** - * Iterates over all content routers in parallel to notify it is - * a provider of the given key. - * - * @param {CID} key - The CID key of the content to find - * @returns {Promise} - */ - async provide (key) { // eslint-disable-line require-await - if (!routers.length) { - throw errCode(new Error('No content routers available'), 'NO_ROUTERS_AVAILABLE') - } - - return Promise.all(routers.map((router) => router.provide(key))) - }, - - /** - * Store the given key/value pair in the DHT. - * - * @param {Uint8Array} key - * @param {Uint8Array} value - * @param {Object} [options] - put options - * @param {number} [options.minPeers] - minimum number of peers required to successfully put - * @returns {Promise} - */ - async put (key, value, options) { // eslint-disable-line require-await - if (!node.isStarted() || !dht.isStarted) { - throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED) - } - - return dht.put(key, value, options) - }, - - /** - * Get the value to the given key. - * Times out after 1 minute by default. - * - * @param {Uint8Array} key - * @param {Object} [options] - get options - * @param {number} [options.timeout] - optional timeout (default: 60000) - * @returns {Promise} - */ - async get (key, options) { // eslint-disable-line require-await - if (!node.isStarted() || !dht.isStarted) { - throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED) - } - - return dht.get(key, options) - }, - - /** - * Get the `n` values to the given key without sorting. - * - * @param {Uint8Array} key - * @param {number} nVals - * @param {Object} [options] - get options - * @param {number} [options.timeout] - optional timeout (default: 60000) - * @returns {Promise} - */ - async getMany (key, nVals, options) { // eslint-disable-line require-await - if (!node.isStarted() || !dht.isStarted) { - throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED) - } - - return dht.getMany(key, nVals, options) + // If we have the dht, make it first + if (this.dht) { + this.routers.unshift(this.dht) } } + + /** + * Iterates over all content routers in series to find providers of the given key. + * Once a content router succeeds, iteration will stop. + * + * @param {CID} key - The CID key of the content to find + * @param {object} [options] + * @param {number} [options.timeout] - How long the query should run + * @param {number} [options.maxNumProviders] - maximum number of providers to find + * @returns {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>} + */ + async * findProviders (key, options) { + if (!this.routers.length) { + throw errCode(new Error('No content this.routers available'), 'NO_ROUTERS_AVAILABLE') + } + + const result = await pAny( + this.routers.map(async (router) => { + const provs = await all(router.findProviders(key, options)) + + if (!provs || !provs.length) { + throw errCode(new Error('not found'), 'NOT_FOUND') + } + return provs + }) + ) + + for (const peer of result) { + yield peer + } + } + + /** + * Iterates over all content routers in parallel to notify it is + * a provider of the given key. + * + * @param {CID} key - The CID key of the content to find + * @returns {Promise} + */ + async provide (key) { // eslint-disable-line require-await + if (!this.routers.length) { + throw errCode(new Error('No content routers available'), 'NO_ROUTERS_AVAILABLE') + } + + return Promise.all(this.routers.map((router) => router.provide(key))) + } + + /** + * Store the given key/value pair in the DHT. + * + * @param {Uint8Array} key + * @param {Uint8Array} value + * @param {Object} [options] - put options + * @param {number} [options.minPeers] - minimum number of peers required to successfully put + * @returns {Promise} + */ + async put (key, value, options) { // eslint-disable-line require-await + if (!this.libp2p.isStarted() || !this.dht.isStarted) { + throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED) + } + + return this.dht.put(key, value, options) + } + + /** + * Get the value to the given key. + * Times out after 1 minute by default. + * + * @param {Uint8Array} key + * @param {Object} [options] - get options + * @param {number} [options.timeout] - optional timeout (default: 60000) + * @returns {Promise} + */ + async get (key, options) { // eslint-disable-line require-await + if (!this.libp2p.isStarted() || !this.dht.isStarted) { + throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED) + } + + return this.dht.get(key, options) + } + + /** + * Get the `n` values to the given key without sorting. + * + * @param {Uint8Array} key + * @param {number} nVals + * @param {Object} [options] - get options + * @param {number} [options.timeout] - optional timeout (default: 60000) + * @returns {Promise} + */ + async getMany (key, nVals, options) { // eslint-disable-line require-await + if (!this.libp2p.isStarted() || !this.dht.isStarted) { + throw errCode(new Error(messages.NOT_STARTED_YET), codes.DHT_NOT_STARTED) + } + + return this.dht.getMany(key, nVals, options) + } } + +module.exports = ContentRouting diff --git a/src/index.js b/src/index.js index 175dd724..f7daaa4c 100644 --- a/src/index.js +++ b/src/index.js @@ -11,7 +11,7 @@ const errCode = require('err-code') const PeerId = require('peer-id') const PeerRouting = require('./peer-routing') -const contentRouting = require('./content-routing') +const ContentRouting = require('./content-routing') const getPeer = require('./get-peer') const { validate: validateConfig } = require('./config') const { codes, messages } = require('./errors') @@ -242,7 +242,7 @@ class Libp2p extends EventEmitter { // Attach remaining APIs // peer and content routing will automatically get modules from _modules and _dht this.peerRouting = new PeerRouting(this) - this.contentRouting = contentRouting(this) + this.contentRouting = new ContentRouting(this) // Mount default protocols ping.mount(this)