Skip to content
This repository was archived by the owner on Feb 12, 2024. It is now read-only.

Commit 587c2f2

Browse files
committed
feat: reprovider
1 parent 0287a6c commit 587c2f2

File tree

10 files changed

+222
-16
lines changed

10 files changed

+222
-16
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@
8989
"hapi-pino": "^6.0.0",
9090
"human-to-milliseconds": "^1.0.0",
9191
"interface-datastore": "~0.6.0",
92-
"ipfs-bitswap": "~0.24.1",
92+
"ipfs-bitswap": "ipfs/js-ipfs-bitswap#feat/use-ipfs-provider",
9393
"ipfs-block": "~0.8.1",
9494
"ipfs-block-service": "~0.15.1",
9595
"ipfs-http-client": "^32.0.0",
Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
'use strict'
22

3-
const CID = require('cids')
4-
const base32 = require('base32.js')
53
const pull = require('pull-stream')
64
const pullDefer = require('pull-defer')
5+
const { blockKeyToCid } = require('../../utils')
76

87
module.exports = function (self) {
98
return () => {
@@ -14,21 +13,12 @@ module.exports = function (self) {
1413
return deferred.resolve(pull.error(err))
1514
}
1615

17-
const refs = blocks.map(b => dsKeyToRef(b.key))
16+
const refs = blocks.map(b => ({
17+
ref: blockKeyToCid(b.key).toString()
18+
}))
1819
deferred.resolve(pull.values(refs))
1920
})
2021

2122
return deferred
2223
}
2324
}
24-
25-
function dsKeyToRef (key) {
26-
try {
27-
// Block key is of the form /<base32 encoded string>
28-
const decoder = new base32.Decoder()
29-
const buff = Buffer.from(decoder.write(key.toString().slice(1)).finalize())
30-
return { ref: new CID(buff).toString() }
31-
} catch (err) {
32-
return { err: `Could not convert block with key '${key}' to CID: ${err.message}` }
33-
}
34-
}

src/core/components/start.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
'use strict'
22

3+
const get = require('dlv')
34
const series = require('async/series')
45
const Bitswap = require('ipfs-bitswap')
56
const setImmediate = require('async/setImmediate')
67
const promisify = require('promisify-es6')
78

89
const IPNS = require('../ipns')
10+
const Provider = require('../provider')
911
const routingConfig = require('../ipns/routing/config')
1012
const createLibp2pBundle = require('./libp2p')
1113

