Compare commits

..

3 Commits

Author SHA1 Message Date
ea67053fd2 chore: release version v0.12.1 2017-09-07 10:53:14 +01:00
cd8e7f137b chore: update contributors 2017-09-07 10:53:14 +01:00
60fa05a2dc chore: update deps 2017-09-07 10:50:32 +01:00
96 changed files with 1424 additions and 2972 deletions

View File

@ -1,71 +0,0 @@
'use strict'
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const pull = require('pull-stream')
const parallel = require('async/parallel')
const rawPeer = require('./test/fixtures/test-peer.json')
const Node = require('./test/utils/bundle.node.js')
const sigServer = require('libp2p-webrtc-star/src/sig-server')
const WebSocketStarRendezvous = require('libp2p-websocket-star-rendezvous')
let wrtcRendezvous
let wsRendezvous
let node
const before = (done) => {
parallel([
(cb) => {
sigServer.start({
port: 15555
// cryptoChallenge: true TODO: needs https://github.com/libp2p/js-libp2p-webrtc-star/issues/128
}, (err, server) => {
if (err) { return cb(err) }
wrtcRendezvous = server
cb()
})
},
(cb) => {
WebSocketStarRendezvous.start({
port: 14444,
refreshPeerListIntervalMS: 1000,
strictMultiaddr: false,
cryptoChallenge: true
}, (err, _server) => {
if (err) { return cb(err) }
wsRendezvous = _server
cb()
})
},
(cb) => {
PeerId.createFromJSON(rawPeer, (err, peerId) => {
if (err) {
return done(err)
}
const peer = new PeerInfo(peerId)
peer.multiaddrs.add('/ip4/127.0.0.1/tcp/9200/ws')
node = new Node(peer)
node.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
node.start(cb)
})
}
], done)
}
const after = (done) => {
setTimeout(() => parallel(
[node, wrtcRendezvous, wsRendezvous].map((s) => {
return (cb) => s.stop(cb)
})
, done), 2000)
}
module.exports = {
hooks: {
pre: before,
post: after
}
}

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
docs
**/node_modules/
**/*.log
test/repo-tests*

View File

@ -1,16 +1,7 @@
**/node_modules/
**/*.log
test/repo-tests*
img
docs
examples
# Logs
logs
*.log
coverage
# Runtime data
pids
*.pid
@ -25,13 +16,13 @@ coverage
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
build
# Optional npm cache directory
.npm
# Dependency directory
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
node_modules
# Optional REPL history
.node_repl_history
test
test

View File

@ -1,19 +1,28 @@
# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
sudo: false
language: node_js
matrix:
include:
- node_js: 'stable'
- node_js: 6
env: CXX=g++-4.8
- node_js: 8
env: CXX=g++-4.8
# - node_js: stable
# env: CXX=g++-4.8
script:
- npm run lint
- npm run test
- npm run coverage
- make test
before_script:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
after_success:
- npm run coverage-publish
addons:
firefox: 'latest'
apt:

View File

@ -1,190 +1,3 @@
<a name="0.20.2"></a>
## [0.20.2](https://github.com/libp2p/js-libp2p/compare/v0.20.1...v0.20.2) (2018-04-10)
<a name="0.20.1"></a>
## [0.20.1](https://github.com/libp2p/js-libp2p/compare/v0.20.0...v0.20.1) (2018-04-10)
<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>
## [0.15.2](https://github.com/libp2p/js-libp2p/compare/v0.15.1...v0.15.2) (2018-01-28)
<a name="0.15.1"></a>
## [0.15.1](https://github.com/libp2p/js-libp2p/compare/v0.15.0...v0.15.1) (2018-01-16)
### Bug Fixes
* typo in DHT setup ([#151](https://github.com/libp2p/js-libp2p/issues/151)) ([61bebd1](https://github.com/libp2p/js-libp2p/commit/61bebd1))
<a name="0.15.0"></a>
# [0.15.0](https://github.com/libp2p/js-libp2p/compare/v0.14.3...v0.15.0) (2018-01-07)
<a name="0.14.3"></a>
## [0.14.3](https://github.com/libp2p/js-libp2p/compare/v0.14.2...v0.14.3) (2017-12-15)
<a name="0.14.2"></a>
## [0.14.2](https://github.com/libp2p/js-libp2p/compare/v0.14.1...v0.14.2) (2017-12-15)
<a name="0.14.1"></a>
## [0.14.1](https://github.com/libp2p/js-libp2p/compare/v0.14.0...v0.14.1) (2017-12-15)
### Bug Fixes
* prevent "The libp2p node is not started yet" when stopping ([#138](https://github.com/libp2p/js-libp2p/issues/138)) ([c88eaf4](https://github.com/libp2p/js-libp2p/commit/c88eaf4))
<a name="0.14.0"></a>
# [0.14.0](https://github.com/libp2p/js-libp2p/compare/v0.13.3...v0.14.0) (2017-12-14)
### Bug Fixes
* remove innactive multiaddrs ([#131](https://github.com/libp2p/js-libp2p/issues/131)) ([1b7360f](https://github.com/libp2p/js-libp2p/commit/1b7360f))
<a name="0.13.3"></a>
## [0.13.3](https://github.com/libp2p/js-libp2p/compare/v0.13.2...v0.13.3) (2017-12-01)
<a name="0.13.2"></a>
## [0.13.2](https://github.com/libp2p/js-libp2p/compare/v0.13.1...v0.13.2) (2017-11-27)
### Features
* Bring libp2p-websocket-star to the Transports family! 🌟 ([#122](https://github.com/libp2p/js-libp2p/issues/122)) ([95f029e](https://github.com/libp2p/js-libp2p/commit/95f029e))
<a name="0.13.1"></a>
## [0.13.1](https://github.com/libp2p/js-libp2p/compare/v0.13.0...v0.13.1) (2017-11-12)
<a name="0.13.0"></a>
# [0.13.0](https://github.com/libp2p/js-libp2p/compare/v0.12.4...v0.13.0) (2017-10-26)
### Features
* enable and test Circuit Relay ([29cc0af](https://github.com/libp2p/js-libp2p/commit/29cc0af))
<a name="0.12.4"></a>
## [0.12.4](https://github.com/libp2p/js-libp2p/compare/v0.12.3...v0.12.4) (2017-09-07)
<a name="0.12.3"></a>
## [0.12.3](https://github.com/libp2p/js-libp2p/compare/v0.12.2...v0.12.3) (2017-09-07)
<a name="0.12.2"></a>
## [0.12.2](https://github.com/libp2p/js-libp2p/compare/v0.12.0...v0.12.2) (2017-09-07)
<a name="0.12.1"></a>
## [0.12.1](https://github.com/libp2p/js-libp2p/compare/v0.12.0...v0.12.1) (2017-09-07)

181
README.md
View File

@ -48,9 +48,9 @@ We've come a long way, but this project is still in Alpha, lots of development i
## Background
libp2p is the product of a long and arduous quest to understand the evolution of the Internet networking stack. In order to build P2P applications, devs have long had to made custom ad-hoc solutions to fit their needs, sometimes making some hard assumptions about their runtimes and the state of the network at the time of their development. Today, looking back more than 20 years, we see a clear pattern in the types of mechanisms built around the Internet Protocol, IP, which can be found throughout many layers of the OSI layer system, libp2p distils these mechanisms into flat categories and defines clear interfaces that once exposed, enable other protocols and applications to use and swap them, enabling upgradability and adaptability for the runtime, without breaking the API.
libp2p is the product of a long and arduous quest to understand the evolution of the Internet networking stack. In order to build P2P applications, dev have long had to made custom ad-hoc solutions to fit their needs, sometimes making some hard assumptions about their runtimes and the state of the network at the time of their development. Today, looking back more than 20 years, we see a clear pattern in the types of mechanisms built around the Internet Protocol, IP, which can be found throughout many layers of the OSI layer system, libp2p distils these mechanisms into flat categories and defines clear interfaces that once exposed, enable other protocols and applications to use and swap them, enabling upgradability and adaptability for the runtime, without breaking the API.
We are in the process of writing better documentation, blog posts, tutorials and a formal specification. Today you can find:
We are in the process of writting better documentation, blog posts, tutorials and a formal specification. Today you can find:
- [libp2p.io](https://libp2p.io)
- [Specification (WIP)](https://github.com/libp2p/specs)
@ -82,7 +82,7 @@ npm install --save libp2p
### [Tutorials and Examples](/examples)
You can find multiple examples on the [examples folder](/examples) that will guide you through using libp2p for several scenarios.
You can find multiple examples on the [examples folder](/examples) that will guide you through using libp2p for several scenarions.
### Extending libp2p skeleton
@ -158,26 +158,16 @@ 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.
#### `libp2p.dial(peer, callback)`
#### `libp2p.dial(peer [, protocol, callback])`
> Dials to another peer in the network, establishes the connection.
> Dials to another peer in the network.
- `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
- `peer`: can be an instance of [PeerInfo][], [PeerId][] or [multiaddr][]
- `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` 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.hangUp(peer, callback)`
#### `libp2p.hangUp(peer, callback)
> Closes an open connection with a peer, graciously.
@ -206,10 +196,10 @@ class Node extends libp2p {
> Handle new protocol
- `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
- `handlerFunc`: Function with signature `function (protocol, conn) {}` where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object
- `handlerFunc`: Function with signature `function (protocol, conn) {}`
- `matchFunc`: Function for matching on protocol (exact matching, semver, etc). Default to exact match.
#### `libp2p.unhandle(protocol)`
#### `libp2p.unhandle(protocol)
> Stop handling protocol
@ -249,13 +239,9 @@ class Node extends libp2p {
> 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 also exposed for the time being`
`DHT methods exposed`
#### `libp2p.dht.put(key, value, callback)`
@ -277,149 +263,6 @@ class Node extends libp2p {
[multiaddr]: https://github.com/multiformats/js-multiaddr
[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
**Clone and install dependencies:**
```sh
> git clone https://github.com/ipfs/js-ipfs.git
> cd js-ipfs
> npm install
```
### Tests
#### Run unit tests
```sh
# run all the unit tsts
> npm test
# run just Node.js tests
> npm run test:node
# run just Browser tests (Chrome)
> npm run test:browser
```
#### Run interop tests
```sh
N/A
```
#### Run benchmark tests
```sh
N/A
```
### Packages
@ -431,8 +274,6 @@ 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-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-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** |
| [`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** |
@ -463,7 +304,7 @@ List of packages currently in existence for libp2p
The libp2p implementation in JavaScript is a work in progress. As such, there are a few things you can do right now to help out:
- Go through the modules and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrastructure behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically.
- Go through the modules and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrasture behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically.
- **Perform code reviews**. Most of this has been developed by @diasdavid, which means that more eyes will help a) speed the project along b) ensure quality and c) reduce possible future bugs.
- **Add tests**. There can never be enough tests.

View File

@ -1,29 +0,0 @@
# Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
version: "{build}"
environment:
matrix:
- nodejs_version: "6"
- nodejs_version: "8"
matrix:
fast_finish: true
install:
# Install Node.js
- ps: Install-Product node $env:nodejs_version
# Upgrade npm
- npm install -g npm
# Output our current versions for debugging
- node --version
- npm --version
# Install our package dependencies
- npm install
test_script:
- npm run test:node
build: off

2
ci/Jenkinsfile vendored
View File

@ -1,2 +0,0 @@
// Warning: This file is automatically synced from https://github.com/ipfs/ci-sync so if you want to change it, please change it there and ask someone to sync all repositories.
javascript()

View File

@ -2,22 +2,12 @@ machine:
node:
version: stable
test:
pre:
- npm run lint
post:
- npm run coverage -- --upload --providers coveralls
dependencies:
pre:
- google-chrome --version
- curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
- for v in $(curl http://archive.ubuntu.com/ubuntu/pool/main/n/nss/ | grep "href=" | grep "libnss3.*deb\"" -o | grep -o "libnss3.*deb" | grep "3.28" | grep "14.04"); do curl -L -o $v http://archive.ubuntu.com/ubuntu/pool/main/n/nss/$v; done && rm libnss3-tools*_i386.deb libnss3-dev*_i386.deb
- sudo dpkg -i google-chrome.deb || true
- sudo dpkg -i libnss3*.deb || true
- sudo apt-get update
- sudo apt-get install -f || true
- sudo dpkg -i libnss3*.deb
- sudo apt-get install -f
- sudo apt-get install --only-upgrade lsb-base
- sudo dpkg -i google-chrome.deb

View File

@ -10,8 +10,8 @@ Let us know if you find any issue or if you want to contribute and add a new tut
- [Protocol and Stream Muxing](./protocol-and-stream-muxing)
- [Encrypted Communications](./encrypted-communications)
- [Discovery Mechanisms](./discovery-mechanisms)
- [Peer Routing](./peer-and-content-routing)
- [Content Routing](./peer-and-content-routing)
- [Peer Routing](./peer-routing)
- [Content Routing](./content-routing)
- [PubSub](./pubsub)
- [NAT Traversal](./nat-traversal)
- Circuit Relay (future)

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,7 @@
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex')
const Multiplex = require('libp2p-multiplex')
const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info')
const MulticastDNS = require('libp2p-mdns')
@ -14,7 +14,7 @@ class MyBundle extends libp2p {
const modules = {
transport: [new TCP()],
connection: {
muxer: [Mplex],
muxer: [Multiplex],
crypto: [SECIO]
},
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
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).
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).
First, we create our libp2p bundle.
@ -18,7 +18,7 @@ class MyBundle extends libp2p {
const modules = {
transport: [new TCP()],
connection: {
muxer: [Mplex],
muxer: [Multiplex],
crypto: [SECIO]
},
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.
```JavaScript
```
let node
waterfall([
@ -111,7 +111,7 @@ class MyBundle extends libp2p {
const modules = {
transport: [new TCP()],
connection: {
muxer: [Mplex],
muxer: [Multiplex],
crypto: [SECIO]
},
// 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()))
console.log('Dialing to peer:', listenerMultiaddr.toString())
dialerNode.dialProtocol(listenerPeerInfo, '/echo/1.0.0', (err, conn) => {
dialerNode.dial(listenerPeerInfo, '/echo/1.0.0', (err, conn) => {
if (err) { throw err }
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 spdy = require('libp2p-spdy')
const KadDHT = require('libp2p-kad-dht')
const mplex = require('libp2p-mplex')
const multiplex = require('libp2p-multiplex')
const secio = require('libp2p-secio')
const libp2p = require('../../..')
@ -17,7 +17,7 @@ function mapMuxers (list) {
}
switch (pref.trim().toLowerCase()) {
case 'spdy': return spdy
case 'mplex': return mplex
case 'multiplex': return multiplex
default:
throw new Error(pref + ' muxer not available')
}
@ -31,7 +31,7 @@ function getMuxers (muxers) {
} else if (muxers) {
return mapMuxers(muxers)
} else {
return [mplex, spdy]
return [multiplex, spdy]
}
}

View File

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

View File

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

View File

@ -32,7 +32,7 @@ class MyBundle extends libp2p {
}
```
And that's it, from now on, all your libp2p communications are encrypted. Try running the example [1.js](./1.js) to see it working.
And that's it, from now on, all your libp2p communications are encrypted. Try running the exampme [1.js](./1.js) to see it working.
If you want to want to learn more about how SECIO works, you can read the [great write up done by Dominic Tarr](https://github.com/auditdrivencrypto/secure-channel/blob/master/prior-art.md#ipfss-secure-channel).

View File

@ -10,20 +10,20 @@
},
"license": "MIT",
"devDependencies": {
"browserify": "^14.5.0",
"browserify": "^14.4.0",
"concat-stream": "^1.6.0",
"detect-dom-ready": "^1.0.2",
"node-static": "^0.7.10"
"node-static": "^0.7.9"
},
"dependencies": {
"detect-dom-ready": "^1.0.2",
"libp2p": "^0.13.0",
"libp2p-mplex": "^0.6.0",
"libp2p-railing": "^0.7.1",
"libp2p-secio": "^0.8.1",
"libp2p-spdy": "^0.11.0",
"libp2p-webrtc-star": "^0.13.2",
"libp2p-websockets": "^0.10.4",
"peer-info": "^0.11.0"
"libp2p": "^0.11.0",
"libp2p-multiplex": "^0.4.4",
"libp2p-railing": "^0.6.1",
"libp2p-secio": "^0.7.1",
"libp2p-spdy": "^0.10.6",
"libp2p-webrtc-star": "^0.12.0",
"libp2p-websockets": "^0.10.1",
"peer-info": "^0.10.0"
}
}

View File

@ -3,7 +3,7 @@
const WebRTCStar = require('libp2p-webrtc-star')
const WebSockets = require('libp2p-websockets')
const Mplex = require('libp2p-mplex')
const Multiplex = require('libp2p-multiplex')
const SPDY = require('libp2p-spdy')
const SECIO = require('libp2p-secio')
@ -19,9 +19,7 @@ const bootstrapers = [
'/dns4/sfo-3.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
'/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
'/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
'/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
'/dns4/wss0.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
'/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6'
'/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64'
]
class Node extends libp2p {
@ -37,7 +35,7 @@ class Node extends libp2p {
],
connection: {
muxer: [
Mplex,
Multiplex,
SPDY
],
crypto: [SECIO]

View File

@ -10,7 +10,7 @@ function createNode (callback) {
}
const peerIdStr = peerInfo.id.toB58String()
const ma = `/dns4/star-signal.cloud.ipfs.team/tcp/443/wss/p2p-webrtc-star/ipfs/${peerIdStr}`
const ma = `/libp2p-webrtc-star/dns4/star-signal.cloud.ipfs.team/wss/ipfs/${peerIdStr}`
peerInfo.multiaddrs.add(ma)

View File

@ -13,4 +13,4 @@ Simple go into the folder [1](./1) and execute the following
# open your browser in port :9090
```
[Version Published on IPFS](http://ipfs.io/ipfs/Qmbc1J7ehw1dNYachbkCWPto4RsnVvqCKNVzmYEod2gXcy)
[Version Published on IPFS](http://ipfs.io/ipfs/QmcBnUWsPG9rFRnYUQH7FkgpxgUppnujcRvyVje77eiKwr)

View File

@ -2,7 +2,7 @@
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex')
const Multiplex = require('libp2p-multiplex')
const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info')
const KadDHT = require('libp2p-kad-dht')
@ -15,7 +15,7 @@ class MyBundle extends libp2p {
const modules = {
transport: [new TCP()],
connection: {
muxer: [Mplex],
muxer: [Multiplex],
crypto: [SECIO]
},
// we add the DHT module that will enable Peer and Content Routing
@ -53,7 +53,7 @@ parallel([
(cb) => node1.dial(node2.peerInfo, cb),
(cb) => node2.dial(node3.peerInfo, cb),
// Set up of the cons might take time
(cb) => setTimeout(cb, 300)
(cb) => setTimeout(cb, 100)
], (err) => {
if (err) { throw err }

View File

@ -2,7 +2,7 @@
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex')
const Multiplex = require('libp2p-multiplex')
const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info')
const CID = require('cids')
@ -16,7 +16,7 @@ class MyBundle extends libp2p {
const modules = {
transport: [new TCP()],
connection: {
muxer: [Mplex],
muxer: [Multiplex],
crypto: [SECIO]
},
// we add the DHT module that will enable Peer and Content Routing
@ -54,7 +54,7 @@ parallel([
(cb) => node1.dial(node2.peerInfo, cb),
(cb) => node2.dial(node3.peerInfo, cb),
// Set up of the cons might take time
(cb) => setTimeout(cb, 300)
(cb) => setTimeout(cb, 100)
], (err) => {
if (err) { throw err }

View File

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

View File

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

View File

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

View File

@ -74,10 +74,10 @@ parallel([
if (err) { throw err }
console.log('Addresses by which both peers are connected')
node1.peerBook
.getAllArray()
.forEach((peer) => console.log('node 1 to node 2:', peer.isConnected().toString()))
.getAllArray()
.forEach((peer) => console.log('node 1 to node 2:', peer.isConnected().toString()))
node2.peerBook
.getAllArray()
.forEach((peer) => console.log('node 2 to node 1:', peer.isConnected().toString()))
.getAllArray()
.forEach((peer) => console.log('node 2 to node 1:', peer.isConnected().toString()))
})
})

View File

@ -30,7 +30,7 @@ node2.handle('/your-protocol', (protocol, conn) => {
After the protocol is _handled_, now we can dial to it.
```JavaScript
node1.dialProtocol(node2.peerInfo, '/your-protocol', (err, conn) => {
node1.dial(node2.peerInfo, '/your-protocol', (err, conn) => {
if (err) { throw err }
pull(pull.values(['my own protocol, wow!']), conn)
})
@ -47,7 +47,7 @@ node2.handle('/another-protocol/1.0.1', (protocol, conn) => {
)
})
// ...
node1.dialProtocol(node2.peerInfo, '/another-protocol/1.0.0', (err, conn) => {
node1.dial(node2.peerInfo, '/another-protocol/1.0.0', (err, conn) => {
if (err) { throw err }
pull(pull.values(['semver me please']), conn)
})
@ -74,7 +74,7 @@ node2.handle('/custom-match-func', (protocol, conn) => {
}
})
// ...
node1.dialProtocol(node2.peerInfo, '/custom-match-func/some-query', (err, conn) => {
node1.dial(node2.peerInfo, '/custom-match-func/some-query', (err, conn) => {
if (err) { throw err }
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.
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.
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.
```JavaScript
const SPDY = require('libp2p-spdy')
@ -129,17 +129,17 @@ node2.handle('/b', (protocol, conn) => {
})
series([
(cb) => node1.dialProtocol(node2.peerInfo, '/a', (err, conn) => {
(cb) => node1.dial(node2.peerInfo, '/a', (err, conn) => {
if (err) { throw err }
pull(pull.values(['protocol (a)']), conn)
cb()
}),
(cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => {
if (err) { throw err }
pull(pull.values(['protocol (b)']), conn)
cb()
}),
(cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => {
if (err) { throw err }
pull(pull.values(['another conn on protocol (b)']), conn)
cb()
@ -158,9 +158,9 @@ another protocol (b)
# 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 _bidirectional connection_.
There is one last trick on _protocol and stream multiplexing_ that libp2p uses to make everyone's life easier and that is _biderectional 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'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.
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.
You can see this working on example [3.js](./3.js). The result should look like the following:

View File

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

View File

@ -1,6 +1,8 @@
# Publish Subscribe
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).
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.
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:
@ -10,31 +12,30 @@ 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
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).
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).
Using PubSub is super simple, all you have to do is start a libp2p node, PubSub will be enabled by default.
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.
```JavaScript
const FloodSub = require('libp2p-floodsub')
const fs1 = new FloodSub(node1)
const fs2 = new FloodSub(node2)
series([
(cb) => fs1.start(cb),
(cb) => fs2.start(cb),
(cb) => node1.once('peer:discovery', (peer) => node1.dial(peer, cb)),
(cb) => setTimeout(cb, 500)
], (err) => {
if (err) { throw err }
// Subscribe to the topic 'news'
node1.pubsub.subscribe('news',
(msg) => console.log(msg.from, msg.data.toString()),
() => {
setInterval(() => {
// Publish the message on topic 'news'
node2.pubsub.publish(
'news',
Buffer.from('Bird bird bird, bird is the word!'),
() => {}
)
}, 1000)
}
)
fs2.on('news', (msg) => console.log(msg.from, msg.data.toString()))
fs2.subscribe('news')
setInterval(() => {
fs1.publish('news', Buffer.from('Bird bird bird, bird is the word!'))
}, 1000)
})
```

View File

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

View File

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

View File

@ -143,7 +143,7 @@ parallel([
)
})
node1.dialProtocol(node2.peerInfo, '/print', (err, conn) => {
node1.dial(node2.peerInfo, '/print', (err, conn) => {
if (err) { throw err }
pull(pull.values(['Hello', ' ', 'p2p', ' ', 'world', '!']), conn)
@ -240,21 +240,21 @@ parallel([
node3.handle('/print', print)
// node 1 (TCP) dials to node 2 (TCP+WebSockets)
node1.dialProtocol(node2.peerInfo, '/print', (err, conn) => {
node1.dial(node2.peerInfo, '/print', (err, conn) => {
if (err) { throw err }
pull(pull.values(['node 1 dialed to node 2 successfully']), conn)
})
// node 2 (TCP+WebSockets) dials to node 2 (WebSockets)
node2.dialProtocol(node3.peerInfo, '/print', (err, conn) => {
node2.dial(node3.peerInfo, '/print', (err, conn) => {
if (err) { throw err }
pull(pull.values(['node 2 dialed to node 3 successfully']), conn)
})
// node 3 (WebSockets) attempts to dial to node 1 (TCP)
node3.dialProtocol(node1.peerInfo, '/print', (err, conn) => {
node3.dial(node1.peerInfo, '/print', (err, conn) => {
if (err) {
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.
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.
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.
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, so contributions are welcome!
Hope this tutorial was useful. We are always looking to improve it, contributions are welcome!

55
gulpfile.js Normal file
View File

@ -0,0 +1,55 @@
'use strict'
const gulp = require('gulp')
const Node = require('./test/nodejs-bundle/nodejs-bundle.js')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const pull = require('pull-stream')
const sigServer = require('libp2p-webrtc-star/src/sig-server')
let server
let node
const rawPeer = require('./test/browser-bundle/peer.json')
gulp.task('libnode:start', (done) => {
let count = 0
const ready = () => ++count === 2 ? done() : null
sigServer.start({ port: 15555 }, (err, _server) => {
if (err) {
throw err
}
server = _server
ready()
})
PeerId.createFromJSON(rawPeer, (err, peerId) => {
if (err) {
return done(err)
}
const peer = new PeerInfo(peerId)
peer.multiaddrs.add('/ip4/127.0.0.1/tcp/9200/ws')
node = new Node(peer)
node.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
node.start(() => ready())
})
})
gulp.task('libnode:stop', (done) => {
setTimeout(() => node.stop((err) => {
if (err) {
return done(err)
}
server.stop(done)
}), 2000)
})
gulp.task('test:browser:before', ['libnode:start'])
gulp.task('test:node:before', ['libnode:start'])
gulp.task('test:browser:after', ['libnode:stop'])
gulp.task('test:node:after', ['libnode:stop'])
require('aegir/gulp')(gulp)

View File

@ -1,19 +1,19 @@
{
"name": "libp2p",
"version": "0.20.2",
"version": "0.12.1",
"description": "JavaScript base class for libp2p bundles",
"main": "src/index.js",
"scripts": {
"lint": "aegir lint",
"build": "aegir build",
"test": "aegir test -t node -t browser",
"test:node": "aegir test -t node",
"test:browser": "aegir test -t browser",
"release": "aegir release -t node -t browser",
"release-minor": "aegir release --type minor -t node -t browser",
"release-major": "aegir release --type major -t node -t browser",
"coverage": "aegir coverage",
"coverage-publish": "aegir coverage --provider coveralls"
"test": "gulp test",
"test:node": "gulp test:node",
"test:browser": "gulp test:browser --dom",
"release": "gulp release --dom",
"release-minor": "gulp release --type minor --dom",
"release-major": "gulp release --type major --dom",
"build": "gulp build",
"lint": "aegir-lint",
"coverage": "aegir-coverage",
"coverage-publish": "aegir-coverage publish"
},
"repository": {
"type": "git",
@ -26,7 +26,7 @@
"node": ">=6.0.0",
"npm": ">=3.0.0"
},
"pre-push": [
"pre-commit": [
"lint",
"test"
],
@ -37,69 +37,47 @@
},
"homepage": "https://github.com/libp2p/js-libp2p",
"dependencies": {
"async": "^2.6.0",
"libp2p-floodsub": "^0.15.0",
"libp2p-ping": "~0.7.0",
"libp2p-switch": "~0.39.0",
"mafmt": "^6.0.0",
"multiaddr": "^4.0.0",
"peer-book": "~0.7.0",
"peer-id": "~0.10.7",
"libp2p-websockets": "^0.11.0",
"peer-info": "~0.14.1"
"async": "^2.5.0",
"libp2p-ping": "~0.6.0",
"libp2p-swarm": "~0.32.1",
"mafmt": "^3.0.1",
"multiaddr": "^3.0.1",
"peer-book": "~0.5.0",
"peer-id": "~0.10.0",
"peer-info": "~0.11.0"
},
"devDependencies": {
"aegir": "^13.0.6",
"aegir": "^11.0.2",
"chai": "^4.1.2",
"cids": "~0.5.3",
"dirty-chai": "^2.0.1",
"electron-webrtc": "~0.3.0",
"libp2p-circuit": "~0.2.0",
"libp2p-kad-dht": "~0.10.0",
"libp2p-mdns": "~0.11.0",
"libp2p-mplex": "~0.7.0",
"libp2p-railing": "~0.8.0",
"libp2p-secio": "~0.10.0",
"libp2p-spdy": "~0.12.1",
"libp2p-tcp": "~0.12.0",
"libp2p-webrtc-star": "~0.14.0",
"libp2p-websocket-star": "~0.8.0",
"libp2p-websocket-star-rendezvous": "~0.2.3",
"cids": "~0.5.1",
"libp2p-kad-dht": "~0.5.0",
"libp2p-mdns": "~0.9.0",
"libp2p-multiplex": "~0.5.0",
"libp2p-railing": "~0.7.0",
"libp2p-secio": "~0.8.1",
"libp2p-spdy": "~0.11.0",
"libp2p-tcp": "~0.11.0",
"libp2p-webrtc-star": "~0.13.1",
"libp2p-websockets": "~0.10.1",
"lodash.times": "^4.3.2",
"pre-commit": "^1.2.2",
"pull-goodbye": "0.0.2",
"pull-serializer": "~0.3.2",
"pull-stream": "^3.6.7",
"pull-serializer": "^0.3.2",
"pull-stream": "^3.6.0",
"safe-buffer": "^5.1.1",
"sinon": "^4.5.0",
"wrtc": "0.1.1"
"electron-webrtc": "^0.3.0",
"wrtc": "0.0.62"
},
"contributors": [
"Chris Bratlien <chrisbratlien@gmail.com>",
"Chris Dostert <chrisdostert@users.noreply.github.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>",
"David Dias <daviddias.p@gmail.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Elven <mon.samuel@qq.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Giovanni T. Parra <fiatjaf@gmail.com>",
"Irakli Gozalishvili <rfobic@gmail.com>",
"Joel Gustafson <joelg@mit.edu>",
"John Rees <johnrees@users.noreply.github.com>",
"Kevin Kwok <antimatter15@gmail.com>",
"Lars Gierth <lgierth@users.noreply.github.com>",
"Maciej Krüger <mkg20001@gmail.com>",
"Nuno Nogueira <nunofmn@gmail.com>",
"Pedro Teixeira <i@pgte.me>",
"RasmusErik Voel Jensen <github@solsort.com>",
"Richard Littauer <richard.littauer@gmail.com>",
"Ryan Bell <ryan@piing.net>",
"Sönke Hahn <soenkehahn@gmail.com>",
"Tiago Alves <alvesjtiago@gmail.com>",
"Zane Starr <zcstarr@gmail.com>",
"greenkeeperio-bot <support@greenkeeper.io>",
"mayerwin <mayerwin@users.noreply.github.com>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>"
"mayerwin <mayerwin@users.noreply.github.com>"
]
}
}

View File

@ -1,3 +0,0 @@
# PDD Test Stories Implementation
> Implementation of the Compliance tests from https://github.com/libp2p/interop

View File

@ -1,20 +0,0 @@
{
"name": "pdd-impl",
"version": "0.0.0",
"description": "PDD Test Stories implementation",
"repository": {
"type": "git",
"url": " "
},
"keywords": [
"PDD",
"libp2p"
],
"author": "David Dias <daviddias@ipfs.io>",
"license": "MIT",
"dependencies": {
"libp2p": "file:./..",
"libp2p-interop": "github:libp2p/interop#master",
"tape": "^4.8.0"
}
}

View File

@ -1,104 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const WebSockets = require('libp2p-websockets')
const SECIO = require('libp2p-secio')
const Multiplex = require('libp2p-multiplex')
const Railing = require('libp2p-railing')
const MulticastDNS = require('libp2p-mdns')
const KadDHT = require('libp2p-kad-dht')
const PeerInfo = require('peer-info')
const pull = require('pull-stream')
const waterfall = require('async/waterfall')
const series = require('async/series')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class IPFSBundle extends libp2p {
constructor (peerInfo, options) {
options = Object.assign({ bootstrap: [] }, options)
const modules = {
transport: [
new TCP(),
new WebSockets()
],
connection: {
muxer: [
Multiplex
],
crypto: [
SECIO
]
},
discovery: [
new MulticastDNS(peerInfo, 'ipfs.local'),
new Railing(options.bootstrap)
],
DHT: KadDHT
}
super(modules, peerInfo, undefined, options)
}
}
test('story 1 - peerA', (t) => {
t.plan(10)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000')
node = new IPFSBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node successfully')
t.ok(node.isStarted(), 'PeerA is Running')
const peerBAddr = `/ip4/127.0.0.1/tcp/10001/ipfs/${PeerB.id}`
node.handle('/time/1.0.0', (protocol, conn) => {
pull(
pull.values([Date.now().toString()]),
conn,
pull.onEnd((err) => {
t.ifErr(err)
t.pass('Sent time successfully')
})
)
})
series([
(cb) => setTimeout(cb, 5 * 1000), // time to run both scripts
(cb) => node.ping(peerBAddr, (err, p) => {
t.ifErr(err, 'initiated Ping to PeerB')
p.once('error', (err) => t.ifErr(err, 'Ping should not fail'))
p.once('ping', (time) => {
t.pass('ping PeerB successfully')
p.stop()
cb()
})
}),
(cb) => node.dial(peerBAddr, '/echo/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
const data = Buffer.from('Hey')
pull(
pull.values([data]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received echo back')
t.deepEqual(values[0], data)
cb()
})
)
}),
(cb) => setTimeout(cb, 2 * 1000) // time to both finish
], () => node.stop((err) => t.ifErr(err, 'PeerA has stopped')))
})
})

View File

@ -1,98 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const WebSockets = require('libp2p-websockets')
const SECIO = require('libp2p-secio')
const Multiplex = require('libp2p-multiplex')
const Railing = require('libp2p-railing')
const MulticastDNS = require('libp2p-mdns')
const KadDHT = require('libp2p-kad-dht')
const PeerInfo = require('peer-info')
const pull = require('pull-stream')
const waterfall = require('async/waterfall')
const series = require('async/series')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class IPFSBundle extends libp2p {
constructor (peerInfo, options) {
options = Object.assign({ bootstrap: [] }, options)
const modules = {
transport: [
new TCP(),
new WebSockets()
],
connection: {
muxer: [
Multiplex
],
crypto: [
SECIO
]
},
discovery: [
new MulticastDNS(peerInfo, 'ipfs.local'),
new Railing(options.bootstrap)
],
DHT: KadDHT
}
super(modules, peerInfo, undefined, options)
}
}
test('story 1 - peerA', (t) => {
t.plan(8)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10001')
node = new IPFSBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node successfully')
t.ok(node.isStarted(), 'PeerB is Running')
const peerAAddr = `/ip4/127.0.0.1/tcp/10000/ipfs/${PeerA.id}`
node.handle('/echo/1.0.0', (protocol, conn) => {
pull(
conn,
conn,
pull.onEnd((err) => t.ifErr(err, 'echo was successful'))
)
})
series([
(cb) => setTimeout(cb, 5 * 1000), // time to run both scripts
(cb) => node.ping(peerAAddr, (err, p) => {
t.ifErr(err, 'initiated Ping to PeerA')
p.once('error', (err) => t.ifErr(err, 'Ping should not fail'))
p.once('ping', (time) => {
t.pass('ping PeerA successfully')
p.stop()
cb()
})
}),
(cb) => node.dial(peerAAddr, '/time/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
pull(
pull.values([]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received time')
cb()
})
)
}),
(cb) => setTimeout(cb, 2 * 1000) // time to both finish
], () => node.stop((err) => t.ifErr(err, 'PeerB has stopped')))
})
})

View File

@ -1,54 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new TCP()]
}
super(modules, peerInfo)
}
}
test('story 1 - peerA', (t) => {
t.plan(6)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerBAddr = `/ip4/127.0.0.1/tcp/10001/ipfs/${PeerB.id}`
node.dial(PeerBAddr, '/echo/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
const data = Buffer.from('Heey')
pull(
pull.values([data]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received echo back')
t.deepEqual(values[0], data)
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
})
)
})
})
})

View File

@ -1,49 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new TCP()]
}
super(modules, peerInfo)
}
}
test('story 1 - peerB', (t) => {
t.plan(5)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10001')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err)
t.ok(node.isStarted(), 'PeerB is running')
node.handle('/echo/1.0.0', (protocol, conn) => {
pull(
conn,
conn,
pull.onEnd((err) => {
t.ifErr(err)
t.pass('Received End of Connection')
node.stop((err) => {
t.ifErr(err, 'PeerB has stopped')
})
})
)
})
})
})

View File

@ -1,54 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new WebSockets()]
}
super(modules, peerInfo)
}
}
test('story 2 - peerA', (t) => {
t.plan(6)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000/ws')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerBAddr = `/ip4/127.0.0.1/tcp/10001/ws/ipfs/${PeerB.id}`
node.dial(PeerBAddr, '/echo/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
const data = Buffer.from('Heey')
pull(
pull.values([data]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received echo back')
t.deepEqual(values[0], data)
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
})
)
})
})
})

View File

@ -1,49 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new WebSockets()]
}
super(modules, peerInfo)
}
}
test('story 2 - peerB', (t) => {
t.plan(5)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10001/ws')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err)
t.ok(node.isStarted(), 'PeerB is running')
node.handle('/echo/1.0.0', (protocol, conn) => {
pull(
conn,
pull.through(v => v, err => {
t.ifErr(err)
t.pass('Received End of Connection')
node.stop((err) => {
t.ifErr(err, 'PeerB has stopped')
})
}),
conn
)
})
})
})

View File

@ -1,42 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new TCP()]
}
super(modules, peerInfo)
}
}
test('story 3 - peerA', (t) => {
t.plan(4)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerBAddr = `/ip4/127.0.0.1/tcp/10001/ws/ipfs/${PeerB.id}`
setTimeout(() => node.dial(PeerBAddr, '/echo/1.0.0', (err, conn) => {
t.ok(err, 'dial failed')
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
}), 1000)
})
})

View File

@ -1,42 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new WebSockets()]
}
super(modules, peerInfo)
}
}
test('story 3 - peerB', (t) => {
t.plan(4)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000/ws')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerAAddr = `/ip4/127.0.0.1/tcp/10000/ws/ipfs/${PeerA.id}`
setTimeout(() => node.dial(PeerAAddr, '/echo/1.0.0', (err, conn) => {
t.ok(err, 'dial failed')
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
}), 1000)
})
})

View File

@ -1,20 +0,0 @@
'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)
}
}
}

View File

@ -1,27 +0,0 @@
'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)
}
}
}

View File

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

View File

@ -1,48 +0,0 @@
'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,16 +7,13 @@ const setImmediate = require('async/setImmediate')
const each = require('async/each')
const series = require('async/series')
const PeerBook = require('peer-book')
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')
const Swarm = require('libp2p-swarm')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const PeerBook = require('peer-book')
const mafmt = require('mafmt')
const multiaddr = require('multiaddr')
exports = module.exports
@ -35,29 +32,25 @@ class Node extends EventEmitter {
this._isStarted = false
this.switch = new Switch(this.peerInfo, this.peerBook, _options.switch)
this.stats = this.switch.stats
this.swarm = new Swarm(this.peerInfo, this.peerBook)
// Attach stream multiplexers
if (this.modules.connection && this.modules.connection.muxer) {
let muxers = this.modules.connection.muxer
muxers = Array.isArray(muxers) ? muxers : [muxers]
muxers.forEach((muxer) => this.switch.connection.addStreamMuxer(muxer))
muxers.forEach((muxer) => this.swarm.connection.addStreamMuxer(muxer))
// If muxer exists, we can use Identify
this.switch.connection.reuse()
// If muxer exists, we can use Relay for listening/dialing
this.switch.connection.enableCircuitRelay(_options.relay)
this.swarm.connection.reuse()
// Received incommind dial and muxer upgrade happened,
// reuse this muxed connection
this.switch.on('peer-mux-established', (peerInfo) => {
this.swarm.on('peer-mux-established', (peerInfo) => {
this.emit('peer:connect', peerInfo)
this.peerBook.put(peerInfo)
})
this.switch.on('peer-mux-closed', (peerInfo) => {
this.swarm.on('peer-mux-closed', (peerInfo) => {
this.emit('peer:disconnect', peerInfo)
})
}
@ -67,7 +60,7 @@ class Node extends EventEmitter {
let cryptos = this.modules.connection.crypto
cryptos = Array.isArray(cryptos) ? cryptos : [cryptos]
cryptos.forEach((crypto) => {
this.switch.connection.crypto(crypto.tag, crypto.encrypt)
this.swarm.connection.crypto(crypto.tag, crypto.encrypt)
})
}
@ -81,23 +74,67 @@ class Node extends EventEmitter {
})
}
// Mount default protocols
Ping.mount(this.swarm)
// dht provided components (peerRouting, contentRouting, dht)
if (_modules.DHT) {
this._dht = new this.modules.DHT(this.switch, {
this._dht = new this.modules.DHT(this.swarm, {
kBucketSize: 20,
datastore: _options.DHT && _options.DHT.datastore
datastoer: _options.DHT && _options.DHT.datastore
})
}
this.peerRouting = peerRouting(this)
this.contentRouting = contentRouting(this)
this.dht = dht(this)
this.pubsub = pubsub(this)
this.peerRouting = {
findPeer: (id, callback) => {
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._getPeerInfo = getPeerInfo(this)
this._dht.findPeer(id, callback)
}
}
// Mount default protocols
Ping.mount(this.switch)
this.contentRouting = {
findProviders: (key, timeout, callback) => {
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)
}
}
}
/*
@ -117,20 +154,21 @@ class Node extends EventEmitter {
// so that we can have webrtc-star addrs without adding manually the id
const maOld = []
const maNew = []
this.peerInfo.multiaddrs.toArray().forEach((ma) => {
if (!ma.getPeerId()) {
this.peerInfo.multiaddrs.forEach((ma) => {
if (!mafmt.IPFS.matches(ma)) {
maOld.push(ma)
maNew.push(ma.encapsulate('/ipfs/' + this.peerInfo.id.toB58String()))
}
})
this.peerInfo.multiaddrs.replace(maOld, maNew)
const multiaddrs = this.peerInfo.multiaddrs.toArray()
transports.forEach((transport) => {
if (transport.filter(multiaddrs).length > 0) {
this.switch.transport.add(
this.swarm.transport.add(
transport.tag || transport.constructor.name, transport)
} else if (WebSockets.isWebSockets(transport)) {
} else if (transport.constructor &&
transport.constructor.name === 'WebSockets') {
// TODO find a cleaner way to signal that a transport is always
// used for dialing, even if no listener
ws = transport
@ -138,11 +176,11 @@ class Node extends EventEmitter {
})
series([
(cb) => this.switch.start(cb),
(cb) => this.swarm.listen(cb),
(cb) => {
if (ws) {
// always add dialing on websockets
this.switch.transport.add(ws.tag || ws.constructor.name, ws)
this.swarm.transport.add(ws.tag || ws.constructor.name, ws)
}
// all transports need to be setup before discover starts
@ -152,37 +190,12 @@ class Node extends EventEmitter {
cb()
},
(cb) => {
// TODO: chicken-and-egg problem #1:
// TODO: chicken-and-egg problem:
// have to set started here because DHT requires libp2p is already started
this._isStarted = true
if (this._dht) {
this._dht.start(cb)
} else {
cb()
return this._dht.start(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) => {
// detect which multiaddrs we don't have a transport for and remove them
const multiaddrs = this.peerInfo.multiaddrs.toArray()
transports.forEach((transport) => {
multiaddrs.forEach((multiaddr) => {
if (!multiaddr.toString().match(/\/p2p-circuit($|\/)/) &&
!transports.find((transport) => transport.filter(multiaddr).length > 0)) {
this.peerInfo.multiaddrs.delete(multiaddr)
}
})
})
cb()
},
(cb) => {
@ -196,6 +209,8 @@ class Node extends EventEmitter {
* Stop the libp2p node by closing its listeners and open connections
*/
stop (callback) {
this._isStarted = false
if (this.modules.discovery) {
this.modules.discovery.forEach((discovery) => {
setImmediate(() => discovery.stop(() => {}))
@ -203,48 +218,36 @@ class Node extends EventEmitter {
}
series([
(cb) => {
if (this._floodSub.started) {
this._floodSub.stop(cb)
}
},
(cb) => {
if (this._dht) {
return this._dht.stop(cb)
}
cb()
},
(cb) => this.switch.stop(cb),
(cb) => this.swarm.close(cb),
(cb) => {
this.emit('stop')
cb()
}
], (err) => {
this._isStarted = false
callback(err)
})
], callback)
}
isStarted () {
return this._isStarted
}
dial (peer, callback) {
ping (peer, callback) {
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { return callback(err) }
if (err) {
return callback(err)
}
this.switch.dial(peerInfo, (err) => {
if (err) { return callback(err) }
this.peerBook.put(peerInfo)
callback()
})
callback(null, new Ping(this.swarm, peerInfo))
})
}
dialProtocol (peer, protocol, callback) {
dial (peer, protocol, callback) {
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
if (typeof protocol === 'function') {
@ -253,10 +256,14 @@ class Node extends EventEmitter {
}
this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { return callback(err) }
if (err) {
return callback(err)
}
this.switch.dial(peerInfo, protocol, (err, conn) => {
if (err) { return callback(err) }
this.swarm.dial(peerInfo, protocol, (err, conn) => {
if (err) {
return callback(err)
}
this.peerBook.put(peerInfo)
callback(null, conn)
})
@ -267,27 +274,52 @@ class Node extends EventEmitter {
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { return callback(err) }
if (err) {
return callback(err)
}
this.switch.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))
this.swarm.hangUp(peerInfo, callback)
})
}
handle (protocol, handlerFunc, matchFunc) {
this.switch.handle(protocol, handlerFunc, matchFunc)
this.swarm.handle(protocol, handlerFunc, matchFunc)
}
unhandle (protocol) {
this.switch.unhandle(protocol)
this.swarm.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 (not string)
} else if (multiaddr.isMultiaddr(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))
}
}

