mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-05-16 12:31:20 +00:00
chore: minor fixes and initial tests added
This commit is contained in:
parent
8dab477aca
commit
72dea969c3
@ -6,9 +6,7 @@ The PeerStore needs to manage the high level operations on its inner books. More
|
||||
|
||||
(Future considerations: Peerstore should manage a job runner to trigger books runners for data trimming or computations)
|
||||
|
||||
## Peers Environment
|
||||
|
||||
#### Sense
|
||||
## Data gathering
|
||||
|
||||
Several libp2p subsystems will perform operations, which will gather relevant information about peers. Some operations might not have this as an end goal, but can also gather important data.
|
||||
|
||||
@ -27,13 +25,13 @@ While it is currently not supported in js-libp2p, future iterations may also sup
|
||||
|
||||
It is also possible to gather relevant information for peers from other protocols / subsystems. For instance, in `DHT` operations, nodes can exchange peer data as part of the `DHT` operation. In this case, we can learn additional information about a peer we already know. In this scenario the `PeerStore` should not replace the existing data it has, just add it.
|
||||
|
||||
#### Act
|
||||
## Data Consumption
|
||||
|
||||
When the `PeerStore` data is updated, this information might be important for different parties.
|
||||
|
||||
`js-libp2p` keeps a topology of peers for each protocol a node is running. This way, once a protocol is supported for a peer, the topology of that protocol should be informed that a new peer may be used and the subsystem can decide if it should open a new stream it that peer or not.
|
||||
Every time a peer needs to dial another peer, it is essential that it knows the multiaddrs used by the peer, in order to perform a successful dial to a peer. The same is true for pinging a peer. While the `AddressBook` is going to keep its data updated, it will also emit `change:multiaddrs` events so that subsystems/users interested in knowing these changes can be notifyied instead of pooling the `AddressBook`.
|
||||
|
||||
Every time a peer needs to dial another peer, it is essential that it knows the multiaddrs used by the peer, in order to perform a successful dial to a peer. The same is true for pinging a peer.
|
||||
Everytime a peer starts/stops supporting a protocol, libp2p subsystems or users might need to act accordingly. `js-libp2p` registrar orchestrates known peers, established connections and protocol topologies. This way, once a protocol is supported for a peer, the topology of that protocol should be informed that a new peer may be used and the subsystem can decide if it should open a new stream with that peer or not. For these situations, the `ProtoBook` will emit `change:protocols` events whenever supported protocols of a peer change.
|
||||
|
||||
## PeerStore implementation
|
||||
|
||||
@ -48,60 +46,17 @@ Access to its underlying books:
|
||||
|
||||
High level operations:
|
||||
|
||||
- `peerStore.set(peerId, data, options)` or `events`
|
||||
- `peerStore.delete(peerId)`
|
||||
|
||||
High level set which should be able to identify the type of data received and forward to the appropriate book sets. More than a bridge, this aims to allow the combination of multiple data storage as follows:
|
||||
Deletes the provided peer from every book.
|
||||
|
||||
`data = { multiaddrs: [...], protocols: [...] }`
|
||||
- `peerStore.find(peerId)`
|
||||
|
||||
---- (should be removed / re-written, but important for design decisions)
|
||||
TODO (Move to API.doc and reference)
|
||||
|
||||
One aspect that we need to consider is wether we should add information to every book, even if we don't have any relevant information for it. For instance, if we just discover a peer via a typical discovery service, we will have the `peerId` and an array of `multiaddr`. When we do `peerStore.set()`, should we also do `protoBook.set()` with an empty list of protocols? I don't see any advantage on adding to the remaining ones.
|
||||
- `peerStore.peers()`
|
||||
|
||||
**IMPORTANT:** This is one of the biggest design decisions to make (set vs events). The programmatic API is the easiest solution but it can provide users an API that they sould not need. If we go on an event-based approach, the `peerStore` should receive all the relevant subsystems (discovery, identifyService, ...) and sense the environment (via events) to gather the information that would need to be sent via the API. Thile the latest seems the best solution, it is the more complex one to implement, as we would ideally have an interface that those subsystems would need to implement and each time we have a new subsystem that needs to add data to the peerStore, we might need to update the `peer-store` codebase (or have a good set of abstractions).
|
||||
|
||||
It is also important pointing out that users would be able to use `peerStore.protoBook.*`, so eventually we should move those into `peerStore._ protoBook.*` if we do not intend them to use it.
|
||||
|
||||
---
|
||||
|
||||
- `peerStore.get(peerId, options)`
|
||||
|
||||
Get the information of a provided peer. The amount of information that we want can be customized with the following options, which are true by default:
|
||||
|
||||
```js
|
||||
{
|
||||
address: true,
|
||||
proto: true,
|
||||
key: true,
|
||||
metadata: true
|
||||
}
|
||||
```
|
||||
|
||||
- `peerStore.delete(peerId, [data])`
|
||||
|
||||
Deletes the provided peer from every book. If data is provided, just remove the data from the books. The data should be provided as follows:
|
||||
|
||||
```js
|
||||
{
|
||||
address: [],
|
||||
proto: [],
|
||||
key: [],
|
||||
metadata: []
|
||||
}
|
||||
```
|
||||
|
||||
- `peerStore.peers(options)`
|
||||
|
||||
Get an array of all the peers, as well as their information. The information intended can be customized with the following options, which are true by default:
|
||||
|
||||
```js
|
||||
{
|
||||
address: true,
|
||||
proto: true,
|
||||
key: true,
|
||||
metadata: true
|
||||
}
|
||||
```
|
||||
Get an array of all the peers, as well as their information.
|
||||
|
||||
## Address Book
|
||||
|
||||
@ -119,18 +74,17 @@ A `peerId.toString()` identifier mapping to a `multiaddrInfo` object, which shou
|
||||
}
|
||||
```
|
||||
|
||||
**Note:** except for multiaddr namings, the other properties are placeholders for now and might not be as described in the future milestones.
|
||||
**Note:** except for multiaddr naming, the other properties are placeholders for now and might not be as described in the future milestones.
|
||||
|
||||
- `addressBook.data`
|
||||
- `addressBook.set()`
|
||||
- `addressBook.get()`
|
||||
- `getMultiaddrsForPeer()`
|
||||
- `addressBook.has()`
|
||||
- `addressBook.getMultiaddrsForPeer()`
|
||||
- `addressBook.delete()`
|
||||
- `addressBook.peers()`
|
||||
|
||||
It is important pointing out that the API methods which return arrays of data (`set`, `get`, `getMultiaddrsForPeer`) should return the `multiaddr` property of the `multiaddrInfo` and not the entire `multiaddrInfo` as the remaining data should be used internally. Should we consider having two datastructure instead?
|
||||
It is important pointing out that the API methods which return arrays of data (`set`, `get`, `getMultiaddrsForPeer`) should return the `multiaddr` property of the `multiaddrInfo` and not the entire `multiaddrInfo` as the remaining data should be used internally.
|
||||
|
||||
Further API methods will probably be added in the context of multiaddr `ttl` and multiaddr confidence.
|
||||
(Future considerations: Further API methods will probably be added in the context of multiaddr `ttl` and multiaddr confidence.)
|
||||
|
||||
**Not Yet Implemented**: Multiaddr Confidence
|
||||
|
||||
@ -148,12 +102,11 @@ The `protoBook` holds the identifiers of the protocols supported by each peer. T
|
||||
|
||||
A `peerId.toString()` identifier mapping to a `Set` of protocol identifier strings.
|
||||
|
||||
- `protoBook.data`
|
||||
- `protoBook.set()`
|
||||
- `protoBook.get()`
|
||||
- `protoBook.has()`
|
||||
- `protoBook.delete()`
|
||||
- `protoBook.supports()`
|
||||
- `protoBook.peers()`
|
||||
|
||||
## Metadata Book
|
||||
|
||||
|
@ -8,6 +8,8 @@ log.error = debug('libp2p:peer-store:address-book:error')
|
||||
const multiaddr = require('multiaddr')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const Book = require('./book')
|
||||
|
||||
const {
|
||||
ERR_INVALID_PARAMETERS
|
||||
} = require('../errors')
|
||||
@ -16,7 +18,7 @@ const {
|
||||
* The AddressBook is responsible for keeping the known multiaddrs
|
||||
* of a peer.
|
||||
*/
|
||||
class AddressBook {
|
||||
class AddressBook extends Book {
|
||||
/**
|
||||
* MultiaddrInfo object
|
||||
* @typedef {Object} multiaddrInfo
|
||||
@ -30,6 +32,7 @@ class AddressBook {
|
||||
* @param {EventEmitter} peerStore
|
||||
*/
|
||||
constructor (peerStore) {
|
||||
super(peerStore, 'change:multiaddrs', 'multiaddrs')
|
||||
/**
|
||||
* PeerStore Event emitter, used by the AddressBook to emit:
|
||||
* "peer" - emitted when a peer is discovered by the node.
|
||||
@ -41,7 +44,7 @@ class AddressBook {
|
||||
* Map known peers to their known multiaddrs.
|
||||
* @type {Map<string, Array<multiaddrInfo>}
|
||||
*/
|
||||
this.addressBook = new Map()
|
||||
this.data = new Map()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -50,7 +53,7 @@ class AddressBook {
|
||||
* @param {Array<Multiaddr>|Multiaddr} addresses
|
||||
* @param {Object} [options]
|
||||
* @param {boolean} [options.replace = true] wether addresses received replace stored ones or a unique union is performed.
|
||||
* @returns {Array<Multiaddr>}
|
||||
* @returns {Array<multiaddrInfo>}
|
||||
*/
|
||||
set (peerId, addresses, { replace = true } = {}) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
@ -89,11 +92,11 @@ class AddressBook {
|
||||
* If the peer is not known, it is set with the given addresses.
|
||||
* @param {PeerId} peerId
|
||||
* @param {Array<multiaddrInfo>} multiaddrInfos
|
||||
* @returns {Array<string>}
|
||||
* @returns {Array<multiaddrInfo>}
|
||||
*/
|
||||
_replace (peerId, multiaddrInfos) {
|
||||
const id = peerId.toString()
|
||||
const rec = this.addressBook.get(id)
|
||||
const rec = this.data.get(id)
|
||||
|
||||
// Already know the peer
|
||||
if (rec && rec.length === multiaddrInfos.length) {
|
||||
@ -106,7 +109,7 @@ class AddressBook {
|
||||
}
|
||||
}
|
||||
|
||||
this.addressBook.set(id, multiaddrInfos)
|
||||
this.data.set(id, multiaddrInfos)
|
||||
|
||||
this._ps.emit('peer', peerId)
|
||||
this._ps.emit('change:multiaddrs', {
|
||||
@ -122,11 +125,11 @@ class AddressBook {
|
||||
* If the peer is not known, it is set with the given addresses.
|
||||
* @param {PeerId} peerId
|
||||
* @param {Array<multiaddrInfo>} multiaddrInfos
|
||||
* @returns {Array<string>}
|
||||
* @returns {Array<multiaddrInfo>}
|
||||
*/
|
||||
_add (peerId, multiaddrInfos) {
|
||||
const id = peerId.toString()
|
||||
const rec = this.addressBook.get(id) || []
|
||||
const rec = this.data.get(id) || []
|
||||
|
||||
// Add recorded uniquely to the new array
|
||||
rec.forEach((mi) => {
|
||||
@ -137,11 +140,11 @@ class AddressBook {
|
||||
|
||||
// If the recorded length is equal to the new after the uniquely union
|
||||
// The content is the same, no need to update.
|
||||
if (rec.length === multiaddrInfos) {
|
||||
if (rec.length === multiaddrInfos.length) {
|
||||
return [...multiaddrInfos]
|
||||
}
|
||||
|
||||
this.addressBook.set(id, multiaddrInfos)
|
||||
this.data.set(id, multiaddrInfos)
|
||||
this._ps.emit('change:multiaddrs', {
|
||||
peerId,
|
||||
multiaddrs: multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
@ -156,25 +159,6 @@ class AddressBook {
|
||||
return [...multiaddrInfos]
|
||||
}
|
||||
|
||||
/**
|
||||
* Get known addresses of a provided peer.
|
||||
* @param {PeerId} peerId
|
||||
* @returns {Array<Multiaddr>}
|
||||
*/
|
||||
get (peerId) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
const record = this.addressBook.get(peerId.toString())
|
||||
|
||||
if (!record) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return record.map((multiaddrInfo) => multiaddrInfo.multiaddr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the known multiaddrs for a given peer. All returned multiaddrs
|
||||
* will include the encapsulated `PeerId` of the peer.
|
||||
@ -186,7 +170,7 @@ class AddressBook {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
const record = this.addressBook.get(peerId.toString())
|
||||
const record = this.data.get(peerId.toString())
|
||||
|
||||
if (!record) {
|
||||
return undefined
|
||||
@ -199,71 +183,6 @@ class AddressBook {
|
||||
return addr.encapsulate(`/p2p/${peerId.toB58String()}`)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Has known addresses of a provided peer.
|
||||
* @param {PeerId} peerId
|
||||
* @returns {boolean}
|
||||
*/
|
||||
has (peerId) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
return this.addressBook.has(peerId.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the provided peer from the book.
|
||||
* If addresses are provided, just remove the provided addresses and keep the peer.
|
||||
* @param {PeerId} peerId
|
||||
* @param {Array<multiaddr>|multiaddr} [addresses]
|
||||
* @returns {boolean}
|
||||
*/
|
||||
delete (peerId, addresses) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
if (addresses) {
|
||||
return this._remove(peerId, addresses)
|
||||
}
|
||||
|
||||
this._ps('change:multiaddrs', {
|
||||
peerId,
|
||||
multiaddrs: []
|
||||
})
|
||||
|
||||
return this.addressBook.delete(peerId.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given multiaddrs from the provided peer.
|
||||
* @param {PeerId} peerId
|
||||
* @param {Array<multiaddr>|multiaddr} addresses
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_remove (peerId, addresses) {
|
||||
if (!Array.isArray(addresses)) {
|
||||
addresses = [addresses]
|
||||
}
|
||||
|
||||
const record = this.addressBook.get(peerId.toString())
|
||||
|
||||
if (!record) {
|
||||
return false
|
||||
}
|
||||
|
||||
record.filter((mi) => addresses.includes(mi.multiaddr))
|
||||
// TODO: should we keep it if empty?
|
||||
|
||||
this._ps('change:multiaddrs', {
|
||||
peerId,
|
||||
multiaddrs: record.map((multiaddrInfo) => multiaddrInfo.multiaddr)
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AddressBook
|
||||
|
75
src/peer-store/book.js
Normal file
75
src/peer-store/book.js
Normal file
@ -0,0 +1,75 @@
|
||||
'use strict'
|
||||
|
||||
const errcode = require('err-code')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const {
|
||||
ERR_INVALID_PARAMETERS
|
||||
} = require('../errors')
|
||||
|
||||
/**
|
||||
* The Book is the skeleton for the PeerStore books.
|
||||
*/
|
||||
class Book {
|
||||
constructor (eventEmitter, eventName, eventProperty) {
|
||||
this.eventEmitter = eventEmitter
|
||||
this.eventName = eventName
|
||||
this.eventProperty = eventProperty
|
||||
|
||||
/**
|
||||
* Map known peers to their data.
|
||||
* @type {Map<string, Array<Data>}
|
||||
*/
|
||||
this.data = new Map()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set known data of a provided peer.
|
||||
* @param {PeerId} peerId
|
||||
* @param {Array<Data>|Data} data
|
||||
* @param {Object} [options]
|
||||
* @param {boolean} [options.replace = true] wether data received replace stored the one or a unique union is performed.
|
||||
*/
|
||||
set (peerId, data, options) {
|
||||
throw errcode(new Error('set must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the known data of a provided peer.
|
||||
* @param {PeerId} peerId
|
||||
* @returns {Array<Data>}
|
||||
*/
|
||||
get (peerId) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
const rec = this.data.get(peerId.toString())
|
||||
|
||||
return rec ? [...rec] : undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the provided peer from the book.
|
||||
* @param {PeerId} peerId
|
||||
* @returns {boolean}
|
||||
*/
|
||||
delete (peerId) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
if (!this.data.delete(peerId.toString())) {
|
||||
return false
|
||||
}
|
||||
|
||||
this.eventEmitter.emit(this.eventName, {
|
||||
peerId,
|
||||
[this.eventProperty]: []
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Book
|
@ -7,6 +7,8 @@ log.error = debug('libp2p:peer-store:proto-book:error')
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const Book = require('./book')
|
||||
|
||||
const {
|
||||
ERR_INVALID_PARAMETERS
|
||||
} = require('../errors')
|
||||
@ -16,12 +18,14 @@ const {
|
||||
* protocols of a peer.
|
||||
* @fires ProtoBook#change:protocols
|
||||
*/
|
||||
class ProtoBook {
|
||||
class ProtoBook extends Book {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {EventEmitter} peerStore
|
||||
*/
|
||||
constructor (peerStore) {
|
||||
super(peerStore, 'change:protocols', 'protocols')
|
||||
|
||||
/**
|
||||
* PeerStore Event emitter, used by the ProtoBook to emit:
|
||||
* "change:protocols" - emitted when the known protocols of a peer change.
|
||||
@ -32,12 +36,13 @@ class ProtoBook {
|
||||
* Map known peers to their known protocols.
|
||||
* @type {Map<string, Set<string>}
|
||||
*/
|
||||
this.protoBook = new Map()
|
||||
this.data = new Map()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set known protocols of a provided peer.
|
||||
* If the peer was not known before, it will be added.
|
||||
* @override
|
||||
* @param {PeerId} peerId
|
||||
* @param {Array<string>|string} protocols
|
||||
* @param {Object} [options]
|
||||
@ -58,10 +63,10 @@ class ProtoBook {
|
||||
}
|
||||
|
||||
if (replace) {
|
||||
return this._replace(PeerId, protocols)
|
||||
return this._replace(peerId, protocols)
|
||||
}
|
||||
|
||||
return this._add(PeerId, protocols)
|
||||
return this._add(peerId, protocols)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,7 +78,7 @@ class ProtoBook {
|
||||
*/
|
||||
_replace (peerId, protocols) {
|
||||
const id = peerId.toString()
|
||||
const recSet = this.protoBook.get(id)
|
||||
const recSet = this.data.get(id)
|
||||
const newSet = new Set(protocols)
|
||||
|
||||
const isSetEqual = (a, b) => a.size === b.size && [...a].every(value => b.has(value))
|
||||
@ -84,7 +89,7 @@ class ProtoBook {
|
||||
return protocols
|
||||
}
|
||||
|
||||
this.protoBook.set(id, newSet)
|
||||
this.data.set(id, newSet)
|
||||
this._ps.emit('change:protocols', {
|
||||
peerId,
|
||||
protocols
|
||||
@ -102,7 +107,7 @@ class ProtoBook {
|
||||
*/
|
||||
_add (peerId, protocols) {
|
||||
const id = peerId.toString()
|
||||
const recSet = this.protoBook.get(id) || new Set()
|
||||
const recSet = this.data.get(id) || new Set()
|
||||
const newSet = new Set([...recSet, ...protocols])
|
||||
|
||||
// Any new protocol added?
|
||||
@ -112,7 +117,7 @@ class ProtoBook {
|
||||
|
||||
protocols = [...newSet]
|
||||
|
||||
this.protoBook.set(id, newSet)
|
||||
this.data.set(id, newSet)
|
||||
this._ps.emit('change:protocols', {
|
||||
peerId,
|
||||
protocols
|
||||
@ -121,21 +126,6 @@ class ProtoBook {
|
||||
return protocols
|
||||
}
|
||||
|
||||
/**
|
||||
* Get known supported protocols of a provided peer.
|
||||
* @param {PeerId} peerId
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
get (peerId) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
const recSet = this.protoBook.get(peerId.toString())
|
||||
|
||||
return recSet ? [...recSet] : undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify if the provided peer supports the given protocols.
|
||||
* @param {PeerId} peerId
|
||||
@ -147,11 +137,15 @@ class ProtoBook {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
if (!protocols) {
|
||||
throw errcode(new Error('protocols must be provided'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
if (!Array.isArray(protocols)) {
|
||||
protocols = [protocols]
|
||||
}
|
||||
|
||||
const recSet = this.protoBook.get(peerId.toString())
|
||||
const recSet = this.data.get(peerId.toString())
|
||||
|
||||
if (!recSet) {
|
||||
return false
|
||||
@ -159,75 +153,6 @@ class ProtoBook {
|
||||
|
||||
return [...recSet].filter((p) => protocols.includes(p)).length === protocols.length
|
||||
}
|
||||
|
||||
/**
|
||||
* Has known protocols of a provided peer.
|
||||
* @param {PeerId} peerId
|
||||
* @returns {boolean}
|
||||
*/
|
||||
has (peerId) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
return this.protoBook.has(peerId.toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the provided peer from the book.
|
||||
* If protocols are provided, just remove the provided protocols and keep the peer.
|
||||
* @param {PeerId} peerId
|
||||
* @param {Array<string>|string} [protocols]
|
||||
* @returns {boolean}
|
||||
*/
|
||||
delete (peerId, protocols) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
|
||||
if (protocols) {
|
||||
return this._remove(peerId, protocols)
|
||||
}
|
||||
|
||||
if (!this.protoBook.delete(peerId.toString())) {
|
||||
return false
|
||||
}
|
||||
|
||||
this._ps.emit('change:protocols', {
|
||||
peerId,
|
||||
protocols: []
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given protocols from the provided peer.
|
||||
* @param {PeerId} peerId
|
||||
* @param {Array<string>|string} protocols
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_remove (peerId, protocols) {
|
||||
if (!Array.isArray(protocols)) {
|
||||
protocols = [protocols]
|
||||
}
|
||||
|
||||
const recSet = this.protoBook.get(peerId.toString())
|
||||
|
||||
if (!recSet) {
|
||||
return false
|
||||
}
|
||||
|
||||
protocols.forEach((p) => recSet.delete(p))
|
||||
// TODO: should we keep it if empty?
|
||||
|
||||
this._ps.emit('change:protocols', {
|
||||
peerId,
|
||||
protocols: [...recSet]
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ProtoBook
|
||||
|
357
test/peer-store/address-book.spec.js
Normal file
357
test/peer-store/address-book.spec.js
Normal file
@ -0,0 +1,357 @@
|
||||
'use strict'
|
||||
/* eslint-env mocha */
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const { expect } = chai
|
||||
const sinon = require('sinon')
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
const pDefer = require('p-defer')
|
||||
|
||||
const multiaddr = require('multiaddr')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const AddressBook = require('../../src/peer-store/address-book')
|
||||
|
||||
const {
|
||||
ERR_INVALID_PARAMETERS
|
||||
} = require('../../src/errors')
|
||||
|
||||
const addr1 = multiaddr('/ip4/127.0.0.1/tcp/8000')
|
||||
const addr2 = multiaddr('/ip4/127.0.0.1/tcp/8001')
|
||||
const addr3 = multiaddr('/ip4/127.0.0.1/tcp/8002')
|
||||
|
||||
const arraysAreEqual = (a, b) => a.length === b.length && a.sort().every((item, index) => b[index] === item)
|
||||
|
||||
describe('addressBook', () => {
|
||||
describe('addressBook.set', () => {
|
||||
let peerId
|
||||
let ee, ab
|
||||
|
||||
before(async () => {
|
||||
peerId = await PeerId.create()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
ab = new AddressBook(ee)
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
ee.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
ab.set('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if no addresses provided', () => {
|
||||
expect(() => {
|
||||
ab.set(peerId)
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid multiaddrs are provided', () => {
|
||||
expect(() => {
|
||||
ab.set(peerId, 'invalid multiaddr')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('replaces the stored content by default and emit change event', () => {
|
||||
const defer = pDefer()
|
||||
sinon.spy(ab, '_replace')
|
||||
sinon.spy(ab, '_add')
|
||||
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
ee.once('change:multiaddrs', ({ peerId, multiaddrs }) => {
|
||||
expect(peerId).to.exist()
|
||||
expect(multiaddrs).to.eql(supportedMultiaddrs)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
const multiaddrInfos = ab.set(peerId, supportedMultiaddrs)
|
||||
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
|
||||
expect(ab._replace.callCount).to.equal(1)
|
||||
expect(ab._add.callCount).to.equal(0)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrs)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('adds the new content if replace is disabled and emit change event', () => {
|
||||
const defer = pDefer()
|
||||
sinon.spy(ab, '_replace')
|
||||
sinon.spy(ab, '_add')
|
||||
|
||||
const supportedMultiaddrsA = [addr1, addr2]
|
||||
const supportedMultiaddrsB = [addr3]
|
||||
const finalMultiaddrs = supportedMultiaddrsA.concat(supportedMultiaddrsB)
|
||||
|
||||
let changeTrigger = 2
|
||||
ee.on('change:multiaddrs', ({ multiaddrs }) => {
|
||||
changeTrigger--
|
||||
if (changeTrigger === 0 && arraysAreEqual(multiaddrs, finalMultiaddrs)) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// Replace
|
||||
let multiaddrInfos = ab.set(peerId, supportedMultiaddrsA)
|
||||
let multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(ab._replace.callCount).to.equal(1)
|
||||
expect(ab._add.callCount).to.equal(0)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrsA)
|
||||
|
||||
// Add
|
||||
multiaddrInfos = ab.set(peerId, supportedMultiaddrsB, { replace: false })
|
||||
multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(ab._replace.callCount).to.equal(1)
|
||||
expect(ab._add.callCount).to.equal(1)
|
||||
expect(multiaddrs).to.have.deep.members(finalMultiaddrs)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('emits on set (replace) if not storing the exact same content', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrsA = [addr1, addr2]
|
||||
const supportedMultiaddrsB = [addr2]
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:multiaddrs', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
|
||||
// set 2 (same content)
|
||||
const multiaddrInfos = ab.set(peerId, supportedMultiaddrsB)
|
||||
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrsB)
|
||||
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on set (replace) if it is storing the exact same content', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:multiaddrs', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.reject()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
// set 2 (same content)
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('emits on set (add) if the content to add not exists', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrsA = [addr1]
|
||||
const supportedMultiaddrsB = [addr2]
|
||||
const finalMultiaddrs = supportedMultiaddrsA.concat(supportedMultiaddrsB)
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:multiaddrs', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
const multiaddrInfos = ab.set(peerId, supportedMultiaddrsB, { replace: false })
|
||||
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(finalMultiaddrs)
|
||||
|
||||
await defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on set (merge) if the content to add already exists', async () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrsA = [addr1, addr2]
|
||||
const supportedMultiaddrsB = [addr2]
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:multiaddrs', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.reject()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
ab.set(peerId, supportedMultiaddrsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
ab.set(peerId, supportedMultiaddrsB, { replace: false })
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
await defer.promise
|
||||
})
|
||||
})
|
||||
|
||||
describe('addressBook.get', () => {
|
||||
let peerId
|
||||
let ee, ab
|
||||
|
||||
before(async () => {
|
||||
peerId = await PeerId.create()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
ab = new AddressBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
ab.get('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns undefined if no multiaddrs are known for the provided peer', () => {
|
||||
const multiaddrInfos = ab.get(peerId)
|
||||
|
||||
expect(multiaddrInfos).to.not.exist()
|
||||
})
|
||||
|
||||
it('returns the multiaddrs stored', () => {
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
const multiaddrInfos = ab.get(peerId)
|
||||
const multiaddrs = multiaddrInfos.map((mi) => mi.multiaddr)
|
||||
expect(multiaddrs).to.have.deep.members(supportedMultiaddrs)
|
||||
})
|
||||
})
|
||||
|
||||
describe('addressBook.getMultiaddrsForPeer', () => {
|
||||
let peerId
|
||||
let ee, ab
|
||||
|
||||
before(async () => {
|
||||
peerId = await PeerId.create()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
ab = new AddressBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
ab.getMultiaddrsForPeer('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns undefined if no multiaddrs are known for the provided peer', () => {
|
||||
const multiaddrInfos = ab.getMultiaddrsForPeer(peerId)
|
||||
|
||||
expect(multiaddrInfos).to.not.exist()
|
||||
})
|
||||
|
||||
it('returns the multiaddrs stored', () => {
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
const multiaddrs = ab.getMultiaddrsForPeer(peerId)
|
||||
multiaddrs.forEach((m) => {
|
||||
expect(m.getPeerId()).to.equal(peerId.toB58String())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('addressBook.delete', () => {
|
||||
let peerId
|
||||
let ee, ab
|
||||
|
||||
before(async () => {
|
||||
peerId = await PeerId.create()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
ab = new AddressBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
ab.delete('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns false if no records exist for the peer and no event is emitted', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
ee.on('change:multiaddrs', () => {
|
||||
defer.reject()
|
||||
})
|
||||
|
||||
const deleted = ab.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(false)
|
||||
|
||||
// Wait 50ms for incorrect invalid event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('returns true if the record exists and an event is emitted', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedMultiaddrs = [addr1, addr2]
|
||||
ab.set(peerId, supportedMultiaddrs)
|
||||
|
||||
// Listen after set
|
||||
ee.on('change:multiaddrs', ({ multiaddrs }) => {
|
||||
expect(multiaddrs.length).to.eql(0)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
const deleted = ab.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(true)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
})
|
||||
})
|
@ -7,6 +7,7 @@ const { expect } = chai
|
||||
const sinon = require('sinon')
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
const pDefer = require('p-defer')
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
@ -16,6 +17,8 @@ const {
|
||||
ERR_INVALID_PARAMETERS
|
||||
} = require('../../src/errors')
|
||||
|
||||
const arraysAreEqual = (a, b) => a.length === b.length && a.sort().every((item, index) => b[index] === item)
|
||||
|
||||
describe('protoBook', () => {
|
||||
describe('protoBook.set', () => {
|
||||
let peerId
|
||||
@ -30,40 +33,323 @@ describe('protoBook', () => {
|
||||
pb = new ProtoBook(ee)
|
||||
})
|
||||
|
||||
it('should thrown invalid parameters error if invalid PeerId is provided', () => {
|
||||
afterEach(() => {
|
||||
ee.removeAllListeners()
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.set('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('should thrown invalid parameters error if no protocols provided', () => {
|
||||
it('throwns invalid parameters error if no protocols provided', () => {
|
||||
expect(() => {
|
||||
pb.set(peerId)
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('should replace the stored content by default', () => {
|
||||
it('replaces the stored content by default and emit change event', () => {
|
||||
const defer = pDefer()
|
||||
sinon.spy(pb, '_replace')
|
||||
sinon.spy(pb, '_add')
|
||||
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
const protocols = pb.set(peerId, supportedProtocols)
|
||||
|
||||
expect(pb._replace.callCount).to.equal(1)
|
||||
expect(pb._add.callCount).to.equal(0)
|
||||
expect(protocols).to.eql(supportedProtocols)
|
||||
ee.once('change:protocols', ({ peerId, protocols }) => {
|
||||
expect(peerId).to.exist()
|
||||
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
it('should replace the stored content by default', () => {
|
||||
sinon.spy(pb, '_replace')
|
||||
sinon.spy(pb, '_add')
|
||||
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
const protocols = pb.set(peerId, supportedProtocols)
|
||||
|
||||
expect(pb._replace.callCount).to.equal(1)
|
||||
expect(pb._add.callCount).to.equal(0)
|
||||
expect(protocols).to.eql(supportedProtocols)
|
||||
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('adds the new content if replace is disabled and emit change event', () => {
|
||||
const defer = pDefer()
|
||||
sinon.spy(pb, '_replace')
|
||||
sinon.spy(pb, '_add')
|
||||
|
||||
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||
const supportedProtocolsB = ['protocol3']
|
||||
const finalProtocols = supportedProtocolsA.concat(supportedProtocolsB)
|
||||
|
||||
let changeTrigger = 2
|
||||
ee.on('change:protocols', ({ protocols }) => {
|
||||
changeTrigger--
|
||||
if (changeTrigger === 0 && arraysAreEqual(protocols, finalProtocols)) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// Replace
|
||||
let protocols = pb.set(peerId, supportedProtocolsA)
|
||||
expect(pb._replace.callCount).to.equal(1)
|
||||
expect(pb._add.callCount).to.equal(0)
|
||||
expect(protocols).to.have.deep.members(supportedProtocolsA)
|
||||
|
||||
// Add
|
||||
protocols = pb.set(peerId, supportedProtocolsB, { replace: false })
|
||||
expect(pb._replace.callCount).to.equal(1)
|
||||
expect(pb._add.callCount).to.equal(1)
|
||||
expect(protocols).to.have.deep.members(finalProtocols)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('emits on set (replace) if not storing the exact same content', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||
const supportedProtocolsB = ['protocol2']
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:protocols', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
|
||||
// set 2 (same content)
|
||||
const protocols = pb.set(peerId, supportedProtocolsB)
|
||||
expect(protocols).to.have.deep.members(supportedProtocolsB)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on set (replace) if it is storing the exact same content', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:protocols', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.reject()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocols)
|
||||
|
||||
// set 2 (same content)
|
||||
pb.set(peerId, supportedProtocols)
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('emits on set (add) if the content to add not exists', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1']
|
||||
const supportedProtocolsB = ['protocol2']
|
||||
const finalProtocols = supportedProtocolsA.concat(supportedProtocolsB)
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:protocols', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
const protocols = pb.set(peerId, supportedProtocolsB, { replace: false })
|
||||
expect(protocols).to.have.deep.members(finalProtocols)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('does not emit on set (merge) if the content to add already exists', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocolsA = ['protocol1', 'protocol2']
|
||||
const supportedProtocolsB = ['protocol2']
|
||||
|
||||
let changeCounter = 0
|
||||
ee.on('change:protocols', () => {
|
||||
changeCounter++
|
||||
if (changeCounter > 1) {
|
||||
defer.reject()
|
||||
}
|
||||
})
|
||||
|
||||
// set 1
|
||||
pb.set(peerId, supportedProtocolsA)
|
||||
|
||||
// set 2 (content already existing)
|
||||
pb.set(peerId, supportedProtocolsB, { replace: false })
|
||||
|
||||
// Wait 50ms for incorrect second event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
})
|
||||
|
||||
describe('protoBook.get', () => {
|
||||
let peerId
|
||||
let ee, pb
|
||||
|
||||
before(async () => {
|
||||
peerId = await PeerId.create()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
pb = new ProtoBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.get('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns undefined if no protocols are known for the provided peer', () => {
|
||||
const protocols = pb.get(peerId)
|
||||
|
||||
expect(protocols).to.not.exist()
|
||||
})
|
||||
|
||||
it('returns the protocols stored', () => {
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
|
||||
pb.set(peerId, supportedProtocols)
|
||||
|
||||
const protocols = pb.get(peerId)
|
||||
expect(protocols).to.have.deep.members(supportedProtocols)
|
||||
})
|
||||
})
|
||||
|
||||
describe('protoBook.supports', () => {
|
||||
let peerId
|
||||
let ee, pb
|
||||
|
||||
before(async () => {
|
||||
peerId = await PeerId.create()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
pb = new ProtoBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.supports('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if no protocols provided', () => {
|
||||
expect(() => {
|
||||
pb.supports(peerId)
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns false if no records exist for the peer', () => {
|
||||
const supportedProtocols = ['protocol1']
|
||||
const supports = pb.supports(peerId, supportedProtocols[0])
|
||||
|
||||
expect(supports).to.equal(false)
|
||||
})
|
||||
|
||||
it('returns true if the protocol is supported', () => {
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
|
||||
pb.set(peerId, supportedProtocols)
|
||||
|
||||
const supports = pb.supports(peerId, supportedProtocols[1])
|
||||
expect(supports).to.equal(true)
|
||||
})
|
||||
|
||||
it('returns false if part of the protocols is supported', () => {
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
const otherProtocols = ['protocol3', 'protocol4']
|
||||
|
||||
pb.set(peerId, supportedProtocols)
|
||||
|
||||
const supports = pb.supports(peerId, [supportedProtocols[0], ...otherProtocols])
|
||||
expect(supports).to.equal(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('protoBook.delete', () => {
|
||||
let peerId
|
||||
let ee, pb
|
||||
|
||||
before(async () => {
|
||||
peerId = await PeerId.create()
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
ee = new EventEmitter()
|
||||
pb = new ProtoBook(ee)
|
||||
})
|
||||
|
||||
it('throwns invalid parameters error if invalid PeerId is provided', () => {
|
||||
expect(() => {
|
||||
pb.delete('invalid peerId')
|
||||
}).to.throw(ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('returns false if no records exist for the peer and no event is emitted', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
ee.on('change:protocols', () => {
|
||||
defer.reject()
|
||||
})
|
||||
|
||||
const deleted = pb.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(false)
|
||||
|
||||
// Wait 50ms for incorrect invalid event
|
||||
setTimeout(() => {
|
||||
defer.resolve()
|
||||
}, 50)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('returns true if the record exists and an event is emitted', () => {
|
||||
const defer = pDefer()
|
||||
|
||||
const supportedProtocols = ['protocol1', 'protocol2']
|
||||
pb.set(peerId, supportedProtocols)
|
||||
|
||||
// Listen after set
|
||||
ee.on('change:protocols', ({ protocols }) => {
|
||||
expect(protocols.length).to.eql(0)
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
const deleted = pb.delete(peerId)
|
||||
|
||||
expect(deleted).to.equal(true)
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
})
|
||||
})
|
||||
|
Loading…
x
Reference in New Issue
Block a user