Compare commits

..

36 Commits

Author SHA1 Message Date
b6e41922a7 chore: release version v0.10.0 2017-07-07 13:27:04 +01:00
195673c2d3 chore: update contributors 2017-07-07 13:27:04 +01:00
647d10fe10 chore: update deps 2017-07-07 13:25:34 +01:00
73f2f6d050 feat: state events and query changes (#100) 2017-07-07 12:56:46 +01:00
2d40f3ad6a docs: update header of the README (#97) 2017-07-05 18:18:31 +01:00
13452c959e docs: rm bundles from table 2017-07-05 18:08:10 +01:00
547c4dbd33 docs: refactor examples (#96) 2017-07-05 12:12:51 +01:00
606fa737b8 WIP - feat: convergence (#94)
* feat: convergence

* structure examples
2017-07-04 11:43:45 +01:00
e3870f3f8a Merge pull request #90 from libp2p/fix/missing-dep-async
fix: added missing dep async
2017-06-28 19:29:44 +01:00
45b0f61824 fix: added missing dep async 2017-06-17 14:29:19 +01:00
0263b899e3 chore: release version v0.9.1 2017-04-16 16:54:49 +01:00
fb92e672ee chore: update contributors 2017-04-16 16:54:49 +01:00
2e326e1619 fix: do not use assert in async funcs (#88) 2017-04-16 16:54:31 +01:00
e4e9761c99 Fix docs 2017-04-16 11:56:34 +01:00
a5b7de1b6b chore: release version v0.9.0 2017-04-06 15:50:57 -04:00
9a7a381f85 chore: update contributors 2017-04-06 15:50:56 -04:00
1f00855e6e chore: update deps 2017-04-06 15:46:13 -04:00
8aa932a491 [WIP] Awesome DHT (#86)
* feat: integrate dht

* better interfaces

* docs: add documentation for peerRouting, contentRouting, dht

* fix: take in passed datastore

* fix: update usage of _getPeerInfo

* fix: getPeerInfo

* docs: update docs

* moar
2017-04-06 15:45:23 -04:00
babb90fe17 chore: release version v0.8.0 2017-03-31 16:19:24 +01:00
2f9070a725 chore: update contributors 2017-03-31 16:19:24 +01:00
a48ec65961 Merge pull request #85 from libp2p/feat/advanced-peer-book
fix: correct method on peer-book
2017-03-31 16:18:37 +01:00
031ecb3fe7 fix: correct method on peer-book 2017-03-31 16:17:59 +01:00
c6bdd869be Merge pull request #76 from libp2p/feat/advanced-peer-book
fix: avoid deleting nodes from peerBook
2017-03-31 16:17:18 +01:00
dee0340806 chore: update to latest peer-info, peer-book and libp2p-swarm 2017-03-31 15:52:20 +01:00
a4b41b0f9a feat: not remove peer from peerBook on disconnect 2017-03-30 07:20:45 +01:00
291e79fc99 fix: addition of ipfs id appendix must come before transport filtering 2017-03-29 21:02:37 +01:00
59ea9c388f feat: append peer id to multiaddr if not there 2017-03-29 20:02:54 +01:00
300936f2f3 fix: avoid deleting nodes from peerBook 2017-03-29 18:03:00 +01:00
9f4ec2a915 chore: release version v0.7.0 2017-03-29 08:03:58 +01:00
c7f4368007 chore: update contributors 2017-03-29 08:03:58 +01:00
9ff04779f5 Merge pull request #75 from libp2p/feat/update-peer-events
feat: Feat/update peer events
2017-03-29 08:03:13 +01:00
f73c045767 feat: update events to conform with #74 2017-03-29 07:32:46 +01:00
8840c9b250 docs: document new events 2017-03-29 07:32:29 +01:00
df4c99df4a chore: release version v0.6.2 2017-03-28 12:44:52 +01:00
6e05a0b239 chore: update contributors 2017-03-28 12:44:52 +01:00
c781abc30c chore: deps 2017-03-28 12:43:00 +01:00
53 changed files with 2763 additions and 166 deletions

View File

@ -1,3 +1,66 @@
<a name="0.10.0"></a>
# [0.10.0](https://github.com/libp2p/js-libp2p/compare/v0.9.1...v0.10.0) (2017-07-07)
### Bug Fixes
* added missing dep async ([45b0f61](https://github.com/libp2p/js-libp2p/commit/45b0f61))
### Features
* state events and query changes ([#100](https://github.com/libp2p/js-libp2p/issues/100)) ([73f2f6d](https://github.com/libp2p/js-libp2p/commit/73f2f6d))
<a name="0.9.1"></a>
## [0.9.1](https://github.com/libp2p/js-libp2p/compare/v0.9.0...v0.9.1) (2017-04-16)
### Bug Fixes
* do not use assert in async funcs ([#88](https://github.com/libp2p/js-libp2p/issues/88)) ([2e326e1](https://github.com/libp2p/js-libp2p/commit/2e326e1))
<a name="0.9.0"></a>
# [0.9.0](https://github.com/libp2p/js-libp2p/compare/v0.8.0...v0.9.0) (2017-04-06)
<a name="0.8.0"></a>
# [0.8.0](https://github.com/libp2p/js-libp2p/compare/v0.7.0...v0.8.0) (2017-03-31)
### Bug Fixes
* addition of ipfs id appendix must come before transport filtering ([291e79f](https://github.com/libp2p/js-libp2p/commit/291e79f))
* avoid deleting nodes from peerBook ([300936f](https://github.com/libp2p/js-libp2p/commit/300936f))
* correct method on peer-book ([031ecb3](https://github.com/libp2p/js-libp2p/commit/031ecb3))
### Features
* append peer id to multiaddr if not there ([59ea9c3](https://github.com/libp2p/js-libp2p/commit/59ea9c3))
* not remove peer from peerBook on disconnect ([a4b41b0](https://github.com/libp2p/js-libp2p/commit/a4b41b0))
<a name="0.7.0"></a>
# [0.7.0](https://github.com/libp2p/js-libp2p/compare/v0.6.2...v0.7.0) (2017-03-29)
### Features
* update events to conform with [#74](https://github.com/libp2p/js-libp2p/issues/74) ([f73c045](https://github.com/libp2p/js-libp2p/commit/f73c045))
<a name="0.6.2"></a>
## [0.6.2](https://github.com/libp2p/js-libp2p/compare/v0.6.1...v0.6.2) (2017-03-28)
<a name="0.6.1"></a> <a name="0.6.1"></a>
## [0.6.1](https://github.com/libp2p/js-libp2p/compare/v0.6.0...v0.6.1) (2017-03-27) ## [0.6.1](https://github.com/libp2p/js-libp2p/compare/v0.6.0...v0.6.1) (2017-03-27)

View File

@ -1,13 +1,28 @@
![](https://github.com/libp2p/js-libp2p/blob/fe2d097bfa072ef6733f2defb568bdc526052ee4/img/js-libp2p.png?raw=true) <h1 align="center">
<a href="libp2p.io"><img width="250" src="https://github.com/libp2p/libp2p/blob/master/logo/alternates/libp2p-logo-alt-2.png?raw=true" alt="libp2p hex logo" /></a>
</h1>
[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](http://ipn.io) <h3 align="center">The JavaScript implementation of the libp2p Networking Stack.</h3>
[![](https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square)](http://webchat.freenode.net/?channels=%23ipfs)
[![Build Status](https://travis-ci.org/libp2p/js-libp2p.svg?style=flat-square)](https://travis-ci.org/libp2p/js-libp2p)
![coverage](https://img.shields.io/badge/coverage-%3F-yellow.svg?style=flat-square)
[![Dependency Status](https://david-dm.org/libp2p/js-libp2p.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/feross/standard)
> libp2p is the networking stack of IPFS, a modular networking library to solve P2P application needs. <p align="center">
<a href="http://ipn.io"><img src="https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square" /></a>
<a href="http://libp2p.io/"><img src="https://img.shields.io/badge/project-libp2p-blue.svg?style=flat-square" /></a>
<a href="http://webchat.freenode.net/?channels=%23ipfs"><img src="https://img.shields.io/badge/freenode-%23ipfs-blue.svg?style=flat-square" /></a>
<a href="https://waffle.io/libp2p/libp2p"><img src="https://img.shields.io/badge/pm-waffle-blue.svg?style=flat-square" /></a>
</p>
<p align="center">
<a href="https://travis-ci.org/libp2p/js-libp2p"><img src="https://travis-ci.org/libp2p/js-libp2p.svg?branch=master" /></a>
<a href="https://circleci.com/gh/libp2p/js-libp2p"><img src="https://circleci.com/gh/libp2p/js-libp2p.svg?style=svg" /></a>
<a href="https://coveralls.io/github/libp2p/js-libp2p?branch=master"><img src="https://coveralls.io/repos/github/libp2p/js-libp2p/badge.svg?branch=master"></a>
<br>
<a href="https://david-dm.org/libp2p/js-libp2p"><img src="https://david-dm.org/libp2p/js-libp2p.svg?style=flat-square" /></a>
<a href="https://github.com/feross/standard"><img src="https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square"></a>
<a href="https://github.com/RichardLitt/standard-readme"><img src="https://img.shields.io/badge/standard--readme-OK-green.svg?style=flat-square" /></a>
<a href=""><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>
<br>
</p>
## Table of Contents ## Table of Contents
@ -28,7 +43,7 @@ libp2p is the product of a long and arduous quest to understand the evolution of
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 writting better documentation, blog posts, tutorials and a formal specification. Today you can find:
- [libp2p.io - The libp2p Website (WIP)](https://github.com/libp2p/website) - [libp2p.io](https://libp2p.io)
- [Specification (WIP)](https://github.com/libp2p/specs) - [Specification (WIP)](https://github.com/libp2p/specs)
- Talks - Talks
- [`libp2p <3 ethereum` at DEVCON2](https://ethereumfoundation.org/devcon/?session=libp2p) [video](https://www.youtube.com/watch?v=HxueJbeMVG4) [slides](https://ethereumfoundation.org/devcon/wp-content/uploads/2016/10/libp2p-HEART-devp2p-IPFS-PLUS-Ethereum-networking.pdf) [demo-1](https://ethereumfoundation.org/devcon/wp-content/uploads/2016/10/libp2p_demo1-1.mp4) [demo-2](https://ethereumfoundation.org/devcon/wp-content/uploads/2016/10/libp2p_demo2-1.mp4) - [`libp2p <3 ethereum` at DEVCON2](https://ethereumfoundation.org/devcon/?session=libp2p) [video](https://www.youtube.com/watch?v=HxueJbeMVG4) [slides](https://ethereumfoundation.org/devcon/wp-content/uploads/2016/10/libp2p-HEART-devp2p-IPFS-PLUS-Ethereum-networking.pdf) [demo-1](https://ethereumfoundation.org/devcon/wp-content/uploads/2016/10/libp2p_demo1-1.mp4) [demo-2](https://ethereumfoundation.org/devcon/wp-content/uploads/2016/10/libp2p_demo2-1.mp4)
@ -41,8 +56,8 @@ To sum up, libp2p is a "network stack" -- a protocol suite -- that cleanly separ
With its modular nature, libp2p can be found being used in different projects with different sets of features, while preserving the same top level API. `js-libp2p` is only a skeleton and should not be installed directly, if you are looking for a prebundled libp2p stack, please check: With its modular nature, libp2p can be found being used in different projects with different sets of features, while preserving the same top level API. `js-libp2p` is only a skeleton and should not be installed directly, if you are looking for a prebundled libp2p stack, please check:
- [libp2p-ipfs-nodejs](https://github.com/ipfs/js-libp2p-ipfs-nodejs) - The libp2p build used by js-ipfs when run in Node.js - [libp2p-ipfs-nodejs](https://github.com/ipfs/js-ipfs/tree/master/src/core/runtime/libp2p-nodejs.js) - The libp2p build used by js-ipfs when run in Node.js
- [libp2p-ipfs-browser](https://github.com/ipfs/js-libp2p-ipfs-browser) - The libp2p build used by js-ipfs when run in a Browser (that supports WebRTC) - [libp2p-ipfs-browser](https://github.com/ipfs/js-ipfs/tree/master/src/core/runtime/libp2p-browser.js) - The libp2p build used by js-ipfs when run in a Browser (that supports WebRTC)
If you have developed a libp2p bundle, please consider submitting it to this list so that it can be found easily by the users of libp2p. If you have developed a libp2p bundle, please consider submitting it to this list so that it can be found easily by the users of libp2p.
@ -75,6 +90,7 @@ const WS = require('libp2p-websockets')
const spdy = require('libp2p-spdy') const spdy = require('libp2p-spdy')
const secio = require('libp2p-secio') const secio = require('libp2p-secio')
const MulticastDNS = require('libp2p-mdns') const MulticastDNS = require('libp2p-mdns')
const DHT = require('libp2p-kad-dht')
class Node extends libp2p { class Node extends libp2p {
constructor (peerInfo, peerBook, options) { constructor (peerInfo, peerBook, options) {
@ -95,7 +111,9 @@ class Node extends libp2p {
}, },
discovery: [ discovery: [
new MulticastDNS(peerInfo, 'your-identifier') new MulticastDNS(peerInfo, 'your-identifier')
] ],
// DHT is passed as its own enabling PeerRouting, ContentRouting and DHT itself components
dht: DHT
} }
super(modules, peerInfo, peerBook, options) super(modules, peerInfo, peerBook, options)
@ -144,6 +162,35 @@ class Node extends libp2p {
`callback` is a function with the following `function (err) {}` signature, where `err` is an Error in case stopping the node fails. `callback` is a function with the following `function (err) {}` signature, where `err` is an Error in case stopping the node fails.
#### `libp2p.peerRouting.findPeer(id, callback)`
> Looks up for multiaddrs of a peer in the DHT
- `id`: instance of [PeerId][]
#### `libp2p.contentRouting.findProviders(key, timeout, callback)`
- `key`: Buffer
- `timeout`: Number miliseconds
#### `libp2p.contentRouting.provide(key, callback)`
- `key`: Buffer
#### `libp2p.dht.put(key, value, callback)`
- `key`: Buffer
- `value`: Buffer
#### `libp2p.dht.get(key, callback)`
- `key`: Buffer
#### `libp2p.dht.getMany(key, nVals, callback)`
- `key`: Buffer
- `nVals`: Number
#### `libp2p.handle(protocol, handlerFunc [, matchFunc])` #### `libp2p.handle(protocol, handlerFunc [, matchFunc])`
> Handle new protocol > Handle new protocol
@ -158,12 +205,24 @@ class Node extends libp2p {
- `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0') - `protocol`: String that defines the protocol (e.g '/ipfs/bitswap/1.1.0')
#### `libp2p.on('peer', (peer) => {})` #### `libp2p.on('peer:discovery', (peer) => {})`
> Peer has been discovered. > Peer has been discovered.
- `peer`: instance of [PeerInfo][] - `peer`: instance of [PeerInfo][]
#### `libp2p.on('peer:connect', (peer) => {})`
> We connected to a new peer
- `peer`: instance of [PeerInfo][]
#### `libp2p.on('peer:disconnect', (peer) => {})`
> We disconnected from Peer
- `peer`: instance of [PeerInfo][]
#### `libp2p.isOn()` #### `libp2p.isOn()`
> Check if libp2p is started > Check if libp2p is started
@ -205,9 +264,6 @@ List of packages currently in existence for libp2p
| Package | Version | Dependencies | DevDependencies | | Package | Version | Dependencies | DevDependencies |
|---------|---------|--------------|-----------------| |---------|---------|--------------|-----------------|
| **Bundles** |
| [`libp2p-ipfs-nodejs`](//github.com/ipfs/js-libp2p-ipfs-nodejs) | [![npm](https://img.shields.io/npm/v/libp2p-ipfs-nodejs.svg?maxAge=86400&style=flat-square)](//github.com/ipfs/js-libp2p-ipfs-nodejs/releases) | [![Dependency Status](https://david-dm.org/ipfs/js-libp2p-ipfs-nodejs.svg?style=flat-square)](https://david-dm.org/ipfs/js-libp2p-ipfs-nodejs) | [![devDependency Status](https://david-dm.org/ipfs/js-libp2p-ipfs-nodejs/dev-status.svg?style=flat-square)](https://david-dm.org/ipfs/js-libp2p-ipfs-nodejs?type=dev) |
| [`libp2p-ipfs-browser`](//github.com/ipfs/js-libp2p-ipfs-browser) | [![npm](https://img.shields.io/npm/v/libp2p-ipfs-browser.svg?maxAge=86400&style=flat-square)](//github.com/ipfs/js-libp2p-ipfs-browser/releases) | [![Dependency Status](https://david-dm.org/ipfs/js-libp2p-ipfs-browser.svg?style=flat-square)](https://david-dm.org/ipfs/js-libp2p-ipfs-browser) | [![devDependency Status](https://david-dm.org/ipfs/js-libp2p-ipfs-browser/dev-status.svg?style=flat-square)](https://david-dm.org/ipfs/js-libp2p-ipfs-browser?type=dev) |
| **Transports** | | **Transports** |
| [`libp2p-utp`](//github.com/libp2p/js-libp2p-utp) | [![npm](https://img.shields.io/npm/v/libp2p-utp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utp/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-utp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-utp/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp?type=dev) | | [`libp2p-utp`](//github.com/libp2p/js-libp2p-utp) | [![npm](https://img.shields.io/npm/v/libp2p-utp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utp/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-utp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-utp/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp?type=dev) |
| [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/libp2p-websockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-websockets/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets?type=dev) | | [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/libp2p-websockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Dependency Status](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) | [![devDependency Status](https://david-dm.org/libp2p/js-libp2p-websockets/dev-status.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets?type=dev) |

View File

@ -1,6 +1,11 @@
### Examples list # `js-libp2p` Examples and Tutorials
Here are some examples built with libp2p bundles. In this folder, you can find a variety of examples to help you get started in using js-libp2p, in Node.js and in the Browser. Every example as a specific purpose and some of each incorporate a full tutorial that you can follow through, helping you expand your knowledge about libp2p and p2p networks in general.
- https://github.com/ipfs/js-libp2p-ipfs/tree/master/examples/echo Let us know if you find any issue or if you want to contribute and add a new tutorial, feel welcome to submit a PR, thank you!
- https://github.com/ipfs/js-libp2p-ipfs/tree/master/examples/chat
## Examples
- [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)

View File

@ -1,4 +0,0 @@
Using libp2p-swarm
==================

View File

@ -1,39 +0,0 @@
'use strict'
var Swarm = require('libp2p-swarm')
var tcp = require('libp2p-tcp')
var multiaddr = require('multiaddr')
var Id = require('peer-id')
var Spdy = require('libp2p-spdy')
var Libp2p = require('../../src')
var Peer = require('peer-info')
// set up
var mh = multiaddr('/ip4/127.0.0.1/tcp/8010')
var p = new Peer(Id.create(), [])
var sw = new Swarm(p)
// create a libp2p node
var node = new Libp2p(sw)
node.swarm.addTransport('tcp', tcp, {multiaddr: mh}, {}, {port: 8010}, function () {
// Ready to receive incoming connections
sw.addStreamMuxer('spdy', Spdy, {})
// dial to another node
var mh2 = multiaddr('/ip4/127.0.0.1/tcp/8020')
var p2 = new Peer(Id.create(), [mh2])
node.swarm.dial(p2, {}, '/sparkles/1.0.0', function (err, conn) {
if (err) {
return console.error(err)
}
console.log('-> connection is ready')
process.stdin.pipe(conn).pipe(process.stdout)
})
})

View File

@ -1,31 +0,0 @@
'use strict'
var Swarm = require('libp2p-swarm')
var tcp = require('libp2p-tcp')
var multiaddr = require('multiaddr')
var Id = require('peer-id')
var Spdy = require('libp2p-spdy')
var Libp2p = require('../../src')
var Peer = require('peer-info')
// set up
var mh = multiaddr('/ip4/127.0.0.1/tcp/8020')
var p = new Peer(Id.create(), [])
var sw = new Swarm(p)
sw.addTransport('tcp', tcp, {multiaddr: mh}, {}, {port: 8020}, function () {
// Ready to receive incoming connections
sw.addStreamMuxer('spdy', Spdy, {})
// create a libp2p node
var node = new Libp2p(sw)
// handle/mount a protocol
node.swarm.handleProtocol('/sparkles/1.0.0', function (conn) {
process.stdin.pipe(conn).pipe(process.stdout)
})
})

1
examples/chat/README.md Normal file
View File

@ -0,0 +1 @@
# Chat example with libp2p

View File

@ -0,0 +1,77 @@
'use strict'
/* eslint-disable no-console */
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const Node = require('./libp2p-bundle')
const pull = require('pull-stream')
const async = require('async')
const Pushable = require('pull-pushable')
const p = Pushable()
let idListener
async.parallel([
(callback) => {
PeerId.createFromJSON(require('./peer-id-dialer'), (err, idDialer) => {
if (err) {
throw err
}
callback(null, idDialer)
})
},
(callback) => {
PeerId.createFromJSON(require('./peer-id-listener'), (err, idListener) => {
if (err) {
throw err
}
callback(null, idListener)
})
}
], (err, ids) => {
if (err) throw err
const peerDialer = new PeerInfo(ids[0])
peerDialer.multiaddr.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')
nodeDialer.start((err) => {
if (err) {
throw err
}
console.log('Dialer ready, listening on:')
peerListener.multiaddrs.forEach((ma) => {
console.log(ma.toString() + '/ipfs/' + idListener.toB58String())
})
nodeDialer.dialByPeerInfo(peerListener, '/chat/1.0.0', (err, conn) => {
if (err) {
throw err
}
console.log('nodeA dialed to nodeB on protocol: /chat/1.0.0')
console.log('Type a message and see what happens')
// Write operation. Data sent as a buffer
pull(
p,
conn
)
// Sink, data converted from buffer to utf8 string
pull(
conn,
pull.map((data) => {
return data.toString('utf8').replace('\n', '')
}),
pull.drain(console.log)
)
process.stdin.setEncoding('utf8')
process.openStdin().on('data', (chunk) => {
var data = chunk.toString()
p.push(data)
})
})
})
})

View File

@ -0,0 +1,80 @@
'use strict'
const TCP = require('libp2p-tcp')
const MulticastDNS = require('libp2p-mdns')
const WS = require('libp2p-websockets')
const Railing = require('libp2p-railing')
const spdy = require('libp2p-spdy')
const KadDHT = require('libp2p-kad-dht')
const multiplex = require('libp2p-multiplex')
const secio = require('libp2p-secio')
const libp2p = require('../..')
function mapMuxers (list) {
return list.map((pref) => {
if (typeof pref !== 'string') {
return pref
}
switch (pref.trim().toLowerCase()) {
case 'spdy': return spdy
case 'multiplex': return multiplex
default:
throw new Error(pref + ' muxer not available')
}
})
}
function getMuxers (muxers) {
const muxerPrefs = process.env.LIBP2P_MUXER
if (muxerPrefs && !muxers) {
return mapMuxers(muxerPrefs.split(','))
} else if (muxers) {
return mapMuxers(muxers)
} else {
return [multiplex, spdy]
}
}
class Node extends libp2p {
constructor (peerInfo, peerBook, options) {
options = options || {}
const modules = {
transport: [
new TCP(),
new WS()
],
connection: {
muxer: getMuxers(options.muxer),
crypto: [ secio ]
},
discovery: []
}
if (options.dht) {
modules.DHT = KadDHT
}
if (options.mdns) {
const mdns = new MulticastDNS(peerInfo, 'ipfs.local')
modules.discovery.push(mdns)
}
if (options.bootstrap) {
const r = new Railing(options.bootstrap)
modules.discovery.push(r)
}
if (options.modules && options.modules.transport) {
options.modules.transport.forEach((t) => modules.transport.push(t))
}
if (options.modules && options.modules.discovery) {
options.modules.discovery.forEach((d) => modules.discovery.push(d))
}
super(modules, peerInfo, peerBook, options)
}
}
module.exports = Node

View File

@ -0,0 +1,54 @@
'use strict'
/* eslint-disable no-console */
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const Node = require('./libp2p-bundle.js')
const pull = require('pull-stream')
const Pushable = require('pull-pushable')
const p = Pushable()
PeerId.createFromJSON(require('./peer-id-listener'), (err, idListener) => {
if (err) {
throw err
}
const peerListener = new PeerInfo(idListener)
peerListener.multiaddr.add('/ip4/0.0.0.0/tcp/10333')
const nodeListener = new Node(peerListener)
nodeListener.start((err) => {
if (err) {
throw err
}
nodeListener.swarm.on('peer-mux-established', (peerInfo) => {
console.log(peerInfo.id.toB58String())
})
nodeListener.handle('/chat/1.0.0', (protocol, conn) => {
pull(
p,
conn
)
pull(
conn,
pull.map((data) => {
return data.toString('utf8').replace('\n', '')
}),
pull.drain(console.log)
)
process.stdin.setEncoding('utf8')
process.openStdin().on('data', (chunk) => {
var data = chunk.toString()
p.push(data)
})
})
console.log('Listener ready, listening on:')
peerListener.multiaddrs.forEach((ma) => {
console.log(ma.toString() + '/ipfs/' + idListener.toB58String())
})
})
})

View File

@ -0,0 +1,5 @@
{
"id": "Qma3GsJmB47xYuyahPZPSadh1avvxfyYQwk8R3UnFrQ6aP",
"privKey": "CAASpwkwggSjAgEAAoIBAQCaNSDOjPz6T8HZsf7LDpxiQRiN2OjeyIHUS05p8QWOr3EFUCFsC31R4moihE5HN+FxNalUyyFZU//yjf1pdnlMJqrVByJSMa+y2y4x2FucpoCAO97Tx+iWzwlZ2UXEUXM1Y81mhPbeWXy+wP2xElTgIER0Tsn/thoA0SD2u9wJuVvM7dB7cBcHYmqV6JH+KWCedRTum6O1BssqP/4Lbm2+rkrbZ4+oVRoU2DRLoFhKqwqLtylrbuj4XOI3XykMXV5+uQXz1JzubNOB9lsc6K+eRC+w8hhhDuFMgzkZ4qomCnx3uhO67KaICd8yqqBa6PJ/+fBM5Xk4hjyR40bwcf41AgMBAAECggEAZnrCJ6IYiLyyRdr9SbKXCNDb4YByGYPEi/HT1aHgIJfFE1PSMjxcdytxfyjP4JJpVtPjiT9JFVU2ddoYu5qJN6tGwjVwgJEWg1UXmPaAw1T/drjS94kVsAs82qICtFmwp52Apg3dBZ0Qwq/8qE1XbG7lLyohIbfCBiL0tiPYMfkcsN9gnFT/kFCX0LVs2pa9fHCRMY9rqCc4/rWJa1w8sMuQ23y4lDaxKF9OZVvOHFQkbBDrkquWHE4r55fchCz/rJklkPJUNENuncBRu0/2X+p4IKFD1DnttXNwb8j4LPiSlLro1T0hiUr5gO2QmdYwXFF63Q3mjQy0+5I4eNbjjQKBgQDZvZy3gUKS/nQNkYfq9za80uLbIj/cWbO+ZZjXCsj0fNIcQFJcKMBoA7DjJvu2S/lf86/41YHkPdmrLAEQAkJ+5BBNOycjYK9minTEjIMMmZDTXXugZ62wnU6F46uLkgEChTqEP57Y6xwwV+JaEDFEsW5N1eE9lEVX9nGIr4phMwKBgQC1TazLuEt1WBx/iUT83ita7obXqoKNzwsS/MWfY2innzYZKDOqeSYZzLtt9uTtp4X4uLyPbYs0qFYhXLsUYMoGHNN8+NdjoyxCjQRJRBkMtaNR0lc5lVDWl3bTuJovjFCgAr9uqJrmI5OHcCIk/cDpdWb3nWaMihVlePmiTcTy9wKBgQCU0u7c1jKkudqks4XM6a+2HAYGdUBk4cLjLhnrUWnNAcuyl5wzdX8dGPi8KZb+IKuQE8WBNJ2VXVj7kBYh1QmSJVunDflQSvNYCOaKuOeRoxzD+y9Wkca74qkbBmPn/6FFEb7PSZTO+tPHjyodGNgz9XpJJRjQuBk1aDJtlF3m1QKBgE5SAr5ym65SZOU3UGUIOKRsfDW4Q/OsqDUImvpywCgBICaX9lHDShFFHwau7FA52ScL7vDquoMB4UtCOtLfyQYA9995w9oYCCurrVlVIJkb8jSLcADBHw3EmqF1kq3NqJqm9TmBfoDCh52vdCCUufxgKh33kfBOSlXuf7B8dgMbAoGAZ3r0/mBQX6S+s5+xCETMTSNv7TQzxgtURIpVs+ZVr2cMhWhiv+n0Omab9X9Z50se8cWl5lkvx8vn3D/XHHIPrMF6qk7RAXtvReb+PeitNvm0odqjFv0J2qki6fDs0HKwq4kojAXI1Md8Th0eobNjsy21fEEJT7uKMJdovI/SErI=",
"pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaNSDOjPz6T8HZsf7LDpxiQRiN2OjeyIHUS05p8QWOr3EFUCFsC31R4moihE5HN+FxNalUyyFZU//yjf1pdnlMJqrVByJSMa+y2y4x2FucpoCAO97Tx+iWzwlZ2UXEUXM1Y81mhPbeWXy+wP2xElTgIER0Tsn/thoA0SD2u9wJuVvM7dB7cBcHYmqV6JH+KWCedRTum6O1BssqP/4Lbm2+rkrbZ4+oVRoU2DRLoFhKqwqLtylrbuj4XOI3XykMXV5+uQXz1JzubNOB9lsc6K+eRC+w8hhhDuFMgzkZ4qomCnx3uhO67KaICd8yqqBa6PJ/+fBM5Xk4hjyR40bwcf41AgMBAAE="
}

View File

@ -0,0 +1,5 @@
{
"id": "QmcrQZ6RJdpYuGvZqD5QEHAv6qX4BrQLJLQPQUrTrzdcgm",
"privKey": "CAASqAkwggSkAgEAAoIBAQDLZZcGcbe4urMBVlcHgN0fpBymY+xcr14ewvamG70QZODJ1h9sljlExZ7byLiqRB3SjGbfpZ1FweznwNxWtWpjHkQjTVXeoM4EEgDSNO/Cg7KNlU0EJvgPJXeEPycAZX9qASbVJ6EECQ40VR/7+SuSqsdL1hrmG1phpIju+D64gLyWpw9WEALfzMpH5I/KvdYDW3N4g6zOD2mZNp5y1gHeXINHWzMF596O72/6cxwyiXV1eJ000k1NVnUyrPjXtqWdVLRk5IU1LFpoQoXZU5X1hKj1a2qt/lZfH5eOrF/ramHcwhrYYw1txf8JHXWO/bbNnyemTHAvutZpTNrsWATfAgMBAAECggEAQj0obPnVyjxLFZFnsFLgMHDCv9Fk5V5bOYtmxfvcm50us6ye+T8HEYWGUa9RrGmYiLweuJD34gLgwyzE1RwptHPj3tdNsr4NubefOtXwixlWqdNIjKSgPlaGULQ8YF2tm/kaC2rnfifwz0w1qVqhPReO5fypL+0ShyANVD3WN0Fo2ugzrniCXHUpR2sHXSg6K+2+qWdveyjNWog34b7CgpV73Ln96BWae6ElU8PR5AWdMnRaA9ucA+/HWWJIWB3Fb4+6uwlxhu2L50Ckq1gwYZCtGw63q5L4CglmXMfIKnQAuEzazq9T4YxEkp+XDnVZAOgnQGUBYpetlgMmkkh9qQKBgQDvsEs0ThzFLgnhtC2Jy//ZOrOvIAKAZZf/mS08AqWH3L0/Rjm8ZYbLsRcoWU78sl8UFFwAQhMRDBP9G+RPojWVahBL/B7emdKKnFR1NfwKjFdDVaoX5uNvZEKSl9UubbC4WZJ65u/cd5jEnj+w3ir9G8n+P1gp/0yBz02nZXFgSwKBgQDZPQr4HBxZL7Kx7D49ormIlB7CCn2i7mT11Cppn5ifUTrp7DbFJ2t9e8UNk6tgvbENgCKXvXWsmflSo9gmMxeEOD40AgAkO8Pn2R4OYhrwd89dECiKM34HrVNBzGoB5+YsAno6zGvOzLKbNwMG++2iuNXqXTk4uV9GcI8OnU5ZPQKBgCZUGrKSiyc85XeiSGXwqUkjifhHNh8yH8xPwlwGUFIZimnD4RevZI7OEtXw8iCWpX2gg9XGuyXOuKORAkF5vvfVriV4e7c9Ad4Igbj8mQFWz92EpV6NHXGCpuKqRPzXrZrNOA9PPqwSs+s9IxI1dMpk1zhBCOguWx2m+NP79NVhAoGBAI6WSoTfrpu7ewbdkVzTWgQTdLzYNe6jmxDf2ZbKclrf7lNr/+cYIK2Ud5qZunsdBwFdgVcnu/02czeS42TvVBgs8mcgiQc/Uy7yi4/VROlhOnJTEMjlU2umkGc3zLzDgYiRd7jwRDLQmMrYKNyEr02HFKFn3w8kXSzW5I8rISnhAoGBANhchHVtJd3VMYvxNcQb909FiwTnT9kl9pkjhwivx+f8/K8pDfYCjYSBYCfPTM5Pskv5dXzOdnNuCj6Y2H/9m2SsObukBwF0z5Qijgu1DsxvADVIKZ4rzrGb4uSEmM6200qjJ/9U98fVM7rvOraakrhcf9gRwuspguJQnSO9cLj6",
"pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLZZcGcbe4urMBVlcHgN0fpBymY+xcr14ewvamG70QZODJ1h9sljlExZ7byLiqRB3SjGbfpZ1FweznwNxWtWpjHkQjTVXeoM4EEgDSNO/Cg7KNlU0EJvgPJXeEPycAZX9qASbVJ6EECQ40VR/7+SuSqsdL1hrmG1phpIju+D64gLyWpw9WEALfzMpH5I/KvdYDW3N4g6zOD2mZNp5y1gHeXINHWzMF596O72/6cxwyiXV1eJ000k1NVnUyrPjXtqWdVLRk5IU1LFpoQoXZU5X1hKj1a2qt/lZfH5eOrF/ramHcwhrYYw1txf8JHXWO/bbNnyemTHAvutZpTNrsWATfAgMBAAE="
}

1
examples/echo/README.md Normal file
View File

@ -0,0 +1 @@
# Echo example with libp2p

View File

@ -0,0 +1,56 @@
'use strict'
/* eslint-disable no-console */
/*
* Dialer Node
*/
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const Node = require('./libp2p-bundle')
const pull = require('pull-stream')
const async = require('async')
async.parallel([
(cb) => PeerId.createFromJSON(require('./id-d'), cb),
(cb) => PeerId.createFromJSON(require('./id-l'), cb)
], (err, ids) => {
if (err) { throw err }
// Dialer
const dialerId = ids[0]
const dialerPeerInfo = new PeerInfo(dialerId)
dialerPeerInfo.multiaddr.add('/ip4/0.0.0.0/tcp/0')
const dialerNode = new Node(dialerPeerInfo)
// Peer to Dial
const listenerPeerInfo = new PeerInfo(ids[1])
const listenerId = ids[1]
const listenerMultiaddr = '/ip4/127.0.0.1/tcp/10333/ipfs/' +
listenerId.toB58String()
listenerPeerInfo.multiaddr.add(listenerMultiaddr)
dialerNode.start((err) => {
if (err) { throw err }
console.log('Dialer ready, listening on:')
dialerPeerInfo.multiaddrs.forEach((ma) => console.log(ma.toString() +
'/ipfs/' + dialerId.toB58String()))
console.log('Dialing to peer:', listenerMultiaddr.toString())
dialerNode.dialByPeerInfo(listenerPeerInfo, '/echo/1.0.0', (err, conn) => {
if (err) { throw err }
console.log('nodeA dialed to nodeB on protocol: /echo/1.0.0')
pull(
pull.values(['hey']),
conn,
pull.collect((err, data) => {
if (err) { throw err }
console.log('received echo:', data.toString())
})
)
})
})
})

View File

@ -0,0 +1,5 @@
{
"id": "Qma3GsJmB47xYuyahPZPSadh1avvxfyYQwk8R3UnFrQ6aP",
"privKey": "CAASpwkwggSjAgEAAoIBAQCaNSDOjPz6T8HZsf7LDpxiQRiN2OjeyIHUS05p8QWOr3EFUCFsC31R4moihE5HN+FxNalUyyFZU//yjf1pdnlMJqrVByJSMa+y2y4x2FucpoCAO97Tx+iWzwlZ2UXEUXM1Y81mhPbeWXy+wP2xElTgIER0Tsn/thoA0SD2u9wJuVvM7dB7cBcHYmqV6JH+KWCedRTum6O1BssqP/4Lbm2+rkrbZ4+oVRoU2DRLoFhKqwqLtylrbuj4XOI3XykMXV5+uQXz1JzubNOB9lsc6K+eRC+w8hhhDuFMgzkZ4qomCnx3uhO67KaICd8yqqBa6PJ/+fBM5Xk4hjyR40bwcf41AgMBAAECggEAZnrCJ6IYiLyyRdr9SbKXCNDb4YByGYPEi/HT1aHgIJfFE1PSMjxcdytxfyjP4JJpVtPjiT9JFVU2ddoYu5qJN6tGwjVwgJEWg1UXmPaAw1T/drjS94kVsAs82qICtFmwp52Apg3dBZ0Qwq/8qE1XbG7lLyohIbfCBiL0tiPYMfkcsN9gnFT/kFCX0LVs2pa9fHCRMY9rqCc4/rWJa1w8sMuQ23y4lDaxKF9OZVvOHFQkbBDrkquWHE4r55fchCz/rJklkPJUNENuncBRu0/2X+p4IKFD1DnttXNwb8j4LPiSlLro1T0hiUr5gO2QmdYwXFF63Q3mjQy0+5I4eNbjjQKBgQDZvZy3gUKS/nQNkYfq9za80uLbIj/cWbO+ZZjXCsj0fNIcQFJcKMBoA7DjJvu2S/lf86/41YHkPdmrLAEQAkJ+5BBNOycjYK9minTEjIMMmZDTXXugZ62wnU6F46uLkgEChTqEP57Y6xwwV+JaEDFEsW5N1eE9lEVX9nGIr4phMwKBgQC1TazLuEt1WBx/iUT83ita7obXqoKNzwsS/MWfY2innzYZKDOqeSYZzLtt9uTtp4X4uLyPbYs0qFYhXLsUYMoGHNN8+NdjoyxCjQRJRBkMtaNR0lc5lVDWl3bTuJovjFCgAr9uqJrmI5OHcCIk/cDpdWb3nWaMihVlePmiTcTy9wKBgQCU0u7c1jKkudqks4XM6a+2HAYGdUBk4cLjLhnrUWnNAcuyl5wzdX8dGPi8KZb+IKuQE8WBNJ2VXVj7kBYh1QmSJVunDflQSvNYCOaKuOeRoxzD+y9Wkca74qkbBmPn/6FFEb7PSZTO+tPHjyodGNgz9XpJJRjQuBk1aDJtlF3m1QKBgE5SAr5ym65SZOU3UGUIOKRsfDW4Q/OsqDUImvpywCgBICaX9lHDShFFHwau7FA52ScL7vDquoMB4UtCOtLfyQYA9995w9oYCCurrVlVIJkb8jSLcADBHw3EmqF1kq3NqJqm9TmBfoDCh52vdCCUufxgKh33kfBOSlXuf7B8dgMbAoGAZ3r0/mBQX6S+s5+xCETMTSNv7TQzxgtURIpVs+ZVr2cMhWhiv+n0Omab9X9Z50se8cWl5lkvx8vn3D/XHHIPrMF6qk7RAXtvReb+PeitNvm0odqjFv0J2qki6fDs0HKwq4kojAXI1Md8Th0eobNjsy21fEEJT7uKMJdovI/SErI=",
"pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCaNSDOjPz6T8HZsf7LDpxiQRiN2OjeyIHUS05p8QWOr3EFUCFsC31R4moihE5HN+FxNalUyyFZU//yjf1pdnlMJqrVByJSMa+y2y4x2FucpoCAO97Tx+iWzwlZ2UXEUXM1Y81mhPbeWXy+wP2xElTgIER0Tsn/thoA0SD2u9wJuVvM7dB7cBcHYmqV6JH+KWCedRTum6O1BssqP/4Lbm2+rkrbZ4+oVRoU2DRLoFhKqwqLtylrbuj4XOI3XykMXV5+uQXz1JzubNOB9lsc6K+eRC+w8hhhDuFMgzkZ4qomCnx3uhO67KaICd8yqqBa6PJ/+fBM5Xk4hjyR40bwcf41AgMBAAE="
}

View File

@ -0,0 +1,5 @@
{
"id": "QmcrQZ6RJdpYuGvZqD5QEHAv6qX4BrQLJLQPQUrTrzdcgm",
"privKey": "CAASqAkwggSkAgEAAoIBAQDLZZcGcbe4urMBVlcHgN0fpBymY+xcr14ewvamG70QZODJ1h9sljlExZ7byLiqRB3SjGbfpZ1FweznwNxWtWpjHkQjTVXeoM4EEgDSNO/Cg7KNlU0EJvgPJXeEPycAZX9qASbVJ6EECQ40VR/7+SuSqsdL1hrmG1phpIju+D64gLyWpw9WEALfzMpH5I/KvdYDW3N4g6zOD2mZNp5y1gHeXINHWzMF596O72/6cxwyiXV1eJ000k1NVnUyrPjXtqWdVLRk5IU1LFpoQoXZU5X1hKj1a2qt/lZfH5eOrF/ramHcwhrYYw1txf8JHXWO/bbNnyemTHAvutZpTNrsWATfAgMBAAECggEAQj0obPnVyjxLFZFnsFLgMHDCv9Fk5V5bOYtmxfvcm50us6ye+T8HEYWGUa9RrGmYiLweuJD34gLgwyzE1RwptHPj3tdNsr4NubefOtXwixlWqdNIjKSgPlaGULQ8YF2tm/kaC2rnfifwz0w1qVqhPReO5fypL+0ShyANVD3WN0Fo2ugzrniCXHUpR2sHXSg6K+2+qWdveyjNWog34b7CgpV73Ln96BWae6ElU8PR5AWdMnRaA9ucA+/HWWJIWB3Fb4+6uwlxhu2L50Ckq1gwYZCtGw63q5L4CglmXMfIKnQAuEzazq9T4YxEkp+XDnVZAOgnQGUBYpetlgMmkkh9qQKBgQDvsEs0ThzFLgnhtC2Jy//ZOrOvIAKAZZf/mS08AqWH3L0/Rjm8ZYbLsRcoWU78sl8UFFwAQhMRDBP9G+RPojWVahBL/B7emdKKnFR1NfwKjFdDVaoX5uNvZEKSl9UubbC4WZJ65u/cd5jEnj+w3ir9G8n+P1gp/0yBz02nZXFgSwKBgQDZPQr4HBxZL7Kx7D49ormIlB7CCn2i7mT11Cppn5ifUTrp7DbFJ2t9e8UNk6tgvbENgCKXvXWsmflSo9gmMxeEOD40AgAkO8Pn2R4OYhrwd89dECiKM34HrVNBzGoB5+YsAno6zGvOzLKbNwMG++2iuNXqXTk4uV9GcI8OnU5ZPQKBgCZUGrKSiyc85XeiSGXwqUkjifhHNh8yH8xPwlwGUFIZimnD4RevZI7OEtXw8iCWpX2gg9XGuyXOuKORAkF5vvfVriV4e7c9Ad4Igbj8mQFWz92EpV6NHXGCpuKqRPzXrZrNOA9PPqwSs+s9IxI1dMpk1zhBCOguWx2m+NP79NVhAoGBAI6WSoTfrpu7ewbdkVzTWgQTdLzYNe6jmxDf2ZbKclrf7lNr/+cYIK2Ud5qZunsdBwFdgVcnu/02czeS42TvVBgs8mcgiQc/Uy7yi4/VROlhOnJTEMjlU2umkGc3zLzDgYiRd7jwRDLQmMrYKNyEr02HFKFn3w8kXSzW5I8rISnhAoGBANhchHVtJd3VMYvxNcQb909FiwTnT9kl9pkjhwivx+f8/K8pDfYCjYSBYCfPTM5Pskv5dXzOdnNuCj6Y2H/9m2SsObukBwF0z5Qijgu1DsxvADVIKZ4rzrGb4uSEmM6200qjJ/9U98fVM7rvOraakrhcf9gRwuspguJQnSO9cLj6",
"pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLZZcGcbe4urMBVlcHgN0fpBymY+xcr14ewvamG70QZODJ1h9sljlExZ7byLiqRB3SjGbfpZ1FweznwNxWtWpjHkQjTVXeoM4EEgDSNO/Cg7KNlU0EJvgPJXeEPycAZX9qASbVJ6EECQ40VR/7+SuSqsdL1hrmG1phpIju+D64gLyWpw9WEALfzMpH5I/KvdYDW3N4g6zOD2mZNp5y1gHeXINHWzMF596O72/6cxwyiXV1eJ000k1NVnUyrPjXtqWdVLRk5IU1LFpoQoXZU5X1hKj1a2qt/lZfH5eOrF/ramHcwhrYYw1txf8JHXWO/bbNnyemTHAvutZpTNrsWATfAgMBAAE="
}

View File

@ -0,0 +1,80 @@
'use strict'
const TCP = require('libp2p-tcp')
const MulticastDNS = require('libp2p-mdns')
const WS = require('libp2p-websockets')
const Railing = require('libp2p-railing')
const spdy = require('libp2p-spdy')
const KadDHT = require('libp2p-kad-dht')
const multiplex = require('libp2p-multiplex')
const secio = require('libp2p-secio')
const libp2p = require('../../..')
function mapMuxers (list) {
return list.map((pref) => {
if (typeof pref !== 'string') {
return pref
}
switch (pref.trim().toLowerCase()) {
case 'spdy': return spdy
case 'multiplex': return multiplex
default:
throw new Error(pref + ' muxer not available')
}
})
}
function getMuxers (muxers) {
const muxerPrefs = process.env.LIBP2P_MUXER
if (muxerPrefs && !muxers) {
return mapMuxers(muxerPrefs.split(','))
} else if (muxers) {
return mapMuxers(muxers)
} else {
return [multiplex, spdy]
}
}
class Node extends libp2p {
constructor (peerInfo, peerBook, options) {
options = options || {}
const modules = {
transport: [
new TCP(),
new WS()
],
connection: {
muxer: getMuxers(options.muxer),
crypto: [ secio ]
},
discovery: []
}
if (options.dht) {
modules.DHT = KadDHT
}
if (options.mdns) {
const mdns = new MulticastDNS(peerInfo, 'ipfs.local')
modules.discovery.push(mdns)
}
if (options.bootstrap) {
const r = new Railing(options.bootstrap)
modules.discovery.push(r)
}
if (options.modules && options.modules.transport) {
options.modules.transport.forEach((t) => modules.transport.push(t))
}
if (options.modules && options.modules.discovery) {
options.modules.discovery.forEach((d) => modules.discovery.push(d))
}
super(modules, peerInfo, peerBook, options)
}
}
module.exports = Node

View File

@ -0,0 +1,44 @@
'use strict'
/* eslint-disable no-console */
/*
* Listener Node
*/
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const Node = require('./libp2p-bundle')
const pull = require('pull-stream')
const series = require('async/series')
let listenerId
let listenerNode
series([
(cb) => {
PeerId.createFromJSON(require('./id-l'), (err, id) => {
if (err) { return cb(err) }
listenerId = id
cb()
})
},
(cb) => {
const listenerPeerInfo = new PeerInfo(listenerId)
listenerPeerInfo.multiaddr.add('/ip4/0.0.0.0/tcp/10333')
listenerNode = new Node(listenerPeerInfo)
listenerNode.swarm.on('peer-mux-established', (peerInfo) => {
console.log('received dial to me from:', peerInfo.id.toB58String())
})
listenerNode.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
listenerNode.start(cb)
}
], (err) => {
if (err) { throw err }
console.log('Listener ready, listening on:')
listenerNode.peerInfo.multiaddrs.forEach((ma) => {
console.log(ma.toString() + '/ipfs/' + listenerId.toB58String())
})
})

1
examples/see-nodes/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
bundle.js

View File

@ -0,0 +1,12 @@
# See nodes
> See other nodes in the network using WebRTC Star Discovery
# Try it out
```
# After having run `npm install` at the root of the repo.
> npm install
> npm start
# open your browser in port :9090
```

View File

@ -0,0 +1,22 @@
{
"name": "see-nodes",
"version": "0.0.0",
"description": "See other nodes in the network using WebRTC Star discovery mechanism",
"main": "src/index.js",
"scripts": {
"bundle": "browserify src/index.js > public/bundle.js",
"serve": "static public -p 9090 -H '{\"Cache-Control\": \"no-cache, must-revalidate\"}'",
"mon": "nodemon --exec \"npm run start\" --ignore public/bundle.js",
"start": "npm run bundle && npm run serve"
},
"license": "MIT",
"devDependencies": {
"browserify": "^14.0.0",
"browserify-optional": "^1.0.0",
"concat-stream": "^1.6.0",
"detect-dom-ready": "^1.0.2",
"node-static": "^0.7.9",
"nodemon": "^1.11.0"
},
"dependencies": {}
}

View File

@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>p2p mapper</title>
</head>
<body>
<h1>p2p mapper</h1>
<div id="my-peer"></div>
<div id="swarm"></div>
<script src="bundle.js"></script>
</body>
</html>

View File

@ -0,0 +1,24 @@
'use strict'
const PeerInfo = require('peer-info')
const Node = require('./libp2p-bundle')
function createNode (callback) {
PeerInfo.create((err, peerInfo) => {
if (err) {
return callback(err)
}
const peerIdStr = peerInfo.id.toB58String()
const ma = `/libp2p-webrtc-star/dns4/star-signal.cloud.ipfs.team/wss/ipfs/${peerIdStr}`
peerInfo.multiaddrs.add(ma)
const node = new Node(peerInfo, undefined, { webRTCStar: true })
node.idStr = peerIdStr
callback(null, node)
})
}
module.exports = createNode

View File

@ -0,0 +1,58 @@
'use strict'
const domReady = require('detect-dom-ready')
const createNode = require('./create-node')
domReady(() => {
const myPeerDiv = document.getElementById('my-peer')
const swarmDiv = document.getElementById('swarm')
createNode((err, node) => {
if (err) {
return console.log('Could not create the Node, check if your browser has WebRTC Support', err)
}
node.on('peer:discovery', (peerInfo) => {
console.log('Discovered a peer')
const idStr = peerInfo.id.toB58String()
console.log('Discovered: ' + idStr)
node.dial(peerInfo, (err, conn) => {
if (err) { return console.log('Failed to dial:', idStr) }
})
})
node.on('peer:connect', (peerInfo) => {
const idStr = peerInfo.id.toB58String()
console.log('Got connection to: ' + idStr)
const connDiv = document.createElement('div')
connDiv.innerHTML = 'Connected to: ' + idStr
connDiv.id = idStr
swarmDiv.append(connDiv)
})
node.on('peer:disconnect', (peerInfo) => {
const idStr = peerInfo.id.toB58String()
console.log('Lost connection to: ' + idStr)
document.getElementById(idStr).remove()
})
node.start((err) => {
if (err) {
return console.log('WebRTC not supported')
}
const idStr = node.peerInfo.id.toB58String()
const idDiv = document
.createTextNode('Node is ready. ID: ' + idStr)
myPeerDiv.append(idDiv)
console.log('Node is listening o/')
// NOTE: to stop the node
// node.stop((err) => {})
})
})
})

View File

@ -0,0 +1,27 @@
'use strict'
const WebRTCStar = require('libp2p-webrtc-star')
const multiplex = require('libp2p-multiplex')
const spdy = require('libp2p-spdy')
const secio = require('libp2p-secio')
const libp2p = require('../../..')
class Node extends libp2p {
constructor (peerInfo, peerBook, options) {
options = options || {}
const wstar = new WebRTCStar()
const modules = {
transport: [wstar],
connection: {
muxer: [multiplex, spdy],
crypto: [secio]
},
discovery: [wstar.discovery]
}
super(modules, peerInfo, peerBook, options)
}
}
module.exports = Node

55
gulpfile.js Normal file
View File

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

View File

@ -1,14 +1,17 @@
{ {
"name": "libp2p", "name": "libp2p",
"version": "0.6.1", "version": "0.10.0",
"description": "JavaScript Skeleton for libp2p bundles", "description": "JavaScript Skeleton for libp2p bundles",
"main": "src/index.js", "main": "src/index.js",
"scripts": { "scripts": {
"test": "aegir-test node", "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", "lint": "aegir-lint",
"release": "aegir-release node",
"release-minor": "aegir-release --type minor",
"release-major": "aegir-release --type major",
"coverage": "aegir-coverage", "coverage": "aegir-coverage",
"coverage-publish": "aegir-coverage publish" "coverage-publish": "aegir-coverage publish"
}, },
@ -34,22 +37,44 @@
}, },
"homepage": "https://github.com/libp2p/js-libp2p", "homepage": "https://github.com/libp2p/js-libp2p",
"devDependencies": { "devDependencies": {
"aegir": "^11.0.1", "aegir": "^11.0.2",
"chai": "^3.5.0", "chai": "^4.0.2",
"dirty-chai": "^1.2.2", "cids": "^0.5.0",
"pre-commit": "^1.2.2" "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.3",
"libp2p-railing": "^0.5.1",
"libp2p-secio": "^0.6.8",
"libp2p-spdy": "^0.10.6",
"libp2p-swarm": "^0.29.1",
"libp2p-tcp": "^0.10.1",
"libp2p-webrtc-star": "^0.11.0",
"libp2p-websockets": "^0.10.0",
"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",
"safe-buffer": "^5.1.1",
"wrtc": "0.0.62"
}, },
"dependencies": { "dependencies": {
"async": "^2.5.0",
"libp2p-ping": "~0.3.2", "libp2p-ping": "~0.3.2",
"libp2p-swarm": "~0.27.0", "libp2p-swarm": "~0.29.1",
"multiaddr": "^2.2.3", "mafmt": "^2.1.8",
"peer-book": "~0.3.2", "multiaddr": "^2.3.0",
"peer-id": "~0.8.5", "peer-book": "~0.4.0",
"peer-info": "~0.8.5" "peer-id": "~0.8.7",
"peer-info": "~0.9.2"
}, },
"contributors": [ "contributors": [
"David Dias <daviddias.p@gmail.com>", "David Dias <daviddias.p@gmail.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>", "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Pedro Teixeira <i@pgte.me>",
"Richard Littauer <richard.littauer@gmail.com>", "Richard Littauer <richard.littauer@gmail.com>",
"greenkeeperio-bot <support@greenkeeper.io>", "greenkeeperio-bot <support@greenkeeper.io>",
"mayerwin <mayerwin@users.noreply.github.com>" "mayerwin <mayerwin@users.noreply.github.com>"

View File

@ -1,18 +1,23 @@
'use strict' 'use strict'
const EventEmitter = require('events').EventEmitter
const assert = require('assert')
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 Swarm = require('libp2p-swarm')
const PeerId = require('peer-id') const PeerId = require('peer-id')
const PeerInfo = require('peer-info') const PeerInfo = require('peer-info')
const PeerBook = require('peer-book') const PeerBook = require('peer-book')
const mafmt = require('mafmt')
const multiaddr = require('multiaddr') const multiaddr = require('multiaddr')
const EventEmitter = require('events').EventEmitter
const assert = require('assert')
const Ping = require('libp2p-ping')
const setImmediate = require('async/setImmediate')
exports = module.exports exports = module.exports
const OFFLINE_ERROR_MESSAGE = 'The libp2p node is not started yet' const NOT_STARTED_ERROR_MESSAGE = 'The libp2p node is not started yet'
class Node extends EventEmitter { class Node extends EventEmitter {
constructor (_modules, _peerInfo, _peerBook, _options) { constructor (_modules, _peerInfo, _peerBook, _options) {
@ -23,29 +28,28 @@ class Node extends EventEmitter {
this.modules = _modules this.modules = _modules
this.peerInfo = _peerInfo this.peerInfo = _peerInfo
this.peerBook = _peerBook || new PeerBook() this.peerBook = _peerBook || new PeerBook()
this.isOnline = false this._isStarted = false
this.swarm = new Swarm(this.peerInfo) this.swarm = new Swarm(this.peerInfo, this.peerBook)
// Attach stream multiplexers // Attach stream multiplexers
if (this.modules.connection.muxer) { if (this.modules.connection.muxer) {
let muxers = this.modules.connection.muxer let muxers = this.modules.connection.muxer
muxers = Array.isArray(muxers) ? muxers : [muxers] muxers = Array.isArray(muxers) ? muxers : [muxers]
muxers.forEach((muxer) => { muxers.forEach((muxer) => this.swarm.connection.addStreamMuxer(muxer))
this.swarm.connection.addStreamMuxer(muxer)
})
// If muxer exists, we can use Identify // If muxer exists, we can use Identify
this.swarm.connection.reuse() this.swarm.connection.reuse()
// Received incommind dial and muxer upgrade happened, reuse this // Received incommind dial and muxer upgrade happened,
// muxed connection // reuse this muxed connection
this.swarm.on('peer-mux-established', (peerInfo) => { this.swarm.on('peer-mux-established', (peerInfo) => {
this.emit('peer:connect', peerInfo)
this.peerBook.put(peerInfo) this.peerBook.put(peerInfo)
}) })
this.swarm.on('peer-mux-closed', (peerInfo) => { this.swarm.on('peer-mux-closed', (peerInfo) => {
this.peerBook.removeByB58String(peerInfo.id.toB58String()) this.emit('peer:disconnect', peerInfo)
}) })
} }
@ -62,17 +66,70 @@ class Node extends EventEmitter {
if (this.modules.discovery) { if (this.modules.discovery) {
let discoveries = this.modules.discovery let discoveries = this.modules.discovery
discoveries = Array.isArray(discoveries) ? discoveries : [discoveries] discoveries = Array.isArray(discoveries) ? discoveries : [discoveries]
discoveries.forEach((discovery) => { discoveries.forEach((discovery) => {
discovery.on('peer', (peerInfo) => this.emit('peer', peerInfo)) discovery.on('peer', (peerInfo) => this.emit('peer:discovery', peerInfo))
}) })
} }
// Mount default protocols // Mount default protocols
Ping.mount(this.swarm) Ping.mount(this.swarm)
// Not fully implemented in js-libp2p yet // dht provided components (peerRouting, contentRouting, dht)
this.routing = undefined if (_modules.DHT) {
this.records = undefined this._dht = new this.modules.DHT(this, 20, _options.DHT && _options.DHT.datastore)
}
this.peerRouting = {
findPeer: (id, callback) => {
if (!this._dht) {
return callback(new Error('DHT is not available'))
}
this._dht.findPeer(id, callback)
}
}
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)
}
}
} }
/* /*
@ -88,7 +145,18 @@ class Node extends EventEmitter {
let transports = this.modules.transport let transports = this.modules.transport
transports = Array.isArray(transports) ? transports : [transports] transports = Array.isArray(transports) ? transports : [transports]
const multiaddrs = this.peerInfo.multiaddrs
// 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)) {
maOld.push(ma)
maNew.push(ma.encapsulate('/ipfs/' + this.peerInfo.id.toB58String()))
}
})
this.peerInfo.multiaddrs.replace(maOld, maNew)
const multiaddrs = this.peerInfo.multiaddrs.toArray()
transports.forEach((transport) => { transports.forEach((transport) => {
if (transport.filter(multiaddrs).length > 0) { if (transport.filter(multiaddrs).length > 0) {
@ -102,31 +170,41 @@ class Node extends EventEmitter {
} }
}) })
this.swarm.listen((err) => { series([
if (err) { (cb) => this.swarm.listen(cb),
return callback(err) (cb) => {
} if (ws) {
if (ws) { // always add dialing on websockets
this.swarm.transport.add(ws.tag || ws.constructor.name, ws) this.swarm.transport.add(ws.tag || ws.constructor.name, ws)
} }
this.isOnline = true // all transports need to be setup before discover starts
if (this.modules.discovery) {
if (this.modules.discovery) { return each(this.modules.discovery, (d, cb) => d.start(cb), cb)
this.modules.discovery.forEach((discovery) => { }
setImmediate(() => discovery.start(() => {})) cb()
}) },
(cb) => {
// TODO: chicken-and-egg problem:
// have to set started here because DHT requires libp2p is already started
this._isStarted = true
if (this._dht) {
return this._dht.start(cb)
}
cb()
},
(cb) => {
this.emit('start')
cb()
} }
], callback)
callback()
})
} }
/* /*
* Stop the libp2p node by closing its listeners and open connections * Stop the libp2p node by closing its listeners and open connections
*/ */
stop (callback) { stop (callback) {
this.isOnline = false this._isStarted = false
if (this.modules.discovery) { if (this.modules.discovery) {
this.modules.discovery.forEach((discovery) => { this.modules.discovery.forEach((discovery) => {
@ -134,43 +212,69 @@ class Node extends EventEmitter {
}) })
} }
this.swarm.close(callback) series([
(cb) => {
if (this._dht) {
return this._dht.stop(cb)
}
cb()
},
(cb) => this.swarm.close(cb),
(cb) => {
this.emit('stop')
cb()
}
], callback)
} }
isOn () { isStarted () {
return this.isOnline return this._isStarted
} }
ping (peer, callback) { ping (peer, callback) {
assert(this.isOn(), OFFLINE_ERROR_MESSAGE) assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
const peerInfo = this._getPeerInfo(peer) this._getPeerInfo(peer, (err, peerInfo) => {
callback(null, new Ping(this.swarm, peerInfo)) if (err) {
return callback(err)
}
callback(null, new Ping(this.swarm, peerInfo))
})
} }
dial (peer, protocol, callback) { dial (peer, protocol, callback) {
assert(this.isOn(), OFFLINE_ERROR_MESSAGE) assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
const peerInfo = this._getPeerInfo(peer)
if (typeof protocol === 'function') { if (typeof protocol === 'function') {
callback = protocol callback = protocol
protocol = undefined protocol = undefined
} }
this.swarm.dial(peerInfo, protocol, (err, conn) => { this._getPeerInfo(peer, (err, peerInfo) => {
if (err) { if (err) {
return callback(err) return callback(err)
} }
this.peerBook.put(peerInfo)
callback(null, conn) this.swarm.dial(peerInfo, protocol, (err, conn) => {
if (err) {
return callback(err)
}
this.peerBook.put(peerInfo)
callback(null, conn)
})
}) })
} }
hangUp (peer, callback) { hangUp (peer, callback) {
assert(this.isOn(), OFFLINE_ERROR_MESSAGE) assert(this.isStarted(), NOT_STARTED_ERROR_MESSAGE)
const peerInfo = this._getPeerInfo(peer)
this.peerBook.removeByB58String(peerInfo.id.toB58String()) this._getPeerInfo(peer, (err, peerInfo) => {
this.swarm.hangUp(peerInfo, callback) if (err) {
return callback(err)
}
this.swarm.hangUp(peerInfo, callback)
})
} }
handle (protocol, handlerFunc, matchFunc) { handle (protocol, handlerFunc, matchFunc) {
@ -184,31 +288,33 @@ class Node extends EventEmitter {
/* /*
* Helper method to check the data type of peer and convert it to PeerInfo * Helper method to check the data type of peer and convert it to PeerInfo
*/ */
_getPeerInfo (peer) { _getPeerInfo (peer, callback) {
let p let p
// PeerInfo
if (PeerInfo.isPeerInfo(peer)) { if (PeerInfo.isPeerInfo(peer)) {
p = peer p = peer
// Multiaddr instance (not string)
} else if (multiaddr.isMultiaddr(peer)) { } else if (multiaddr.isMultiaddr(peer)) {
const peerIdB58Str = peer.getPeerId() const peerIdB58Str = peer.getPeerId()
try { try {
p = this.peerBook.getByB58String(peerIdB58Str) p = this.peerBook.get(peerIdB58Str)
} catch (err) { } catch (err) {
p = new PeerInfo(PeerId.createFromB58String(peerIdB58Str)) p = new PeerInfo(PeerId.createFromB58String(peerIdB58Str))
} }
p.multiaddr.add(peer) p.multiaddrs.add(peer)
// PeerId
} else if (PeerId.isPeerId(peer)) { } else if (PeerId.isPeerId(peer)) {
const peerIdB58Str = peer.toB58String() const peerIdB58Str = peer.toB58String()
try { try {
p = this.peerBook.getByB58String(peerIdB58Str) p = this.peerBook.get(peerIdB58Str)
} catch (err) { } catch (err) {
// TODO this is where PeerRouting comes into place return this.peerRouting.findPeer(peer, callback)
throw new Error('No knowledge about: ' + peerIdB58Str)
} }
} else { } else {
throw new Error('peer type not recognized') return setImmediate(() => callback(new Error('peer type not recognized')))
} }
return p setImmediate(() => callback(null, p))
} }
} }

View File

@ -0,0 +1,67 @@
'use strict'
const WS = require('libp2p-websockets')
const WebRTCStar = require('libp2p-webrtc-star')
const spdy = require('libp2p-spdy')
const multiplex = require('libp2p-multiplex')
const secio = require('libp2p-secio')
const Railing = require('libp2p-railing')
const libp2p = require('../..')
function mapMuxers (list) {
return list.map((pref) => {
if (typeof pref !== 'string') {
return pref
}
switch (pref.trim().toLowerCase()) {
case 'spdy':
return spdy
case 'multiplex':
return multiplex
default:
throw new Error(pref + ' muxer not available')
}
})
}
function getMuxers (options) {
if (options) {
return mapMuxers(options)
} else {
return [multiplex, spdy]
}
}
class Node extends libp2p {
constructor (peerInfo, peerBook, options) {
options = options || {}
const webRTCStar = new WebRTCStar()
const modules = {
transport: [
new WS(),
webRTCStar
],
connection: {
muxer: getMuxers(options.muxer),
crypto: [
secio
]
},
discovery: []
}
if (options.webRTCStar) {
modules.discovery.push(webRTCStar.discovery)
}
if (options.bootstrap) {
const r = new Railing(options.bootstrap)
modules.discovery.push(r)
}
super(modules, peerInfo, peerBook, options)
}
}
module.exports = Node

View File

@ -0,0 +1,5 @@
{
"id": "Qmex1SSsueWFsUfjdkugJ5zhcnjddAt8TxcnDLUXKD9Sx7",
"privKey": "CAASqAkwggSkAgEAAoIBAQCXzV127CvVHOGMzvsn/U+/32JM58KA6k0FSCCeNFzNowiDS/vV5eezGN5AFoxsF6icWLoaczz7l9RdVD+I/t6PEt9X7XUdrDCtSS8WmAcCgvZWSSf7yAd3jT4GSZDUIgIEeRZsERDt/yVqTLwsZ1G9dMIeh8sbf2zwjTXZIWaRM6o4lq3DYFfzLvJUXlJodxPogU7l7nLkITPUv+yQAMcVHizbNwJvwiETKYeUj73/m/wEPAlnFESexDstxNiIwE/FH8Ao50QPZRO6E6Jb0hhYSI/4CLRdrzDFm/Vzplei3Wr2DokSROaNyeG37VAueyA+pDqn84um+L9uXLwbv5FbAgMBAAECggEAdBUzV/GaQ0nmoQrWvOnUxmFIho7kCjkh1NwnNVPNc+Msa1r7pcI9wJNPwap8j1w4L/cZuYhOJgcg+o2mWFiuULKZ4F9Ro/M89gZ038457g2/2pPu43c/Xoi/2YcAHXg0Gr+OCe2zCIyITBWKAFqyAzL6DubAxrJW2Ezj1LrZ+EZgMyzbh/go/eEGSJaaGkINeAkY144DqDWWWvzyhKhryipsGkZGEkVy9xJgMEI3ipVvuPez2XAvoyyeuinBBLe+Z2vY5G50XXzbIMhIQGLncHf9MwTv6wt1ilyOSLOXK0BoQbB76J3R3is5dSULXXP9r8VocjLBEkmBuf4FXAKzoQKBgQDNNS4F1XE1gxD8LPkL+aB/hi6eVHVPhr+w0I/9ATikcLGeUfBM2Gd6cZRPFtNVrv1p6ZF1D1UyGDknGbDBSQd9wLUgb0fDoo3jKYMGWq6G+VvaP5rzWQeBV8YV2EhSmUk1i6kiYe2ZE8WyrPie7iwpQIY60e2A8Ly0GKZiBZUcHQKBgQC9YDAVsGnEHFVFkTDpvw5HwEzCgTb2A3NgkGY3rTYZ7L6AFjqCYmUwFB8Fmbyc4kdFWNh8wfmq5Qrvl49NtaeukiqWKUUlB8uPdztB1P0IahA2ks0owStZlRifmwfgYyMd4xE17lhaOgQQJZZPxmP0F6mdOvb3YJafNURCdMS51wKBgEvvIM+h0tmFXXSjQ6kNvzlRMtD92ccKysYn9xAdMpOO6/r0wSH+dhQWEVZO0PcE4NsfReb2PIVj90ojtIdhebcr5xpQc1LORQjJJKXmSmzBux6AqNrhl+hhzXfp56FA/Zkly/lgGWaqrV5XqUxOP+Mn8EO1yNgMvRc7g94DyNB1AoGBAKLBuXHalXwDsdHBUB2Eo3xNLGt6bEcRfia+0+sEBdxQGQWylQScFkU09dh1YaIf44sZKa5HdBFJGpYCVxo9hmjFnK5Dt/Z0daHOonIY4INLzLVqg8KECoLKXkhGEIXsDjFQhukn+G1LMVTDSSU055DQiWjlVX4UWD9qo0jOXIkvAoGBAMP50p2X6PsWWZUuuR7i1JOJHRyQZPWdHh9p8SSLnCtEpHYZfJr4INXNmhnSiB/3TUnHix2vVKjosjMTCk/CjfzXV2H41WPOLZ2/Pi3SxCicWIRj4kCcWhkEuIF2jGkg1+jmNiCl/zNMaBOAIP3QbDPtqOWbYlPd2YIzdj6WQ6R4",
"pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCXzV127CvVHOGMzvsn/U+/32JM58KA6k0FSCCeNFzNowiDS/vV5eezGN5AFoxsF6icWLoaczz7l9RdVD+I/t6PEt9X7XUdrDCtSS8WmAcCgvZWSSf7yAd3jT4GSZDUIgIEeRZsERDt/yVqTLwsZ1G9dMIeh8sbf2zwjTXZIWaRM6o4lq3DYFfzLvJUXlJodxPogU7l7nLkITPUv+yQAMcVHizbNwJvwiETKYeUj73/m/wEPAlnFESexDstxNiIwE/FH8Ao50QPZRO6E6Jb0hhYSI/4CLRdrzDFm/Vzplei3Wr2DokSROaNyeG37VAueyA+pDqn84um+L9uXLwbv5FbAgMBAAE="
}

View File

@ -0,0 +1,121 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const parallel = require('async/parallel')
const pull = require('pull-stream')
const Node = require('./browser-bundle')
describe('libp2p-ipfs-browser (webrtc only)', () => {
let peer1
let peer2
let node1
let node2
it('create two peerInfo with webrtc-star addrs', (done) => {
parallel([
(cb) => PeerId.create({ bits: 1024 }, cb),
(cb) => PeerId.create({ bits: 1024 }, cb)
], (err, ids) => {
expect(err).to.not.exist()
peer1 = new PeerInfo(ids[0])
const ma1 = '/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)
})
})
})

View File

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

7
test/browser.js Normal file
View File

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

10
test/node.js Normal file
View File

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

View File

@ -0,0 +1,90 @@
/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
const utils = require('./utils')
const createNode = utils.createNode
const _times = require('lodash.times')
const CID = require('cids')
describe('.contentRouting', () => {
let nodeA
let nodeB
let nodeC
let nodeD
let nodeE
before((done) => {
const tasks = _times(5, () => (cb) => {
createNode('/ip4/0.0.0.0/tcp/0', {
mdns: false,
dht: true
}, (err, node) => {
expect(err).to.not.exist()
node.start((err) => cb(err, node))
})
})
parallel(tasks, (err, nodes) => {
expect(err).to.not.exist()
nodeA = nodes[0]
nodeB = nodes[1]
nodeC = nodes[2]
nodeD = nodes[3]
nodeE = nodes[4]
parallel([
(cb) => nodeA.dial(nodeB.peerInfo, cb),
(cb) => nodeB.dial(nodeC.peerInfo, cb),
(cb) => nodeC.dial(nodeD.peerInfo, cb),
(cb) => nodeD.dial(nodeE.peerInfo, cb),
(cb) => nodeE.dial(nodeA.peerInfo, cb)
], done)
})
})
after((done) => {
parallel([
(cb) => nodeA.stop(cb),
(cb) => nodeB.stop(cb),
(cb) => nodeC.stop(cb),
(cb) => nodeD.stop(cb),
(cb) => nodeE.stop(cb)
], done)
})
describe('le ring', () => {
const cid = new CID('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL')
it('let kbucket get filled', (done) => {
setTimeout(() => done(), 250)
})
it('nodeA.contentRouting.provide', (done) => {
nodeA.contentRouting.provide(cid, done)
})
it('nodeE.contentRouting.findProviders for existing record', (done) => {
nodeE.contentRouting.findProviders(cid, 5000, (err, providers) => {
expect(err).to.not.exist()
expect(providers).to.have.length.above(0)
done()
})
})
it('nodeC.contentRouting.findProviders for non existing record (timeout)', (done) => {
const cid = new CID('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSnnnn')
nodeE.contentRouting.findProviders(cid, 5000, (err, providers) => {
expect(err).to.not.exist()
expect(providers).to.have.length(0)
done()
})
})
})
})

View File

@ -0,0 +1,99 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
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 createNode = utils.createNode
const echo = utils.echo
describe('discovery', () => {
let nodeA
let nodeB
let port = 24642
let ss
function setup (options) {
before((done) => {
port++
parallel([
(cb) => {
signalling.start({ port: port }, (err, server) => {
expect(err).to.not.exist()
ss = server
cb()
})
},
(cb) => createNode([
'/ip4/0.0.0.0/tcp/0',
`/libp2p-webrtc-star/ip4/127.0.0.1/tcp/${port}/ws`
], options, (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',
`/libp2p-webrtc-star/ip4/127.0.0.1/tcp/${port}/ws`
], options, (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),
(cb) => ss.stop(done)
], done)
})
}
describe('MulticastDNS', () => {
setup({ mdns: true })
it('find a peer', (done) => {
nodeA.once('peer:discovery', (peerInfo) => {
expect(nodeB.peerInfo.id.toB58String())
.to.eql(peerInfo.id.toB58String())
done()
})
})
})
// TODO needs a delay (this test is already long)
describe.skip('WebRTCStar', () => {
setup({ webRTCStar: true })
it('find a peer', (done) => {
nodeA.once('peer:discovery', (peerInfo) => {
expect(nodeB.peerInfo.id.toB58String())
.to.eql(peerInfo.id.toB58String())
done()
})
})
})
describe('MulticastDNS + WebRTCStar', () => {
setup({
webRTCStar: true,
mdns: true
})
it('find a peer', (done) => {
nodeA.once('peer:discovery', (peerInfo) => {
expect(nodeB.peerInfo.id.toB58String())
.to.eql(peerInfo.id.toB58String())
done()
})
})
})
})

View File

@ -0,0 +1,80 @@
'use strict'
const TCP = require('libp2p-tcp')
const MulticastDNS = require('libp2p-mdns')
const WS = require('libp2p-websockets')
const Railing = require('libp2p-railing')
const spdy = require('libp2p-spdy')
const KadDHT = require('libp2p-kad-dht')
const multiplex = require('libp2p-multiplex')
const secio = require('libp2p-secio')
const libp2p = require('../..')
function mapMuxers (list) {
return list.map((pref) => {
if (typeof pref !== 'string') {
return pref
}
switch (pref.trim().toLowerCase()) {
case 'spdy': return spdy
case 'multiplex': return multiplex
default:
throw new Error(pref + ' muxer not available')
}
})
}
function getMuxers (muxers) {
const muxerPrefs = process.env.LIBP2P_MUXER
if (muxerPrefs && !muxers) {
return mapMuxers(muxerPrefs.split(','))
} else if (muxers) {
return mapMuxers(muxers)
} else {
return [multiplex, spdy]
}
}
class Node extends libp2p {
constructor (peerInfo, peerBook, options) {
options = options || {}
const modules = {
transport: [
new TCP(),
new WS()
],
connection: {
muxer: getMuxers(options.muxer),
crypto: [ secio ]
},
discovery: []
}
if (options.dht) {
modules.DHT = KadDHT
}
if (options.mdns) {
const mdns = new MulticastDNS(peerInfo, 'ipfs.local')
modules.discovery.push(mdns)
}
if (options.bootstrap) {
const r = new Railing(options.bootstrap)
modules.discovery.push(r)
}
if (options.modules && options.modules.transport) {
options.modules.transport.forEach((t) => modules.transport.push(t))
}
if (options.modules && options.modules.discovery) {
options.modules.discovery.forEach((d) => modules.discovery.push(d))
}
super(modules, peerInfo, peerBook, options)
}
}
module.exports = Node

View File

@ -0,0 +1,94 @@
/* eslint-env mocha */
/* eslint max-nested-callbacks: ["error", 8] */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
const utils = require('./utils')
const createNode = utils.createNode
const _times = require('lodash.times')
describe('.peerRouting', () => {
let nodeA
let nodeB
let nodeC
let nodeD
let nodeE
before((done) => {
const tasks = _times(5, () => (cb) => {
createNode('/ip4/0.0.0.0/tcp/0', {
mdns: false,
dht: true
}, (err, node) => {
expect(err).to.not.exist()
node.start((err) => cb(err, node))
})
})
parallel(tasks, (err, nodes) => {
expect(err).to.not.exist()
nodeA = nodes[0]
nodeB = nodes[1]
nodeC = nodes[2]
nodeD = nodes[3]
nodeE = nodes[4]
parallel([
(cb) => nodeA.dial(nodeB.peerInfo, cb),
(cb) => nodeB.dial(nodeC.peerInfo, cb),
(cb) => nodeC.dial(nodeD.peerInfo, cb),
(cb) => nodeD.dial(nodeE.peerInfo, cb),
(cb) => nodeE.dial(nodeA.peerInfo, cb)
], done)
})
})
after((done) => {
parallel([
(cb) => nodeA.stop(cb),
(cb) => nodeB.stop(cb),
(cb) => nodeC.stop(cb),
(cb) => nodeD.stop(cb),
(cb) => nodeE.stop(cb)
], done)
})
describe('el ring', () => {
it('let kbucket get filled', (done) => {
setTimeout(() => done(), 250)
})
it('nodeA.dial by Id to node C', (done) => {
nodeA.dial(nodeC.peerInfo.id, (err) => {
expect(err).to.not.exist()
done()
})
})
it('nodeB.dial by Id to node D', (done) => {
nodeB.dial(nodeD.peerInfo.id, (err) => {
expect(err).to.not.exist()
done()
})
})
it('nodeC.dial by Id to node E', (done) => {
nodeC.dial(nodeE.peerInfo.id, (err) => {
expect(err).to.not.exist()
done()
})
})
it('nodeB.peerRouting.findPeer(nodeE.peerInfo.id)', (done) => {
nodeB.peerRouting.findPeer(nodeE.peerInfo.id, (err, peerInfo) => {
expect(err).to.not.exist()
expect(nodeE.peerInfo.id.toB58String()).to.equal(peerInfo.id.toB58String())
done()
})
})
})
})

View File

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

View File

@ -0,0 +1,207 @@
/* 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
function test (nodeA, nodeB, callback) {
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')])
callback()
})
)
})
}
function teardown (nodeA, nodeB, callback) {
parallel([
(cb) => nodeA.stop(cb),
(cb) => nodeB.stop(cb)
], callback)
}
describe('stream muxing', (done) => {
it('spdy only', (done) => {
let nodeA
let nodeB
function setup (callback) {
parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['spdy']
}, (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', {
muxer: ['spdy']
}, (err, node) => {
expect(err).to.not.exist()
nodeB = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
], callback)
}
series([
(cb) => setup(cb),
(cb) => test(nodeA, nodeB, cb),
(cb) => teardown(nodeA, nodeB, cb)
], done)
})
it('multiplex only', (done) => {
let nodeA
let nodeB
function setup (callback) {
parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['multiplex']
}, (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', {
muxer: ['multiplex']
}, (err, node) => {
expect(err).to.not.exist()
nodeB = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
], callback)
}
series([
(cb) => setup(cb),
(cb) => test(nodeA, nodeB, cb),
(cb) => teardown(nodeA, nodeB, cb)
], done)
})
it('spdy + multiplex', (done) => {
let nodeA
let nodeB
function setup (callback) {
parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['spdy', 'multiplex']
}, (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', {
muxer: ['spdy', 'multiplex']
}, (err, node) => {
expect(err).to.not.exist()
nodeB = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
], callback)
}
series([
(cb) => setup(cb),
(cb) => test(nodeA, nodeB, cb),
(cb) => teardown(nodeA, nodeB, cb)
], done)
})
it('spdy + multiplex switched order', (done) => {
let nodeA
let nodeB
function setup (callback) {
parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['spdy', 'multiplex']
}, (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', {
muxer: ['multiplex', 'spdy']
}, (err, node) => {
expect(err).to.not.exist()
nodeB = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
], callback)
}
series([
(cb) => setup(cb),
(cb) => test(nodeA, nodeB, cb),
(cb) => teardown(nodeA, nodeB, cb)
], done)
})
it('one without the other fails to establish a muxedConn', (done) => {
let nodeA
let nodeB
function setup (callback) {
parallel([
(cb) => createNode('/ip4/0.0.0.0/tcp/0', {
muxer: ['spdy']
}, (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', {
muxer: ['multiplex']
}, (err, node) => {
expect(err).to.not.exist()
nodeB = node
node.handle('/echo/1.0.0', echo)
node.start(cb)
})
], callback)
}
series([
(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)
nodeA.dial(nodeB.peerInfo, (err) => {
expect(err).to.not.exist()
expect(Object.keys(nodeA.swarm.muxedConns)).to.have.length(0)
cb()
})
},
(cb) => teardown(nodeA, nodeB, cb)
], done)
})
})

View File

@ -0,0 +1,246 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const expect = chai.expect
const parallel = require('async/parallel')
const signalling = require('libp2p-webrtc-star/src/sig-server')
const WStar = require('libp2p-webrtc-star')
const wrtc = require('wrtc')
const utils = require('./utils')
const createNode = utils.createNode
const echo = utils.echo
describe('TCP + WebSockets + WebRTCStar', () => {
let nodeAll
let nodeTCP
let nodeWS
let nodeWStar
let ss
before((done) => {
parallel([
(cb) => {
signalling.start({ port: 24642 }, (err, server) => {
expect(err).to.not.exist()
ss = server
cb()
})
},
(cb) => {
const wstar = new WStar({wrtc: wrtc})
createNode([
'/ip4/0.0.0.0/tcp/0',
'/ip4/127.0.0.1/tcp/25011/ws',
'/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)
}
})
})
})

View File

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

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

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

View File

@ -0,0 +1,5 @@
{
"id": "QmaG17D4kfTB2RNUCr16bSfVvUVt2Xn3rPYeqQDvnVcXFr",
"privKey": "CAASqAkwggSkAgEAAoIBAQDBpXRrSLoVhP8C4YI0nm+YTb7UIe+xT9dwaMzKcGsH2zzz1lfxl54e1XNO+6Ut+If5jswpydgHhn9nGPod53sUIR2m+BiHOAH/Blgfa1nUKUkspts1MH3z5ZaO6Xo336Y0Uaw7UqfeIzKliTM6bpev2XIHyu0v/VJ2mylzfbDLMWqZs/shE3xwCJCD/PxoVpTlr/SzzF7MdgDMxkyiC3iLZ5Zkm+baPbi3mpKM0ue25Thedcc0KFjhQrjBfy5FPamrsMn5fnnoHwnQl9u7UWigzeC+7X+38EML1sVrV37ExxHPtM6882Ivjc7VN6zFHOHD2c9eVfbShkIf8YkVQUcFAgMBAAECggEAVE1mgGo58LJknml0WNn8tS5rfEiF5AhhPyOwvBTy04nDYFgZEykxgjTkrSbqgzfmYmOjSDICJUyNXGHISYqDz4CXOyBY9U0RuWeWp58BjVan75N4bRB+VNbHk9HbDkYEQlSoCW9ze0aRfvVa4v5QdRLSDMhwN+stokrsYcX/WIWYTM2e2jW+qQOzS8SJl7wYsgtd3WikrxwXkRL3sCMHEcgcPhoKacoD5Yr9cB0IC5vzhu4t/WMa+N2UEndcKGAbXsh8kA7BPFM6lqnEpOHpWEVEAYasAwFGUvUN9GwhtqpaNNS2sG6Nrz95cC99Nqx58uIXcTAJm3Fh/WfKJ6I1xQKBgQD+g7A5OSWw+i/zhTKVPJg93/eohViL0dGZT9Tf0/VslsFl00FwnZmBKA6BJ6ZL3hD00OcqIL3m6EzZ4q38U97XZxf2OUsPPJtl+Avqtlk16AHRHB9I17LGXJ30xZRkxL665oLms0D2T4NIZZX/uVMoS18lRvCZj1aEYQFCrZYgowKBgQDCxtA695S0vl6E3Q4G6MrDZK+2JqjaGL0XTnpHWiAjnk2lnV2CCZnWpEHT+ebF2fWx5nYQo5sugc6bS+4k9jRNUgxf2sQieZYCBjbnjCEVrPTm/dPTkaw1CQ/ox5/R1/Elbw8vteF9uUAvR0FL8Ss1Dqw6B2SxdTowxMy6qQ7sNwKBgG2N3eMj2DeP2egm45kdliK8L2yYyX6V+HTXyjf2kuQFGIZuIvMIw7S2u1eY65ooon/fFEIsCdJFGB+J1X6R05BAzi2sh8StP+7qkKadi1UK4w1R352JS2jbIRrlmXSuw7LL2njXnBTqMQaOw7xp14O2vePb32EaNBGTd+ltsvulAoGBALGIc4370oA4MIDb2Ag2MXKNmJbnf+piuB/BOTVGEZtFlDKLUArR43W/+/xRgKX/97FyhVS/OxfV21Kzj9oCy0NasMrB5RojRraLoYnFsPZH0mWlIGlsEtG4c9bR9XtYX4WmR+pN1r04mCc/xGWK6b4PpK2zxXT2i9ad2pmctGxbAoGBAIcp0UML5QCqvLmcob2/6PCRaYAxJBb9lDqOHredMgQih2hGnHFCyKk9eBAbFf/KN0guJTBDaAJRclcxsLLn7rV6grMNt+0EUepm7tWT0z5j8gNGbGGhuGDdqcmfJTc2EMdQrfhzYDN3rL1v3l+Ujwla2khL2ozE7SQ/KVeA1saY",
"pubKey": "CAASpgIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBpXRrSLoVhP8C4YI0nm+YTb7UIe+xT9dwaMzKcGsH2zzz1lfxl54e1XNO+6Ut+If5jswpydgHhn9nGPod53sUIR2m+BiHOAH/Blgfa1nUKUkspts1MH3z5ZaO6Xo336Y0Uaw7UqfeIzKliTM6bpev2XIHyu0v/VJ2mylzfbDLMWqZs/shE3xwCJCD/PxoVpTlr/SzzF7MdgDMxkyiC3iLZ5Zkm+baPbi3mpKM0ue25Thedcc0KFjhQrjBfy5FPamrsMn5fnnoHwnQl9u7UWigzeC+7X+38EML1sVrV37ExxHPtM6882Ivjc7VN6zFHOHD2c9eVfbShkIf8YkVQUcFAgMBAAE="
}

View File

@ -0,0 +1,84 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
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 createNode = utils.createNode
const echo = utils.echo
describe('Turbolence tests', () => {
let nodeA
let nodeSpawn
before((done) => {
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(done)
})
})
after((done) => nodeA.stop(done))
it('spawn a node in a different process', (done) => {
const filePath = path.join(__dirname, './spawn-libp2p-node.js')
nodeSpawn = spawn(filePath, { env: process.env })
let spawned = false
nodeSpawn.stdout.on('data', (data) => {
// console.log(data.toString())
if (!spawned) {
spawned = true
done()
}
})
nodeSpawn.stderr.on('data', (data) => console.log(data.toString()))
})
it('connect nodeA to that node', (done) => {
const spawnedId = require('./test-data/test-id.json')
const maddr = multiaddr('/ip4/127.0.0.1/tcp/12345/ipfs/' + spawnedId.id)
nodeA.dial(maddr, '/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([new Buffer('hey')]),
conn,
pull.collect((err, data) => {
expect(err).to.not.exist()
expect(data).to.eql([new Buffer('hey')])
done()
})
)
})
})
it('crash that node, ensure nodeA continues going steady', (done) => {
// TODO investigate why CI crashes
setTimeout(() => nodeSpawn.kill('SIGKILL'), 1000)
// nodeSpawn.kill('SIGKILL')
setTimeout(check, 5000)
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()
}
})
})

View File

@ -0,0 +1,43 @@
/* eslint-env mocha */
'use strict'
const chai = require('chai')
chai.use(require('dirty-chai'))
const Node = require('./nodejs-bundle')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
function createNode (multiaddrs, options, callback) {
if (typeof options === 'function') {
callback = options
options = {}
}
if (!Array.isArray(multiaddrs)) {
multiaddrs = [multiaddrs]
}
waterfall([
(cb) => PeerId.create({ bits: 1024 }, cb),
(peerId, cb) => PeerInfo.create(peerId, cb),
(peerInfo, cb) => {
multiaddrs.map((ma) => peerInfo.multiaddrs.add(ma))
cb(null, peerInfo)
},
(peerInfo, cb) => {
const node = new Node(peerInfo, undefined, options)
cb(null, node)
}
], callback)
}
function echo (protocol, conn) {
pull(conn, conn)
}
module.exports = {
createNode: createNode,
echo: echo
}