View File

@ -1,13 +0,0 @@
'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)
}
}
}

View File

@ -1,93 +0,0 @@
'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

@ -2,9 +2,8 @@
const WS = require('libp2p-websockets')
const WebRTCStar = require('libp2p-webrtc-star')
const WebSocketStar = require('libp2p-websocket-star')
const spdy = require('libp2p-spdy')
const mplex = require('libp2p-mplex')
const multiplex = require('libp2p-multiplex')
const secio = require('libp2p-secio')
const Railing = require('libp2p-railing')
const libp2p = require('../..')
@ -17,8 +16,8 @@ function mapMuxers (list) {
switch (pref.trim().toLowerCase()) {
case 'spdy':
return spdy
case 'mplex':
return mplex
case 'multiplex':
return multiplex
default:
throw new Error(pref + ' muxer not available')
}
@ -29,21 +28,19 @@ function getMuxers (options) {
if (options) {
return mapMuxers(options)
} else {
return [mplex, spdy]
return [multiplex, spdy]
}
}
class Node extends libp2p {
constructor (peerInfo, peerBook, options) {
options = options || {}
const wrtcStar = new WebRTCStar({ id: peerInfo.id })
const wsStar = new WebSocketStar({ id: peerInfo.id })
const webRTCStar = new WebRTCStar()
const modules = {
transport: [
new WS(),
wrtcStar,
wsStar
webRTCStar
],
connection: {
muxer: getMuxers(options.muxer),
@ -55,11 +52,7 @@ class Node extends libp2p {
}
if (options.webRTCStar) {
modules.discovery.push(wrtcStar.discovery)
}
if (options.wsStar) {
modules.discovery.push(wsStar.discovery)
modules.discovery.push(webRTCStar.discovery)
}
if (options.bootstrap) {

View File

@ -0,0 +1,121 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const parallel = require('async/parallel')
const pull = require('pull-stream')
const Node = require('./browser-bundle')
describe('libp2p-ipfs-browser (webrtc only)', () => {
let peer1
let peer2
let node1
let node2
it('create two peerInfo with webrtc-star addrs', (done) => {
parallel([
(cb) => PeerId.create({ bits: 1024 }, cb),
(cb) => PeerId.create({ bits: 1024 }, cb)
], (err, ids) => {
expect(err).to.not.exist()
peer1 = new PeerInfo(ids[0])
const ma1 = '/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/' + ids[0].toB58String()
peer1.multiaddrs.add(ma1)
peer2 = new PeerInfo(ids[1])
const ma2 = '/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/' + ids[1].toB58String()
peer2.multiaddrs.add(ma2)
done()
})
})
it('create two libp2p nodes with those peers', (done) => {
node1 = new Node(peer1, null, { webRTCStar: true })
node2 = new Node(peer2, null, { webRTCStar: true })
done()
})
it('listen on the two libp2p nodes', (done) => {
parallel([
(cb) => node1.start(cb),
(cb) => node2.start(cb)
], done)
})
it('handle a protocol on the first node', () => {
node2.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
})
it('dial from the second node to the first node', (done) => {
node1.dial(peer2, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
const text = 'hello'
const peers1 = node1.peerBook.getAll()
expect(Object.keys(peers1)).to.have.length(1)
const peers2 = node2.peerBook.getAll()
expect(Object.keys(peers2)).to.have.length(1)
pull(
pull.values([Buffer.from(text)]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data[0].toString()).to.equal(text)
done()
})
)
}
})
})
it('node1 hangUp node2', (done) => {
node1.hangUp(peer2, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
const peers = node1.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(node1.swarm.muxedConns)).to.have.length(0)
done()
}
})
})
it('create a third node and check that discovery works', (done) => {
let counter = 0
function check () {
if (++counter === 3) {
expect(Object.keys(node1.swarm.muxedConns).length).to.equal(1)
expect(Object.keys(node2.swarm.muxedConns).length).to.equal(1)
done()
}
}
PeerId.create((err, id3) => {
expect(err).to.not.exist()
const peer3 = new PeerInfo(id3)
const ma3 = '/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/' + id3.toB58String()
peer3.multiaddrs.add(ma3)
node1.on('peer:discovery', (peerInfo) => node1.dial(peerInfo, check))
node2.on('peer:discovery', (peerInfo) => node2.dial(peerInfo, check))
const node3 = new Node(peer3, null, { webRTCStar: true })
node3.start(check)
})
})
})

