Compare commits

...

67 Commits

Author SHA1 Message Date
10a8ec3f31 chore: release version v0.17.0 2018-02-16 18:26:06 +00:00
41d202c4ba chore: update contributors 2018-02-16 18:26:06 +00:00
a5fd05875c chore: make tests faster 2018-02-16 19:23:35 +01:00
379febb610 chore: fix linting and move linting to circle 2018-02-16 19:23:35 +01:00
99873e877b docs: update pubsub example 2018-02-16 19:23:35 +01:00
4e01c094bc test: test pubsub on and off 2018-02-16 19:23:35 +01:00
8fcafe2d90 docs: update pubsub example 2018-02-16 19:23:35 +01:00
947eaf166b fix: use correct reference to floodSub 2018-02-16 19:23:35 +01:00
1ebf725ac4 docs: add docs 2018-02-16 19:23:35 +01:00
0c543b7180 feat: add pubsub to libp2p 2018-02-16 19:23:35 +01:00
beeb36c10c chore: release version v0.16.5 2018-02-14 10:55:16 +01:00
0acc7e5d72 chore: update contributors 2018-02-14 10:55:16 +01:00
9fd94b98a1 chore: update deps 2018-02-14 10:48:21 +01:00
5c3037037a chore: release version v0.16.4 2018-02-09 12:45:17 +00:00
362217c8da chore: update contributors 2018-02-09 12:45:17 +00:00
7733ba5cd7 chore: release version v0.16.3 2018-02-08 08:11:24 +00:00
52bf826ec6 chore: update contributors 2018-02-08 08:11:24 +00:00
10619afbe6 chore: release version v0.16.2 2018-02-07 09:50:30 +00:00
3debabdd26 chore: update contributors 2018-02-07 09:50:30 +00:00
56e095983a chore: update npm ignore 2018-02-07 09:50:01 +00:00
ebdb696742 chore: release version v0.16.1 2018-02-07 09:45:01 +00:00
721e6ee9ce chore: update contributors 2018-02-07 09:45:01 +00:00
98f2903088 chore: release version v0.16.0 2018-02-07 08:39:08 +00:00
3dda282dfd chore: update contributors 2018-02-07 08:39:08 +00:00
03faf69212 test: fix linting 2018-02-07 08:37:03 +00:00
0062a4b5eb docs: update examples 2018-02-07 08:37:03 +00:00
f7f85dce0a test: update tests to new API 2018-02-07 08:37:03 +00:00
59df82a675 docs: dialProtocol 2018-02-07 08:37:03 +00:00
6651401f0b feat: dialProtocol and small refactor 2018-02-07 08:37:03 +00:00
cd43863db6 chore: use pre-push 2018-02-07 07:31:10 +00:00
23e8293b75 feat: use libp2p-switch 2018-02-07 07:31:10 +00:00
68c170a40d docs: Add ws-star and ws-star-rendezvous (#158) 2018-02-07 07:07:53 +00:00
bd8a35aaf9 feat: add explicit error for case peer id not included in multiaddr (#155) 2018-02-05 12:36:20 +01:00
248d86d050 fix typo (#152) 2018-01-27 23:26:57 -08:00
8225b11082 fix typo (#153) 2018-01-27 23:26:52 -08:00
1355af2b51 docs: fix typos (#154) 2018-01-27 23:26:46 -08:00
a85f041843 chore: release version v0.15.2 2018-01-27 18:51:45 -08:00
2c0cda2a7c chore: update contributors 2018-01-27 18:51:45 -08:00
b4ba267589 chore: update deps 2018-01-27 18:48:44 -08:00
4c81f39ebe chore: release version v0.15.1 2018-01-16 06:16:15 -08:00
76922383ab chore: update contributors 2018-01-16 06:16:15 -08:00
3fc57ff397 chore: bump timeout on after 2018-01-16 06:13:42 -08:00
13b36dcaa6 chore: update deps 2018-01-16 06:03:04 -08:00
61bebd10fc fix: typo in DHT setup (#151)
I think there was a typo that would have ignored passed options and fallback to defaults for DHT datastore.
2018-01-16 05:58:12 -08:00
97cde1ccb4 test: Various pdd fixes (#150)
* fix(pdd): url for interop pkg was pointing to non-existing branch

* fix(pdd): case-sensitive names

peer-B.json does not _actually_ exist

* fix(pdd): story 2 peer b
2018-01-10 14:53:24 +00:00
07b0cdc30e docs: note the Connection type on .handle and .dial docs (#149) 2018-01-07 18:47:02 +00:00
73b6d60e32 docs: update to new URL format on the browser example 2018-01-07 17:17:22 +00:00
808f7495a9 chore: release version v0.15.0 2018-01-07 17:09:57 +00:00
ae21a6facf chore: update contributors 2018-01-07 17:09:56 +00:00
3aba3fd176 chore: update deps (#148) 2018-01-07 17:00:24 +00:00
dc2da39a19 docs: tcp/443 on webrtc-star example. (#147)
according to https://github.com/libp2p/js-libp2p-webrtc-star/issues/134 and my own fiddling with this example.
2018-01-06 14:28:20 +00:00
f8b441fff5 docs: Update README.md (#143)
added missing backtick
2018-01-02 07:18:41 +00:00
190ad54f9e PDD Compliance Tests (#137)
* transport story 1 done

* c

* transport series 2

* transports story 3

* the ipfs-bundle story 1
2017-12-18 10:23:34 +00:00
582f8bed2e docs: fix links on examples peer and content routing (#141) 2017-12-18 09:53:30 +00:00
59de0da19c chore: release version v0.14.3 2017-12-15 08:25:08 +00:00
0caf600c9a chore: update contributors 2017-12-15 08:25:08 +00:00
a4943b4509 chore: update npm ignore 2017-12-15 08:24:49 +00:00
c128873a07 chore: release version v0.14.2 2017-12-15 07:15:05 +00:00
5e2b6df04a chore: update contributors 2017-12-15 07:15:05 +00:00
8d2d8c98a0 chore: release version v0.14.1 2017-12-15 07:10:42 +00:00
30bf5bb161 chore: update contributors 2017-12-15 07:10:42 +00:00
c88eaf416c fix: prevent "The libp2p node is not started yet" when stopping (#138) 2017-12-15 07:08:44 +00:00
c7f20383d9 chore: release version v0.14.0 2017-12-14 07:39:37 +00:00
a86a95c19f chore: update contributors 2017-12-14 07:39:37 +00:00
1b7360fcfa fix: remove innactive multiaddrs (#131) 2017-12-14 07:27:13 +00:00
67ca37c356 chore: updating CI files (#132)
* Updating CI files

This commit updates all CI scripts to the latest version

* chore: update deps

* bump timout

* fix circle
2017-12-14 07:14:36 +00:00
0870068ebc docs: fix typo (#136) 2017-12-11 12:16:05 +00:00
63 changed files with 1311 additions and 417 deletions

View File

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

View File

@ -1,28 +1,19 @@
# 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 sudo: false
language: node_js language: node_js
matrix: matrix:
include: include:
- node_js: 6 - node_js: 'stable'
env: CXX=g++-4.8 env: CXX=g++-4.8
- node_js: 8
env: CXX=g++-4.8
# - node_js: stable
# env: CXX=g++-4.8
script: script:
- npm run lint
- npm run test - npm run test
- npm run coverage
- make test
before_script: before_script:
- export DISPLAY=:99.0 - export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start - sh -e /etc/init.d/xvfb start
after_success:
- npm run coverage-publish
addons: addons:
firefox: 'latest' firefox: 'latest'
apt: apt:

View File

@ -1,3 +1,105 @@
<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> <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) ## [0.13.3](https://github.com/libp2p/js-libp2p/compare/v0.13.2...v0.13.3) (2017-12-01)

View File

@ -48,7 +48,7 @@ We've come a long way, but this project is still in Alpha, lots of development i
## Background ## 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, 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. 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.
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 writing better documentation, blog posts, tutorials and a formal specification. Today you can find:
@ -158,16 +158,26 @@ class Node extends libp2p {
`callback` is a function with the following `function (err) {}` signature, where `err` is an Error in case stopping the node fails. `callback` is a function with the following `function (err) {}` signature, where `err` is an Error in case stopping the node fails.
#### `libp2p.dial(peer [, protocol, callback])` #### `libp2p.dial(peer, callback)`
> Dials to another peer in the network. > Dials to another peer in the network, establishes the connection.
- `peer`: can be an instance of [PeerInfo][], [PeerId][] or [multiaddr][] - `peer`: can be an instance of [PeerInfo][], [PeerId][], [multiaddr][], or a multiaddr string
- `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. `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.dialProtocol(peer, protocol, callback)`
> Dials to another peer in the network and selects a protocol to talk with that peer.
- `peer`: can be an instance of [PeerInfo][], [PeerId][], [multiaddr][], or a multiaddr string
- `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
- `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)`
> Closes an open connection with a peer, graciously. > Closes an open connection with a peer, graciously.
@ -196,7 +206,7 @@ class Node extends libp2p {
> Handle new protocol > Handle new protocol
- `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0') - `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
- `handlerFunc`: Function with signature `function (protocol, conn) {}` - `handlerFunc`: Function with signature `function (protocol, conn) {}` where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object
- `matchFunc`: Function for matching on protocol (exact matching, semver, etc). Default to exact match. - `matchFunc`: Function for matching on protocol (exact matching, semver, etc). Default to exact match.
#### `libp2p.unhandle(protocol)` #### `libp2p.unhandle(protocol)`
@ -239,9 +249,13 @@ class Node extends libp2p {
> PeerInfo instance of the node > PeerInfo instance of the node
#### `libp2p.pubsub`
> Same API as IPFS PubSub, defined in the [CORE API Spec](https://github.com/ipfs/interface-ipfs-core/blob/master/SPEC/PUBSUB.md). Just replace `ipfs` by `libp2p` and you are golden.
--------------------- ---------------------
`DHT methods exposed` `DHT methods also exposed for the time being`
#### `libp2p.dht.put(key, value, callback)` #### `libp2p.dht.put(key, value, callback)`
@ -310,6 +324,8 @@ List of packages currently in existence for libp2p
| [`libp2p-utp`](//github.com/libp2p/js-libp2p-utp) | [![npm](https://img.shields.io/npm/v/libp2p-utp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utp/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-utp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-utp/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp?type=dev) | | [`libp2p-utp`](//github.com/libp2p/js-libp2p-utp) | [![npm](https://img.shields.io/npm/v/libp2p-utp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utp/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-utp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-utp/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp?type=dev) |
| [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/libp2p-websockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-websockets/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets?type=dev) | | [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/libp2p-websockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-websockets/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets?type=dev) |
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-webrtc-star/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star?type=dev) | | [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-webrtc-star/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star?type=dev) |
| [`libp2p-websocket-star`](//github.com/libp2p/js-libp2p-websocket-star) | [![npm](https://img.shields.io/npm/v/libp2p-websocket-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websocket-star/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websocket-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-websocket-star/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star?type=dev) |
| [`libp2p-websocket-star-rendezvous`](//github.com/libp2p/js-libp2p-websocket-star-rendezvous) | [![npm](https://img.shields.io/npm/v/libp2p-websocket-star-rendezvous.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websocket-star-rendezvous/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websocket-star-rendezvous.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star-rendezvous) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-websocket-star-rendezvous/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star-rendezvous?type=dev) |
| **Connection Upgrades** | | **Connection Upgrades** |
| [`interface-connection`](//github.com/libp2p/interface-connection) | [![npm](https://img.shields.io/npm/v/interface-connection.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/interface-connection/releases) | [![Dependency Status](https://david-dm.org/libp2p/interface-connection.svg?style=flat-square)](https://david-dm.org/libp2p/interface-connection) | [![devDependency Status](https://david-dm.org/libp2p/interface-connection/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/interface-connection?type=dev) | | [`interface-connection`](//github.com/libp2p/interface-connection) | [![npm](https://img.shields.io/npm/v/interface-connection.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/interface-connection/releases) | [![Dependency Status](https://david-dm.org/libp2p/interface-connection.svg?style=flat-square)](https://david-dm.org/libp2p/interface-connection) | [![devDependency Status](https://david-dm.org/libp2p/interface-connection/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/interface-connection?type=dev) |
| **Stream Muxers** | | **Stream Muxers** |

29
appveyor.yml Normal file
View File

@ -0,0 +1,29 @@
# 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 Normal file
View File

@ -0,0 +1,2 @@
// 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,6 +2,12 @@ machine:
node: node:
version: stable version: stable
test:
pre:
- npm run lint
post:
- npm run coverage -- --upload --providers coveralls
dependencies: dependencies:
pre: pre:
- google-chrome --version - google-chrome --version
@ -15,4 +21,4 @@ dependencies:
- sudo apt-get install -f - sudo apt-get install -f
- sudo apt-get install --only-upgrade lsb-base - sudo apt-get install --only-upgrade lsb-base
- sudo dpkg -i google-chrome.deb - sudo dpkg -i google-chrome.deb
- google-chrome --version - google-chrome --version

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) - [Protocol and Stream Muxing](./protocol-and-stream-muxing)
- [Encrypted Communications](./encrypted-communications) - [Encrypted Communications](./encrypted-communications)
- [Discovery Mechanisms](./discovery-mechanisms) - [Discovery Mechanisms](./discovery-mechanisms)
- [Peer Routing](./peer-routing) - [Peer Routing](./peer-and-content-routing)
- [Content Routing](./content-routing) - [Content Routing](./peer-and-content-routing)
- [PubSub](./pubsub) - [PubSub](./pubsub)
- [NAT Traversal](./nat-traversal) - [NAT Traversal](./nat-traversal)
- Circuit Relay (future) - Circuit Relay (future)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -30,7 +30,7 @@ node2.handle('/your-protocol', (protocol, conn) => {
After the protocol is _handled_, now we can dial to it. After the protocol is _handled_, now we can dial to it.
```JavaScript ```JavaScript
node1.dial(node2.peerInfo, '/your-protocol', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/your-protocol', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['my own protocol, wow!']), conn) pull(pull.values(['my own protocol, wow!']), conn)
}) })
@ -47,7 +47,7 @@ node2.handle('/another-protocol/1.0.1', (protocol, conn) => {
) )
}) })
// ... // ...
node1.dial(node2.peerInfo, '/another-protocol/1.0.0', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/another-protocol/1.0.0', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['semver me please']), conn) pull(pull.values(['semver me please']), conn)
}) })
@ -74,7 +74,7 @@ node2.handle('/custom-match-func', (protocol, conn) => {
} }
}) })
// ... // ...
node1.dial(node2.peerInfo, '/custom-match-func/some-query', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/custom-match-func/some-query', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['do I fall into your criteria?']), conn) pull(pull.values(['do I fall into your criteria?']), conn)
}) })
@ -129,17 +129,17 @@ node2.handle('/b', (protocol, conn) => {
}) })
series([ series([
(cb) => node1.dial(node2.peerInfo, '/a', (err, conn) => { (cb) => node1.dialProtocol(node2.peerInfo, '/a', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['protocol (a)']), conn) pull(pull.values(['protocol (a)']), conn)
cb() cb()
}), }),
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => { (cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['protocol (b)']), conn) pull(pull.values(['protocol (b)']), conn)
cb() cb()
}), }),
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => { (cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['another conn on protocol (b)']), conn) pull(pull.values(['another conn on protocol (b)']), conn)
cb() cb()
@ -158,9 +158,9 @@ another protocol (b)
# 3. Bidirectional connections # 3. Bidirectional connections
There is one last trick on _protocol and stream multiplexing_ that libp2p uses to make everyone's life easier and that is _biderectional connection_. There is one last trick on _protocol and stream multiplexing_ that libp2p uses to make everyone's life easier and that is _bidirectional connection_.
With the aid of both mechanisms, we can reuse an incomming connection to dial streams out too, this is specially useful when you are behind tricky NAT, firewalls or if you are running in a browser, where you can have listening addrs, but you can dial out. By dialing out, you enable other peers to talk with you in Protocols that they want, simply by opening a new multiplexed stream. With the aid of both mechanisms, we can reuse an incomming connection to dial streams out too, this is specially useful when you are behind tricky NAT, firewalls or if you are running in a browser, where you can't have listening addrs, but you can dial out. By dialing out, you enable other peers to talk with you in Protocols that they want, simply by opening a new multiplexed stream.
You can see this working on example [3.js](./3.js). The result should look like the following: You can see this working on example [3.js](./3.js). The result should look like the following:

View File

@ -6,7 +6,6 @@ const Multiplex = require('libp2p-multiplex')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info') const PeerInfo = require('peer-info')
const MulticastDNS = require('libp2p-mdns') const MulticastDNS = require('libp2p-mdns')
const FloodSub = require('libp2p-floodsub')
const waterfall = require('async/waterfall') const waterfall = require('async/waterfall')
const parallel = require('async/parallel') const parallel = require('async/parallel')
const series = require('async/series') const series = require('async/series')
@ -19,7 +18,9 @@ class MyBundle extends libp2p {
muxer: [Multiplex], muxer: [Multiplex],
crypto: [SECIO] crypto: [SECIO]
}, },
discovery: [new MulticastDNS(peerInfo, { interval: 2000 })] discovery: [
new MulticastDNS(peerInfo, { interval: 2000 })
]
} }
super(modules, peerInfo) super(modules, peerInfo)
} }
@ -47,22 +48,19 @@ parallel([
const node1 = nodes[0] const node1 = nodes[0]
const node2 = nodes[1] const node2 = nodes[1]
const fs1 = new FloodSub(node1)
const fs2 = new FloodSub(node2)
series([ series([
(cb) => fs1.start(cb),
(cb) => fs2.start(cb),
(cb) => node1.once('peer:discovery', (peer) => node1.dial(peer, cb)), (cb) => node1.once('peer:discovery', (peer) => node1.dial(peer, cb)),
(cb) => setTimeout(cb, 500) (cb) => setTimeout(cb, 500)
], (err) => { ], (err) => {
if (err) { throw err } if (err) { throw err }
fs2.on('news', (msg) => console.log(msg.from, msg.data.toString())) node1.pubsub.subscribe('news',
fs2.subscribe('news') (msg) => console.log(msg.from, msg.data.toString()),
() => {
setInterval(() => { setInterval(() => {
fs1.publish('news', Buffer.from('Bird bird bird, bird is the word!')) node2.pubsub.publish('news', Buffer.from('Bird bird bird, bird is the word!'))
}, 1000) }, 1000)
}
)
}) })
}) })

