mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-20 02:51:56 +00:00
Compare commits
25 Commits
fix/event-
...
v0.29.4
Author | SHA1 | Date | |
---|---|---|---|
|
48656712ea | ||
|
1a5ae74741 | ||
|
8691465a52 | ||
|
6350a187c7 | ||
|
8e3bb09279 | ||
|
73204958ee | ||
|
e9e4b731a5 | ||
|
d0a9fada32 | ||
|
824a444f56 | ||
|
fef54b2b2c | ||
|
8f29a667a1 | ||
|
093c0ea13f | ||
|
61c36f9e09 | ||
|
f82da56901 | ||
|
06f26e586f | ||
|
8879634363 | ||
|
4a80afce8f | ||
|
f75ae341bb | ||
|
f2d010a3ab | ||
|
e04224a1e2 | ||
|
4c6be91588 | ||
|
5f50054d94 | ||
|
d7d8439e71 | ||
|
4c7a89b710 | ||
|
4eabe07bde |
@@ -7,7 +7,7 @@ stages:
|
|||||||
|
|
||||||
node_js:
|
node_js:
|
||||||
- 'lts/*'
|
- 'lts/*'
|
||||||
- 'stable'
|
- '14'
|
||||||
|
|
||||||
os:
|
os:
|
||||||
- linux
|
- linux
|
||||||
|
48
CHANGELOG.md
48
CHANGELOG.md
@@ -1,3 +1,51 @@
|
|||||||
|
<a name="0.29.4"></a>
|
||||||
|
## [0.29.4](https://github.com/libp2p/js-libp2p/compare/v0.29.3...v0.29.4) (2020-12-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* dial self ([#826](https://github.com/libp2p/js-libp2p/issues/826)) ([6350a18](https://github.com/libp2p/js-libp2p/commit/6350a18))
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* custom and store self agent version + store self protocol version ([#800](https://github.com/libp2p/js-libp2p/issues/800)) ([d0a9fad](https://github.com/libp2p/js-libp2p/commit/d0a9fad))
|
||||||
|
* support custom listener options ([#822](https://github.com/libp2p/js-libp2p/issues/822)) ([8691465](https://github.com/libp2p/js-libp2p/commit/8691465))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.29.3"></a>
|
||||||
|
## [0.29.3](https://github.com/libp2p/js-libp2p/compare/v0.29.2...v0.29.3) (2020-11-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* resolve multiaddrs before dial ([#782](https://github.com/libp2p/js-libp2p/issues/782)) ([093c0ea](https://github.com/libp2p/js-libp2p/commit/093c0ea))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.29.2"></a>
|
||||||
|
## [0.29.2](https://github.com/libp2p/js-libp2p/compare/v0.29.1...v0.29.2) (2020-10-23)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* cleanup open streams on conn close ([#791](https://github.com/libp2p/js-libp2p/issues/791)) ([06f26e5](https://github.com/libp2p/js-libp2p/commit/06f26e5))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="0.29.1"></a>
|
||||||
|
## [0.29.1](https://github.com/libp2p/js-libp2p/compare/v0.29.0...v0.29.1) (2020-10-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* catch error in upgrader close call ([e04224a](https://github.com/libp2p/js-libp2p/commit/e04224a))
|
||||||
|
* ensure streams are closed on connection close ([4c6be91](https://github.com/libp2p/js-libp2p/commit/4c6be91))
|
||||||
|
* flakey identify test firefox ([#774](https://github.com/libp2p/js-libp2p/issues/774)) ([60d437f](https://github.com/libp2p/js-libp2p/commit/60d437f))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="0.29.0"></a>
|
<a name="0.29.0"></a>
|
||||||
# [0.29.0](https://github.com/libp2p/js-libp2p/compare/v0.28.10...v0.29.0) (2020-08-27)
|
# [0.29.0](https://github.com/libp2p/js-libp2p/compare/v0.28.10...v0.29.0) (2020-08-27)
|
||||||
|
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
<a href="https://github.com/feross/standard"><img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square"></a>
|
<a href="https://github.com/feross/standard"><img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square"></a>
|
||||||
<a href="https://github.com/RichardLitt/standard-readme"><img src="https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square" /></a>
|
<a href="https://github.com/RichardLitt/standard-readme"><img src="https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square" /></a>
|
||||||
<a href=""><img src="https://img.shields.io/badge/npm-%3E%3D6.0.0-orange.svg?style=flat-square" /></a>
|
<a href=""><img src="https://img.shields.io/badge/npm-%3E%3D6.0.0-orange.svg?style=flat-square" /></a>
|
||||||
<a href=""><img src="https://img.shields.io/badge/Node.js-%3E%3D10.0.0-orange.svg?style=flat-square" /></a>
|
<a href=""><img src="https://img.shields.io/badge/Node.js-%3E%3D12.0.0-orange.svg?style=flat-square" /></a>
|
||||||
<br>
|
<br>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
52
doc/API.md
52
doc/API.md
@@ -48,6 +48,8 @@
|
|||||||
* [`pubsub.unsubscribe`](#pubsubunsubscribe)
|
* [`pubsub.unsubscribe`](#pubsubunsubscribe)
|
||||||
* [`pubsub.on`](#pubsubon)
|
* [`pubsub.on`](#pubsubon)
|
||||||
* [`pubsub.removeListener`](#pubsubremovelistener)
|
* [`pubsub.removeListener`](#pubsubremovelistener)
|
||||||
|
* [`pubsub.topicValidators.set`](#pubsubtopicvalidatorsset)
|
||||||
|
* [`pubsub.topicValidators.delete`](#pubsubtopicvalidatorsdelete)
|
||||||
* [`connectionManager.get`](#connectionmanagerget)
|
* [`connectionManager.get`](#connectionmanagerget)
|
||||||
* [`connectionManager.setPeerValue`](#connectionmanagersetpeervalue)
|
* [`connectionManager.setPeerValue`](#connectionmanagersetpeervalue)
|
||||||
* [`connectionManager.size`](#connectionmanagersize)
|
* [`connectionManager.size`](#connectionmanagersize)
|
||||||
@@ -90,6 +92,7 @@ Creates an instance of Libp2p.
|
|||||||
| options.modules | [`Array<object>`](./CONFIGURATION.md#modules) | libp2p [modules](./CONFIGURATION.md#modules) to use |
|
| options.modules | [`Array<object>`](./CONFIGURATION.md#modules) | libp2p [modules](./CONFIGURATION.md#modules) to use |
|
||||||
| [options.addresses] | `{ listen: Array<string>, announce: Array<string>, noAnnounce: Array<string> }` | Addresses for transport listening and to advertise to the network |
|
| [options.addresses] | `{ listen: Array<string>, announce: Array<string>, noAnnounce: Array<string> }` | Addresses for transport listening and to advertise to the network |
|
||||||
| [options.config] | `object` | libp2p modules configuration and core configuration |
|
| [options.config] | `object` | libp2p modules configuration and core configuration |
|
||||||
|
| [options.host] | `{ agentVersion: string }` | libp2p host options |
|
||||||
| [options.connectionManager] | [`object`](./CONFIGURATION.md#configuring-connection-manager) | libp2p Connection Manager [configuration](./CONFIGURATION.md#configuring-connection-manager) |
|
| [options.connectionManager] | [`object`](./CONFIGURATION.md#configuring-connection-manager) | libp2p Connection Manager [configuration](./CONFIGURATION.md#configuring-connection-manager) |
|
||||||
| [options.transportManager] | [`object`](./CONFIGURATION.md#configuring-transport-manager) | libp2p transport manager [configuration](./CONFIGURATION.md#configuring-transport-manager) |
|
| [options.transportManager] | [`object`](./CONFIGURATION.md#configuring-transport-manager) | libp2p transport manager [configuration](./CONFIGURATION.md#configuring-transport-manager) |
|
||||||
| [options.datastore] | `object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) (in memory datastore will be used if not provided) |
|
| [options.datastore] | `object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) (in memory datastore will be used if not provided) |
|
||||||
@@ -111,12 +114,25 @@ For Libp2p configurations and modules details read the [Configuration Document](
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const Libp2p = require('libp2p')
|
const Libp2p = require('libp2p')
|
||||||
|
const TCP = require('libp2p-tcp')
|
||||||
|
const MPLEX = require('libp2p-mplex')
|
||||||
|
const { NOISE } = require('libp2p-noise')
|
||||||
|
|
||||||
// specify options
|
async function main () {
|
||||||
const options = {}
|
// specify options
|
||||||
|
const options = {
|
||||||
|
modules: {
|
||||||
|
transport: [TCP],
|
||||||
|
streamMuxer: [MPLEX],
|
||||||
|
connEncryption: [NOISE]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create libp2p
|
// create libp2p
|
||||||
const libp2p = await Libp2p.create(options)
|
const libp2p = await Libp2p.create(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
```
|
```
|
||||||
|
|
||||||
Note: The [`PeerId`][peer-id] option is not required and will be generated if it is not provided.
|
Note: The [`PeerId`][peer-id] option is not required and will be generated if it is not provided.
|
||||||
@@ -128,12 +144,30 @@ As an alternative, it is possible to create a Libp2p instance with the construct
|
|||||||
|
|
||||||
```js
|
```js
|
||||||
const Libp2p = require('libp2p')
|
const Libp2p = require('libp2p')
|
||||||
|
const TCP = require('libp2p-tcp')
|
||||||
|
const MPLEX = require('libp2p-mplex')
|
||||||
|
const { NOISE } = require('libp2p-noise')
|
||||||
|
const PeerId = require('peer-id')
|
||||||
|
|
||||||
// specify options
|
async function main () {
|
||||||
const options = {}
|
const peerId = await PeerId.create();
|
||||||
|
|
||||||
// create libp2p
|
// specify options
|
||||||
const libp2p = new Libp2p(options)
|
// peerId is required when Libp2p is instantiated via the constructor
|
||||||
|
const options = {
|
||||||
|
peerId,
|
||||||
|
modules: {
|
||||||
|
transport: [TCP],
|
||||||
|
streamMuxer: [MPLEX],
|
||||||
|
connEncryption: [NOISE]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create libp2p
|
||||||
|
const libp2p = new Libp2p(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
main()
|
||||||
```
|
```
|
||||||
|
|
||||||
Required keys in the `options` object:
|
Required keys in the `options` object:
|
||||||
@@ -663,7 +697,7 @@ Queries the DHT for the n values stored for the given key (without sorting).
|
|||||||
// ...
|
// ...
|
||||||
|
|
||||||
const key = '/key'
|
const key = '/key'
|
||||||
const { from, val } = await libp2p.contentRouting.get(key)
|
const records = await libp2p.contentRouting.getMany(key, 2)
|
||||||
```
|
```
|
||||||
|
|
||||||
### peerRouting.findPeer
|
### peerRouting.findPeer
|
||||||
|
@@ -465,6 +465,7 @@ Dialing in libp2p can be configured to limit the rate of dialing, and how long d
|
|||||||
| maxParallelDials | `number` | How many multiaddrs we can dial in parallel. |
|
| maxParallelDials | `number` | How many multiaddrs we can dial in parallel. |
|
||||||
| maxDialsPerPeer | `number` | How many multiaddrs we can dial per peer, in parallel. |
|
| maxDialsPerPeer | `number` | How many multiaddrs we can dial per peer, in parallel. |
|
||||||
| dialTimeout | `number` | Second dial timeout per peer in ms. |
|
| dialTimeout | `number` | Second dial timeout per peer in ms. |
|
||||||
|
| resolvers | `object` | Dial [Resolvers](https://github.com/multiformats/js-multiaddr/blob/master/src/resolvers/index.js) for resolving multiaddrs |
|
||||||
|
|
||||||
The below configuration example shows how the dialer should be configured, with the current defaults:
|
The below configuration example shows how the dialer should be configured, with the current defaults:
|
||||||
|
|
||||||
@@ -474,6 +475,8 @@ const TCP = require('libp2p-tcp')
|
|||||||
const MPLEX = require('libp2p-mplex')
|
const MPLEX = require('libp2p-mplex')
|
||||||
const { NOISE } = require('libp2p-noise')
|
const { NOISE } = require('libp2p-noise')
|
||||||
|
|
||||||
|
const { dnsaddrResolver } = require('multiaddr/src/resolvers')
|
||||||
|
|
||||||
const node = await Libp2p.create({
|
const node = await Libp2p.create({
|
||||||
modules: {
|
modules: {
|
||||||
transport: [TCP],
|
transport: [TCP],
|
||||||
@@ -483,7 +486,10 @@ const node = await Libp2p.create({
|
|||||||
dialer: {
|
dialer: {
|
||||||
maxParallelDials: 100,
|
maxParallelDials: 100,
|
||||||
maxDialsPerPeer: 4,
|
maxDialsPerPeer: 4,
|
||||||
dialTimeout: 30e3
|
dialTimeout: 30e3,
|
||||||
|
resolvers: {
|
||||||
|
dnsaddr: dnsaddrResolver
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -645,6 +651,35 @@ const node = await Libp2p.create({
|
|||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
|
During Libp2p startup, transport listeners will be created for the configured listen multiaddrs. Some transports support custom listener options and you can set them using the `listenerOptions` in the transport configuration. For example, [libp2p-webrtc-star](https://github.com/libp2p/js-libp2p-webrtc-star) transport listener supports the configuration of its underlying [simple-peer](https://github.com/feross/simple-peer) ice server(STUN/TURN) config as follows:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const transportKey = WebRTCStar.prototype[Symbol.toStringTag]
|
||||||
|
const node = await Libp2p.create({
|
||||||
|
modules: {
|
||||||
|
transport: [WebRTCStar],
|
||||||
|
streamMuxer: [MPLEX],
|
||||||
|
connEncryption: [NOISE]
|
||||||
|
},
|
||||||
|
addresses: {
|
||||||
|
listen: ['/dns4/your-wrtc-star.pub/tcp/443/wss/p2p-webrtc-star'] // your webrtc dns multiaddr
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
transport: {
|
||||||
|
[transportKey]: {
|
||||||
|
listenerOptions: {
|
||||||
|
config: {
|
||||||
|
iceServers: [
|
||||||
|
{"urls": ["turn:YOUR.TURN.SERVER:3478"], "username": "YOUR.USER", "credential": "YOUR.PASSWORD"},
|
||||||
|
{"urls": ["stun:YOUR.STUN.SERVER:3478"], "username": "", "credential": ""}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
## Configuration examples
|
## Configuration examples
|
||||||
|
|
||||||
As libp2p is designed to be a modular networking library, its usage will vary based on individual project needs. We've included links to some existing project configurations for your reference, in case you wish to replicate their configuration:
|
As libp2p is designed to be a modular networking library, its usage will vary based on individual project needs. We've included links to some existing project configurations for your reference, in case you wish to replicate their configuration:
|
||||||
|
@@ -204,8 +204,8 @@ const Bootstrap = require('libp2p-bootstrap')
|
|||||||
|
|
||||||
// Known peers addresses
|
// Known peers addresses
|
||||||
const bootstrapMultiaddrs = [
|
const bootstrapMultiaddrs = [
|
||||||
'/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||||
'/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3'
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN'
|
||||||
]
|
]
|
||||||
|
|
||||||
const node = await Libp2p.create({
|
const node = await Libp2p.create({
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const multiaddr = require('multiaddr')
|
const multiaddr = require('multiaddr')
|
||||||
const Node = require('./libp2p-bundle')
|
const createLibp2p = require('./libp2p-bundle')
|
||||||
const { stdinToStream, streamToConsole } = require('./stream')
|
const { stdinToStream, streamToConsole } = require('./stream')
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
@@ -13,7 +13,7 @@ async function run() {
|
|||||||
])
|
])
|
||||||
|
|
||||||
// Create a new libp2p node on localhost with a randomly chosen port
|
// Create a new libp2p node on localhost with a randomly chosen port
|
||||||
const nodeDialer = new Node({
|
const nodeDialer = await createLibp2p({
|
||||||
peerId: idDialer,
|
peerId: idDialer,
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||||
|
@@ -7,21 +7,16 @@ const { NOISE } = require('libp2p-noise')
|
|||||||
const defaultsDeep = require('@nodeutils/defaults-deep')
|
const defaultsDeep = require('@nodeutils/defaults-deep')
|
||||||
const libp2p = require('../../..')
|
const libp2p = require('../../..')
|
||||||
|
|
||||||
class Node extends libp2p {
|
async function createLibp2p(_options) {
|
||||||
constructor (_options) {
|
const defaults = {
|
||||||
const defaults = {
|
modules: {
|
||||||
modules: {
|
transport: [TCP, WS],
|
||||||
transport: [
|
streamMuxer: [mplex],
|
||||||
TCP,
|
connEncryption: [NOISE],
|
||||||
WS
|
},
|
||||||
],
|
|
||||||
streamMuxer: [ mplex ],
|
|
||||||
connEncryption: [ NOISE ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super(defaultsDeep(_options, defaults))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return libp2p.create(defaultsDeep(_options, defaults))
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Node
|
module.exports = createLibp2p
|
||||||
|
@@ -2,13 +2,13 @@
|
|||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const Node = require('./libp2p-bundle.js')
|
const createLibp2p = require('./libp2p-bundle.js')
|
||||||
const { stdinToStream, streamToConsole } = require('./stream')
|
const { stdinToStream, streamToConsole } = require('./stream')
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
// Create a new libp2p node with the given multi-address
|
// Create a new libp2p node with the given multi-address
|
||||||
const idListener = await PeerId.createFromJSON(require('./peer-id-listener'))
|
const idListener = await PeerId.createFromJSON(require('./peer-id-listener'))
|
||||||
const nodeListener = new Node({
|
const nodeListener = await createLibp2p({
|
||||||
peerId: idListener,
|
peerId: idListener,
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: ['/ip4/0.0.0.0/tcp/10333']
|
listen: ['/ip4/0.0.0.0/tcp/10333']
|
||||||
|
@@ -10,14 +10,11 @@ const Bootstrap = require('libp2p-bootstrap')
|
|||||||
// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-nodejs.json
|
// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-nodejs.json
|
||||||
const bootstrapers = [
|
const bootstrapers = [
|
||||||
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
||||||
'/ip4/104.236.176.52/tcp/4001/p2p/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
||||||
'/ip4/104.236.179.241/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||||
'/ip4/162.243.248.213/tcp/4001/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
||||||
'/ip4/128.199.219.111/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
||||||
'/ip4/104.236.76.40/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
||||||
'/ip4/178.62.158.247/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
|
|
||||||
'/ip4/178.62.61.185/tcp/4001/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
|
|
||||||
'/ip4/104.236.151.122/tcp/4001/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
;(async () => {
|
;(async () => {
|
||||||
|
@@ -40,14 +40,11 @@ In this configuration, we use a `bootstrappers` array listing peers to connect _
|
|||||||
```JavaScript
|
```JavaScript
|
||||||
const bootstrapers = [
|
const bootstrapers = [
|
||||||
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
||||||
'/ip4/104.236.176.52/tcp/4001/p2p/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
||||||
'/ip4/104.236.179.241/tcp/4001/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||||
'/ip4/162.243.248.213/tcp/4001/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
||||||
'/ip4/128.199.219.111/tcp/4001/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
||||||
'/ip4/104.236.76.40/tcp/4001/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
||||||
'/ip4/178.62.158.247/tcp/4001/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
|
|
||||||
'/ip4/178.62.61.185/tcp/4001/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
|
|
||||||
'/ip4/104.236.151.122/tcp/4001/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx'
|
|
||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -93,23 +90,17 @@ From running [1.js](./1.js), you should see the following:
|
|||||||
```bash
|
```bash
|
||||||
> node 1.js
|
> node 1.js
|
||||||
Discovered: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
|
Discovered: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
|
||||||
Discovered: QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z
|
Discovered: QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN
|
||||||
Discovered: QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM
|
Discovered: QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb
|
||||||
Discovered: QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm
|
Discovered: QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp
|
||||||
Discovered: QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu
|
Discovered: QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa
|
||||||
Discovered: QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64
|
Discovered: QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt
|
||||||
Discovered: QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd
|
|
||||||
Discovered: QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
|
|
||||||
Discovered: QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
|
|
||||||
Connection established to: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
|
Connection established to: QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ
|
||||||
Connection established to: QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z
|
Connection established to: QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN
|
||||||
Connection established to: QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM
|
Connection established to: QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp
|
||||||
Connection established to: QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm
|
Connection established to: QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa
|
||||||
Connection established to: QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu
|
Connection established to: QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt
|
||||||
Connection established to: QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64
|
Connection established to: QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb
|
||||||
Connection established to: QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd
|
|
||||||
Connection established to: QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3
|
|
||||||
Connection established to: QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## 2. MulticastDNS to find other peers in the network
|
## 2. MulticastDNS to find other peers in the network
|
||||||
|
@@ -5,9 +5,8 @@
|
|||||||
* Dialer Node
|
* Dialer Node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const multiaddr = require('multiaddr')
|
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const Node = require('./libp2p-bundle')
|
const createLibp2p = require('./libp2p-bundle')
|
||||||
const pipe = require('it-pipe')
|
const pipe = require('it-pipe')
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
@@ -17,7 +16,7 @@ async function run() {
|
|||||||
])
|
])
|
||||||
|
|
||||||
// Dialer
|
// Dialer
|
||||||
const dialerNode = new Node({
|
const dialerNode = await createLibp2p({
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||||
},
|
},
|
||||||
|
@@ -8,21 +8,16 @@ const { NOISE } = require('libp2p-noise')
|
|||||||
const defaultsDeep = require('@nodeutils/defaults-deep')
|
const defaultsDeep = require('@nodeutils/defaults-deep')
|
||||||
const libp2p = require('../../..')
|
const libp2p = require('../../..')
|
||||||
|
|
||||||
class Node extends libp2p {
|
async function createLibp2p(_options) {
|
||||||
constructor (_options) {
|
const defaults = {
|
||||||
const defaults = {
|
modules: {
|
||||||
modules: {
|
transport: [TCP, WS],
|
||||||
transport: [
|
streamMuxer: [mplex],
|
||||||
TCP,
|
connEncryption: [NOISE],
|
||||||
WS
|
},
|
||||||
],
|
|
||||||
streamMuxer: [ mplex ],
|
|
||||||
connEncryption: [ NOISE ]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super(defaultsDeep(_options, defaults))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return libp2p.create(defaultsDeep(_options, defaults))
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Node
|
module.exports = createLibp2p
|
||||||
|
@@ -6,14 +6,14 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const Node = require('./libp2p-bundle')
|
const createLibp2p = require('./libp2p-bundle')
|
||||||
const pipe = require('it-pipe')
|
const pipe = require('it-pipe')
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
const listenerId = await PeerId.createFromJSON(require('./id-l'))
|
const listenerId = await PeerId.createFromJSON(require('./id-l'))
|
||||||
|
|
||||||
// Listener libp2p node
|
// Listener libp2p node
|
||||||
const listenerNode = new Node({
|
const listenerNode = await createLibp2p({
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: ['/ip4/0.0.0.0/tcp/10333']
|
listen: ['/ip4/0.0.0.0/tcp/10333']
|
||||||
},
|
},
|
||||||
|
@@ -31,12 +31,11 @@ document.addEventListener('DOMContentLoaded', async () => {
|
|||||||
[Bootstrap.tag]: {
|
[Bootstrap.tag]: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
list: [
|
list: [
|
||||||
'/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
||||||
'/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||||
'/dns4/sfo-3.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
||||||
'/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
||||||
'/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
|
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
||||||
'/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64'
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,7 +8,7 @@ const { NOISE } = require('libp2p-noise')
|
|||||||
const createNode = async () => {
|
const createNode = async () => {
|
||||||
const node = await Libp2p.create({
|
const node = await Libp2p.create({
|
||||||
addresses: {
|
addresses: {
|
||||||
// To signall the addresses we want to be available, we use
|
// To signal the addresses we want to be available, we use
|
||||||
// the multiaddr format, a self describable address
|
// the multiaddr format, a self describable address
|
||||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||||
},
|
},
|
||||||
|
@@ -12,7 +12,7 @@ const concat = require('it-concat')
|
|||||||
const createNode = async () => {
|
const createNode = async () => {
|
||||||
const node = await Libp2p.create({
|
const node = await Libp2p.create({
|
||||||
addresses: {
|
addresses: {
|
||||||
// To signall the addresses we want to be available, we use
|
// To signal the addresses we want to be available, we use
|
||||||
// the multiaddr format, a self describable address
|
// the multiaddr format, a self describable address
|
||||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||||
},
|
},
|
||||||
|
@@ -16,7 +16,7 @@ const createNode = async (transports, addresses = []) => {
|
|||||||
|
|
||||||
const node = await Libp2p.create({
|
const node = await Libp2p.create({
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: addresses.map((a) => a)
|
listen: addresses
|
||||||
},
|
},
|
||||||
modules: {
|
modules: {
|
||||||
transport: transports,
|
transport: transports,
|
||||||
|
@@ -13,10 +13,10 @@ When using libp2p, you need properly configure it, that is, pick your set of mod
|
|||||||
You will need 4 dependencies total, so go ahead and install all of them with:
|
You will need 4 dependencies total, so go ahead and install all of them with:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
> npm install libp2p libp2p-tcp libp2p-noise peer-info
|
> npm install libp2p libp2p-tcp libp2p-noise
|
||||||
```
|
```
|
||||||
|
|
||||||
Then, on your favorite text editor create a file with the `.js` extension. I've called mine `1.js`.
|
Then, in your favorite text editor create a file with the `.js` extension. I've called mine `1.js`.
|
||||||
|
|
||||||
First thing is to create our own libp2p node! Insert:
|
First thing is to create our own libp2p node! Insert:
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ const { NOISE } = require('libp2p-noise')
|
|||||||
const createNode = async () => {
|
const createNode = async () => {
|
||||||
const node = await Libp2p.create({
|
const node = await Libp2p.create({
|
||||||
addresses: {
|
addresses: {
|
||||||
// To signall the addresses we want to be available, we use
|
// To signal the addresses we want to be available, we use
|
||||||
// the multiaddr format, a self describable address
|
// the multiaddr format, a self describable address
|
||||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||||
},
|
},
|
||||||
@@ -77,20 +77,41 @@ That `QmW2cKTakTYqbQkUzBTEGXgWYFj1YEPeUndE1YWs6CBzDQ` is the PeerId that was cre
|
|||||||
|
|
||||||
Now that we have our `createNode` function, let's create two nodes and make them dial to each other! You can find the complete solution at [2.js](./2.js).
|
Now that we have our `createNode` function, let's create two nodes and make them dial to each other! You can find the complete solution at [2.js](./2.js).
|
||||||
|
|
||||||
For this step, we will need one more dependency.
|
For this step, we will need some more dependencies.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
> npm install it-pipe it-buffer
|
> npm install it-pipe it-concat libp2p-mplex
|
||||||
```
|
```
|
||||||
|
|
||||||
And we also need to import the module on our .js file:
|
And we also need to import the modules on our .js file:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const pipe = require('it-pipe')
|
const pipe = require('it-pipe')
|
||||||
const { toBuffer } = require('it-buffer')
|
const concat = require('it-concat')
|
||||||
|
const MPLEX = require('libp2p-mplex')
|
||||||
```
|
```
|
||||||
|
|
||||||
We are going to reuse the `createNode` function from step 1, but this time to make things simpler, we will create another function to print the addrs to avoid duplicating code.
|
We are going to reuse the `createNode` function from step 1, but this time add a stream multiplexer from `libp2p-mplex`.
|
||||||
|
```js
|
||||||
|
const createNode = async () => {
|
||||||
|
const node = await Libp2p.create({
|
||||||
|
addresses: {
|
||||||
|
// To signal the addresses we want to be available, we use
|
||||||
|
// the multiaddr format, a self describable address
|
||||||
|
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||||
|
},
|
||||||
|
modules: {
|
||||||
|
transport: [TCP],
|
||||||
|
connEncryption: [NOISE],
|
||||||
|
streamMuxer: [MPLEX] // <--- Add this line
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await node.start()
|
||||||
|
return node
|
||||||
|
}
|
||||||
|
```
|
||||||
|
We will also make things simpler by creating another function to print the multiaddresses to avoid duplicating code.
|
||||||
|
|
||||||
```JavaScript
|
```JavaScript
|
||||||
function printAddrs (node, number) {
|
function printAddrs (node, number) {
|
||||||
@@ -99,7 +120,7 @@ function printAddrs (node, number) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Then,
|
Then add,
|
||||||
|
|
||||||
```js
|
```js
|
||||||
;(async () => {
|
;(async () => {
|
||||||
@@ -111,18 +132,15 @@ Then,
|
|||||||
printAddrs(node1, '1')
|
printAddrs(node1, '1')
|
||||||
printAddrs(node2, '2')
|
printAddrs(node2, '2')
|
||||||
|
|
||||||
node2.handle('/print', ({ stream }) => {
|
node2.handle('/print', async ({ stream }) => {
|
||||||
pipe(
|
const result = await pipe(
|
||||||
stream,
|
stream,
|
||||||
async function (source) {
|
concat
|
||||||
for await (const msg of source) {
|
|
||||||
console.log(msg.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
console.log(result.toString())
|
||||||
})
|
})
|
||||||
|
|
||||||
node1.peerStore.addressBook.set(node2.peerId, node2.multiaddrs)
|
node1.peerStore.addressBook.set(node2.peerId, node2.multiaddrs)
|
||||||
const { stream } = await node1.dialProtocol(node2.peerId, '/print')
|
const { stream } = await node1.dialProtocol(node2.peerId, '/print')
|
||||||
|
|
||||||
await pipe(
|
await pipe(
|
||||||
@@ -131,8 +149,9 @@ node1.peerStore.addressBook.set(node2.peerId, node2.multiaddrs)
|
|||||||
)
|
)
|
||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
For more information refer to the [docs](https://github.com/libp2p/js-libp2p/blob/master/doc/API.md).
|
||||||
|
|
||||||
The result should be look like:
|
The result should look like:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
> node 2.js
|
> node 2.js
|
||||||
@@ -147,29 +166,29 @@ Hello p2p world!
|
|||||||
|
|
||||||
## 3. Using multiple transports
|
## 3. Using multiple transports
|
||||||
|
|
||||||
Next, we want to be available in multiple transports to increase our chances of having common transports in the network. A simple scenario, a node running in the browser only has access to HTTP, WebSockets and WebRTC since the browser doesn't let you open any other kind of transport, for this node to dial to some other node, that other node needs to share a common transport.
|
Next, we want nodes to have multiple transports available to increase their chances of having a common transport in the network to communicate over. A simple scenario is a node running in the browser only having access to HTTP, WebSockets and WebRTC since the browser doesn't let you open any other kind of transport. For this node to dial to some other node, that other node needs to share a common transport.
|
||||||
|
|
||||||
What we are going to do in this step is to create 3 nodes, one with TCP, another with TCP+WebSockets and another one with just WebSockets. The full solution can be found on [3.js](./3.js).
|
What we are going to do in this step is to create 3 nodes: one with TCP, another with TCP+WebSockets and another one with just WebSockets. The full solution can be found on [3.js](./3.js).
|
||||||
|
|
||||||
In this example, we will need to also install `libp2p-websockets`, go ahead and install:
|
In this example, we will need to also install `libp2p-websockets`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
> npm install libp2p-websockets
|
> npm install libp2p-websockets
|
||||||
```
|
```
|
||||||
|
|
||||||
We want to create 3 nodes, one with TCP, one with TCP+WebSockets and one with just WebSockets. We need to update our `createNode` function to contemplate WebSockets as well. Moreover, let's upgrade our function to enable us to pick the addrs in which a node will start a listener:
|
We want to create 3 nodes: one with TCP, one with TCP+WebSockets and one with just WebSockets. We need to update our `createNode` function to accept WebSocket connections as well. Moreover, let's upgrade our function to enable us to pick the addresses over which a node will start a listener:
|
||||||
|
|
||||||
```JavaScript
|
```JavaScript
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
const createNode = async (transports, multiaddrs = []) => {
|
const createNode = async (transports, addresses = []) => {
|
||||||
if (!Array.isArray(multiaddrs)) {
|
if (!Array.isArray(addresses)) {
|
||||||
multiaddrs = [multiaddrs]
|
addresses = [addresses]
|
||||||
}
|
}
|
||||||
|
|
||||||
const node = await Libp2p.create({
|
const node = await Libp2p.create({
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: multiaddrs.map((a) => multiaddr(a))
|
listen: addresses
|
||||||
},
|
},
|
||||||
modules: {
|
modules: {
|
||||||
transport: transports,
|
transport: transports,
|
||||||
@@ -231,7 +250,7 @@ try {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`print` is a function created using the code from 2.js, but factored into its own function to save lines, here it is:
|
`print` is a function that prints each piece of data from a stream onto a new line but factored into its own function to save lines:
|
||||||
|
|
||||||
```JavaScript
|
```JavaScript
|
||||||
function print ({ stream }) {
|
function print ({ stream }) {
|
||||||
@@ -246,7 +265,7 @@ function print ({ stream }) {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If everything was set correctly, you now should see the following after you run the script:
|
If everything was set correctly, you now should see something similar to the following after running the script:
|
||||||
|
|
||||||
```Bash
|
```Bash
|
||||||
> node 3.js
|
> node 3.js
|
||||||
@@ -265,13 +284,13 @@ node 3 failed to dial to node 1 with:
|
|||||||
Error: No transport available for address /ip4/127.0.0.1/tcp/51482
|
Error: No transport available for address /ip4/127.0.0.1/tcp/51482
|
||||||
```
|
```
|
||||||
|
|
||||||
As expected, we created 3 nodes, node 1 with TCP, node 2 with TCP+WebSockets and node 3 with just WebSockets. node 1 -> node 2 and node 2 -> node 3 managed to dial correctly because they shared a common transport, however, node 3 -> node 1 failed because they didn't share any.
|
As expected, we created 3 nodes: node 1 with TCP, node 2 with TCP+WebSockets and node 3 with just WebSockets. node 1 -> node 2 and node 2 -> node 3 managed to dial correctly because they shared a common transport; however, node 3 -> node 1 failed because they didn't share any.
|
||||||
|
|
||||||
## 4. How to create a new libp2p transport
|
## 4. How to create a new libp2p transport
|
||||||
|
|
||||||
Today there are already several transports available and plenty to come, you can find these at [interface-transport implementations](https://github.com/libp2p/js-interfaces/tree/master/src/transport#modules-that-implement-the-interface) list.
|
Today there are already several transports available and plenty to come. You can find these at [interface-transport implementations](https://github.com/libp2p/js-interfaces/tree/master/src/transport#modules-that-implement-the-interface) list.
|
||||||
|
|
||||||
Adding more transports is done through the same way as you added TCP and WebSockets. Some transports might offer extra functionalities, but as far as libp2p is concerned, if it follows the interface defined at the [spec](https://github.com/libp2p/js-interfaces/tree/master/src/transport#api) it will be able to use it.
|
Adding more transports is done through the same way as you added TCP and WebSockets. Some transports might offer extra functionalities, but as far as libp2p is concerned, if it follows the interface defined in the [spec](https://github.com/libp2p/js-interfaces/tree/master/src/transport#api) it will be able to use it.
|
||||||
|
|
||||||
If you decide to implement a transport yourself, please consider adding to the list so that others can use it as well.
|
If you decide to implement a transport yourself, please consider adding to the list so that others can use it as well.
|
||||||
|
|
||||||
|
35
package.json
35
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "libp2p",
|
"name": "libp2p",
|
||||||
"version": "0.29.0",
|
"version": "0.29.4",
|
||||||
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
|
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
|
||||||
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
"mafmt": "^8.0.0",
|
"mafmt": "^8.0.0",
|
||||||
"merge-options": "^2.0.0",
|
"merge-options": "^2.0.0",
|
||||||
"moving-average": "^1.0.0",
|
"moving-average": "^1.0.0",
|
||||||
"multiaddr": "^8.0.0",
|
"multiaddr": "^8.1.0",
|
||||||
"multicodec": "^2.0.0",
|
"multicodec": "^2.0.0",
|
||||||
"multistream-select": "^1.0.0",
|
"multistream-select": "^1.0.0",
|
||||||
"mutable-proxy": "^1.0.0",
|
"mutable-proxy": "^1.0.0",
|
||||||
@@ -105,7 +105,7 @@
|
|||||||
"libp2p-gossipsub": "^0.6.0",
|
"libp2p-gossipsub": "^0.6.0",
|
||||||
"libp2p-kad-dht": "^0.20.0",
|
"libp2p-kad-dht": "^0.20.0",
|
||||||
"libp2p-mdns": "^0.15.0",
|
"libp2p-mdns": "^0.15.0",
|
||||||
"libp2p-mplex": "^0.10.0",
|
"libp2p-mplex": "^0.10.1",
|
||||||
"libp2p-noise": "^2.0.0",
|
"libp2p-noise": "^2.0.0",
|
||||||
"libp2p-secio": "^0.13.1",
|
"libp2p-secio": "^0.13.1",
|
||||||
"libp2p-tcp": "^0.15.1",
|
"libp2p-tcp": "^0.15.1",
|
||||||
@@ -132,39 +132,44 @@
|
|||||||
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
|
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
|
||||||
"Maciej Krüger <mkg20001@gmail.com>",
|
"Maciej Krüger <mkg20001@gmail.com>",
|
||||||
"Hugo Dias <mail@hugodias.me>",
|
"Hugo Dias <mail@hugodias.me>",
|
||||||
"Volker Mische <volker.mische@gmail.com>",
|
|
||||||
"dirkmc <dirkmdev@gmail.com>",
|
"dirkmc <dirkmdev@gmail.com>",
|
||||||
|
"Volker Mische <volker.mische@gmail.com>",
|
||||||
"Richard Littauer <richard.littauer@gmail.com>",
|
"Richard Littauer <richard.littauer@gmail.com>",
|
||||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
"a1300 <matthias-knopp@gmx.net>",
|
||||||
"Andrew Nesbitt <andrewnez@gmail.com>",
|
|
||||||
"Elven <mon.samuel@qq.com>",
|
"Elven <mon.samuel@qq.com>",
|
||||||
|
"Andrew Nesbitt <andrewnez@gmail.com>",
|
||||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||||
"Ryan Bell <ryan@piing.net>",
|
"Ryan Bell <ryan@piing.net>",
|
||||||
"Thomas Eizinger <thomas@eizinger.io>",
|
"Thomas Eizinger <thomas@eizinger.io>",
|
||||||
|
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
||||||
"Didrik Nordström <didrik@betamos.se>",
|
"Didrik Nordström <didrik@betamos.se>",
|
||||||
"Francis Gulotta <wizard@roborooter.com>",
|
"Irakli Gozalishvili <rfobic@gmail.com>",
|
||||||
"Florian-Merle <florian.david.merle@gmail.com>",
|
"Ethan Lam <elmemphis2000@gmail.com>",
|
||||||
"Joel Gustafson <joelg@mit.edu>",
|
"Joel Gustafson <joelg@mit.edu>",
|
||||||
"Julien Bouquillon <contact@revolunet.com>",
|
"Julien Bouquillon <contact@revolunet.com>",
|
||||||
"Kevin Kwok <antimatter15@gmail.com>",
|
"Kevin Kwok <antimatter15@gmail.com>",
|
||||||
"Felipe Martins <felipebrasil93@gmail.com>",
|
|
||||||
"Nuno Nogueira <nunofmn@gmail.com>",
|
"Nuno Nogueira <nunofmn@gmail.com>",
|
||||||
"Fei Liu <liu.feiwood@gmail.com>",
|
|
||||||
"RasmusErik Voel Jensen <github@solsort.com>",
|
|
||||||
"Dmitriy Ryajov <dryajov@gmail.com>",
|
"Dmitriy Ryajov <dryajov@gmail.com>",
|
||||||
|
"RasmusErik Voel Jensen <github@solsort.com>",
|
||||||
|
"Diogo Silva <fsdiogo@gmail.com>",
|
||||||
|
"Samlior <samlior@foxmail.com>",
|
||||||
|
"Smite Chow <xiaopengyou@live.com>",
|
||||||
"Soeren <nikorpoulsen@gmail.com>",
|
"Soeren <nikorpoulsen@gmail.com>",
|
||||||
"Sönke Hahn <soenkehahn@gmail.com>",
|
"Sönke Hahn <soenkehahn@gmail.com>",
|
||||||
|
"robertkiel <robert.kiel@validitylabs.org>",
|
||||||
"Tiago Alves <alvesjtiago@gmail.com>",
|
"Tiago Alves <alvesjtiago@gmail.com>",
|
||||||
"Diogo Silva <fsdiogo@gmail.com>",
|
"Daijiro Wachi <daijiro.wachi@gmail.com>",
|
||||||
"Yusef Napora <yusef@napora.org>",
|
"Yusef Napora <yusef@napora.org>",
|
||||||
"Zane Starr <zcstarr@gmail.com>",
|
"Zane Starr <zcstarr@gmail.com>",
|
||||||
"Daijiro Wachi <daijiro.wachi@gmail.com>",
|
"Cindy Wu <ciindy.wu@gmail.com>",
|
||||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||||
"ebinks <elizabethjbinks@gmail.com>",
|
"ebinks <elizabethjbinks@gmail.com>",
|
||||||
"Bernd Strehl <bernd.strehl@gmail.com>",
|
"Bernd Strehl <bernd.strehl@gmail.com>",
|
||||||
|
"Florian-Merle <florian.david.merle@gmail.com>",
|
||||||
|
"Francis Gulotta <wizard@roborooter.com>",
|
||||||
|
"Felipe Martins <felipebrasil93@gmail.com>",
|
||||||
"isan_rivkin <isanrivkin@gmail.com>",
|
"isan_rivkin <isanrivkin@gmail.com>",
|
||||||
"Henrique Dias <hacdias@gmail.com>",
|
"Henrique Dias <hacdias@gmail.com>",
|
||||||
"robertkiel <robert.kiel@validitylabs.org>",
|
"Fei Liu <liu.feiwood@gmail.com>"
|
||||||
"Irakli Gozalishvili <rfobic@gmail.com>"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,10 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const mergeOptions = require('merge-options')
|
const mergeOptions = require('merge-options')
|
||||||
|
const { dnsaddrResolver } = require('multiaddr/src/resolvers')
|
||||||
|
|
||||||
const Constants = require('./constants')
|
const Constants = require('./constants')
|
||||||
|
const { AGENT_VERSION } = require('./identify/consts')
|
||||||
|
|
||||||
const { FaultTolerance } = require('./transport-manager')
|
const { FaultTolerance } = require('./transport-manager')
|
||||||
|
|
||||||
@@ -20,7 +23,13 @@ const DefaultConfig = {
|
|||||||
dialer: {
|
dialer: {
|
||||||
maxParallelDials: Constants.MAX_PARALLEL_DIALS,
|
maxParallelDials: Constants.MAX_PARALLEL_DIALS,
|
||||||
maxDialsPerPeer: Constants.MAX_PER_PEER_DIALS,
|
maxDialsPerPeer: Constants.MAX_PER_PEER_DIALS,
|
||||||
dialTimeout: Constants.DIAL_TIMEOUT
|
dialTimeout: Constants.DIAL_TIMEOUT,
|
||||||
|
resolvers: {
|
||||||
|
dnsaddr: dnsaddrResolver
|
||||||
|
}
|
||||||
|
},
|
||||||
|
host: {
|
||||||
|
agentVersion: AGENT_VERSION
|
||||||
},
|
},
|
||||||
metrics: {
|
metrics: {
|
||||||
enabled: false
|
enabled: false
|
||||||
|
@@ -27,13 +27,15 @@ class Dialer {
|
|||||||
* @param {number} [options.concurrency = MAX_PARALLEL_DIALS] - Number of max concurrent dials.
|
* @param {number} [options.concurrency = MAX_PARALLEL_DIALS] - Number of max concurrent dials.
|
||||||
* @param {number} [options.perPeerLimit = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
|
* @param {number} [options.perPeerLimit = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
|
||||||
* @param {number} [options.timeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
|
* @param {number} [options.timeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
|
||||||
|
* @param {object} [options.resolvers = {}] - multiaddr resolvers to use when dialing
|
||||||
*/
|
*/
|
||||||
constructor ({
|
constructor ({
|
||||||
transportManager,
|
transportManager,
|
||||||
peerStore,
|
peerStore,
|
||||||
concurrency = MAX_PARALLEL_DIALS,
|
concurrency = MAX_PARALLEL_DIALS,
|
||||||
timeout = DIAL_TIMEOUT,
|
timeout = DIAL_TIMEOUT,
|
||||||
perPeerLimit = MAX_PER_PEER_DIALS
|
perPeerLimit = MAX_PER_PEER_DIALS,
|
||||||
|
resolvers = {}
|
||||||
}) {
|
}) {
|
||||||
this.transportManager = transportManager
|
this.transportManager = transportManager
|
||||||
this.peerStore = peerStore
|
this.peerStore = peerStore
|
||||||
@@ -42,6 +44,10 @@ class Dialer {
|
|||||||
this.perPeerLimit = perPeerLimit
|
this.perPeerLimit = perPeerLimit
|
||||||
this.tokens = [...new Array(concurrency)].map((_, index) => index)
|
this.tokens = [...new Array(concurrency)].map((_, index) => index)
|
||||||
this._pendingDials = new Map()
|
this._pendingDials = new Map()
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(resolvers)) {
|
||||||
|
multiaddr.resolvers.set(key, value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +75,7 @@ class Dialer {
|
|||||||
* @returns {Promise<Connection>}
|
* @returns {Promise<Connection>}
|
||||||
*/
|
*/
|
||||||
async connectToPeer (peer, options = {}) {
|
async connectToPeer (peer, options = {}) {
|
||||||
const dialTarget = this._createDialTarget(peer)
|
const dialTarget = await this._createDialTarget(peer)
|
||||||
|
|
||||||
if (!dialTarget.addrs.length) {
|
if (!dialTarget.addrs.length) {
|
||||||
throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES)
|
throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES)
|
||||||
@@ -105,22 +111,28 @@ class Dialer {
|
|||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {PeerId|Multiaddr|string} peer - A PeerId or Multiaddr
|
* @param {PeerId|Multiaddr|string} peer - A PeerId or Multiaddr
|
||||||
* @returns {DialTarget}
|
* @returns {Promise<DialTarget>}
|
||||||
*/
|
*/
|
||||||
_createDialTarget (peer) {
|
async _createDialTarget (peer) {
|
||||||
const { id, multiaddrs } = getPeer(peer)
|
const { id, multiaddrs } = getPeer(peer)
|
||||||
|
|
||||||
if (multiaddrs) {
|
if (multiaddrs) {
|
||||||
this.peerStore.addressBook.add(id, multiaddrs)
|
this.peerStore.addressBook.add(id, multiaddrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
let addrs = this.peerStore.addressBook.getMultiaddrsForPeer(id) || []
|
let knownAddrs = this.peerStore.addressBook.getMultiaddrsForPeer(id) || []
|
||||||
|
|
||||||
// If received a multiaddr to dial, it should be the first to use
|
// If received a multiaddr to dial, it should be the first to use
|
||||||
// But, if we know other multiaddrs for the peer, we should try them too.
|
// But, if we know other multiaddrs for the peer, we should try them too.
|
||||||
if (multiaddr.isMultiaddr(peer)) {
|
if (multiaddr.isMultiaddr(peer)) {
|
||||||
addrs = addrs.filter((addr) => !peer.equals(addr))
|
knownAddrs = knownAddrs.filter((addr) => !peer.equals(addr))
|
||||||
addrs.unshift(peer)
|
knownAddrs.unshift(peer)
|
||||||
|
}
|
||||||
|
|
||||||
|
const addrs = []
|
||||||
|
for (const a of knownAddrs) {
|
||||||
|
const resolvedAddrs = await this._resolve(a)
|
||||||
|
resolvedAddrs.forEach(ra => addrs.push(ra))
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -190,6 +202,52 @@ class Dialer {
|
|||||||
log('token %d released', token)
|
log('token %d released', token)
|
||||||
this.tokens.push(token)
|
this.tokens.push(token)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve multiaddr recursively.
|
||||||
|
*
|
||||||
|
* @param {Multiaddr} ma
|
||||||
|
* @returns {Promise<Array<Multiaddr>>}
|
||||||
|
*/
|
||||||
|
async _resolve (ma) {
|
||||||
|
// TODO: recursive logic should live in multiaddr once dns4/dns6 support is in place
|
||||||
|
// Now only supporting resolve for dnsaddr
|
||||||
|
const resolvableProto = ma.protoNames().includes('dnsaddr')
|
||||||
|
|
||||||
|
// Multiaddr is not resolvable? End recursion!
|
||||||
|
if (!resolvableProto) {
|
||||||
|
return [ma]
|
||||||
|
}
|
||||||
|
|
||||||
|
const resolvedMultiaddrs = await this._resolveRecord(ma)
|
||||||
|
const recursiveMultiaddrs = await Promise.all(resolvedMultiaddrs.map((nm) => {
|
||||||
|
return this._resolve(nm)
|
||||||
|
}))
|
||||||
|
|
||||||
|
return recursiveMultiaddrs.flat().reduce((array, newM) => {
|
||||||
|
if (!array.find(m => m.equals(newM))) {
|
||||||
|
array.push(newM)
|
||||||
|
}
|
||||||
|
return array
|
||||||
|
}, []) // Unique addresses
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve a given multiaddr. If this fails, an empty array will be returned
|
||||||
|
*
|
||||||
|
* @param {Multiaddr} ma
|
||||||
|
* @returns {Promise<Array<Multiaddr>>}
|
||||||
|
*/
|
||||||
|
async _resolveRecord (ma) {
|
||||||
|
try {
|
||||||
|
ma = multiaddr(ma.toString()) // Use current multiaddr module
|
||||||
|
const multiaddrs = await ma.resolve()
|
||||||
|
return multiaddrs
|
||||||
|
} catch (_) {
|
||||||
|
log.error(`multiaddr ${ma} could not be resolved`)
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = Dialer
|
module.exports = Dialer
|
||||||
|
@@ -16,6 +16,7 @@ exports.codes = {
|
|||||||
ERR_NODE_NOT_STARTED: 'ERR_NODE_NOT_STARTED',
|
ERR_NODE_NOT_STARTED: 'ERR_NODE_NOT_STARTED',
|
||||||
ERR_ALREADY_ABORTED: 'ERR_ALREADY_ABORTED',
|
ERR_ALREADY_ABORTED: 'ERR_ALREADY_ABORTED',
|
||||||
ERR_NO_VALID_ADDRESSES: 'ERR_NO_VALID_ADDRESSES',
|
ERR_NO_VALID_ADDRESSES: 'ERR_NO_VALID_ADDRESSES',
|
||||||
|
ERR_DIALED_SELF: 'ERR_DIALED_SELF',
|
||||||
ERR_DISCOVERED_SELF: 'ERR_DISCOVERED_SELF',
|
ERR_DISCOVERED_SELF: 'ERR_DISCOVERED_SELF',
|
||||||
ERR_DUPLICATE_TRANSPORT: 'ERR_DUPLICATE_TRANSPORT',
|
ERR_DUPLICATE_TRANSPORT: 'ERR_DUPLICATE_TRANSPORT',
|
||||||
ERR_ENCRYPTION_FAILED: 'ERR_ENCRYPTION_FAILED',
|
ERR_ENCRYPTION_FAILED: 'ERR_ENCRYPTION_FAILED',
|
||||||
|
@@ -83,6 +83,16 @@ class IdentifyService {
|
|||||||
this._protocols = protocols
|
this._protocols = protocols
|
||||||
|
|
||||||
this.handleMessage = this.handleMessage.bind(this)
|
this.handleMessage = this.handleMessage.bind(this)
|
||||||
|
|
||||||
|
// Store self host metadata
|
||||||
|
this._host = {
|
||||||
|
agentVersion: AGENT_VERSION,
|
||||||
|
protocolVersion: PROTOCOL_VERSION,
|
||||||
|
...libp2p._options.host
|
||||||
|
}
|
||||||
|
|
||||||
|
this.peerStore.metadataBook.set(this.peerId, 'AgentVersion', uint8ArrayFromString(this._host.agentVersion))
|
||||||
|
this.peerStore.metadataBook.set(this.peerId, 'ProtocolVersion', uint8ArrayFromString(this._host.protocolVersion))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -246,8 +256,8 @@ class IdentifyService {
|
|||||||
const signedPeerRecord = await this._getSelfPeerRecord()
|
const signedPeerRecord = await this._getSelfPeerRecord()
|
||||||
|
|
||||||
const message = Message.encode({
|
const message = Message.encode({
|
||||||
protocolVersion: PROTOCOL_VERSION,
|
protocolVersion: this._host.protocolVersion,
|
||||||
agentVersion: AGENT_VERSION,
|
agentVersion: this._host.agentVersion,
|
||||||
publicKey,
|
publicKey,
|
||||||
listenAddrs: this._libp2p.multiaddrs.map((ma) => ma.bytes),
|
listenAddrs: this._libp2p.multiaddrs.map((ma) => ma.bytes),
|
||||||
signedPeerRecord,
|
signedPeerRecord,
|
||||||
|
12
src/index.js
12
src/index.js
@@ -134,7 +134,8 @@ class Libp2p extends EventEmitter {
|
|||||||
peerStore: this.peerStore,
|
peerStore: this.peerStore,
|
||||||
concurrency: this._options.dialer.maxParallelDials,
|
concurrency: this._options.dialer.maxParallelDials,
|
||||||
perPeerLimit: this._options.dialer.maxDialsPerPeer,
|
perPeerLimit: this._options.dialer.maxDialsPerPeer,
|
||||||
timeout: this._options.dialer.dialTimeout
|
timeout: this._options.dialer.dialTimeout,
|
||||||
|
resolvers: this._options.dialer.resolvers
|
||||||
})
|
})
|
||||||
|
|
||||||
this._modules.transport.forEach((Transport) => {
|
this._modules.transport.forEach((Transport) => {
|
||||||
@@ -241,7 +242,7 @@ class Libp2p extends EventEmitter {
|
|||||||
* Stop the libp2p node by closing its listeners and open connections
|
* Stop the libp2p node by closing its listeners and open connections
|
||||||
*
|
*
|
||||||
* @async
|
* @async
|
||||||
* @returns {void}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async stop () {
|
async stop () {
|
||||||
log('libp2p is stopping')
|
log('libp2p is stopping')
|
||||||
@@ -334,6 +335,11 @@ class Libp2p extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
async dialProtocol (peer, protocols, options) {
|
async dialProtocol (peer, protocols, options) {
|
||||||
const { id, multiaddrs } = getPeer(peer)
|
const { id, multiaddrs } = getPeer(peer)
|
||||||
|
|
||||||
|
if (id.equals(this.peerId)) {
|
||||||
|
throw errCode(new Error('Cannot dial self'), codes.ERR_DIALED_SELF)
|
||||||
|
}
|
||||||
|
|
||||||
let connection = this.connectionManager.get(id)
|
let connection = this.connectionManager.get(id)
|
||||||
|
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
@@ -600,7 +606,7 @@ class Libp2p extends EventEmitter {
|
|||||||
* instance if one is not provided in options.
|
* instance if one is not provided in options.
|
||||||
*
|
*
|
||||||
* @param {object} options - Libp2p configuration options
|
* @param {object} options - Libp2p configuration options
|
||||||
* @returns {Libp2p}
|
* @returns {Promise<Libp2p>}
|
||||||
*/
|
*/
|
||||||
Libp2p.create = async function create (options = {}) {
|
Libp2p.create = async function create (options = {}) {
|
||||||
if (options.peerId) {
|
if (options.peerId) {
|
||||||
|
@@ -20,6 +20,7 @@ class TransportManager {
|
|||||||
this.upgrader = upgrader
|
this.upgrader = upgrader
|
||||||
this._transports = new Map()
|
this._transports = new Map()
|
||||||
this._listeners = new Map()
|
this._listeners = new Map()
|
||||||
|
this._listenerOptions = new Map()
|
||||||
this.faultTolerance = faultTolerance
|
this.faultTolerance = faultTolerance
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@ class TransportManager {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this._transports.set(key, transport)
|
this._transports.set(key, transport)
|
||||||
|
this._listenerOptions.set(key, transportOptions.listenerOptions || {})
|
||||||
if (!this._listeners.has(key)) {
|
if (!this._listeners.has(key)) {
|
||||||
this._listeners.set(key, [])
|
this._listeners.set(key, [])
|
||||||
}
|
}
|
||||||
@@ -154,7 +156,7 @@ class TransportManager {
|
|||||||
// For each supported multiaddr, create a listener
|
// For each supported multiaddr, create a listener
|
||||||
for (const addr of supportedAddrs) {
|
for (const addr of supportedAddrs) {
|
||||||
log('creating listener for %s on %s', key, addr)
|
log('creating listener for %s on %s', key, addr)
|
||||||
const listener = transport.createListener({}, this.onConnection)
|
const listener = transport.createListener(this._listenerOptions.get(key), this.onConnection)
|
||||||
this._listeners.get(key).push(listener)
|
this._listeners.get(key).push(listener)
|
||||||
|
|
||||||
// We need to attempt to listen on everything
|
// We need to attempt to listen on everything
|
||||||
|
@@ -5,6 +5,7 @@ const log = debug('libp2p:upgrader')
|
|||||||
log.error = debug('libp2p:upgrader:error')
|
log.error = debug('libp2p:upgrader:error')
|
||||||
const Multistream = require('multistream-select')
|
const Multistream = require('multistream-select')
|
||||||
const { Connection } = require('libp2p-interfaces/src/connection')
|
const { Connection } = require('libp2p-interfaces/src/connection')
|
||||||
|
const ConnectionStatus = require('libp2p-interfaces/src/connection/status')
|
||||||
const PeerId = require('peer-id')
|
const PeerId = require('peer-id')
|
||||||
const pipe = require('it-pipe')
|
const pipe = require('it-pipe')
|
||||||
const errCode = require('err-code')
|
const errCode = require('err-code')
|
||||||
@@ -268,8 +269,18 @@ class Upgrader {
|
|||||||
maConn.timeline = new Proxy(_timeline, {
|
maConn.timeline = new Proxy(_timeline, {
|
||||||
set: (...args) => {
|
set: (...args) => {
|
||||||
if (connection && args[1] === 'close' && args[2] && !_timeline.close) {
|
if (connection && args[1] === 'close' && args[2] && !_timeline.close) {
|
||||||
connection.stat.status = 'closed'
|
// Wait for close to finish before notifying of the closure
|
||||||
this.onConnectionEnd(connection)
|
(async () => {
|
||||||
|
try {
|
||||||
|
if (connection.stat.status === ConnectionStatus.OPEN) {
|
||||||
|
await connection.close()
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
log.error(err)
|
||||||
|
} finally {
|
||||||
|
this.onConnectionEnd(connection)
|
||||||
|
}
|
||||||
|
})()
|
||||||
}
|
}
|
||||||
|
|
||||||
return Reflect.set(...args)
|
return Reflect.set(...args)
|
||||||
@@ -295,7 +306,13 @@ class Upgrader {
|
|||||||
},
|
},
|
||||||
newStream: newStream || errConnectionNotMultiplexed,
|
newStream: newStream || errConnectionNotMultiplexed,
|
||||||
getStreams: () => muxer ? muxer.streams : errConnectionNotMultiplexed,
|
getStreams: () => muxer ? muxer.streams : errConnectionNotMultiplexed,
|
||||||
close: err => maConn.close(err)
|
close: async (err) => {
|
||||||
|
await maConn.close(err)
|
||||||
|
// Ensure remaining streams are aborted
|
||||||
|
if (muxer) {
|
||||||
|
muxer.streams.map(stream => stream.abort(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.onConnection(connection)
|
this.onConnection(connection)
|
||||||
|
@@ -18,10 +18,16 @@ const listenMultiaddr = '/ip4/127.0.0.1/tcp/15002/ws'
|
|||||||
|
|
||||||
describe('Connection Manager', () => {
|
describe('Connection Manager', () => {
|
||||||
let libp2p
|
let libp2p
|
||||||
|
let peerIds
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
peerIds = await peerUtils.createPeerId({ number: 2 })
|
||||||
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
[libp2p] = await peerUtils.createPeer({
|
[libp2p] = await peerUtils.createPeer({
|
||||||
config: {
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: [listenMultiaddr]
|
listen: [listenMultiaddr]
|
||||||
},
|
},
|
||||||
@@ -33,12 +39,10 @@ describe('Connection Manager', () => {
|
|||||||
afterEach(() => libp2p.stop())
|
afterEach(() => libp2p.stop())
|
||||||
|
|
||||||
it('should filter connections on disconnect, removing the closed one', async () => {
|
it('should filter connections on disconnect, removing the closed one', async () => {
|
||||||
const [localPeer, remotePeer] = await peerUtils.createPeerId({ number: 2 })
|
const conn1 = await mockConnection({ localPeer: peerIds[0], remotePeer: peerIds[1] })
|
||||||
|
const conn2 = await mockConnection({ localPeer: peerIds[0], remotePeer: peerIds[1] })
|
||||||
|
|
||||||
const conn1 = await mockConnection({ localPeer, remotePeer })
|
const id = peerIds[1].toB58String()
|
||||||
const conn2 = await mockConnection({ localPeer, remotePeer })
|
|
||||||
|
|
||||||
const id = remotePeer.toB58String()
|
|
||||||
|
|
||||||
// Add connection to the connectionManager
|
// Add connection to the connectionManager
|
||||||
libp2p.connectionManager.onConnect(conn1)
|
libp2p.connectionManager.onConnect(conn1)
|
||||||
@@ -57,6 +61,7 @@ describe('Connection Manager', () => {
|
|||||||
it('should add connection on dial and remove on node stop', async () => {
|
it('should add connection on dial and remove on node stop', async () => {
|
||||||
const [remoteLibp2p] = await peerUtils.createPeer({
|
const [remoteLibp2p] = await peerUtils.createPeer({
|
||||||
config: {
|
config: {
|
||||||
|
peerId: peerIds[1],
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: ['/ip4/127.0.0.1/tcp/15003/ws']
|
listen: ['/ip4/127.0.0.1/tcp/15003/ws']
|
||||||
},
|
},
|
||||||
@@ -89,9 +94,16 @@ describe('Connection Manager', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('libp2p.connections', () => {
|
describe('libp2p.connections', () => {
|
||||||
|
let peerIds
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
peerIds = await peerUtils.createPeerId({ number: 2 })
|
||||||
|
})
|
||||||
|
|
||||||
it('libp2p.connections gets the connectionManager conns', async () => {
|
it('libp2p.connections gets the connectionManager conns', async () => {
|
||||||
const [libp2p] = await peerUtils.createPeer({
|
const [libp2p] = await peerUtils.createPeer({
|
||||||
config: {
|
config: {
|
||||||
|
peerId: peerIds[0],
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: ['/ip4/127.0.0.1/tcp/15003/ws']
|
listen: ['/ip4/127.0.0.1/tcp/15003/ws']
|
||||||
},
|
},
|
||||||
@@ -100,6 +112,7 @@ describe('libp2p.connections', () => {
|
|||||||
})
|
})
|
||||||
const [remoteLibp2p] = await peerUtils.createPeer({
|
const [remoteLibp2p] = await peerUtils.createPeer({
|
||||||
config: {
|
config: {
|
||||||
|
peerId: peerIds[1],
|
||||||
addresses: {
|
addresses: {
|
||||||
listen: ['/ip4/127.0.0.1/tcp/15004/ws']
|
listen: ['/ip4/127.0.0.1/tcp/15004/ws']
|
||||||
},
|
},
|
||||||
|
@@ -11,7 +11,9 @@ const PeerId = require('peer-id')
|
|||||||
const delay = require('delay')
|
const delay = require('delay')
|
||||||
const pDefer = require('p-defer')
|
const pDefer = require('p-defer')
|
||||||
const pSettle = require('p-settle')
|
const pSettle = require('p-settle')
|
||||||
|
const pWaitFor = require('p-wait-for')
|
||||||
const pipe = require('it-pipe')
|
const pipe = require('it-pipe')
|
||||||
|
const pushable = require('it-pushable')
|
||||||
const AggregateError = require('aggregate-error')
|
const AggregateError = require('aggregate-error')
|
||||||
const { Connection } = require('libp2p-interfaces/src/connection')
|
const { Connection } = require('libp2p-interfaces/src/connection')
|
||||||
const { AbortError } = require('libp2p-interfaces/src/transport/errors')
|
const { AbortError } = require('libp2p-interfaces/src/transport/errors')
|
||||||
@@ -156,9 +158,9 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
|
|
||||||
it('should dial to the max concurrency', async () => {
|
it('should dial to the max concurrency', async () => {
|
||||||
const addrs = [
|
const addrs = [
|
||||||
'/ip4/0.0.0.0/tcp/8000',
|
multiaddr('/ip4/0.0.0.0/tcp/8000'),
|
||||||
'/ip4/0.0.0.0/tcp/8001',
|
multiaddr('/ip4/0.0.0.0/tcp/8001'),
|
||||||
'/ip4/0.0.0.0/tcp/8002'
|
multiaddr('/ip4/0.0.0.0/tcp/8002')
|
||||||
]
|
]
|
||||||
const dialer = new Dialer({
|
const dialer = new Dialer({
|
||||||
transportManager: localTM,
|
transportManager: localTM,
|
||||||
@@ -299,6 +301,50 @@ describe('Dialing (direct, TCP)', () => {
|
|||||||
expect(libp2p.dialer.connectToPeer.callCount).to.equal(1)
|
expect(libp2p.dialer.connectToPeer.callCount).to.equal(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should close all streams when the connection closes', async () => {
|
||||||
|
libp2p = new Libp2p({
|
||||||
|
peerId,
|
||||||
|
modules: {
|
||||||
|
transport: [Transport],
|
||||||
|
streamMuxer: [Muxer],
|
||||||
|
connEncryption: [Crypto]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// register some stream handlers to simulate several protocols
|
||||||
|
libp2p.handle('/stream-count/1', ({ stream }) => pipe(stream, stream))
|
||||||
|
libp2p.handle('/stream-count/2', ({ stream }) => pipe(stream, stream))
|
||||||
|
remoteLibp2p.handle('/stream-count/3', ({ stream }) => pipe(stream, stream))
|
||||||
|
remoteLibp2p.handle('/stream-count/4', ({ stream }) => pipe(stream, stream))
|
||||||
|
|
||||||
|
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
|
||||||
|
const connection = await libp2p.dial(remotePeerId)
|
||||||
|
|
||||||
|
// Create local to remote streams
|
||||||
|
const { stream } = await connection.newStream('/echo/1.0.0')
|
||||||
|
await connection.newStream('/stream-count/3')
|
||||||
|
await libp2p.dialProtocol(remoteLibp2p.peerId, '/stream-count/4')
|
||||||
|
|
||||||
|
// Partially write to the echo stream
|
||||||
|
const source = pushable()
|
||||||
|
stream.sink(source)
|
||||||
|
source.push('hello')
|
||||||
|
|
||||||
|
// Create remote to local streams
|
||||||
|
await remoteLibp2p.dialProtocol(libp2p.peerId, '/stream-count/1')
|
||||||
|
await remoteLibp2p.dialProtocol(libp2p.peerId, '/stream-count/2')
|
||||||
|
|
||||||
|
// Verify stream count
|
||||||
|
const remoteConn = remoteLibp2p.connectionManager.get(libp2p.peerId)
|
||||||
|
expect(connection.streams).to.have.length(5)
|
||||||
|
expect(remoteConn.streams).to.have.length(5)
|
||||||
|
|
||||||
|
// Close the connection and verify all streams have been closed
|
||||||
|
await connection.close()
|
||||||
|
await pWaitFor(() => connection.streams.length === 0)
|
||||||
|
await pWaitFor(() => remoteConn.streams.length === 0)
|
||||||
|
})
|
||||||
|
|
||||||
it('should be able to use hangup to close connections', async () => {
|
it('should be able to use hangup to close connections', async () => {
|
||||||
libp2p = new Libp2p({
|
libp2p = new Libp2p({
|
||||||
peerId,
|
peerId,
|
||||||
|
@@ -263,7 +263,6 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
|
|
||||||
describe('libp2p.dialer', () => {
|
describe('libp2p.dialer', () => {
|
||||||
let libp2p
|
let libp2p
|
||||||
let remoteLibp2p
|
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
sinon.restore()
|
sinon.restore()
|
||||||
@@ -271,10 +270,6 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
libp2p = null
|
libp2p = null
|
||||||
})
|
})
|
||||||
|
|
||||||
after(async () => {
|
|
||||||
remoteLibp2p && await remoteLibp2p.stop()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should create a dialer', () => {
|
it('should create a dialer', () => {
|
||||||
libp2p = new Libp2p({
|
libp2p = new Libp2p({
|
||||||
peerId,
|
peerId,
|
||||||
@@ -414,5 +409,20 @@ describe('Dialing (direct, WebSockets)', () => {
|
|||||||
|
|
||||||
expect(libp2p.dialer.destroy).to.have.property('callCount', 1)
|
expect(libp2p.dialer.destroy).to.have.property('callCount', 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should fail to dial self', async () => {
|
||||||
|
libp2p = new Libp2p({
|
||||||
|
peerId,
|
||||||
|
modules: {
|
||||||
|
transport: [Transport],
|
||||||
|
streamMuxer: [Muxer],
|
||||||
|
connEncryption: [Crypto]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(libp2p.dial(peerId))
|
||||||
|
.to.eventually.be.rejected()
|
||||||
|
.and.to.have.property('code', ErrorCodes.ERR_DIALED_SELF)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
176
test/dialing/resolver.spec.js
Normal file
176
test/dialing/resolver.spec.js
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
'use strict'
|
||||||
|
/* eslint-env mocha */
|
||||||
|
|
||||||
|
const { expect } = require('aegir/utils/chai')
|
||||||
|
const sinon = require('sinon')
|
||||||
|
|
||||||
|
const multiaddr = require('multiaddr')
|
||||||
|
const { Resolver } = require('multiaddr/src/resolvers/dns')
|
||||||
|
|
||||||
|
const { codes: ErrorCodes } = require('../../src/errors')
|
||||||
|
|
||||||
|
const peerUtils = require('../utils/creators/peer')
|
||||||
|
const baseOptions = require('../utils/base-options.browser')
|
||||||
|
|
||||||
|
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
|
||||||
|
const relayAddr = MULTIADDRS_WEBSOCKETS[0]
|
||||||
|
|
||||||
|
const getDnsaddrStub = (peerId) => [
|
||||||
|
[`dnsaddr=/dnsaddr/ams-1.bootstrap.libp2p.io/p2p/${peerId}`],
|
||||||
|
[`dnsaddr=/dnsaddr/ams-2.bootstrap.libp2p.io/p2p/${peerId}`],
|
||||||
|
[`dnsaddr=/dnsaddr/lon-1.bootstrap.libp2p.io/p2p/${peerId}`],
|
||||||
|
[`dnsaddr=/dnsaddr/nrt-1.bootstrap.libp2p.io/p2p/${peerId}`],
|
||||||
|
[`dnsaddr=/dnsaddr/nyc-1.bootstrap.libp2p.io/p2p/${peerId}`],
|
||||||
|
[`dnsaddr=/dnsaddr/sfo-2.bootstrap.libp2p.io/p2p/${peerId}`]
|
||||||
|
]
|
||||||
|
|
||||||
|
const relayedAddr = (peerId) => `${relayAddr}/p2p-circuit/p2p/${peerId}`
|
||||||
|
|
||||||
|
const getDnsRelayedAddrStub = (peerId) => [
|
||||||
|
[`dnsaddr=${relayedAddr(peerId)}`]
|
||||||
|
]
|
||||||
|
|
||||||
|
describe('Dialing (resolvable addresses)', () => {
|
||||||
|
let libp2p, remoteLibp2p
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
[libp2p, remoteLibp2p] = await peerUtils.createPeer({
|
||||||
|
number: 2,
|
||||||
|
config: {
|
||||||
|
modules: baseOptions.modules,
|
||||||
|
addresses: {
|
||||||
|
listen: [multiaddr(`${relayAddr}/p2p-circuit`)]
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
peerDiscovery: {
|
||||||
|
autoDial: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
started: true,
|
||||||
|
populateAddressBooks: false
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
sinon.restore()
|
||||||
|
await Promise.all([libp2p, remoteLibp2p].map(n => n.stop()))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('resolves dnsaddr to ws local address', async () => {
|
||||||
|
const remoteId = remoteLibp2p.peerId.toB58String()
|
||||||
|
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
|
||||||
|
const relayedAddrFetched = multiaddr(relayedAddr(remoteId))
|
||||||
|
|
||||||
|
// Transport spy
|
||||||
|
const transport = libp2p.transportManager._transports.get('Circuit')
|
||||||
|
sinon.spy(transport, 'dial')
|
||||||
|
|
||||||
|
// Resolver stub
|
||||||
|
const stub = sinon.stub(Resolver.prototype, 'resolveTxt')
|
||||||
|
stub.onCall(0).returns(Promise.resolve(getDnsRelayedAddrStub(remoteId)))
|
||||||
|
|
||||||
|
// Dial with address resolve
|
||||||
|
const connection = await libp2p.dial(dialAddr)
|
||||||
|
expect(connection).to.exist()
|
||||||
|
expect(connection.remoteAddr.equals(relayedAddrFetched))
|
||||||
|
|
||||||
|
const dialArgs = transport.dial.firstCall.args
|
||||||
|
expect(dialArgs[0].equals(relayedAddrFetched)).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('resolves a dnsaddr recursively', async () => {
|
||||||
|
const remoteId = remoteLibp2p.peerId.toB58String()
|
||||||
|
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
|
||||||
|
const relayedAddrFetched = multiaddr(relayedAddr(remoteId))
|
||||||
|
|
||||||
|
// Transport spy
|
||||||
|
const transport = libp2p.transportManager._transports.get('Circuit')
|
||||||
|
sinon.spy(transport, 'dial')
|
||||||
|
|
||||||
|
// Resolver stub
|
||||||
|
const stub = sinon.stub(Resolver.prototype, 'resolveTxt')
|
||||||
|
let firstCall = false
|
||||||
|
stub.callsFake(() => {
|
||||||
|
if (!firstCall) {
|
||||||
|
firstCall = true
|
||||||
|
// Return an array of dnsaddr
|
||||||
|
return Promise.resolve(getDnsaddrStub(remoteId))
|
||||||
|
}
|
||||||
|
return Promise.resolve(getDnsRelayedAddrStub(remoteId))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Dial with address resolve
|
||||||
|
const connection = await libp2p.dial(dialAddr)
|
||||||
|
expect(connection).to.exist()
|
||||||
|
expect(connection.remoteAddr.equals(relayedAddrFetched))
|
||||||
|
|
||||||
|
const dialArgs = transport.dial.firstCall.args
|
||||||
|
expect(dialArgs[0].equals(relayedAddrFetched)).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
// TODO: Temporary solution does not resolve dns4/dns6
|
||||||
|
// Resolver just returns the received multiaddrs
|
||||||
|
it('stops recursive resolve if finds dns4/dns6 and dials it', async () => {
|
||||||
|
const remoteId = remoteLibp2p.peerId.toB58String()
|
||||||
|
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
|
||||||
|
|
||||||
|
// Stub resolver
|
||||||
|
const dnsMa = multiaddr(`/dns4/ams-1.remote.libp2p.io/tcp/443/wss/p2p/${remoteId}`)
|
||||||
|
const stubResolve = sinon.stub(Resolver.prototype, 'resolveTxt')
|
||||||
|
stubResolve.returns(Promise.resolve([
|
||||||
|
[`dnsaddr=${dnsMa}`]
|
||||||
|
]))
|
||||||
|
|
||||||
|
// Stub transport
|
||||||
|
const transport = libp2p.transportManager._transports.get('WebSockets')
|
||||||
|
const stubTransport = sinon.stub(transport, 'dial')
|
||||||
|
stubTransport.callsFake((multiaddr) => {
|
||||||
|
expect(multiaddr.equals(dnsMa)).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
await libp2p.dial(dialAddr)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('resolves a dnsaddr recursively not failing if one address fails to resolve', async () => {
|
||||||
|
const remoteId = remoteLibp2p.peerId.toB58String()
|
||||||
|
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
|
||||||
|
const relayedAddrFetched = multiaddr(relayedAddr(remoteId))
|
||||||
|
|
||||||
|
// Transport spy
|
||||||
|
const transport = libp2p.transportManager._transports.get('Circuit')
|
||||||
|
sinon.spy(transport, 'dial')
|
||||||
|
|
||||||
|
// Resolver stub
|
||||||
|
const stub = sinon.stub(Resolver.prototype, 'resolveTxt')
|
||||||
|
stub.onCall(0).callsFake(() => Promise.resolve(getDnsaddrStub(remoteId)))
|
||||||
|
stub.onCall(1).callsFake(() => Promise.reject(new Error()))
|
||||||
|
stub.callsFake(() => Promise.resolve(getDnsRelayedAddrStub(remoteId)))
|
||||||
|
|
||||||
|
// Dial with address resolve
|
||||||
|
const connection = await libp2p.dial(dialAddr)
|
||||||
|
expect(connection).to.exist()
|
||||||
|
expect(connection.remoteAddr.equals(relayedAddrFetched))
|
||||||
|
|
||||||
|
const dialArgs = transport.dial.firstCall.args
|
||||||
|
expect(dialArgs[0].equals(relayedAddrFetched)).to.eql(true)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fails to dial if resolve fails and there are no addresses to dial', async () => {
|
||||||
|
const remoteId = remoteLibp2p.peerId.toB58String()
|
||||||
|
const dialAddr = multiaddr(`/dnsaddr/remote.libp2p.io/p2p/${remoteId}`)
|
||||||
|
|
||||||
|
// Stub resolver
|
||||||
|
const stubResolve = sinon.stub(Resolver.prototype, 'resolveTxt')
|
||||||
|
stubResolve.returns(Promise.reject(new Error()))
|
||||||
|
|
||||||
|
// Stub transport
|
||||||
|
const transport = libp2p.transportManager._transports.get('WebSockets')
|
||||||
|
const spy = sinon.spy(transport, 'dial')
|
||||||
|
|
||||||
|
await expect(libp2p.dial(dialAddr))
|
||||||
|
.to.eventually.be.rejectedWith(Error)
|
||||||
|
.and.to.have.nested.property('.code', ErrorCodes.ERR_NO_VALID_ADDRESSES)
|
||||||
|
expect(spy.callCount).to.eql(0)
|
||||||
|
})
|
||||||
|
})
|
@@ -53,7 +53,8 @@ describe('Identify', () => {
|
|||||||
peerId: localPeer,
|
peerId: localPeer,
|
||||||
connectionManager: new EventEmitter(),
|
connectionManager: new EventEmitter(),
|
||||||
peerStore: new PeerStore({ peerId: localPeer }),
|
peerStore: new PeerStore({ peerId: localPeer }),
|
||||||
multiaddrs: listenMaddrs
|
multiaddrs: listenMaddrs,
|
||||||
|
_options: { host: {} }
|
||||||
},
|
},
|
||||||
protocols
|
protocols
|
||||||
})
|
})
|
||||||
@@ -63,7 +64,8 @@ describe('Identify', () => {
|
|||||||
peerId: remotePeer,
|
peerId: remotePeer,
|
||||||
connectionManager: new EventEmitter(),
|
connectionManager: new EventEmitter(),
|
||||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||||
multiaddrs: listenMaddrs
|
multiaddrs: listenMaddrs,
|
||||||
|
_options: { host: {} }
|
||||||
},
|
},
|
||||||
protocols
|
protocols
|
||||||
})
|
})
|
||||||
@@ -106,7 +108,8 @@ describe('Identify', () => {
|
|||||||
peerId: localPeer,
|
peerId: localPeer,
|
||||||
connectionManager: new EventEmitter(),
|
connectionManager: new EventEmitter(),
|
||||||
peerStore: new PeerStore({ peerId: localPeer }),
|
peerStore: new PeerStore({ peerId: localPeer }),
|
||||||
multiaddrs: listenMaddrs
|
multiaddrs: listenMaddrs,
|
||||||
|
_options: { host: {} }
|
||||||
},
|
},
|
||||||
protocols
|
protocols
|
||||||
})
|
})
|
||||||
@@ -116,7 +119,8 @@ describe('Identify', () => {
|
|||||||
peerId: remotePeer,
|
peerId: remotePeer,
|
||||||
connectionManager: new EventEmitter(),
|
connectionManager: new EventEmitter(),
|
||||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||||
multiaddrs: listenMaddrs
|
multiaddrs: listenMaddrs,
|
||||||
|
_options: { host: {} }
|
||||||
},
|
},
|
||||||
protocols
|
protocols
|
||||||
})
|
})
|
||||||
@@ -165,7 +169,8 @@ describe('Identify', () => {
|
|||||||
peerId: localPeer,
|
peerId: localPeer,
|
||||||
connectionManager: new EventEmitter(),
|
connectionManager: new EventEmitter(),
|
||||||
peerStore: new PeerStore({ peerId: localPeer }),
|
peerStore: new PeerStore({ peerId: localPeer }),
|
||||||
multiaddrs: []
|
multiaddrs: [],
|
||||||
|
_options: { host: {} }
|
||||||
},
|
},
|
||||||
protocols
|
protocols
|
||||||
})
|
})
|
||||||
@@ -174,7 +179,8 @@ describe('Identify', () => {
|
|||||||
peerId: remotePeer,
|
peerId: remotePeer,
|
||||||
connectionManager: new EventEmitter(),
|
connectionManager: new EventEmitter(),
|
||||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||||
multiaddrs: []
|
multiaddrs: [],
|
||||||
|
_options: { host: {} }
|
||||||
},
|
},
|
||||||
protocols
|
protocols
|
||||||
})
|
})
|
||||||
@@ -201,6 +207,36 @@ describe('Identify', () => {
|
|||||||
.and.to.have.property('code', Errors.ERR_INVALID_PEER)
|
.and.to.have.property('code', Errors.ERR_INVALID_PEER)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should store host data and protocol version into metadataBook', () => {
|
||||||
|
const agentVersion = 'js-project/1.0.0'
|
||||||
|
const peerStore = new PeerStore({ peerId: localPeer })
|
||||||
|
|
||||||
|
sinon.spy(peerStore.metadataBook, 'set')
|
||||||
|
|
||||||
|
new IdentifyService({ // eslint-disable-line no-new
|
||||||
|
libp2p: {
|
||||||
|
peerId: localPeer,
|
||||||
|
connectionManager: new EventEmitter(),
|
||||||
|
peerStore,
|
||||||
|
multiaddrs: listenMaddrs,
|
||||||
|
_options: {
|
||||||
|
host: {
|
||||||
|
agentVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
protocols
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(peerStore.metadataBook.set.callCount).to.eql(2)
|
||||||
|
|
||||||
|
const storedAgentVersion = peerStore.metadataBook.getValue(localPeer, 'AgentVersion')
|
||||||
|
const storedProtocolVersion = peerStore.metadataBook.getValue(localPeer, 'ProtocolVersion')
|
||||||
|
|
||||||
|
expect(agentVersion).to.eql(unit8ArrayToString(storedAgentVersion))
|
||||||
|
expect(storedProtocolVersion).to.exist()
|
||||||
|
})
|
||||||
|
|
||||||
describe('push', () => {
|
describe('push', () => {
|
||||||
it('should be able to push identify updates to another peer', async () => {
|
it('should be able to push identify updates to another peer', async () => {
|
||||||
const connectionManager = new EventEmitter()
|
const connectionManager = new EventEmitter()
|
||||||
@@ -211,7 +247,8 @@ describe('Identify', () => {
|
|||||||
peerId: localPeer,
|
peerId: localPeer,
|
||||||
connectionManager: new EventEmitter(),
|
connectionManager: new EventEmitter(),
|
||||||
peerStore: new PeerStore({ peerId: localPeer }),
|
peerStore: new PeerStore({ peerId: localPeer }),
|
||||||
multiaddrs: listenMaddrs
|
multiaddrs: listenMaddrs,
|
||||||
|
_options: { host: {} }
|
||||||
},
|
},
|
||||||
protocols: new Map([
|
protocols: new Map([
|
||||||
[multicodecs.IDENTIFY],
|
[multicodecs.IDENTIFY],
|
||||||
@@ -224,7 +261,8 @@ describe('Identify', () => {
|
|||||||
peerId: remotePeer,
|
peerId: remotePeer,
|
||||||
connectionManager,
|
connectionManager,
|
||||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||||
multiaddrs: []
|
multiaddrs: [],
|
||||||
|
_options: { host: {} }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -272,7 +310,8 @@ describe('Identify', () => {
|
|||||||
peerId: localPeer,
|
peerId: localPeer,
|
||||||
connectionManager: new EventEmitter(),
|
connectionManager: new EventEmitter(),
|
||||||
peerStore: new PeerStore({ peerId: localPeer }),
|
peerStore: new PeerStore({ peerId: localPeer }),
|
||||||
multiaddrs: listenMaddrs
|
multiaddrs: listenMaddrs,
|
||||||
|
_options: { host: {} }
|
||||||
},
|
},
|
||||||
protocols: new Map([
|
protocols: new Map([
|
||||||
[multicodecs.IDENTIFY],
|
[multicodecs.IDENTIFY],
|
||||||
@@ -285,7 +324,8 @@ describe('Identify', () => {
|
|||||||
peerId: remotePeer,
|
peerId: remotePeer,
|
||||||
connectionManager,
|
connectionManager,
|
||||||
peerStore: new PeerStore({ peerId: remotePeer }),
|
peerStore: new PeerStore({ peerId: remotePeer }),
|
||||||
multiaddrs: []
|
multiaddrs: [],
|
||||||
|
_options: { host: {} }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -404,5 +444,23 @@ describe('Identify', () => {
|
|||||||
// Verify the streams close
|
// Verify the streams close
|
||||||
await pWaitFor(() => connection.streams.length === 0)
|
await pWaitFor(() => connection.streams.length === 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should store host data and protocol version into metadataBook', () => {
|
||||||
|
const agentVersion = 'js-project/1.0.0'
|
||||||
|
|
||||||
|
libp2p = new Libp2p({
|
||||||
|
...baseOptions,
|
||||||
|
peerId,
|
||||||
|
host: {
|
||||||
|
agentVersion
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const storedAgentVersion = libp2p.peerStore.metadataBook.getValue(localPeer, 'AgentVersion')
|
||||||
|
const storedProtocolVersion = libp2p.peerStore.metadataBook.getValue(localPeer, 'ProtocolVersion')
|
||||||
|
|
||||||
|
expect(agentVersion).to.eql(unit8ArrayToString(storedAgentVersion))
|
||||||
|
expect(storedProtocolVersion).to.exist()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@@ -10,6 +10,7 @@ const TransportManager = require('../../src/transport-manager')
|
|||||||
const Transport = require('libp2p-tcp')
|
const Transport = require('libp2p-tcp')
|
||||||
const multiaddr = require('multiaddr')
|
const multiaddr = require('multiaddr')
|
||||||
const mockUpgrader = require('../utils/mockUpgrader')
|
const mockUpgrader = require('../utils/mockUpgrader')
|
||||||
|
const sinon = require('sinon')
|
||||||
const addrs = [
|
const addrs = [
|
||||||
multiaddr('/ip4/127.0.0.1/tcp/0'),
|
multiaddr('/ip4/127.0.0.1/tcp/0'),
|
||||||
multiaddr('/ip4/127.0.0.1/tcp/0')
|
multiaddr('/ip4/127.0.0.1/tcp/0')
|
||||||
@@ -40,7 +41,9 @@ describe('Transport Manager (TCP)', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should be able to listen', async () => {
|
it('should be able to listen', async () => {
|
||||||
tm.add(Transport.prototype[Symbol.toStringTag], Transport)
|
tm.add(Transport.prototype[Symbol.toStringTag], Transport, { listenerOptions: { listen: 'carefully' } })
|
||||||
|
const transport = tm._transports.get(Transport.prototype[Symbol.toStringTag])
|
||||||
|
const spyListener = sinon.spy(transport, 'createListener')
|
||||||
await tm.listen()
|
await tm.listen()
|
||||||
expect(tm._listeners).to.have.key(Transport.prototype[Symbol.toStringTag])
|
expect(tm._listeners).to.have.key(Transport.prototype[Symbol.toStringTag])
|
||||||
expect(tm._listeners.get(Transport.prototype[Symbol.toStringTag])).to.have.length(addrs.length)
|
expect(tm._listeners.get(Transport.prototype[Symbol.toStringTag])).to.have.length(addrs.length)
|
||||||
@@ -48,6 +51,7 @@ describe('Transport Manager (TCP)', () => {
|
|||||||
expect(tm.getAddrs().length).to.equal(addrs.length)
|
expect(tm.getAddrs().length).to.equal(addrs.length)
|
||||||
await tm.close()
|
await tm.close()
|
||||||
expect(tm._listeners.get(Transport.prototype[Symbol.toStringTag])).to.have.length(0)
|
expect(tm._listeners.get(Transport.prototype[Symbol.toStringTag])).to.have.length(0)
|
||||||
|
expect(spyListener.firstCall.firstArg).to.deep.equal({ listen: 'carefully' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should be able to dial', async () => {
|
it('should be able to dial', async () => {
|
||||||
|
@@ -125,7 +125,10 @@ describe('libp2p.transportManager', () => {
|
|||||||
const spy = sinon.spy()
|
const spy = sinon.spy()
|
||||||
const key = spy.prototype[Symbol.toStringTag] = 'TransportSpy'
|
const key = spy.prototype[Symbol.toStringTag] = 'TransportSpy'
|
||||||
const customOptions = {
|
const customOptions = {
|
||||||
another: 'value'
|
another: 'value',
|
||||||
|
listenerOptions: {
|
||||||
|
listen: 'carefully'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
libp2p = new Libp2p({
|
libp2p = new Libp2p({
|
||||||
peerId,
|
peerId,
|
||||||
@@ -143,6 +146,7 @@ describe('libp2p.transportManager', () => {
|
|||||||
expect(libp2p.transportManager).to.exist()
|
expect(libp2p.transportManager).to.exist()
|
||||||
// Our transport and circuit relay
|
// Our transport and circuit relay
|
||||||
expect(libp2p.transportManager._transports.size).to.equal(2)
|
expect(libp2p.transportManager._transports.size).to.equal(2)
|
||||||
|
expect(libp2p.transportManager._listenerOptions.size).to.equal(2)
|
||||||
expect(spy).to.have.property('callCount', 1)
|
expect(spy).to.have.property('callCount', 1)
|
||||||
expect(spy.getCall(0)).to.have.deep.property('args', [{
|
expect(spy.getCall(0)).to.have.deep.property('args', [{
|
||||||
...customOptions,
|
...customOptions,
|
||||||
|
Reference in New Issue
Block a user