View File

@ -0,0 +1,201 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const pull = require('pull-stream')
const goodbye = require('pull-goodbye')
const serializer = require('pull-serializer')
const Buffer = require('safe-buffer').Buffer
const Node = require('./browser-bundle')
const rawPeer = require('./peer.json')
describe('libp2p-ipfs-browser (websockets only)', () => {
let peerB
let nodeA
before((done) => {
const ma = '/ip4/127.0.0.1/tcp/9200/ws/ipfs/' + rawPeer.id
PeerId.createFromPrivKey(rawPeer.privKey, (err, id) => {
if (err) {
return done(err)
}
peerB = new PeerInfo(id)
peerB.multiaddrs.add(ma)
done()
})
})
after((done) => nodeA.stop(done))
it('create libp2pNode', (done) => {
PeerInfo.create((err, peerInfo) => {
expect(err).to.not.exist()
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
nodeA = new Node(peerInfo)
done()
})
})
it('create libp2pNode with multiplex only', (done) => {
PeerInfo.create((err, peerInfo) => {
expect(err).to.not.exist()
const b = new Node(peerInfo, null, { muxer: ['multiplex'] })
expect(b.modules.connection.muxer).to.eql([require('libp2p-multiplex')])
done()
})
})
it('start libp2pNode', (done) => {
nodeA.start(done)
})
// General connectivity tests
it('libp2p.dial using Multiaddr nodeA to nodeB', (done) => {
nodeA.dial(peerB.multiaddrs.toArray()[0], (err) => {
expect(err).to.not.exist()
setTimeout(check, 500) // Some time for Identify to finish
function check () {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
done()
}
})
})
it('libp2p.dial using Multiaddr on Protocol nodeA to nodeB', (done) => {
nodeA.dial(peerB.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
pull(
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) => {
nodeA.hangUp(peerB.multiaddrs.toArray()[0], (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
done()
}
})
})
it('libp2p.dial using PeerInfo nodeA to nodeB', (done) => {
nodeA.dial(peerB, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500) // Some time for Identify to finish
function check () {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
done()
}
})
})
it('libp2p.dial using PeerInfo on Protocol nodeA to nodeB', (done) => {
nodeA.dial(peerB, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
const peers = nodeA.peerBook.getAll()
expect(err).to.not.exist()
expect(Object.keys(peers)).to.have.length(1)
pull(
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) => {
nodeA.hangUp(peerB, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
const peers = nodeA.peerBook.getAll()
expect(err).to.not.exist()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
done()
}
})
})
describe('stress', () => {
it('one big write', (done) => {
nodeA.dial(peerB, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
const rawMessage = Buffer.alloc(100000)
rawMessage.fill('a')
const s = serializer(goodbye({
source: pull.values([rawMessage]),
sink: pull.collect((err, results) => {
expect(err).to.not.exist()
expect(results).to.have.length(1)
expect(Buffer.from(results[0])).to.have.length(rawMessage.length)
done()
})
}))
pull(s, conn, s)
})
})
it('many writes', (done) => {
nodeA.dial(peerB, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
const s = serializer(goodbye({
source: pull(
pull.infinite(),
pull.take(1000),
pull.map((val) => Buffer.from(val.toString()))
),
sink: pull.collect((err, result) => {
expect(err).to.not.exist()
expect(result).to.have.length(1000)
done()
})
}))
pull(s, conn, s)
})
})
})
})

