This repository was archived by the owner on Feb 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat: reprovider #2184
Closed
Closed
feat: reprovider #2184
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
'use strict' | ||
|
||
const errCode = require('err-code') | ||
const human = require('human-to-milliseconds') | ||
const promisify = require('promisify-es6') | ||
const assert = require('assert') | ||
|
||
const CID = require('cids') | ||
|
||
const Reprovider = require('./reprovider') | ||
|
||
class Provider { | ||
/** | ||
* Provider goal is to announce blocks to the network. | ||
* It keeps track of which blocks are provided, and allow them to be reprovided | ||
* @param {Libp2p} libp2p libp2p instance | ||
* @param {Blockstore} blockstore blockstore instance | ||
* @param {object} options reprovider options | ||
* @param {string} options.delay reprovider initial delay in human friendly time | ||
* @param {string} options.interval reprovider interval in human friendly time | ||
* @param {string} options.strategy reprovider strategy | ||
*/ | ||
constructor (libp2p, blockstore, options = {}) { | ||
// Assert options | ||
this._validateOptions(options) | ||
|
||
this._running = false | ||
|
||
this._contentRouting = libp2p.contentRouting | ||
this._blockstore = blockstore | ||
|
||
// handle options (config uses uppercase) | ||
const humanDelay = options.Delay || options.delay || '15s' | ||
const delay = human(humanDelay) | ||
const humanInterval = options.Interval || options.interval || '12h' | ||
const interval = human(humanInterval) | ||
const strategy = options.Strategy || options.strategy || 'all' | ||
|
||
this._options = { | ||
delay, | ||
interval, | ||
strategy | ||
} | ||
|
||
this.reprovider = new Reprovider(this._contentRouting, this._blockstore, this._options) | ||
|
||
} | ||
|
||
/** | ||
* Begin processing the provider work | ||
* @returns {void} | ||
*/ | ||
async start () { | ||
// do not run twice | ||
if (this._running) { | ||
return | ||
} | ||
|
||
this._running = true | ||
|
||
// Start reprovider | ||
this.reprovider.start() | ||
} | ||
|
||
/** | ||
* Stop the provider | ||
* @returns {void} | ||
*/ | ||
stop () { | ||
this._running = false | ||
|
||
// stop the reprovider | ||
this.reprovider.stop() | ||
} | ||
|
||
/** | ||
* Announce block to the network | ||
* Takes a cid and makes an attempt to announce it to the network | ||
* @param {CID} cid | ||
*/ | ||
async provide (cid) { | ||
if (!CID.isCID(cid)) { | ||
throw errCode('invalid CID to provide', 'ERR_INVALID_CID') | ||
} | ||
|
||
await promisify((callback) => { | ||
this._contentRouting.provide(cid, callback) | ||
})() | ||
} | ||
|
||
/** | ||
* Find providers of a block in the network | ||
* @param {CID} cid cid of the block | ||
* @param {object} options | ||
* @param {number} options.timeout - how long the query should maximally run, in ms (default: 60000) | ||
* @param {number} options.maxNumProviders - maximum number of providers to find | ||
* @returns {Promise} | ||
*/ | ||
async findProviders (cid, options) { // eslint-disable-line require-await | ||
if (!CID.isCID(cid)) { | ||
throw errCode('invalid CID to find', 'ERR_INVALID_CID') | ||
} | ||
|
||
return promisify((callback) => { | ||
this._contentRouting.findProviders(cid, options, callback) | ||
})() | ||
} | ||
|
||
// Validate Provider options | ||
_validateOptions (options) { | ||
const delay = (options.Delay || options.delay) | ||
assert(delay && parseInt(delay) !== 0, '0 delay is not a valid value for reprovider') | ||
|
||
const interval = (options.Interval || options.interval) | ||
assert(interval && parseInt(interval) !== 0, '0 interval is not a valid value for reprovider') | ||
|
||
const strategy = (options.Strategy || options.strategy) | ||
assert(strategy && (strategy === 'all' || strategy === 'pinned' || strategy === 'roots'), | ||
'Reprovider must have one of the following strategies: `all`, `pinned` or `roots`') | ||
} | ||
} | ||
|
||
exports = module.exports = Provider |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
'use strict' | ||
|
||
const { default: PQueue } = require('p-queue') | ||
|
||
const debug = require('debug') | ||
const log = debug('ipfs:provider') | ||
log.error = debug('ipfs:provider:error') | ||
|
||
class WorkerQueue { | ||
vasco-santos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/** | ||
* Creates an instance of a WorkerQueue. | ||
* @param {function} executeWork | ||
* @param {number} [concurrency=3] | ||
*/ | ||
constructor (executeWork, concurrency = 3) { | ||
this.executeWork = executeWork | ||
this._concurrency = concurrency | ||
|
||
this.running = false | ||
this.queue = new PQueue({ concurrency }) | ||
} | ||
|
||
/** | ||
* Use the queue from async to keep `concurrency` amount items running | ||
* @param {Block[]} blocks | ||
*/ | ||
async execute (blocks) { | ||
this.running = true | ||
|
||
// Fill queue with the processing blocks function | ||
this.queue.addAll(blocks.map((block) => async () => this._processNext(block))) // eslint-disable-line require-await | ||
|
||
// Wait for finishing | ||
await this.queue.onIdle() | ||
|
||
this.stop() | ||
} | ||
|
||
/** | ||
* Stop the worker | ||
*/ | ||
stop () { | ||
if (!this.running) { | ||
return | ||
} | ||
|
||
this.running = false | ||
this.queue.clear() | ||
} | ||
|
||
/** | ||
* Process the next block in the queue. | ||
* @param {Block} block | ||
*/ | ||
async _processNext (block) { | ||
if (!this.running) { | ||
return | ||
} | ||
|
||
// Execute work | ||
log('queue:work') | ||
|
||
let execErr | ||
try { | ||
await this.executeWork(block) | ||
} catch (err) { | ||
execErr = err | ||
} | ||
|
||
log('queue:work:done', execErr) | ||
} | ||
} | ||
|
||
exports = module.exports = WorkerQueue |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.