@@ -45,6 +47,8 @@ module.exports = (self) => {
4547
libp2p.start(err => {
4648
if (err) return cb(err)
4749
self.libp2p = libp2p
50+
51+
self._provider = new Provider(libp2p, self._repo.blocks, get(config, 'Reprovider'))
4852
cb()
4953
})
5054
})
@@ -56,9 +60,15 @@ module.exports = (self) => {
5660
self._bitswap = new Bitswap(
5761
self.libp2p,
5862
self._repo.blocks,
63+
self._provider,
5964
{ statsEnabled: true }
6065
)
6166

67+
if (!get(self._options, 'offline') &&
68+
(get(self._options, 'libp2p.config.dht.enabled', false) || get(self._options, 'libp2p.modules.contentRouting', false))) {
69+
self._provider.start()
70+
}
71+
6272
self._bitswap.start()
6373
self._blockService.setExchange(self._bitswap)
6474

src/core/provider/index.js

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
'use strict'
2+
3+
const errCode = require('err-code')
4+
const human = require('human-to-milliseconds')
5+
const promisify = require('promisify-es6')
6+
7+
const CID = require('cids')
8+
9+
const Reprovider = require('./reprovider')
10+
11+
class Provider {
12+
/**
13+
* Provider goal is to announce blocks to the network.
14+
* It keeps track of which blocks are provided, and allow them to be reprovided
15+
* @param {Libp2p} libp2p
16+
* @param {Blockstore} blockstore
17+
* @param {object} options
18+
* @memberof Provider
19+
*/
20+
constructor (libp2p, blockstore, options) {
21+
// the CIDs for which provide announcements should be made
22+
// this.tracker = [] // TODO queue
23+
this._running = false
24+
25+
this._contentRouting = libp2p.contentRouting
26+
this._blockstore = blockstore
27+
this._options = options
28+
this.reprovider = undefined
29+
}
30+
31+
/**
32+
* Begin processing the provider work
33+
* @returns {void}
34+
*/
35+
async start () {
36+
// do not run twice
37+
if (this._running) {
38+
return
39+
}
40+
41+
this._running = true
42+
43+
// handle options
44+
const strategy = this._options.strategy || 'all'
45+
const humanInterval = this._options.Interval || '12h'
46+
const interval = await promisify((callback) => human(humanInterval, callback))()
47+
const options = {
48+
interval,
49+
strategy
50+
}
51+
52+
this.reprovider = new Reprovider(this._contentRouting, this._blockstore, options)
53+
54+
// Start reprovider
55+
this.reprovider.start()
56+
}
57+
58+
/**
59+
* Stop the provider
60+
* @returns {void}
61+
*/
62+
stop () {
63+
this._running = true
64+
65+
// stop the reprovider
66+
return this.reprovider.stop()
67+
}
68+
69+
/**
70+
* Announce block to the network and add and entry to the tracker
71+
* Takes a cid and makes an attempt to announce it to the network
72+
* @param {CID} cid
73+
*/
74+
async provide (cid) {
75+
if (!CID.isCID(cid)) {
76+
throw errCode('invalid CID to provide', 'ERR_INVALID_CID')
77+
}
78+
79+
await promisify((callback) => {
80+
this._contentRouting.provide(cid, callback)
81+
})()
82+
}
83+
84+
async findProviders (cid, options) { // eslint-disable-line require-await
85+
if (!CID.isCID(cid)) {
86+
throw errCode('invalid CID to find', 'ERR_INVALID_CID')
87+
}
88+
89+
return promisify((callback) => {
90+
this._contentRouting.findProviders(cid, options, callback)
91+
})()
92+
}
93+
}
94+
95+
exports = module.exports = Provider

src/core/provider/queue.js

Whitespace-only changes.

src/core/provider/reprovider.js

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
'use strict'
2+
3+
const promisify = require('promisify-es6')
4+
5+
const { blockKeyToCid } = require('../utils')
6+
7+
// const initialDelay = 10000
8+
const initialDelay = 5000
9+
10+
class Reprovider {
11+
/**
12+
* Reprovider goal is t§o reannounce blocks to the network.
13+
* @param {object} contentRouting
14+
* @param {Blockstore} blockstore
15+
* @param {object} options
16+
* @memberof Reprovider
17+
*/
18+
constructor (contentRouting, blockstore, options) {
19+
this._contentRouting = contentRouting
20+
this._blockstore = blockstore
21+
this._options = options
22+
23+
this._timeoutId = undefined
24+
}
25+
26+
/**
27+
* Begin processing the reprovider work and waiting for reprovide triggers
28+
* @returns {void}
29+
*/
30+
start () {
31+
// Start doing reprovides after the initial delay
32+
this._timeoutId = setTimeout(() => {
33+
// start runner immediately
34+
this._runPeriodically()
35+
}, initialDelay)
36+
}
37+
38+
/**
39+
* Stops the reprovider. Any active reprovide actions should be aborted
40+
* @returns {void}
41+
*/
42+
stop () {
43+
if (this._timeoutId) {
44+
clearTimeout(this._timeoutId)
45+
this._timeoutId = undefined
46+
}
47+
}
48+
49+
/**
50+
* Run reprovide on every `options.interval` ms
51+
* @private
52+
* @returns {void}
53+
*/
54+
async _runPeriodically () {
55+
while (this._timeoutId) {
56+
const blocks = await promisify((callback) => this._blockstore.query({}, callback))()
57+
58+
await this._reprovide(blocks)
59+
60+
// Each subsequent walk should run on a `this._options.interval` interval
61+
await new Promise(resolve => {
62+
this._timeoutId = setTimeout(resolve, this._options.interval)
63+
})
64+
}
65+
}
66+
67+
/**
68+
* Do the reprovide work to libp2p content routing
69+
* @param {Block[]} blocks blocks in Blockstore
70+
* @private
71+
* @returns {void}
72+
*/
73+
async _reprovide (blocks) { // eslint-disable-line require-await
74+
// TODO: Async queue
75+
for (let i = 0; i < blocks.length && this._timeoutId; i++) {
76+
// const cid = blockKeyToCid(blocks[i].key.toBuffer())
77+
78+
// console.log('cid', cid)
79+
// TODO: needs the DHT / Content Routing
80+
// await promisify((callback) => {
81+
// this._contentRouting.provide(cid, callback)
82+
// })()
83+
}
84+
}
85+
}
86+
87+
exports = module.exports = Reprovider

src/core/runtime/config-browser.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ module.exports = () => ({
2626
'/dns4/node0.preload.ipfs.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
2727
'/dns4/node1.preload.ipfs.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6'
2828
],
29+
Reprovider: {
30+
Interval: '12h',
31+
Strategy: 'all'
32+
},
2933
Swarm: {
3034
ConnMgr: {
3135
LowWater: 200,

src/core/runtime/config-nodejs.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ module.exports = () => ({
3939
'/dns4/node0.preload.ipfs.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
4040
'/dns4/node1.preload.ipfs.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6'
4141
],
42+
Reprovider: {
43+
Interval: '12h',
44+
Strategy: 'all'
45+
},
4246
Swarm: {
4347
ConnMgr: {
4448
LowWater: 200,

src/core/utils.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const promisify = require('promisify-es6')
44
const map = require('async/map')
55
const isIpfs = require('is-ipfs')
66
const CID = require('cids')
7+
const base32 = require('base32.js')
78

89
const ERR_BAD_PATH = 'ERR_BAD_PATH'
910
exports.OFFLINE_ERROR = 'This command must be run in online mode. Try running \'ipfs daemon\' first.'
@@ -134,7 +135,22 @@ const resolvePath = promisify(function (objectAPI, ipfsPaths, callback) {
134135
}
135136
}, callback)
136137
})
138+
/**
139+
* Convert a block key to cid
140+
* @param {Key} key form /<base32 encoded string>
141+
* @returns {CID}
142+
*/
143+
function blockKeyToCid (key) {
144+
try {
145+
const decoder = new base32.Decoder()
146+
const buff = Buffer.from(decoder.write(key.toString().slice(1)).finalize())
147+
return new CID(buff)
148+
} catch (err) {
149+
return { err: `Could not convert block with key '${key}' to CID: ${err.message}` }
150+
}
151+
}
137152

138153
exports.normalizePath = normalizePath
139154
exports.parseIpfsPath = parseIpfsPath
140155
exports.resolvePath = resolvePath
156+
exports.blockKeyToCid = blockKeyToCid

test/core/kad-dht.node.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ function createNode (callback) {
3232
}, callback)
3333
}
3434

35-
describe('kad-dht is routing content and peers correctly', () => {
35+
describe.only('kad-dht is routing content and peers correctly', () => {
3636
let nodeA
3737
let nodeB
3838
let nodeC

0 commit comments

Comments
 (0)