Compare commits

...

17 Commits

Author SHA1 Message Date
2e4459b315 chore: release version v0.24.0 2018-11-16 14:12:01 +01:00
2a5232b541 chore: update contributors 2018-11-16 14:12:01 +01:00
44915b3723 0.24.0-rc.3 2018-11-15 18:59:22 +01:00
64bba57255 chore: add publish files to package 2018-11-15 18:58:40 +01:00
88ebd1fc09 test: improve multiaddr trim test 2018-11-15 18:01:31 +01:00
92cd591da4 chore: update deps 2018-11-15 18:01:31 +01:00
320d84f541 docs: update examples (#271)
* docs: fix examples

* chore: remove non jenkins ci files

* chore: update libp2p-spdy

* chore: update libp2p-spdy

* docs: update example language
2018-11-14 18:50:17 +01:00
970deec2a4 feat: add maxNumProviders to findprovs (#283)
* feat: add maxNumProviders to findprovs

* chore: upgrade libp2p-kad-dht
2018-11-13 11:46:51 +01:00
714b6ec2b9 fix: improve get peer info errors 2018-11-12 19:26:40 +01:00
f71fdfdf35 feat: conditionally emit errors
test: add tests for emit override
2018-11-12 19:26:04 +01:00
e92053da9a Chore/update deps (#279)
* chore: update deps

* test: remove unneeded timeout

* chore: make nock a dev dep, it was not
2018-11-06 22:52:16 +01:00
17b5f73b3d fix: dont call callback before it's properly set 2018-11-05 15:43:59 +01:00
c18d2a4147 0.24.0-rc.2 2018-11-01 15:10:36 +01:00
f1baa7e0b1 chore: update switch version 2018-11-01 15:10:35 +01:00
4abc868ab3 0.24.0-rc.1 2018-11-01 15:10:35 +01:00
40e840d5fd feat: add datastore to config 2018-10-31 14:43:16 +01:00
9518eb44b3 docs: improve browser example connectability (#240) 2018-10-31 14:42:24 +01:00
26 changed files with 235 additions and 122 deletions

View File

@ -1,3 +1,8 @@
<a name="0.24.0"></a>
# [0.24.0](https://github.com/libp2p/js-libp2p/compare/v0.24.0-rc.3...v0.24.0) (2018-11-16)
<a name="0.23.1"></a> <a name="0.23.1"></a>
## [0.23.1](https://github.com/libp2p/js-libp2p/compare/v0.23.0...v0.23.1) (2018-08-13) ## [0.23.1](https://github.com/libp2p/js-libp2p/compare/v0.23.0...v0.23.1) (2018-08-13)

View File

@ -261,12 +261,12 @@ Required keys in the `options` object:
- `key`: Buffer - `key`: Buffer
- `options`: object of options - `options`: object of options
- `options.maxTimeout`: Number milliseconds - `options.maxTimeout`: Number milliseconds
- `options.maxNumProviders` maximum number of providers to find
#### `libp2p.contentRouting.provide(key, callback)` #### `libp2p.contentRouting.provide(key, callback)`
- `key`: Buffer - `key`: Buffer
#### `libp2p.handle(protocol, handlerFunc [, matchFunc])` #### `libp2p.handle(protocol, handlerFunc [, matchFunc])`
> Handle new protocol > Handle new protocol

View File

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

View File

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

View File

@ -10,4 +10,4 @@ This example creates a simple chat app in your terminal.
1. Run the listener in window 1, `node listener.js` 1. Run the listener in window 1, `node listener.js`
2. Run the dialer in window 2, `node dialer.js` 2. Run the dialer in window 2, `node dialer.js`
3. Type a message in either window and hit _enter_ 3. Type a message in either window and hit _enter_
4. Tell youself secrets to your hearts content! 4. Tell yourself secrets to your hearts content!

View File

@ -3,7 +3,7 @@
const TCP = require('libp2p-tcp') const TCP = require('libp2p-tcp')
const MulticastDNS = require('libp2p-mdns') const MulticastDNS = require('libp2p-mdns')
const WS = require('libp2p-websockets') const WS = require('libp2p-websockets')
const Bootstrap = require('libp2p-railing') const Bootstrap = require('libp2p-bootstrap')
const spdy = require('libp2p-spdy') const spdy = require('libp2p-spdy')
const KadDHT = require('libp2p-kad-dht') const KadDHT = require('libp2p-kad-dht')
const mplex = require('libp2p-mplex') const mplex = require('libp2p-mplex')

View File

@ -18,8 +18,8 @@ various Peer Discovery modules and see the impact it has on your Peer count.
1. Install IPFS locally if you dont already have it. [Install Guide](https://docs.ipfs.io/introduction/install/) 1. Install IPFS locally if you dont already have it. [Install Guide](https://docs.ipfs.io/introduction/install/)
2. Run the IPFS daemon: `ipfs daemon` 2. Run the IPFS daemon: `ipfs daemon`
3. The daemon will output a line about its API address, like `API server listening on /ip4/127.0.0.1/tcp/8080` 3. The daemon will output a line about its API address, like `API server listening on /ip4/127.0.0.1/tcp/8080`
4. In another window output the addresses of the node: `ipfs id`. Make note of the websocket address, is will contain `/ws/` in the address. 4. In another window output the addresses of the node: `ipfs id`. Make note of the websocket address, it will contain `/ws/` in the address.
5. In `./src/libp2p-bundle.js` replace the `delegatedApiOptions` host and port of your node if they are different. 5. In `./src/libp2p-bundle.js` check if the host and port of your node are correct, according to the previous step. If they are different, replace them.
6. In `./src/App.js` replace `BootstrapNode` with your nodes Websocket address from step 4. 6. In `./src/App.js` replace `BootstrapNode` with your nodes Websocket address from step 4.
7. Start this example: 7. Start this example:

View File

@ -6,7 +6,7 @@ const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex') const Mplex = require('libp2p-mplex')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
const PeerInfo = require('peer-info') const PeerInfo = require('peer-info')
const Bootstrap = require('libp2p-railing') const Bootstrap = require('libp2p-bootstrap')
const waterfall = require('async/waterfall') const waterfall = require('async/waterfall')
const defaultsDeep = require('@nodeutils/defaults-deep') const defaultsDeep = require('@nodeutils/defaults-deep')

View File

@ -3,7 +3,7 @@
const TCP = require('libp2p-tcp') const TCP = require('libp2p-tcp')
const MulticastDNS = require('libp2p-mdns') const MulticastDNS = require('libp2p-mdns')
const WS = require('libp2p-websockets') const WS = require('libp2p-websockets')
const Bootstrap = require('libp2p-railing') const Bootstrap = require('libp2p-bootstrap')
const spdy = require('libp2p-spdy') const spdy = require('libp2p-spdy')
const KadDHT = require('libp2p-kad-dht') const KadDHT = require('libp2p-kad-dht')
const mplex = require('libp2p-mplex') const mplex = require('libp2p-mplex')

View File

@ -37,4 +37,4 @@ And that's it, from now on, all your libp2p communications are encrypted. Try ru
If you want to want to learn more about how SECIO works, you can read the [great write up done by Dominic Tarr](https://github.com/auditdrivencrypto/secure-channel/blob/master/prior-art.md#ipfss-secure-channel). If you want to want to learn more about how SECIO works, you can read the [great write up done by Dominic Tarr](https://github.com/auditdrivencrypto/secure-channel/blob/master/prior-art.md#ipfss-secure-channel).
Importante note: SECIO hasn't been audited and so, we do not recommend to trust its security. We intent to move to TLS 1.3 once the specification is finalized and an implementation exists that we can use. Important note: SECIO hasn't been audited and so, we do not recommend to trust its security. We intent to move to TLS 1.3 once the specification is finalized and an implementation exists that we can use.

View File

@ -17,11 +17,12 @@
}, },
"dependencies": { "dependencies": {
"detect-dom-ready": "^1.0.2", "detect-dom-ready": "^1.0.2",
"libp2p-bootstrap": "~0.9.3",
"libp2p-mplex": "~0.8.0", "libp2p-mplex": "~0.8.0",
"libp2p-railing": "~0.9.1",
"libp2p-secio": "~0.10.0", "libp2p-secio": "~0.10.0",
"libp2p-spdy": "~0.12.1", "libp2p-spdy": "~0.12.1",
"libp2p-webrtc-star": "~0.15.3", "libp2p-webrtc-star": "~0.15.3",
"libp2p-websocket-star": "~0.8.1",
"libp2p-websockets": "~0.12.0", "libp2p-websockets": "~0.12.0",
"peer-info": "~0.14.1" "peer-info": "~0.14.1"
} }

View File

@ -2,15 +2,16 @@
const WebRTCStar = require('libp2p-webrtc-star') const WebRTCStar = require('libp2p-webrtc-star')
const WebSockets = require('libp2p-websockets') const WebSockets = require('libp2p-websockets')
const WebSocketStar = require('libp2p-websocket-star')
const Mplex = require('libp2p-mplex') const Mplex = require('libp2p-mplex')
const SPDY = require('libp2p-spdy') const SPDY = require('libp2p-spdy')
const SECIO = require('libp2p-secio') const SECIO = require('libp2p-secio')
const Bootstrap = require('libp2p-railing') const Bootstrap = require('libp2p-bootstrap')
const defaultsDeep = require('@nodeutils/defaults-deep') const defaultsDeep = require('@nodeutils/defaults-deep')
const libp2p = require('../../../../') const libp2p = require('../../../../')
// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-browser.json // Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-browser.json
const bootstrapers = [ const bootstrapList = [
'/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd', '/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
'/dns4/sfo-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx', '/dns4/sfo-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx',
'/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3', '/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
@ -19,19 +20,21 @@ const bootstrapers = [
'/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu', '/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
'/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm', '/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
'/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64', '/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
'/dns4/wss0.bootstrap.libp2p.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic', '/dns4/node0.preload.ipfs.io/tcp/443/wss/ipfs/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
'/dns4/wss1.bootstrap.libp2p.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6' '/dns4/node0.preload.ipfs.io/tcp/443/wss/ipfs/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6'
] ]
class Node extends libp2p { class Node extends libp2p {
constructor (_options) { constructor (_options) {
const wrtcStar = new WebRTCStar({ id: _options.peerInfo.id }) const wrtcStar = new WebRTCStar({ id: _options.peerInfo.id })
const wsstar = new WebSocketStar({ id: _options.peerInfo.id })
const defaults = { const defaults = {
modules: { modules: {
transport: [ transport: [
wrtcStar, wrtcStar,
new WebSockets() WebSockets,
wsstar
], ],
streamMuxer: [ streamMuxer: [
Mplex, Mplex,
@ -42,6 +45,7 @@ class Node extends libp2p {
], ],
peerDiscovery: [ peerDiscovery: [
wrtcStar.discovery, wrtcStar.discovery,
wsstar.discovery,
Bootstrap Bootstrap
] ]
}, },
@ -55,14 +59,14 @@ class Node extends libp2p {
}, },
bootstrap: { bootstrap: {
interval: 10000, interval: 10000,
enabled: false, enabled: true,
list: bootstrapers list: bootstrapList
} }
}, },
relay: { relay: {
enabled: false, enabled: true,
hop: { hop: {
enabled: false, enabled: true,
active: false active: false
} }
}, },
@ -70,6 +74,9 @@ class Node extends libp2p {
dht: false, dht: false,
pubsub: false pubsub: false
} }
},
connectionManager: {
maxPeers: 50
} }
} }

View File

@ -1,4 +1,5 @@
/* eslint-disable no-console */ /* eslint no-console: ["error", { allow: ["log"] }] */
/* eslint max-nested-callbacks: ["error", 5] */
'use strict' 'use strict'
const domReady = require('detect-dom-ready') const domReady = require('detect-dom-ready')
@ -13,13 +14,25 @@ domReady(() => {
return console.log('Could not create the Node, check if your browser has WebRTC Support', err) return console.log('Could not create the Node, check if your browser has WebRTC Support', err)
} }
node.on('peer:discovery', (peerInfo) => { let connections = {}
console.log('Discovered a peer')
const idStr = peerInfo.id.toB58String()
console.log('Discovered: ' + idStr)
node.on('peer:discovery', (peerInfo) => {
const idStr = peerInfo.id.toB58String()
if (connections[idStr]) {
// If we're already trying to connect to this peer, dont dial again
return
}
console.log('Discovered a peer:', idStr)
connections[idStr] = true
node.dial(peerInfo, (err, conn) => { node.dial(peerInfo, (err, conn) => {
if (err) { return console.log('Failed to dial:', idStr) } if (err) {
// Prevent immediate connection retries from happening
// and include a 10s jitter
const timeToNextDial = 25 * 1000 + (Math.random(0) * 10000).toFixed(0)
console.log('Failed to dial:', idStr)
setTimeout(() => delete connections[idStr], timeToNextDial)
}
}) })
}) })
@ -34,8 +47,10 @@ domReady(() => {
node.on('peer:disconnect', (peerInfo) => { node.on('peer:disconnect', (peerInfo) => {
const idStr = peerInfo.id.toB58String() const idStr = peerInfo.id.toB58String()
delete connections[idStr]
console.log('Lost connection to: ' + idStr) console.log('Lost connection to: ' + idStr)
document.getElementById(idStr).remove() const el = document.getElementById(idStr)
el && el.remove()
}) })
node.start((err) => { node.start((err) => {

View File

@ -1,9 +1,13 @@
{ {
"name": "libp2p", "name": "libp2p",
"version": "0.23.1", "version": "0.24.0",
"description": "JavaScript base class for libp2p bundles", "description": "JavaScript base class for libp2p bundles",
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>", "leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"main": "src/index.js", "main": "src/index.js",
"files": [
"dist",
"src"
],
"scripts": { "scripts": {
"lint": "aegir lint", "lint": "aegir lint",
"build": "aegir build", "build": "aegir build",
@ -38,51 +42,52 @@
}, },
"dependencies": { "dependencies": {
"async": "^2.6.1", "async": "^2.6.1",
"debug": "^4.0.1", "debug": "^4.1.0",
"err-code": "^1.1.2", "err-code": "^1.1.2",
"fsm-event": "^2.1.0", "fsm-event": "^2.1.0",
"joi": "^13.6.0", "joi": "^14.0.6",
"joi-browser": "^13.4.0", "joi-browser": "^13.4.0",
"libp2p-connection-manager": "~0.0.2", "libp2p-connection-manager": "~0.0.2",
"libp2p-floodsub": "~0.15.0", "libp2p-floodsub": "~0.15.1",
"libp2p-ping": "~0.8.0", "libp2p-ping": "~0.8.3",
"libp2p-switch": "~0.41.0", "libp2p-switch": "~0.41.2",
"libp2p-websockets": "~0.12.0", "libp2p-websockets": "~0.12.0",
"mafmt": "^6.0.2", "mafmt": "^6.0.2",
"multiaddr": "^5.0.0", "multiaddr": "^5.0.2",
"nock": "^9.4.3",
"peer-book": "~0.8.0", "peer-book": "~0.8.0",
"peer-id": "~0.11.0", "peer-id": "~0.12.0",
"peer-info": "~0.14.1" "peer-info": "~0.14.1"
}, },
"devDependencies": { "devDependencies": {
"@nodeutils/defaults-deep": "^1.1.0", "@nodeutils/defaults-deep": "^1.1.0",
"aegir": "^15.2.0", "aegir": "^17.0.1",
"chai": "^4.1.2", "chai": "^4.2.0",
"chai-checkmark": "^1.0.1", "chai-checkmark": "^1.0.1",
"cids": "~0.5.3", "cids": "~0.5.5",
"dirty-chai": "^2.0.1", "dirty-chai": "^2.0.1",
"electron-webrtc": "~0.3.0", "electron-webrtc": "~0.3.0",
"interface-datastore": "~0.6.0",
"libp2p-bootstrap": "~0.9.3", "libp2p-bootstrap": "~0.9.3",
"libp2p-circuit": "~0.2.1", "libp2p-circuit": "~0.3.0",
"libp2p-delegated-content-routing": "~0.2.2", "libp2p-delegated-content-routing": "~0.2.2",
"libp2p-delegated-peer-routing": "~0.2.2", "libp2p-delegated-peer-routing": "~0.2.2",
"libp2p-kad-dht": "~0.10.5", "libp2p-kad-dht": "~0.11.1",
"libp2p-mdns": "~0.12.0", "libp2p-mdns": "~0.12.0",
"libp2p-mplex": "~0.8.2", "libp2p-mplex": "~0.8.4",
"libp2p-secio": "~0.10.0", "libp2p-secio": "~0.10.1",
"libp2p-spdy": "~0.12.1", "libp2p-spdy": "~0.13.0",
"libp2p-tcp": "~0.13.0", "libp2p-tcp": "~0.13.0",
"libp2p-webrtc-star": "~0.15.5", "libp2p-webrtc-star": "~0.15.5",
"libp2p-websocket-star": "~0.8.1", "libp2p-websocket-star": "~0.9.0",
"libp2p-websocket-star-rendezvous": "~0.2.3", "libp2p-websocket-star-rendezvous": "~0.2.4",
"lodash.times": "^4.3.2", "lodash.times": "^4.3.2",
"nock": "^10.0.2",
"pull-goodbye": "0.0.2", "pull-goodbye": "0.0.2",
"pull-serializer": "~0.3.2", "pull-serializer": "~0.3.2",
"pull-stream": "^3.6.9", "pull-stream": "^3.6.9",
"sinon": "^6.3.4", "sinon": "^7.1.1",
"webrtcsupport": "^2.2.0", "webrtcsupport": "^2.2.0",
"wrtc": "~0.2.0" "wrtc": "~0.3.2"
}, },
"contributors": [ "contributors": [
"Alan Shaw <alan@tableflip.io>", "Alan Shaw <alan@tableflip.io>",
@ -96,6 +101,7 @@
"Florian-Merle <florian.david.merle@gmail.com>", "Florian-Merle <florian.david.merle@gmail.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>", "Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Giovanni T. Parra <fiatjaf@gmail.com>", "Giovanni T. Parra <fiatjaf@gmail.com>",
"Henrique Dias <hacdias@gmail.com>",
"Hugo Dias <hugomrdias@gmail.com>", "Hugo Dias <hugomrdias@gmail.com>",
"Irakli Gozalishvili <rfobic@gmail.com>", "Irakli Gozalishvili <rfobic@gmail.com>",
"Jacob Heun <jacobheun@gmail.com>", "Jacob Heun <jacobheun@gmail.com>",
@ -113,6 +119,8 @@
"Ryan Bell <ryan@piing.net>", "Ryan Bell <ryan@piing.net>",
"Sönke Hahn <soenkehahn@gmail.com>", "Sönke Hahn <soenkehahn@gmail.com>",
"Tiago Alves <alvesjtiago@gmail.com>", "Tiago Alves <alvesjtiago@gmail.com>",
"Vasco Santos <vasco.santos@ua.pt>",
"Vasco Santos <vasco.santos@moxy.studio>",
"Volker Mische <volker.mische@gmail.com>", "Volker Mische <volker.mische@gmail.com>",
"Zane Starr <zcstarr@gmail.com>", "Zane Starr <zcstarr@gmail.com>",
"greenkeeperio-bot <support@greenkeeper.io>", "greenkeeperio-bot <support@greenkeeper.io>",

View File

@ -7,6 +7,7 @@ const ModuleSchema = Joi.alternatives().try(Joi.func(), Joi.object())
const OptionsSchema = Joi.object({ const OptionsSchema = Joi.object({
// TODO: create proper validators for the generics // TODO: create proper validators for the generics
connectionManager: Joi.object(), connectionManager: Joi.object(),
datastore: Joi.object(),
peerInfo: Joi.object().required(), peerInfo: Joi.object().required(),
peerBook: Joi.object(), peerBook: Joi.object(),
modules: Joi.object().keys({ modules: Joi.object().keys({

View File

@ -20,14 +20,11 @@ module.exports = (node) => {
* @param {CID} key The CID key of the content to find * @param {CID} key The CID key of the content to find
* @param {object} options * @param {object} options
* @param {number} options.maxTimeout How long the query should run * @param {number} options.maxTimeout How long the query should run
* @param {number} options.maxNumProviders - maximum number of providers to find
* @param {function(Error, Result<Array>)} callback * @param {function(Error, Result<Array>)} callback
* @returns {void} * @returns {void}
*/ */
findProviders: (key, options, callback) => { findProviders: (key, options, callback) => {
if (!routers.length) {
return callback(errCode(new Error('No content routers available'), 'NO_ROUTERS_AVAILABLE'))
}
if (typeof options === 'function') { if (typeof options === 'function') {
callback = options callback = options
options = {} options = {}
@ -37,6 +34,10 @@ module.exports = (node) => {
} }
} }
if (!routers.length) {
return callback(errCode(new Error('No content routers available'), 'NO_ROUTERS_AVAILABLE'))
}
const tasks = routers.map((router) => { const tasks = routers.map((router) => {
return (cb) => router.findProviders(key, options, (err, results) => { return (cb) => router.findProviders(key, options, (err, results) => {
if (err) { if (err) {

View File

@ -3,7 +3,7 @@
const PeerId = require('peer-id') const PeerId = require('peer-id')
const PeerInfo = require('peer-info') const PeerInfo = require('peer-info')
const multiaddr = require('multiaddr') const multiaddr = require('multiaddr')
const setImmediate = require('async/setImmediate') const errCode = require('err-code')
module.exports = (node) => { module.exports = (node) => {
/* /*
@ -20,16 +20,21 @@ module.exports = (node) => {
try { try {
peer = multiaddr(peer) peer = multiaddr(peer)
} catch (err) { } catch (err) {
return setImmediate(() => callback(err)) return callback(
errCode(err, 'ERR_INVALID_MULTIADDR')
)
} }
} }
const peerIdB58Str = peer.getPeerId() const peerIdB58Str = peer.getPeerId()
if (!peerIdB58Str) { if (!peerIdB58Str) {
return setImmediate(() => { return callback(
callback(new Error('peer multiaddr instance or string must include peerId')) errCode(
}) new Error('peer multiaddr instance or string must include peerId'),
'ERR_INVALID_MULTIADDR'
)
)
} }
try { try {
@ -48,9 +53,14 @@ module.exports = (node) => {
return node.peerRouting.findPeer(peer, callback) return node.peerRouting.findPeer(peer, callback)
} }
} else { } else {
return setImmediate(() => callback(new Error('peer type not recognized'))) return callback(
errCode(
new Error(`${p} is not a valid peer type`),
'ERR_INVALID_PEER_TYPE'
)
)
} }
setImmediate(() => callback(null, p)) callback(null, p)
} }
} }

View File

@ -41,6 +41,7 @@ class Node extends EventEmitter {
// and add default values where appropriate // and add default values where appropriate
_options = validateConfig(_options) _options = validateConfig(_options)
this.datastore = _options.datastore
this.peerInfo = _options.peerInfo this.peerInfo = _options.peerInfo
this.peerBook = _options.peerBook || new PeerBook() this.peerBook = _options.peerBook || new PeerBook()
@ -50,7 +51,10 @@ class Node extends EventEmitter {
this._transport = [] // Transport instances/references this._transport = [] // Transport instances/references
this._discovery = [] // Discovery service instances/references this._discovery = [] // Discovery service instances/references
// create the switch, and listen for errors
this._switch = new Switch(this.peerInfo, this.peerBook, _options.switch) this._switch = new Switch(this.peerInfo, this.peerBook, _options.switch)
this._switch.on('error', (...args) => this.emit('error', ...args))
this.stats = this._switch.stats this.stats = this._switch.stats
this.connectionManager = new ConnectionManager(this, _options.connectionManager) this.connectionManager = new ConnectionManager(this, _options.connectionManager)
@ -100,9 +104,7 @@ class Node extends EventEmitter {
this._dht = new DHT(this._switch, { this._dht = new DHT(this._switch, {
kBucketSize: this._config.dht.kBucketSize || 20, kBucketSize: this._config.dht.kBucketSize || 20,
enabledDiscovery, enabledDiscovery,
// TODO make datastore an option of libp2p itself so datastore: this.datastore
// that other things can use it as well
datastore: dht.datastore
}) })
} }
@ -163,6 +165,21 @@ class Node extends EventEmitter {
}) })
} }
/**
* Overrides EventEmitter.emit to conditionally emit errors
* if there is a handler. If not, errors will be logged.
* @param {string} eventName
* @param {...any} args
* @returns {void}
*/
emit (eventName, ...args) {
if (eventName === 'error' && !this._events.error) {
log.error(...args)
} else {
super.emit(eventName, ...args)
}
}
/** /**
* Starts the libp2p node and all sub services * Starts the libp2p node and all sub services
* *

View File

@ -22,15 +22,15 @@ module.exports = (node) => {
* @returns {void} * @returns {void}
*/ */
findPeer: (id, options, callback) => { findPeer: (id, options, callback) => {
if (!routers.length) {
callback(errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE'))
}
if (typeof options === 'function') { if (typeof options === 'function') {
callback = options callback = options
options = {} options = {}
} }
if (!routers.length) {
callback(errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE'))
}
const tasks = routers.map((router) => { const tasks = routers.map((router) => {
return (cb) => router.findPeer(id, options, (err, result) => { return (cb) => router.findPeer(id, options, (err, result) => {
if (err) { if (err) {

View File

@ -107,6 +107,22 @@ describe('.contentRouting', () => {
}) })
}) })
it('nodeE.contentRouting.findProviders with limited number of providers', (done) => {
parallel([
(cb) => nodeA.contentRouting.provide(cid, cb),
(cb) => nodeB.contentRouting.provide(cid, cb),
(cb) => nodeC.contentRouting.provide(cid, cb)
], (err) => {
expect(err).to.not.exist()
nodeE.contentRouting.findProviders(cid, { maxNumProviders: 2 }, (err, providers) => {
expect(err).to.not.exist()
expect(providers).to.have.length(2)
done()
})
})
})
it('nodeC.contentRouting.findProviders for non existing record (timeout)', (done) => { it('nodeC.contentRouting.findProviders for non existing record (timeout)', (done) => {
const cid = new CID('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSnnnn') const cid = new CID('QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSnnnn')
@ -367,4 +383,29 @@ describe('.contentRouting', () => {
}) })
}) })
}) })
describe('no routers', () => {
let nodeA
before((done) => {
createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
expect(err).to.not.exist()
nodeA = node
done()
})
})
it('.findProviders should return an error with no options', (done) => {
nodeA.contentRouting.findProviders('a cid', (err) => {
expect(err).to.exist()
done()
})
})
it('.findProviders should return an error with options', (done) => {
nodeA.contentRouting.findProviders('a cid', { maxTimeout: 5000 }, (err) => {
expect(err).to.exist()
done()
})
})
})
}) })

View File

@ -80,4 +80,25 @@ describe('libp2p creation', () => {
done() done()
}) })
}) })
it('should not throw errors from switch if node has no error listeners', (done) => {
createNode([], {}, (err, node) => {
expect(err).to.not.exist()
node._switch.emit('error', new Error('bad things'))
done()
})
})
it('should emit errors from switch if node has error listeners', (done) => {
const error = new Error('bad things')
createNode([], {}, (err, node) => {
expect(err).to.not.exist()
node.once('error', (err) => {
expect(err).to.eql(error)
done()
})
node._switch.emit('error', error)
})
})
}) })

View File

@ -6,14 +6,18 @@ const chai = require('chai')
chai.use(require('dirty-chai')) chai.use(require('dirty-chai'))
const expect = chai.expect const expect = chai.expect
const MemoryStore = require('interface-datastore').MemoryDatastore
const createNode = require('./utils/create-node') const createNode = require('./utils/create-node')
describe('.dht', () => { describe('.dht', () => {
describe('enabled', () => { describe('enabled', () => {
let nodeA let nodeA
const datastore = new MemoryStore()
before(function (done) { before(function (done) {
createNode('/ip4/0.0.0.0/tcp/0', { createNode('/ip4/0.0.0.0/tcp/0', {
datastore,
config: { config: {
EXPERIMENTAL: { EXPERIMENTAL: {
dht: true dht: true

View File

@ -11,7 +11,7 @@ describe('getPeerInfo', () => {
it('should callback with error for invalid string multiaddr', (done) => { it('should callback with error for invalid string multiaddr', (done) => {
getPeerInfo(null)('INVALID MULTIADDR', (err) => { getPeerInfo(null)('INVALID MULTIADDR', (err) => {
expect(err).to.exist() expect(err).to.exist()
expect(err.message).to.contain('must start with a "/"') expect(err.code).to.eql('ERR_INVALID_MULTIADDR')
done() done()
}) })
}) })
@ -19,7 +19,15 @@ describe('getPeerInfo', () => {
it('should callback with error for invalid non-peer multiaddr', (done) => { it('should callback with error for invalid non-peer multiaddr', (done) => {
getPeerInfo(null)('/ip4/8.8.8.8/tcp/1080', (err) => { getPeerInfo(null)('/ip4/8.8.8.8/tcp/1080', (err) => {
expect(err).to.exist() expect(err).to.exist()
expect(err.message).to.equal('peer multiaddr instance or string must include peerId') expect(err.code).to.equal('ERR_INVALID_MULTIADDR')
done()
})
})
it('should callback with error for invalid non-peer multiaddr', (done) => {
getPeerInfo(null)(undefined, (err) => {
expect(err).to.exist()
expect(err.code).to.eql('ERR_INVALID_PEER_TYPE')
done() done()
}) })
}) })

View File

@ -29,10 +29,12 @@ describe('multiaddr trim', () => {
expect(err).to.not.exist() expect(err).to.not.exist()
const multiaddrs = node.peerInfo.multiaddrs.toArray() const multiaddrs = node.peerInfo.multiaddrs.toArray()
expect(multiaddrs.length).to.be.at.least(2)
// ensure the p2p-webrtc-direct address has been trimmed
multiaddrs.forEach((addr) => {
expect(() => addr.decapsulate('/ip4/0.0.0.0/tcp/999/wss/p2p-webrtc-direct')).to.throw()
})
expect(multiaddrs.length).to.at.least(2)
expect(multiaddrs[0].toString())
.to.match(/^\/ip4\/127\.0\.0\.1\/tcp\/[0-9]+\/ws\/ipfs\/\w+$/)
node.stop(done) node.stop(done)
}) })
}) })

View File

@ -266,4 +266,29 @@ describe('.peerRouting', () => {
}) })
}) })
}) })
describe('no routers', () => {
let nodeA
before((done) => {
createNode('/ip4/0.0.0.0/tcp/0', (err, node) => {
expect(err).to.not.exist()
nodeA = node
done()
})
})
it('.findPeer should return an error with no options', (done) => {
nodeA.peerRouting.findPeer('a cid', (err) => {
expect(err).to.exist()
done()
})
})
it('.findPeer should return an error with options', (done) => {
nodeA.peerRouting.findPeer('a cid', { maxTimeout: 5000 }, (err) => {
expect(err).to.exist()
done()
})
})
})
}) })

View File

@ -28,8 +28,6 @@ function teardown (nodeA, nodeB, callback) {
describe('stream muxing', () => { describe('stream muxing', () => {
it('spdy only', function (done) { it('spdy only', function (done) {
this.timeout(5 * 1000)
let nodeA let nodeA
let nodeB let nodeB