View File

@ -1,4 +1,7 @@
'use strict'
const w = require('webrtcsupport')
require('./base')
require('./transports.browser')
require('./browser-bundle/websockets-only')
if (w.support) { require('./browser-bundle/webrtc-star-only') }

View File

@ -1,201 +0,0 @@
/* eslint-env mocha */
'use strict'
const waterfall = require('async/waterfall')
const series = require('async/series')
const parallel = require('async/parallel')
const utils = require('./utils/node')
const Circuit = require('libp2p-circuit')
const multiaddr = require('multiaddr')
const tryEcho = require('./utils/try-echo')
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const sinon = require('sinon')
describe('circuit relay', function () {
let handlerSpies = []
let relayNode1
let relayNode2
let nodeWS1
let nodeWS2
let nodeTCP1
let nodeTCP2
function setupNode (addrs, options, cb) {
if (typeof options === 'function') {
cb = options
options = {}
}
options = options || {}
return utils.createNode(addrs, options, (err, node) => {
expect(err).to.not.exist()
node.handle('/echo/1.0.0', utils.echo)
node.start((err) => {
expect(err).to.not.exist()
handlerSpies.push(sinon.spy(node.switch.transports[Circuit.tag].listeners[0].hopHandler, 'handle'))
cb(node)
})
})
}
before(function (done) {
this.timeout(20000)
waterfall([
// set up passive relay
(cb) => setupNode([
'/ip4/0.0.0.0/tcp/0/ws',
'/ip4/0.0.0.0/tcp/0'
], {
relay: {
enabled: true,
hop: {
enabled: true,
active: false // passive relay
}
}
}, (node) => {
relayNode1 = node
cb()
}),
// setup active relay
(cb) => setupNode([
'/ip4/0.0.0.0/tcp/0/ws',
'/ip4/0.0.0.0/tcp/0'
], {
relay: {
enabled: true,
hop: {
enabled: true,
active: false // passive relay
}
}
}, (node) => {
relayNode2 = node
cb()
}),
// setup node with WS
(cb) => setupNode([
'/ip4/0.0.0.0/tcp/0/ws'
], {
relay: {
enabled: true
}
}, (node) => {
nodeWS1 = node
cb()
}),
// setup node with WS
(cb) => setupNode([
'/ip4/0.0.0.0/tcp/0/ws'
], {
relay: {
enabled: true
}
}, (node) => {
nodeWS2 = node
cb()
}),
// set up node with TCP and listening on relay1
(cb) => setupNode([
'/ip4/0.0.0.0/tcp/0',
`/ipfs/${relayNode1.peerInfo.id.toB58String()}/p2p-circuit`
], {
relay: {
enabled: true
}
}, (node) => {
nodeTCP1 = node
cb()
}),
// set up node with TCP and listening on relay2 over TCP transport
(cb) => setupNode([
'/ip4/0.0.0.0/tcp/0',
`/ip4/0.0.0.0/tcp/0/ipfs/${relayNode2.peerInfo.id.toB58String()}/p2p-circuit`
], {
relay: {
enabled: true
}
}, (node) => {
nodeTCP2 = node
cb()
})
], (err) => {
expect(err).to.not.exist()
series([
(cb) => nodeWS1.dial(relayNode1.peerInfo, cb),
(cb) => nodeWS1.dial(relayNode2.peerInfo, cb),
(cb) => nodeTCP1.dial(relayNode1.peerInfo, cb),
(cb) => nodeTCP2.dial(relayNode2.peerInfo, cb)
], done)
})
})
after((done) => {
parallel([
(cb) => relayNode1.stop(cb),
(cb) => relayNode2.stop(cb),
(cb) => nodeWS1.stop(cb),
(cb) => nodeWS2.stop(cb),
(cb) => nodeTCP1.stop(cb),
(cb) => nodeTCP2.stop(cb)
], done)
})
describe('any relay', function () {
this.timeout(20 * 1000)
it('dial from WS1 to TCP1 over any R', (done) => {
nodeWS1.dialProtocol(nodeTCP1.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
expect(conn).to.exist()
tryEcho(conn, done)
})
})
it('fail to dial - no R from WS2 to TCP1', (done) => {
nodeWS2.dialProtocol(nodeTCP2.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.exist()
expect(conn).to.not.exist()
done()
})
})
})
describe('explicit relay', function () {
this.timeout(20 * 1000)
it('dial from WS1 to TCP1 over R1', (done) => {
nodeWS1.dialProtocol(nodeTCP1.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
expect(conn).to.exist()
tryEcho(conn, () => {
const addr = multiaddr(handlerSpies[0].args[2][0].dstPeer.addrs[0]).toString()
expect(addr).to.equal(`/ipfs/${nodeTCP1.peerInfo.id.toB58String()}`)
done()
})
})
})
it('dial from WS1 to TCP2 over R2', (done) => {
nodeWS1.dialProtocol(nodeTCP2.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
expect(conn).to.exist()
tryEcho(conn, () => {
const addr = multiaddr(handlerSpies[1].args[2][0].dstPeer.addrs[0]).toString()
expect(addr).to.equal(`/ipfs/${nodeTCP2.peerInfo.id.toB58String()}`)
done()
})
})
})
})
})

