mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-08 13:21:34 +00:00
Compare commits
113 Commits
Author | SHA1 | Date | |
---|---|---|---|
7733ba5cd7 | |||
52bf826ec6 | |||
10619afbe6 | |||
3debabdd26 | |||
56e095983a | |||
ebdb696742 | |||
721e6ee9ce | |||
98f2903088 | |||
3dda282dfd | |||
03faf69212 | |||
0062a4b5eb | |||
f7f85dce0a | |||
59df82a675 | |||
6651401f0b | |||
cd43863db6 | |||
23e8293b75 | |||
68c170a40d | |||
bd8a35aaf9 | |||
248d86d050 | |||
8225b11082 | |||
1355af2b51 | |||
a85f041843 | |||
2c0cda2a7c | |||
b4ba267589 | |||
4c81f39ebe | |||
76922383ab | |||
3fc57ff397 | |||
13b36dcaa6 | |||
61bebd10fc | |||
97cde1ccb4 | |||
07b0cdc30e | |||
73b6d60e32 | |||
808f7495a9 | |||
ae21a6facf | |||
3aba3fd176 | |||
dc2da39a19 | |||
f8b441fff5 | |||
190ad54f9e | |||
582f8bed2e | |||
59de0da19c | |||
0caf600c9a | |||
a4943b4509 | |||
c128873a07 | |||
5e2b6df04a | |||
8d2d8c98a0 | |||
30bf5bb161 | |||
c88eaf416c | |||
c7f20383d9 | |||
a86a95c19f | |||
1b7360fcfa | |||
67ca37c356 | |||
0870068ebc | |||
8563395d32 | |||
ef3cae5b5a | |||
f602cd9f79 | |||
ec956c1d42 | |||
c906f698e4 | |||
95f029eb7a | |||
38a68a01b7 | |||
c08aa517a0 | |||
8eac0f806e | |||
9fd092fddf | |||
87ddc25bee | |||
efb2b67f19 | |||
7c0b4daf49 | |||
aeb3ae1301 | |||
97df76f9c5 | |||
3ad696445d | |||
30bec8d53b | |||
db2b5300b4 | |||
df4d60df88 | |||
29cc0afc64 | |||
2504cbeb26 | |||
468cc421fa | |||
0b991e19d1 | |||
2a81fc75a8 | |||
e04c249d4d | |||
4a995613ae | |||
066c4976bb | |||
429cf9c361 | |||
01c20f8ab9 | |||
c8adce3906 | |||
6e3c5427de | |||
3e140d2c47 | |||
f0858c20bd | |||
ef9c2a6296 | |||
090d75d383 | |||
04a4ffcc36 | |||
7f7278fe82 | |||
2c03222136 | |||
65857838f9 | |||
cad173e3bd | |||
19ce266f1b | |||
a2a85eb8d6 | |||
b674bccfc2 | |||
4ae8e43b8b | |||
6b059a0ba8 | |||
363259f832 | |||
56dbd9e7c2 | |||
314b45897f | |||
0a6f1faf82 | |||
5a638794c5 | |||
d3b0f380bb | |||
c1ccc1d5fb | |||
49484f734c | |||
43345cee6d | |||
06eb7a19f3 | |||
76ef5fdf50 | |||
c8f4eaf982 | |||
abe5c8c171 | |||
a01221f89c | |||
4224c1fe61 | |||
019cd4715d |
71
.aegir.js
Normal file
71
.aegir.js
Normal file
@ -0,0 +1,71 @@
|
||||
'use strict'
|
||||
|
||||
const PeerInfo = require('peer-info')
|
||||
const PeerId = require('peer-id')
|
||||
const pull = require('pull-stream')
|
||||
const parallel = require('async/parallel')
|
||||
|
||||
const rawPeer = require('./test/fixtures/test-peer.json')
|
||||
const Node = require('./test/utils/bundle.node.js')
|
||||
const sigServer = require('libp2p-webrtc-star/src/sig-server')
|
||||
const WebSocketStarRendezvous = require('libp2p-websocket-star-rendezvous')
|
||||
|
||||
let wrtcRendezvous
|
||||
let wsRendezvous
|
||||
let node
|
||||
|
||||
const before = (done) => {
|
||||
parallel([
|
||||
(cb) => {
|
||||
sigServer.start({
|
||||
port: 15555
|
||||
// cryptoChallenge: true TODO: needs https://github.com/libp2p/js-libp2p-webrtc-star/issues/128
|
||||
}, (err, server) => {
|
||||
if (err) { return cb(err) }
|
||||
wrtcRendezvous = server
|
||||
cb()
|
||||
})
|
||||
},
|
||||
(cb) => {
|
||||
WebSocketStarRendezvous.start({
|
||||
port: 14444,
|
||||
refreshPeerListIntervalMS: 1000,
|
||||
strictMultiaddr: false,
|
||||
cryptoChallenge: true
|
||||
}, (err, _server) => {
|
||||
if (err) { return cb(err) }
|
||||
wsRendezvous = _server
|
||||
cb()
|
||||
})
|
||||
},
|
||||
(cb) => {
|
||||
PeerId.createFromJSON(rawPeer, (err, peerId) => {
|
||||
if (err) {
|
||||
return done(err)
|
||||
}
|
||||
const peer = new PeerInfo(peerId)
|
||||
|
||||
peer.multiaddrs.add('/ip4/127.0.0.1/tcp/9200/ws')
|
||||
|
||||
node = new Node(peer)
|
||||
node.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
|
||||
node.start(cb)
|
||||
})
|
||||
}
|
||||
], done)
|
||||
}
|
||||
|
||||
const after = (done) => {
|
||||
setTimeout(() => parallel(
|
||||
[node, wrtcRendezvous, wsRendezvous].map((s) => {
|
||||
return (cb) => s.stop(cb)
|
||||
})
|
||||
, done), 2000)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
hooks: {
|
||||
pre: before,
|
||||
post: after
|
||||
}
|
||||
}
|
26
.gitignore
vendored
26
.gitignore
vendored
@ -1,7 +1,14 @@
|
||||
docs
|
||||
**/node_modules/
|
||||
**/*.log
|
||||
test/repo-tests*
|
||||
**/bundle.js
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
coverage
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
@ -20,16 +27,17 @@ coverage
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
build
|
||||
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||
node_modules
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
lib
|
||||
dist
|
||||
test/test-data/go-ipfs-repo/LOCK
|
||||
test/test-data/go-ipfs-repo/LOG
|
||||
test/test-data/go-ipfs-repo/LOG.old
|
||||
|
||||
# while testing npm5
|
||||
package-lock.json
|
||||
|
21
.npmignore
21
.npmignore
@ -1,7 +1,16 @@
|
||||
**/node_modules/
|
||||
**/*.log
|
||||
test/repo-tests*
|
||||
img
|
||||
docs
|
||||
examples
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
coverage
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
@ -16,13 +25,13 @@ coverage
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
build
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
# Dependency directory
|
||||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git
|
||||
node_modules
|
||||
|
||||
test
|
18
.travis.yml
18
.travis.yml
@ -1,23 +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
|
||||
language: node_js
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- node_js: 4
|
||||
env: CXX=g++-4.8
|
||||
- node_js: 6
|
||||
env:
|
||||
- SAUCE=true
|
||||
- CXX=g++-4.8
|
||||
- node_js: stable
|
||||
env: CXX=g++-4.8
|
||||
|
||||
# Make sure we have new NPM.
|
||||
before_install:
|
||||
- npm install -g npm
|
||||
- node_js: 8
|
||||
env: CXX=g++-4.8
|
||||
# - node_js: stable
|
||||
# env: CXX=g++-4.8
|
||||
|
||||
script:
|
||||
- npm run lint
|
||||
- npm test
|
||||
- npm run test
|
||||
- npm run coverage
|
||||
|
||||
before_script:
|
||||
|
152
CHANGELOG.md
152
CHANGELOG.md
@ -1,3 +1,155 @@
|
||||
<a name="0.16.3"></a>
|
||||
## [0.16.3](https://github.com/libp2p/js-libp2p/compare/v0.16.2...v0.16.3) (2018-02-08)
|
||||
|
||||
|
||||
|
||||
<a name="0.16.2"></a>
|
||||
## [0.16.2](https://github.com/libp2p/js-libp2p/compare/v0.16.1...v0.16.2) (2018-02-07)
|
||||
|
||||
|
||||
|
||||
<a name="0.16.1"></a>
|
||||
## [0.16.1](https://github.com/libp2p/js-libp2p/compare/v0.16.0...v0.16.1) (2018-02-07)
|
||||
|
||||
|
||||
|
||||
<a name="0.16.0"></a>
|
||||
# [0.16.0](https://github.com/libp2p/js-libp2p/compare/v0.15.2...v0.16.0) (2018-02-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add explicit error for case peer id not included in multiaddr ([#155](https://github.com/libp2p/js-libp2p/issues/155)) ([bd8a35a](https://github.com/libp2p/js-libp2p/commit/bd8a35a))
|
||||
* dialProtocol and small refactor ([6651401](https://github.com/libp2p/js-libp2p/commit/6651401))
|
||||
* use libp2p-switch ([23e8293](https://github.com/libp2p/js-libp2p/commit/23e8293))
|
||||
|
||||
|
||||
|
||||
<a name="0.15.2"></a>
|
||||
## [0.15.2](https://github.com/libp2p/js-libp2p/compare/v0.15.1...v0.15.2) (2018-01-28)
|
||||
|
||||
|
||||
|
||||
<a name="0.15.1"></a>
|
||||
## [0.15.1](https://github.com/libp2p/js-libp2p/compare/v0.15.0...v0.15.1) (2018-01-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* typo in DHT setup ([#151](https://github.com/libp2p/js-libp2p/issues/151)) ([61bebd1](https://github.com/libp2p/js-libp2p/commit/61bebd1))
|
||||
|
||||
|
||||
|
||||
<a name="0.15.0"></a>
|
||||
# [0.15.0](https://github.com/libp2p/js-libp2p/compare/v0.14.3...v0.15.0) (2018-01-07)
|
||||
|
||||
|
||||
|
||||
<a name="0.14.3"></a>
|
||||
## [0.14.3](https://github.com/libp2p/js-libp2p/compare/v0.14.2...v0.14.3) (2017-12-15)
|
||||
|
||||
|
||||
|
||||
<a name="0.14.2"></a>
|
||||
## [0.14.2](https://github.com/libp2p/js-libp2p/compare/v0.14.1...v0.14.2) (2017-12-15)
|
||||
|
||||
|
||||
|
||||
<a name="0.14.1"></a>
|
||||
## [0.14.1](https://github.com/libp2p/js-libp2p/compare/v0.14.0...v0.14.1) (2017-12-15)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent "The libp2p node is not started yet" when stopping ([#138](https://github.com/libp2p/js-libp2p/issues/138)) ([c88eaf4](https://github.com/libp2p/js-libp2p/commit/c88eaf4))
|
||||
|
||||
|
||||
|
||||
<a name="0.14.0"></a>
|
||||
# [0.14.0](https://github.com/libp2p/js-libp2p/compare/v0.13.3...v0.14.0) (2017-12-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove innactive multiaddrs ([#131](https://github.com/libp2p/js-libp2p/issues/131)) ([1b7360f](https://github.com/libp2p/js-libp2p/commit/1b7360f))
|
||||
|
||||
|
||||
|
||||
<a name="0.13.3"></a>
|
||||
## [0.13.3](https://github.com/libp2p/js-libp2p/compare/v0.13.2...v0.13.3) (2017-12-01)
|
||||
|
||||
|
||||
|
||||
<a name="0.13.2"></a>
|
||||
## [0.13.2](https://github.com/libp2p/js-libp2p/compare/v0.13.1...v0.13.2) (2017-11-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Bring libp2p-websocket-star to the Transports family! 🌟 ([#122](https://github.com/libp2p/js-libp2p/issues/122)) ([95f029e](https://github.com/libp2p/js-libp2p/commit/95f029e))
|
||||
|
||||
|
||||
|
||||
<a name="0.13.1"></a>
|
||||
## [0.13.1](https://github.com/libp2p/js-libp2p/compare/v0.13.0...v0.13.1) (2017-11-12)
|
||||
|
||||
|
||||
|
||||
<a name="0.13.0"></a>
|
||||
# [0.13.0](https://github.com/libp2p/js-libp2p/compare/v0.12.4...v0.13.0) (2017-10-26)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* enable and test Circuit Relay ([29cc0af](https://github.com/libp2p/js-libp2p/commit/29cc0af))
|
||||
|
||||
|
||||
|
||||
<a name="0.12.4"></a>
|
||||
## [0.12.4](https://github.com/libp2p/js-libp2p/compare/v0.12.3...v0.12.4) (2017-09-07)
|
||||
|
||||
|
||||
|
||||
<a name="0.12.3"></a>
|
||||
## [0.12.3](https://github.com/libp2p/js-libp2p/compare/v0.12.2...v0.12.3) (2017-09-07)
|
||||
|
||||
|
||||
|
||||
<a name="0.12.2"></a>
|
||||
## [0.12.2](https://github.com/libp2p/js-libp2p/compare/v0.12.0...v0.12.2) (2017-09-07)
|
||||
|
||||
|
||||
|
||||
<a name="0.12.1"></a>
|
||||
## [0.12.1](https://github.com/libp2p/js-libp2p/compare/v0.12.0...v0.12.1) (2017-09-07)
|
||||
|
||||
|
||||
|
||||
<a name="0.12.0"></a>
|
||||
# [0.12.0](https://github.com/libp2p/js-libp2p/compare/v0.11.0...v0.12.0) (2017-09-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* p2p addrs situation ([#119](https://github.com/libp2p/js-libp2p/issues/119)) ([cad173e](https://github.com/libp2p/js-libp2p/commit/cad173e))
|
||||
|
||||
|
||||
|
||||
<a name="0.11.0"></a>
|
||||
# [0.11.0](https://github.com/libp2p/js-libp2p/compare/v0.10.2...v0.11.0) (2017-07-22)
|
||||
|
||||
|
||||
|
||||
<a name="0.10.2"></a>
|
||||
## [0.10.2](https://github.com/libp2p/js-libp2p/compare/v0.10.1...v0.10.2) (2017-07-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* circle ci, thanks victor! ([4224c1f](https://github.com/libp2p/js-libp2p/commit/4224c1f))
|
||||
|
||||
|
||||
|
||||
<a name="0.10.1"></a>
|
||||
## [0.10.1](https://github.com/libp2p/js-libp2p/compare/v0.10.0...v0.10.1) (2017-07-10)
|
||||
|
||||
|
@ -1,151 +1,3 @@
|
||||
# IPFS Community Code of Conduct
|
||||
# Contributor Code of Conduct
|
||||
|
||||
We believe that our mission is best served in an environment that is friendly,
|
||||
safe, and accepting; free from intimidation or harassment.
|
||||
|
||||
Towards this end, certain behaviors and practices will not be tolerated.
|
||||
|
||||
## tl;dr
|
||||
|
||||
- Be respectful.
|
||||
- We're here to help: abuse@ipfs.io
|
||||
- Abusive behavior is never tolerated.
|
||||
- Violations of this code may result in swift and permanent expulsion from the IPFS community.
|
||||
- "Too long, didn't read" is not a valid excuse for not knowing what is in this document.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Scope](#scope)
|
||||
- [Friendly Harassment-Free Space](#friendly-harassment-free-space)
|
||||
- [Reporting Violations of this Code of Conduct](#reporting-violations-of-this-code-of-conduct)
|
||||
- [Copyright Violations](#copyright-violations)
|
||||
- [Consequences](#consequences)
|
||||
- [Addressing Grievances](#addressing-grievances)
|
||||
- [Contact Info](#contact-info)
|
||||
- [Changes](#changes)
|
||||
- [Credit and License](#credit-and-license)
|
||||
|
||||
## Scope
|
||||
|
||||
We expect all members of the IPFS community to abide by this Code of Conduct
|
||||
at all times in all IPFS community venues, online and in person, and in one-on-one
|
||||
communications pertaining to IPFS affairs.
|
||||
|
||||
This policy covers the usage of IPFS public infrastructure, including the
|
||||
IPFS.io HTTP gateways, as well as other IPFS websites, IPFS related events,
|
||||
and any other services offered by or on behalf of the IPFS community. It also
|
||||
applies to behavior in the context of the IPFS Open Source project
|
||||
communities, including but not limited to public GitHub repositories, IRC
|
||||
channels, social media, mailing lists, and public events.
|
||||
|
||||
This Code of Conduct is in addition to, and does not in any way nullify or
|
||||
invalidate, any other terms or conditions related to use of IPFS services.
|
||||
|
||||
The definitions of various subjective terms such as "discriminatory",
|
||||
"hateful", or "confusing" will be decided at the sole discretion of the IPFS
|
||||
abuse team.
|
||||
|
||||
## Friendly Harassment-Free Space
|
||||
|
||||
We are committed to providing a friendly, safe and welcoming environment for
|
||||
all, regardless of gender identity, sexual orientation, disability, ethnicity,
|
||||
religion, age, physical appearance, body size, race, or similar personal
|
||||
characteristics.
|
||||
|
||||
We ask that you please respect that people have differences of opinion
|
||||
regarding technical choices, and that every design or implementation choice
|
||||
carries a trade-off and numerous costs. There is seldom a single right answer.
|
||||
A difference of technology preferences is not a license to be rude.
|
||||
|
||||
Any spamming, trolling, flaming, baiting, or other attention-stealing
|
||||
behavior is not welcome, and will not be tolerated.
|
||||
|
||||
Harassing other users is never tolerated, whether via public or private media.
|
||||
|
||||
Avoid using offensive or harassing nicknames, or other identifiers that might
|
||||
detract from a friendly, safe, and welcoming environment for all.
|
||||
|
||||
Harassment includes, but is not limited to: harmful or prejudicial verbal or
|
||||
written comments related to gender identity, sexual orientation, disability,
|
||||
ethnicity, religion, age, physical appearance, body size, race, or similar
|
||||
personal characteristics; inappropriate use of nudity, sexual images, and/or
|
||||
sexually explicit language in public spaces; threats of physical or non-
|
||||
physical harm; deliberate intimidation, stalking or following; harassing
|
||||
photography or recording; sustained disruption of talks or other events;
|
||||
inappropriate physical contact; and unwelcome sexual attention.
|
||||
|
||||
Media shared through public infrastructure run by the IPFS team must not
|
||||
contain illegal or infringing content. You should only publish content via
|
||||
IPFS public infrastructure if you have the right to do so. This includes
|
||||
complying with all software license agreements or other intellectual property
|
||||
restrictions. You will be solely responsible for any violation of laws or
|
||||
others’ intellectual property rights.
|
||||
|
||||
## Reporting Violations of this Code of Conduct
|
||||
|
||||
If you believe someone is harassing you or has otherwise violated this Code of
|
||||
Conduct, please contact us at abuse@ipfs.io to send us an abuse report. If
|
||||
this is the initial report of a problem, please include as much detail as
|
||||
possible. It is easiest for us to address issues when we have more context.
|
||||
|
||||
## Copyright Violations
|
||||
|
||||
We respect the intellectual property of others and ask that you do too. If you
|
||||
believe any content or other materials available through public IPFS
|
||||
infrastructure violates a copyright held by you and you would like to submit a
|
||||
notice pursuant to the Digital Millennium Copyright Act or other similar
|
||||
international law, you can submit a notice to our agent for service of notice
|
||||
to: abuse@ipfs.io
|
||||
|
||||
(We will add a physical mailing address here when we acquire one).
|
||||
|
||||
Please make sure your notice meets the Digital Millennium Copyright Act
|
||||
requirements.
|
||||
|
||||
## Consequences
|
||||
|
||||
All content published to public IPFS infrastructure is hosted at the sole
|
||||
discretion of the IPFS team.
|
||||
|
||||
Unacceptable behavior from any community member will not be tolerated.
|
||||
|
||||
Anyone asked to stop unacceptable behavior is expected to comply immediately.
|
||||
|
||||
If a community member engages in unacceptable behavior, the ipfs team
|
||||
may take any action they deem appropriate, up to and including a temporary ban
|
||||
or permanent expulsion from the community without warning (and without refund
|
||||
in the case of a paid event or service).
|
||||
|
||||
## Addressing Grievances
|
||||
|
||||
If you feel you have been falsely or unfairly accused of violating this Code
|
||||
of Conduct, you should notify the IPFS team. We will do our best to ensure
|
||||
that your grievance is handled appropriately.
|
||||
|
||||
In general, we will choose the course of action that we judge as being most in
|
||||
the interest of fostering a safe and friendly community.
|
||||
|
||||
On IRC, let one of the ops know if you think that someone has transgressed
|
||||
against the Code of Conduct. If you would like to be an op and promise to
|
||||
help maintain and abide by the code, please let us know.
|
||||
|
||||
## Contact Info
|
||||
|
||||
Please contact abuse@ipfs.io if you need to report a problem or address a
|
||||
grievance related to an abuse report.
|
||||
|
||||
You are also encouraged to contact us if you are curious about something that
|
||||
might be "on the line" between appropriate and inappropriate content. We are
|
||||
happy to provide guidance to help you be a successful part of our community.
|
||||
|
||||
## Changes
|
||||
|
||||
This is a living document and may be updated from time to time. Please refer
|
||||
to the git history for this document to view the changes.
|
||||
|
||||
## Credit and License
|
||||
This Code of Conduct is based on the
|
||||
[npm Code of Conduct](https://www.npmjs.com/policies/conduct).
|
||||
|
||||
This document may be reused under a [Creative Commons Attribution-ShareAlike
|
||||
License](http://creativecommons.org/licenses/by-sa/4.0/).
|
||||
The `js-libp2p` project follows the [`IPFS Community Code of Conduct`](https://github.com/ipfs/community/blob/master/code-of-conduct.md)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Contributing guidelines
|
||||
|
||||
libp2p as a project, including js-libp2p and all of its modules, follows the [standard IPFS Community contributing guidelines](https://github.com/ipfs/community/blob/master/js-project-guidelines.md).
|
||||
libp2p as a project, including js-libp2p and all of its modules, follows the [standard IPFS Community contributing guidelines](https://github.com/ipfs/community/blob/master/contribution-guidelines.md).
|
||||
|
||||
We also adhere to the [IPFS JavaScript Community contributing guidelines](https://github.com/ipfs/community/blob/master/js-project-guidelines.md) which provide additional information of how to collaborate and contribute in the JavaScript implementation of libp2p.
|
||||
|
||||
|
43
ISSUE_TEMPLATE.md
Normal file
43
ISSUE_TEMPLATE.md
Normal file
@ -0,0 +1,43 @@
|
||||
<!--
|
||||
Thank you for reporting an issue.
|
||||
|
||||
This issue tracker is for bugs and issues found within the JavaScript implementation of libp2p.
|
||||
If you require more general support please file an issue on our discuss forum. https://discuss.ipfs.io/
|
||||
|
||||
Please fill in as much of the template below as you're able.
|
||||
|
||||
Version: package.json version or the commit you have installed.
|
||||
Platform: output of `uname -a` (UNIX), or version and 32 or 64-bit (Windows). If using in a Browser, please share the browser version as well.
|
||||
Subsystem: if known, please specify affected core module name (e.g Transports, SECIO, etc).
|
||||
|
||||
If possible, please provide code that demonstrates the problem, keeping it as
|
||||
simple and free of external dependencies as you are able.
|
||||
-->
|
||||
|
||||
- **Version**:
|
||||
- **Platform**:
|
||||
- **Subsystem**:
|
||||
|
||||
<!-- Bug, Feature, Question, Enhancement, Etc -->
|
||||
#### Type:
|
||||
|
||||
<!--
|
||||
One of following:
|
||||
Critical - System crash, application panic.
|
||||
High - The main functionality of the application does not work, API breakage, repo format breakage, etc.
|
||||
Medium - A non-essential functionality does not work, performance issues, etc.
|
||||
Low - An optional functionality does not work.
|
||||
Very Low - Translation or documentation mistake. Something that won't give anyone a bad day.
|
||||
-->
|
||||
#### Severity:
|
||||
|
||||
#### Description:
|
||||
|
||||
#### Steps to reproduce the error:
|
||||
|
||||
<!--
|
||||
This is for you! Please read, and then delete this text before posting it.
|
||||
The js-ipfs issues are only for bug reports and directly actionable features.
|
||||
|
||||
Read https://github.com/ipfs/community/blob/master/contributing.md#reporting-issues if your issue doesn't fit either of those categories.
|
||||
-->
|
92
README.md
92
README.md
@ -20,10 +20,18 @@
|
||||
<a href="https://github.com/feross/standard"><img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square"></a>
|
||||
<a href="https://github.com/RichardLitt/standard-readme"><img src="https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square" /></a>
|
||||
<a href=""><img src="https://img.shields.io/badge/npm-%3E%3D3.0.0-orange.svg?style=flat-square" /></a>
|
||||
<a href=""><img src="https://img.shields.io/badge/Node.js-%3E%3D4.0.0-orange.svg?style=flat-square" /></a>
|
||||
<a href=""><img src="https://img.shields.io/badge/Node.js-%3E%3D6.0.0-orange.svg?style=flat-square" /></a>
|
||||
<br>
|
||||
</p>
|
||||
|
||||
### Project status
|
||||
|
||||
We've come a long way, but this project is still in Alpha, lots of development is happening, API might change, beware of the Dragons 🐉..
|
||||
|
||||
**Want to get started?** Check our [examples folder](/examples). You can check the development status at the [Waffle Board](https://waffle.io/libp2p/js-libp2p).
|
||||
|
||||
[](https://waffle.io/libp2p/js-libp2p/metrics/throughput)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Background](#background)
|
||||
@ -40,9 +48,9 @@
|
||||
|
||||
## 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 writting 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:
|
||||
|
||||
- [libp2p.io](https://libp2p.io)
|
||||
- [Specification (WIP)](https://github.com/libp2p/specs)
|
||||
@ -74,7 +82,7 @@ npm install --save libp2p
|
||||
|
||||
### [Tutorials and Examples](/examples)
|
||||
|
||||
You can find multiple examples on the [examples folder](/examples) that will guide you through using libp2p for several scenarions.
|
||||
You can find multiple examples on the [examples folder](/examples) that will guide you through using libp2p for several scenarios.
|
||||
|
||||
### Extending libp2p skeleton
|
||||
|
||||
@ -150,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.
|
||||
|
||||
#### `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][]
|
||||
- `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
|
||||
- `peer`: can be an instance of [PeerInfo][], [PeerId][], [multiaddr][], or a multiaddr string
|
||||
- `callback`: Function with signature `function (err, conn) {}` where `conn` is a [Connection](https://github.com/libp2p/interface-connection) object
|
||||
|
||||
`callback` is a function with the following `function (err, conn) {}` signature, where `err` is an Error in of failure to dial the connection and `conn` is a [Connection][] instance in case of a protocol selected, if not it is undefined.
|
||||
|
||||
#### `libp2p.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.
|
||||
|
||||
@ -188,10 +206,10 @@ class Node extends libp2p {
|
||||
> Handle new protocol
|
||||
|
||||
- `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
|
||||
- `handlerFunc`: Function with signature `function (protocol, conn) {}`
|
||||
- `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.
|
||||
|
||||
#### `libp2p.unhandle(protocol)
|
||||
#### `libp2p.unhandle(protocol)`
|
||||
|
||||
> Stop handling protocol
|
||||
|
||||
@ -249,24 +267,48 @@ class Node extends libp2p {
|
||||
- `key`: Buffer
|
||||
- `nVals`: Number
|
||||
|
||||
---------------------
|
||||
|
||||
`SOON™`
|
||||
|
||||
#### `libp2p.findPeers`
|
||||
|
||||
#### `libp2p.findProviders`
|
||||
|
||||
#### `libp2p.record.put`
|
||||
|
||||
#### `libp2p.record.get`
|
||||
|
||||
[PeerInfo]: https://github.com/libp2p/js-peer-info
|
||||
[PeerId]: https://github.com/libp2p/js-peer-id
|
||||
[PeerBook]: https://github.com/libp2p/js-peer-book
|
||||
[multiaddr]: https://github.com/multiformats/js-multiaddr
|
||||
[Connection]: https://github.com/libp2p/interface-connection
|
||||
|
||||
## Development
|
||||
|
||||
**Clone and install dependencies:**
|
||||
|
||||
```sh
|
||||
> git clone https://github.com/ipfs/js-ipfs.git
|
||||
> cd js-ipfs
|
||||
> npm install
|
||||
```
|
||||
|
||||
### Tests
|
||||
|
||||
#### Run unit tests
|
||||
|
||||
```sh
|
||||
# run all the unit tsts
|
||||
> npm test
|
||||
|
||||
# run just Node.js tests
|
||||
> npm run test:node
|
||||
|
||||
# run just Browser tests (Chrome)
|
||||
> npm run test:browser
|
||||
```
|
||||
|
||||
#### Run interop tests
|
||||
|
||||
```sh
|
||||
N/A
|
||||
```
|
||||
|
||||
#### Run benchmark tests
|
||||
|
||||
```sh
|
||||
N/A
|
||||
```
|
||||
|
||||
### Packages
|
||||
|
||||
@ -278,6 +320,8 @@ List of packages currently in existence for libp2p
|
||||
| [`libp2p-utp`](//github.com/libp2p/js-libp2p-utp) | [](//github.com/libp2p/js-libp2p-utp/releases) | [](https://david-dm.org/libp2p/js-libp2p-utp) | [](https://david-dm.org/libp2p/js-libp2p-utp?type=dev) |
|
||||
| [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [](//github.com/libp2p/js-libp2p-websockets/releases) | [](https://david-dm.org/libp2p/js-libp2p-websockets) | [](https://david-dm.org/libp2p/js-libp2p-websockets?type=dev) |
|
||||
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [](https://david-dm.org/libp2p/js-libp2p-webrtc-star?type=dev) |
|
||||
| [`libp2p-websocket-star`](//github.com/libp2p/js-libp2p-websocket-star) | [](//github.com/libp2p/js-libp2p-websocket-star/releases) | [](https://david-dm.org/libp2p/js-libp2p-websocket-star) | [](https://david-dm.org/libp2p/js-libp2p-websocket-star?type=dev) |
|
||||
| [`libp2p-websocket-star-rendezvous`](//github.com/libp2p/js-libp2p-websocket-star-rendezvous) | [](//github.com/libp2p/js-libp2p-websocket-star-rendezvous/releases) | [](https://david-dm.org/libp2p/js-libp2p-websocket-star-rendezvous) | [](https://david-dm.org/libp2p/js-libp2p-websocket-star-rendezvous?type=dev) |
|
||||
| **Connection Upgrades** |
|
||||
| [`interface-connection`](//github.com/libp2p/interface-connection) | [](//github.com/libp2p/interface-connection/releases) | [](https://david-dm.org/libp2p/interface-connection) | [](https://david-dm.org/libp2p/interface-connection?type=dev) |
|
||||
| **Stream Muxers** |
|
||||
@ -308,7 +352,7 @@ List of packages currently in existence for libp2p
|
||||
|
||||
The libp2p implementation in JavaScript is a work in progress. As such, there are a few things you can do right now to help out:
|
||||
|
||||
- Go through the modules and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrasture behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically.
|
||||
- Go through the modules and **check out existing issues**. This would be especially useful for modules in active development. Some knowledge of IPFS/libp2p may be required, as well as the infrastructure behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically.
|
||||
- **Perform code reviews**. Most of this has been developed by @diasdavid, which means that more eyes will help a) speed the project along b) ensure quality and c) reduce possible future bugs.
|
||||
- **Add tests**. There can never be enough tests.
|
||||
|
||||
|
29
appveyor.yml
Normal file
29
appveyor.yml
Normal 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
2
ci/Jenkinsfile
vendored
Normal 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()
|
12
circle.yml
12
circle.yml
@ -5,8 +5,14 @@ machine:
|
||||
dependencies:
|
||||
pre:
|
||||
- google-chrome --version
|
||||
- wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
|
||||
- sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
|
||||
- curl -L -o google-chrome.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
|
||||
- for v in $(curl http://archive.ubuntu.com/ubuntu/pool/main/n/nss/ | grep "href=" | grep "libnss3.*deb\"" -o | grep -o "libnss3.*deb" | grep "3.28" | grep "14.04"); do curl -L -o $v http://archive.ubuntu.com/ubuntu/pool/main/n/nss/$v; done && rm libnss3-tools*_i386.deb libnss3-dev*_i386.deb
|
||||
- sudo dpkg -i google-chrome.deb || true
|
||||
- sudo dpkg -i libnss3*.deb || true
|
||||
- sudo apt-get update
|
||||
- sudo apt-get --only-upgrade install google-chrome-stable
|
||||
- sudo apt-get install -f || true
|
||||
- sudo dpkg -i libnss3*.deb
|
||||
- sudo apt-get install -f
|
||||
- sudo apt-get install --only-upgrade lsb-base
|
||||
- sudo dpkg -i google-chrome.deb
|
||||
- google-chrome --version
|
@ -10,8 +10,8 @@ Let us know if you find any issue or if you want to contribute and add a new tut
|
||||
- [Protocol and Stream Muxing](./protocol-and-stream-muxing)
|
||||
- [Encrypted Communications](./encrypted-communications)
|
||||
- [Discovery Mechanisms](./discovery-mechanisms)
|
||||
- [Peer Routing](./peer-routing)
|
||||
- [Content Routing](./content-routing)
|
||||
- [Peer Routing](./peer-and-content-routing)
|
||||
- [Content Routing](./peer-and-content-routing)
|
||||
- [PubSub](./pubsub)
|
||||
- [NAT Traversal](./nat-traversal)
|
||||
- Circuit Relay (future)
|
||||
@ -23,4 +23,3 @@ Let us know if you find any issue or if you want to contribute and add a new tut
|
||||
- Running libp2p in the Electron (future)
|
||||
- [The standard echo net example with libp2p](./echo)
|
||||
- [A simple chat app with](./chat)
|
||||
- [See other nodes in the network using WebRTC Star discovery mechanism](./see-nodes)
|
||||
|
@ -30,12 +30,12 @@ async.parallel([
|
||||
], (err, ids) => {
|
||||
if (err) throw err
|
||||
const peerDialer = new PeerInfo(ids[0])
|
||||
peerDialer.multiaddr.add('/ip4/0.0.0.0/tcp/0')
|
||||
peerDialer.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
|
||||
const nodeDialer = new Node(peerDialer)
|
||||
|
||||
const peerListener = new PeerInfo(ids[1])
|
||||
idListener = ids[1]
|
||||
peerListener.multiaddr.add('/ip4/127.0.0.1/tcp/10333')
|
||||
peerListener.multiaddrs.add('/ip4/127.0.0.1/tcp/10333')
|
||||
nodeDialer.start((err) => {
|
||||
if (err) {
|
||||
throw err
|
||||
@ -47,7 +47,7 @@ async.parallel([
|
||||
console.log(ma.toString() + '/ipfs/' + idListener.toB58String())
|
||||
})
|
||||
|
||||
nodeDialer.dialByPeerInfo(peerListener, '/chat/1.0.0', (err, conn) => {
|
||||
nodeDialer.dialProtocol(peerListener, '/chat/1.0.0', (err, conn) => {
|
||||
if (err) {
|
||||
throw err
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ const spdy = require('libp2p-spdy')
|
||||
const KadDHT = require('libp2p-kad-dht')
|
||||
const multiplex = require('libp2p-multiplex')
|
||||
const secio = require('libp2p-secio')
|
||||
const libp2p = require('../..')
|
||||
const libp2p = require('../../..')
|
||||
|
||||
function mapMuxers (list) {
|
||||
return list.map((pref) => {
|
||||
|
@ -13,7 +13,7 @@ PeerId.createFromJSON(require('./peer-id-listener'), (err, idListener) => {
|
||||
throw err
|
||||
}
|
||||
const peerListener = new PeerInfo(idListener)
|
||||
peerListener.multiaddr.add('/ip4/0.0.0.0/tcp/10333')
|
||||
peerListener.multiaddrs.add('/ip4/0.0.0.0/tcp/10333')
|
||||
const nodeListener = new Node(peerListener)
|
||||
|
||||
nodeListener.start((err) => {
|
||||
|
@ -20,7 +20,7 @@ async.parallel([
|
||||
// Dialer
|
||||
const dialerId = ids[0]
|
||||
const dialerPeerInfo = new PeerInfo(dialerId)
|
||||
dialerPeerInfo.multiaddr.add('/ip4/0.0.0.0/tcp/0')
|
||||
dialerPeerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
|
||||
const dialerNode = new Node(dialerPeerInfo)
|
||||
|
||||
// Peer to Dial
|
||||
@ -28,7 +28,7 @@ async.parallel([
|
||||
const listenerId = ids[1]
|
||||
const listenerMultiaddr = '/ip4/127.0.0.1/tcp/10333/ipfs/' +
|
||||
listenerId.toB58String()
|
||||
listenerPeerInfo.multiaddr.add(listenerMultiaddr)
|
||||
listenerPeerInfo.multiaddrs.add(listenerMultiaddr)
|
||||
|
||||
dialerNode.start((err) => {
|
||||
if (err) { throw err }
|
||||
@ -38,7 +38,7 @@ async.parallel([
|
||||
'/ipfs/' + dialerId.toB58String()))
|
||||
|
||||
console.log('Dialing to peer:', listenerMultiaddr.toString())
|
||||
dialerNode.dialByPeerInfo(listenerPeerInfo, '/echo/1.0.0', (err, conn) => {
|
||||
dialerNode.dialProtocol(listenerPeerInfo, '/echo/1.0.0', (err, conn) => {
|
||||
if (err) { throw err }
|
||||
|
||||
console.log('nodeA dialed to nodeB on protocol: /echo/1.0.0')
|
||||
|
@ -24,7 +24,7 @@ series([
|
||||
},
|
||||
(cb) => {
|
||||
const listenerPeerInfo = new PeerInfo(listenerId)
|
||||
listenerPeerInfo.multiaddr.add('/ip4/0.0.0.0/tcp/10333')
|
||||
listenerPeerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/10333')
|
||||
listenerNode = new Node(listenerPeerInfo)
|
||||
|
||||
listenerNode.swarm.on('peer-mux-established', (peerInfo) => {
|
||||
|
@ -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 }
|
||||
pull(pull.values(['This information is sent out encrypted to the other peer']), conn)
|
||||
})
|
||||
|
@ -32,7 +32,7 @@ class MyBundle extends libp2p {
|
||||
}
|
||||
```
|
||||
|
||||
And that's it, from now on, all your libp2p communications are encrypted. Try running the exampme [1.js](./1.js) to see it working.
|
||||
And that's it, from now on, all your libp2p communications are encrypted. Try running the example [1.js](./1.js) to see it working.
|
||||
|
||||
If you want to want to learn more about how SECIO works, you can read the [great write up done by Dominic Tarr](https://github.com/auditdrivencrypto/secure-channel/blob/master/prior-art.md#ipfss-secure-channel).
|
||||
|
||||
|
@ -10,20 +10,20 @@
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"browserify": "^14.0.0",
|
||||
"browserify": "^14.5.0",
|
||||
"concat-stream": "^1.6.0",
|
||||
"detect-dom-ready": "^1.0.2",
|
||||
"node-static": "^0.7.9"
|
||||
"node-static": "^0.7.10"
|
||||
},
|
||||
"dependencies": {
|
||||
"detect-dom-ready": "^1.0.2",
|
||||
"libp2p": "^0.10.0",
|
||||
"libp2p-multiplex": "^0.4.4",
|
||||
"libp2p-railing": "^0.5.2",
|
||||
"libp2p-secio": "^0.6.8",
|
||||
"libp2p-spdy": "^0.10.6",
|
||||
"libp2p-webrtc-star": "^0.11.0",
|
||||
"libp2p-websockets": "^0.10.0",
|
||||
"peer-info": "^0.9.3"
|
||||
"libp2p": "^0.13.0",
|
||||
"libp2p-multiplex": "^0.5.0",
|
||||
"libp2p-railing": "^0.7.1",
|
||||
"libp2p-secio": "^0.8.1",
|
||||
"libp2p-spdy": "^0.11.0",
|
||||
"libp2p-webrtc-star": "^0.13.2",
|
||||
"libp2p-websockets": "^0.10.4",
|
||||
"peer-info": "^0.11.0"
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,9 @@ const bootstrapers = [
|
||||
'/dns4/sfo-3.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
|
||||
'/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
|
||||
'/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
|
||||
'/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64'
|
||||
'/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
|
||||
'/dns4/wss0.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
|
||||
'/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6'
|
||||
]
|
||||
|
||||
class Node extends libp2p {
|
||||
|
@ -10,7 +10,7 @@ function createNode (callback) {
|
||||
}
|
||||
|
||||
const peerIdStr = peerInfo.id.toB58String()
|
||||
const ma = `/libp2p-webrtc-star/dns4/star-signal.cloud.ipfs.team/wss/ipfs/${peerIdStr}`
|
||||
const ma = `/dns4/star-signal.cloud.ipfs.team/tcp/443/wss/p2p-webrtc-star/ipfs/${peerIdStr}`
|
||||
|
||||
peerInfo.multiaddrs.add(ma)
|
||||
|
||||
|
@ -12,3 +12,5 @@ Simple go into the folder [1](./1) and execute the following
|
||||
> npm start
|
||||
# open your browser in port :9090
|
||||
```
|
||||
|
||||
[Version Published on IPFS](http://ipfs.io/ipfs/Qmbc1J7ehw1dNYachbkCWPto4RsnVvqCKNVzmYEod2gXcy)
|
||||
|
67
examples/peer-and-content-routing/1.js
Normal file
67
examples/peer-and-content-routing/1.js
Normal file
@ -0,0 +1,67 @@
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('libp2p')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const Multiplex = require('libp2p-multiplex')
|
||||
const SECIO = require('libp2p-secio')
|
||||
const PeerInfo = require('peer-info')
|
||||
const KadDHT = require('libp2p-kad-dht')
|
||||
|
||||
const waterfall = require('async/waterfall')
|
||||
const parallel = require('async/parallel')
|
||||
|
||||
class MyBundle extends libp2p {
|
||||
constructor (peerInfo) {
|
||||
const modules = {
|
||||
transport: [new TCP()],
|
||||
connection: {
|
||||
muxer: [Multiplex],
|
||||
crypto: [SECIO]
|
||||
},
|
||||
// we add the DHT module that will enable Peer and Content Routing
|
||||
DHT: KadDHT
|
||||
}
|
||||
super(modules, peerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
function createNode (callback) {
|
||||
let node
|
||||
|
||||
waterfall([
|
||||
(cb) => PeerInfo.create(cb),
|
||||
(peerInfo, cb) => {
|
||||
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
|
||||
node = new MyBundle(peerInfo)
|
||||
node.start(cb)
|
||||
}
|
||||
], (err) => callback(err, node))
|
||||
}
|
||||
|
||||
parallel([
|
||||
(cb) => createNode(cb),
|
||||
(cb) => createNode(cb),
|
||||
(cb) => createNode(cb)
|
||||
], (err, nodes) => {
|
||||
if (err) { throw err }
|
||||
|
||||
const node1 = nodes[0]
|
||||
const node2 = nodes[1]
|
||||
const node3 = nodes[2]
|
||||
|
||||
parallel([
|
||||
(cb) => node1.dial(node2.peerInfo, cb),
|
||||
(cb) => node2.dial(node3.peerInfo, cb),
|
||||
// Set up of the cons might take time
|
||||
(cb) => setTimeout(cb, 300)
|
||||
], (err) => {
|
||||
if (err) { throw err }
|
||||
|
||||
node1.peerRouting.findPeer(node3.peerInfo.id, (err, peer) => {
|
||||
if (err) { throw err }
|
||||
|
||||
console.log('Found it, multiaddrs are:')
|
||||
peer.multiaddrs.forEach((ma) => console.log(ma.toString()))
|
||||
})
|
||||
})
|
||||
})
|
75
examples/peer-and-content-routing/2.js
Normal file
75
examples/peer-and-content-routing/2.js
Normal file
@ -0,0 +1,75 @@
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('libp2p')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const Multiplex = require('libp2p-multiplex')
|
||||
const SECIO = require('libp2p-secio')
|
||||
const PeerInfo = require('peer-info')
|
||||
const CID = require('cids')
|
||||
const KadDHT = require('libp2p-kad-dht')
|
||||
|
||||
const waterfall = require('async/waterfall')
|
||||
const parallel = require('async/parallel')
|
||||
|
||||
class MyBundle extends libp2p {
|
||||
constructor (peerInfo) {
|
||||
const modules = {
|
||||
transport: [new TCP()],
|
||||
connection: {
|
||||
muxer: [Multiplex],
|
||||
crypto: [SECIO]
|
||||
},
|
||||
// we add the DHT module that will enable Peer and Content Routing
|
||||
DHT: KadDHT
|
||||
}
|
||||
super(modules, peerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
function createNode (callback) {
|
||||
let node
|
||||
|
||||
waterfall([
|
||||
(cb) => PeerInfo.create(cb),
|
||||
(peerInfo, cb) => {
|
||||
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
|
||||
node = new MyBundle(peerInfo)
|
||||
node.start(cb)
|
||||
}
|
||||
], (err) => callback(err, node))
|
||||
}
|
||||
|
||||
parallel([
|
||||
(cb) => createNode(cb),
|
||||
(cb) => createNode(cb),
|
||||
(cb) => createNode(cb)
|
||||
], (err, nodes) => {
|
||||
if (err) { throw err }
|
||||
|
||||
const node1 = nodes[0]
|
||||
const node2 = nodes[1]
|
||||
const node3 = nodes[2]
|
||||
|
||||
parallel([
|
||||
(cb) => node1.dial(node2.peerInfo, cb),
|
||||
(cb) => node2.dial(node3.peerInfo, cb),
|
||||
// Set up of the cons might take time
|
||||
(cb) => setTimeout(cb, 300)
|
||||
], (err) => {
|
||||
if (err) { throw err }
|
||||
|
||||
const cid = new CID('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL')
|
||||
|
||||
node1.contentRouting.provide(cid, (err) => {
|
||||
if (err) { throw err }
|
||||
|
||||
console.log('Node %s is providing %s', node1.peerInfo.id.toB58String(), cid.toBaseEncodedString())
|
||||
|
||||
node3.contentRouting.findProviders(cid, 5000, (err, providers) => {
|
||||
if (err) { throw err }
|
||||
|
||||
console.log('Found provider:', providers[0].id.toB58String())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
106
examples/peer-and-content-routing/README.md
Normal file
106
examples/peer-and-content-routing/README.md
Normal file
@ -0,0 +1,106 @@
|
||||
# Peer and Content Routing
|
||||
|
||||
DHTs (Distributed Hash Tables) are one of the most common building blocks used when creating P2P networks. However, the name doesn't make justice to all the benefits it brings and putting the whole set of features in one box has proven to be limiting when we want to integrate multiple pieces together. With this in mind, we've come up with a new definition for what a DHT offers: Peer Routing and Content Routing.
|
||||
|
||||
Peer Routing is the category of modules that offer a way to find other peers in the network by intentionally issuing queries, iterative or recursive, until a Peer is found or the closest Peers, given the Peer Routing algorithm strategy are found.
|
||||
|
||||
Content Routing is the category of modules that offer a way to find where content lives in the network, it works in two steps: 1) Peers provide (announce) to the network that they are holders of specific content (multihashes) and 2) Peers issue queries to find where that content lives. A Content Routing mechanism could be as complex as a Kademlia DHT or a simple registry somewhere in the network.
|
||||
|
||||
# 1. Using Peer Routing to find other peers
|
||||
|
||||
This example builds on top of the [Protocol and Stream Muxing](../protocol-and-stream-muxing). We need to install `libp2p-kad-dht`, go ahead and `npm install libp2p-kad-dht`. If you want to see the final version, open [1.js](./1.js).
|
||||
|
||||
First, let's update our bundle to support Peer Routing and Content Routing.
|
||||
|
||||
```JavaScript
|
||||
class MyBundle extends libp2p {
|
||||
constructor (peerInfo) {
|
||||
const modules = {
|
||||
transport: [new TCP()],
|
||||
connection: {
|
||||
muxer: [Multiplex],
|
||||
crypto: [SECIO]
|
||||
},
|
||||
// we add the DHT module that will enable Peer and Content Routing
|
||||
DHT: KadDHT
|
||||
}
|
||||
super(modules, peerInfo)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Once that is done, we can use the createNode function we developed in the previous example to create 3 nodes. Connect node 1 to node 2 and node 2 to node 3. We will use node 2 as a way to find the whereabouts of node 3
|
||||
|
||||
```JavaScript
|
||||
const node1 = nodes[0]
|
||||
const node2 = nodes[1]
|
||||
const node3 = nodes[2]
|
||||
|
||||
parallel([
|
||||
(cb) => node1.dial(node2.peerInfo, cb),
|
||||
(cb) => node2.dial(node3.peerInfo, cb),
|
||||
// Set up of the cons might take time
|
||||
(cb) => setTimeout(cb, 100)
|
||||
], (err) => {
|
||||
if (err) { throw err }
|
||||
|
||||
//
|
||||
node1.peerRouting.findPeer(node3.peerInfo.id, (err, peer) => {
|
||||
if (err) { throw err }
|
||||
|
||||
console.log('Found it, multiaddrs are:')
|
||||
peer.multiaddrs.forEach((ma) => console.log(ma.toString()))
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
You should see the output being something like:
|
||||
|
||||
```Bash
|
||||
> node 1.js
|
||||
Found it, multiaddrs are:
|
||||
/ip4/127.0.0.1/tcp/63617/ipfs/QmWrFXvZr9S4iDqycyoyc2zDdrT1jg9wpdenUTdd1LTar6
|
||||
/ip4/192.168.86.41/tcp/63617/ipfs/QmWrFXvZr9S4iDqycyoyc2zDdrT1jg9wpdenUTdd1LTar6
|
||||
```
|
||||
|
||||
You have successfully used Peer Routing to find a peer that you were not directly connected. Now all you have to do is to dial to the multiaddrs you discovered.
|
||||
|
||||
# 2. Using Content Routing to find providers of content
|
||||
|
||||
With Content Routing, you can create records that are stored in multiple points in the network, these records can be resolved by you or other peers and they act as memos or rendezvous points. A great usage of this feature is to support discovery of content, where one node holds a file and instead of using a centralized tracker to inform other nodes that it holds that file, it simply puts a record in the network that can be resolved by other peers. Peer Routing and Content Routing are commonly known as Distributed Hash Tables, DHT.
|
||||
|
||||
You can find this example completed in [2.js](./2.js), however as you will see it is very simple to update the previous example.
|
||||
|
||||
Instead of calling `peerRouting.findPeer`, we will use `contentRouting.provide` and `contentRouting.findProviders`.
|
||||
|
||||
```JavaScript
|
||||
node1.contentRouting.provide(cid, (err) => {
|
||||
if (err) { throw err }
|
||||
|
||||
console.log('Node %s is providing %s', node1.peerInfo.id.toB58String(), cid.toBaseEncodedString())
|
||||
|
||||
node3.contentRouting.findProviders(cid, 5000, (err, providers) => {
|
||||
if (err) { throw err }
|
||||
|
||||
console.log('Found provider:', providers[0].id.toB58String())
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
The output of your program should look like:
|
||||
|
||||
```bash
|
||||
> node 2.js
|
||||
Node QmSsmVPoTy3WpzwiNPnsKmonBaZjK2HitFs2nWUvwK31Pz is providing QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL
|
||||
Found provider: QmSsmVPoTy3WpzwiNPnsKmonBaZjK2HitFs2nWUvwK31Pz
|
||||
```
|
||||
|
||||
That's it, now you know how to find peers that have pieces of information that interest you!
|
||||
|
||||
# 3. Future Work
|
||||
|
||||
Currently, the only mechanisms for Peer and Content Routing come from the DHT, however we do have the intention to support:
|
||||
|
||||
- Multiple Peer Routing Mechanisms, including ones that do recursive searches (i.e [webrtc-explorer](http://daviddias.me/blog/webrtc-explorer-2-0-0-alpha-release/) like packet switching or [CJDNS](https://github.com/cjdelisle/cjdns) path finder)
|
||||
- Content Routing via PubSub
|
||||
- Content Routing via centralized index (i.e a tracker)
|
@ -1,2 +0,0 @@
|
||||
# WIP - This example is still in the works
|
||||

|
@ -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 }
|
||||
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 }
|
||||
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 }
|
||||
pull(pull.values(['do I fall into your criteria?']), conn)
|
||||
})
|
||||
|
@ -60,17 +60,17 @@ parallel([
|
||||
})
|
||||
|
||||
series([
|
||||
(cb) => node1.dial(node2.peerInfo, '/a', (err, conn) => {
|
||||
(cb) => node1.dialProtocol(node2.peerInfo, '/a', (err, conn) => {
|
||||
if (err) { throw err }
|
||||
pull(pull.values(['protocol (a)']), conn)
|
||||
cb()
|
||||
}),
|
||||
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => {
|
||||
(cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
|
||||
if (err) { throw err }
|
||||
pull(pull.values(['protocol (b)']), conn)
|
||||
cb()
|
||||
}),
|
||||
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => {
|
||||
(cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
|
||||
if (err) { throw err }
|
||||
pull(pull.values(['another conn on protocol (b)']), conn)
|
||||
cb()
|
||||
|
@ -30,7 +30,7 @@ node2.handle('/your-protocol', (protocol, conn) => {
|
||||
After the protocol is _handled_, now we can dial to it.
|
||||
|
||||
```JavaScript
|
||||
node1.dial(node2.peerInfo, '/your-protocol', (err, conn) => {
|
||||
node1.dialProtocol(node2.peerInfo, '/your-protocol', (err, conn) => {
|
||||
if (err) { throw err }
|
||||
pull(pull.values(['my own protocol, wow!']), conn)
|
||||
})
|
||||
@ -47,7 +47,7 @@ node2.handle('/another-protocol/1.0.1', (protocol, conn) => {
|
||||
)
|
||||
})
|
||||
// ...
|
||||
node1.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 }
|
||||
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 }
|
||||
pull(pull.values(['do I fall into your criteria?']), conn)
|
||||
})
|
||||
@ -129,17 +129,17 @@ node2.handle('/b', (protocol, conn) => {
|
||||
})
|
||||
|
||||
series([
|
||||
(cb) => node1.dial(node2.peerInfo, '/a', (err, conn) => {
|
||||
(cb) => node1.dialProtocol(node2.peerInfo, '/a', (err, conn) => {
|
||||
if (err) { throw err }
|
||||
pull(pull.values(['protocol (a)']), conn)
|
||||
cb()
|
||||
}),
|
||||
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => {
|
||||
(cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
|
||||
if (err) { throw err }
|
||||
pull(pull.values(['protocol (b)']), conn)
|
||||
cb()
|
||||
}),
|
||||
(cb) => node1.dial(node2.peerInfo, '/b', (err, conn) => {
|
||||
(cb) => node1.dialProtocol(node2.peerInfo, '/b', (err, conn) => {
|
||||
if (err) { throw err }
|
||||
pull(pull.values(['another conn on protocol (b)']), conn)
|
||||
cb()
|
||||
@ -158,9 +158,9 @@ another protocol (b)
|
||||
|
||||
# 3. Bidirectional connections
|
||||
|
||||
There is one last trick on _protocol and stream multiplexing_ that libp2p uses to make everyone's life easier and that is _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:
|
||||
|
||||
|
68
examples/pubsub/1.js
Normal file
68
examples/pubsub/1.js
Normal file
@ -0,0 +1,68 @@
|
||||
'use strict'
|
||||
|
||||
const libp2p = require('libp2p')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const Multiplex = require('libp2p-multiplex')
|
||||
const SECIO = require('libp2p-secio')
|
||||
const PeerInfo = require('peer-info')
|
||||
const MulticastDNS = require('libp2p-mdns')
|
||||
const FloodSub = require('libp2p-floodsub')
|
||||
const waterfall = require('async/waterfall')
|
||||
const parallel = require('async/parallel')
|
||||
const series = require('async/series')
|
||||
|
||||
class MyBundle extends libp2p {
|
||||
constructor (peerInfo) {
|
||||
const modules = {
|
||||
transport: [new TCP()],
|
||||
connection: {
|
||||
muxer: [Multiplex],
|
||||
crypto: [SECIO]
|
||||
},
|
||||
discovery: [new MulticastDNS(peerInfo, { interval: 2000 })]
|
||||
}
|
||||
super(modules, peerInfo)
|
||||
}
|
||||
}
|
||||
|
||||
function createNode (callback) {
|
||||
let node
|
||||
|
||||
waterfall([
|
||||
(cb) => PeerInfo.create(cb),
|
||||
(peerInfo, cb) => {
|
||||
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
|
||||
node = new MyBundle(peerInfo)
|
||||
node.start(cb)
|
||||
}
|
||||
], (err) => callback(err, node))
|
||||
}
|
||||
|
||||
parallel([
|
||||
(cb) => createNode(cb),
|
||||
(cb) => createNode(cb)
|
||||
], (err, nodes) => {
|
||||
if (err) { throw err }
|
||||
|
||||
const node1 = nodes[0]
|
||||
const node2 = nodes[1]
|
||||
|
||||
const fs1 = new FloodSub(node1)
|
||||
const fs2 = new FloodSub(node2)
|
||||
|
||||
series([
|
||||
(cb) => fs1.start(cb),
|
||||
(cb) => fs2.start(cb),
|
||||
(cb) => node1.once('peer:discovery', (peer) => node1.dial(peer, cb)),
|
||||
(cb) => setTimeout(cb, 500)
|
||||
], (err) => {
|
||||
if (err) { throw err }
|
||||
|
||||
fs2.on('news', (msg) => console.log(msg.from, msg.data.toString()))
|
||||
fs2.subscribe('news')
|
||||
|
||||
setInterval(() => {
|
||||
fs1.publish('news', Buffer.from('Bird bird bird, bird is the word!'))
|
||||
}, 1000)
|
||||
})
|
||||
})
|
@ -1,2 +1,60 @@
|
||||
# WIP - This example is still in the works
|
||||

|
||||
# 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.
|
||||
|
||||
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:
|
||||
|
||||
- [Collaborative Text Editing](https://www.youtube.com/watch?v=-kdx8rJd8rQ)
|
||||
- [IPFS PubSub (using libp2p-floodsub) for IoT](https://www.youtube.com/watch?v=qLpM5pBDGiE).
|
||||
- [Real Time distributed Applications](https://www.youtube.com/watch?v=vQrbxyDPSXg)
|
||||
|
||||
## 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).
|
||||
|
||||
Getting PubSub is super simple, all you have to do is require the FloodSub module and pass it in a libp2p node, once you have done that you can start subscribing and publishing in any topic.
|
||||
|
||||
```JavaScript
|
||||
const FloodSub = require('libp2p-floodsub')
|
||||
|
||||
const fs1 = new FloodSub(node1)
|
||||
const fs2 = new FloodSub(node2)
|
||||
|
||||
series([
|
||||
(cb) => fs1.start(cb),
|
||||
(cb) => fs2.start(cb),
|
||||
(cb) => node1.once('peer:discovery', (peer) => node1.dial(peer, cb)),
|
||||
(cb) => setTimeout(cb, 500)
|
||||
], (err) => {
|
||||
if (err) { throw err }
|
||||
|
||||
fs2.on('news', (msg) => console.log(msg.from, msg.data.toString()))
|
||||
fs2.subscribe('news')
|
||||
|
||||
setInterval(() => {
|
||||
fs1.publish('news', Buffer.from('Bird bird bird, bird is the word!'))
|
||||
}, 1000)
|
||||
})
|
||||
```
|
||||
|
||||
The output of the program should look like:
|
||||
|
||||
```
|
||||
> node 1.js
|
||||
QmWpvkKm6qHLhoxpWrTswY6UMNWDyn8hN265Qp9ZYvgS82 Bird bird bird, bird is the word!
|
||||
QmWpvkKm6qHLhoxpWrTswY6UMNWDyn8hN265Qp9ZYvgS82 Bird bird bird, bird is the word!
|
||||
QmWpvkKm6qHLhoxpWrTswY6UMNWDyn8hN265Qp9ZYvgS82 Bird bird bird, bird is the word!
|
||||
QmWpvkKm6qHLhoxpWrTswY6UMNWDyn8hN265Qp9ZYvgS82 Bird bird bird, bird is the word!
|
||||
QmWpvkKm6qHLhoxpWrTswY6UMNWDyn8hN265Qp9ZYvgS82 Bird bird bird, bird is the word!
|
||||
```
|
||||
|
||||
## 2. Future work
|
||||
|
||||
libp2p/IPFS PubSub is enabling a whole set of Distributed Real Time applications using CRDT (Conflict-Free Replicated Data Types). It is still going through heavy research (and hacking) and we invite you to join the conversation at [research-CRDT](https://github.com/ipfs/research-CRDT). Here is a list of some of the exciting examples:
|
||||
|
||||
- [PubSub Room](https://github.com/ipfs-labs/ipfs-pubsub-room)
|
||||
- [Live DB - A always in Sync DB using CRDT](https://github.com/ipfs-labs/ipfs-live-db)
|
||||
- [IIIF Annotations over IPFS, CRDT and libp2p](https://www.youtube.com/watch?v=hmAniA6g9D0&feature=youtu.be&t=10m40s)
|
||||
- [orbit.chat - p2p chat application, fully running in the browser with js-ipfs, js-libp2p and orbit-db](http://orbit.chat/)
|
||||
|
@ -26,7 +26,7 @@ waterfall([
|
||||
], (err) => {
|
||||
if (err) { throw err }
|
||||
|
||||
console.log('node has started (true/false):', node.isOn())
|
||||
console.log('node has started (true/false):', node.isStarted())
|
||||
console.log('listening on:')
|
||||
node.peerInfo.multiaddrs.forEach((ma) => console.log(ma.toString()))
|
||||
})
|
||||
|
@ -54,7 +54,7 @@ parallel([
|
||||
)
|
||||
})
|
||||
|
||||
node1.dial(node2.peerInfo, '/print', (err, conn) => {
|
||||
node1.dialProtocol(node2.peerInfo, '/print', (err, conn) => {
|
||||
if (err) { throw err }
|
||||
|
||||
pull(pull.values(['Hello', ' ', 'p2p', ' ', 'world', '!']), conn)
|
||||
|
@ -66,19 +66,19 @@ parallel([
|
||||
node2.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 }
|
||||
|
||||
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 }
|
||||
|
||||
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) {
|
||||
console.log('node 3 failed to dial to node 1 with:', err.message)
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ A more complete definition of what is a transport can be found on the [interface
|
||||
|
||||
## 1. Creating a libp2p Bundle with TCP
|
||||
|
||||
When using libp2p, you always want to create your own libp2p Bundle, that is, pick your set of modules and create your network stack with the properties you need. In this example, we will create a bundle with TCP. You can find the complete solution on the file [1.js](/1.js).
|
||||
When using libp2p, you always want to create your own libp2p Bundle, that is, pick your set of modules and create your network stack with the properties you need. In this example, we will create a bundle with TCP. You can find the complete solution on the file [1.js](./1.js).
|
||||
|
||||
You will need 4 deps total, so go ahead and install all of them with:
|
||||
|
||||
@ -65,7 +65,7 @@ waterfall([
|
||||
if (err) { throw err }
|
||||
|
||||
// At this point the node has started
|
||||
console.log('node has started (true/false):', node.isOn())
|
||||
console.log('node has started (true/false):', node.isStarted())
|
||||
// And we can print the now listening addresses.
|
||||
// If you are familiar with TCP, you might have noticed
|
||||
// that we specified the node to listen in 0.0.0.0 and port
|
||||
@ -90,7 +90,7 @@ That `QmW2cKTakTYqbQkUzBTEGXgWYFj1YEPeUndE1YWs6CBzDQ` is the PeerId that was cre
|
||||
|
||||
## 2. Dialing from one node to another node
|
||||
|
||||
Now that we have our bundle, let's create two nodes and make them dial to each other! You can find the complete solution at [2.js](/2.js).
|
||||
Now that we have our bundle, let's create two nodes and make them dial to each other! You can find the complete solution at [2.js](./2.js).
|
||||
|
||||
For this step, we will need one more dependency.
|
||||
|
||||
@ -143,7 +143,7 @@ parallel([
|
||||
)
|
||||
})
|
||||
|
||||
node1.dial(node2.peerInfo, '/print', (err, conn) => {
|
||||
node1.dialProtocol(node2.peerInfo, '/print', (err, conn) => {
|
||||
if (err) { throw err }
|
||||
|
||||
pull(pull.values(['Hello', ' ', 'p2p', ' ', 'world', '!']), conn)
|
||||
@ -168,7 +168,7 @@ Hello p2p world!
|
||||
|
||||
Next, we want to be available in multiple transports to increase our chances of having common transports in the network. A simple scenario, a node running in the browser only has access to HTTP, WebSockets and WebRTC since the browser doesn't let you open any other kind of transport, for this node to dial to some other node, that other node needs to share a common transport.
|
||||
|
||||
What we are going to do in this step is to create 3 nodes, one with TCP, another with TCP+WebSockets and another one with just WebSockets. The full solution can be found on [3.js](3.js).
|
||||
What we are going to do in this step is to create 3 nodes, one with TCP, another with TCP+WebSockets and another one with just WebSockets. The full solution can be found on [3.js](./3.js).
|
||||
|
||||
In this example, we will need to also install `libp2p-websockets`, go ahead and install:
|
||||
|
||||
@ -240,21 +240,21 @@ parallel([
|
||||
node3.handle('/print', print)
|
||||
|
||||
// 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 }
|
||||
|
||||
pull(pull.values(['node 1 dialed to node 2 successfully']), conn)
|
||||
})
|
||||
|
||||
// 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 }
|
||||
|
||||
pull(pull.values(['node 2 dialed to node 3 successfully']), conn)
|
||||
})
|
||||
|
||||
// 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) {
|
||||
console.log('node 3 failed to dial to node 1 with:', err.message)
|
||||
}
|
||||
@ -298,8 +298,8 @@ As expected, we created 3 nodes, node 1 with TCP, node 2 with TCP+WebSockets and
|
||||
|
||||
Today there are already 3 transports available, one in the works and plenty to come, you can find these at [interface-transport implementations](https://github.com/libp2p/interface-transport#modules-that-implement-the-interface) list.
|
||||
|
||||
Adding more transports is done through the same way as you added TCP and WebSockets. Some transports might offer extra functionalities but 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.
|
||||
|
||||
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!
|
||||
|
55
gulpfile.js
55
gulpfile.js
@ -1,55 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const gulp = require('gulp')
|
||||
const Node = require('./test/nodejs-bundle/nodejs-bundle.js')
|
||||
const PeerInfo = require('peer-info')
|
||||
const PeerId = require('peer-id')
|
||||
const pull = require('pull-stream')
|
||||
|
||||
const sigServer = require('libp2p-webrtc-star/src/sig-server')
|
||||
let server
|
||||
|
||||
let node
|
||||
const rawPeer = require('./test/browser-bundle/peer.json')
|
||||
|
||||
gulp.task('libnode:start', (done) => {
|
||||
let count = 0
|
||||
const ready = () => ++count === 2 ? done() : null
|
||||
|
||||
sigServer.start({ port: 15555 }, (err, _server) => {
|
||||
if (err) {
|
||||
throw err
|
||||
}
|
||||
server = _server
|
||||
ready()
|
||||
})
|
||||
|
||||
PeerId.createFromJSON(rawPeer, (err, peerId) => {
|
||||
if (err) {
|
||||
return done(err)
|
||||
}
|
||||
const peer = new PeerInfo(peerId)
|
||||
|
||||
peer.multiaddrs.add('/ip4/127.0.0.1/tcp/9200/ws')
|
||||
|
||||
node = new Node(peer)
|
||||
node.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
|
||||
node.start(() => ready())
|
||||
})
|
||||
})
|
||||
|
||||
gulp.task('libnode:stop', (done) => {
|
||||
setTimeout(() => node.stop((err) => {
|
||||
if (err) {
|
||||
return done(err)
|
||||
}
|
||||
server.stop(done)
|
||||
}), 2000)
|
||||
})
|
||||
|
||||
gulp.task('test:browser:before', ['libnode:start'])
|
||||
gulp.task('test:node:before', ['libnode:start'])
|
||||
gulp.task('test:browser:after', ['libnode:stop'])
|
||||
gulp.task('test:node:after', ['libnode:stop'])
|
||||
|
||||
require('aegir/gulp')(gulp)
|
105
package.json
105
package.json
@ -1,19 +1,19 @@
|
||||
{
|
||||
"name": "libp2p",
|
||||
"version": "0.10.1",
|
||||
"version": "0.16.3",
|
||||
"description": "JavaScript base class for libp2p bundles",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"test": "gulp test",
|
||||
"test:node": "gulp test:node",
|
||||
"test:browser": "gulp test:browser --dom",
|
||||
"release": "gulp release --dom",
|
||||
"release-minor": "gulp release --type minor --dom",
|
||||
"release-major": "gulp release --type major --dom",
|
||||
"build": "gulp build",
|
||||
"lint": "aegir-lint",
|
||||
"coverage": "aegir-coverage",
|
||||
"coverage-publish": "aegir-coverage publish"
|
||||
"lint": "aegir lint",
|
||||
"build": "aegir build",
|
||||
"test": "aegir test -t node -t browser",
|
||||
"test:node": "aegir test -t node",
|
||||
"test:browser": "aegir test -t browser",
|
||||
"release": "aegir release -t node -t browser",
|
||||
"release-minor": "aegir release --type minor -t node -t browser",
|
||||
"release-major": "aegir release --type major -t node -t browser",
|
||||
"coverage": "aegir coverage",
|
||||
"coverage-publish": "aegir coverage --provider coveralls"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -23,10 +23,10 @@
|
||||
"IPFS"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0.0",
|
||||
"node": ">=6.0.0",
|
||||
"npm": ">=3.0.0"
|
||||
},
|
||||
"pre-commit": [
|
||||
"pre-push": [
|
||||
"lint",
|
||||
"test"
|
||||
],
|
||||
@ -36,47 +36,66 @@
|
||||
"url": "https://github.com/libp2p/js-libp2p/issues"
|
||||
},
|
||||
"homepage": "https://github.com/libp2p/js-libp2p",
|
||||
"dependencies": {
|
||||
"async": "^2.6.0",
|
||||
"libp2p-ping": "~0.6.0",
|
||||
"libp2p-switch": "~0.36.0",
|
||||
"mafmt": "^3.0.2",
|
||||
"multiaddr": "^3.0.2",
|
||||
"peer-book": "~0.5.4",
|
||||
"peer-id": "~0.10.5",
|
||||
"peer-info": "~0.11.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"aegir": "^11.0.2",
|
||||
"chai": "^4.0.2",
|
||||
"cids": "^0.5.0",
|
||||
"dirty-chai": "^2.0.0",
|
||||
"electron-webrtc": "^0.3.0",
|
||||
"libp2p-kad-dht": "^0.2.0",
|
||||
"libp2p-mdns": "^0.7.0",
|
||||
"libp2p-multiplex": "^0.4.4",
|
||||
"libp2p-railing": "^0.5.2",
|
||||
"libp2p-secio": "^0.6.8",
|
||||
"libp2p-spdy": "^0.10.6",
|
||||
"libp2p-swarm": "^0.29.2",
|
||||
"libp2p-tcp": "^0.10.1",
|
||||
"libp2p-webrtc-star": "^0.11.0",
|
||||
"libp2p-websockets": "^0.10.0",
|
||||
"aegir": "^12.4.0",
|
||||
"chai": "^4.1.2",
|
||||
"cids": "~0.5.2",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"electron-webrtc": "~0.3.0",
|
||||
"libp2p-circuit": "~0.1.4",
|
||||
"libp2p-kad-dht": "~0.6.3",
|
||||
"libp2p-mdns": "~0.9.2",
|
||||
"libp2p-multiplex": "~0.5.1",
|
||||
"libp2p-railing": "~0.7.1",
|
||||
"libp2p-secio": "~0.9.1",
|
||||
"libp2p-spdy": "~0.11.0",
|
||||
"libp2p-tcp": "~0.11.5",
|
||||
"libp2p-webrtc-star": "~0.13.3",
|
||||
"libp2p-websockets": "~0.10.4",
|
||||
"libp2p-websocket-star": "~0.7.2",
|
||||
"libp2p-websocket-star-rendezvous": "~0.2.2",
|
||||
"lodash.times": "^4.3.2",
|
||||
"mafmt": "^2.1.8",
|
||||
"pre-commit": "^1.2.2",
|
||||
"pull-goodbye": "0.0.2",
|
||||
"pull-serializer": "^0.3.2",
|
||||
"pull-stream": "^3.6.0",
|
||||
"pull-serializer": "~0.3.2",
|
||||
"pull-stream": "^3.6.1",
|
||||
"safe-buffer": "^5.1.1",
|
||||
"wrtc": "0.0.62"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "^2.5.0",
|
||||
"libp2p-ping": "~0.4.0",
|
||||
"libp2p-swarm": "~0.29.1",
|
||||
"mafmt": "^2.1.8",
|
||||
"multiaddr": "^2.3.0",
|
||||
"peer-book": "~0.4.0",
|
||||
"peer-id": "~0.8.7",
|
||||
"peer-info": "~0.9.2"
|
||||
"sinon": "^4.2.2",
|
||||
"wrtc": "0.0.65"
|
||||
},
|
||||
"contributors": [
|
||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||
"Chris Dostert <chrisdostert@users.noreply.github.com>",
|
||||
"Daijiro Wachi <daijiro.wachi@gmail.com>",
|
||||
"David Dias <daviddias.p@gmail.com>",
|
||||
"Dmitriy Ryajov <dryajov@gmail.com>",
|
||||
"Elven <mon.samuel@qq.com>",
|
||||
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
"Irakli Gozalishvili <rfobic@gmail.com>",
|
||||
"Joel Gustafson <joelg@mit.edu>",
|
||||
"John Rees <johnrees@users.noreply.github.com>",
|
||||
"Kevin Kwok <antimatter15@gmail.com>",
|
||||
"Lars Gierth <lgierth@users.noreply.github.com>",
|
||||
"Maciej Krüger <mkg20001@gmail.com>",
|
||||
"Nuno Nogueira <nunofmn@gmail.com>",
|
||||
"Pedro Teixeira <i@pgte.me>",
|
||||
"RasmusErik Voel Jensen <github@solsort.com>",
|
||||
"Richard Littauer <richard.littauer@gmail.com>",
|
||||
"Ryan Bell <ryan@piing.net>",
|
||||
"Tiago Alves <alvesjtiago@gmail.com>",
|
||||
"greenkeeperio-bot <support@greenkeeper.io>",
|
||||
"mayerwin <mayerwin@users.noreply.github.com>"
|
||||
"mayerwin <mayerwin@users.noreply.github.com>",
|
||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>"
|
||||
]
|
||||
}
|
3
pdd/README.md
Normal file
3
pdd/README.md
Normal 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
20
pdd/package.json
Normal 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"
|
||||
}
|
||||
}
|
104
pdd/pdd-the-ipfs-bundle--story-1--peer-a.js
Normal file
104
pdd/pdd-the-ipfs-bundle--story-1--peer-a.js
Normal 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')))
|
||||
})
|
||||
})
|
98
pdd/pdd-the-ipfs-bundle--story-1--peer-b.js
Normal file
98
pdd/pdd-the-ipfs-bundle--story-1--peer-b.js
Normal 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')))
|
||||
})
|
||||
})
|
0
pdd/pdd-the-ipfs-bundle--story-2--peer-a.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-2--peer-a.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-2--peer-b.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-2--peer-b.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-3--peer-a.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-3--peer-a.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-3--peer-b.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-3--peer-b.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-3--peer-c.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-3--peer-c.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-4--peer-a.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-4--peer-a.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-4--peer-b.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-4--peer-b.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-4--peer-c.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-4--peer-c.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-4--peer-d.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-4--peer-d.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-4--peer-e.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-4--peer-e.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-5--peer-a.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-5--peer-a.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-5--peer-b.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-5--peer-b.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-5--peer-c.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-5--peer-c.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-5--peer-d.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-5--peer-d.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-5--peer-e.js
Normal file
0
pdd/pdd-the-ipfs-bundle--story-5--peer-e.js
Normal file
54
pdd/pdd-transport--story-1--peer-a.js
Normal file
54
pdd/pdd-transport--story-1--peer-a.js
Normal 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'))
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
49
pdd/pdd-transport--story-1--peer-b.js
Normal file
49
pdd/pdd-transport--story-1--peer-b.js
Normal 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')
|
||||
})
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
54
pdd/pdd-transport--story-2--peer-a.js
Normal file
54
pdd/pdd-transport--story-2--peer-a.js
Normal 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'))
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
49
pdd/pdd-transport--story-2--peer-b.js
Normal file
49
pdd/pdd-transport--story-2--peer-b.js
Normal 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
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
42
pdd/pdd-transport--story-3--peer-a.js
Normal file
42
pdd/pdd-transport--story-3--peer-a.js
Normal 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)
|
||||
})
|
||||
})
|
42
pdd/pdd-transport--story-3--peer-b.js
Normal file
42
pdd/pdd-transport--story-3--peer-b.js
Normal 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
20
src/content-routing.js
Normal 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
27
src/dht.js
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
48
src/get-peer-info.js
Normal file
48
src/get-peer-info.js
Normal 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))
|
||||
}
|
||||
}
|
203
src/index.js
203
src/index.js
@ -7,13 +7,14 @@ const setImmediate = require('async/setImmediate')
|
||||
const each = require('async/each')
|
||||
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 mafmt = require('mafmt')
|
||||
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 getPeerInfo = require('./get-peer-info')
|
||||
|
||||
exports = module.exports
|
||||
|
||||
@ -28,27 +29,32 @@ class Node extends EventEmitter {
|
||||
this.modules = _modules
|
||||
this.peerInfo = _peerInfo
|
||||
this.peerBook = _peerBook || new PeerBook()
|
||||
_options = _options || {}
|
||||
|
||||
this._isStarted = false
|
||||
|
||||
this.swarm = new Swarm(this.peerInfo, this.peerBook)
|
||||
this.switch = new Switch(this.peerInfo, this.peerBook)
|
||||
|
||||
// Attach stream multiplexers
|
||||
if (this.modules.connection && this.modules.connection.muxer) {
|
||||
let muxers = this.modules.connection.muxer
|
||||
muxers = Array.isArray(muxers) ? muxers : [muxers]
|
||||
muxers.forEach((muxer) => this.swarm.connection.addStreamMuxer(muxer))
|
||||
muxers.forEach((muxer) => this.switch.connection.addStreamMuxer(muxer))
|
||||
|
||||
// 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
|
||||
this.switch.connection.enableCircuitRelay(_options.relay)
|
||||
|
||||
// Received incommind dial and muxer upgrade happened,
|
||||
// reuse this muxed connection
|
||||
this.swarm.on('peer-mux-established', (peerInfo) => {
|
||||
this.switch.on('peer-mux-established', (peerInfo) => {
|
||||
this.emit('peer:connect', peerInfo)
|
||||
this.peerBook.put(peerInfo)
|
||||
})
|
||||
|
||||
this.swarm.on('peer-mux-closed', (peerInfo) => {
|
||||
this.switch.on('peer-mux-closed', (peerInfo) => {
|
||||
this.emit('peer:disconnect', peerInfo)
|
||||
})
|
||||
}
|
||||
@ -58,7 +64,7 @@ class Node extends EventEmitter {
|
||||
let cryptos = this.modules.connection.crypto
|
||||
cryptos = Array.isArray(cryptos) ? cryptos : [cryptos]
|
||||
cryptos.forEach((crypto) => {
|
||||
this.swarm.connection.crypto(crypto.tag, crypto.encrypt)
|
||||
this.switch.connection.crypto(crypto.tag, crypto.encrypt)
|
||||
})
|
||||
}
|
||||
|
||||
@ -72,64 +78,22 @@ class Node extends EventEmitter {
|
||||
})
|
||||
}
|
||||
|
||||
// Mount default protocols
|
||||
Ping.mount(this.swarm)
|
||||
|
||||
// dht provided components (peerRouting, contentRouting, dht)
|
||||
if (_modules.DHT) {
|
||||
this._dht = new this.modules.DHT(this, 20, _options.DHT && _options.DHT.datastore)
|
||||
this._dht = new this.modules.DHT(this.switch, {
|
||||
kBucketSize: 20,
|
||||
datastore: _options.DHT && _options.DHT.datastore
|
||||
})
|
||||
}
|
||||
|
||||
this.peerRouting = {
|
||||
findPeer: (id, callback) => {
|
||||
if (!this._dht) {
|
||||
return callback(new Error('DHT is not available'))
|
||||
}
|
||||
this.peerRouting = peerRouting(this)
|
||||
this.contentRouting = contentRouting(this)
|
||||
this.dht = dht(this)
|
||||
|
||||
this._dht.findPeer(id, callback)
|
||||
}
|
||||
}
|
||||
this._getPeerInfo = getPeerInfo(this)
|
||||
|
||||
this.contentRouting = {
|
||||
findProviders: (key, timeout, callback) => {
|
||||
if (!this._dht) {
|
||||
return callback(new Error('DHT is not available'))
|
||||
}
|
||||
|
||||
this._dht.findProviders(key, timeout, callback)
|
||||
},
|
||||
provide: (key, callback) => {
|
||||
if (!this._dht) {
|
||||
return callback(new Error('DHT is not available'))
|
||||
}
|
||||
|
||||
this._dht.provide(key, callback)
|
||||
}
|
||||
}
|
||||
|
||||
this.dht = {
|
||||
put: (key, value, callback) => {
|
||||
if (!this._dht) {
|
||||
return callback(new Error('DHT is not available'))
|
||||
}
|
||||
|
||||
this._dht.put(key, value, callback)
|
||||
},
|
||||
get: (key, callback) => {
|
||||
if (!this._dht) {
|
||||
return callback(new Error('DHT is not available'))
|
||||
}
|
||||
|
||||
this._dht.get(key, callback)
|
||||
},
|
||||
getMany (key, nVals, callback) {
|
||||
if (!this._dht) {
|
||||
return callback(new Error('DHT is not available'))
|
||||
}
|
||||
|
||||
this._dht.getMany(key, nVals, callback)
|
||||
}
|
||||
}
|
||||
// Mount default protocols
|
||||
Ping.mount(this.switch)
|
||||
}
|
||||
|
||||
/*
|
||||
@ -149,18 +113,18 @@ class Node extends EventEmitter {
|
||||
// so that we can have webrtc-star addrs without adding manually the id
|
||||
const maOld = []
|
||||
const maNew = []
|
||||
this.peerInfo.multiaddrs.forEach((ma) => {
|
||||
if (!mafmt.IPFS.matches(ma)) {
|
||||
this.peerInfo.multiaddrs.toArray().forEach((ma) => {
|
||||
if (!ma.getPeerId()) {
|
||||
maOld.push(ma)
|
||||
maNew.push(ma.encapsulate('/ipfs/' + this.peerInfo.id.toB58String()))
|
||||
}
|
||||
})
|
||||
this.peerInfo.multiaddrs.replace(maOld, maNew)
|
||||
const multiaddrs = this.peerInfo.multiaddrs.toArray()
|
||||
|
||||
const multiaddrs = this.peerInfo.multiaddrs.toArray()
|
||||
transports.forEach((transport) => {
|
||||
if (transport.filter(multiaddrs).length > 0) {
|
||||
this.swarm.transport.add(
|
||||
this.switch.transport.add(
|
||||
transport.tag || transport.constructor.name, transport)
|
||||
} else if (transport.constructor &&
|
||||
transport.constructor.name === 'WebSockets') {
|
||||
@ -171,11 +135,11 @@ class Node extends EventEmitter {
|
||||
})
|
||||
|
||||
series([
|
||||
(cb) => this.swarm.listen(cb),
|
||||
(cb) => this.switch.start(cb),
|
||||
(cb) => {
|
||||
if (ws) {
|
||||
// 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
|
||||
@ -193,6 +157,19 @@ class Node extends EventEmitter {
|
||||
}
|
||||
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) => {
|
||||
this.emit('start')
|
||||
cb()
|
||||
@ -204,8 +181,6 @@ class Node extends EventEmitter {
|
||||
* Stop the libp2p node by closing its listeners and open connections
|
||||
*/
|
||||
stop (callback) {
|
||||
this._isStarted = false
|
||||
|
||||
if (this.modules.discovery) {
|
||||
this.modules.discovery.forEach((discovery) => {
|
||||
setImmediate(() => discovery.stop(() => {}))
|
||||
@ -219,30 +194,37 @@ class Node extends EventEmitter {
|
||||
}
|
||||
cb()
|
||||
},
|
||||
(cb) => this.swarm.close(cb),
|
||||
(cb) => this.switch.stop(cb),
|
||||
(cb) => {
|
||||
this.emit('stop')
|
||||
cb()
|
||||
}
|
||||
], callback)
|
||||
], (err) => {
|
||||
this._isStarted = false
|
||||
callback(err)
|
||||
})
|
||||
}
|
||||
|
||||
isStarted () {
|
||||
return this._isStarted
|
||||
}
|
||||
|
||||
ping (peer, callback) {
|
||||
dial (peer, callback) {
|
||||
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)
|
||||
|
||||
if (typeof protocol === 'function') {
|
||||
@ -251,14 +233,10 @@ class Node extends EventEmitter {
|
||||
}
|
||||
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
if (err) { return callback(err) }
|
||||
|
||||
this.swarm.dial(peerInfo, protocol, (err, conn) => {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
}
|
||||
this.switch.dial(peerInfo, protocol, (err, conn) => {
|
||||
if (err) { return callback(err) }
|
||||
this.peerBook.put(peerInfo)
|
||||
callback(null, conn)
|
||||
})
|
||||
@ -269,52 +247,27 @@ class Node extends EventEmitter {
|
||||
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
|
||||
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) {
|
||||
return callback(err)
|
||||
if (err) { return callback(err) }
|
||||
|
||||
this.switch.hangUp(peerInfo, callback)
|
||||
})
|
||||
}
|
||||
|
||||
this.swarm.hangUp(peerInfo, callback)
|
||||
ping (peer, callback) {
|
||||
assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
|
||||
this._getPeerInfo(peer, (err, peerInfo) => {
|
||||
if (err) { return callback(err) }
|
||||
|
||||
callback(null, new Ping(this.switch, peerInfo))
|
||||
})
|
||||
}
|
||||
|
||||
handle (protocol, handlerFunc, matchFunc) {
|
||||
this.swarm.handle(protocol, handlerFunc, matchFunc)
|
||||
this.switch.handle(protocol, handlerFunc, matchFunc)
|
||||
}
|
||||
|
||||
unhandle (protocol) {
|
||||
this.swarm.unhandle(protocol)
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper method to check the data type of peer and convert it to PeerInfo
|
||||
*/
|
||||
_getPeerInfo (peer, callback) {
|
||||
let p
|
||||
// PeerInfo
|
||||
if (PeerInfo.isPeerInfo(peer)) {
|
||||
p = peer
|
||||
// Multiaddr instance (not string)
|
||||
} else if (multiaddr.isMultiaddr(peer)) {
|
||||
const peerIdB58Str = peer.getPeerId()
|
||||
try {
|
||||
p = this.peerBook.get(peerIdB58Str)
|
||||
} catch (err) {
|
||||
p = new PeerInfo(PeerId.createFromB58String(peerIdB58Str))
|
||||
}
|
||||
p.multiaddrs.add(peer)
|
||||
// PeerId
|
||||
} else if (PeerId.isPeerId(peer)) {
|
||||
const peerIdB58Str = peer.toB58String()
|
||||
try {
|
||||
p = this.peerBook.get(peerIdB58Str)
|
||||
} catch (err) {
|
||||
return this.peerRouting.findPeer(peer, callback)
|
||||
}
|
||||
} else {
|
||||
return setImmediate(() => callback(new Error('peer type not recognized')))
|
||||
}
|
||||
|
||||
setImmediate(() => callback(null, p))
|
||||
this.switch.unhandle(protocol)
|
||||
}
|
||||
}
|
||||
|
||||
|
13
src/peer-routing.js
Normal file
13
src/peer-routing.js
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const PeerInfo = require('peer-info')
|
||||
const PeerId = require('peer-id')
|
||||
const parallel = require('async/parallel')
|
||||
const pull = require('pull-stream')
|
||||
|
||||
const Node = require('./browser-bundle')
|
||||
|
||||
describe('libp2p-ipfs-browser (webrtc only)', () => {
|
||||
let peer1
|
||||
let peer2
|
||||
let node1
|
||||
let node2
|
||||
|
||||
it('create two peerInfo with webrtc-star addrs', (done) => {
|
||||
parallel([
|
||||
(cb) => PeerId.create({ bits: 1024 }, cb),
|
||||
(cb) => PeerId.create({ bits: 1024 }, cb)
|
||||
], (err, ids) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
peer1 = new PeerInfo(ids[0])
|
||||
const ma1 = '/libp2p-webrtc-star/ip4/127.0.0.1/tcp/15555/ws/ipfs/' + ids[0].toB58String()
|
||||
peer1.multiaddrs.add(ma1)
|
||||
|
||||
peer2 = new PeerInfo(ids[1])
|
||||
const ma2 = '/libp2p-webrtc-star/ip4/127.0.0.1/tcp/15555/ws/ipfs/' + ids[1].toB58String()
|
||||
peer2.multiaddrs.add(ma2)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('create two libp2p nodes with those peers', (done) => {
|
||||
node1 = new Node(peer1, null, { webRTCStar: true })
|
||||
node2 = new Node(peer2, null, { webRTCStar: true })
|
||||
done()
|
||||
})
|
||||
|
||||
it('listen on the two libp2p nodes', (done) => {
|
||||
parallel([
|
||||
(cb) => node1.start(cb),
|
||||
(cb) => node2.start(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
it('handle a protocol on the first node', () => {
|
||||
node2.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
|
||||
})
|
||||
|
||||
it('dial from the second node to the first node', (done) => {
|
||||
node1.dial(peer2, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
const text = 'hello'
|
||||
const peers1 = node1.peerBook.getAll()
|
||||
expect(Object.keys(peers1)).to.have.length(1)
|
||||
|
||||
const peers2 = node2.peerBook.getAll()
|
||||
expect(Object.keys(peers2)).to.have.length(1)
|
||||
|
||||
pull(
|
||||
pull.values([Buffer(text)]),
|
||||
conn,
|
||||
pull.collect((err, data) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(data[0].toString()).to.equal(text)
|
||||
done()
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('node1 hangUp node2', (done) => {
|
||||
node1.hangUp(peer2, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
const peers = node1.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(node1.swarm.muxedConns)).to.have.length(0)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('create a third node and check that discovery works', (done) => {
|
||||
let counter = 0
|
||||
|
||||
function check () {
|
||||
if (++counter === 3) {
|
||||
expect(Object.keys(node1.swarm.muxedConns).length).to.equal(1)
|
||||
expect(Object.keys(node2.swarm.muxedConns).length).to.equal(1)
|
||||
done()
|
||||
}
|
||||
}
|
||||
|
||||
PeerId.create((err, id3) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
const peer3 = new PeerInfo(id3)
|
||||
const ma3 = '/libp2p-webrtc-star/ip4/127.0.0.1/tcp/15555/ws/ipfs/' + id3.toB58String()
|
||||
peer3.multiaddrs.add(ma3)
|
||||
|
||||
node1.on('peer:discovery', (peerInfo) => node1.dial(peerInfo, check))
|
||||
node2.on('peer:discovery', (peerInfo) => node2.dial(peerInfo, check))
|
||||
|
||||
const node3 = new Node(peer3, null, { webRTCStar: true })
|
||||
node3.start(check)
|
||||
})
|
||||
})
|
||||
})
|
@ -1,201 +0,0 @@
|
||||
/* eslint max-nested-callbacks: ["error", 8] */
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const PeerInfo = require('peer-info')
|
||||
const PeerId = require('peer-id')
|
||||
const pull = require('pull-stream')
|
||||
const goodbye = require('pull-goodbye')
|
||||
const serializer = require('pull-serializer')
|
||||
const Buffer = require('safe-buffer').Buffer
|
||||
|
||||
const Node = require('./browser-bundle')
|
||||
const rawPeer = require('./peer.json')
|
||||
|
||||
describe('libp2p-ipfs-browser (websockets only)', () => {
|
||||
let peerB
|
||||
let nodeA
|
||||
|
||||
before((done) => {
|
||||
const ma = '/ip4/127.0.0.1/tcp/9200/ws/ipfs/' + rawPeer.id
|
||||
|
||||
PeerId.createFromPrivKey(rawPeer.privKey, (err, id) => {
|
||||
if (err) {
|
||||
return done(err)
|
||||
}
|
||||
|
||||
peerB = new PeerInfo(id)
|
||||
peerB.multiaddrs.add(ma)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
after((done) => nodeA.stop(done))
|
||||
|
||||
it('create libp2pNode', (done) => {
|
||||
PeerInfo.create((err, peerInfo) => {
|
||||
expect(err).to.not.exist()
|
||||
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
|
||||
|
||||
nodeA = new Node(peerInfo)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('create libp2pNode with multiplex only', (done) => {
|
||||
PeerInfo.create((err, peerInfo) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
const b = new Node(peerInfo, null, { muxer: ['multiplex'] })
|
||||
expect(b.modules.connection.muxer).to.eql([require('libp2p-multiplex')])
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('start libp2pNode', (done) => {
|
||||
nodeA.start(done)
|
||||
})
|
||||
|
||||
// General connectivity tests
|
||||
|
||||
it('libp2p.dial using Multiaddr nodeA to nodeB', (done) => {
|
||||
nodeA.dial(peerB.multiaddrs.toArray()[0], (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
setTimeout(check, 500) // Some time for Identify to finish
|
||||
|
||||
function check () {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('libp2p.dial using Multiaddr on Protocol nodeA to nodeB', (done) => {
|
||||
nodeA.dial(peerB.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
pull(
|
||||
pull.values([Buffer.from('hey')]),
|
||||
conn,
|
||||
pull.collect((err, data) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(data).to.eql([Buffer.from('hey')])
|
||||
done()
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('libp2p.hangUp using Multiaddr nodeA to nodeB', (done) => {
|
||||
nodeA.hangUp(peerB.multiaddrs.toArray()[0], (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('libp2p.dial using PeerInfo nodeA to nodeB', (done) => {
|
||||
nodeA.dial(peerB, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
setTimeout(check, 500) // Some time for Identify to finish
|
||||
|
||||
function check () {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('libp2p.dial using PeerInfo on Protocol nodeA to nodeB', (done) => {
|
||||
nodeA.dial(peerB, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(err).to.not.exist()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
pull(
|
||||
pull.values([Buffer.from('hey')]),
|
||||
conn,
|
||||
pull.collect((err, data) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(data).to.eql([Buffer.from('hey')])
|
||||
done()
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('libp2p.hangUp using PeerInfo nodeA to nodeB', (done) => {
|
||||
nodeA.hangUp(peerB, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(err).to.not.exist()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('stress', () => {
|
||||
it('one big write', (done) => {
|
||||
nodeA.dial(peerB, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
const rawMessage = Buffer.alloc(100000)
|
||||
rawMessage.fill('a')
|
||||
|
||||
const s = serializer(goodbye({
|
||||
source: pull.values([rawMessage]),
|
||||
sink: pull.collect((err, results) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(results).to.have.length(1)
|
||||
expect(Buffer.from(results[0])).to.have.length(rawMessage.length)
|
||||
done()
|
||||
})
|
||||
}))
|
||||
pull(s, conn, s)
|
||||
})
|
||||
})
|
||||
|
||||
it('many writes', (done) => {
|
||||
nodeA.dial(peerB, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
const s = serializer(goodbye({
|
||||
source: pull(
|
||||
pull.infinite(),
|
||||
pull.take(1000),
|
||||
pull.map((val) => Buffer.from(val.toString()))
|
||||
),
|
||||
sink: pull.collect((err, result) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(result).to.have.length(1000)
|
||||
done()
|
||||
})
|
||||
}))
|
||||
|
||||
pull(s, conn, s)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@ -1,7 +1,4 @@
|
||||
'use strict'
|
||||
|
||||
const w = require('webrtcsupport')
|
||||
|
||||
require('./base')
|
||||
require('./browser-bundle/websockets-only')
|
||||
if (w.support) { require('./browser-bundle/webrtc-star-only') }
|
||||
require('./transports.browser')
|
||||
|
201
test/circuit-relay.node.js
Normal file
201
test/circuit-relay.node.js
Normal file
@ -0,0 +1,201 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const waterfall = require('async/waterfall')
|
||||
const series = require('async/series')
|
||||
const parallel = require('async/parallel')
|
||||
const utils = require('./utils/node')
|
||||
const Circuit = require('libp2p-circuit')
|
||||
const multiaddr = require('multiaddr')
|
||||
const tryEcho = require('./utils/try-echo')
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const sinon = require('sinon')
|
||||
|
||||
describe('circuit relay', function () {
|
||||
let handlerSpies = []
|
||||
let relayNode1
|
||||
let relayNode2
|
||||
let nodeWS1
|
||||
let nodeWS2
|
||||
let nodeTCP1
|
||||
let nodeTCP2
|
||||
|
||||
function setupNode (addrs, options, cb) {
|
||||
if (typeof options === 'function') {
|
||||
cb = options
|
||||
options = {}
|
||||
}
|
||||
|
||||
options = options || {}
|
||||
|
||||
return utils.createNode(addrs, options, (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
node.handle('/echo/1.0.0', utils.echo)
|
||||
node.start((err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
handlerSpies.push(sinon.spy(node.switch.transports[Circuit.tag].listeners[0].hopHandler, 'handle'))
|
||||
cb(node)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
before(function (done) {
|
||||
this.timeout(20000)
|
||||
|
||||
waterfall([
|
||||
// set up passive relay
|
||||
(cb) => setupNode([
|
||||
'/ip4/0.0.0.0/tcp/0/ws',
|
||||
'/ip4/0.0.0.0/tcp/0'
|
||||
], {
|
||||
relay: {
|
||||
enabled: true,
|
||||
hop: {
|
||||
enabled: true,
|
||||
active: false // passive relay
|
||||
}
|
||||
}
|
||||
}, (node) => {
|
||||
relayNode1 = node
|
||||
cb()
|
||||
}),
|
||||
// setup active relay
|
||||
(cb) => setupNode([
|
||||
'/ip4/0.0.0.0/tcp/0/ws',
|
||||
'/ip4/0.0.0.0/tcp/0'
|
||||
], {
|
||||
relay: {
|
||||
enabled: true,
|
||||
hop: {
|
||||
enabled: true,
|
||||
active: false // passive relay
|
||||
}
|
||||
}
|
||||
}, (node) => {
|
||||
relayNode2 = node
|
||||
cb()
|
||||
}),
|
||||
// setup node with WS
|
||||
(cb) => setupNode([
|
||||
'/ip4/0.0.0.0/tcp/0/ws'
|
||||
], {
|
||||
relay: {
|
||||
enabled: true
|
||||
}
|
||||
}, (node) => {
|
||||
nodeWS1 = node
|
||||
cb()
|
||||
}),
|
||||
// setup node with WS
|
||||
(cb) => setupNode([
|
||||
'/ip4/0.0.0.0/tcp/0/ws'
|
||||
], {
|
||||
relay: {
|
||||
enabled: true
|
||||
}
|
||||
}, (node) => {
|
||||
nodeWS2 = node
|
||||
cb()
|
||||
}),
|
||||
// set up node with TCP and listening on relay1
|
||||
(cb) => setupNode([
|
||||
'/ip4/0.0.0.0/tcp/0',
|
||||
`/ipfs/${relayNode1.peerInfo.id.toB58String()}/p2p-circuit`
|
||||
], {
|
||||
relay: {
|
||||
enabled: true
|
||||
}
|
||||
}, (node) => {
|
||||
nodeTCP1 = node
|
||||
cb()
|
||||
}),
|
||||
// set up node with TCP and listening on relay2 over TCP transport
|
||||
(cb) => setupNode([
|
||||
'/ip4/0.0.0.0/tcp/0',
|
||||
`/ip4/0.0.0.0/tcp/0/ipfs/${relayNode2.peerInfo.id.toB58String()}/p2p-circuit`
|
||||
], {
|
||||
relay: {
|
||||
enabled: true
|
||||
}
|
||||
}, (node) => {
|
||||
nodeTCP2 = node
|
||||
cb()
|
||||
})
|
||||
], (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
series([
|
||||
(cb) => nodeWS1.dial(relayNode1.peerInfo, cb),
|
||||
(cb) => nodeWS1.dial(relayNode2.peerInfo, cb),
|
||||
(cb) => nodeTCP1.dial(relayNode1.peerInfo, cb),
|
||||
(cb) => nodeTCP2.dial(relayNode2.peerInfo, cb)
|
||||
], done)
|
||||
})
|
||||
})
|
||||
|
||||
after((done) => {
|
||||
parallel([
|
||||
(cb) => relayNode1.stop(cb),
|
||||
(cb) => relayNode2.stop(cb),
|
||||
(cb) => nodeWS1.stop(cb),
|
||||
(cb) => nodeWS2.stop(cb),
|
||||
(cb) => nodeTCP1.stop(cb),
|
||||
(cb) => nodeTCP2.stop(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
describe('any relay', function () {
|
||||
this.timeout(20 * 1000)
|
||||
|
||||
it('dial from WS1 to TCP1 over any R', (done) => {
|
||||
nodeWS1.dialProtocol(nodeTCP1.peerInfo, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(conn).to.exist()
|
||||
tryEcho(conn, done)
|
||||
})
|
||||
})
|
||||
|
||||
it('fail to dial - no R from WS2 to TCP1', (done) => {
|
||||
nodeWS2.dialProtocol(nodeTCP2.peerInfo, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.exist()
|
||||
expect(conn).to.not.exist()
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('explicit relay', function () {
|
||||
this.timeout(20 * 1000)
|
||||
|
||||
it('dial from WS1 to TCP1 over R1', (done) => {
|
||||
nodeWS1.dialProtocol(nodeTCP1.peerInfo, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(conn).to.exist()
|
||||
|
||||
tryEcho(conn, () => {
|
||||
const addr = multiaddr(handlerSpies[0].args[2][0].dstPeer.addrs[0]).toString()
|
||||
expect(addr).to.equal(`/ipfs/${nodeTCP1.peerInfo.id.toB58String()}`)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
it('dial from WS1 to TCP2 over R2', (done) => {
|
||||
nodeWS1.dialProtocol(nodeTCP2.peerInfo, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(conn).to.exist()
|
||||
|
||||
tryEcho(conn, () => {
|
||||
const addr = multiaddr(handlerSpies[1].args[2][0].dstPeer.addrs[0]).toString()
|
||||
expect(addr).to.equal(`/ipfs/${nodeTCP2.peerInfo.id.toB58String()}`)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@ -7,10 +7,10 @@ const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const parallel = require('async/parallel')
|
||||
const utils = require('./utils')
|
||||
const createNode = utils.createNode
|
||||
const _times = require('lodash.times')
|
||||
const CID = require('cids')
|
||||
const utils = require('./utils/node')
|
||||
const createNode = utils.createNode
|
||||
|
||||
describe('.contentRouting', () => {
|
||||
let nodeA
|
||||
@ -19,7 +19,8 @@ describe('.contentRouting', () => {
|
||||
let nodeD
|
||||
let nodeE
|
||||
|
||||
before((done) => {
|
||||
before(function (done) {
|
||||
this.timeout(5 * 1000)
|
||||
const tasks = _times(5, () => (cb) => {
|
||||
createNode('/ip4/0.0.0.0/tcp/0', {
|
||||
mdns: false,
|
40
test/multiaddr-trim.js
Normal file
40
test/multiaddr-trim.js
Normal 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)
|
||||
})
|
||||
})
|
||||
})
|
14
test/node.js
14
test/node.js
@ -1,10 +1,10 @@
|
||||
'use strict'
|
||||
|
||||
require('./base')
|
||||
require('./nodejs-bundle/tcp')
|
||||
require('./nodejs-bundle/tcp+websockets')
|
||||
require('./nodejs-bundle/tcp+websockets+webrtc-star')
|
||||
require('./nodejs-bundle/stream-muxing')
|
||||
require('./nodejs-bundle/discovery')
|
||||
require('./nodejs-bundle/peer-routing')
|
||||
require('./nodejs-bundle/content-routing')
|
||||
require('./transports.node')
|
||||
require('./stream-muxing.node')
|
||||
require('./peer-discovery.node')
|
||||
require('./peer-routing.node')
|
||||
require('./content-routing.node')
|
||||
require('./circuit-relay.node')
|
||||
require('./multiaddr-trim')
|
||||
|
@ -1,30 +0,0 @@
|
||||
#! /usr/bin/env node
|
||||
|
||||
'use strict'
|
||||
|
||||
const Node = require('./nodejs-bundle')
|
||||
const PeerInfo = require('peer-info')
|
||||
const PeerId = require('peer-id')
|
||||
const pull = require('pull-stream')
|
||||
|
||||
const idBak = require('./test-data/test-id.json')
|
||||
|
||||
PeerId.createFromJSON(idBak, (err, peerId) => {
|
||||
if (err) {
|
||||
throw err
|
||||
}
|
||||
|
||||
const peerInfo = new PeerInfo(peerId)
|
||||
|
||||
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/12345')
|
||||
|
||||
const node = new Node(peerInfo)
|
||||
|
||||
node.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
|
||||
|
||||
node.start((err) => {
|
||||
if (err) { throw err }
|
||||
|
||||
console.log('Spawned node started, env:', process.env.LIBP2P_MUXER)
|
||||
})
|
||||
})
|
@ -1,246 +0,0 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const parallel = require('async/parallel')
|
||||
const signalling = require('libp2p-webrtc-star/src/sig-server')
|
||||
const WStar = require('libp2p-webrtc-star')
|
||||
const wrtc = require('wrtc')
|
||||
const utils = require('./utils')
|
||||
const createNode = utils.createNode
|
||||
const echo = utils.echo
|
||||
|
||||
describe('TCP + WebSockets + WebRTCStar', () => {
|
||||
let nodeAll
|
||||
let nodeTCP
|
||||
let nodeWS
|
||||
let nodeWStar
|
||||
|
||||
let ss
|
||||
|
||||
before((done) => {
|
||||
parallel([
|
||||
(cb) => {
|
||||
signalling.start({ port: 24642 }, (err, server) => {
|
||||
expect(err).to.not.exist()
|
||||
ss = server
|
||||
cb()
|
||||
})
|
||||
},
|
||||
(cb) => {
|
||||
const wstar = new WStar({wrtc: wrtc})
|
||||
createNode([
|
||||
'/ip4/0.0.0.0/tcp/0',
|
||||
'/ip4/127.0.0.1/tcp/25011/ws',
|
||||
'/libp2p-webrtc-star/ip4/127.0.0.1/tcp/24642/ws'
|
||||
], {
|
||||
modules: {
|
||||
transport: [wstar],
|
||||
discovery: [wstar.discovery]
|
||||
}
|
||||
}, (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeAll = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
},
|
||||
(cb) => createNode([
|
||||
'/ip4/0.0.0.0/tcp/0'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeTCP = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
(cb) => createNode([
|
||||
'/ip4/127.0.0.1/tcp/25022/ws'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeWS = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
|
||||
(cb) => {
|
||||
const wstar = new WStar({wrtc: wrtc})
|
||||
|
||||
createNode([
|
||||
'/libp2p-webrtc-star/ip4/127.0.0.1/tcp/24642/ws'
|
||||
], {
|
||||
modules: {
|
||||
transport: [wstar],
|
||||
discovery: [wstar.discovery]
|
||||
}
|
||||
}, (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeWStar = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
}
|
||||
], done)
|
||||
})
|
||||
|
||||
after((done) => {
|
||||
parallel([
|
||||
(cb) => nodeAll.stop(cb),
|
||||
(cb) => nodeTCP.stop(cb),
|
||||
(cb) => nodeWS.stop(cb),
|
||||
(cb) => nodeWStar.stop(cb),
|
||||
(cb) => ss.stop(done)
|
||||
], done)
|
||||
})
|
||||
|
||||
it('nodeAll.dial nodeTCP using PeerInfo', (done) => {
|
||||
nodeAll.dial(nodeTCP.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeAll.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeTCP.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeTCP.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.hangUp nodeTCP using PeerInfo', (done) => {
|
||||
nodeAll.hangUp(nodeTCP.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeAll.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeTCP.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeTCP.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.dial nodeWS using PeerInfo', (done) => {
|
||||
nodeAll.dial(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeAll.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(2)
|
||||
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeWS.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.hangUp nodeWS using PeerInfo', (done) => {
|
||||
nodeAll.hangUp(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeAll.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(2)
|
||||
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeWS.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.dial nodeWStar using PeerInfo', (done) => {
|
||||
nodeAll.dial(nodeWStar.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeAll.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(3)
|
||||
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeWStar.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.hangUp nodeWStar using PeerInfo', (done) => {
|
||||
nodeAll.hangUp(nodeWStar.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeAll.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(3)
|
||||
expect(Object.keys(nodeAll.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeWStar.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeWStar.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
@ -1,167 +0,0 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const parallel = require('async/parallel')
|
||||
// const multiaddr = require('multiaddr')
|
||||
// const pull = require('pull-stream')
|
||||
const utils = require('./utils')
|
||||
const createNode = utils.createNode
|
||||
const echo = utils.echo
|
||||
|
||||
describe('TCP + WebSockets', () => {
|
||||
let nodeTCP
|
||||
let nodeTCPnWS
|
||||
let nodeWS
|
||||
|
||||
before((done) => {
|
||||
parallel([
|
||||
(cb) => createNode([
|
||||
'/ip4/0.0.0.0/tcp/0'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeTCP = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
(cb) => createNode([
|
||||
'/ip4/0.0.0.0/tcp/0',
|
||||
'/ip4/127.0.0.1/tcp/25011/ws'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeTCPnWS = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
(cb) => createNode([
|
||||
'/ip4/127.0.0.1/tcp/25022/ws'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeWS = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
], done)
|
||||
})
|
||||
|
||||
after((done) => {
|
||||
parallel([
|
||||
(cb) => nodeTCP.stop(cb),
|
||||
(cb) => nodeTCPnWS.stop(cb),
|
||||
(cb) => nodeWS.stop(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
it('nodeTCP.dial nodeTCPnWS using PeerInfo', (done) => {
|
||||
nodeTCP.dial(nodeTCPnWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeTCP.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeTCP.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeTCPnWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeTCP.hangUp nodeTCPnWS using PeerInfo', (done) => {
|
||||
nodeTCP.hangUp(nodeTCPnWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeTCP.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeTCP.swarm.muxedConns)).to.have.length(0)
|
||||
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeTCPnWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeTCPnWS.dial nodeWS using PeerInfo', (done) => {
|
||||
nodeTCPnWS.dial(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeTCPnWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(2)
|
||||
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeWS.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeTCPnWS.hangUp nodeWS using PeerInfo', (done) => {
|
||||
nodeTCPnWS.hangUp(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeTCPnWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(2)
|
||||
expect(Object.keys(nodeTCPnWS.swarm.muxedConns)).to.have.length(0)
|
||||
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeWS.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Until https://github.com/libp2p/js-libp2p/issues/46 is resolved
|
||||
// Everynode will be able to dial in WebSockets
|
||||
it.skip('nodeTCP.dial nodeWS using PeerInfo is unsuccesful', (done) => {
|
||||
nodeTCP.dial(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.exist()
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
@ -1,234 +0,0 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const parallel = require('async/parallel')
|
||||
const series = require('async/series')
|
||||
const pull = require('pull-stream')
|
||||
const utils = require('./utils')
|
||||
const createNode = utils.createNode
|
||||
const echo = utils.echo
|
||||
|
||||
describe('TCP only', () => {
|
||||
let nodeA
|
||||
let nodeB
|
||||
|
||||
before((done) => {
|
||||
parallel([
|
||||
(cb) => createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeA = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
(cb) => createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeB = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
], done)
|
||||
})
|
||||
|
||||
after((done) => {
|
||||
parallel([
|
||||
(cb) => nodeA.stop(cb),
|
||||
(cb) => nodeB.stop(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
it('nodeA.dial nodeB using PeerInfo without proto (warmup)', (done) => {
|
||||
nodeA.dial(nodeB.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(err).to.not.exist()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(err).to.not.exist()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.dial nodeB using PeerInfo', (done) => {
|
||||
nodeA.dial(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
pull(
|
||||
pull.values([new Buffer('hey')]),
|
||||
conn,
|
||||
pull.collect((err, data) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(data).to.be.eql([new Buffer('hey')])
|
||||
done()
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.hangUp nodeB using PeerInfo (first)', (done) => {
|
||||
nodeA.hangUp(nodeB.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeB.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.dial nodeB using multiaddr', (done) => {
|
||||
nodeA.dial(nodeB.peerInfo.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => {
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
expect(err).to.not.exist()
|
||||
series([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], () => {
|
||||
pull(
|
||||
pull.values([new Buffer('hey')]),
|
||||
conn,
|
||||
pull.collect((err, data) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(data).to.be.eql([new Buffer('hey')])
|
||||
done()
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.hangUp nodeB using multiaddr (second)', (done) => {
|
||||
nodeA.hangUp(nodeB.peerInfo.multiaddrs.toArray()[0], (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeB.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.dial nodeB using PeerId', (done) => {
|
||||
nodeA.dial(nodeB.peerInfo.id, '/echo/1.0.0', (err, conn) => {
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
expect(err).to.not.exist()
|
||||
series([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], () => {
|
||||
pull(
|
||||
pull.values([new Buffer('hey')]),
|
||||
conn,
|
||||
pull.collect((err, data) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(data).to.be.eql([new Buffer('hey')])
|
||||
done()
|
||||
})
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.hangUp nodeB using PeerId (third)', (done) => {
|
||||
nodeA.hangUp(nodeB.peerInfo.multiaddrs.toArray()[0], (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeB.swarm.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
@ -6,11 +6,11 @@ chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const signalling = require('libp2p-webrtc-star/src/sig-server')
|
||||
const parallel = require('async/parallel')
|
||||
const utils = require('./utils')
|
||||
const utils = require('./utils/node')
|
||||
const createNode = utils.createNode
|
||||
const echo = utils.echo
|
||||
|
||||
describe('discovery', () => {
|
||||
describe('peer discovery', () => {
|
||||
let nodeA
|
||||
let nodeB
|
||||
let port = 24642
|
||||
@ -29,7 +29,7 @@ describe('discovery', () => {
|
||||
},
|
||||
(cb) => createNode([
|
||||
'/ip4/0.0.0.0/tcp/0',
|
||||
`/libp2p-webrtc-star/ip4/127.0.0.1/tcp/${port}/ws`
|
||||
`/ip4/127.0.0.1/tcp/${port}/ws/p2p-webrtc-star`
|
||||
], options, (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeA = node
|
||||
@ -38,7 +38,7 @@ describe('discovery', () => {
|
||||
}),
|
||||
(cb) => createNode([
|
||||
'/ip4/0.0.0.0/tcp/0',
|
||||
`/libp2p-webrtc-star/ip4/127.0.0.1/tcp/${port}/ws`
|
||||
`/ip4/127.0.0.1/tcp/${port}/ws/p2p-webrtc-star`
|
||||
], options, (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeB = node
|
||||
@ -60,7 +60,9 @@ describe('discovery', () => {
|
||||
describe('MulticastDNS', () => {
|
||||
setup({ mdns: true })
|
||||
|
||||
it('find a peer', (done) => {
|
||||
it('find a peer', function (done) {
|
||||
this.timeout(15 * 1000)
|
||||
|
||||
nodeA.once('peer:discovery', (peerInfo) => {
|
||||
expect(nodeB.peerInfo.id.toB58String())
|
||||
.to.eql(peerInfo.id.toB58String())
|
||||
@ -73,7 +75,8 @@ describe('discovery', () => {
|
||||
describe.skip('WebRTCStar', () => {
|
||||
setup({ webRTCStar: true })
|
||||
|
||||
it('find a peer', (done) => {
|
||||
it('find a peer', function (done) {
|
||||
this.timeout(15 * 1000)
|
||||
nodeA.once('peer:discovery', (peerInfo) => {
|
||||
expect(nodeB.peerInfo.id.toB58String())
|
||||
.to.eql(peerInfo.id.toB58String())
|
||||
@ -88,7 +91,8 @@ describe('discovery', () => {
|
||||
mdns: true
|
||||
})
|
||||
|
||||
it('find a peer', (done) => {
|
||||
it('find a peer', function (done) {
|
||||
this.timeout(15 * 1000)
|
||||
nodeA.once('peer:discovery', (peerInfo) => {
|
||||
expect(nodeB.peerInfo.id.toB58String())
|
||||
.to.eql(peerInfo.id.toB58String())
|
@ -7,9 +7,9 @@ const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const parallel = require('async/parallel')
|
||||
const utils = require('./utils')
|
||||
const createNode = utils.createNode
|
||||
const _times = require('lodash.times')
|
||||
const utils = require('./utils/node')
|
||||
const createNode = utils.createNode
|
||||
|
||||
describe('.peerRouting', () => {
|
||||
let nodeA
|
||||
@ -18,7 +18,9 @@ describe('.peerRouting', () => {
|
||||
let nodeD
|
||||
let nodeE
|
||||
|
||||
before((done) => {
|
||||
before(function (done) {
|
||||
this.timeout(5 * 1000)
|
||||
|
||||
const tasks = _times(5, () => (cb) => {
|
||||
createNode('/ip4/0.0.0.0/tcp/0', {
|
||||
mdns: false,
|
@ -6,24 +6,15 @@ chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const parallel = require('async/parallel')
|
||||
const series = require('async/series')
|
||||
const pull = require('pull-stream')
|
||||
const utils = require('./utils')
|
||||
const utils = require('./utils/node')
|
||||
const tryEcho = require('./utils/try-echo')
|
||||
const createNode = utils.createNode
|
||||
const echo = utils.echo
|
||||
|
||||
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()
|
||||
|
||||
pull(
|
||||
pull.values([new Buffer('hey')]),
|
||||
conn,
|
||||
pull.collect((err, data) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(data).to.be.eql([new Buffer('hey')])
|
||||
callback()
|
||||
})
|
||||
)
|
||||
tryEcho(conn, callback)
|
||||
})
|
||||
}
|
||||
|
||||
@ -34,8 +25,10 @@ function teardown (nodeA, nodeB, callback) {
|
||||
], callback)
|
||||
}
|
||||
|
||||
describe('stream muxing', (done) => {
|
||||
it('spdy only', (done) => {
|
||||
describe('stream muxing', () => {
|
||||
it('spdy only', function (done) {
|
||||
this.timeout(5 * 1000)
|
||||
|
||||
let nodeA
|
||||
let nodeB
|
||||
|
||||
@ -99,7 +92,9 @@ describe('stream muxing', (done) => {
|
||||
], done)
|
||||
})
|
||||
|
||||
it('spdy + multiplex', (done) => {
|
||||
it('spdy + multiplex', function (done) {
|
||||
this.timeout(5000)
|
||||
|
||||
let nodeA
|
||||
let nodeB
|
||||
|
||||
@ -131,7 +126,9 @@ describe('stream muxing', (done) => {
|
||||
], done)
|
||||
})
|
||||
|
||||
it('spdy + multiplex switched order', (done) => {
|
||||
it('spdy + multiplex switched order', function (done) {
|
||||
this.timeout(5 * 1000)
|
||||
|
||||
let nodeA
|
||||
let nodeB
|
||||
|
||||
@ -163,7 +160,9 @@ describe('stream muxing', (done) => {
|
||||
], done)
|
||||
})
|
||||
|
||||
it('one without the other fails to establish a muxedConn', (done) => {
|
||||
it('one without the other fails to establish a muxedConn', function (done) {
|
||||
this.timeout(5 * 1000)
|
||||
|
||||
let nodeA
|
||||
let nodeB
|
||||
|
||||
@ -192,12 +191,12 @@ describe('stream muxing', (done) => {
|
||||
(cb) => setup(cb),
|
||||
(cb) => {
|
||||
// it will just 'warm up a conn'
|
||||
expect(Object.keys(nodeA.swarm.muxers)).to.have.length(1)
|
||||
expect(Object.keys(nodeB.swarm.muxers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.switch.muxers)).to.have.length(1)
|
||||
expect(Object.keys(nodeB.switch.muxers)).to.have.length(1)
|
||||
|
||||
nodeA.dial(nodeB.peerInfo, (err) => {
|
||||
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()
|
||||
})
|
||||
},
|
391
test/transports.browser.js
Normal file
391
test/transports.browser.js
Normal file
@ -0,0 +1,391 @@
|
||||
/* eslint max-nested-callbacks: ["error", 8] */
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const PeerInfo = require('peer-info')
|
||||
const PeerId = require('peer-id')
|
||||
const pull = require('pull-stream')
|
||||
const parallel = require('async/parallel')
|
||||
const goodbye = require('pull-goodbye')
|
||||
const serializer = require('pull-serializer')
|
||||
const w = require('webrtcsupport')
|
||||
const tryEcho = require('./utils/try-echo')
|
||||
|
||||
const Node = require('./utils/bundle.browser')
|
||||
const rawPeer = require('./fixtures/test-peer.json')
|
||||
|
||||
describe('transports', () => {
|
||||
describe('websockets', () => {
|
||||
let peerB
|
||||
let nodeA
|
||||
|
||||
before((done) => {
|
||||
const ma = '/ip4/127.0.0.1/tcp/9200/ws/ipfs/' + rawPeer.id
|
||||
|
||||
PeerId.createFromPrivKey(rawPeer.privKey, (err, id) => {
|
||||
if (err) {
|
||||
return done(err)
|
||||
}
|
||||
|
||||
peerB = new PeerInfo(id)
|
||||
peerB.multiaddrs.add(ma)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
after((done) => nodeA.stop(done))
|
||||
|
||||
it('create libp2pNode', (done) => {
|
||||
PeerInfo.create((err, peerInfo) => {
|
||||
expect(err).to.not.exist()
|
||||
peerInfo.multiaddrs.add('/ip4/0.0.0.0/tcp/0')
|
||||
|
||||
nodeA = new Node(peerInfo)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('create libp2pNode with multiplex only', (done) => {
|
||||
PeerInfo.create((err, peerInfo) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
const b = new Node(peerInfo, null, { muxer: ['multiplex'] })
|
||||
expect(b.modules.connection.muxer).to.eql([require('libp2p-multiplex')])
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('start libp2pNode', (done) => {
|
||||
nodeA.start(done)
|
||||
})
|
||||
|
||||
// General connectivity tests
|
||||
|
||||
it('.dial using Multiaddr', (done) => {
|
||||
nodeA.dial(peerB.multiaddrs.toArray()[0], (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
setTimeout(check, 500) // Some time for Identify to finish
|
||||
|
||||
function check () {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('.dialProtocol using Multiaddr', (done) => {
|
||||
nodeA.dialProtocol(peerB.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
tryEcho(conn, done)
|
||||
})
|
||||
})
|
||||
|
||||
it('.hangUp using Multiaddr', (done) => {
|
||||
nodeA.hangUp(peerB.multiaddrs.toArray()[0], (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('.dial using PeerInfo', (done) => {
|
||||
nodeA.dial(peerB, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
setTimeout(check, 500) // Some time for Identify to finish
|
||||
|
||||
function check () {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('.dialProtocol using PeerInfo', (done) => {
|
||||
nodeA.dialProtocol(peerB, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(err).to.not.exist()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
tryEcho(conn, done)
|
||||
})
|
||||
})
|
||||
|
||||
it('.hangUp using PeerInfo', (done) => {
|
||||
nodeA.hangUp(peerB, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(err).to.not.exist()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('stress', () => {
|
||||
it('one big write', (done) => {
|
||||
nodeA.dialProtocol(peerB, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
const rawMessage = Buffer.alloc(100000)
|
||||
rawMessage.fill('a')
|
||||
|
||||
const s = serializer(goodbye({
|
||||
source: pull.values([rawMessage]),
|
||||
sink: pull.collect((err, results) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(results).to.have.length(1)
|
||||
expect(Buffer.from(results[0])).to.have.length(rawMessage.length)
|
||||
done()
|
||||
})
|
||||
}))
|
||||
pull(s, conn, s)
|
||||
})
|
||||
})
|
||||
|
||||
it('many writes', (done) => {
|
||||
nodeA.dialProtocol(peerB, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
const s = serializer(goodbye({
|
||||
source: pull(
|
||||
pull.infinite(),
|
||||
pull.take(1000),
|
||||
pull.map((val) => Buffer.from(val.toString()))
|
||||
),
|
||||
sink: pull.collect((err, result) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(result).to.have.length(1000)
|
||||
done()
|
||||
})
|
||||
}))
|
||||
|
||||
pull(s, conn, s)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('webrtc-star', () => {
|
||||
if (!w.support) { return console.log('NO WEBRTC SUPPORT') }
|
||||
|
||||
let peer1
|
||||
let peer2
|
||||
let node1
|
||||
let node2
|
||||
|
||||
it('create two peerInfo with webrtc-star addrs', (done) => {
|
||||
parallel([
|
||||
(cb) => PeerId.create({ bits: 1024 }, cb),
|
||||
(cb) => PeerId.create({ bits: 1024 }, cb)
|
||||
], (err, ids) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
peer1 = new PeerInfo(ids[0])
|
||||
const ma1 = '/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/' + ids[0].toB58String()
|
||||
peer1.multiaddrs.add(ma1)
|
||||
|
||||
peer2 = new PeerInfo(ids[1])
|
||||
const ma2 = '/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/' + ids[1].toB58String()
|
||||
peer2.multiaddrs.add(ma2)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('create two libp2p nodes with those peers', (done) => {
|
||||
node1 = new Node(peer1, null, { webRTCStar: true })
|
||||
node2 = new Node(peer2, null, { webRTCStar: true })
|
||||
done()
|
||||
})
|
||||
|
||||
it('start two libp2p nodes', (done) => {
|
||||
parallel([
|
||||
(cb) => node1.start(cb),
|
||||
(cb) => node2.start(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
it('.handle echo on first node', () => {
|
||||
node2.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
|
||||
})
|
||||
|
||||
it('.dialProtocol from the second node to the first node', (done) => {
|
||||
node1.dialProtocol(peer2, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
const peers1 = node1.peerBook.getAll()
|
||||
expect(Object.keys(peers1)).to.have.length(1)
|
||||
|
||||
const peers2 = node2.peerBook.getAll()
|
||||
expect(Object.keys(peers2)).to.have.length(1)
|
||||
|
||||
tryEcho(conn, done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('node1 hangUp node2', (done) => {
|
||||
node1.hangUp(peer2, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
const peers = node1.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(node1.switch.muxedConns)).to.have.length(0)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('create a third node and check that discovery works', (done) => {
|
||||
let counter = 0
|
||||
|
||||
function check () {
|
||||
if (++counter === 3) {
|
||||
expect(Object.keys(node1.switch.muxedConns).length).to.equal(1)
|
||||
expect(Object.keys(node2.switch.muxedConns).length).to.equal(1)
|
||||
done()
|
||||
}
|
||||
}
|
||||
|
||||
PeerId.create((err, id3) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
const peer3 = new PeerInfo(id3)
|
||||
const ma3 = '/ip4/127.0.0.1/tcp/15555/ws/p2p-webrtc-star/ipfs/' + id3.toB58String()
|
||||
peer3.multiaddrs.add(ma3)
|
||||
|
||||
node1.on('peer:discovery', (peerInfo) => node1.dial(peerInfo, check))
|
||||
node2.on('peer:discovery', (peerInfo) => node2.dial(peerInfo, check))
|
||||
|
||||
const node3 = new Node(peer3, null, { webRTCStar: true })
|
||||
node3.start(check)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('websocket-star', () => {
|
||||
let peer1
|
||||
let peer2
|
||||
let node1
|
||||
let node2
|
||||
|
||||
it('create two peerInfo with websocket-star addrs', (done) => {
|
||||
parallel([
|
||||
(cb) => PeerId.create({ bits: 1024 }, cb),
|
||||
(cb) => PeerId.create({ bits: 1024 }, cb)
|
||||
], (err, ids) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
peer1 = new PeerInfo(ids[0])
|
||||
const ma1 = '/ip4/127.0.0.1/tcp/14444/ws/p2p-websocket-star/'
|
||||
peer1.multiaddrs.add(ma1)
|
||||
|
||||
peer2 = new PeerInfo(ids[1])
|
||||
const ma2 = '/ip4/127.0.0.1/tcp/14444/ws/p2p-websocket-star/'
|
||||
peer2.multiaddrs.add(ma2)
|
||||
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('create two libp2p nodes with those peers', (done) => {
|
||||
node1 = new Node(peer1, null, { wsStar: true })
|
||||
node2 = new Node(peer2, null, { wsStar: true })
|
||||
done()
|
||||
})
|
||||
|
||||
it('listen on the two libp2p nodes', (done) => {
|
||||
parallel([
|
||||
(cb) => node1.start(cb),
|
||||
(cb) => node2.start(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
it('handle a protocol on the first node', () => {
|
||||
node2.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
|
||||
})
|
||||
|
||||
it('.dialProtocol from the second node to the first node', (done) => {
|
||||
node1.dialProtocol(peer2, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
const peers1 = node1.peerBook.getAll()
|
||||
expect(Object.keys(peers1)).to.have.length(1)
|
||||
|
||||
const peers2 = node2.peerBook.getAll()
|
||||
expect(Object.keys(peers2)).to.have.length(1)
|
||||
|
||||
tryEcho(conn, done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('node1 hangUp node2', (done) => {
|
||||
node1.hangUp(peer2, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
const peers = node1.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(node1.switch.muxedConns)).to.have.length(0)
|
||||
done()
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('create a third node and check that discovery works', (done) => {
|
||||
let counter = 0
|
||||
|
||||
function check () {
|
||||
if (++counter === 3) {
|
||||
expect(Object.keys(node1.switch.muxedConns).length).to.equal(1)
|
||||
expect(Object.keys(node2.switch.muxedConns).length).to.equal(1)
|
||||
done()
|
||||
}
|
||||
}
|
||||
|
||||
PeerId.create((err, id3) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
const peer3 = new PeerInfo(id3)
|
||||
const ma3 = '/ip4/127.0.0.1/tcp/14444/ws/p2p-websocket-star/ipfs/' + id3.toB58String()
|
||||
peer3.multiaddrs.add(ma3)
|
||||
|
||||
node1.on('peer:discovery', (peerInfo) => node1.dial(peerInfo, check))
|
||||
node2.on('peer:discovery', (peerInfo) => node2.dial(peerInfo, check))
|
||||
|
||||
const node3 = new Node(peer3, null, { wsStar: true })
|
||||
node3.start(check)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
652
test/transports.node.js
Normal file
652
test/transports.node.js
Normal file
@ -0,0 +1,652 @@
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const expect = chai.expect
|
||||
const parallel = require('async/parallel')
|
||||
const series = require('async/series')
|
||||
const utils = require('./utils/node.js')
|
||||
const signalling = require('libp2p-webrtc-star/src/sig-server')
|
||||
const rendezvous = require('libp2p-websocket-star-rendezvous')
|
||||
const WSStar = require('libp2p-websocket-star')
|
||||
const WRTCStar = require('libp2p-webrtc-star')
|
||||
const wrtc = require('wrtc')
|
||||
const tryEcho = require('./utils/try-echo')
|
||||
|
||||
const createNode = utils.createNode
|
||||
const echo = utils.echo
|
||||
|
||||
describe('transports', () => {
|
||||
describe('TCP only', () => {
|
||||
let nodeA
|
||||
let nodeB
|
||||
|
||||
before((done) => {
|
||||
parallel([
|
||||
(cb) => createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeA = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
(cb) => createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeB = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
], done)
|
||||
})
|
||||
|
||||
after((done) => {
|
||||
parallel([
|
||||
(cb) => nodeA.stop(cb),
|
||||
(cb) => nodeB.stop(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
it('nodeA.dial nodeB using PeerInfo without proto (warmup)', (done) => {
|
||||
nodeA.dial(nodeB.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(err).to.not.exist()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(err).to.not.exist()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.dial nodeB using PeerInfo', (done) => {
|
||||
nodeA.dialProtocol(nodeB.peerInfo, '/echo/1.0.0', (err, conn) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
tryEcho(conn, done)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.hangUp nodeB using PeerInfo (first)', (done) => {
|
||||
nodeA.hangUp(nodeB.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeB.switch.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.dialProtocol nodeB using multiaddr', (done) => {
|
||||
nodeA.dialProtocol(nodeB.peerInfo.multiaddrs.toArray()[0], '/echo/1.0.0', (err, conn) => {
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
expect(err).to.not.exist()
|
||||
series([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], () => tryEcho(conn, done))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.hangUp nodeB using multiaddr (second)', (done) => {
|
||||
nodeA.hangUp(nodeB.peerInfo.multiaddrs.toArray()[0], (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
expect(Object.keys(nodeB.switch.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.dialProtocol nodeB using PeerId', (done) => {
|
||||
nodeA.dialProtocol(nodeB.peerInfo.id, '/echo/1.0.0', (err, conn) => {
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
expect(err).to.not.exist()
|
||||
series([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], () => tryEcho(conn, done))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeA.hangUp nodeB using PeerId (third)', (done) => {
|
||||
nodeA.hangUp(nodeB.peerInfo.multiaddrs.toArray()[0], (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeB.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeB.switch.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('TCP + WebSockets', () => {
|
||||
let nodeTCP
|
||||
let nodeTCPnWS
|
||||
let nodeWS
|
||||
|
||||
before((done) => {
|
||||
parallel([
|
||||
(cb) => createNode([
|
||||
'/ip4/0.0.0.0/tcp/0'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeTCP = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
(cb) => createNode([
|
||||
'/ip4/0.0.0.0/tcp/0',
|
||||
'/ip4/127.0.0.1/tcp/25011/ws'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeTCPnWS = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
(cb) => createNode([
|
||||
'/ip4/127.0.0.1/tcp/25022/ws'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeWS = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
], done)
|
||||
})
|
||||
|
||||
after((done) => {
|
||||
parallel([
|
||||
(cb) => nodeTCP.stop(cb),
|
||||
(cb) => nodeTCPnWS.stop(cb),
|
||||
(cb) => nodeWS.stop(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
it('nodeTCP.dial nodeTCPnWS using PeerInfo', (done) => {
|
||||
nodeTCP.dial(nodeTCPnWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeTCP.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeTCP.switch.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeTCPnWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeTCP.hangUp nodeTCPnWS using PeerInfo', (done) => {
|
||||
nodeTCP.hangUp(nodeTCPnWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeTCP.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeTCP.switch.muxedConns)).to.have.length(0)
|
||||
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeTCPnWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeTCPnWS.dial nodeWS using PeerInfo', (done) => {
|
||||
nodeTCPnWS.dial(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
|
||||
// Some time for Identify to finish
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeTCPnWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(2)
|
||||
expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeWS.switch.muxedConns)).to.have.length(1)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeTCPnWS.hangUp nodeWS using PeerInfo', (done) => {
|
||||
nodeTCPnWS.hangUp(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(check, 500)
|
||||
|
||||
function check () {
|
||||
parallel([
|
||||
(cb) => {
|
||||
const peers = nodeTCPnWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(2)
|
||||
expect(Object.keys(nodeTCPnWS.switch.muxedConns)).to.have.length(0)
|
||||
|
||||
cb()
|
||||
},
|
||||
(cb) => {
|
||||
const peers = nodeWS.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeWS.switch.muxedConns)).to.have.length(0)
|
||||
cb()
|
||||
}
|
||||
], done)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// Until https://github.com/libp2p/js-libp2p/issues/46 is resolved
|
||||
// Everynode will be able to dial in WebSockets
|
||||
it.skip('nodeTCP.dial nodeWS using PeerInfo is unsuccesful', (done) => {
|
||||
nodeTCP.dial(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.exist()
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('TCP + WebSockets + WebRTCStar', () => {
|
||||
let nodeAll
|
||||
let nodeTCP
|
||||
let nodeWS
|
||||
let nodeWStar
|
||||
|
||||
let ss
|
||||
|
||||
before(function (done) {
|
||||
this.timeout(5 * 1000)
|
||||
|
||||
parallel([
|
||||
(cb) => {
|
||||
signalling.start({ port: 24642 }, (err, server) => {
|
||||
expect(err).to.not.exist()
|
||||
ss = server
|
||||
cb()
|
||||
})
|
||||
},
|
||||
(cb) => {
|
||||
const wstar = new WRTCStar({wrtc: wrtc})
|
||||
createNode([
|
||||
'/ip4/0.0.0.0/tcp/0',
|
||||
'/ip4/127.0.0.1/tcp/25011/ws',
|
||||
'/ip4/127.0.0.1/tcp/24642/ws/p2p-webrtc-star'
|
||||
], {
|
||||
modules: {
|
||||
transport: [wstar],
|
||||
discovery: [wstar.discovery]
|
||||
}
|
||||
}, (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeAll = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
},
|
||||
(cb) => createNode([
|
||||
'/ip4/0.0.0.0/tcp/0'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeTCP = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
(cb) => createNode([
|
||||
'/ip4/127.0.0.1/tcp/25022/ws'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeWS = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
|
||||
(cb) => {
|
||||
const wstar = new WRTCStar({wrtc: wrtc})
|
||||
|
||||
createNode([
|
||||
'/ip4/127.0.0.1/tcp/24642/ws/p2p-webrtc-star'
|
||||
], {
|
||||
modules: {
|
||||
transport: [wstar],
|
||||
discovery: [wstar.discovery]
|
||||
}
|
||||
}, (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeWStar = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
}
|
||||
], done)
|
||||
})
|
||||
|
||||
after(function (done) {
|
||||
this.timeout(10 * 1000)
|
||||
|
||||
parallel([
|
||||
(cb) => nodeAll.stop(cb),
|
||||
(cb) => nodeTCP.stop(cb),
|
||||
(cb) => nodeWS.stop(cb),
|
||||
(cb) => nodeWStar.stop(cb),
|
||||
(cb) => ss.stop(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
function check (otherNode, muxed, peers, callback) {
|
||||
let i = 1;
|
||||
[nodeAll, otherNode].forEach((node) => {
|
||||
expect(Object.keys(node.peerBook.getAll())).to.have.length(i-- ? peers : 1)
|
||||
expect(Object.keys(node.switch.muxedConns)).to.have.length(muxed)
|
||||
})
|
||||
callback()
|
||||
}
|
||||
|
||||
it('nodeAll.dial nodeTCP using PeerInfo', (done) => {
|
||||
nodeAll.dial(nodeTCP.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeTCP, 1, 1, done), 500)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.hangUp nodeTCP using PeerInfo', (done) => {
|
||||
nodeAll.hangUp(nodeTCP.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeTCP, 0, 1, done), 500)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.dial nodeWS using PeerInfo', (done) => {
|
||||
nodeAll.dial(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeWS, 1, 2, done), 500)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.hangUp nodeWS using PeerInfo', (done) => {
|
||||
nodeAll.hangUp(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeWS, 0, 2, done), 500)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.dial nodeWStar using PeerInfo', function (done) {
|
||||
this.timeout(40 * 1000)
|
||||
|
||||
nodeAll.dial(nodeWStar.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeWStar, 1, 3, done), 500)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.hangUp nodeWStar using PeerInfo', (done) => {
|
||||
nodeAll.hangUp(nodeWStar.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
setTimeout(() => check(nodeWStar, 0, 3, done), 500)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('TCP + WebSockets + WebSocketStar', () => {
|
||||
let nodeAll
|
||||
let nodeTCP
|
||||
let nodeWS
|
||||
let nodeWStar
|
||||
|
||||
let ss
|
||||
|
||||
before((done) => {
|
||||
parallel([
|
||||
(cb) => {
|
||||
rendezvous.start({ port: 24642 }, (err, server) => {
|
||||
expect(err).to.not.exist()
|
||||
ss = server
|
||||
cb()
|
||||
})
|
||||
},
|
||||
(cb) => {
|
||||
const wstar = new WSStar()
|
||||
createNode([
|
||||
'/ip4/0.0.0.0/tcp/0',
|
||||
'/ip4/127.0.0.1/tcp/25011/ws',
|
||||
'/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star'
|
||||
], {
|
||||
modules: {
|
||||
transport: [wstar],
|
||||
discovery: [wstar.discovery]
|
||||
}
|
||||
}, (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeAll = node
|
||||
wstar.lazySetId(node.peerInfo.id)
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
},
|
||||
(cb) => createNode([
|
||||
'/ip4/0.0.0.0/tcp/0'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeTCP = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
(cb) => createNode([
|
||||
'/ip4/127.0.0.1/tcp/25022/ws'
|
||||
], (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeWS = node
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
}),
|
||||
|
||||
(cb) => {
|
||||
const wstar = new WSStar({})
|
||||
|
||||
createNode([
|
||||
'/ip4/127.0.0.1/tcp/24642/ws/p2p-websocket-star'
|
||||
], {
|
||||
modules: {
|
||||
transport: [wstar],
|
||||
discovery: [wstar.discovery]
|
||||
}
|
||||
}, (err, node) => {
|
||||
expect(err).to.not.exist()
|
||||
nodeWStar = node
|
||||
wstar.lazySetId(node.peerInfo.id)
|
||||
node.handle('/echo/1.0.0', echo)
|
||||
node.start(cb)
|
||||
})
|
||||
}
|
||||
], done)
|
||||
})
|
||||
|
||||
after((done) => {
|
||||
parallel([
|
||||
(cb) => nodeAll.stop(cb),
|
||||
(cb) => nodeTCP.stop(cb),
|
||||
(cb) => nodeWS.stop(cb),
|
||||
(cb) => nodeWStar.stop(cb),
|
||||
(cb) => ss.stop(cb)
|
||||
], done)
|
||||
})
|
||||
|
||||
function check (otherNode, muxed, peers, done) {
|
||||
let i = 1;
|
||||
[nodeAll, otherNode].forEach((node) => {
|
||||
expect(Object.keys(node.peerBook.getAll())).to.have.length(i-- ? peers : 1)
|
||||
expect(Object.keys(node.switch.muxedConns)).to.have.length(muxed)
|
||||
})
|
||||
done()
|
||||
}
|
||||
|
||||
it('nodeAll.dial nodeTCP using PeerInfo', (done) => {
|
||||
nodeAll.dial(nodeTCP.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeTCP, 1, 1, done), 500)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.hangUp nodeTCP using PeerInfo', (done) => {
|
||||
nodeAll.hangUp(nodeTCP.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeTCP, 0, 1, done), 500)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.dial nodeWS using PeerInfo', (done) => {
|
||||
nodeAll.dial(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeWS, 1, 2, done), 500)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.hangUp nodeWS using PeerInfo', (done) => {
|
||||
nodeAll.hangUp(nodeWS.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeWS, 0, 2, done), 500)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.dial nodeWStar using PeerInfo', (done) => {
|
||||
nodeAll.dial(nodeWStar.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeWStar, 1, 3, done), 500)
|
||||
})
|
||||
})
|
||||
|
||||
it('nodeAll.hangUp nodeWStar using PeerInfo', (done) => {
|
||||
nodeAll.hangUp(nodeWStar.peerInfo, (err) => {
|
||||
expect(err).to.not.exist()
|
||||
// Some time for Identify to finish
|
||||
setTimeout(() => check(nodeWStar, 0, 3, done), 500)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@ -7,9 +7,8 @@ const expect = chai.expect
|
||||
const multiaddr = require('multiaddr')
|
||||
const spawn = require('child_process').spawn
|
||||
const path = require('path')
|
||||
// const map = require('async/map')
|
||||
const pull = require('pull-stream')
|
||||
const utils = require('./utils')
|
||||
const utils = require('./utils/node')
|
||||
const createNode = utils.createNode
|
||||
const echo = utils.echo
|
||||
|
||||
@ -57,11 +56,11 @@ describe('Turbolence tests', () => {
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
|
||||
pull(
|
||||
pull.values([new Buffer('hey')]),
|
||||
pull.values([Buffer.from('hey')]),
|
||||
conn,
|
||||
pull.collect((err, data) => {
|
||||
expect(err).to.not.exist()
|
||||
expect(data).to.eql([new Buffer('hey')])
|
||||
expect(data).to.eql([Buffer.from('hey')])
|
||||
done()
|
||||
})
|
||||
)
|
||||
@ -77,7 +76,7 @@ describe('Turbolence tests', () => {
|
||||
function check () {
|
||||
const peers = nodeA.peerBook.getAll()
|
||||
expect(Object.keys(peers)).to.have.length(1)
|
||||
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
|
||||
expect(Object.keys(nodeA.switch.muxedConns)).to.have.length(0)
|
||||
done()
|
||||
}
|
||||
})
|
@ -2,6 +2,7 @@
|
||||
|
||||
const WS = require('libp2p-websockets')
|
||||
const WebRTCStar = require('libp2p-webrtc-star')
|
||||
const WebSocketStar = require('libp2p-websocket-star')
|
||||
const spdy = require('libp2p-spdy')
|
||||
const multiplex = require('libp2p-multiplex')
|
||||
const secio = require('libp2p-secio')
|
||||
@ -35,12 +36,14 @@ function getMuxers (options) {
|
||||
class Node extends libp2p {
|
||||
constructor (peerInfo, peerBook, options) {
|
||||
options = options || {}
|
||||
const webRTCStar = new WebRTCStar()
|
||||
const wrtcStar = new WebRTCStar({ id: peerInfo.id })
|
||||
const wsStar = new WebSocketStar({ id: peerInfo.id })
|
||||
|
||||
const modules = {
|
||||
transport: [
|
||||
new WS(),
|
||||
webRTCStar
|
||||
wrtcStar,
|
||||
wsStar
|
||||
],
|
||||
connection: {
|
||||
muxer: getMuxers(options.muxer),
|
||||
@ -52,7 +55,11 @@ class Node extends libp2p {
|
||||
}
|
||||
|
||||
if (options.webRTCStar) {
|
||||
modules.discovery.push(webRTCStar.discovery)
|
||||
modules.discovery.push(wrtcStar.discovery)
|
||||
}
|
||||
|
||||
if (options.wsStar) {
|
||||
modules.discovery.push(wsStar.discovery)
|
||||
}
|
||||
|
||||
if (options.bootstrap) {
|
@ -3,7 +3,7 @@
|
||||
|
||||
const chai = require('chai')
|
||||
chai.use(require('dirty-chai'))
|
||||
const Node = require('./nodejs-bundle')
|
||||
const Node = require('./bundle.node')
|
||||
const PeerInfo = require('peer-info')
|
||||
const PeerId = require('peer-id')
|
||||
const waterfall = require('async/waterfall')
|
||||
@ -15,6 +15,8 @@ function createNode (multiaddrs, options, callback) {
|
||||
options = {}
|
||||
}
|
||||
|
||||
options = options || {}
|
||||
|
||||
if (!Array.isArray(multiaddrs)) {
|
||||
multiaddrs = [multiaddrs]
|
||||
}
|
21
test/utils/try-echo.js
Normal file
21
test/utils/try-echo.js
Normal 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()
|
||||
})
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user