From e844d303931dde731e52ea437c67d0f0b9f50197 Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 24 Jul 2019 15:41:49 +0200 Subject: [PATCH] fix: limit concurrent HTTP requests (#12) All HTTP requests made by this module are sent to the same delegate host. Browsers throttle the number of concurrent requests per hostname, right now it is 6 per host, which suffocates the use of delegate and blocking it from being used for preload or delegated content routing. This introduces a task queue that limits the number of concurrent requests, making it safe to run in browser context. See also: https://github.com/libp2p/js-libp2p-delegated-content-routing/issues/12 License: MIT Signed-off-by: Marcin Rataj --- .gitignore | 3 ++- package.json | 2 ++ src/index.js | 22 +++++++++++++++++++--- test/index.spec.js | 4 ++-- 4 files changed, 25 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index f86e967..5801c69 100644 --- a/.gitignore +++ b/.gitignore @@ -61,4 +61,5 @@ docs .env yarn.lock -package-lock.json \ No newline at end of file +package-lock.json +dist/ diff --git a/package.json b/package.json index 664335f..0a68e15 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,9 @@ "ipfsd-ctl": "^0.44.1" }, "dependencies": { + "debug": "^4.1.1", "ipfs-http-client": "^33.1.0", + "p-queue": "^6.1.0", "peer-id": "~0.12.2" }, "contributors": [ diff --git a/src/index.js b/src/index.js index 8446d1c..56f2ce8 100644 --- a/src/index.js +++ b/src/index.js @@ -3,18 +3,31 @@ const PeerId = require('peer-id') const dht = require('ipfs-http-client/src/dht') const defaultConfig = require('ipfs-http-client/src/utils/default-config') +const { default: PQueue } = require('p-queue') +const debug = require('debug') + +const log = debug('libp2p-delegated-peer-routing') +log.error = debug('libp2p-delegated-peer-routing:error') const DEFAULT_MAX_TIMEOUT = 30e3 // 30 second default const DEFAULT_IPFS_API = { protocol: 'https', port: 443, - host: 'ipfs.io' + host: 'node0.delegate.ipfs.io' } +const CONCURRENT_HTTP_REQUESTS = 4 class DelegatedPeerRouting { constructor (api) { this.api = Object.assign({}, defaultConfig(), DEFAULT_IPFS_API, api) this.dht = dht(this.api) + + // limit concurrency to avoid request flood in web browser + // https://github.com/libp2p/js-libp2p-delegated-content-routing/issues/12 + this._httpQueue = new PQueue({ + concurrency: CONCURRENT_HTTP_REQUESTS + }) + log(`enabled DelegatedPeerRouting via ${this.api.protocol}://${this.api.host}:${this.api.port}`) } /** @@ -29,19 +42,22 @@ class DelegatedPeerRouting { if (PeerId.isPeerId(id)) { id = id.toB58String() } + log('findPeer starts: ' + id) options.maxTimeout = options.maxTimeout || DEFAULT_MAX_TIMEOUT try { - return await this.dht.findPeer(id, { + return await this._httpQueue.add(() => this.dht.findPeer(id, { timeout: `${options.maxTimeout}ms`// The api requires specification of the time unit (s/ms) - }) + })) } catch (err) { if (err.message.includes('not found')) { return undefined } throw err + } finally { + log('findPeer finished: ' + id) } } } diff --git a/test/index.spec.js b/test/index.spec.js index 59f69a5..b162b25 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -64,14 +64,14 @@ describe('DelegatedPeerRouting', function () { }) describe('create', () => { - it('should default to https://ipfs.io as the delegate', () => { + it('should default to https://node0.delegate.ipfs.io as the delegate', () => { const router = new DelegatedPeerRouting() expect(router.api).to.include({ 'api-path': '/api/v0/', protocol: 'https', port: 443, - host: 'ipfs.io' + host: 'node0.delegate.ipfs.io' }) })