From 411111c83aac2fa84a0520e42e2f1318815518cf Mon Sep 17 00:00:00 2001 From: Marcin Rataj Date: Wed, 24 Jul 2019 11:33:32 +0200 Subject: [PATCH] fix: limit concurrent HTTP requests 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' }) })