mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-06-17 11:11:21 +00:00
feat: discover and connect to closest peers (#798)
This commit is contained in:
committed by
Vasco Santos
parent
4ebcdb085c
commit
baedf3fe5a
@ -1,40 +1,126 @@
|
||||
'use strict'
|
||||
|
||||
const errCode = require('err-code')
|
||||
const debug = require('debug')
|
||||
const log = debug('libp2p:peer-routing')
|
||||
log.error = debug('libp2p:peer-routing:error')
|
||||
|
||||
const all = require('it-all')
|
||||
const pAny = require('p-any')
|
||||
const {
|
||||
setDelayedInterval,
|
||||
clearDelayedInterval
|
||||
} = require('set-delayed-interval')
|
||||
|
||||
module.exports = (node) => {
|
||||
const routers = node._modules.peerRouting || []
|
||||
/**
|
||||
* Responsible for managing the usage of the available Peer Routing modules.
|
||||
*/
|
||||
class PeerRouting {
|
||||
/**
|
||||
* @class
|
||||
* @param {Libp2p} libp2p
|
||||
*/
|
||||
constructor (libp2p) {
|
||||
this._peerId = libp2p.peerId
|
||||
this._peerStore = libp2p.peerStore
|
||||
this._routers = libp2p._modules.peerRouting || []
|
||||
|
||||
// If we have the dht, make it first
|
||||
if (node._dht) {
|
||||
routers.unshift(node._dht)
|
||||
// If we have the dht, make it first
|
||||
if (libp2p._dht) {
|
||||
this._routers.unshift(libp2p._dht)
|
||||
}
|
||||
|
||||
this._refreshManagerOptions = libp2p._options.peerRouting.refreshManager
|
||||
|
||||
this._findClosestPeersTask = this._findClosestPeersTask.bind(this)
|
||||
}
|
||||
|
||||
return {
|
||||
/**
|
||||
* Iterates over all peer routers in series to find the given peer.
|
||||
*
|
||||
* @param {string} id - The id of the peer to find
|
||||
* @param {object} [options]
|
||||
* @param {number} [options.timeout] - How long the query should run
|
||||
* @returns {Promise<{ id: PeerId, multiaddrs: Multiaddr[] }>}
|
||||
*/
|
||||
findPeer: async (id, options) => { // eslint-disable-line require-await
|
||||
if (!routers.length) {
|
||||
throw errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE')
|
||||
/**
|
||||
* Start peer routing service.
|
||||
*/
|
||||
start () {
|
||||
if (!this._routers.length || this._timeoutId || !this._refreshManagerOptions.enabled) {
|
||||
return
|
||||
}
|
||||
|
||||
this._timeoutId = setDelayedInterval(
|
||||
this._findClosestPeersTask, this._refreshManagerOptions.interval, this._refreshManagerOptions.bootDelay
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Recurrent task to find closest peers and add their addresses to the Address Book.
|
||||
*/
|
||||
async _findClosestPeersTask () {
|
||||
try {
|
||||
for await (const { id, multiaddrs } of this.getClosestPeers(this._peerId.id)) {
|
||||
this._peerStore.addressBook.add(id, multiaddrs)
|
||||
}
|
||||
} catch (err) {
|
||||
log.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop peer routing service.
|
||||
*/
|
||||
stop () {
|
||||
clearDelayedInterval(this._timeoutId)
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all peer routers in series to find the given peer.
|
||||
*
|
||||
* @param {string} id - The id of the peer to find
|
||||
* @param {object} [options]
|
||||
* @param {number} [options.timeout] - How long the query should run
|
||||
* @returns {Promise<{ id: PeerId, multiaddrs: Multiaddr[] }>}
|
||||
*/
|
||||
async findPeer (id, options) { // eslint-disable-line require-await
|
||||
if (!this._routers.length) {
|
||||
throw errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE')
|
||||
}
|
||||
|
||||
return pAny(this._routers.map(async (router) => {
|
||||
const result = await router.findPeer(id, options)
|
||||
|
||||
// If we don't have a result, we need to provide an error to keep trying
|
||||
if (!result || Object.keys(result).length === 0) {
|
||||
throw errCode(new Error('not found'), 'NOT_FOUND')
|
||||
}
|
||||
|
||||
return pAny(routers.map(async (router) => {
|
||||
const result = await router.findPeer(id, options)
|
||||
return result
|
||||
}))
|
||||
}
|
||||
|
||||
// If we don't have a result, we need to provide an error to keep trying
|
||||
if (!result || Object.keys(result).length === 0) {
|
||||
/**
|
||||
* Attempt to find the closest peers on the network to the given key.
|
||||
*
|
||||
* @param {Uint8Array} key - A CID like key
|
||||
* @param {Object} [options]
|
||||
* @param {number} [options.timeout=30e3] - How long the query can take.
|
||||
* @returns {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>}
|
||||
*/
|
||||
async * getClosestPeers (key, options = { timeout: 30e3 }) {
|
||||
if (!this._routers.length) {
|
||||
throw errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE')
|
||||
}
|
||||
|
||||
const result = await pAny(
|
||||
this._routers.map(async (router) => {
|
||||
const peers = await all(router.getClosestPeers(key, options))
|
||||
|
||||
if (!peers || !peers.length) {
|
||||
throw errCode(new Error('not found'), 'NOT_FOUND')
|
||||
}
|
||||
return peers
|
||||
})
|
||||
)
|
||||
|
||||
return result
|
||||
}))
|
||||
for (const peer of result) {
|
||||
yield peer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PeerRouting
|
||||
|
Reference in New Issue
Block a user