mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-16 17:11:57 +00:00
Compare commits
7 Commits
chore/use-
...
refactor/a
Author | SHA1 | Date | |
---|---|---|---|
|
7e1a9d677b | ||
|
1ba1ca7714 | ||
|
691e9b7f7b | ||
|
751a22741f | ||
|
461faca1ca | ||
|
31d1b2369a | ||
|
83409deaa6 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -3,6 +3,7 @@ docs
|
||||
**/*.log
|
||||
test/repo-tests*
|
||||
**/bundle.js
|
||||
.cache
|
||||
|
||||
# Logs
|
||||
logs
|
||||
|
12
CHANGELOG.md
12
CHANGELOG.md
@@ -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)
|
||||
|
||||
|
@@ -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.
|
||||
|
69
doc/API.md
69
doc/API.md
@@ -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
|
||||
|
@@ -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
247
doc/GETTING_STARTED.md
Normal 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
|
4
examples/libp2p-in-the-browser/.babelrc
Normal file
4
examples/libp2p-in-the-browser/.babelrc
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env"],
|
||||
"plugins": ["syntax-async-functions","transform-regenerator"]
|
||||
}
|
1
examples/libp2p-in-the-browser/1/.gitignore
vendored
1
examples/libp2p-in-the-browser/1/.gitignore
vendored
@@ -1 +0,0 @@
|
||||
bundle.js
|
@@ -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"
|
||||
}
|
||||
}
|
@@ -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>
|
@@ -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
|
@@ -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
|
@@ -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) => {})
|
||||
})
|
||||
})
|
||||
})
|
@@ -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.
|
||||
|
23
examples/libp2p-in-the-browser/index.html
Normal file
23
examples/libp2p-in-the-browser/index.html
Normal 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>
|
73
examples/libp2p-in-the-browser/index.js
Normal file
73
examples/libp2p-in-the-browser/index.js
Normal 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
|
||||
})
|
34
examples/libp2p-in-the-browser/package.json
Normal file
34
examples/libp2p-in-the-browser/package.json
Normal 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"
|
||||
}
|
||||
}
|
10
package.json
10
package.json
@@ -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",
|
||||
@@ -90,7 +90,7 @@
|
||||
"libp2p-delegated-content-routing": "^0.4.1",
|
||||
"libp2p-delegated-peer-routing": "^0.4.0",
|
||||
"libp2p-floodsub": "^0.20.0",
|
||||
"libp2p-gossipsub": "ChainSafe/gossipsub-js#fix/bind-is-not-needed",
|
||||
"libp2p-gossipsub": "^0.2.0",
|
||||
"libp2p-kad-dht": "^0.18.2",
|
||||
"libp2p-mdns": "^0.13.0",
|
||||
"libp2p-mplex": "^0.9.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"
|
||||
},
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -113,7 +113,7 @@ class Dialer {
|
||||
}
|
||||
const addrs = this.peerStore.multiaddrsForPeer(dialable)
|
||||
return {
|
||||
id: dialable.id.toString(),
|
||||
id: dialable.id.toB58String(),
|
||||
addrs
|
||||
}
|
||||
}
|
||||
|
@@ -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)
|
||||
}
|
||||
|
||||
|
@@ -314,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()
|
||||
})
|
||||
)
|
||||
@@ -426,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
|
||||
}
|
||||
@@ -445,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) {
|
||||
|
@@ -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()
|
||||
}
|
||||
|
@@ -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')
|
||||
|
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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,
|
||||
|
@@ -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)
|
||||
|
@@ -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)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@@ -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)
|
||||
|
@@ -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()
|
||||
|
@@ -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()
|
||||
|
@@ -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'])
|
||||
|
@@ -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')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@@ -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++
|
||||
|
Reference in New Issue
Block a user