View File

@ -1,40 +0,0 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const series = require('async/series')
const createNode = require('./utils/node').createNode
describe('multiaddr trim', () => {
it('non used multiaddrs get trimmed', (done) => {
let node
series([
(cb) => createNode([
'/ip4/0.0.0.0/tcp/999/wss/p2p-webrtc-direct',
'/ip4/127.0.0.1/tcp/55555/ws',
'/ip4/0.0.0.0/tcp/0/'
], (err, _node) => {
expect(err).to.not.exist()
node = _node
const multiaddrs = node.peerInfo.multiaddrs.toArray()
// multiaddrs.forEach((ma) => console.log(ma.toString()))
expect(multiaddrs).to.have.length(3)
cb()
}),
(cb) => node.start(cb)
], (err) => {
expect(err).to.not.exist()
const multiaddrs = node.peerInfo.multiaddrs.toArray()
// console.log('--')
// multiaddrs.forEach((ma) => console.log(ma.toString()))
expect(multiaddrs.length).to.at.least(2)
expect(multiaddrs[0].toString()).to.match(/^\/ip4\/127\.0\.0\.1\/tcp\/[0-9]+\/ws\/ipfs\/\w+$/)
node.stop(done)
})
})
})

View File

@ -1,12 +1,10 @@
'use strict'
require('./base')
require('./transports.node')
require('./stream-muxing.node')
require('./peer-discovery.node')
require('./pubsub.node')
require('./peer-routing.node')
require('./content-routing.node')
require('./circuit-relay.node')
require('./multiaddr-trim')
require('./stats')
require('./nodejs-bundle/tcp')
require('./nodejs-bundle/tcp+websockets')
require('./nodejs-bundle/tcp+websockets+webrtc-star')
require('./nodejs-bundle/stream-muxing')
require('./nodejs-bundle/discovery')
require('./nodejs-bundle/peer-routing')
require('./nodejs-bundle/content-routing')

