Compare commits

..

59 Commits

Author SHA1 Message Date
db3f6dbb06 chore: release version v0.20.0 2018-04-06 17:03:47 +01:00
3808c365b1 chore: update contributors 2018-04-06 17:03:47 +01:00
19528ef15e chore: update deps 2018-04-06 17:02:51 +01:00
bb0c9905ed feat: use class-is for type checks 2018-04-05 19:47:02 +01:00
141920cd14 chore: update deps 2018-04-05 19:47:02 +01:00
2dc94cd907 chore: release version v0.19.2 2018-03-28 15:34:00 -07:00
7fc1cd0f7c chore: update contributors 2018-03-28 15:33:59 -07:00
26f3f9a319 chore: release version v0.19.1 2018-03-28 15:32:20 -07:00
e9ce4ac795 chore: update deps 2018-03-28 15:32:20 -07:00
bca86873cc docs: enable missing syntax highlighting (#178)
Enable missing syntax highlighting for example code in `discovery-mechanisms/README.md`.
2018-03-20 21:43:56 -07:00
bcca813171 chore: release version v0.19.0 2018-03-15 08:16:12 -07:00
cfc5958a4b chore: update contributors 2018-03-15 08:16:12 -07:00
4527d5fff1 stats: tests: bind to localhost only 2018-03-15 08:09:56 -07:00
2c04a71007 stats: exposed and documented 2018-03-15 08:09:56 -07:00
642b8ad751 chore: update deps 2018-03-15 07:57:30 -07:00
ada73221b0 chore: update deps 2018-03-14 06:27:53 -07:00
2e40e9dda1 docs: update echo and chat examples to use libp2p-switch (#174) 2018-03-06 13:25:55 +01:00
e531b1bf3d docs: fix pubsub example, solves #167 2018-02-22 07:06:21 +00:00
fdfc237780 chore: release version v0.18.0 2018-02-19 09:59:47 +00:00
83a09dbc0e chore: update contributors 2018-02-19 09:59:47 +00:00
b28eba067e chore: update deps 2018-02-19 09:58:08 +00:00
b871bb0a1a docs: update examples to use libp2p-mplex module 2018-02-19 09:58:08 +00:00
14d3578eaf test: update tests to use libp2p-mplex module 2018-02-19 09:58:08 +00:00
10a8ec3f31 chore: release version v0.17.0 2018-02-16 18:26:06 +00:00
41d202c4ba chore: update contributors 2018-02-16 18:26:06 +00:00
a5fd05875c chore: make tests faster 2018-02-16 19:23:35 +01:00
379febb610 chore: fix linting and move linting to circle 2018-02-16 19:23:35 +01:00
99873e877b docs: update pubsub example 2018-02-16 19:23:35 +01:00
4e01c094bc test: test pubsub on and off 2018-02-16 19:23:35 +01:00
8fcafe2d90 docs: update pubsub example 2018-02-16 19:23:35 +01:00
947eaf166b fix: use correct reference to floodSub 2018-02-16 19:23:35 +01:00
1ebf725ac4 docs: add docs 2018-02-16 19:23:35 +01:00
0c543b7180 feat: add pubsub to libp2p 2018-02-16 19:23:35 +01:00
beeb36c10c chore: release version v0.16.5 2018-02-14 10:55:16 +01:00
0acc7e5d72 chore: update contributors 2018-02-14 10:55:16 +01:00
9fd94b98a1 chore: update deps 2018-02-14 10:48:21 +01:00
5c3037037a chore: release version v0.16.4 2018-02-09 12:45:17 +00:00
362217c8da chore: update contributors 2018-02-09 12:45:17 +00:00
7733ba5cd7 chore: release version v0.16.3 2018-02-08 08:11:24 +00:00
52bf826ec6 chore: update contributors 2018-02-08 08:11:24 +00:00
10619afbe6 chore: release version v0.16.2 2018-02-07 09:50:30 +00:00
3debabdd26 chore: update contributors 2018-02-07 09:50:30 +00:00
56e095983a chore: update npm ignore 2018-02-07 09:50:01 +00:00
ebdb696742 chore: release version v0.16.1 2018-02-07 09:45:01 +00:00
721e6ee9ce chore: update contributors 2018-02-07 09:45:01 +00:00
98f2903088 chore: release version v0.16.0 2018-02-07 08:39:08 +00:00
3dda282dfd chore: update contributors 2018-02-07 08:39:08 +00:00
03faf69212 test: fix linting 2018-02-07 08:37:03 +00:00
0062a4b5eb docs: update examples 2018-02-07 08:37:03 +00:00
f7f85dce0a test: update tests to new API 2018-02-07 08:37:03 +00:00
59df82a675 docs: dialProtocol 2018-02-07 08:37:03 +00:00
6651401f0b feat: dialProtocol and small refactor 2018-02-07 08:37:03 +00:00
cd43863db6 chore: use pre-push 2018-02-07 07:31:10 +00:00
23e8293b75 feat: use libp2p-switch 2018-02-07 07:31:10 +00:00
68c170a40d docs: Add ws-star and ws-star-rendezvous (#158) 2018-02-07 07:07:53 +00:00
bd8a35aaf9 feat: add explicit error for case peer id not included in multiaddr (#155) 2018-02-05 12:36:20 +01:00
248d86d050 fix typo (#152) 2018-01-27 23:26:57 -08:00
8225b11082 fix typo (#153) 2018-01-27 23:26:52 -08:00
1355af2b51 docs: fix typos (#154) 2018-01-27 23:26:46 -08:00
48 changed files with 862 additions and 458 deletions

View File

@ -1,6 +1,9 @@
**/node_modules/ **/node_modules/
**/*.log **/*.log
test/repo-tests* test/repo-tests*
img
docs
examples
# Logs # Logs
logs logs

View File

@ -4,25 +4,16 @@ language: node_js
matrix: matrix:
include: include:
- node_js: 6 - node_js: 'stable'
env: CXX=g++-4.8 env: CXX=g++-4.8
- node_js: 8
env: CXX=g++-4.8
# - node_js: stable
# env: CXX=g++-4.8
script: script:
- npm run lint
- npm run test - npm run test
- npm run coverage
before_script: before_script:
- export DISPLAY=:99.0 - export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start - sh -e /etc/init.d/xvfb start
after_success:
- npm run coverage-publish
addons: addons:
firefox: 'latest' firefox: 'latest'
apt: apt:

View File

@ -1,3 +1,85 @@
<a name="0.20.0"></a>
# [0.20.0](https://github.com/libp2p/js-libp2p/compare/v0.19.2...v0.20.0) (2018-04-06)
### Features
* use class-is for type checks ([bb0c990](https://github.com/libp2p/js-libp2p/commit/bb0c990))
<a name="0.19.2"></a>
## [0.19.2](https://github.com/libp2p/js-libp2p/compare/v0.19.0...v0.19.2) (2018-03-28)
<a name="0.19.1"></a>
## [0.19.1](https://github.com/libp2p/js-libp2p/compare/v0.19.0...v0.19.1) (2018-03-28)
<a name="0.19.0"></a>
# [0.19.0](https://github.com/libp2p/js-libp2p/compare/v0.18.0...v0.19.0) (2018-03-15)
<a name="0.18.0"></a>
# [0.18.0](https://github.com/libp2p/js-libp2p/compare/v0.17.0...v0.18.0) (2018-02-19)
<a name="0.17.0"></a>
# [0.17.0](https://github.com/libp2p/js-libp2p/compare/v0.16.5...v0.17.0) (2018-02-16)
### Bug Fixes
* use correct reference to floodSub ([947eaf1](https://github.com/libp2p/js-libp2p/commit/947eaf1))
### Features
* add pubsub to libp2p ([0c543b7](https://github.com/libp2p/js-libp2p/commit/0c543b7))
<a name="0.16.5"></a>
## [0.16.5](https://github.com/libp2p/js-libp2p/compare/v0.16.4...v0.16.5) (2018-02-14)
<a name="0.16.4"></a>
## [0.16.4](https://github.com/libp2p/js-libp2p/compare/v0.16.3...v0.16.4) (2018-02-09)
<a name="0.16.3"></a>
## [0.16.3](https://github.com/libp2p/js-libp2p/compare/v0.16.2...v0.16.3) (2018-02-08)
<a name="0.16.2"></a>
## [0.16.2](https://github.com/libp2p/js-libp2p/compare/v0.16.1...v0.16.2) (2018-02-07)
<a name="0.16.1"></a>
## [0.16.1](https://github.com/libp2p/js-libp2p/compare/v0.16.0...v0.16.1) (2018-02-07)
<a name="0.16.0"></a>
# [0.16.0](https://github.com/libp2p/js-libp2p/compare/v0.15.2...v0.16.0) (2018-02-07)
### Features
* add explicit error for case peer id not included in multiaddr ([#155](https://github.com/libp2p/js-libp2p/issues/155)) ([bd8a35a](https://github.com/libp2p/js-libp2p/commit/bd8a35a))
* dialProtocol and small refactor ([6651401](https://github.com/libp2p/js-libp2p/commit/6651401))
* use libp2p-switch ([23e8293](https://github.com/libp2p/js-libp2p/commit/23e8293))
<a name="0.15.2"></a> <a name="0.15.2"></a>
## [0.15.2](https://github.com/libp2p/js-libp2p/compare/v0.15.1...v0.15.2) (2018-01-28) ## [0.15.2](https://github.com/libp2p/js-libp2p/compare/v0.15.1...v0.15.2) (2018-01-28)

130
README.md
View File

@ -158,11 +158,20 @@ class Node extends libp2p {
`callback` is a function with the following `function (err) {}` signature, where `err` is an Error in case stopping the node fails. `callback` is a function with the following `function (err) {}` signature, where `err` is an Error in case stopping the node fails.
#### `libp2p.dial(peer [, protocol, callback])` #### `libp2p.dial(peer, callback)`
> Dials to another peer in the network. > Dials to another peer in the network, establishes the connection.
- `peer`: can be an instance of [PeerInfo][], [PeerId][] or [multiaddr][] - `peer`: can be an instance of [PeerInfo][], [PeerId][], [multiaddr][], or a multiaddr string
- `callback`: Function with signature `function (err, conn) {}` where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object
`callback` is a function with the following `function (err, conn) {}` signature, where `err` is an Error in of failure to dial the connection and `conn` is a [Connection][] instance in case of a protocol selected, if not it is undefined.
#### `libp2p.dialProtocol(peer, protocol, callback)`
> Dials to another peer in the network and selects a protocol to talk with that peer.
- `peer`: can be an instance of [PeerInfo][], [PeerId][], [multiaddr][], or a multiaddr string
- `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0') - `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
- `callback`: Function with signature `function (err, conn) {}` where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object - `callback`: Function with signature `function (err, conn) {}` where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object
@ -240,9 +249,13 @@ class Node extends libp2p {
> PeerInfo instance of the node > PeerInfo instance of the node
#### `libp2p.pubsub`
> Same API as IPFS PubSub, defined in the [CORE API Spec](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md). Just replace `ipfs` by `libp2p` and you are golden.
--------------------- ---------------------
`DHT methods exposed` `DHT methods also exposed for the time being`
#### `libp2p.dht.put(key, value, callback)` #### `libp2p.dht.put(key, value, callback)`
@ -264,6 +277,113 @@ class Node extends libp2p {
[multiaddr]: https://github.com/multiformats/js-multiaddr [multiaddr]: https://github.com/multiformats/js-multiaddr
[Connection]: https://github.com/libp2p/interface-connection [Connection]: https://github.com/libp2p/interface-connection
-------
### Switch Stats API
##### `libp2p.stats.emit('update')`
Every time any stat value changes, this object emits an `update` event.
#### Global stats
##### `libp2p.stats.global.snapshot`
Should return a stats snapshot, which is an object containing the following keys and respective values:
- dataSent: amount of bytes sent, [Big](https://github.com/MikeMcl/big.js#readme) number
- dataReceived: amount of bytes received, [Big](https://github.com/MikeMcl/big.js#readme) number
##### `libp2p.stats.global.movingAverages`
Returns an object containing the following keys:
- dataSent
- dataReceived
Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` miliseconds).
Each one of these values is [an exponential moving-average instance](https://github.com/pgte/moving-average#readme).
#### Per-transport stats
##### `libp2p.stats.transports()`
Returns an array containing the tags (string) for each observed transport.
##### `libp2p.stats.forTransport(transportTag).snapshot`
Should return a stats snapshot, which is an object containing the following keys and respective values:
- dataSent: amount of bytes sent, [Big](https://github.com/MikeMcl/big.js#readme) number
- dataReceived: amount of bytes received, [Big](https://github.com/MikeMcl/big.js#readme) number
##### `libp2p.stats.forTransport(transportTag).movingAverages`
Returns an object containing the following keys:
dataSent
dataReceived
Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` miliseconds).
Each one of these values is [an exponential moving-average instance](https://github.com/pgte/moving-average#readme).
#### Per-protocol stats
##### `libp2p.stats.protocols()`
Returns an array containing the tags (string) for each observed protocol.
##### `libp2p.stats.forProtocol(protocolTag).snapshot`
Should return a stats snapshot, which is an object containing the following keys and respective values:
- dataSent: amount of bytes sent, [Big](https://github.com/MikeMcl/big.js#readme) number
- dataReceived: amount of bytes received, [Big](https://github.com/MikeMcl/big.js#readme) number
##### `libp2p.stats.forProtocol(protocolTag).movingAverages`
Returns an object containing the following keys:
- dataSent
- dataReceived
Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` miliseconds).
Each one of these values is [an exponential moving-average instance](https://github.com/pgte/moving-average#readme).
#### Per-peer stats
##### `libp2p.stats.peers()`
Returns an array containing the peerIDs (B58-encoded string) for each observed peer.
##### `libp2p.stats.forPeer(peerId:String).snapshot`
Should return a stats snapshot, which is an object containing the following keys and respective values:
- dataSent: amount of bytes sent, [Big](https://github.com/MikeMcl/big.js#readme) number
- dataReceived: amount of bytes received, [Big](https://github.com/MikeMcl/big.js#readme) number
##### `libp2p.stats.forPeer(peerId:String).movingAverages`
Returns an object containing the following keys:
- dataSent
- dataReceived
Each one of them contains an object that has a key for each interval (`60000`, `300000` and `900000` miliseconds).
Each one of these values is [an exponential moving-average instance](https://github.com/pgte/moving-average#readme).
#### Stats update interval
Stats are not updated in real-time. Instead, measurements are buffered and stats are updated at an interval. The maximum interval can be defined through the `Switch` constructor option `stats.computeThrottleTimeout`, defined in miliseconds.
## Development ## Development
**Clone and install dependencies:** **Clone and install dependencies:**
@ -311,6 +431,8 @@ List of packages currently in existence for libp2p
| [`libp2p-utp`](//github.com/libp2p/js-libp2p-utp) | [![npm](https://img.shields.io/npm/v/libp2p-utp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utp/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-utp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-utp/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp?type=dev) | | [`libp2p-utp`](//github.com/libp2p/js-libp2p-utp) | [![npm](https://img.shields.io/npm/v/libp2p-utp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utp/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-utp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-utp/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp?type=dev) |
| [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/libp2p-websockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-websockets/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets?type=dev) | | [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/libp2p-websockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-websockets/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets?type=dev) |
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-webrtc-star/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star?type=dev) | | [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-webrtc-star/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star?type=dev) |
| [`libp2p-websocket-star`](//github.com/libp2p/js-libp2p-websocket-star) | [![npm](https://img.shields.io/npm/v/libp2p-websocket-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websocket-star/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websocket-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-websocket-star/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star?type=dev) |
| [`libp2p-websocket-star-rendezvous`](//github.com/libp2p/js-libp2p-websocket-star-rendezvous) | [![npm](https://img.shields.io/npm/v/libp2p-websocket-star-rendezvous.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websocket-star-rendezvous/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websocket-star-rendezvous.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star-rendezvous) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-websocket-star-rendezvous/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star-rendezvous?type=dev) |
| **Connection Upgrades** | | **Connection Upgrades** |
| [`interface-connection`](//github.com/libp2p/interface-connection) | [![npm](https://img.shields.io/npm/v/interface-connection.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/interface-connection/releases) | [![Dependency Status](https://david-dm.org/libp2p/interface-connection.svg?style=flat-square)](https://david-dm.org/libp2p/interface-connection) | [![devDependency Status](https://david-dm.org/libp2p/interface-connection/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/interface-connection?type=dev) | | [`interface-connection`](//github.com/libp2p/interface-connection) | [![npm](https://img.shields.io/npm/v/interface-connection.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/interface-connection/releases) | [![Dependency Status](https://david-dm.org/libp2p/interface-connection.svg?style=flat-square)](https://david-dm.org/libp2p/interface-connection) | [![devDependency Status](https://david-dm.org/libp2p/interface-connection/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/interface-connection?type=dev) |
| **Stream Muxers** | | **Stream Muxers** |

View File

@ -2,6 +2,12 @@ machine:
node: node:
version: stable version: stable
test:
pre:
- npm run lint
post:
- npm run coverage -- --upload --providers coveralls
dependencies: dependencies:
pre: pre:
- google-chrome --version - google-chrome --version

View File

@ -47,7 +47,7 @@ async.parallel([
console.log(ma.toString() + '/ipfs/' + idListener.toB58String()) console.log(ma.toString() + '/ipfs/' + idListener.toB58String())
}) })
nodeDialer.dial(peerListener, '/chat/1.0.0', (err, conn) => { nodeDialer.dialProtocol(peerListener, '/chat/1.0.0', (err, conn) => {
if (err) { if (err) {
throw err throw err
} }

View File

@ -6,7 +6,7 @@ const WS = require('libp2p-websockets')
const Railing = require('libp2p-railing') const Railing = require('libp2p-railing')
const spdy = require('libp2p-spdy') const spdy = require('libp2p-spdy')
const KadDHT = require('libp2p-kad-dht') const KadDHT = require('libp2p-kad-dht')
const multiplex = require('libp2p-multiplex') const mplex = require('libp2p-mplex')
const secio = require('libp2p-secio') const secio = require('libp2p-secio')
const libp2p = require('../../..') const libp2p = require('../../..')
@ -17,7 +17,7 @@ function mapMuxers (list) {
} }
switch (pref.trim().toLowerCase()) { switch (pref.trim().toLowerCase()) {
case 'spdy': return spdy case 'spdy': return spdy
case 'multiplex': return multiplex case 'mplex': return mplex
default: default:
throw new Error(pref + ' muxer not available') throw new Error(pref + ' muxer not available')
} }
@ -31,7 +31,7 @@ function getMuxers (muxers) {
} else if (muxers) { } else if (muxers) {
return mapMuxers(muxers) return mapMuxers(muxers)
} else { } else {
return [multiplex, spdy] return [mplex, spdy]
} }
} }

View File

@ -21,7 +21,7 @@ PeerId.createFromJSON(require('./peer-id-listener'), (err, idListener) => {
throw err throw err
} }
nodeListener.swarm.on('peer-mux-established', (peerInfo) => { nodeListener.switch.on('peer-mux-established', (peerInfo) => {
console.log(peerInfo.id.toB58String()) console.log(peerInfo.id.toB58String())
}) })

View File

@ -2,7 +2,7 @@
const libp2p = require('libp2p') const libp2p = require('libp2p')
const TCP = require('libp2p-tcp') const TCP = require('libp2p-tcp')
const Multiplex = require('libp2p-multiplex') const Mplex = require('libp2p-mplex')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info') const PeerInfo = require('peer-info')
const Railing = require('libp2p-railing') const Railing = require('libp2p-railing')
@ -26,7 +26,7 @@ class MyBundle extends libp2p {
const modules = { const modules = {
transport: [new TCP()], transport: [new TCP()],
connection: { connection: {
muxer: [Multiplex], muxer: [Mplex],
crypto: [SECIO] crypto: [SECIO]
}, },
discovery: [new Railing(bootstrapers)] discovery: [new Railing(bootstrapers)]

View File

@ -2,7 +2,7 @@
const libp2p = require('libp2p') const libp2p = require('libp2p')
const TCP = require('libp2p-tcp') const TCP = require('libp2p-tcp')
const Multiplex = require('libp2p-multiplex') const Mplex = require('libp2p-mplex')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info') const PeerInfo = require('peer-info')
const MulticastDNS = require('libp2p-mdns') const MulticastDNS = require('libp2p-mdns')
@ -14,7 +14,7 @@ class MyBundle extends libp2p {
const modules = { const modules = {
transport: [new TCP()], transport: [new TCP()],
connection: { connection: {
muxer: [Multiplex], muxer: [Mplex],
crypto: [SECIO] crypto: [SECIO]
}, },
discovery: [new MulticastDNS(peerInfo, { interval: 1000 })] discovery: [new MulticastDNS(peerInfo, { interval: 1000 })]

View File

@ -8,7 +8,7 @@ These mechanisms save configuration and enable a node to operate without any exp
## 1. Bootstrap list of Peers when booting a node ## 1. Bootstrap list of Peers when booting a node
For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, multiplex and SECIO. You can see the complete example at [1.js](./1.js). For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, mplex and SECIO. You can see the complete example at [1.js](./1.js).
First, we create our libp2p bundle. First, we create our libp2p bundle.
@ -18,7 +18,7 @@ class MyBundle extends libp2p {
const modules = { const modules = {
transport: [new TCP()], transport: [new TCP()],
connection: { connection: {
muxer: [Multiplex], muxer: [Mplex],
crypto: [SECIO] crypto: [SECIO]
}, },
discovery: [new Railing(bootstrapers)] discovery: [new Railing(bootstrapers)]
@ -46,7 +46,7 @@ const bootstrapers = [
Now, once we create and start the node, we can listen for events such as `peer:discovery` and `peer:connect`, these events tell us when we found a peer, independently of the discovery mechanism used and when we actually dialed to that peer. Now, once we create and start the node, we can listen for events such as `peer:discovery` and `peer:connect`, these events tell us when we found a peer, independently of the discovery mechanism used and when we actually dialed to that peer.
``` ```JavaScript
let node let node
waterfall([ waterfall([
@ -111,7 +111,7 @@ class MyBundle extends libp2p {
const modules = { const modules = {
transport: [new TCP()], transport: [new TCP()],
connection: { connection: {
muxer: [Multiplex], muxer: [Mplex],
crypto: [SECIO] crypto: [SECIO]
}, },
// We set the interval here to 1 second so that is faster to observe. The // We set the interval here to 1 second so that is faster to observe. The

View File

@ -38,7 +38,7 @@ async.parallel([
'/ipfs/' + dialerId.toB58String())) '/ipfs/' + dialerId.toB58String()))
console.log('Dialing to peer:', listenerMultiaddr.toString()) console.log('Dialing to peer:', listenerMultiaddr.toString())
dialerNode.dial(listenerPeerInfo, '/echo/1.0.0', (err, conn) => { dialerNode.dialProtocol(listenerPeerInfo, '/echo/1.0.0', (err, conn) => {
if (err) { throw err } if (err) { throw err }
console.log('nodeA dialed to nodeB on protocol: /echo/1.0.0') console.log('nodeA dialed to nodeB on protocol: /echo/1.0.0')

View File

@ -6,7 +6,7 @@ const WS = require('libp2p-websockets')
const Railing = require('libp2p-railing') const Railing = require('libp2p-railing')
const spdy = require('libp2p-spdy') const spdy = require('libp2p-spdy')
const KadDHT = require('libp2p-kad-dht') const KadDHT = require('libp2p-kad-dht')
const multiplex = require('libp2p-multiplex') const mplex = require('libp2p-mplex')
const secio = require('libp2p-secio') const secio = require('libp2p-secio')
const libp2p = require('../../..') const libp2p = require('../../..')
@ -17,7 +17,7 @@ function mapMuxers (list) {
} }
switch (pref.trim().toLowerCase()) { switch (pref.trim().toLowerCase()) {
case 'spdy': return spdy case 'spdy': return spdy
case 'multiplex': return multiplex case 'mplex': return mplex
default: default:
throw new Error(pref + ' muxer not available') throw new Error(pref + ' muxer not available')
} }
@ -31,7 +31,7 @@ function getMuxers (muxers) {
} else if (muxers) { } else if (muxers) {
return mapMuxers(muxers) return mapMuxers(muxers)
} else { } else {
return [multiplex, spdy] return [mplex, spdy]
} }
} }

View File

@ -27,7 +27,7 @@ series([
listenerPeerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/10333') listenerPeerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/10333')
listenerNode = new Node(listenerPeerInfo) listenerNode = new Node(listenerPeerInfo)
listenerNode.swarm.on('peer-mux-established', (peerInfo) => { listenerNode.switch.on('peer-mux-established', (peerInfo) => {
console.log('received dial to me from:', peerInfo.id.toB58String()) console.log('received dial to me from:', peerInfo.id.toB58String())
}) })

View File

@ -52,7 +52,7 @@ parallel([
) )
}) })
node1.dial(node2.peerInfo, '/a-protocol', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/a-protocol', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['This information is sent out encrypted to the other peer']), conn) pull(pull.values(['This information is sent out encrypted to the other peer']), conn)
}) })

View File

@ -18,7 +18,7 @@
"dependencies": { "dependencies": {
"detect-dom-ready": "^1.0.2", "detect-dom-ready": "^1.0.2",
"libp2p": "^0.13.0", "libp2p": "^0.13.0",
"libp2p-multiplex": "^0.5.0", "libp2p-mplex": "^0.6.0",
"libp2p-railing": "^0.7.1", "libp2p-railing": "^0.7.1",
"libp2p-secio": "^0.8.1", "libp2p-secio": "^0.8.1",
"libp2p-spdy": "^0.11.0", "libp2p-spdy": "^0.11.0",

View File

@ -3,7 +3,7 @@
const WebRTCStar = require('libp2p-webrtc-star') const WebRTCStar = require('libp2p-webrtc-star')
const WebSockets = require('libp2p-websockets') const WebSockets = require('libp2p-websockets')
const Multiplex = require('libp2p-multiplex') const Mplex = require('libp2p-mplex')
const SPDY = require('libp2p-spdy') const SPDY = require('libp2p-spdy')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
@ -37,7 +37,7 @@ class Node extends libp2p {
], ],
connection: { connection: {
muxer: [ muxer: [
Multiplex, Mplex,
SPDY SPDY
], ],
crypto: [SECIO] crypto: [SECIO]

View File

@ -2,7 +2,7 @@
const libp2p = require('libp2p') const libp2p = require('libp2p')
const TCP = require('libp2p-tcp') const TCP = require('libp2p-tcp')
const Multiplex = require('libp2p-multiplex') const Mplex = require('libp2p-mplex')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info') const PeerInfo = require('peer-info')
const KadDHT = require('libp2p-kad-dht') const KadDHT = require('libp2p-kad-dht')
@ -15,7 +15,7 @@ class MyBundle extends libp2p {
const modules = { const modules = {
transport: [new TCP()], transport: [new TCP()],
connection: { connection: {
muxer: [Multiplex], muxer: [Mplex],
crypto: [SECIO] crypto: [SECIO]
}, },
// we add the DHT module that will enable Peer and Content Routing // we add the DHT module that will enable Peer and Content Routing

View File

@ -2,7 +2,7 @@
const libp2p = require('libp2p') const libp2p = require('libp2p')
const TCP = require('libp2p-tcp') const TCP = require('libp2p-tcp')
const Multiplex = require('libp2p-multiplex') const Mplex = require('libp2p-mplex')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info') const PeerInfo = require('peer-info')
const CID = require('cids') const CID = require('cids')
@ -16,7 +16,7 @@ class MyBundle extends libp2p {
const modules = { const modules = {
transport: [new TCP()], transport: [new TCP()],
connection: { connection: {
muxer: [Multiplex], muxer: [Mplex],
crypto: [SECIO] crypto: [SECIO]
}, },
// we add the DHT module that will enable Peer and Content Routing // we add the DHT module that will enable Peer and Content Routing

View File

@ -18,7 +18,7 @@ class MyBundle extends libp2p {
const modules = { const modules = {
transport: [new TCP()], transport: [new TCP()],
connection: { connection: {
muxer: [Multiplex], muxer: [Mplex],
crypto: [SECIO] crypto: [SECIO]
}, },
// we add the DHT module that will enable Peer and Content Routing // we add the DHT module that will enable Peer and Content Routing

View File

@ -75,20 +75,20 @@ parallel([
}) })
*/ */
node1.dial(node2.peerInfo, '/your-protocol', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/your-protocol', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['my own protocol, wow!']), conn) pull(pull.values(['my own protocol, wow!']), conn)
}) })
/* /*
node1.dial(node2.peerInfo, '/another-protocol/1.0.0', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/another-protocol/1.0.0', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['semver me please']), conn) pull(pull.values(['semver me please']), conn)
}) })
*/ */
/* /*
node1.dial(node2.peerInfo, '/custom-match-func/some-query', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/custom-match-func/some-query', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['do I fall into your criteria?']), conn) pull(pull.values(['do I fall into your criteria?']), conn)
}) })

View File

@ -60,17 +60,17 @@ parallel([
}) })
series([ series([
(cb) => node1.dial(node2.peerInfo, '/a', (err, conn) => { (cb) => node1.dialProtocol(node2.peerInfo, '/a', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['protocol (a)']), conn) pull(pull.values(['protocol (a)']), conn)
cb() cb()
}), }),
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => { (cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['protocol (b)']), conn) pull(pull.values(['protocol (b)']), conn)
cb() cb()
}), }),
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => { (cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['another conn on protocol (b)']), conn) pull(pull.values(['another conn on protocol (b)']), conn)
cb() cb()

View File

@ -30,7 +30,7 @@ node2.handle('/your-protocol', (protocol, conn) => {
After the protocol is _handled_, now we can dial to it. After the protocol is _handled_, now we can dial to it.
```JavaScript ```JavaScript
node1.dial(node2.peerInfo, '/your-protocol', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/your-protocol', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['my own protocol, wow!']), conn) pull(pull.values(['my own protocol, wow!']), conn)
}) })
@ -47,7 +47,7 @@ node2.handle('/another-protocol/1.0.1', (protocol, conn) => {
) )
}) })
// ... // ...
node1.dial(node2.peerInfo, '/another-protocol/1.0.0', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/another-protocol/1.0.0', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['semver me please']), conn) pull(pull.values(['semver me please']), conn)
}) })
@ -74,7 +74,7 @@ node2.handle('/custom-match-func', (protocol, conn) => {
} }
}) })
// ... // ...
node1.dial(node2.peerInfo, '/custom-match-func/some-query', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/custom-match-func/some-query', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['do I fall into your criteria?']), conn) pull(pull.values(['do I fall into your criteria?']), conn)
}) })
@ -88,7 +88,7 @@ The example above would require a node to create a whole new connection for ever
Stream multiplexing is a old concept, in fact it happens in many of the layers of the [OSI System](https://en.wikipedia.org/wiki/OSI_model), in libp2p we make this feature to our avail by letting the user pick which module for stream multiplexing to use. Stream multiplexing is a old concept, in fact it happens in many of the layers of the [OSI System](https://en.wikipedia.org/wiki/OSI_model), in libp2p we make this feature to our avail by letting the user pick which module for stream multiplexing to use.
Currently, we have two available [libp2p-spdy](https://github.com/libp2p/js-libp2p-spdy) and [libp2p-multiplex](https://github.com/libp2p/js-libp2p-multiplex) and pluging them in is as easy as adding another transport. Let's revisit our libp2p bundle. Currently, we have two available [libp2p-spdy](https://github.com/libp2p/js-libp2p-spdy) and [libp2p-mplex](https://github.com/libp2p/js-libp2p-mplex) and pluging them in is as easy as adding another transport. Let's revisit our libp2p bundle.
```JavaScript ```JavaScript
const SPDY = require('libp2p-spdy') const SPDY = require('libp2p-spdy')
@ -129,17 +129,17 @@ node2.handle('/b', (protocol, conn) => {
}) })
series([ series([
(cb) => node1.dial(node2.peerInfo, '/a', (err, conn) => { (cb) => node1.dialProtocol(node2.peerInfo, '/a', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['protocol (a)']), conn) pull(pull.values(['protocol (a)']), conn)
cb() cb()
}), }),
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => { (cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['protocol (b)']), conn) pull(pull.values(['protocol (b)']), conn)
cb() cb()
}), }),
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => { (cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['another conn on protocol (b)']), conn) pull(pull.values(['another conn on protocol (b)']), conn)
cb() cb()
@ -158,9 +158,9 @@ another protocol (b)
# 3. Bidirectional connections # 3. Bidirectional connections
There is one last trick on _protocol and stream multiplexing_ that libp2p uses to make everyone's life easier and that is _biderectional connection_. There is one last trick on _protocol and stream multiplexing_ that libp2p uses to make everyone's life easier and that is _bidirectional connection_.
With the aid of both mechanisms, we can reuse an incomming connection to dial streams out too, this is specially useful when you are behind tricky NAT, firewalls or if you are running in a browser, where you can have listening addrs, but you can dial out. By dialing out, you enable other peers to talk with you in Protocols that they want, simply by opening a new multiplexed stream. With the aid of both mechanisms, we can reuse an incomming connection to dial streams out too, this is specially useful when you are behind tricky NAT, firewalls or if you are running in a browser, where you can't have listening addrs, but you can dial out. By dialing out, you enable other peers to talk with you in Protocols that they want, simply by opening a new multiplexed stream.
You can see this working on example [3.js](./3.js). The result should look like the following: You can see this working on example [3.js](./3.js). The result should look like the following:

View File

@ -2,11 +2,10 @@
const libp2p = require('libp2p') const libp2p = require('libp2p')
const TCP = require('libp2p-tcp') const TCP = require('libp2p-tcp')
const Multiplex = require('libp2p-multiplex') const Mplex = require('libp2p-mplex')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info') const PeerInfo = require('peer-info')
const MulticastDNS = require('libp2p-mdns') const MulticastDNS = require('libp2p-mdns')
const FloodSub = require('libp2p-floodsub')
const waterfall = require('async/waterfall') const waterfall = require('async/waterfall')
const parallel = require('async/parallel') const parallel = require('async/parallel')
const series = require('async/series') const series = require('async/series')
@ -16,10 +15,12 @@ class MyBundle extends libp2p {
const modules = { const modules = {
transport: [new TCP()], transport: [new TCP()],
connection: { connection: {
muxer: [Multiplex], muxer: [Mplex],
crypto: [SECIO] crypto: [SECIO]
}, },
discovery: [new MulticastDNS(peerInfo, { interval: 2000 })] discovery: [
new MulticastDNS(peerInfo, { interval: 2000 })
]
} }
super(modules, peerInfo) super(modules, peerInfo)
} }
@ -47,22 +48,25 @@ parallel([
const node1 = nodes[0] const node1 = nodes[0]
const node2 = nodes[1] const node2 = nodes[1]
const fs1 = new FloodSub(node1)
const fs2 = new FloodSub(node2)
series([ series([
(cb) => fs1.start(cb),
(cb) => fs2.start(cb),
(cb) => node1.once('peer:discovery', (peer) => node1.dial(peer, cb)), (cb) => node1.once('peer:discovery', (peer) => node1.dial(peer, cb)),
(cb) => setTimeout(cb, 500) (cb) => setTimeout(cb, 500)
], (err) => { ], (err) => {
if (err) { throw err } if (err) { throw err }
fs2.on('news', (msg) => console.log(msg.from, msg.data.toString())) // Subscribe to the topic 'news'
fs2.subscribe('news') node1.pubsub.subscribe('news',
(msg) => console.log(msg.from, msg.data.toString()),
() => {
setInterval(() => { setInterval(() => {
fs1.publish('news', Buffer.from('Bird bird bird, bird is the word!')) // Publish the message on topic 'news'
node2.pubsub.publish(
'news',
Buffer.from('Bird bird bird, bird is the word!'),
() => {}
)
}, 1000) }, 1000)
}
)
}) })
}) })

View File

@ -1,8 +1,6 @@
# Publish Subscribe # Publish Subscribe
Publish Subscribe is something out of scope for the modular networking stack that is libp2p, however, it is something that is enabled through the primitives that libp2p offers and so it has become one of the most interesting use cases for libp2p. Publish Subscribe is also included on the stack. Currently, we have on PubSub implementation which we ship by default [libp2p-floodsub](https://github.com/libp2p/js-libp2p-floodsub), with many more being researched at [research-pubsub](https://github.com/libp2p/research-pubsub).
Currently, we have a PubSub implementation, [libp2p-floodsub](https://github.com/libp2p/js-libp2p-floodsub) and many more being researched at [research-pubsub](https://github.com/libp2p/research-pubsub).
We've seen many interesting use cases appear with this, here are some highlights: We've seen many interesting use cases appear with this, here are some highlights:
@ -12,30 +10,31 @@ We've seen many interesting use cases appear with this, here are some highlights
## 1. Setting up a simple PubSub network on top of libp2p ## 1. Setting up a simple PubSub network on top of libp2p
For this example, we will use MulticastDNS for automatic Peer Discovery and libp2p-floodsub to give us the PubSub primitives we are looking for. This example is based the previous examples found in [Discovery Mechanisms](../discovery-mechanisms). You can find the complete version at [1.js](./1.js). For this example, we will use MulticastDNS for automatic Peer Discovery. This example is based the previous examples found in [Discovery Mechanisms](../discovery-mechanisms). You can find the complete version at [1.js](./1.js).
Getting PubSub is super simple, all you have to do is require the FloodSub module and pass it in a libp2p node, once you have done that you can start subscribing and publishing in any topic. Using PubSub is super simple, all you have to do is start a libp2p node, PubSub will be enabled by default.
```JavaScript ```JavaScript
const FloodSub = require('libp2p-floodsub')
const fs1 = new FloodSub(node1)
const fs2 = new FloodSub(node2)
series([ series([
(cb) => fs1.start(cb),
(cb) => fs2.start(cb),
(cb) => node1.once('peer:discovery', (peer) => node1.dial(peer, cb)), (cb) => node1.once('peer:discovery', (peer) => node1.dial(peer, cb)),
(cb) => setTimeout(cb, 500) (cb) => setTimeout(cb, 500)
], (err) => { ], (err) => {
if (err) { throw err } if (err) { throw err }
fs2.on('news', (msg) => console.log(msg.from, msg.data.toString())) // Subscribe to the topic 'news'
fs2.subscribe('news') node1.pubsub.subscribe('news',
(msg) => console.log(msg.from, msg.data.toString()),
() => {
setInterval(() => { setInterval(() => {
fs1.publish('news', Buffer.from('Bird bird bird, bird is the word!')) // Publish the message on topic 'news'
node2.pubsub.publish(
'news',
Buffer.from('Bird bird bird, bird is the word!'),
() => {}
)
}, 1000) }, 1000)
}
)
}) })
``` ```

View File

@ -54,7 +54,7 @@ parallel([
) )
}) })
node1.dial(node2.peerInfo, '/print', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/print', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['Hello', ' ', 'p2p', ' ', 'world', '!']), conn) pull(pull.values(['Hello', ' ', 'p2p', ' ', 'world', '!']), conn)

View File

@ -66,19 +66,19 @@ parallel([
node2.handle('/print', print) node2.handle('/print', print)
node3.handle('/print', print) node3.handle('/print', print)
node1.dial(node2.peerInfo, '/print', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/print', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['node 1 dialed to node 2 successfully']), conn) pull(pull.values(['node 1 dialed to node 2 successfully']), conn)
}) })
node2.dial(node3.peerInfo, '/print', (err, conn) => { node2.dialProtocol(node3.peerInfo, '/print', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['node 2 dialed to node 3 successfully']), conn) pull(pull.values(['node 2 dialed to node 3 successfully']), conn)
}) })
node3.dial(node1.peerInfo, '/print', (err, conn) => { node3.dialProtocol(node1.peerInfo, '/print', (err, conn) => {
if (err) { if (err) {
console.log('node 3 failed to dial to node 1 with:', err.message) console.log('node 3 failed to dial to node 1 with:', err.message)
} }

View File

@ -143,7 +143,7 @@ parallel([
) )
}) })
node1.dial(node2.peerInfo, '/print', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/print', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['Hello', ' ', 'p2p', ' ', 'world', '!']), conn) pull(pull.values(['Hello', ' ', 'p2p', ' ', 'world', '!']), conn)
@ -240,21 +240,21 @@ parallel([
node3.handle('/print', print) node3.handle('/print', print)
// node 1 (TCP) dials to node 2 (TCP+WebSockets) // node 1 (TCP) dials to node 2 (TCP+WebSockets)
node1.dial(node2.peerInfo, '/print', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/print', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['node 1 dialed to node 2 successfully']), conn) pull(pull.values(['node 1 dialed to node 2 successfully']), conn)
}) })
// node 2 (TCP+WebSockets) dials to node 2 (WebSockets) // node 2 (TCP+WebSockets) dials to node 2 (WebSockets)
node2.dial(node3.peerInfo, '/print', (err, conn) => { node2.dialProtocol(node3.peerInfo, '/print', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['node 2 dialed to node 3 successfully']), conn) pull(pull.values(['node 2 dialed to node 3 successfully']), conn)
}) })
// node 3 (WebSockets) attempts to dial to node 1 (TCP) // node 3 (WebSockets) attempts to dial to node 1 (TCP)
node3.dial(node1.peerInfo, '/print', (err, conn) => { node3.dialProtocol(node1.peerInfo, '/print', (err, conn) => {
if (err) { if (err) {
console.log('node 3 failed to dial to node 1 with:', err.message) console.log('node 3 failed to dial to node 1 with:', err.message)
} }
@ -298,8 +298,8 @@ As expected, we created 3 nodes, node 1 with TCP, node 2 with TCP+WebSockets and
Today there are already 3 transports available, one in the works and plenty to come, you can find these at [interface-transport implementations](https://github.com/libp2p/interface-transport#modules-that-implement-the-interface) list. Today there are already 3 transports available, one in the works and plenty to come, you can find these at [interface-transport implementations](https://github.com/libp2p/interface-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 for what is libp2p concern, as long as it follows the interface defined at the [spec](https://github.com/libp2p/interface-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 at the [spec](https://github.com/libp2p/interface-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.
Hope this tutorial was useful. We are always looking to improve it, contributions are welcome! Hope this tutorial was useful. We are always looking to improve it, so contributions are welcome!

View File

@ -1,6 +1,6 @@
{ {
"name": "libp2p", "name": "libp2p",
"version": "0.15.2", "version": "0.20.0",
"description": "JavaScript base class for libp2p bundles", "description": "JavaScript base class for libp2p bundles",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
@ -26,7 +26,7 @@
"node": ">=6.0.0", "node": ">=6.0.0",
"npm": ">=3.0.0" "npm": ">=3.0.0"
}, },
"pre-commit": [ "pre-push": [
"lint", "lint",
"test" "test"
], ],
@ -38,45 +38,48 @@
"homepage": "https://github.com/libp2p/js-libp2p", "homepage": "https://github.com/libp2p/js-libp2p",
"dependencies": { "dependencies": {
"async": "^2.6.0", "async": "^2.6.0",
"libp2p-ping": "~0.6.0", "libp2p-floodsub": "^0.15.0",
"libp2p-swarm": "~0.35.1", "libp2p-ping": "~0.7.0",
"mafmt": "^3.0.2", "libp2p-switch": "~0.39.0",
"multiaddr": "^3.0.2", "mafmt": "^6.0.0",
"peer-book": "~0.5.4", "multiaddr": "^4.0.0",
"peer-id": "~0.10.5", "peer-book": "~0.7.0",
"peer-info": "~0.11.6" "peer-id": "~0.10.7",
"peer-info": "~0.14.0"
}, },
"devDependencies": { "devDependencies": {
"aegir": "^12.4.0", "aegir": "^13.0.6",
"chai": "^4.1.2", "chai": "^4.1.2",
"cids": "~0.5.2", "cids": "~0.5.3",
"dirty-chai": "^2.0.1", "dirty-chai": "^2.0.1",
"electron-webrtc": "~0.3.0", "electron-webrtc": "~0.3.0",
"libp2p-circuit": "~0.1.4", "libp2p-circuit": "~0.2.0",
"libp2p-kad-dht": "~0.6.0", "libp2p-kad-dht": "~0.10.0",
"libp2p-mdns": "~0.9.1", "libp2p-mdns": "~0.11.0",
"libp2p-multiplex": "~0.5.1", "libp2p-mplex": "~0.7.0",
"libp2p-railing": "~0.7.1", "libp2p-railing": "~0.8.0",
"libp2p-secio": "~0.9.1", "libp2p-secio": "~0.10.0",
"libp2p-spdy": "~0.11.0", "libp2p-spdy": "~0.12.1",
"libp2p-tcp": "~0.11.2", "libp2p-tcp": "~0.12.0",
"libp2p-webrtc-star": "~0.13.3", "libp2p-webrtc-star": "~0.14.0",
"libp2p-websockets": "~0.10.4", "libp2p-websockets": "~0.11.0",
"libp2p-websocket-star": "~0.7.2", "libp2p-websocket-star": "~0.8.0",
"libp2p-websocket-star-rendezvous": "~0.2.2", "libp2p-websocket-star-rendezvous": "~0.2.3",
"lodash.times": "^4.3.2", "lodash.times": "^4.3.2",
"pre-commit": "^1.2.2", "pre-commit": "^1.2.2",
"pull-goodbye": "0.0.2", "pull-goodbye": "0.0.2",
"pull-serializer": "~0.3.2", "pull-serializer": "~0.3.2",
"pull-stream": "^3.6.1", "pull-stream": "^3.6.7",
"safe-buffer": "^5.1.1", "safe-buffer": "^5.1.1",
"sinon": "^4.2.2", "sinon": "^4.5.0",
"wrtc": "0.0.65" "wrtc": "0.1.1"
}, },
"contributors": [ "contributors": [
"Chris Bratlien <chrisbratlien@gmail.com>", "Chris Bratlien <chrisbratlien@gmail.com>",
"Chris Dostert <chrisdostert@users.noreply.github.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>", "Daijiro Wachi <daijiro.wachi@gmail.com>",
"David Dias <daviddias.p@gmail.com>", "David Dias <daviddias.p@gmail.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>", "Dmitriy Ryajov <dryajov@gmail.com>",
"Elven <mon.samuel@qq.com>", "Elven <mon.samuel@qq.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>", "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
@ -92,7 +95,9 @@
"RasmusErik Voel Jensen <github@solsort.com>", "RasmusErik Voel Jensen <github@solsort.com>",
"Richard Littauer <richard.littauer@gmail.com>", "Richard Littauer <richard.littauer@gmail.com>",
"Ryan Bell <ryan@piing.net>", "Ryan Bell <ryan@piing.net>",
"Sönke Hahn <soenkehahn@gmail.com>",
"Tiago Alves <alvesjtiago@gmail.com>", "Tiago Alves <alvesjtiago@gmail.com>",
"Zane Starr <zcstarr@gmail.com>",
"greenkeeperio-bot <support@greenkeeper.io>", "greenkeeperio-bot <support@greenkeeper.io>",
"mayerwin <mayerwin@users.noreply.github.com>", "mayerwin <mayerwin@users.noreply.github.com>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>" "ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>"

20
src/content-routing.js Normal file
View File

@ -0,0 +1,20 @@
'use strict'
module.exports = (node) => {
return {
findProviders: (key, timeout, callback) => {
if (!node._dht) {
return callback(new Error('DHT is not available'))
}
node._dht.findProviders(key, timeout, callback)
},
provide: (key, callback) => {
if (!node._dht) {
return callback(new Error('DHT is not available'))
}
node._dht.provide(key, callback)
}
}
}

27
src/dht.js Normal file
View File

@ -0,0 +1,27 @@
'use strict'
module.exports = (node) => {
return {
put: (key, value, callback) => {
if (!node._dht) {
return callback(new Error('DHT is not available'))
}
node._dht.put(key, value, callback)
},
get: (key, callback) => {
if (!node._dht) {
return callback(new Error('DHT is not available'))
}
node._dht.get(key, callback)
},
getMany (key, nVals, callback) {
if (!node._dht) {
return callback(new Error('DHT is not available'))
}
node._dht.getMany(key, nVals, callback)
}
}
}

3
src/error-messages.js Normal file
View File

@ -0,0 +1,3 @@
'use strict'
exports.NOT_STARTED_YET = 'The libp2p node is not started yet'

48
src/get-peer-info.js Normal file
View File

@ -0,0 +1,48 @@
'use strict'
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const multiaddr = require('multiaddr')
module.exports = (node) => {
/*
* Helper method to check the data type of peer and convert it to PeerInfo
*/
return function (peer, callback) {
let p
// PeerInfo
if (PeerInfo.isPeerInfo(peer)) {
p = peer
// Multiaddr instance or Multiaddr String
} else if (multiaddr.isMultiaddr(peer) || typeof peer === 'string') {
if (typeof peer === 'string') {
peer = multiaddr(peer)
}
const peerIdB58Str = peer.getPeerId()
if (!peerIdB58Str) {
throw new Error(`peer multiaddr instance or string must include peerId`)
}
try {
p = node.peerBook.get(peerIdB58Str)
} catch (err) {
p = new PeerInfo(PeerId.createFromB58String(peerIdB58Str))
}
p.multiaddrs.add(peer)
// PeerId
} else if (PeerId.isPeerId(peer)) {
const peerIdB58Str = peer.toB58String()
try {
p = node.peerBook.get(peerIdB58Str)
} catch (err) {
return node.peerRouting.findPeer(peer, callback)
}
} else {
return setImmediate(() => callback(new Error('peer type not recognized')))
}
setImmediate(() => callback(null, p))
}
}

View File

@ -7,12 +7,16 @@ const setImmediate = require('async/setImmediate')
const each = require('async/each') const each = require('async/each')
const series = require('async/series') const series = require('async/series')
const Ping = require('libp2p-ping')
const Swarm = require('libp2p-swarm')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const PeerBook = require('peer-book') const PeerBook = require('peer-book')
const multiaddr = require('multiaddr') const Switch = require('libp2p-switch')
const Ping = require('libp2p-ping')
const WebSockets = require('libp2p-websockets')
const peerRouting = require('./peer-routing')
const contentRouting = require('./content-routing')
const dht = require('./dht')
const pubsub = require('./pubsub')
const getPeerInfo = require('./get-peer-info')
exports = module.exports exports = module.exports
@ -31,28 +35,29 @@ class Node extends EventEmitter {
this._isStarted = false this._isStarted = false
this.swarm = new Swarm(this.peerInfo, this.peerBook) this.switch = new Switch(this.peerInfo, this.peerBook, _options.switch)
this.stats = this.switch.stats
// Attach stream multiplexers // Attach stream multiplexers
if (this.modules.connection && this.modules.connection.muxer) { if (this.modules.connection && this.modules.connection.muxer) {
let muxers = this.modules.connection.muxer let muxers = this.modules.connection.muxer
muxers = Array.isArray(muxers) ? muxers : [muxers] muxers = Array.isArray(muxers) ? muxers : [muxers]
muxers.forEach((muxer) => this.swarm.connection.addStreamMuxer(muxer)) muxers.forEach((muxer) => this.switch.connection.addStreamMuxer(muxer))
// If muxer exists, we can use Identify // If muxer exists, we can use Identify
this.swarm.connection.reuse() this.switch.connection.reuse()
// If muxer exists, we can use Relay for listening/dialing // If muxer exists, we can use Relay for listening/dialing
this.swarm.connection.enableCircuitRelay(_options.relay) this.switch.connection.enableCircuitRelay(_options.relay)
// Received incommind dial and muxer upgrade happened, // Received incommind dial and muxer upgrade happened,
// reuse this muxed connection // reuse this muxed connection
this.swarm.on('peer-mux-established', (peerInfo) => { this.switch.on('peer-mux-established', (peerInfo) => {
this.emit('peer:connect', peerInfo) this.emit('peer:connect', peerInfo)
this.peerBook.put(peerInfo) this.peerBook.put(peerInfo)
}) })
this.swarm.on('peer-mux-closed', (peerInfo) => { this.switch.on('peer-mux-closed', (peerInfo) => {
this.emit('peer:disconnect', peerInfo) this.emit('peer:disconnect', peerInfo)
}) })
} }
@ -62,7 +67,7 @@ class Node extends EventEmitter {
let cryptos = this.modules.connection.crypto let cryptos = this.modules.connection.crypto
cryptos = Array.isArray(cryptos) ? cryptos : [cryptos] cryptos = Array.isArray(cryptos) ? cryptos : [cryptos]
cryptos.forEach((crypto) => { cryptos.forEach((crypto) => {
this.swarm.connection.crypto(crypto.tag, crypto.encrypt) this.switch.connection.crypto(crypto.tag, crypto.encrypt)
}) })
} }
@ -76,67 +81,23 @@ class Node extends EventEmitter {
}) })
} }
// Mount default protocols
Ping.mount(this.swarm)
// dht provided components (peerRouting, contentRouting, dht) // dht provided components (peerRouting, contentRouting, dht)
if (_modules.DHT) { if (_modules.DHT) {
this._dht = new this.modules.DHT(this.swarm, { this._dht = new this.modules.DHT(this.switch, {
kBucketSize: 20, kBucketSize: 20,
datastore: _options.DHT && _options.DHT.datastore datastore: _options.DHT && _options.DHT.datastore
}) })
} }
this.peerRouting = { this.peerRouting = peerRouting(this)
findPeer: (id, callback) => { this.contentRouting = contentRouting(this)
if (!this._dht) { this.dht = dht(this)
return callback(new Error('DHT is not available')) this.pubsub = pubsub(this)
}
this._dht.findPeer(id, callback) this._getPeerInfo = getPeerInfo(this)
}
}
this.contentRouting = { // Mount default protocols
findProviders: (key, timeout, callback) => { Ping.mount(this.switch)
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.findProviders(key, timeout, callback)
},
provide: (key, callback) => {
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.provide(key, callback)
}
}
this.dht = {
put: (key, value, callback) => {
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.put(key, value, callback)
},
get: (key, callback) => {
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.get(key, callback)
},
getMany (key, nVals, callback) {
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.getMany(key, nVals, callback)
}
}
} }
/* /*
@ -167,10 +128,9 @@ class Node extends EventEmitter {
const multiaddrs = this.peerInfo.multiaddrs.toArray() const multiaddrs = this.peerInfo.multiaddrs.toArray()
transports.forEach((transport) => { transports.forEach((transport) => {
if (transport.filter(multiaddrs).length > 0) { if (transport.filter(multiaddrs).length > 0) {
this.swarm.transport.add( this.switch.transport.add(
transport.tag || transport.constructor.name, transport) transport.tag || transport.constructor.name, transport)
} else if (transport.constructor && } else if (WebSockets.isWebSockets(transport)) {
transport.constructor.name === 'WebSockets') {
// TODO find a cleaner way to signal that a transport is always // TODO find a cleaner way to signal that a transport is always
// used for dialing, even if no listener // used for dialing, even if no listener
ws = transport ws = transport
@ -178,11 +138,11 @@ class Node extends EventEmitter {
}) })
series([ series([
(cb) => this.swarm.listen(cb), (cb) => this.switch.start(cb),
(cb) => { (cb) => {
if (ws) { if (ws) {
// always add dialing on websockets // always add dialing on websockets
this.swarm.transport.add(ws.tag || ws.constructor.name, ws) this.switch.transport.add(ws.tag || ws.constructor.name, ws)
} }
// all transports need to be setup before discover starts // all transports need to be setup before discover starts
@ -192,17 +152,29 @@ class Node extends EventEmitter {
cb() cb()
}, },
(cb) => { (cb) => {
// TODO: chicken-and-egg problem: // TODO: chicken-and-egg problem #1:
// have to set started here because DHT requires libp2p is already started // have to set started here because DHT requires libp2p is already started
this._isStarted = true this._isStarted = true
if (this._dht) { if (this._dht) {
return this._dht.start(cb) this._dht.start(cb)
} } else {
cb() cb()
}
}, },
(cb) => {
// TODO: chicken-and-egg problem #2:
// have to set started here because FloodSub requires libp2p is already started
if (this._options !== false) {
this._floodSub.start(cb)
} else {
cb()
}
},
(cb) => { (cb) => {
// detect which multiaddrs we don't have a transport for and remove them // detect which multiaddrs we don't have a transport for and remove them
const multiaddrs = this.peerInfo.multiaddrs.toArray() const multiaddrs = this.peerInfo.multiaddrs.toArray()
transports.forEach((transport) => { transports.forEach((transport) => {
multiaddrs.forEach((multiaddr) => { multiaddrs.forEach((multiaddr) => {
if (!multiaddr.toString().match(/\/p2p-circuit($|\/)/) && if (!multiaddr.toString().match(/\/p2p-circuit($|\/)/) &&
@ -231,13 +203,18 @@ class Node extends EventEmitter {
} }
series([ series([
(cb) => {
if (this._floodSub.started) {
this._floodSub.stop(cb)
}
},
(cb) => { (cb) => {
if (this._dht) { if (this._dht) {
return this._dht.stop(cb) return this._dht.stop(cb)
} }
cb() cb()
}, },
(cb) => this.swarm.close(cb), (cb) => this.switch.stop(cb),
(cb) => { (cb) => {
this.emit('stop') this.emit('stop')
cb() cb()
@ -252,18 +229,22 @@ class Node extends EventEmitter {
return this._isStarted return this._isStarted
} }
ping (peer, callback) { dial (peer, callback) {
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE) assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
this._getPeerInfo(peer, (err, peerInfo) => {
if (err) {
return callback(err)
}
callback(null, new Ping(this.swarm, peerInfo)) this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { return callback(err) }
this.switch.dial(peerInfo, (err) => {
if (err) { return callback(err) }
this.peerBook.put(peerInfo)
callback()
})
}) })
} }
dial (peer, protocol, callback) { dialProtocol (peer, protocol, callback) {
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE) assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
if (typeof protocol === 'function') { if (typeof protocol === 'function') {
@ -272,14 +253,10 @@ class Node extends EventEmitter {
} }
this._getPeerInfo(peer, (err, peerInfo) => { this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { if (err) { return callback(err) }
return callback(err)
}
this.swarm.dial(peerInfo, protocol, (err, conn) => { this.switch.dial(peerInfo, protocol, (err, conn) => {
if (err) { if (err) { return callback(err) }
return callback(err)
}
this.peerBook.put(peerInfo) this.peerBook.put(peerInfo)
callback(null, conn) callback(null, conn)
}) })
@ -290,56 +267,27 @@ class Node extends EventEmitter {
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE) assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
this._getPeerInfo(peer, (err, peerInfo) => { this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { if (err) { return callback(err) }
return callback(err)
this.switch.hangUp(peerInfo, callback)
})
} }
this.swarm.hangUp(peerInfo, callback) ping (peer, callback) {
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { return callback(err) }
callback(null, new Ping(this.switch, peerInfo))
}) })
} }
handle (protocol, handlerFunc, matchFunc) { handle (protocol, handlerFunc, matchFunc) {
this.swarm.handle(protocol, handlerFunc, matchFunc) this.switch.handle(protocol, handlerFunc, matchFunc)
} }
unhandle (protocol) { unhandle (protocol) {
this.swarm.unhandle(protocol) this.switch.unhandle(protocol)
}
/*
* Helper method to check the data type of peer and convert it to PeerInfo
*/
_getPeerInfo (peer, callback) {
let p
// PeerInfo
if (PeerInfo.isPeerInfo(peer)) {
p = peer
// Multiaddr instance or Multiaddr String
} else if (multiaddr.isMultiaddr(peer) || typeof peer === 'string') {
if (typeof peer === 'string') {
peer = multiaddr(peer)
}
const peerIdB58Str = peer.getPeerId()
try {
p = this.peerBook.get(peerIdB58Str)
} catch (err) {
p = new PeerInfo(PeerId.createFromB58String(peerIdB58Str))
}
p.multiaddrs.add(peer)
// PeerId
} else if (PeerId.isPeerId(peer)) {
const peerIdB58Str = peer.toB58String()
try {
p = this.peerBook.get(peerIdB58Str)
} catch (err) {
return this.peerRouting.findPeer(peer, callback)
}
} else {
return setImmediate(() => callback(new Error('peer type not recognized')))
}
setImmediate(() => callback(null, p))
} }
} }

13
src/peer-routing.js Normal file
View File

@ -0,0 +1,13 @@
'use strict'
module.exports = (node) => {
return {
findPeer: (id, callback) => {
if (!node._dht) {
return callback(new Error('DHT is not available'))
}
node._dht.findPeer(id, callback)
}
}
}

93
src/pubsub.js Normal file
View File

@ -0,0 +1,93 @@
'use strict'
const setImmediate = require('async/setImmediate')
const NOT_STARTED_YET = require('./error-messages').NOT_STARTED_YET
const FloodSub = require('libp2p-floodsub')
module.exports = (node) => {
const floodSub = new FloodSub(node)
node._floodSub = floodSub
return {
subscribe: (topic, options, handler, callback) => {
if (typeof options === 'function') {
callback = handler
handler = options
options = {}
}
if (!node.isStarted() && !floodSub.started) {
return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
}
function subscribe (cb) {
if (floodSub.listenerCount(topic) === 0) {
floodSub.subscribe(topic)
}
floodSub.on(topic, handler)
setImmediate(cb)
}
subscribe(callback)
},
unsubscribe: (topic, handler) => {
if (!node.isStarted() && !floodSub.started) {
throw new Error(NOT_STARTED_YET)
}
floodSub.removeListener(topic, handler)
if (floodSub.listenerCount(topic) === 0) {
floodSub.unsubscribe(topic)
}
},
publish: (topic, data, callback) => {
if (!node.isStarted() && !floodSub.started) {
return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
}
if (!Buffer.isBuffer(data)) {
return setImmediate(() => callback(new Error('data must be a Buffer')))
}
floodSub.publish(topic, data)
setImmediate(() => callback())
},
ls: (callback) => {
if (!node.isStarted() && !floodSub.started) {
return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
}
const subscriptions = Array.from(floodSub.subscriptions)
setImmediate(() => callback(null, subscriptions))
},
peers: (topic, callback) => {
if (!node.isStarted() && !floodSub.started) {
return setImmediate(() => callback(new Error(NOT_STARTED_YET)))
}
if (typeof topic === 'function') {
callback = topic
topic = null
}
const peers = Array.from(floodSub.peers.values())
.filter((peer) => topic ? peer.topics.has(topic) : true)
.map((peer) => peer.info.id.toB58String())
setImmediate(() => callback(null, peers))
},
setMaxListeners (n) {
return floodSub.setMaxListeners(n)
}
}
}

View File

@ -1,17 +1,16 @@
/* eslint-env mocha */ /* eslint-env mocha */
'use strict' 'use strict'
const pull = require('pull-stream')
const waterfall = require('async/waterfall') const waterfall = require('async/waterfall')
const series = require('async/series') const series = require('async/series')
const parallel = require('async/parallel') const parallel = require('async/parallel')
const utils = require('./utils/node') const utils = require('./utils/node')
const Circuit = require('libp2p-circuit') const Circuit = require('libp2p-circuit')
const multiaddr = require('multiaddr') const multiaddr = require('multiaddr')
const tryEcho = require('./utils/try-echo')
const chai = require('chai') const chai = require('chai')
chai.use(require('dirty-chai')) chai.use(require('dirty-chai'))
const expect = chai.expect const expect = chai.expect
const sinon = require('sinon') const sinon = require('sinon')
@ -39,7 +38,7 @@ describe('circuit relay', function () {
node.start((err) => { node.start((err) => {
expect(err).to.not.exist() expect(err).to.not.exist()
handlerSpies.push(sinon.spy(node.swarm.transports[Circuit.tag].listeners[0].hopHandler, 'handle')) handlerSpies.push(sinon.spy(node.switch.transports[Circuit.tag].listeners[0].hopHandler, 'handle'))
cb(node) cb(node)
}) })
}) })
@ -153,25 +152,16 @@ describe('circuit relay', function () {
describe('any relay', function () { describe('any relay', function () {
this.timeout(20 * 1000) this.timeout(20 * 1000)
it('should dial from WS1 to TCP1 over any R', (done) => { it('dial from WS1 to TCP1 over any R', (done) => {
nodeWS1.dial(nodeTCP1.peerInfo, '/echo/1.0.0', (err, conn) => { nodeWS1.dialProtocol(nodeTCP1.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
expect(conn).to.exist() expect(conn).to.exist()
tryEcho(conn, done)
pull(
pull.values(['hello']),
conn,
pull.collect((err, result) => {
expect(err).to.not.exist()
expect(result[0].toString()).to.equal('hello')
done()
})
)
}) })
}) })
it('should not dial - no R from WS2 to TCP1', (done) => { it('fail to dial - no R from WS2 to TCP1', (done) => {
nodeWS2.dial(nodeTCP2.peerInfo, '/echo/1.0.0', (err, conn) => { nodeWS2.dialProtocol(nodeTCP2.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.exist() expect(err).to.exist()
expect(conn).to.not.exist() expect(conn).to.not.exist()
done() done()
@ -182,43 +172,29 @@ describe('circuit relay', function () {
describe('explicit relay', function () { describe('explicit relay', function () {
this.timeout(20 * 1000) this.timeout(20 * 1000)
it('should dial from WS1 to TCP1 over R1', (done) => { it('dial from WS1 to TCP1 over R1', (done) => {
nodeWS1.dial(nodeTCP1.peerInfo, '/echo/1.0.0', (err, conn) => { nodeWS1.dialProtocol(nodeTCP1.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
expect(conn).to.exist() expect(conn).to.exist()
pull( tryEcho(conn, () => {
pull.values(['hello']),
conn,
pull.collect((err, result) => {
expect(err).to.not.exist()
expect(result[0].toString()).to.equal('hello')
const addr = multiaddr(handlerSpies[0].args[2][0].dstPeer.addrs[0]).toString() const addr = multiaddr(handlerSpies[0].args[2][0].dstPeer.addrs[0]).toString()
expect(addr).to.equal(`/ipfs/${nodeTCP1.peerInfo.id.toB58String()}`) expect(addr).to.equal(`/ipfs/${nodeTCP1.peerInfo.id.toB58String()}`)
done() done()
}) })
)
}) })
}) })
it('should dial from WS1 to TCP2 over R2', (done) => { it('dial from WS1 to TCP2 over R2', (done) => {
nodeWS1.dial(nodeTCP2.peerInfo, '/echo/1.0.0', (err, conn) => { nodeWS1.dialProtocol(nodeTCP2.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
expect(conn).to.exist() expect(conn).to.exist()
pull( tryEcho(conn, () => {
pull.values(['hello']),
conn,
pull.collect((err, result) => {
expect(err).to.not.exist()
expect(result[0].toString()).to.equal('hello')
const addr = multiaddr(handlerSpies[1].args[2][0].dstPeer.addrs[0]).toString() const addr = multiaddr(handlerSpies[1].args[2][0].dstPeer.addrs[0]).toString()
expect(addr).to.equal(`/ipfs/${nodeTCP2.peerInfo.id.toB58String()}`) expect(addr).to.equal(`/ipfs/${nodeTCP2.peerInfo.id.toB58String()}`)
done() done()
}) })
)
}) })
}) })
}) })

View File

@ -4,7 +4,9 @@ require('./base')
require('./transports.node') require('./transports.node')
require('./stream-muxing.node') require('./stream-muxing.node')
require('./peer-discovery.node') require('./peer-discovery.node')
require('./pubsub.node')
require('./peer-routing.node') require('./peer-routing.node')
require('./content-routing.node') require('./content-routing.node')
require('./circuit-relay.node') require('./circuit-relay.node')
require('./multiaddr-trim') require('./multiaddr-trim')
require('./stats')

87
test/pubsub.node.js Normal file
View File

@ -0,0 +1,87 @@
/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
const waterfall = require('async/waterfall')
const _times = require('lodash.times')
const utils = require('./utils/node')
const createNode = utils.createNode
function startTwo (callback) {
const tasks = _times(2, () => (cb) => {
createNode('/ip4/0.0.0.0/tcp/0', {
mdns: false
}, (err, node) => {
expect(err).to.not.exist()
node.start((err) => cb(err, node))
})
})
parallel(tasks, (err, nodes) => {
expect(err).to.not.exist()
nodes[0].dial(nodes[1].peerInfo, (err) => callback(err, nodes))
})
}
function stopTwo (nodes, callback) {
parallel([
(cb) => nodes[0].stop(cb),
(cb) => nodes[1].stop(cb)
], callback)
}
// There is a vast test suite on PubSub through js-ipfs
// https://github.com/ipfs/interface-ipfs-core/blob/master/js/src/pubsub.js
// and libp2p-floodsub itself
// https://github.com/libp2p/js-libp2p-floodsub/tree/master/test
// TODO: consider if all or some of those should come here
describe('.pubsub', () => {
describe('.pubsub on (default)', (done) => {
it('start two nodes and send one message', (done) => {
waterfall([
(cb) => startTwo(cb),
(nodes, cb) => {
const data = Buffer.from('test')
nodes[0].pubsub.subscribe('pubsub',
(msg) => {
expect(msg.data).to.eql(data)
cb(null, nodes)
},
(err) => {
expect(err).to.not.exist()
setTimeout(() => nodes[1].pubsub.publish('pubsub', data, (err) => {
expect(err).to.not.exist()
}), 500)
}
)
},
(nodes, cb) => stopTwo(nodes, cb)
], done)
})
})
describe('.pubsub off', () => {
it('fail to use pubsub if disabled', (done) => {
createNode('/ip4/0.0.0.0/tcp/0', {
mdns: false,
pubsub: false
}, (err, node) => {
expect(err).to.not.exist()
node.pubsub.subscribe('news',
(msg) => {},
(err) => {
expect(err).to.exist()
done()
}
)
})
})
})
})

24
test/stats.js Normal file
View File

@ -0,0 +1,24 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const createNode = require('./utils/node').createNode
describe('libp2p', (done) => {
it('has stats', () => {
createNode('/ip4/127.0.0.1/tcp/0', {
mdns: false,
dht: true
}, (err, node) => {
expect(err).to.not.exist()
node.start((err) => {
expect(err).to.not.exist()
expect(node.stats).to.exist()
node.stop(done)
})
})
})
})

View File

@ -6,24 +6,15 @@ chai.use(require('dirty-chai'))
const expect = chai.expect const expect = chai.expect
const parallel = require('async/parallel') const parallel = require('async/parallel')
const series = require('async/series') const series = require('async/series')
const pull = require('pull-stream')
const utils = require('./utils/node') const utils = require('./utils/node')
const tryEcho = require('./utils/try-echo')
const createNode = utils.createNode const createNode = utils.createNode
const echo = utils.echo const echo = utils.echo
function test (nodeA, nodeB, callback) { function test (nodeA, nodeB, callback) {
nodeA.dial(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => { nodeA.dialProtocol(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
tryEcho(conn, callback)
pull(
pull.values([Buffer.from('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.be.eql([Buffer.from('hey')])
callback()
})
)
}) })
} }
@ -69,14 +60,14 @@ describe('stream muxing', () => {
], done) ], done)
}) })
it('multiplex only', (done) => { it('mplex only', (done) => {
let nodeA let nodeA
let nodeB let nodeB
function setup (callback) { function setup (callback) {
parallel([ parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', { (cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['multiplex'] muxer: ['mplex']
}, (err, node) => { }, (err, node) => {
expect(err).to.not.exist() expect(err).to.not.exist()
nodeA = node nodeA = node
@ -84,7 +75,7 @@ describe('stream muxing', () => {
node.start(cb) node.start(cb)
}), }),
(cb) => createNode('/ip4/0.0.0.0/tcp/0', { (cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['multiplex'] muxer: ['mplex']
}, (err, node) => { }, (err, node) => {
expect(err).to.not.exist() expect(err).to.not.exist()
nodeB = node nodeB = node
@ -101,7 +92,7 @@ describe('stream muxing', () => {
], done) ], done)
}) })
it('spdy + multiplex', function (done) { it('spdy + mplex', function (done) {
this.timeout(5000) this.timeout(5000)
let nodeA let nodeA
@ -110,7 +101,7 @@ describe('stream muxing', () => {
function setup (callback) { function setup (callback) {
parallel([ parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', { (cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['spdy', 'multiplex'] muxer: ['spdy', 'mplex']
}, (err, node) => { }, (err, node) => {
expect(err).to.not.exist() expect(err).to.not.exist()
nodeA = node nodeA = node
@ -118,7 +109,7 @@ describe('stream muxing', () => {
node.start(cb) node.start(cb)
}), }),
(cb) => createNode('/ip4/0.0.0.0/tcp/0', { (cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['spdy', 'multiplex'] muxer: ['spdy', 'mplex']
}, (err, node) => { }, (err, node) => {
expect(err).to.not.exist() expect(err).to.not.exist()
nodeB = node nodeB = node
@ -135,8 +126,8 @@ describe('stream muxing', () => {
], done) ], done)
}) })
it('spdy + multiplex switched order', function (done) { it('spdy + mplex switched order', function (done) {
this.timeout(5000) this.timeout(5 * 1000)
let nodeA let nodeA
let nodeB let nodeB
@ -144,7 +135,7 @@ describe('stream muxing', () => {
function setup (callback) { function setup (callback) {
parallel([ parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', { (cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['spdy', 'multiplex'] muxer: ['spdy', 'mplex']
}, (err, node) => { }, (err, node) => {
expect(err).to.not.exist() expect(err).to.not.exist()
nodeA = node nodeA = node
@ -152,7 +143,7 @@ describe('stream muxing', () => {
node.start(cb) node.start(cb)
}), }),
(cb) => createNode('/ip4/0.0.0.0/tcp/0', { (cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['multiplex', 'spdy'] muxer: ['mplex', 'spdy']
}, (err, node) => { }, (err, node) => {
expect(err).to.not.exist() expect(err).to.not.exist()
nodeB = node nodeB = node
@ -170,7 +161,7 @@ describe('stream muxing', () => {
}) })
it('one without the other fails to establish a muxedConn', function (done) { it('one without the other fails to establish a muxedConn', function (done) {
this.timeout(5000) this.timeout(5 * 1000)
let nodeA let nodeA
let nodeB let nodeB
@ -186,7 +177,7 @@ describe('stream muxing', () => {
node.start(cb) node.start(cb)
}), }),
(cb) => createNode('/ip4/0.0.0.0/tcp/0', { (cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['multiplex'] muxer: ['mplex']
}, (err, node) => { }, (err, node) => {
expect(err).to.not.exist() expect(err).to.not.exist()
nodeB = node nodeB = node
@ -200,12 +191,12 @@ describe('stream muxing', () => {
(cb) => setup(cb), (cb) => setup(cb),
(cb) => { (cb) => {
// it will just 'warm up a conn' // it will just 'warm up a conn'
expect(Object.keys(nodeA.swarm.muxers)).to.have.length(1) expect(Object.keys(nodeA.switch.muxers)).to.have.length(1)
expect(Object.keys(nodeB.swarm.muxers)).to.have.length(1) expect(Object.keys(nodeB.switch.muxers)).to.have.length(1)
nodeA.dial(nodeB.peerInfo, (err) => { nodeA.dial(nodeB.peerInfo, (err) => {
expect(err).to.not.exist() expect(err).to.not.exist()
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
cb() cb()
}) })
}, },

View File

@ -12,6 +12,7 @@ const parallel = require('async/parallel')
const goodbye = require('pull-goodbye') const goodbye = require('pull-goodbye')
const serializer = require('pull-serializer') const serializer = require('pull-serializer')
const w = require('webrtcsupport') const w = require('webrtcsupport')
const tryEcho = require('./utils/try-echo')
const Node = require('./utils/bundle.browser') const Node = require('./utils/bundle.browser')
const rawPeer = require('./fixtures/test-peer.json') const rawPeer = require('./fixtures/test-peer.json')
@ -47,12 +48,12 @@ describe('transports', () => {
}) })
}) })
it('create libp2pNode with multiplex only', (done) => { it('create libp2pNode with mplex only', (done) => {
PeerInfo.create((err, peerInfo) => { PeerInfo.create((err, peerInfo) => {
expect(err).to.not.exist() expect(err).to.not.exist()
const b = new Node(peerInfo, null, { muxer: ['multiplex'] }) const b = new Node(peerInfo, null, { muxer: ['mplex'] })
expect(b.modules.connection.muxer).to.eql([require('libp2p-multiplex')]) expect(b.modules.connection.muxer).to.eql([require('libp2p-mplex')])
done() done()
}) })
}) })
@ -63,7 +64,7 @@ describe('transports', () => {
// General connectivity tests // General connectivity tests
it('libp2p.dial using Multiaddr nodeA to nodeB', (done) => { it('.dial using Multiaddr', (done) => {
nodeA.dial(peerB.multiaddrs.toArray()[0], (err) => { nodeA.dial(peerB.multiaddrs.toArray()[0], (err) => {
expect(err).to.not.exist() expect(err).to.not.exist()
@ -77,26 +78,18 @@ describe('transports', () => {
}) })
}) })
it('libp2p.dial using Multiaddr on Protocol nodeA to nodeB', (done) => { it('.dialProtocol using Multiaddr', (done) => {
nodeA.dial(peerB.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => { nodeA.dialProtocol(peerB.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
const peers = nodeA.peerBook.getAll() const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
pull( tryEcho(conn, done)
pull.values([Buffer.from('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.eql([Buffer.from('hey')])
done()
})
)
}) })
}) })
it('libp2p.hangUp using Multiaddr nodeA to nodeB', (done) => { it('.hangUp using Multiaddr', (done) => {
nodeA.hangUp(peerB.multiaddrs.toArray()[0], (err) => { nodeA.hangUp(peerB.multiaddrs.toArray()[0], (err) => {
expect(err).to.not.exist() expect(err).to.not.exist()
@ -105,13 +98,13 @@ describe('transports', () => {
function check () { function check () {
const peers = nodeA.peerBook.getAll() const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
done() done()
} }
}) })
}) })
it('libp2p.dial using PeerInfo nodeA to nodeB', (done) => { it('.dial using PeerInfo', (done) => {
nodeA.dial(peerB, (err) => { nodeA.dial(peerB, (err) => {
expect(err).to.not.exist() expect(err).to.not.exist()
@ -125,26 +118,18 @@ describe('transports', () => {
}) })
}) })
it('libp2p.dial using PeerInfo on Protocol nodeA to nodeB', (done) => { it('.dialProtocol using PeerInfo', (done) => {
nodeA.dial(peerB, '/echo/1.0.0', (err, conn) => { nodeA.dialProtocol(peerB, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
const peers = nodeA.peerBook.getAll() const peers = nodeA.peerBook.getAll()
expect(err).to.not.exist() expect(err).to.not.exist()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
pull( tryEcho(conn, done)
pull.values([Buffer.from('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.eql([Buffer.from('hey')])
done()
})
)
}) })
}) })
it('libp2p.hangUp using PeerInfo nodeA to nodeB', (done) => { it('.hangUp using PeerInfo', (done) => {
nodeA.hangUp(peerB, (err) => { nodeA.hangUp(peerB, (err) => {
expect(err).to.not.exist() expect(err).to.not.exist()
setTimeout(check, 500) setTimeout(check, 500)
@ -153,7 +138,7 @@ describe('transports', () => {
const peers = nodeA.peerBook.getAll() const peers = nodeA.peerBook.getAll()
expect(err).to.not.exist() expect(err).to.not.exist()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
done() done()
} }
}) })
@ -161,7 +146,7 @@ describe('transports', () => {
describe('stress', () => { describe('stress', () => {
it('one big write', (done) => { it('one big write', (done) => {
nodeA.dial(peerB, '/echo/1.0.0', (err, conn) => { nodeA.dialProtocol(peerB, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
const rawMessage = Buffer.alloc(100000) const rawMessage = Buffer.alloc(100000)
rawMessage.fill('a') rawMessage.fill('a')
@ -180,7 +165,7 @@ describe('transports', () => {
}) })
it('many writes', (done) => { it('many writes', (done) => {
nodeA.dial(peerB, '/echo/1.0.0', (err, conn) => { nodeA.dialProtocol(peerB, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
const s = serializer(goodbye({ const s = serializer(goodbye({
@ -235,39 +220,30 @@ describe('transports', () => {
done() done()
}) })
it('listen on the two libp2p nodes', (done) => { it('start two libp2p nodes', (done) => {
parallel([ parallel([
(cb) => node1.start(cb), (cb) => node1.start(cb),
(cb) => node2.start(cb) (cb) => node2.start(cb)
], done) ], done)
}) })
it('handle a protocol on the first node', () => { it('.handle echo on first node', () => {
node2.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn)) node2.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
}) })
it('dial from the second node to the first node', (done) => { it('.dialProtocol from the second node to the first node', (done) => {
node1.dial(peer2, '/echo/1.0.0', (err, conn) => { node1.dialProtocol(peer2, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
setTimeout(check, 500) setTimeout(check, 500)
function check () { function check () {
const text = 'hello'
const peers1 = node1.peerBook.getAll() const peers1 = node1.peerBook.getAll()
expect(Object.keys(peers1)).to.have.length(1) expect(Object.keys(peers1)).to.have.length(1)
const peers2 = node2.peerBook.getAll() const peers2 = node2.peerBook.getAll()
expect(Object.keys(peers2)).to.have.length(1) expect(Object.keys(peers2)).to.have.length(1)
pull( tryEcho(conn, done)
pull.values([Buffer.from(text)]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data[0].toString()).to.equal(text)
done()
})
)
} }
}) })
}) })
@ -280,7 +256,7 @@ describe('transports', () => {
function check () { function check () {
const peers = node1.peerBook.getAll() const peers = node1.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(node1.swarm.muxedConns)).to.have.length(0) expect(Object.keys(node1.switch.muxedConns)).to.have.length(0)
done() done()
} }
}) })
@ -291,8 +267,8 @@ describe('transports', () => {
function check () { function check () {
if (++counter === 3) { if (++counter === 3) {
expect(Object.keys(node1.swarm.muxedConns).length).to.equal(1) expect(Object.keys(node1.switch.muxedConns).length).to.equal(1)
expect(Object.keys(node2.swarm.muxedConns).length).to.equal(1) expect(Object.keys(node2.switch.muxedConns).length).to.equal(1)
done() done()
} }
} }
@ -355,28 +331,19 @@ describe('transports', () => {
node2.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn)) node2.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
}) })
it('dial from the second node to the first node', (done) => { it('.dialProtocol from the second node to the first node', (done) => {
node1.dial(peer2, '/echo/1.0.0', (err, conn) => { node1.dialProtocol(peer2, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
setTimeout(check, 500) setTimeout(check, 500)
function check () { function check () {
const text = 'hello'
const peers1 = node1.peerBook.getAll() const peers1 = node1.peerBook.getAll()
expect(Object.keys(peers1)).to.have.length(1) expect(Object.keys(peers1)).to.have.length(1)
const peers2 = node2.peerBook.getAll() const peers2 = node2.peerBook.getAll()
expect(Object.keys(peers2)).to.have.length(1) expect(Object.keys(peers2)).to.have.length(1)
pull( tryEcho(conn, done)
pull.values([Buffer.from(text)]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data[0].toString()).to.equal(text)
done()
})
)
} }
}) })
}) })
@ -389,7 +356,7 @@ describe('transports', () => {
function check () { function check () {
const peers = node1.peerBook.getAll() const peers = node1.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(node1.swarm.muxedConns)).to.have.length(0) expect(Object.keys(node1.switch.muxedConns)).to.have.length(0)
done() done()
} }
}) })
@ -400,8 +367,8 @@ describe('transports', () => {
function check () { function check () {
if (++counter === 3) { if (++counter === 3) {
expect(Object.keys(node1.swarm.muxedConns).length).to.equal(1) expect(Object.keys(node1.switch.muxedConns).length).to.equal(1)
expect(Object.keys(node2.swarm.muxedConns).length).to.equal(1) expect(Object.keys(node2.switch.muxedConns).length).to.equal(1)
done() done()
} }
} }

View File

@ -6,13 +6,13 @@ chai.use(require('dirty-chai'))
const expect = chai.expect const expect = chai.expect
const parallel = require('async/parallel') const parallel = require('async/parallel')
const series = require('async/series') const series = require('async/series')
const pull = require('pull-stream')
const utils = require('./utils/node.js') const utils = require('./utils/node.js')
const signalling = require('libp2p-webrtc-star/src/sig-server') const signalling = require('libp2p-webrtc-star/src/sig-server')
const rendezvous = require('libp2p-websocket-star-rendezvous') const rendezvous = require('libp2p-websocket-star-rendezvous')
const WSStar = require('libp2p-websocket-star') const WSStar = require('libp2p-websocket-star')
const WRTCStar = require('libp2p-webrtc-star') const WRTCStar = require('libp2p-webrtc-star')
const wrtc = require('wrtc') const wrtc = require('wrtc')
const tryEcho = require('./utils/try-echo')
const createNode = utils.createNode const createNode = utils.createNode
const echo = utils.echo const echo = utils.echo
@ -73,18 +73,10 @@ describe('transports', () => {
}) })
it('nodeA.dial nodeB using PeerInfo', (done) => { it('nodeA.dial nodeB using PeerInfo', (done) => {
nodeA.dial(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => { nodeA.dialProtocol(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
pull( tryEcho(conn, done)
pull.values([Buffer.from('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.be.eql([Buffer.from('hey')])
done()
})
)
}) })
}) })
@ -98,14 +90,14 @@ describe('transports', () => {
(cb) => { (cb) => {
const peers = nodeA.peerBook.getAll() const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
cb() cb()
}, },
(cb) => { (cb) => {
const peers = nodeB.peerBook.getAll() const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeB.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeB.switch.muxedConns)).to.have.length(0)
cb() cb()
} }
], done) ], done)
@ -113,8 +105,8 @@ describe('transports', () => {
}) })
}) })
it('nodeA.dial nodeB using multiaddr', (done) => { it('nodeA.dialProtocol nodeB using multiaddr', (done) => {
nodeA.dial(nodeB.peerInfo.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => { nodeA.dialProtocol(nodeB.peerInfo.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => {
// Some time for Identify to finish // Some time for Identify to finish
setTimeout(check, 500) setTimeout(check, 500)
@ -125,27 +117,17 @@ describe('transports', () => {
const peers = nodeA.peerBook.getAll() const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
cb() cb()
}, },
(cb) => { (cb) => {
const peers = nodeB.peerBook.getAll() const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
cb() cb()
} }
], () => { ], () => tryEcho(conn, done))
pull(
pull.values([Buffer.from('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.be.eql([Buffer.from('hey')])
done()
})
)
})
} }
}) })
}) })
@ -161,14 +143,14 @@ describe('transports', () => {
const peers = nodeA.peerBook.getAll() const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
cb() cb()
}, },
(cb) => { (cb) => {
const peers = nodeB.peerBook.getAll() const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeB.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeB.switch.muxedConns)).to.have.length(0)
cb() cb()
} }
], done) ], done)
@ -176,8 +158,8 @@ describe('transports', () => {
}) })
}) })
it('nodeA.dial nodeB using PeerId', (done) => { it('nodeA.dialProtocol nodeB using PeerId', (done) => {
nodeA.dial(nodeB.peerInfo.id, '/echo/1.0.0', (err, conn) => { nodeA.dialProtocol(nodeB.peerInfo.id, '/echo/1.0.0', (err, conn) => {
// Some time for Identify to finish // Some time for Identify to finish
setTimeout(check, 500) setTimeout(check, 500)
@ -187,26 +169,16 @@ describe('transports', () => {
(cb) => { (cb) => {
const peers = nodeA.peerBook.getAll() const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
cb() cb()
}, },
(cb) => { (cb) => {
const peers = nodeB.peerBook.getAll() const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
cb() cb()
} }
], () => { ], () => tryEcho(conn, done))
pull(
pull.values([Buffer.from('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.eql([Buffer.from('hey')])
done()
})
)
})
} }
}) })
}) })
@ -221,13 +193,13 @@ describe('transports', () => {
(cb) => { (cb) => {
const peers = nodeA.peerBook.getAll() const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
cb() cb()
}, },
(cb) => { (cb) => {
const peers = nodeB.peerBook.getAll() const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeB.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeB.switch.muxedConns)).to.have.length(0)
cb() cb()
} }
], done) ], done)
@ -291,13 +263,13 @@ describe('transports', () => {
(cb) => { (cb) => {
const peers = nodeTCP.peerBook.getAll() const peers = nodeTCP.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCP.swarm.muxedConns)).to.have.length(1) expect(Object.keys(nodeTCP.switch.muxedConns)).to.have.length(1)
cb() cb()
}, },
(cb) => { (cb) => {
const peers = nodeTCPnWS.peerBook.getAll() const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(1) expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(1)
cb() cb()
} }
], done) ], done)
@ -315,14 +287,14 @@ describe('transports', () => {
(cb) => { (cb) => {
const peers = nodeTCP.peerBook.getAll() const peers = nodeTCP.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCP.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeTCP.switch.muxedConns)).to.have.length(0)
cb() cb()
}, },
(cb) => { (cb) => {
const peers = nodeTCPnWS.peerBook.getAll() const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(0)
cb() cb()
} }
], done) ], done)
@ -342,13 +314,13 @@ describe('transports', () => {
(cb) => { (cb) => {
const peers = nodeTCPnWS.peerBook.getAll() const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(2) expect(Object.keys(peers)).to.have.length(2)
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(1) expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(1)
cb() cb()
}, },
(cb) => { (cb) => {
const peers = nodeWS.peerBook.getAll() const peers = nodeWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeWS.swarm.muxedConns)).to.have.length(1) expect(Object.keys(nodeWS.switch.muxedConns)).to.have.length(1)
cb() cb()
} }
], done) ], done)
@ -366,14 +338,14 @@ describe('transports', () => {
(cb) => { (cb) => {
const peers = nodeTCPnWS.peerBook.getAll() const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(2) expect(Object.keys(peers)).to.have.length(2)
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(0)
cb() cb()
}, },
(cb) => { (cb) => {
const peers = nodeWS.peerBook.getAll() const peers = nodeWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeWS.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeWS.switch.muxedConns)).to.have.length(0)
cb() cb()
} }
], done) ], done)
@ -481,7 +453,7 @@ describe('transports', () => {
let i = 1; let i = 1;
[nodeAll, otherNode].forEach((node) => { [nodeAll, otherNode].forEach((node) => {
expect(Object.keys(node.peerBook.getAll())).to.have.length(i-- ? peers : 1) expect(Object.keys(node.peerBook.getAll())).to.have.length(i-- ? peers : 1)
expect(Object.keys(node.swarm.muxedConns)).to.have.length(muxed) expect(Object.keys(node.switch.muxedConns)).to.have.length(muxed)
}) })
callback() callback()
} }
@ -624,7 +596,7 @@ describe('transports', () => {
let i = 1; let i = 1;
[nodeAll, otherNode].forEach((node) => { [nodeAll, otherNode].forEach((node) => {
expect(Object.keys(node.peerBook.getAll())).to.have.length(i-- ? peers : 1) expect(Object.keys(node.peerBook.getAll())).to.have.length(i-- ? peers : 1)
expect(Object.keys(node.swarm.muxedConns)).to.have.length(muxed) expect(Object.keys(node.switch.muxedConns)).to.have.length(muxed)
}) })
done() done()
} }

View File

@ -76,7 +76,7 @@ describe('Turbolence tests', () => {
function check () { function check () {
const peers = nodeA.peerBook.getAll() const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1) expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
done() done()
} }
}) })

View File

@ -4,7 +4,7 @@ const WS = require('libp2p-websockets')
const WebRTCStar = require('libp2p-webrtc-star') const WebRTCStar = require('libp2p-webrtc-star')
const WebSocketStar = require('libp2p-websocket-star') const WebSocketStar = require('libp2p-websocket-star')
const spdy = require('libp2p-spdy') const spdy = require('libp2p-spdy')
const multiplex = require('libp2p-multiplex') const mplex = require('libp2p-mplex')
const secio = require('libp2p-secio') const secio = require('libp2p-secio')
const Railing = require('libp2p-railing') const Railing = require('libp2p-railing')
const libp2p = require('../..') const libp2p = require('../..')
@ -17,8 +17,8 @@ function mapMuxers (list) {
switch (pref.trim().toLowerCase()) { switch (pref.trim().toLowerCase()) {
case 'spdy': case 'spdy':
return spdy return spdy
case 'multiplex': case 'mplex':
return multiplex return mplex
default: default:
throw new Error(pref + ' muxer not available') throw new Error(pref + ' muxer not available')
} }
@ -29,7 +29,7 @@ function getMuxers (options) {
if (options) { if (options) {
return mapMuxers(options) return mapMuxers(options)
} else { } else {
return [multiplex, spdy] return [mplex, spdy]
} }
} }

View File

@ -6,7 +6,7 @@ const WS = require('libp2p-websockets')
const Railing = require('libp2p-railing') const Railing = require('libp2p-railing')
const spdy = require('libp2p-spdy') const spdy = require('libp2p-spdy')
const KadDHT = require('libp2p-kad-dht') const KadDHT = require('libp2p-kad-dht')
const multiplex = require('libp2p-multiplex') const mplex = require('libp2p-mplex')
const secio = require('libp2p-secio') const secio = require('libp2p-secio')
const libp2p = require('../..') const libp2p = require('../..')
@ -17,7 +17,7 @@ function mapMuxers (list) {
} }
switch (pref.trim().toLowerCase()) { switch (pref.trim().toLowerCase()) {
case 'spdy': return spdy case 'spdy': return spdy
case 'multiplex': return multiplex case 'mplex': return mplex
default: default:
throw new Error(pref + ' muxer not available') throw new Error(pref + ' muxer not available')
} }
@ -31,7 +31,7 @@ function getMuxers (muxers) {
} else if (muxers) { } else if (muxers) {
return mapMuxers(muxers) return mapMuxers(muxers)
} else { } else {
return [multiplex, spdy] return [mplex, spdy]
} }
} }

View File

@ -22,7 +22,7 @@ function createNode (multiaddrs, options, callback) {
} }
waterfall([ waterfall([
(cb) => PeerId.create({ bits: 1024 }, cb), (cb) => PeerId.create({ bits: 512 }, cb),
(peerId, cb) => PeerInfo.create(peerId, cb), (peerId, cb) => PeerInfo.create(peerId, cb),
(peerInfo, cb) => { (peerInfo, cb) => {
multiaddrs.map((ma) => peerInfo.multiaddrs.add(ma)) multiaddrs.map((ma) => peerInfo.multiaddrs.add(ma))

21
test/utils/try-echo.js Normal file
View File

@ -0,0 +1,21 @@
'use strict'
const pull = require('pull-stream')
const chai = require('chai')
const dirtyChai = require('dirty-chai')
const expect = chai.expect
chai.use(dirtyChai)
module.exports = (conn, callback) => {
const values = [Buffer.from('echo')]
pull(
pull.values(values),
conn,
pull.collect((err, _values) => {
expect(err).to.not.exist()
expect(_values).to.eql(values)
callback()
})
)
}