View File

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

View File

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

View File

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

View File

@ -143,7 +143,7 @@ parallel([
) )
}) })
node1.dial(node2.peerInfo, '/print', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/print', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['Hello', ' ', 'p2p', ' ', 'world', '!']), conn) pull(pull.values(['Hello', ' ', 'p2p', ' ', 'world', '!']), conn)
@ -240,21 +240,21 @@ parallel([
node3.handle('/print', print) node3.handle('/print', print)
// node 1 (TCP) dials to node 2 (TCP+WebSockets) // node 1 (TCP) dials to node 2 (TCP+WebSockets)
node1.dial(node2.peerInfo, '/print', (err, conn) => { node1.dialProtocol(node2.peerInfo, '/print', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['node 1 dialed to node 2 successfully']), conn) pull(pull.values(['node 1 dialed to node 2 successfully']), conn)
}) })
// node 2 (TCP+WebSockets) dials to node 2 (WebSockets) // node 2 (TCP+WebSockets) dials to node 2 (WebSockets)
node2.dial(node3.peerInfo, '/print', (err, conn) => { node2.dialProtocol(node3.peerInfo, '/print', (err, conn) => {
if (err) { throw err } if (err) { throw err }
pull(pull.values(['node 2 dialed to node 3 successfully']), conn) pull(pull.values(['node 2 dialed to node 3 successfully']), conn)
}) })
// node 3 (WebSockets) attempts to dial to node 1 (TCP) // node 3 (WebSockets) attempts to dial to node 1 (TCP)
node3.dial(node1.peerInfo, '/print', (err, conn) => { node3.dialProtocol(node1.peerInfo, '/print', (err, conn) => {
if (err) { if (err) {
console.log('node 3 failed to dial to node 1 with:', err.message) console.log('node 3 failed to dial to node 1 with:', err.message)
} }
@ -298,8 +298,8 @@ As expected, we created 3 nodes, node 1 with TCP, node 2 with TCP+WebSockets and
Today there are already 3 transports available, one in the works and plenty to come, you can find these at [interface-transport implementations](https://github.com/libp2p/interface-transport#modules-that-implement-the-interface) list. Today there are already 3 transports available, one in the works and plenty to come, you can find these at [interface-transport implementations](https://github.com/libp2p/interface-transport#modules-that-implement-the-interface) list.
Adding more transports is done through the same way as you added TCP and WebSockets. Some transports might offer extra functionalities but for what is libp2p concern, as long as it follows the interface defined at the [spec](https://github.com/libp2p/interface-transport#api), it will be able to use it. Adding more transports is done through the same way as you added TCP and WebSockets. Some transports might offer extra functionalities, but as far as libp2p is concerned, if it follows the interface defined at the [spec](https://github.com/libp2p/interface-transport#api) it will be able to use it.
If you decide to implement a transport yourself, please consider adding to the list so that others can use it as well. If you decide to implement a transport yourself, please consider adding to the list so that others can use it as well.
Hope this tutorial was useful. We are always looking to improve it, contributions are welcome! Hope this tutorial was useful. We are always looking to improve it, so contributions are welcome!

View File

@ -1,6 +1,6 @@
{ {
"name": "libp2p", "name": "libp2p",
"version": "0.13.3", "version": "0.17.0",
"description": "JavaScript base class for libp2p bundles", "description": "JavaScript base class for libp2p bundles",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
@ -26,7 +26,7 @@
"node": ">=6.0.0", "node": ">=6.0.0",
"npm": ">=3.0.0" "npm": ">=3.0.0"
}, },
"pre-commit": [ "pre-push": [
"lint", "lint",
"test" "test"
], ],
@ -38,48 +38,55 @@
"homepage": "https://github.com/libp2p/js-libp2p", "homepage": "https://github.com/libp2p/js-libp2p",
"dependencies": { "dependencies": {
"async": "^2.6.0", "async": "^2.6.0",
"libp2p-ping": "~0.6.0", "libp2p-floodsub": "^0.14.1",
"libp2p-swarm": "~0.33.2", "libp2p-ping": "~0.6.1",
"mafmt": "^3.0.2", "libp2p-switch": "~0.36.1",
"multiaddr": "^3.0.1", "mafmt": "^4.0.0",
"peer-book": "~0.5.2", "multiaddr": "^3.0.2",
"peer-id": "~0.10.3", "peer-book": "~0.5.4",
"peer-info": "~0.11.3" "peer-id": "~0.10.6",
"peer-info": "~0.11.6"
}, },
"devDependencies": { "devDependencies": {
"aegir": "^12.2.0", "aegir": "^13.0.0",
"chai": "^4.1.2", "chai": "^4.1.2",
"cids": "~0.5.2", "cids": "~0.5.2",
"dirty-chai": "^2.0.1", "dirty-chai": "^2.0.1",
"electron-webrtc": "~0.3.0", "electron-webrtc": "~0.3.0",
"libp2p-circuit": "~0.1.4", "libp2p-circuit": "~0.1.4",
"libp2p-kad-dht": "~0.6.0", "libp2p-kad-dht": "~0.8.0",
"libp2p-mdns": "~0.9.1", "libp2p-mdns": "~0.9.2",
"libp2p-multiplex": "~0.5.0", "libp2p-multiplex": "~0.5.1",
"libp2p-railing": "~0.7.1", "libp2p-railing": "~0.7.1",
"libp2p-secio": "~0.8.1", "libp2p-secio": "~0.9.2",
"libp2p-spdy": "~0.11.0", "libp2p-spdy": "~0.11.0",
"libp2p-tcp": "~0.11.1", "libp2p-tcp": "~0.11.5",
"libp2p-webrtc-star": "~0.13.3", "libp2p-webrtc-star": "~0.13.3",
"libp2p-websockets": "~0.10.4", "libp2p-websockets": "~0.10.4",
"libp2p-websocket-star": "~0.7.1", "libp2p-websocket-star": "~0.7.6",
"libp2p-websocket-star-rendezvous": "~0.2.1", "libp2p-websocket-star-rendezvous": "~0.2.3",
"lodash.times": "^4.3.2", "lodash.times": "^4.3.2",
"pre-commit": "^1.2.2", "pre-commit": "^1.2.2",
"pull-goodbye": "0.0.2", "pull-goodbye": "0.0.2",
"pull-serializer": "~0.3.2", "pull-serializer": "~0.3.2",
"pull-stream": "^3.6.1", "pull-stream": "^3.6.1",
"safe-buffer": "^5.1.1", "safe-buffer": "^5.1.1",
"sinon": "^4.1.2", "sinon": "^4.3.0",
"wrtc": "0.0.63" "wrtc": "0.0.66"
}, },
"contributors": [ "contributors": [
"Chris Bratlien <chrisbratlien@gmail.com>", "Chris Bratlien <chrisbratlien@gmail.com>",
"Chris Dostert <chrisdostert@users.noreply.github.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>", "Daijiro Wachi <daijiro.wachi@gmail.com>",
"David Dias <daviddias.p@gmail.com>", "David Dias <daviddias.p@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>", "Dmitriy Ryajov <dryajov@gmail.com>",
"Elven <mon.samuel@qq.com>", "Elven <mon.samuel@qq.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>", "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"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>", "Lars Gierth <lgierth@users.noreply.github.com>",
"Maciej Krüger <mkg20001@gmail.com>", "Maciej Krüger <mkg20001@gmail.com>",
"Nuno Nogueira <nunofmn@gmail.com>", "Nuno Nogueira <nunofmn@gmail.com>",
@ -87,6 +94,7 @@
"RasmusErik Voel Jensen <github@solsort.com>", "RasmusErik Voel Jensen <github@solsort.com>",
"Richard Littauer <richard.littauer@gmail.com>", "Richard Littauer <richard.littauer@gmail.com>",
"Ryan Bell <ryan@piing.net>", "Ryan Bell <ryan@piing.net>",
"Tiago Alves <alvesjtiago@gmail.com>",
"greenkeeperio-bot <support@greenkeeper.io>", "greenkeeperio-bot <support@greenkeeper.io>",
"mayerwin <mayerwin@users.noreply.github.com>", "mayerwin <mayerwin@users.noreply.github.com>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>" "ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>"

3
pdd/README.md Normal file
View File

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

20
pdd/package.json Normal file
View File

@ -0,0 +1,20 @@
{
"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

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

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

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

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

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

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

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

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

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

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

27
src/dht.js Normal file
View File

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

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

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

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

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

View File

@ -7,12 +7,15 @@ const setImmediate = require('async/setImmediate')
const each = require('async/each') const each = require('async/each')
const series = require('async/series') const series = require('async/series')
const Ping = require('libp2p-ping')
const Swarm = require('libp2p-swarm')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const PeerBook = require('peer-book') const PeerBook = require('peer-book')
const multiaddr = require('multiaddr') const Switch = require('libp2p-switch')
const Ping = require('libp2p-ping')
const peerRouting = require('./peer-routing')
const contentRouting = require('./content-routing')
const dht = require('./dht')
const pubsub = require('./pubsub')
const getPeerInfo = require('./get-peer-info')
exports = module.exports exports = module.exports
@ -31,28 +34,28 @@ class Node extends EventEmitter {
this._isStarted = false this._isStarted = false
this.swarm = new Swarm(this.peerInfo, this.peerBook) this.switch = new Switch(this.peerInfo, this.peerBook)
// Attach stream multiplexers // Attach stream multiplexers
if (this.modules.connection && this.modules.connection.muxer) { if (this.modules.connection && this.modules.connection.muxer) {
let muxers = this.modules.connection.muxer let muxers = this.modules.connection.muxer
muxers = Array.isArray(muxers) ? muxers : [muxers] muxers = Array.isArray(muxers) ? muxers : [muxers]
muxers.forEach((muxer) => this.swarm.connection.addStreamMuxer(muxer)) muxers.forEach((muxer) => this.switch.connection.addStreamMuxer(muxer))
// If muxer exists, we can use Identify // If muxer exists, we can use Identify
this.swarm.connection.reuse() this.switch.connection.reuse()
// If muxer exists, we can use Relay for listening/dialing // If muxer exists, we can use Relay for listening/dialing
this.swarm.connection.enableCircuitRelay(_options.relay) this.switch.connection.enableCircuitRelay(_options.relay)
// Received incommind dial and muxer upgrade happened, // Received incommind dial and muxer upgrade happened,
// reuse this muxed connection // reuse this muxed connection
this.swarm.on('peer-mux-established', (peerInfo) => { this.switch.on('peer-mux-established', (peerInfo) => {
this.emit('peer:connect', peerInfo) this.emit('peer:connect', peerInfo)
this.peerBook.put(peerInfo) this.peerBook.put(peerInfo)
}) })
this.swarm.on('peer-mux-closed', (peerInfo) => { this.switch.on('peer-mux-closed', (peerInfo) => {
this.emit('peer:disconnect', peerInfo) this.emit('peer:disconnect', peerInfo)
}) })
} }
@ -62,7 +65,7 @@ class Node extends EventEmitter {
let cryptos = this.modules.connection.crypto let cryptos = this.modules.connection.crypto
cryptos = Array.isArray(cryptos) ? cryptos : [cryptos] cryptos = Array.isArray(cryptos) ? cryptos : [cryptos]
cryptos.forEach((crypto) => { cryptos.forEach((crypto) => {
this.swarm.connection.crypto(crypto.tag, crypto.encrypt) this.switch.connection.crypto(crypto.tag, crypto.encrypt)
}) })
} }
@ -76,67 +79,23 @@ class Node extends EventEmitter {
}) })
} }
// Mount default protocols
Ping.mount(this.swarm)
// dht provided components (peerRouting, contentRouting, dht) // dht provided components (peerRouting, contentRouting, dht)
if (_modules.DHT) { if (_modules.DHT) {
this._dht = new this.modules.DHT(this.swarm, { this._dht = new this.modules.DHT(this.switch, {
kBucketSize: 20, kBucketSize: 20,
datastoer: _options.DHT && _options.DHT.datastore datastore: _options.DHT && _options.DHT.datastore
}) })
} }
this.peerRouting = { this.peerRouting = peerRouting(this)
findPeer: (id, callback) => { this.contentRouting = contentRouting(this)
if (!this._dht) { this.dht = dht(this)
return callback(new Error('DHT is not available')) this.pubsub = pubsub(this)
}
this._dht.findPeer(id, callback) this._getPeerInfo = getPeerInfo(this)
}
}
this.contentRouting = { // Mount default protocols
findProviders: (key, timeout, callback) => { Ping.mount(this.switch)
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.findProviders(key, timeout, callback)
},
provide: (key, callback) => {
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.provide(key, callback)
}
}
this.dht = {
put: (key, value, callback) => {
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.put(key, value, callback)
},
get: (key, callback) => {
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.get(key, callback)
},
getMany (key, nVals, callback) {
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.getMany(key, nVals, callback)
}
}
} }
/* /*
@ -156,18 +115,18 @@ class Node extends EventEmitter {
// so that we can have webrtc-star addrs without adding manually the id // so that we can have webrtc-star addrs without adding manually the id
const maOld = [] const maOld = []
const maNew = [] const maNew = []
this.peerInfo.multiaddrs.forEach((ma) => { this.peerInfo.multiaddrs.toArray().forEach((ma) => {
if (!ma.getPeerId()) { if (!ma.getPeerId()) {
maOld.push(ma) maOld.push(ma)
maNew.push(ma.encapsulate('/ipfs/' + this.peerInfo.id.toB58String())) maNew.push(ma.encapsulate('/ipfs/' + this.peerInfo.id.toB58String()))
} }
}) })
this.peerInfo.multiaddrs.replace(maOld, maNew) this.peerInfo.multiaddrs.replace(maOld, maNew)
const multiaddrs = this.peerInfo.multiaddrs.toArray()
const multiaddrs = this.peerInfo.multiaddrs.toArray()
transports.forEach((transport) => { transports.forEach((transport) => {
if (transport.filter(multiaddrs).length > 0) { if (transport.filter(multiaddrs).length > 0) {
this.swarm.transport.add( this.switch.transport.add(
transport.tag || transport.constructor.name, transport) transport.tag || transport.constructor.name, transport)
} else if (transport.constructor && } else if (transport.constructor &&
transport.constructor.name === 'WebSockets') { transport.constructor.name === 'WebSockets') {
@ -178,11 +137,11 @@ class Node extends EventEmitter {
}) })
series([ series([
(cb) => this.swarm.listen(cb), (cb) => this.switch.start(cb),
(cb) => { (cb) => {
if (ws) { if (ws) {
// always add dialing on websockets // always add dialing on websockets
this.swarm.transport.add(ws.tag || ws.constructor.name, ws) this.switch.transport.add(ws.tag || ws.constructor.name, ws)
} }
// all transports need to be setup before discover starts // all transports need to be setup before discover starts
@ -192,12 +151,37 @@ class Node extends EventEmitter {
cb() cb()
}, },
(cb) => { (cb) => {
// TODO: chicken-and-egg problem: // TODO: chicken-and-egg problem #1:
// have to set started here because DHT requires libp2p is already started // have to set started here because DHT requires libp2p is already started
this._isStarted = true this._isStarted = true
if (this._dht) { if (this._dht) {
return this._dht.start(cb) this._dht.start(cb)
} else {
cb()
} }
},
(cb) => {
// 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()
}, },
(cb) => { (cb) => {
@ -211,8 +195,6 @@ class Node extends EventEmitter {
* Stop the libp2p node by closing its listeners and open connections * Stop the libp2p node by closing its listeners and open connections
*/ */
stop (callback) { stop (callback) {
this._isStarted = false
if (this.modules.discovery) { if (this.modules.discovery) {
this.modules.discovery.forEach((discovery) => { this.modules.discovery.forEach((discovery) => {
setImmediate(() => discovery.stop(() => {})) setImmediate(() => discovery.stop(() => {}))
@ -220,36 +202,48 @@ class Node extends EventEmitter {
} }
series([ series([
(cb) => {
if (this._floodSub.started) {
this._floodSub.stop(cb)
}
},
(cb) => { (cb) => {
if (this._dht) { if (this._dht) {
return this._dht.stop(cb) return this._dht.stop(cb)
} }
cb() cb()
}, },
(cb) => this.swarm.close(cb), (cb) => this.switch.stop(cb),
(cb) => { (cb) => {
this.emit('stop') this.emit('stop')
cb() cb()
} }
], callback) ], (err) => {
this._isStarted = false
callback(err)
})
} }
isStarted () { isStarted () {
return this._isStarted return this._isStarted
} }
ping (peer, callback) { dial (peer, callback) {
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE) assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
this._getPeerInfo(peer, (err, peerInfo) => {
if (err) {
return callback(err)
}
callback(null, new Ping(this.swarm, peerInfo)) this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { return callback(err) }
this.switch.dial(peerInfo, (err) => {
if (err) { return callback(err) }
this.peerBook.put(peerInfo)
callback()
})
}) })
} }
dial (peer, protocol, callback) { dialProtocol (peer, protocol, callback) {
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE) assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
if (typeof protocol === 'function') { if (typeof protocol === 'function') {
@ -258,14 +252,10 @@ class Node extends EventEmitter {
} }
this._getPeerInfo(peer, (err, peerInfo) => { this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { if (err) { return callback(err) }
return callback(err)
}
this.swarm.dial(peerInfo, protocol, (err, conn) => { this.switch.dial(peerInfo, protocol, (err, conn) => {
if (err) { if (err) { return callback(err) }
return callback(err)
}
this.peerBook.put(peerInfo) this.peerBook.put(peerInfo)
callback(null, conn) callback(null, conn)
}) })
@ -276,52 +266,27 @@ class Node extends EventEmitter {
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE) assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
this._getPeerInfo(peer, (err, peerInfo) => { this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { if (err) { return callback(err) }
return callback(err)
}
this.swarm.hangUp(peerInfo, callback) 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))
}) })
} }
handle (protocol, handlerFunc, matchFunc) { handle (protocol, handlerFunc, matchFunc) {
this.swarm.handle(protocol, handlerFunc, matchFunc) this.switch.handle(protocol, handlerFunc, matchFunc)
} }
unhandle (protocol) { unhandle (protocol) {
this.swarm.unhandle(protocol) this.switch.unhandle(protocol)
}
/*
* Helper method to check the data type of peer and convert it to PeerInfo
*/
_getPeerInfo (peer, callback) {
let p
// PeerInfo
if (PeerInfo.isPeerInfo(peer)) {
p = peer
// Multiaddr instance (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))
} }
} }

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

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

93
src/pubsub.js Normal file
View File

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

View File

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

40
test/multiaddr-trim.js Normal file
View File

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

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

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

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

View File

@ -6,24 +6,15 @@ chai.use(require('dirty-chai'))
const expect = chai.expect const expect = chai.expect
const parallel = require('async/parallel') const parallel = require('async/parallel')
const series = require('async/series') const series = require('async/series')
const pull = require('pull-stream')
const utils = require('./utils/node') const utils = require('./utils/node')
const tryEcho = require('./utils/try-echo')
const createNode = utils.createNode const createNode = utils.createNode
const echo = utils.echo const echo = utils.echo
function test (nodeA, nodeB, callback) { function test (nodeA, nodeB, callback) {
nodeA.dial(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => { nodeA.dialProtocol(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => {
expect(err).to.not.exist() expect(err).to.not.exist()
tryEcho(conn, callback)
pull(
pull.values([Buffer.from('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.be.eql([Buffer.from('hey')])
callback()
})
)
}) })
} }
@ -136,7 +127,7 @@ describe('stream muxing', () => {
}) })
it('spdy + multiplex switched order', function (done) { it('spdy + multiplex switched order', function (done) {
this.timeout(5000) this.timeout(5 * 1000)
let nodeA let nodeA
let nodeB let nodeB
@ -170,7 +161,7 @@ describe('stream muxing', () => {
}) })
it('one without the other fails to establish a muxedConn', function (done) { it('one without the other fails to establish a muxedConn', function (done) {
this.timeout(5000) this.timeout(5 * 1000)
let nodeA let nodeA
let nodeB let nodeB
@ -200,12 +191,12 @@ describe('stream muxing', () => {
(cb) => setup(cb), (cb) => setup(cb),
(cb) => { (cb) => {
// it will just 'warm up a conn' // it will just 'warm up a conn'
expect(Object.keys(nodeA.swarm.muxers)).to.have.length(1) expect(Object.keys(nodeA.switch.muxers)).to.have.length(1)
expect(Object.keys(nodeB.swarm.muxers)).to.have.length(1) expect(Object.keys(nodeB.switch.muxers)).to.have.length(1)
nodeA.dial(nodeB.peerInfo, (err) => { nodeA.dial(nodeB.peerInfo, (err) => {
expect(err).to.not.exist() expect(err).to.not.exist()
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0) expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
cb() cb()
}) })
}, },

View File

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

View File

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

View File

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

View File

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

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

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