View File

@ -7,10 +7,10 @@ const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
const utils = require('./utils')
const createNode = utils.createNode
const _times = require('lodash.times')
const CID = require('cids')
const utils = require('./utils/node')
const createNode = utils.createNode
describe('.contentRouting', () => {
let nodeA
@ -19,8 +19,7 @@ describe('.contentRouting', () => {
let nodeD
let nodeE
before(function (done) {
this.timeout(5 * 1000)
before((done) => {
const tasks = _times(5, () => (cb) => {
createNode('/ip4/0.0.0.0/tcp/0', {
mdns: false,

View File

@ -6,11 +6,11 @@ chai.use(require('dirty-chai'))
const expect = chai.expect
const signalling = require('libp2p-webrtc-star/src/sig-server')
const parallel = require('async/parallel')
const utils = require('./utils/node')
const utils = require('./utils')
const createNode = utils.createNode
const echo = utils.echo
describe('peer discovery', () => {
describe('discovery', () => {
let nodeA
let nodeB
let port = 24642
@ -60,9 +60,7 @@ describe('peer discovery', () => {
describe('MulticastDNS', () => {
setup({ mdns: true })
it('find a peer', function (done) {
this.timeout(15 * 1000)
it('find a peer', (done) => {
nodeA.once('peer:discovery', (peerInfo) => {
expect(nodeB.peerInfo.id.toB58String())
.to.eql(peerInfo.id.toB58String())
@ -75,8 +73,7 @@ describe('peer discovery', () => {
describe.skip('WebRTCStar', () => {
setup({ webRTCStar: true })
it('find a peer', function (done) {
this.timeout(15 * 1000)
it('find a peer', (done) => {
nodeA.once('peer:discovery', (peerInfo) => {
expect(nodeB.peerInfo.id.toB58String())
.to.eql(peerInfo.id.toB58String())
@ -91,8 +88,7 @@ describe('peer discovery', () => {
mdns: true
})
it('find a peer', function (done) {
this.timeout(15 * 1000)
it('find a peer', (done) => {
nodeA.once('peer:discovery', (peerInfo) => {
expect(nodeB.peerInfo.id.toB58String())
.to.eql(peerInfo.id.toB58String())

View File

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

View File

@ -7,9 +7,9 @@ const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
const _times = require('lodash.times')
const utils = require('./utils/node')
const utils = require('./utils')
const createNode = utils.createNode
const _times = require('lodash.times')
describe('.peerRouting', () => {
let nodeA
@ -18,9 +18,7 @@ describe('.peerRouting', () => {
let nodeD
let nodeE
before(function (done) {
this.timeout(5 * 1000)
before((done) => {
const tasks = _times(5, () => (cb) => {
createNode('/ip4/0.0.0.0/tcp/0', {
mdns: false,

View File

@ -0,0 +1,30 @@
#! /usr/bin/env node
'use strict'
const Node = require('./nodejs-bundle')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const pull = require('pull-stream')
const idBak = require('./test-data/test-id.json')
PeerId.createFromJSON(idBak, (err, peerId) => {
if (err) {
throw err
}
const peerInfo = new PeerInfo(peerId)
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/12345')
const node = new Node(peerInfo)
node.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
node.start((err) => {
if (err) { throw err }
console.log('Spawned node started, env:', process.env.LIBP2P_MUXER)
})
})

View File

@ -6,15 +6,24 @@ chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
const series = require('async/series')
const utils = require('./utils/node')
const tryEcho = require('./utils/try-echo')
const pull = require('pull-stream')
const utils = require('./utils')
const createNode = utils.createNode
const echo = utils.echo
function test (nodeA, nodeB, callback) {
nodeA.dialProtocol(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => {
nodeA.dial(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
tryEcho(conn, callback)
pull(
pull.values([new Buffer('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.be.eql([new Buffer('hey')])
callback()
})
)
})
}
@ -25,10 +34,8 @@ function teardown (nodeA, nodeB, callback) {
], callback)
}
describe('stream muxing', () => {
it('spdy only', function (done) {
this.timeout(5 * 1000)
describe('stream muxing', (done) => {
it('spdy only', (done) => {
let nodeA
let nodeB
@ -60,14 +67,14 @@ describe('stream muxing', () => {
], done)
})
it('mplex only', (done) => {
it('multiplex only', (done) => {
let nodeA
let nodeB
function setup (callback) {
parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['mplex']
muxer: ['multiplex']
}, (err, node) => {
expect(err).to.not.exist()
nodeA = node
@ -75,7 +82,7 @@ describe('stream muxing', () => {
node.start(cb)
}),
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['mplex']
muxer: ['multiplex']
}, (err, node) => {
expect(err).to.not.exist()
nodeB = node
@ -92,16 +99,14 @@ describe('stream muxing', () => {
], done)
})
it('spdy + mplex', function (done) {
this.timeout(5000)
it('spdy + multiplex', (done) => {
let nodeA
let nodeB
function setup (callback) {
parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['spdy', 'mplex']
muxer: ['spdy', 'multiplex']
}, (err, node) => {
expect(err).to.not.exist()
nodeA = node
@ -109,7 +114,7 @@ describe('stream muxing', () => {
node.start(cb)
}),
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['spdy', 'mplex']
muxer: ['spdy', 'multiplex']
}, (err, node) => {
expect(err).to.not.exist()
nodeB = node
@ -126,16 +131,14 @@ describe('stream muxing', () => {
], done)
})
it('spdy + mplex switched order', function (done) {
this.timeout(5 * 1000)
it('spdy + multiplex switched order', (done) => {
let nodeA
let nodeB
function setup (callback) {
parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['spdy', 'mplex']
muxer: ['spdy', 'multiplex']
}, (err, node) => {
expect(err).to.not.exist()
nodeA = node
@ -143,7 +146,7 @@ describe('stream muxing', () => {
node.start(cb)
}),
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['mplex', 'spdy']
muxer: ['multiplex', 'spdy']
}, (err, node) => {
expect(err).to.not.exist()
nodeB = node
@ -160,9 +163,7 @@ describe('stream muxing', () => {
], done)
})
it('one without the other fails to establish a muxedConn', function (done) {
this.timeout(5 * 1000)
it('one without the other fails to establish a muxedConn', (done) => {
let nodeA
let nodeB
@ -177,7 +178,7 @@ describe('stream muxing', () => {
node.start(cb)
}),
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['mplex']
muxer: ['multiplex']
}, (err, node) => {
expect(err).to.not.exist()
nodeB = node
@ -191,12 +192,12 @@ describe('stream muxing', () => {
(cb) => setup(cb),
(cb) => {
// it will just 'warm up a conn'
expect(Object.keys(nodeA.switch.muxers)).to.have.length(1)
expect(Object.keys(nodeB.switch.muxers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxers)).to.have.length(1)
expect(Object.keys(nodeB.swarm.muxers)).to.have.length(1)
nodeA.dial(nodeB.peerInfo, (err) => {
expect(err).to.not.exist()
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
cb()
})
},

View File

@ -0,0 +1,246 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
const signalling = require('libp2p-webrtc-star/src/sig-server')
const WStar = require('libp2p-webrtc-star')
const wrtc = require('wrtc')
const utils = require('./utils')
const createNode = utils.createNode
const echo = utils.echo
describe('TCP + WebSockets + WebRTCStar', () => {
let nodeAll
let nodeTCP
let nodeWS
let nodeWStar
let ss
before((done) => {
parallel([
(cb) => {
signalling.start({ port: 24642 }, (err, server) => {
expect(err).to.not.exist()
ss = server
cb()
})
},
(cb) => {
const wstar = new WStar({wrtc: wrtc})
createNode([
'/ip4/0.0.0.0/tcp/0',
'/ip4/127.0.0.1/tcp/25011/ws',
'/ip4/127.0.0.1/tcp/24642/ws/p2p-webrtc-star'
], {
modules: {
transport: [wstar],
discovery: [wstar.discovery]
}
}, (err, node) => {
expect(err).to.not.exist()
nodeAll = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
},
(cb) => createNode([
'/ip4/0.0.0.0/tcp/0'
], (err, node) => {
expect(err).to.not.exist()
nodeTCP = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => createNode([
'/ip4/127.0.0.1/tcp/25022/ws'
], (err, node) => {
expect(err).to.not.exist()
nodeWS = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => {
const wstar = new WStar({wrtc: wrtc})
createNode([
'/ip4/127.0.0.1/tcp/24642/ws/p2p-webrtc-star'
], {
modules: {
transport: [wstar],
discovery: [wstar.discovery]
}
}, (err, node) => {
expect(err).to.not.exist()
nodeWStar = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
}
], done)
})
after((done) => {
parallel([
(cb) => nodeAll.stop(cb),
(cb) => nodeTCP.stop(cb),
(cb) => nodeWS.stop(cb),
(cb) => nodeWStar.stop(cb),
(cb) => ss.stop(done)
], done)
})
it('nodeAll.dial nodeTCP using PeerInfo', (done) => {
nodeAll.dial(nodeTCP.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeAll.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeTCP.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCP.swarm.muxedConns)).to.have.length(1)
cb()
}
], done)
}
})
})
it('nodeAll.hangUp nodeTCP using PeerInfo', (done) => {
nodeAll.hangUp(nodeTCP.peerInfo, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeAll.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeTCP.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCP.swarm.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
it('nodeAll.dial nodeWS using PeerInfo', (done) => {
nodeAll.dial(nodeWS.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeAll.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(2)
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeWS.swarm.muxedConns)).to.have.length(1)
cb()
}
], done)
}
})
})
it('nodeAll.hangUp nodeWS using PeerInfo', (done) => {
nodeAll.hangUp(nodeWS.peerInfo, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeAll.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(2)
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeWS.swarm.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
it('nodeAll.dial nodeWStar using PeerInfo', (done) => {
nodeAll.dial(nodeWStar.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeAll.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(3)
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeWStar.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(1)
cb()
}
], done)
}
})
})
it('nodeAll.hangUp nodeWStar using PeerInfo', (done) => {
nodeAll.hangUp(nodeWStar.peerInfo, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeAll.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(3)
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeWStar.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeWStar.swarm.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
})

View File

@ -0,0 +1,167 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
// const multiaddr = require('multiaddr')
// const pull = require('pull-stream')
const utils = require('./utils')
const createNode = utils.createNode
const echo = utils.echo
describe('TCP + WebSockets', () => {
let nodeTCP
let nodeTCPnWS
let nodeWS
before((done) => {
parallel([
(cb) => createNode([
'/ip4/0.0.0.0/tcp/0'
], (err, node) => {
expect(err).to.not.exist()
nodeTCP = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => createNode([
'/ip4/0.0.0.0/tcp/0',
'/ip4/127.0.0.1/tcp/25011/ws'
], (err, node) => {
expect(err).to.not.exist()
nodeTCPnWS = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => createNode([
'/ip4/127.0.0.1/tcp/25022/ws'
], (err, node) => {
expect(err).to.not.exist()
nodeWS = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
], done)
})
after((done) => {
parallel([
(cb) => nodeTCP.stop(cb),
(cb) => nodeTCPnWS.stop(cb),
(cb) => nodeWS.stop(cb)
], done)
})
it('nodeTCP.dial nodeTCPnWS using PeerInfo', (done) => {
nodeTCP.dial(nodeTCPnWS.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeTCP.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCP.swarm.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(1)
cb()
}
], done)
}
})
})
it('nodeTCP.hangUp nodeTCPnWS using PeerInfo', (done) => {
nodeTCP.hangUp(nodeTCPnWS.peerInfo, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeTCP.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCP.swarm.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
it('nodeTCPnWS.dial nodeWS using PeerInfo', (done) => {
nodeTCPnWS.dial(nodeWS.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(2)
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeWS.swarm.muxedConns)).to.have.length(1)
cb()
}
], done)
}
})
})
it('nodeTCPnWS.hangUp nodeWS using PeerInfo', (done) => {
nodeTCPnWS.hangUp(nodeWS.peerInfo, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(2)
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeWS.swarm.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
// Until https://github.com/libp2p/js-libp2p/issues/46 is resolved
// Everynode will be able to dial in WebSockets
it.skip('nodeTCP.dial nodeWS using PeerInfo is unsuccesful', (done) => {
nodeTCP.dial(nodeWS.peerInfo, (err) => {
expect(err).to.exist()
done()
})
})
})

234
test/nodejs-bundle/tcp.js Normal file
View File

@ -0,0 +1,234 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
const series = require('async/series')
const pull = require('pull-stream')
const utils = require('./utils')
const createNode = utils.createNode
const echo = utils.echo
describe('TCP only', () => {
let nodeA
let nodeB
before((done) => {
parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
expect(err).to.not.exist()
nodeA = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
expect(err).to.not.exist()
nodeB = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
], done)
})
after((done) => {
parallel([
(cb) => nodeA.stop(cb),
(cb) => nodeB.stop(cb)
], done)
})
it('nodeA.dial nodeB using PeerInfo without proto (warmup)', (done) => {
nodeA.dial(nodeB.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(err).to.not.exist()
expect(Object.keys(peers)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(err).to.not.exist()
expect(Object.keys(peers)).to.have.length(1)
cb()
}
], done)
}
})
})
it('nodeA.dial nodeB using PeerInfo', (done) => {
nodeA.dial(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
pull(
pull.values([new Buffer('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.be.eql([new Buffer('hey')])
done()
})
)
})
})
it('nodeA.hangUp nodeB using PeerInfo (first)', (done) => {
nodeA.hangUp(nodeB.peerInfo, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeB.swarm.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
it('nodeA.dial nodeB using multiaddr', (done) => {
nodeA.dial(nodeB.peerInfo.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => {
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
expect(err).to.not.exist()
series([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1)
cb()
}
], () => {
pull(
pull.values([new Buffer('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.be.eql([new Buffer('hey')])
done()
})
)
})
}
})
})
it('nodeA.hangUp nodeB using multiaddr (second)', (done) => {
nodeA.hangUp(nodeB.peerInfo.multiaddrs.toArray()[0], (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeB.swarm.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
it('nodeA.dial nodeB using PeerId', (done) => {
nodeA.dial(nodeB.peerInfo.id, '/echo/1.0.0', (err, conn) => {
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
expect(err).to.not.exist()
series([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1)
cb()
}
], () => {
pull(
pull.values([new Buffer('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.be.eql([new Buffer('hey')])
done()
})
)
})
}
})
})
it('nodeA.hangUp nodeB using PeerId (third)', (done) => {
nodeA.hangUp(nodeB.peerInfo.multiaddrs.toArray()[0], (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeB.swarm.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
})

View File

@ -7,8 +7,9 @@ const expect = chai.expect
const multiaddr = require('multiaddr')
const spawn = require('child_process').spawn
const path = require('path')
// const map = require('async/map')
const pull = require('pull-stream')
const utils = require('./utils/node')
const utils = require('./utils')
const createNode = utils.createNode
const echo = utils.echo
@ -56,11 +57,11 @@ describe('Turbolence tests', () => {
expect(Object.keys(peers)).to.have.length(1)
pull(
pull.values([Buffer.from('hey')]),
pull.values([new Buffer('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.eql([Buffer.from('hey')])
expect(data).to.eql([new Buffer('hey')])
done()
})
)
@ -76,7 +77,7 @@ describe('Turbolence tests', () => {
function check () {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
done()
}
})

View File

@ -3,7 +3,7 @@
const chai = require('chai')
chai.use(require('dirty-chai'))
const Node = require('./bundle.node')
const Node = require('./nodejs-bundle')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const waterfall = require('async/waterfall')
@ -15,14 +15,12 @@ function createNode (multiaddrs, options, callback) {
options = {}
}
options = options || {}
if (!Array.isArray(multiaddrs)) {
multiaddrs = [multiaddrs]
}
waterfall([
(cb) => PeerId.create({ bits: 512 }, cb),
(cb) => PeerId.create({ bits: 1024 }, cb),
(peerId, cb) => PeerInfo.create(peerId, cb),
(peerInfo, cb) => {
multiaddrs.map((ma) => peerInfo.multiaddrs.add(ma))

View File

@ -1,87 +0,0 @@
/* 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()
}
)
})
})
})
})

View File

@ -1,24 +0,0 @@
/* 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

@ -1,391 +0,0 @@
/* eslint max-nested-callbacks: ["error", 8] */
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const pull = require('pull-stream')
const parallel = require('async/parallel')
const goodbye = require('pull-goodbye')
const serializer = require('pull-serializer')
const w = require('webrtcsupport')
const tryEcho = require('./utils/try-echo')
const Node = require('./utils/bundle.browser')
const rawPeer = require('./fixtures/test-peer.json')
describe('transports', () => {
describe('websockets', () => {
let peerB
let nodeA
before((done) => {
const ma = '/ip4/127.0.0.1/tcp/9200/ws/ipfs/' + rawPeer.id
PeerId.createFromPrivKey(rawPeer.privKey, (err, id) => {
if (err) {
return done(err)
}
peerB = new PeerInfo(id)
peerB.multiaddrs.add(ma)
done()
})
})
after((done) => nodeA.stop(done))
it('create libp2pNode', (done) => {
PeerInfo.create((err, peerInfo) => {
expect(err).to.not.exist()
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
nodeA = new Node(peerInfo)
done()
})
})
it('create libp2pNode with mplex only', (done) => {
PeerInfo.create((err, peerInfo) => {
expect(err).to.not.exist()
const b = new Node(peerInfo, null, { muxer: ['mplex'] })
expect(b.modules.connection.muxer).to.eql([require('libp2p-mplex')])
done()
})
})
it('start libp2pNode', (done) => {
nodeA.start(done)
})
// General connectivity tests
it('.dial using Multiaddr', (done) => {
nodeA.dial(peerB.multiaddrs.toArray()[0], (err) => {
expect(err).to.not.exist()
setTimeout(check, 500) // Some time for Identify to finish
function check () {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
done()
}
})
})
it('.dialProtocol using Multiaddr', (done) => {
nodeA.dialProtocol(peerB.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
tryEcho(conn, done)
})
})
it('.hangUp using Multiaddr', (done) => {
nodeA.hangUp(peerB.multiaddrs.toArray()[0], (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
done()
}
})
})
it('.dial using PeerInfo', (done) => {
nodeA.dial(peerB, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500) // Some time for Identify to finish
function check () {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
done()
}
})
})
it('.dialProtocol using PeerInfo', (done) => {
nodeA.dialProtocol(peerB, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
const peers = nodeA.peerBook.getAll()
expect(err).to.not.exist()
expect(Object.keys(peers)).to.have.length(1)
tryEcho(conn, done)
})
})
it('.hangUp using PeerInfo', (done) => {
nodeA.hangUp(peerB, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
const peers = nodeA.peerBook.getAll()
expect(err).to.not.exist()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
done()
}
})
})
describe('stress', () => {
it('one big write', (done) => {
nodeA.dialProtocol(peerB, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
const rawMessage = Buffer.alloc(100000)
rawMessage.fill('a')
const s = serializer(goodbye({
source: pull.values([rawMessage]),
sink: pull.collect((err, results) => {
expect(err).to.not.exist()
expect(results).to.have.length(1)
expect(Buffer.from(results[0])).to.have.length(rawMessage.length)
done()
})
}))
pull(s, conn, s)
})
})
it('many writes', (done) => {
nodeA.dialProtocol(peerB, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
const s = serializer(goodbye({
source: pull(
pull.infinite(),
pull.take(1000),
pull.map((val) => Buffer.from(val.toString()))
),
sink: pull.collect((err, result) => {
expect(err).to.not.exist()
expect(result).to.have.length(1000)
done()
})
}))
pull(s, conn, s)
})
})
})
})
describe('webrtc-star', () => {
if (!w.support) { return console.log('NO WEBRTC SUPPORT') }
let peer1
let peer2
let node1
let node2
it('create two peerInfo with webrtc-star addrs', (done) => {
parallel([
(cb) => PeerId.create({ bits: 1024 }, cb),
(cb) => PeerId.create({ bits: 1024 }, cb)
], (err, ids) => {
expect(err).to.not.exist()
peer1 = new PeerInfo(ids[0])
const ma1 = '/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/' + ids[0].toB58String()
peer1.multiaddrs.add(ma1)
peer2 = new PeerInfo(ids[1])
const ma2 = '/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/' + ids[1].toB58String()
peer2.multiaddrs.add(ma2)
done()
})
})
it('create two libp2p nodes with those peers', (done) => {
node1 = new Node(peer1, null, { webRTCStar: true })
node2 = new Node(peer2, null, { webRTCStar: true })
done()
})
it('start two libp2p nodes', (done) => {
parallel([
(cb) => node1.start(cb),
(cb) => node2.start(cb)
], done)
})
it('.handle echo on first node', () => {
node2.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
})
it('.dialProtocol from the second node to the first node', (done) => {
node1.dialProtocol(peer2, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
const peers1 = node1.peerBook.getAll()
expect(Object.keys(peers1)).to.have.length(1)
const peers2 = node2.peerBook.getAll()
expect(Object.keys(peers2)).to.have.length(1)
tryEcho(conn, done)
}
})
})
it('node1 hangUp node2', (done) => {
node1.hangUp(peer2, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
const peers = node1.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(node1.switch.muxedConns)).to.have.length(0)
done()
}
})
})
it('create a third node and check that discovery works', (done) => {
let counter = 0
function check () {
if (++counter === 3) {
expect(Object.keys(node1.switch.muxedConns).length).to.equal(1)
expect(Object.keys(node2.switch.muxedConns).length).to.equal(1)
done()
}
}
PeerId.create((err, id3) => {
expect(err).to.not.exist()
const peer3 = new PeerInfo(id3)
const ma3 = '/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/' + id3.toB58String()
peer3.multiaddrs.add(ma3)
node1.on('peer:discovery', (peerInfo) => node1.dial(peerInfo, check))
node2.on('peer:discovery', (peerInfo) => node2.dial(peerInfo, check))
const node3 = new Node(peer3, null, { webRTCStar: true })
node3.start(check)
})
})
})
describe('websocket-star', () => {
let peer1
let peer2
let node1
let node2
it('create two peerInfo with websocket-star addrs', (done) => {
parallel([
(cb) => PeerId.create({ bits: 1024 }, cb),
(cb) => PeerId.create({ bits: 1024 }, cb)
], (err, ids) => {
expect(err).to.not.exist()
peer1 = new PeerInfo(ids[0])
const ma1 = '/ip4/127.0.0.1/tcp/14444/ws/p2p-websocket-star/'
peer1.multiaddrs.add(ma1)
peer2 = new PeerInfo(ids[1])
const ma2 = '/ip4/127.0.0.1/tcp/14444/ws/p2p-websocket-star/'
peer2.multiaddrs.add(ma2)
done()
})
})
it('create two libp2p nodes with those peers', (done) => {
node1 = new Node(peer1, null, { wsStar: true })
node2 = new Node(peer2, null, { wsStar: true })
done()
})
it('listen on the two libp2p nodes', (done) => {
parallel([
(cb) => node1.start(cb),
(cb) => node2.start(cb)
], done)
})
it('handle a protocol on the first node', () => {
node2.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
})
it('.dialProtocol from the second node to the first node', (done) => {
node1.dialProtocol(peer2, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
const peers1 = node1.peerBook.getAll()
expect(Object.keys(peers1)).to.have.length(1)
const peers2 = node2.peerBook.getAll()
expect(Object.keys(peers2)).to.have.length(1)
tryEcho(conn, done)
}
})
})
it('node1 hangUp node2', (done) => {
node1.hangUp(peer2, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
const peers = node1.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(node1.switch.muxedConns)).to.have.length(0)
done()
}
})
})
it('create a third node and check that discovery works', (done) => {
let counter = 0
function check () {
if (++counter === 3) {
expect(Object.keys(node1.switch.muxedConns).length).to.equal(1)
expect(Object.keys(node2.switch.muxedConns).length).to.equal(1)
done()
}
}
PeerId.create((err, id3) => {
expect(err).to.not.exist()
const peer3 = new PeerInfo(id3)
const ma3 = '/ip4/127.0.0.1/tcp/14444/ws/p2p-websocket-star/ipfs/' + id3.toB58String()
peer3.multiaddrs.add(ma3)
node1.on('peer:discovery', (peerInfo) => node1.dial(peerInfo, check))
node2.on('peer:discovery', (peerInfo) => node2.dial(peerInfo, check))
const node3 = new Node(peer3, null, { wsStar: true })
node3.start(check)
})
})
})
})

View File

@ -1,652 +0,0 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
const series = require('async/series')
const utils = require('./utils/node.js')
const signalling = require('libp2p-webrtc-star/src/sig-server')
const rendezvous = require('libp2p-websocket-star-rendezvous')
const WSStar = require('libp2p-websocket-star')
const WRTCStar = require('libp2p-webrtc-star')
const wrtc = require('wrtc')
const tryEcho = require('./utils/try-echo')
const createNode = utils.createNode
const echo = utils.echo
describe('transports', () => {
describe('TCP only', () => {
let nodeA
let nodeB
before((done) => {
parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
expect(err).to.not.exist()
nodeA = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
expect(err).to.not.exist()
nodeB = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
], done)
})
after((done) => {
parallel([
(cb) => nodeA.stop(cb),
(cb) => nodeB.stop(cb)
], done)
})
it('nodeA.dial nodeB using PeerInfo without proto (warmup)', (done) => {
nodeA.dial(nodeB.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(err).to.not.exist()
expect(Object.keys(peers)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(err).to.not.exist()
expect(Object.keys(peers)).to.have.length(1)
cb()
}
], done)
}
})
})
it('nodeA.dial nodeB using PeerInfo', (done) => {
nodeA.dialProtocol(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist()
tryEcho(conn, done)
})
})
it('nodeA.hangUp nodeB using PeerInfo (first)', (done) => {
nodeA.hangUp(nodeB.peerInfo, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeB.switch.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
it('nodeA.dialProtocol nodeB using multiaddr', (done) => {
nodeA.dialProtocol(nodeB.peerInfo.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => {
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
expect(err).to.not.exist()
series([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
cb()
}
], () => tryEcho(conn, done))
}
})
})
it('nodeA.hangUp nodeB using multiaddr (second)', (done) => {
nodeA.hangUp(nodeB.peerInfo.multiaddrs.toArray()[0], (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeB.switch.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
it('nodeA.dialProtocol nodeB using PeerId', (done) => {
nodeA.dialProtocol(nodeB.peerInfo.id, '/echo/1.0.0', (err, conn) => {
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
expect(err).to.not.exist()
series([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
cb()
}
], () => tryEcho(conn, done))
}
})
})
it('nodeA.hangUp nodeB using PeerId (third)', (done) => {
nodeA.hangUp(nodeB.peerInfo.multiaddrs.toArray()[0], (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeA.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeB.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeB.switch.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
})
describe('TCP + WebSockets', () => {
let nodeTCP
let nodeTCPnWS
let nodeWS
before((done) => {
parallel([
(cb) => createNode([
'/ip4/0.0.0.0/tcp/0'
], (err, node) => {
expect(err).to.not.exist()
nodeTCP = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => createNode([
'/ip4/0.0.0.0/tcp/0',
'/ip4/127.0.0.1/tcp/25011/ws'
], (err, node) => {
expect(err).to.not.exist()
nodeTCPnWS = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => createNode([
'/ip4/127.0.0.1/tcp/25022/ws'
], (err, node) => {
expect(err).to.not.exist()
nodeWS = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
], done)
})
after((done) => {
parallel([
(cb) => nodeTCP.stop(cb),
(cb) => nodeTCPnWS.stop(cb),
(cb) => nodeWS.stop(cb)
], done)
})
it('nodeTCP.dial nodeTCPnWS using PeerInfo', (done) => {
nodeTCP.dial(nodeTCPnWS.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeTCP.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCP.switch.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(1)
cb()
}
], done)
}
})
})
it('nodeTCP.hangUp nodeTCPnWS using PeerInfo', (done) => {
nodeTCP.hangUp(nodeTCPnWS.peerInfo, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeTCP.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCP.switch.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
it('nodeTCPnWS.dial nodeWS using PeerInfo', (done) => {
nodeTCPnWS.dial(nodeWS.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(2)
expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(1)
cb()
},
(cb) => {
const peers = nodeWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeWS.switch.muxedConns)).to.have.length(1)
cb()
}
], done)
}
})
})
it('nodeTCPnWS.hangUp nodeWS using PeerInfo', (done) => {
nodeTCPnWS.hangUp(nodeWS.peerInfo, (err) => {
expect(err).to.not.exist()
setTimeout(check, 500)
function check () {
parallel([
(cb) => {
const peers = nodeTCPnWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(2)
expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(0)
cb()
},
(cb) => {
const peers = nodeWS.peerBook.getAll()
expect(Object.keys(peers)).to.have.length(1)
expect(Object.keys(nodeWS.switch.muxedConns)).to.have.length(0)
cb()
}
], done)
}
})
})
// Until https://github.com/libp2p/js-libp2p/issues/46 is resolved
// Everynode will be able to dial in WebSockets
it.skip('nodeTCP.dial nodeWS using PeerInfo is unsuccesful', (done) => {
nodeTCP.dial(nodeWS.peerInfo, (err) => {
expect(err).to.exist()
done()
})
})
})
describe('TCP + WebSockets + WebRTCStar', () => {
let nodeAll
let nodeTCP
let nodeWS
let nodeWStar
let ss
before(function (done) {
this.timeout(5 * 1000)
parallel([
(cb) => {
signalling.start({ port: 24642 }, (err, server) => {
expect(err).to.not.exist()
ss = server
cb()
})
},
(cb) => {
const wstar = new WRTCStar({wrtc: wrtc})
createNode([
'/ip4/0.0.0.0/tcp/0',
'/ip4/127.0.0.1/tcp/25011/ws',
'/ip4/127.0.0.1/tcp/24642/ws/p2p-webrtc-star'
], {
modules: {
transport: [wstar],
discovery: [wstar.discovery]
}
}, (err, node) => {
expect(err).to.not.exist()
nodeAll = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
},
(cb) => createNode([
'/ip4/0.0.0.0/tcp/0'
], (err, node) => {
expect(err).to.not.exist()
nodeTCP = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => createNode([
'/ip4/127.0.0.1/tcp/25022/ws'
], (err, node) => {
expect(err).to.not.exist()
nodeWS = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => {
const wstar = new WRTCStar({wrtc: wrtc})
createNode([
'/ip4/127.0.0.1/tcp/24642/ws/p2p-webrtc-star'
], {
modules: {
transport: [wstar],
discovery: [wstar.discovery]
}
}, (err, node) => {
expect(err).to.not.exist()
nodeWStar = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
}
], done)
})
after(function (done) {
this.timeout(10 * 1000)
parallel([
(cb) => nodeAll.stop(cb),
(cb) => nodeTCP.stop(cb),
(cb) => nodeWS.stop(cb),
(cb) => nodeWStar.stop(cb),
(cb) => ss.stop(cb)
], done)
})
function check (otherNode, muxed, peers, callback) {
let i = 1;
[nodeAll, otherNode].forEach((node) => {
expect(Object.keys(node.peerBook.getAll())).to.have.length(i-- ? peers : 1)
expect(Object.keys(node.switch.muxedConns)).to.have.length(muxed)
})
callback()
}
it('nodeAll.dial nodeTCP using PeerInfo', (done) => {
nodeAll.dial(nodeTCP.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeTCP, 1, 1, done), 500)
})
})
it('nodeAll.hangUp nodeTCP using PeerInfo', (done) => {
nodeAll.hangUp(nodeTCP.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeTCP, 0, 1, done), 500)
})
})
it('nodeAll.dial nodeWS using PeerInfo', (done) => {
nodeAll.dial(nodeWS.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeWS, 1, 2, done), 500)
})
})
it('nodeAll.hangUp nodeWS using PeerInfo', (done) => {
nodeAll.hangUp(nodeWS.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeWS, 0, 2, done), 500)
})
})
it('nodeAll.dial nodeWStar using PeerInfo', function (done) {
this.timeout(40 * 1000)
nodeAll.dial(nodeWStar.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeWStar, 1, 3, done), 500)
})
})
it('nodeAll.hangUp nodeWStar using PeerInfo', (done) => {
nodeAll.hangUp(nodeWStar.peerInfo, (err) => {
expect(err).to.not.exist()
setTimeout(() => check(nodeWStar, 0, 3, done), 500)
})
})
})
describe('TCP + WebSockets + WebSocketStar', () => {
let nodeAll
let nodeTCP
let nodeWS
let nodeWStar
let ss
before((done) => {
parallel([
(cb) => {
rendezvous.start({ port: 24642 }, (err, server) => {
expect(err).to.not.exist()
ss = server
cb()
})
},
(cb) => {
const wstar = new WSStar()
createNode([
'/ip4/0.0.0.0/tcp/0',
'/ip4/127.0.0.1/tcp/25011/ws',
'/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star'
], {
modules: {
transport: [wstar],
discovery: [wstar.discovery]
}
}, (err, node) => {
expect(err).to.not.exist()
nodeAll = node
wstar.lazySetId(node.peerInfo.id)
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
},
(cb) => createNode([
'/ip4/0.0.0.0/tcp/0'
], (err, node) => {
expect(err).to.not.exist()
nodeTCP = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => createNode([
'/ip4/127.0.0.1/tcp/25022/ws'
], (err, node) => {
expect(err).to.not.exist()
nodeWS = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
}),
(cb) => {
const wstar = new WSStar({})
createNode([
'/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star'
], {
modules: {
transport: [wstar],
discovery: [wstar.discovery]
}
}, (err, node) => {
expect(err).to.not.exist()
nodeWStar = node
wstar.lazySetId(node.peerInfo.id)
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
}
], done)
})
after((done) => {
parallel([
(cb) => nodeAll.stop(cb),
(cb) => nodeTCP.stop(cb),
(cb) => nodeWS.stop(cb),
(cb) => nodeWStar.stop(cb),
(cb) => ss.stop(cb)
], done)
})
function check (otherNode, muxed, peers, done) {
let i = 1;
[nodeAll, otherNode].forEach((node) => {
expect(Object.keys(node.peerBook.getAll())).to.have.length(i-- ? peers : 1)
expect(Object.keys(node.switch.muxedConns)).to.have.length(muxed)
})
done()
}
it('nodeAll.dial nodeTCP using PeerInfo', (done) => {
nodeAll.dial(nodeTCP.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeTCP, 1, 1, done), 500)
})
})
it('nodeAll.hangUp nodeTCP using PeerInfo', (done) => {
nodeAll.hangUp(nodeTCP.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeTCP, 0, 1, done), 500)
})
})
it('nodeAll.dial nodeWS using PeerInfo', (done) => {
nodeAll.dial(nodeWS.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeWS, 1, 2, done), 500)
})
})
it('nodeAll.hangUp nodeWS using PeerInfo', (done) => {
nodeAll.hangUp(nodeWS.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeWS, 0, 2, done), 500)
})
})
it('nodeAll.dial nodeWStar using PeerInfo', (done) => {
nodeAll.dial(nodeWStar.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeWStar, 1, 3, done), 500)
})
})
it('nodeAll.hangUp nodeWStar using PeerInfo', (done) => {
nodeAll.hangUp(nodeWStar.peerInfo, (err) => {
expect(err).to.not.exist()
// Some time for Identify to finish
setTimeout(() => check(nodeWStar, 0, 3, done), 500)
})
})
})
})

View File

@ -1,21 +0,0 @@
'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()
})
)
}