Compare commits

...

8 Commits

Author SHA1 Message Date
Jacob Heun
7e1a9d677b test(fix): fix listening test for ci 2020-01-24 14:31:38 +01:00
Jacob Heun
1ba1ca7714 chore: release version v0.27.0-rc.0 2020-01-24 11:55:59 +01:00
Jacob Heun
691e9b7f7b chore: update contributors 2020-01-24 11:55:59 +01:00
Vasco Santos
751a22741f refactor: examples-browser (#508)
* refactor: examples-browser

* chore: add information to use signalling server

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: update deps

* docs: refactor libp2p browser example

* docs(examples): add back websockets and boostrap nodes

docs(examples): redo the browser readme

* fix: handle edge case of connections closing early

* chore: fix lint

* chore: update example deps and readme

* chore: update webrtc-star

* chore: apply suggestions from code review

Co-Authored-By: Alan Shaw <alan.shaw@protocol.ai>

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
Co-authored-by: Alan Shaw <alan.shaw@protocol.ai>
2020-01-24 11:43:56 +01:00
Vasco Santos
461faca1ca docs: getting started (#514)
* docs: getting started

* docs: review getting started (#520)

* doc: initial review of getting started

Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>

* chore: move multiplexing to basic setup

* chore: add read more cta

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: just configure multiplexer

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>

* chore: just use websockets and changed dht module introduction

* chore: add reference for events in the API doc

* docs: simplify getting started guide and clean up language

* chore: apply suggestions from code review

Co-Authored-By: Alan Shaw <alan.shaw@protocol.ai>

* docs(fix): address review comments

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
Co-authored-by: Alan Shaw <alan.shaw@protocol.ai>
2020-01-23 17:12:41 +01:00
Jacob Heun
31d1b2369a fix: use toB58String everywhere to be consistent (#537)
* chore: update deps

* fix: consistently use b58 peerid string

The migration to base32 will happen at a later date
2020-01-22 11:47:30 +01:00
Vasco Santos
83409deaa6 fix: registrar should filter the disconnected conn (#532)
* fix: registrar on disconnect only when no connections

* chore: add test
2020-01-14 12:26:24 +01:00
Alan Shaw
c44e6e33ed fix: stop discoveries (#530)
* fix: stop discoveries

* test: add discovery stop test

* chore: fix lint

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-01-07 16:27:32 +01:00
35 changed files with 633 additions and 343 deletions

1
.gitignore vendored
View File

@@ -3,6 +3,7 @@ docs
**/*.log
test/repo-tests*
**/bundle.js
.cache
# Logs
logs

View File

@@ -1,3 +1,15 @@
<a name="0.27.0-rc.0"></a>
# [0.27.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.27.0-pre.2...v0.27.0-rc.0) (2020-01-24)
### Bug Fixes
* registrar should filter the disconnected conn ([#532](https://github.com/libp2p/js-libp2p/issues/532)) ([83409de](https://github.com/libp2p/js-libp2p/commit/83409de))
* stop discoveries ([#530](https://github.com/libp2p/js-libp2p/issues/530)) ([c44e6e3](https://github.com/libp2p/js-libp2p/commit/c44e6e3))
* use toB58String everywhere to be consistent ([#537](https://github.com/libp2p/js-libp2p/issues/537)) ([31d1b23](https://github.com/libp2p/js-libp2p/commit/31d1b23))
<a name="0.27.0-pre.2"></a>
# [0.27.0-pre.2](https://github.com/libp2p/js-libp2p/compare/v0.27.0-pre.1...v0.27.0-pre.2) (2020-01-07)

View File

@@ -49,6 +49,7 @@ We've come a long way, but this project is still in Alpha, lots of development i
- [Usage](#usage)
- [Configuration](#configuration)
- [API](#api)
- [Getting Started](#getting-started)
- [Tutorials and Examples](#tutorials-and-examples)
- [Development](#development)
- [Tests](#tests)
@@ -89,6 +90,10 @@ For all the information on how you can configure libp2p see [CONFIGURATION.md](.
The specification is available on [API.md](./doc/API.md).
### Getting started
If you are starting your journey with `js-libp2p`, read the [GETTING_STARTED.md](./doc/GETTING_STARTED.md) guide.
### Tutorials and Examples
You can find multiple examples on the [examples folder](./examples) that will guide you through using libp2p for several scenarios.

View File

@@ -28,6 +28,7 @@
* [`metrics.protocols`](#metricsprotocols)
* [`metrics.forPeer`](#metricsforpeer)
* [`metrics.forProtocol`](#metricsforprotocol)
* [Events](#events)
* [Types](#types)
* [`Stats`](#stats)
@@ -96,39 +97,6 @@ Required keys in the `options` object:
</details>
Once you have a libp2p instance, you are able to listen to several events it emits, so that you can be noticed of relevant network events.
<details><summary>Events</summary>
#### An error has occurred
`libp2p.on('error', (err) => {})`
- `err`: instance of `Error`
#### A peer has been discovered
`libp2p.on('peer:discovery', (peer) => {})`
If `autoDial` option is `true`, applications should **not** attempt to connect to the peer
unless they are performing a specific action. See [peer discovery and auto dial](./PEER_DISCOVERY.md) for more information.
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
#### We have a new connection to a peer
`libp2p.on('peer:connect', (peer) => {})`
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
#### We have closed a connection to a peer
`libp2p.on('peer:disconnect', (peer) => {})`
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
</details>
## Libp2p Instance Methods
### start
@@ -777,6 +745,41 @@ const peerStats = libp2p.metrics.forProtocol('/meshsub/1.0.0')
console.log(peerStats.toJSON())
```
## Events
Once you have a libp2p instance, you can listen to several events it emits, so that you can be notified of relevant network events.
#### An error has occurred
`libp2p.on('error', (err) => {})`
- `err`: instance of `Error`
#### A peer has been discovered
`libp2p.on('peer:discovery', (peer) => {})`
If `autoDial` option is `true`, applications should **not** attempt to connect to the peer
unless they are performing a specific action. See [peer discovery and auto dial](./PEER_DISCOVERY.md) for more information.
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
#### A new connection to a peer has been opened
This event will be triggered anytime a new Connection is established to another peer.
`libp2p.on('peer:connect', (peer) => {})`
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
#### An existing connection to a peer has been closed
This event will be triggered anytime we are disconnected from another peer, regardless of the circumstances of that disconnection. If we happen to have multiple connections to a peer, this event will **only** be triggered when the last connection is closed.
`libp2p.on('peer:disconnect', (peer) => {})`
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
## Types
### Stats

View File

@@ -129,7 +129,7 @@ If you want to know more about libp2p peer discovery, you should read the follow
Some available content routing modules are:
- [js-libp2p-kad-dht](https://github.com/libp2p/js-libp2p-kad-dht)
- [js-libp2p-delegated-peer-routing](https://github.com/libp2p/js-libp2p-delegated-peer-routing)
- [js-libp2p-delegated-content-routing](https://github.com/libp2p/js-libp2p-delegated-content-routing)
If none of the available content routing protocols fulfills your needs, you can create a libp2p compatible one. A libp2p content routing protocol just needs to be compliant with the [Content Routing Interface](https://github.com/libp2p/js-interfaces/tree/master/src/content-routing). **(WIP: This module is not yet implemented)**

247
doc/GETTING_STARTED.md Normal file
View File

@@ -0,0 +1,247 @@
# Getting Started
Welcome to libp2p! This guide will walk you through setting up a fully functional libp2p node 🚀
- [Getting Started](#getting-started)
- [Install](#install)
- [Configuring libp2p](#configuring-libp2p)
- [Basic setup](#basic-setup)
- [Transports](#transports)
- [Connection Encryption](#connection-encryption)
- [Multiplexing](#multiplexing)
- [Running Libp2p](#running-libp2p)
- [Custom setup](#custom-setup)
- [Peer Discovery](#peer-discovery)
- [Pubsub](#pubsub)
- [What is next](#what-is-next)
## Install
The first step is to install libp2p in your project:
```sh
npm install libp2p
```
## Configuring libp2p
If you're new to libp2p, we recommend configuring your node in stages, as this can make troubleshooting configuration issues much easier. In this guide, we'll do just that. If you're more experienced with libp2p, you may wish to jump to the [Configuration readme](./CONFIGURATION.md).
### Basic setup
Now that we have libp2p installed, let's configure the minimum needed to get your node running. The only modules libp2p requires are a [**Transport**][transport] and [**Crypto**][crypto] module. However, we recommend that a basic setup should also have a [**Stream Multiplexer**](streamMuxer) configured, which we will explain shortly. Let's start by setting up a Transport.
#### Transports
Libp2p uses Transports to establish connections between peers over the network. Transports are the components responsible for performing the actual exchange of data between libp2p nodes. You can configure any number of Transports, but you only need 1 to start with. Supporting more Transports will improve the ability of your node to speak to a larger number of nodes on the network, as matching Transports are required for two nodes to communicate with one another.
You should select Transports according to the runtime of your application; Node.js or the browser. You can see a list of some of the available Transports in the [configuration readme](./CONFIGURATION.md#transport). For this guide let's install `libp2p-websockets`, as it can be used in both Node.js and the browser.
Start by installing `libp2p-websockets`:
```sh
npm install libp2p-websockets
```
Now that we have the module installed, let's configure libp2p to use the Transport. We'll use the [`Libp2p.create`](./API.md#create) method, which takes a single configuration object as its only parameter. We can add the Transport by passing it into the `modules.transport` array:
```js
const Libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const node = await Libp2p.create({
modules: {
transport: [WebSockets]
}
})
```
There are multiple libp2p transports available, you should evaluate the needs of your application and select the Transport(s) that best suit your requirements. You can add as many transports as you like to `modules.transport` in order to establish connections with as many peers as possible.
<details><summary>Read More</summary>
If you want to know more about libp2p transports, you should read the following content:
- https://docs.libp2p.io/concepts/transport
- https://github.com/libp2p/specs/tree/master/connections
</details>
#### Connection Encryption
Encryption is an important part of communicating on the libp2p network. Every connection must be encrypted to help ensure security for everyone. As such, Connection Encryption (Crypto) is a required component of libp2p.
There are a growing number of Crypto modules being developed for libp2p. As those are released they will be tracked in the [Connection Encryption section of the configuration readme](./CONFIGURATION.md#connection-encryption). For now, we are going to configure our node to use the `libp2p-secio` module, which is widely supported across the various libp2p implementations.
```sh
npm install libp2p-secio
```
With `libp2p-secio` installed, we can add it to our existing configuration by importing it and adding it to the `modules.connEncryption` array:
```js
const Libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const SECIO = require('libp2p-secio')
const node = await Libp2p.create({
modules: {
transport: [WebSockets],
connEncryption: [SECIO]
}
})
```
<details><summary>Read More</summary>
If you want to know more about libp2p connection encryption, you should read the following content:
- https://docs.libp2p.io/concepts/secure-comms
- https://github.com/libp2p/specs/tree/master/connections
</details>
#### Multiplexing
While multiplexers are not strictly required, they are highly recommended as they improve the effectiveness and efficiency of connections for the various protocols libp2p runs. Adding a multiplexer to your configuration will allow libp2p to run several of its internal protocols, like Identify, as well as allow your application to easily run any number of protocols over a single connection.
Looking at the [available stream multiplexing](./CONFIGURATION.md#stream-multiplexing) modules, js-libp2p currently only supports `libp2p-mplex`, so we will use that here. Bear in mind that future libp2p Transports might have `multiplexing` capabilities already built-in (such as `QUIC`).
You can install `libp2p-mplex` and add it to your libp2p node as follows in the next example.
```sh
npm install libp2p-mplex
```
```js
const Libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const SECIO = require('libp2p-secio')
const MPLEX = require('libp2p-mplex')
const node = await Libp2p.create({
modules: {
transport: [WebSockets],
connEncryption: [SECIO],
streamMuxer: [MPLEX]
}
})
```
<details><summary>Read More</summary>
If you want to know more about libp2p stream multiplexing, you should read the following content:
- https://docs.libp2p.io/concepts/stream-multiplexing
- https://github.com/libp2p/specs/tree/master/connections
- https://github.com/libp2p/specs/tree/master/mplex
</details>
#### Running Libp2p
Now that you have configured a [**Transport**][transport], [**Crypto**][crypto] and [**Stream Multiplexer**](streamMuxer) module, you can start your libp2p node. We can start and stop libp2p using the [`libp2p.start()`](./API.md#start) and [`libp2p.stop()`](./API.md#stop) methods.
```js
const Libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const SECIO = require('libp2p-secio')
const MPLEX = require('libp2p-mplex')
const node = await Libp2p.create({
modules: {
transport: [WebSockets],
connEncryption: [SECIO],
streamMuxer: [MPLEX]
}
})
// start libp2p
await node.start()
console.log('libp2p has started')
// stop libp2p
await node.stop()
console.log('libp2p has stopped')
```
### Custom setup
Once your libp2p node is running, it is time to get it connected to the public network. We can do this via peer discovery.
#### Peer Discovery
Peer discovery is an important part of creating a well connected libp2p node. A static list of peers will often be used to join the network, but it's useful to couple other discovery mechanisms to ensure you're able to discover other peers that are important to your application.
For each discovered peer libp2p will emit a `peer:discovery` event which includes metadata about that peer. You can read the [Events](./API.md#events) in the API doc to learn more.
Looking at the [available peer discovery](./CONFIGURATION.md#peer-discovery) protocols, there are several options to be considered:
- If you already know the addresses of some other network peers, you should consider using `libp2p-bootstrap` as this is the easiest way of getting your peer into the network.
- If it is likely that you will have other peers on your local network, `libp2p-mdns` is a must if you're node is not running in the browser. It allows peers to discover each other when on the same local network.
- If your application is browser based you can use the `libp2p-webrtc-star` Transport, which includes a rendezvous based peer sharing service.
- A random walk approach can be used via `libp2p-kad-dht`, to crawl the network and find new peers along the way.
For this guide we will configure `libp2p-bootstrap` as this is useful for joining the public network.
Let's install `libp2p-bootstrap`.
```sh
npm install libp2p-bootstrap
```
We can provide specific configurations for each protocol within a `config.peerDiscovery` property in the options as shown below.
```js
const Libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const SECIO = require('libp2p-secio')
const MPLEX = require('libp2p-mplex')
const Bootstrap = require('libp2p-bootstrap')
// Known peers addresses
const bootstrapMultiaddrs = [
'/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
'/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3'
]
const node = await Libp2p.create({
modules: {
transport: [WebSockets],
connEncryption: [SECIO],
streamMuxer: [MPLEX],
peerDiscovery: [Bootstrap]
},
config: {
peerDiscovery: {
autoDial: true, // Auto connect to discovered peers (limited by ConnectionManager minPeers)
// The `tag` property will be searched when creating the instance of your Peer Discovery service.
// The associated object, will be passed to the service when it is instantiated.
[Bootstrap.tag]: {
enabled: true,
list: bootstrapMultiaddrs // provide array of multiaddrs
}
}
}
})
node.on('peer:discovery', (peer) => {
console.log('Discovered %s', peer.id.toB58String()) // Log discovered peer
})
node.on('peer:connect', (peer) => {
console.log('Connected to %s', peer.id.toB58String()) // Log connected peer
})
// start libp2p
await node.start()
```
<details><summary>Read More</summary>
If you want to know more about libp2p peer discovery, you should read the following content:
- https://github.com/libp2p/specs/blob/master/discovery/mdns.md
</details>
## What is next
There are a lot of other concepts within `libp2p`, that are not covered in this guide. For additional configuration options we recommend checking out the [Configuration Readme](./CONFIGURATION.md) and the [examples folder](../examples). If you have any problems getting started, or if anything isn't clear, please let us know by submitting an issue!
[transport]: https://github.com/libp2p/js-interfaces/tree/master/src/transport
[crypto]: https://github.com/libp2p/js-interfaces/tree/master/src/crypto
[streamMuxer]: https://github.com/libp2p/js-interfaces/tree/master/src/stream-muxer

View File

@@ -0,0 +1,4 @@
{
"presets": ["@babel/preset-env"],
"plugins": ["syntax-async-functions","transform-regenerator"]
}

View File

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

View File

@@ -1,32 +0,0 @@
{
"name": "libp2p-in-the-browser",
"version": "0.1.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\"}'",
"start": "npm run bundle && npm run serve"
},
"license": "MIT",
"devDependencies": {
"browserify": "^14.5.0",
"concat-stream": "^1.6.0",
"detect-dom-ready": "^1.0.2",
"node-static": "~0.7.10"
},
"dependencies": {
"detect-dom-ready": "^1.0.2",
"libp2p": "../../../",
"libp2p-bootstrap": "~0.9.7",
"libp2p-gossipsub": "~0.0.4",
"libp2p-kad-dht": "^0.15.3",
"libp2p-mplex": "~0.8.5",
"libp2p-secio": "~0.11.1",
"libp2p-spdy": "~0.13.3",
"libp2p-webrtc-star": "~0.15.8",
"libp2p-websocket-star": "~0.10.2",
"libp2p-websockets": "~0.12.2",
"peer-info": "~0.15.1"
}
}

View File

@@ -1,14 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<title>libp2p in the browser</title>
</head>
<body>
<h1>libp2p node running \o/</h1>
<div id="my-peer"></div>
<div id="swarm"></div>
<script src="bundle.js"></script>
</body>
</html>

View File

@@ -1,94 +0,0 @@
'use strict'
const WebRTCStar = require('libp2p-webrtc-star')
const WebSockets = require('libp2p-websockets')
const WebSocketStar = require('libp2p-websocket-star')
const Mplex = require('libp2p-mplex')
const SPDY = require('libp2p-spdy')
const SECIO = require('libp2p-secio')
const Bootstrap = require('libp2p-bootstrap')
const DHT = require('libp2p-kad-dht')
const Gossipsub = require('libp2p-gossipsub')
const libp2p = require('libp2p')
// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-browser.json
const bootstrapList = [
'/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
'/dns4/sfo-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLju6m7xTh3DuokvT3886QRYqxAzb1kShaanJgW36yx',
'/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
'/dns4/sfo-2.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLnSGccFuZQJzRadHn95W2CrSFmZuTdDWP8HXaHca9z',
'/dns4/sfo-3.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
'/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
'/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
'/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64',
'/dns4/node0.preload.ipfs.io/tcp/443/wss/p2p/QmZMxNdpMkewiVZLMRxaNxUeZpDUb34pWjZ1kZvsd16Zic',
'/dns4/node0.preload.ipfs.io/tcp/443/wss/p2p/Qmbut9Ywz9YEDrz8ySBSgWyJk41Uvm2QJPhwDJzJyGFsD6'
]
class Node extends libp2p {
constructor ({ peerInfo }) {
const wrtcStar = new WebRTCStar({ id: peerInfo.id })
const wsstar = new WebSocketStar({ id: peerInfo.id })
const defaults = {
modules: {
transport: [
wrtcStar,
WebSockets,
wsstar
],
streamMuxer: [
Mplex,
SPDY
],
connEncryption: [
SECIO
],
peerDiscovery: [
wrtcStar.discovery,
wsstar.discovery,
Bootstrap
],
dht: DHT,
pubsub: Gossipsub
},
config: {
peerDiscovery: {
autoDial: true,
webRTCStar: {
enabled: true
},
websocketStar: {
enabled: true
},
bootstrap: {
interval: 20e3,
enabled: true,
list: bootstrapList
}
},
relay: {
enabled: true,
hop: {
enabled: false,
active: false
}
},
dht: {
enabled: false
},
pubsub: {
enabled: false
}
},
connectionManager: {
minPeers: 10,
maxPeers: 50
}
}
super({ ...defaults, peerInfo })
}
}
module.exports = Node

View File

@@ -1,28 +0,0 @@
'use strict'
const PeerInfo = require('peer-info')
const Node = require('./browser-bundle')
function createNode (callback) {
PeerInfo.create((err, peerInfo) => {
if (err) {
return callback(err)
}
const peerIdStr = peerInfo.id.toB58String()
const webrtcAddr = `/dns4/star-signal.cloud.ipfs.team/tcp/443/wss/p2p-webrtc-star/p2p/${peerIdStr}`
const wsAddr = `/dns4/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star`
peerInfo.multiaddrs.add(webrtcAddr)
peerInfo.multiaddrs.add(wsAddr)
const node = new Node({
peerInfo
})
node.idStr = peerIdStr
callback(null, node)
})
}
module.exports = createNode

View File

@@ -1,57 +0,0 @@
/* eslint no-console: ["error", { allow: ["log"] }] */
/* eslint max-nested-callbacks: ["error", 5] */
'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:', peerInfo.id.toB58String())
})
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()
const el = document.getElementById(idStr)
el && el.remove()
})
node.start((err) => {
if (err) {
return console.log(err)
}
const idStr = node.peerInfo.id.toB58String()
const idDiv = document
.createTextNode('Node is ready. ID: ' + idStr)
myPeerDiv.append(idDiv)
console.log('Node is listening o/')
node.peerInfo.multiaddrs.toArray().forEach(ma => {
console.log(ma.toString())
})
// NOTE: to stop the node
// node.stop((err) => {})
})
})
})

View File

@@ -1,22 +1,55 @@
# libp2p running in the Browser
# libp2p in the browser
One of the primary goals with libp2p P2P was to get it fully working in the browser and interopable with the versions running in Go and in Node.js.
This example leverages the [Parcel.js bundler](https://parceljs.org/) to compile and serve the libp2p code in the browser. Parcel uses [Babel](https://babeljs.io/) to handle transpilation of the code. You can use other bundlers such as Webpack or Browserify, but we will not be covering them here.
# 1. Setting up a simple app that lists connections to other nodes
## Setup
Start by installing libp2p's dependencies.
In order to run the example, first install the dependencies from same directory as this README:
```bash
> cd ../../
> npm install
> cd examples/libp2p-in-the-browser
```
cd ./examples/libp2p-in-the-browser
npm install
```
Then simply go into the folder [1](./1) and execute the following
## Signaling Server
```bash
> cd 1
> npm install
> npm start
# open your browser in port :9090
This example uses the `libp2p-webrtc-star` module, which enables libp2p browser nodes to establish direct connections to one another via a central signaling server. For this example, we are using the signaling server that ships with `libp2p-webrtc-star`.
You can start the server by running `npm run server`. This will start a signaling server locally on port `9090`. If you'd like to run a signaling server outside of this example, you can see instructions on how to do so in the [`libp2p-webrtc-star` README](https://github.com/libp2p/js-libp2p-webrtc-star).
When you run the server, you should see output that looks something like this:
```log
$ npm run server
> libp2p-in-browser@1.0.0 server
> star-signal
Listening on: http://0.0.0.0:9090
```
## Running the examples
Once you have started the signaling server, you can run the Parcel server.
```
npm start
```
The output should look something like this:
```log
$ npm start
> libp2p-in-browser@1.0.0 start
> parcel index.html
Server running at http://localhost:1234
✨ Built in 1000ms.
```
This will compile the code and start a server listening on port [http://localhost:1234](http://localhost:1234). Now open your browser to `http://localhost:1234`. You should see a log of your node's Peer ID, the discovered peers from the Bootstrap module, and connections to those peers as they are created.
Now, if you open a second browser tab to `http://localhost:1234`, you should discover your node from the previous tab. This is due to the fact that the `libp2p-webrtc-star` transport also acts as a Peer Discovery interface. Your node will be notified of any peer that connects to the same signaling server you are connected to. Once libp2p discovers this new peer, it will attempt to establish a direct WebRTC connection.
**Note**: In the example we assign libp2p to `window.libp2p`, in case you would like to play around with the API directly in the browser. You can of course make changes to `index.js` and Parcel will automatically rebuild and reload the browser tabs.

View File

@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>js-libp2p parcel.js browser example</title>
</head>
<body>
<header>
<h1 id="status">Starting libp2p...</h1>
</header>
<main>
<pre id="output"></pre>
</main>
<script src="./index.js"></script>
</body>
</html>

View File

@@ -0,0 +1,73 @@
import 'babel-polyfill'
import Libp2p from 'libp2p'
import Websockets from 'libp2p-websockets'
import WebRTCStar from 'libp2p-webrtc-star'
import Secio from 'libp2p-secio'
import Mplex from 'libp2p-mplex'
import Boostrap from 'libp2p-bootstrap'
document.addEventListener('DOMContentLoaded', async () => {
// Create our libp2p node
const libp2p = await Libp2p.create({
modules: {
transport: [Websockets, WebRTCStar],
connEncryption: [Secio],
streamMuxer: [Mplex],
peerDiscovery: [Boostrap]
},
config: {
peerDiscovery: {
bootstrap: {
enabled: true,
list: [
'/dns4/ams-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLer265NRgSp2LA3dPaeykiS1J6DifTC88f5uVQKNAd',
'/dns4/lon-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLMeWqB7YGVLJN3pNLQpmmEk35v6wYtsMGLzSr5QBU3',
'/dns4/sfo-3.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLPppuBtQSGwKDZT2M73ULpjvfd3aZ6ha4oFGL1KrGM',
'/dns4/sgp-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLSafTMBsPKadTEgaXctDQVcqN88CNLHXMkTNwMKPnu',
'/dns4/nyc-1.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLueR4xBeUbY9WZ9xGUUxunbKWcrNFTDAadQJmocnWm',
'/dns4/nyc-2.bootstrap.libp2p.io/tcp/443/wss/p2p/QmSoLV4Bbm51jM9C4gDYZQ9Cy3U6aXMJDAbzgu2fzaDs64'
]
}
}
}
})
// UI elements
const status = document.getElementById('status')
const output = document.getElementById('output')
output.textContent = ''
function log (txt) {
console.info(txt)
output.textContent += `${txt.trim()}\n`
}
// Add the signaling server address, along with our PeerId to our multiaddrs list
// libp2p will automatically attempt to dial to the signaling server so that it can
// receive inbound connections from other peers
const webrtcAddr = '/ip4/0.0.0.0/tcp/9090/wss/p2p-webrtc-star'
libp2p.peerInfo.multiaddrs.add(webrtcAddr)
// Listen for new peers
libp2p.on('peer:discovery', (peerInfo) => {
log(`Found peer ${peerInfo.id.toB58String()}`)
})
// Listen for new connections to peers
libp2p.on('peer:connect', (peerInfo) => {
log(`Connected to ${peerInfo.id.toB58String()}`)
})
// Listen for peers disconnecting
libp2p.on('peer:disconnect', (peerInfo) => {
log(`Disconnected from ${peerInfo.id.toB58String()}`)
})
await libp2p.start()
status.innerText = 'libp2p started!'
log(`libp2p id is ${libp2p.peerInfo.id.toB58String()}`)
// Export libp2p to the window so you can play with the API
window.libp2p = libp2p
})

View File

@@ -0,0 +1,34 @@
{
"name": "libp2p-in-browser",
"version": "1.0.0",
"description": "A libp2p node running in the browser",
"main": "index.js",
"browserslist": [
"last 2 Chrome versions"
],
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "parcel index.html",
"server": "star-signal"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@babel/preset-env": "^7.8.3",
"libp2p": "../../",
"libp2p-bootstrap": "^0.10.3",
"libp2p-mplex": "^0.9.3",
"libp2p-secio": "^0.12.2",
"libp2p-webrtc-star": "^0.17.3",
"libp2p-websockets": "^0.13.2"
},
"devDependencies": {
"@babel/cli": "^7.8.3",
"@babel/core": "^7.8.3",
"babel-plugin-syntax-async-functions": "^6.13.0",
"babel-plugin-transform-regenerator": "^6.26.0",
"babel-polyfill": "^6.26.0",
"parcel-bundler": "^1.12.4"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "libp2p",
"version": "0.27.0-pre.2",
"version": "0.27.0-rc.0",
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"main": "src/index.js",
@@ -57,7 +57,7 @@
"it-protocol-buffers": "^0.2.0",
"latency-monitor": "~0.2.1",
"libp2p-crypto": "^0.17.1",
"libp2p-interfaces": "^0.1.5",
"libp2p-interfaces": "^0.2.3",
"mafmt": "^7.0.0",
"merge-options": "^2.0.0",
"moving-average": "^1.0.0",
@@ -77,7 +77,7 @@
"devDependencies": {
"@nodeutils/defaults-deep": "^1.1.0",
"abortable-iterator": "^2.1.0",
"aegir": "^20.4.1",
"aegir": "^20.5.1",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"cids": "^0.7.1",
@@ -102,7 +102,7 @@
"p-defer": "^3.0.0",
"p-times": "^2.1.0",
"p-wait-for": "^3.1.0",
"sinon": "^7.2.7",
"sinon": "^8.1.0",
"streaming-iterables": "^4.1.0",
"wrtc": "^0.4.1"
},

View File

@@ -36,7 +36,7 @@ class ConnectionManager {
constructor (libp2p, options) {
this._libp2p = libp2p
this._registrar = libp2p.registrar
this._peerId = libp2p.peerInfo.id.toString()
this._peerId = libp2p.peerInfo.id.toB58String()
this._options = mergeOptions.call({ ignoreUndefined: true }, defaultOptions, options)
assert(
this._options.maxConnections > this._options.minConnections,
@@ -91,8 +91,8 @@ class ConnectionManager {
if (value < 0 || value > 1) {
throw new Error('value should be a number between 0 and 1')
}
if (peerId.toString) {
peerId = peerId.toString()
if (peerId.toB58String) {
peerId = peerId.toB58String()
}
this._peerValues.set(peerId, value)
}
@@ -119,7 +119,7 @@ class ConnectionManager {
* @param {Connection} connection
*/
onConnect (connection) {
const peerId = connection.remotePeer.toString()
const peerId = connection.remotePeer.toB58String()
this._connections.set(connection.id, connection)
if (!this._peerValues.has(peerId)) {
this._peerValues.set(peerId, this._options.defaultPeerValue)
@@ -133,7 +133,7 @@ class ConnectionManager {
*/
onDisconnect (connection) {
this._connections.delete(connection.id)
this._peerValues.delete(connection.remotePeer.toString())
this._peerValues.delete(connection.remotePeer.toB58String())
}
/**
@@ -175,7 +175,7 @@ class ConnectionManager {
debug('%s: lowest value peer is %s', this._peerId, peerId)
debug('%s: closing a connection to %j', this._peerId, peerId)
for (const connection of this._connections.values()) {
if (connection.remotePeer.toString() === peerId) {
if (connection.remotePeer.toB58String() === peerId) {
connection.close()
break
}

View File

@@ -113,7 +113,7 @@ class Dialer {
}
const addrs = this.peerStore.multiaddrsForPeer(dialable)
return {
id: dialable.id.toString(),
id: dialable.id.toB58String(),
addrs
}
}

View File

@@ -180,7 +180,7 @@ class IdentifyService {
const id = await PeerId.createFromPubKey(publicKey)
const peerInfo = new PeerInfo(id)
if (connection.remotePeer.toString() !== id.toString()) {
if (connection.remotePeer.toB58String() !== id.toB58String()) {
throw errCode(new Error('identified peer does not match the expected peer'), codes.ERR_INVALID_PEER)
}

View File

@@ -218,7 +218,14 @@ class Libp2p extends EventEmitter {
log('libp2p is stopping')
try {
for (const service of this._discovery.values()) {
service.removeListener('peer', this._onDiscoveryPeer)
}
await Promise.all(Array.from(this._discovery.values(), s => s.stop()))
this.connectionManager.stop()
await Promise.all([
this.pubsub && this.pubsub.stop(),
this._dht && this._dht.stop(),
@@ -307,7 +314,7 @@ class Libp2p extends EventEmitter {
hangUp (peer) {
const peerInfo = getPeerInfo(peer, this.peerStore)
return Promise.all(
this.registrar.connections.get(peerInfo.id.toString()).map(connection => {
this.registrar.connections.get(peerInfo.id.toB58String()).map(connection => {
return connection.close()
})
)
@@ -419,7 +426,7 @@ class Libp2p extends EventEmitter {
* @param {PeerInfo} peerInfo
*/
_onDiscoveryPeer (peerInfo) {
if (peerInfo.id.toString() === this.peerInfo.id.toString()) {
if (peerInfo.id.toB58String() === this.peerInfo.id.toB58String()) {
log.error(new Error(codes.ERR_DISCOVERED_SELF))
return
}
@@ -438,7 +445,7 @@ class Libp2p extends EventEmitter {
if (this._config.peerDiscovery.autoDial === true && !this.registrar.getConnection(peerInfo)) {
const minPeers = this._options.connectionManager.minPeers || 0
if (minPeers > this.connectionManager._connections.size) {
log('connecting to discovered peer %s', peerInfo.id.toString())
log('connecting to discovered peer %s', peerInfo.id.toB58String())
try {
await this.dialer.connectToPeer(peerInfo)
} catch (err) {

View File

@@ -82,7 +82,7 @@ class Metrics {
* @returns {Stats}
*/
forPeer (peerId) {
const idString = peerId.toString()
const idString = peerId.toB58String()
return this._peerStats.get(idString) || this._oldPeers.get(idString)
}
@@ -110,7 +110,7 @@ class Metrics {
* @param {PeerId} peerId
*/
onPeerDisconnected (peerId) {
const idString = peerId.toString()
const idString = peerId.toB58String()
const peerStats = this._peerStats.get(idString)
if (peerStats) {
peerStats.stop()
@@ -140,7 +140,7 @@ class Metrics {
let peerStats = this.forPeer(remotePeer)
if (!peerStats) {
peerStats = new Stats(initialCounters, this._options)
this._peerStats.set(remotePeer.toString(), peerStats)
this._peerStats.set(remotePeer.toB58String(), peerStats)
}
// Peer and global stats
@@ -162,13 +162,13 @@ class Metrics {
* Replaces the `PeerId` string with the given `peerId`.
* If stats are already being tracked for the given `peerId`, the
* placeholder stats will be merged with the existing stats.
* @param {string} placeholder A peerId string
* @param {PeerId} placeholder A peerId string
* @param {PeerId} peerId
*/
updatePlaceholder (placeholder, peerId) {
if (!this._running) return
const placeholderStats = this.forPeer(placeholder)
const peerIdString = peerId.toString()
const peerIdString = peerId.toB58String()
const existingStats = this.forPeer(peerId)
let mergedStats = placeholderStats
@@ -180,7 +180,7 @@ class Metrics {
this._oldPeers.delete(peerIdString)
}
this._peerStats.delete(placeholder.toString())
this._peerStats.delete(placeholder.toB58String())
this._peerStats.set(peerIdString, mergedStats)
mergedStats.start()
}

View File

@@ -74,7 +74,7 @@ class Registrar {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
assert(Connection.isConnection(conn), 'conn must be an instance of interface-connection')
const id = peerInfo.id.toString()
const id = peerInfo.id.toB58String()
const storedConn = this.connections.get(id)
if (storedConn) {
@@ -95,18 +95,18 @@ class Registrar {
onDisconnect (peerInfo, connection, error) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
const id = peerInfo.id.toString()
const id = peerInfo.id.toB58String()
let storedConn = this.connections.get(id)
if (storedConn && storedConn.length > 1) {
storedConn = storedConn.filter((conn) => conn.id === connection.id)
storedConn = storedConn.filter((conn) => conn.id !== connection.id)
this.connections.set(id, storedConn)
} else if (storedConn) {
for (const [, topology] of this.topologies) {
topology.disconnect(peerInfo, error)
}
this.connections.delete(peerInfo.id.toString())
this.connections.delete(peerInfo.id.toB58String())
}
}
@@ -118,7 +118,7 @@ class Registrar {
getConnection (peerInfo) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
const connections = this.connections.get(peerInfo.id.toString())
const connections = this.connections.get(peerInfo.id.toB58String())
// Return the first, open connection
if (connections) {
return connections.find(connection => connection.stat.status === 'open')

View File

@@ -86,8 +86,8 @@ class TransportManager {
try {
return await transport.dial(ma, options)
} catch (err) {
if (err.code) throw err
throw errCode(err, codes.ERR_TRANSPORT_DIAL_FAILED)
if (!err.code) err.code = codes.ERR_TRANSPORT_DIAL_FAILED
throw err
}
}

View File

@@ -73,7 +73,7 @@ class Upgrader {
if (this.metrics) {
({ setTarget: setPeer, proxy: proxyPeer } = mutableProxy())
const idString = (parseInt(Math.random() * 1e9)).toString(36) + Date.now()
setPeer({ toString: () => idString })
setPeer({ toB58String: () => idString })
maConn = this.metrics.trackStream({ stream: maConn, remotePeer: proxyPeer })
}
@@ -147,7 +147,7 @@ class Upgrader {
if (this.metrics) {
({ setTarget: setPeer, proxy: proxyPeer } = mutableProxy())
const idString = (parseInt(Math.random() * 1e9)).toString(36) + Date.now()
setPeer({ toString: () => idString })
setPeer({ toB58String: () => idString })
maConn = this.metrics.trackStream({ stream: maConn, remotePeer: proxyPeer })
}
@@ -216,7 +216,10 @@ class Upgrader {
Muxer,
remotePeer
}) {
let muxer, newStream
let muxer
let newStream
// eslint-disable-next-line prefer-const
let connection
if (Muxer) {
// Create the muxer
@@ -261,7 +264,7 @@ class Upgrader {
const _timeline = maConn.timeline
maConn.timeline = new Proxy(_timeline, {
set: (...args) => {
if (args[1] === 'close' && args[2] && !_timeline.close) {
if (connection && args[1] === 'close' && args[2] && !_timeline.close) {
connection.stat.status = 'closed'
this.onConnectionEnd(connection)
}
@@ -276,7 +279,7 @@ class Upgrader {
}
// Create the connection
const connection = new Connection({
connection = new Connection({
localAddr: maConn.localAddr,
remoteAddr: maConn.remoteAddr,
localPeer: this.localPeer,

View File

@@ -75,7 +75,7 @@ describe('Connection Manager', () => {
const spy = sinon.spy(connection, 'close')
// The connections have the same remote id, give them random ones
// so that we can verify the correct connection was closed
sinon.stub(connection.remotePeer, 'toString').returns(index)
sinon.stub(connection.remotePeer, 'toB58String').returns(index)
const value = Math.random()
spies.set(value, spy)
libp2p.connectionManager.setPeerValue(connection.remotePeer, value)

View File

@@ -41,16 +41,13 @@ describe('Listening', () => {
// Should get something like:
// /ip4/127.0.0.1/tcp/50866
// /ip4/192.168.1.2/tcp/50866
expect(addrs.length).to.equal(2)
const opts = [addrs[0].toOptions(), addrs[1].toOptions()]
expect(opts[0].family).to.equal('ipv4')
expect(opts[1].family).to.equal('ipv4')
expect(opts[0].transport).to.equal('tcp')
expect(opts[1].transport).to.equal('tcp')
expect(opts[0].host).to.match(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)
expect(opts[1].host).to.match(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)
expect(opts[0].port).to.be.gt(0)
expect(opts[1].port).to.be.gt(0)
expect(addrs.length).to.be.at.least(2)
for (const addr of addrs) {
const opts = addr.toOptions()
expect(opts.family).to.equal('ipv4')
expect(opts.transport).to.equal('tcp')
expect(opts.host).to.match(/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/)
expect(opts.port).to.be.gt(0)
}
})
})

View File

@@ -306,7 +306,7 @@ describe('Dialing (direct, TCP)', () => {
}
})
const connection = await libp2p.dial(`${remoteAddr.toString()}/p2p/${remotePeerInfo.id.toString()}`)
const connection = await libp2p.dial(`${remoteAddr.toString()}/p2p/${remotePeerInfo.id.toB58String()}`)
expect(connection).to.exist()
expect(connection.stat.timeline.close).to.not.exist()
await libp2p.hangUp(connection.remotePeer)
@@ -375,7 +375,7 @@ describe('Dialing (direct, TCP)', () => {
})
const dials = 10
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerInfo.id.toString()}`)
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerInfo.id.toB58String()}`)
const dialResults = await Promise.all([...new Array(dials)].map((_, index) => {
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerInfo)
return libp2p.dial(fullAddress)
@@ -405,7 +405,7 @@ describe('Dialing (direct, TCP)', () => {
const error = new Error('Boom')
sinon.stub(libp2p.transportManager, 'dial').callsFake(() => Promise.reject(error))
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerInfo.id.toString()}`)
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerInfo.id.toB58String()}`)
const dialResults = await pSettle([...new Array(dials)].map((_, index) => {
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerInfo)
return libp2p.dial(fullAddress)

View File

@@ -59,11 +59,11 @@ describe('Dialing (via relay, TCP)', () => {
it('should be able to connect to a peer over a relay with active connections', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toString()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toString()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
const tcpAddrs = dstLibp2p.transportManager.getAddrs()
await dstLibp2p.transportManager.listen([multiaddr(`/p2p-circuit${relayAddr}/p2p/${relayIdString}`)])
@@ -94,11 +94,11 @@ describe('Dialing (via relay, TCP)', () => {
it('should fail to connect to a peer over a relay with inactive connections', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toString()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toString()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
await expect(srcLibp2p.dial(dialAddr))
.to.eventually.be.rejectedWith(AggregateError)
@@ -107,11 +107,11 @@ describe('Dialing (via relay, TCP)', () => {
it('should not stay connected to a relay when not already connected and HOP fails', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toString()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toString()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
await expect(srcLibp2p.dial(dialAddr))
.to.eventually.be.rejectedWith(AggregateError)
@@ -124,11 +124,11 @@ describe('Dialing (via relay, TCP)', () => {
it('dialer should stay connected to an already connected relay on hop failure', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toString()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toString()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
await srcLibp2p.dial(relayAddr)
@@ -143,11 +143,11 @@ describe('Dialing (via relay, TCP)', () => {
it('destination peer should stay connected to an already connected relay on hop failure', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toString()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toString()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
// Connect the destination peer and the relay
const tcpAddrs = dstLibp2p.transportManager.getAddrs()

View File

@@ -84,7 +84,12 @@ describe('Identify', () => {
it('should throw if identified peer is the wrong peer', async () => {
const localIdentify = new IdentifyService({
peerInfo: localPeer,
protocols
protocols,
registrar: {
peerStore: {
replace: () => {}
}
}
})
const remoteIdentify = new IdentifyService({
peerInfo: remotePeer,
@@ -92,7 +97,7 @@ describe('Identify', () => {
})
const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234')
const localConnectionMock = { newStream: () => {}, remotePeer }
const localConnectionMock = { newStream: () => {}, remotePeer: localPeer.id }
const remoteConnectionMock = { remoteAddr: observedAddr }
const [local, remote] = duplexPair()

View File

@@ -104,7 +104,7 @@ describe('Metrics', () => {
expect(results.length).to.eql(bytes.length * 10)
const stats = metrics.forPeer(peerId)
expect(metrics.peers).to.eql([peerId.toString()])
expect(metrics.peers).to.eql([peerId.toB58String()])
expect(stats.snapshot.dataReceived.toNumber()).to.equal(results.length)
expect(stats.snapshot.dataSent.toNumber()).to.equal(results.length)
@@ -148,7 +148,7 @@ describe('Metrics', () => {
// Flush the call stack
await delay(0)
expect(metrics.peers).to.eql([peerId.toString(), peerId2.toString()])
expect(metrics.peers).to.eql([peerId.toB58String(), peerId2.toB58String()])
// Verify global metrics
const globalStats = metrics.global
expect(globalStats.snapshot.dataReceived.toNumber()).to.equal(bytes.length * 2)
@@ -181,7 +181,7 @@ describe('Metrics', () => {
pipe(remote, remote)
const mockPeer = {
toString: () => 'a temporary id'
toB58String: () => 'a temporary id'
}
metrics.trackStream({
stream: local,
@@ -197,8 +197,8 @@ describe('Metrics', () => {
await delay(0)
metrics.updatePlaceholder(mockPeer.toString(), peerId)
mockPeer.toString = peerId.toString.bind(peerId)
metrics.updatePlaceholder(mockPeer, peerId)
mockPeer.toB58String = peerId.toB58String.bind(peerId)
input.push(bytes)
input.end()
@@ -206,7 +206,7 @@ describe('Metrics', () => {
await deferredPromise
await delay(0)
expect(metrics.peers).to.eql([peerId.toString()])
expect(metrics.peers).to.eql([peerId.toB58String()])
// Verify global metrics
const globalStats = metrics.global
expect(globalStats.snapshot.dataReceived.toNumber()).to.equal(bytes.length * 2)
@@ -237,7 +237,7 @@ describe('Metrics', () => {
// Disconnect every peer
for (const id of trackedPeers.keys()) {
metrics.onPeerDisconnected({
toString: () => id
toB58String: () => id
})
}
@@ -245,7 +245,9 @@ describe('Metrics', () => {
expect(metrics.peers).to.have.length(0)
const retainedPeers = []
for (const id of trackedPeers.keys()) {
const stat = metrics.forPeer(id)
const stat = metrics.forPeer({
toB58String: () => id
})
if (stat) retainedPeers.push(id)
}
expect(retainedPeers).to.eql(['45', '46', '47', '48', '49'])

View File

@@ -65,6 +65,32 @@ describe('peer discovery', () => {
expect(discoverySpy.called).to.eql(false)
})
it('should stop discovery on libp2p start/stop', async () => {
const mockDiscovery = {
tag: 'mock',
start: () => {},
stop: () => {},
on: () => {},
removeListener: () => {}
}
const startSpy = sinon.spy(mockDiscovery, 'start')
const stopSpy = sinon.spy(mockDiscovery, 'stop')
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerInfo,
modules: {
peerDiscovery: [mockDiscovery]
}
}))
await libp2p.start()
expect(startSpy).to.have.property('callCount', 1)
expect(stopSpy).to.have.property('callCount', 0)
await libp2p.stop()
expect(startSpy).to.have.property('callCount', 1)
expect(stopSpy).to.have.property('callCount', 1)
})
})
describe('discovery modules from transports', () => {

View File

@@ -11,6 +11,7 @@ const Topology = require('libp2p-interfaces/src/topology/multicodec-topology')
const PeerStore = require('../../src/peer-store')
const Registrar = require('../../src/registrar')
const { createMockConnection } = require('./utils')
const peerUtils = require('../utils/creators/peer')
const multicodec = '/test/1.0.0'
@@ -170,5 +171,44 @@ describe('registrar', () => {
await onDisconnectDefer.promise
})
it('should filter connections on disconnect, removing the closed one', async () => {
const onDisconnectDefer = pDefer()
const topologyProps = new Topology({
multicodecs: multicodec,
handlers: {
onConnect: () => {},
onDisconnect: () => {
onDisconnectDefer.resolve()
}
}
})
// Register protocol
registrar.register(topologyProps)
// Setup connections before registrar
const [localPeer, remotePeer] = await peerUtils.createPeerInfo({ number: 2 })
const conn1 = await createMockConnection({ localPeer: localPeer.id, remotePeer: remotePeer.id })
const conn2 = await createMockConnection({ localPeer: localPeer.id, remotePeer: remotePeer.id })
const peerInfo = await PeerInfo.create(remotePeer.id)
const id = peerInfo.id.toB58String()
// Add connection to registrar
peerStore.put(peerInfo)
registrar.onConnect(peerInfo, conn1)
registrar.onConnect(peerInfo, conn2)
expect(registrar.connections.get(id).length).to.eql(2)
conn2._stat.status = 'closed'
registrar.onDisconnect(peerInfo, conn2)
const peerConnections = registrar.connections.get(id)
expect(peerConnections.length).to.eql(1)
expect(peerConnections[0]._stat.status).to.eql('open')
})
})
})

View File

@@ -27,7 +27,8 @@ module.exports.createMockConnection = async (properties = {}) => {
},
direction: 'outbound',
encryption: '/secio/1.0.0',
multiplexer: '/mplex/6.7.0'
multiplexer: '/mplex/6.7.0',
status: 'open'
},
newStream: (protocols) => {
const id = streamId++