mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-31 00:12:00 +00:00
Compare commits
3 Commits
v0.30.13
...
feat/obser
Author | SHA1 | Date | |
---|---|---|---|
|
459d3f24af | ||
|
b1f4e5be4a | ||
|
da4fb5a074 |
@@ -48,7 +48,7 @@ const after = async () => {
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
bundlesize: { maxSize: '223kB' },
|
||||
bundlesize: { maxSize: '216kB' },
|
||||
hooks: {
|
||||
pre: before,
|
||||
post: after
|
||||
|
45
.github/workflows/main.yml
vendored
45
.github/workflows/main.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||
node: [14]
|
||||
node: [12, 14]
|
||||
fail-fast: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
@@ -79,20 +79,13 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: cd examples && yarn && npm run test -- connection-encryption
|
||||
test-discovery-mechanisms-example:
|
||||
needs: check
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: cd examples && yarn && npm run test -- discovery-mechanisms
|
||||
test-echo-example:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: cd examples && yarn && npm run test -- echo
|
||||
- run: cd examples && yarn && npm run test -- echo
|
||||
test-libp2p-in-the-browser-example:
|
||||
needs: check
|
||||
runs-on: macos-latest
|
||||
@@ -100,13 +93,13 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: cd examples && yarn && npm run test -- libp2p-in-the-browser
|
||||
test-peer-and-content-routing-example:
|
||||
test-discovery-mechanisms-example:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: cd examples && yarn && npm run test -- peer-and-content-routing
|
||||
- run: cd examples && yarn && npm run test -- discovery-mechanisms
|
||||
test-pnet-example:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
@@ -114,31 +107,3 @@ jobs:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: cd examples && yarn && npm run test -- pnet
|
||||
test-protocol-and-stream-muxing-example:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: cd examples && yarn && npm run test -- protocol-and-stream-muxing
|
||||
test-pubsub-example:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: cd examples && yarn && npm run test -- pubsub
|
||||
test-transports-example:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: cd examples && yarn && npm run test -- transports
|
||||
test-webrtc-direct-example:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: cd examples && yarn && npm run test -- webrtc-direct
|
||||
|
59
CHANGELOG.md
59
CHANGELOG.md
@@ -1,62 +1,3 @@
|
||||
## [0.30.13](https://github.com/libp2p/js-libp2p/compare/v0.30.12...v0.30.13) (2021-08-19)
|
||||
|
||||
|
||||
|
||||
## [0.30.12](https://github.com/libp2p/js-libp2p/compare/v0.30.11...v0.30.12) (2021-03-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* the API of es6-promisify is not the same as promisify-es6 ([#905](https://github.com/libp2p/js-libp2p/issues/905)) ([a7128f0](https://github.com/libp2p/js-libp2p/commit/a7128f07ec8d4b729145ecfc6ad1d585ffddea46))
|
||||
|
||||
|
||||
|
||||
## [0.30.11](https://github.com/libp2p/js-libp2p/compare/v0.30.10...v0.30.11) (2021-03-23)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* connection direction should be only inbound or outbound ([9504f19](https://github.com/libp2p/js-libp2p/commit/9504f1951a3cca55bb7b4e25e4934e4024034ee8))
|
||||
* interface-datastore update ([f5c1cd1](https://github.com/libp2p/js-libp2p/commit/f5c1cd1fb07bc73cf9d9da3c2eb4327bed4279a4))
|
||||
|
||||
|
||||
|
||||
## [0.30.10](https://github.com/libp2p/js-libp2p/compare/v0.30.9...v0.30.10) (2021-03-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* conn mgr access to moving averages record object ([#897](https://github.com/libp2p/js-libp2p/issues/897)) ([5f702f3](https://github.com/libp2p/js-libp2p/commit/5f702f3481afd4ad4fbc89f0e9b75a6d56b03520))
|
||||
|
||||
|
||||
|
||||
## [0.30.9](https://github.com/libp2p/js-libp2p/compare/v0.30.8...v0.30.9) (2021-02-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* transport manager fault tolerance should include tolerance to transport listen fail ([#893](https://github.com/libp2p/js-libp2p/issues/893)) ([3f314d5](https://github.com/libp2p/js-libp2p/commit/3f314d5e90f74583b721386d0c9c5d8363cd4de7))
|
||||
|
||||
|
||||
|
||||
## [0.30.8](https://github.com/libp2p/js-libp2p/compare/v0.30.7...v0.30.8) (2021-02-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* routers should only use dht if enabled ([#885](https://github.com/libp2p/js-libp2p/issues/885)) ([a34d2bb](https://github.com/libp2p/js-libp2p/commit/a34d2bbcc3d69ec3006137a909a7e8c53b9d378e))
|
||||
|
||||
|
||||
|
||||
## [0.30.7](https://github.com/libp2p/js-libp2p/compare/v0.30.6...v0.30.7) (2021-02-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* do not add observed address received from peers ([#882](https://github.com/libp2p/js-libp2p/issues/882)) ([a36b211](https://github.com/libp2p/js-libp2p/commit/a36b2112aafcee309a02de0cff5440cf69cd53a7))
|
||||
|
||||
|
||||
|
||||
## [0.30.6](https://github.com/libp2p/js-libp2p/compare/v0.30.5...v0.30.6) (2021-01-29)
|
||||
|
||||
|
||||
|
@@ -23,6 +23,7 @@
|
||||
- [Setup with Auto Relay](#setup-with-auto-relay)
|
||||
- [Setup with Keychain](#setup-with-keychain)
|
||||
- [Configuring Dialing](#configuring-dialing)
|
||||
- [Configuring Address Manager](#configuring-address-manager)
|
||||
- [Configuring Connection Manager](#configuring-connection-manager)
|
||||
- [Configuring Transport Manager](#configuring-transport-manager)
|
||||
- [Configuring Metrics](#configuring-metrics)
|
||||
@@ -391,7 +392,6 @@ const Libp2p = require('libp2p')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const MPLEX = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const ipfsHttpClient = require('ipfs-http-client')
|
||||
const DelegatedPeerRouter = require('libp2p-delegated-peer-routing')
|
||||
const DelegatedContentRouter = require('libp2p-delegated-content-routing')
|
||||
const PeerId = require('peer-id')
|
||||
@@ -399,25 +399,17 @@ const PeerId = require('peer-id')
|
||||
// create a peerId
|
||||
const peerId = await PeerId.create()
|
||||
|
||||
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient({
|
||||
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
|
||||
protocol: 'https',
|
||||
port: 443
|
||||
}))
|
||||
|
||||
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient({
|
||||
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
|
||||
protocol: 'https',
|
||||
port: 443
|
||||
}))
|
||||
|
||||
const node = await Libp2p.create({
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
streamMuxer: [MPLEX],
|
||||
connEncryption: [NOISE],
|
||||
contentRouting: [delegatedContentRouting],
|
||||
peerRouting: [delegatedPeerRouting],
|
||||
contentRouting: [
|
||||
new DelegatedContentRouter(peerId)
|
||||
],
|
||||
peerRouting: [
|
||||
new DelegatedPeerRouter()
|
||||
],
|
||||
},
|
||||
peerId,
|
||||
peerRouting: { // Peer routing configuration
|
||||
@@ -558,6 +550,26 @@ const node = await Libp2p.create({
|
||||
}
|
||||
```
|
||||
|
||||
#### Configuring Address Manager
|
||||
|
||||
The address manager receives observed addresses from network peers. We accept observed addresses once a certain number of peers have reported the same observed address within a certain window of time.
|
||||
|
||||
```js
|
||||
const node = await Libp2p.create({
|
||||
addressManager: {
|
||||
observedAddresses: {
|
||||
// we must receive the same observed address from this many
|
||||
// peers before we start believe it
|
||||
minConfidence: 4,
|
||||
// an address must reach the minimum level of confidence within
|
||||
// this timeout otherwise it will be ignored
|
||||
maxLifetimeBeforeEviction: (60 * 10) * 1000 // ten minutes in ms
|
||||
}
|
||||
},
|
||||
// ...other options
|
||||
})
|
||||
```
|
||||
|
||||
#### Configuring Connection Manager
|
||||
|
||||
The Connection Manager prunes Connections in libp2p whenever certain limits are exceeded. If Metrics are enabled, you can also configure the Connection Manager to monitor the bandwidth of libp2p and prune connections as needed. You can read more about what Connection Manager does at [./CONNECTION_MANAGER.md](./CONNECTION_MANAGER.md). The configuration values below show the defaults for Connection Manager. See [./CONNECTION_MANAGER.md](./CONNECTION_MANAGER.md#options) for a full description of the parameters.
|
||||
|
@@ -8,7 +8,7 @@ Let us know if you find any issues, or if you want to contribute and add a new t
|
||||
|
||||
- [Transports](./transports)
|
||||
- [Protocol and Stream Muxing](./protocol-and-stream-muxing)
|
||||
- [Connection Encryption](./connection-encryption)
|
||||
- [Encrypted Communications](./encrypted-communications)
|
||||
- [Discovery Mechanisms](./discovery-mechanisms)
|
||||
- [Peer and Content Routing](./peer-and-content-routing)
|
||||
- [PubSub](./pubsub)
|
||||
|
@@ -1,68 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const Libp2p = require('../../')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const Mplex = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const Gossipsub = require('libp2p-gossipsub')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
const PubsubPeerDiscovery = require('libp2p-pubsub-peer-discovery')
|
||||
|
||||
const createRelayServer = require('libp2p-relay-server')
|
||||
|
||||
const createNode = async (bootstrapers) => {
|
||||
const node = await Libp2p.create({
|
||||
addresses: {
|
||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||
},
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
streamMuxer: [Mplex],
|
||||
connEncryption: [NOISE],
|
||||
pubsub: Gossipsub,
|
||||
peerDiscovery: [Bootstrap, PubsubPeerDiscovery]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
[PubsubPeerDiscovery.tag]: {
|
||||
interval: 1000,
|
||||
enabled: true
|
||||
},
|
||||
[Bootstrap.tag]: {
|
||||
enabled: true,
|
||||
list: bootstrapers
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
const relay = await createRelayServer({
|
||||
listenAddresses: ['/ip4/0.0.0.0/tcp/0']
|
||||
})
|
||||
console.log(`libp2p relay starting with id: ${relay.peerId.toB58String()}`)
|
||||
await relay.start()
|
||||
const relayMultiaddrs = relay.multiaddrs.map((m) => `${m.toString()}/p2p/${relay.peerId.toB58String()}`)
|
||||
|
||||
const [node1, node2] = await Promise.all([
|
||||
createNode(relayMultiaddrs),
|
||||
createNode(relayMultiaddrs)
|
||||
])
|
||||
|
||||
node1.on('peer:discovery', (peerId) => {
|
||||
console.log(`Peer ${node1.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
|
||||
})
|
||||
node2.on('peer:discovery', (peerId) => {
|
||||
console.log(`Peer ${node2.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
|
||||
})
|
||||
|
||||
;[node1, node2].forEach((node, index) => console.log(`Node ${index} starting with id: ${node.peerId.toB58String()}`))
|
||||
await Promise.all([
|
||||
node1.start(),
|
||||
node2.start()
|
||||
])
|
||||
})();
|
@@ -2,13 +2,13 @@
|
||||
|
||||
A Peer Discovery module enables libp2p to find peers to connect to. Think of these mechanisms as ways to join the rest of the network, as railing points.
|
||||
|
||||
With this system, a libp2p node can both have a set of nodes to always connect on boot (bootstraper nodes), discover nodes through locality (e.g connected in the same LAN) or through serendipity (random walks on a DHT).
|
||||
With these system, a libp2p node can both have a set of nodes to always connect on boot (bootstraper nodes), discover nodes through locality (e.g connected in the same LAN) or through serendipity (random walks on a DHT).
|
||||
|
||||
These mechanisms save configuration and enable a node to operate without any explicit dials, it will just work. Once new peers are discovered, their known data is stored in the peer's PeerStore.
|
||||
|
||||
## 1. Bootstrap list of Peers when booting a node
|
||||
|
||||
For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, mplex, and NOISE. You can see the complete example at [1.js](./1.js).
|
||||
For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, mplex and NOISE. You can see the complete example at [1.js](./1.js).
|
||||
|
||||
First, we create our libp2p node.
|
||||
|
||||
@@ -16,7 +16,7 @@ First, we create our libp2p node.
|
||||
const Libp2p = require('libp2p')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
|
||||
const node = await Libp2p.create({
|
||||
const node = Libp2p.create({
|
||||
modules: {
|
||||
transport: [ TCP ],
|
||||
streamMuxer: [ Mplex ],
|
||||
@@ -156,103 +156,10 @@ Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m
|
||||
Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ
|
||||
```
|
||||
|
||||
## 3. Pubsub based Peer Discovery
|
||||
|
||||
For this example, we need [`libp2p-pubsub-peer-discovery`](https://github.com/libp2p/js-libp2p-pubsub-peer-discovery/), go ahead and `npm install` it. You also need to spin up a set of [`libp2p-relay-servers`](https://github.com/libp2p/js-libp2p-relay-server). These servers act as relay servers and a peer discovery source.
|
||||
|
||||
In the context of this example, we will create and run the `libp2p-relay-server` in the same code snippet. You can find the complete solution at [3.js](./3.js).
|
||||
|
||||
You can create your libp2p nodes as follows:
|
||||
|
||||
```js
|
||||
const Libp2p = require('libp2p')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const Mplex = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const Gossipsub = require('libp2p-gossipsub')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
const PubsubPeerDiscovery = require('libp2p-pubsub-peer-discovery')
|
||||
|
||||
const createNode = async (bootstrapers) => {
|
||||
const node = await Libp2p.create({
|
||||
addresses: {
|
||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||
},
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
streamMuxer: [Mplex],
|
||||
connEncryption: [NOISE],
|
||||
pubsub: Gossipsub,
|
||||
peerDiscovery: [Bootstrap, PubsubPeerDiscovery]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
[PubsubPeerDiscovery.tag]: {
|
||||
interval: 1000,
|
||||
enabled: true
|
||||
},
|
||||
[Bootstrap.tag]: {
|
||||
enabled: true,
|
||||
list: bootstrapers
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return node
|
||||
}
|
||||
```
|
||||
|
||||
We will use the `libp2p-relay-server` as bootstrap nodes for the libp2p nodes, so that they establish a connection with the relay after starting. As a result, after they establish a connection with the relay, the pubsub discovery will kick in and the relay will advertise them.
|
||||
|
||||
```js
|
||||
const relay = await createRelayServer({
|
||||
listenAddresses: ['/ip4/0.0.0.0/tcp/0']
|
||||
})
|
||||
console.log(`libp2p relay starting with id: ${relay.peerId.toB58String()}`)
|
||||
await relay.start()
|
||||
const relayMultiaddrs = relay.multiaddrs.map((m) => `${m.toString()}/p2p/${relay.peerId.toB58String()}`)
|
||||
|
||||
const [node1, node2] = await Promise.all([
|
||||
createNode(relayMultiaddrs),
|
||||
createNode(relayMultiaddrs)
|
||||
])
|
||||
|
||||
node1.on('peer:discovery', (peerId) => {
|
||||
console.log(`Peer ${node1.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
|
||||
})
|
||||
node2.on('peer:discovery', (peerId) => {
|
||||
console.log(`Peer ${node2.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
|
||||
})
|
||||
|
||||
;[node1, node2].forEach((node, index) => console.log(`Node ${index} starting with id: ${node.peerId.toB58String()}`))
|
||||
await Promise.all([
|
||||
node1.start(),
|
||||
node2.start()
|
||||
])
|
||||
```
|
||||
|
||||
If you run this example, you will see the other peers being discovered.
|
||||
|
||||
```bash
|
||||
> node 3.js
|
||||
libp2p relay starting with id: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
|
||||
Node 0 starting with id: QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N
|
||||
Node 1 starting with id: QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv
|
||||
Peer QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N discovered: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
|
||||
Peer QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv discovered: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
|
||||
Peer QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv discovered: QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N
|
||||
Peer QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N discovered: QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv
|
||||
```
|
||||
|
||||
Taking into account the output, after the relay and both libp2p nodes start, both libp2p nodes will discover the bootstrap node (relay) and connect with it. After establishing a connection with the relay, they will discover each other.
|
||||
|
||||
This is really useful when running libp2p in constrained environments like a browser. You can run a set of `libp2p-relay-server` nodes that will be responsible for both relaying websocket connections between browser nodes and for discovering other browser peers.
|
||||
|
||||
## 4. Where to find other Peer Discovery Mechanisms
|
||||
## 3. Where to find other Peer Discovery Mechanisms
|
||||
|
||||
There are plenty more Peer Discovery Mechanisms out there, you can:
|
||||
|
||||
- Find one in [libp2p-webrtc-star](https://github.com/libp2p/js-libp2p-webrtc-star). Yes, a transport with discovery capabilities! This happens because WebRTC requires a rendezvous point for peers to exchange [SDP](https://tools.ietf.org/html/rfc4317) offer, which means we have one or more points that can introduce peers to each other. Think of it as MulticastDNS for the Web, as in MulticastDNS only works in LAN.
|
||||
- Any DHT will offer you a discovery capability. You can simple _random-walk_ the routing tables to find other peers to connect to. For example [libp2p-kad-dht](https://github.com/libp2p/js-libp2p-kad-dht) can be used for peer discovery. An example of how to configure it to enable random walks can be found [here](https://github.com/libp2p/js-libp2p/blob/v0.28.4/doc/CONFIGURATION.md#customizing-dht).
|
||||
- Any DHT will offer you a discovery capability. You can simple _random-walk_ the routing tables to find other peers to connect to. For example [libp2p-kad-dht](https://github.com/libp2p/js-libp2p-kad-dht) can be used for peer discovery. An example how to configure it to enable random walks can be found [here](https://github.com/libp2p/js-libp2p/blob/v0.28.4/doc/CONFIGURATION.md#customizing-dht).
|
||||
- You can create your own Discovery service, a registry, a list, a radio beacon, you name it!
|
||||
|
@@ -1,35 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const discoveredCopy = 'discovered:'
|
||||
|
||||
async function test() {
|
||||
let discoverCount = 0
|
||||
|
||||
process.stdout.write('3.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '3.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
// Discovered or Connected
|
||||
if (line.includes(discoveredCopy)) {
|
||||
discoverCount++
|
||||
}
|
||||
})
|
||||
|
||||
await pWaitFor(() => discoverCount === 4)
|
||||
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -2,12 +2,10 @@
|
||||
|
||||
const test1 = require('./test-1')
|
||||
const test2 = require('./test-2')
|
||||
const test3 = require('./test-3')
|
||||
|
||||
async function test () {
|
||||
await test1()
|
||||
await test2()
|
||||
await test3()
|
||||
}
|
||||
|
||||
module.exports = test
|
||||
|
@@ -15,7 +15,7 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@babel/preset-env": "^7.13.0",
|
||||
"@babel/preset-env": "^7.8.3",
|
||||
"libp2p": "../../",
|
||||
"libp2p-bootstrap": "^0.12.1",
|
||||
"libp2p-mplex": "^0.10.0",
|
||||
@@ -24,11 +24,11 @@
|
||||
"libp2p-websockets": "^0.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.13.10",
|
||||
"@babel/core": "^7.13.0",
|
||||
"@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.3"
|
||||
"parcel-bundler": "^1.12.4"
|
||||
}
|
||||
}
|
||||
|
@@ -10,8 +10,6 @@
|
||||
"dependencies": {
|
||||
"execa": "^2.1.0",
|
||||
"fs-extra": "^8.1.0",
|
||||
"libp2p-pubsub-peer-discovery": "^3.0.0",
|
||||
"libp2p-relay-server": "^0.1.2",
|
||||
"p-defer": "^3.0.0",
|
||||
"which": "^2.0.1"
|
||||
},
|
||||
|
@@ -1,36 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test() {
|
||||
process.stdout.write('1.js\n')
|
||||
|
||||
const addrs = []
|
||||
let foundIt = false
|
||||
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
// Discovered peer
|
||||
if (!foundIt && line.includes('Found it, multiaddrs are:')) {
|
||||
foundIt = true
|
||||
}
|
||||
|
||||
addrs.push(line)
|
||||
})
|
||||
|
||||
await pWaitFor(() => addrs.length === 2)
|
||||
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,40 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const providedCopy = 'is providing'
|
||||
const foundCopy = 'Found provider:'
|
||||
|
||||
async function test() {
|
||||
process.stdout.write('2.js\n')
|
||||
const providedDefer = pDefer()
|
||||
const foundDefer = pDefer()
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '2.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes(providedCopy)) {
|
||||
providedDefer.resolve()
|
||||
} else if (line.includes(foundCopy)) {
|
||||
foundDefer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
providedDefer.promise,
|
||||
foundDefer.promise
|
||||
])
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,11 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const test1 = require('./test-1')
|
||||
const test2 = require('./test-2')
|
||||
|
||||
async function test() {
|
||||
await test1()
|
||||
await test2()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,31 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test() {
|
||||
const messageDefer = pDefer()
|
||||
process.stdout.write('1.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes('my own protocol, wow!')) {
|
||||
messageDefer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await messageDefer.promise
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,38 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const messages = [
|
||||
'protocol (a)',
|
||||
'protocol (b)',
|
||||
'another stream on protocol (b)'
|
||||
]
|
||||
|
||||
async function test() {
|
||||
process.stdout.write('2.js\n')
|
||||
|
||||
let count = 0
|
||||
const proc = execa('node', [path.join(__dirname, '2.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (messages.find((m) => line.includes(m))) {
|
||||
count += 1
|
||||
}
|
||||
})
|
||||
|
||||
await pWaitFor(() => count === messages.length)
|
||||
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,37 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const messages = [
|
||||
'from 1 to 2',
|
||||
'from 2 to 1'
|
||||
]
|
||||
|
||||
async function test() {
|
||||
process.stdout.write('3.js\n')
|
||||
|
||||
let count = 0
|
||||
const proc = execa('node', [path.join(__dirname, '3.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (messages.find((m) => line.includes(m))) {
|
||||
count += 1
|
||||
}
|
||||
})
|
||||
|
||||
await pWaitFor(() => count === messages.length)
|
||||
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const test1 = require('./test-1')
|
||||
const test2 = require('./test-2')
|
||||
const test3 = require('./test-3')
|
||||
|
||||
async function test() {
|
||||
await test1()
|
||||
await test2()
|
||||
await test3()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,67 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const stdout = [
|
||||
{
|
||||
topic: 'banana',
|
||||
messageCount: 2
|
||||
},
|
||||
{
|
||||
topic: 'apple',
|
||||
messageCount: 2
|
||||
},
|
||||
{
|
||||
topic: 'car',
|
||||
messageCount: 0
|
||||
},
|
||||
{
|
||||
topic: 'orange',
|
||||
messageCount: 2
|
||||
},
|
||||
]
|
||||
|
||||
async function test () {
|
||||
const defer = pDefer()
|
||||
let topicCount = 0
|
||||
let topicMessageCount = 0
|
||||
|
||||
process.stdout.write('message-filtering/1.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
// End
|
||||
if (topicCount === stdout.length) {
|
||||
defer.resolve()
|
||||
proc.all.removeAllListeners('data')
|
||||
}
|
||||
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (stdout[topicCount] && line.includes(stdout[topicCount].topic)) {
|
||||
// Validate previous number of messages
|
||||
if (topicCount > 0 && topicMessageCount > stdout[topicCount - 1].messageCount) {
|
||||
defer.reject()
|
||||
throw new Error(`topic ${stdout[topicCount - 1].topic} had ${topicMessageCount} messages instead of ${stdout[topicCount - 1].messageCount}`)
|
||||
}
|
||||
|
||||
topicCount++
|
||||
topicMessageCount = 0
|
||||
} else {
|
||||
topicMessageCount++
|
||||
}
|
||||
})
|
||||
|
||||
await defer.promise
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,30 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const defer = pDefer()
|
||||
process.stdout.write('1.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes('node1 received: Bird bird bird, bird is the word!')) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await defer.promise
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,11 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const test1 = require('./test-1')
|
||||
const testMessageFiltering = require('./message-filtering/test')
|
||||
|
||||
async function test() {
|
||||
await test1()
|
||||
await testMessageFiltering()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,38 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const deferStarted = pDefer()
|
||||
const deferListen = pDefer()
|
||||
|
||||
process.stdout.write('1.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
|
||||
if (line.includes('node has started (true/false): true')) {
|
||||
deferStarted.resolve()
|
||||
} else if (line.includes('p2p')) {
|
||||
deferListen.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
deferStarted.promise,
|
||||
deferListen.promise
|
||||
])
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,30 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const defer = pDefer()
|
||||
process.stdout.write('2.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '2.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes('Hello p2p world!')) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await defer.promise
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,41 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const deferNode1 = pDefer()
|
||||
const deferNode2 = pDefer()
|
||||
const deferNode3 = pDefer()
|
||||
|
||||
process.stdout.write('3.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '3.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes('node 1 dialed to node 2 successfully')) {
|
||||
deferNode1.resolve()
|
||||
} else if (line.includes('node 2 dialed to node 3 successfully')) {
|
||||
deferNode2.resolve()
|
||||
} else if (line.includes('node 3 failed to dial to node 1 with:')) {
|
||||
deferNode3.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
deferNode1.promise,
|
||||
deferNode2.promise,
|
||||
deferNode3.promise
|
||||
])
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const test1 = require('./test-1')
|
||||
const test2 = require('./test-2')
|
||||
const test3 = require('./test-3')
|
||||
|
||||
async function test() {
|
||||
await test1()
|
||||
await test2()
|
||||
await test3()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,33 +0,0 @@
|
||||
### Webrtc-direct example
|
||||
|
||||
An example that uses [js-libp2p-webrtc-direct](https://github.com/libp2p/js-libp2p-webrtc-direct) for connecting
|
||||
nodejs libp2p and browser libp2p clients. To run the example:
|
||||
|
||||
## 0. Run a nodejs libp2p listener
|
||||
|
||||
When in the root folder of this example, type `node listener.js` in terminal. You should see an address that listens for
|
||||
incoming connections. Below is just an example of such address. In your case the suffix hash (`peerId`) will be different.
|
||||
|
||||
```bash
|
||||
$ node listener.js
|
||||
Listening on:
|
||||
/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/QmUKQCzEUhhhobcNSrXU5uzxTqbvF1BjMCGNGZzZU14Kgd
|
||||
```
|
||||
|
||||
## 1. Prepare a browser libp2p dialer
|
||||
Confirm that the above address is the same as the field `list` in `public/dialer.js`:
|
||||
```js
|
||||
peerDiscovery: {
|
||||
[Bootstrap.tag]: {
|
||||
enabled: true,
|
||||
// paste the address into `list`
|
||||
list: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/QmUKQCzEUhhhobcNSrXU5uzxTqbvF1BjMCGNGZzZU14Kgd']
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Run a browser libp2p dialer
|
||||
When in the root folder of this example, type `npm run dev` in terminal. You should see an address where you can browse
|
||||
the running client. Open this address in your browser. In console
|
||||
logs you should see logs about successful connection with the node client. In the output of node client you should see
|
||||
a log message about successful connection as well.
|
@@ -1,57 +0,0 @@
|
||||
import 'babel-polyfill'
|
||||
const Libp2p = require('libp2p')
|
||||
const WebRTCDirect = require('libp2p-webrtc-direct')
|
||||
const Mplex = require('libp2p-mplex')
|
||||
const {NOISE} = require('libp2p-noise')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
// use the same peer id as in `listener.js` to avoid copy-pasting of listener's peer id into `peerDiscovery`
|
||||
const hardcodedPeerId = '12D3KooWCuo3MdXfMgaqpLC5Houi1TRoFqgK9aoxok4NK5udMu8m'
|
||||
const libp2p = await Libp2p.create({
|
||||
modules: {
|
||||
transport: [WebRTCDirect],
|
||||
streamMuxer: [Mplex],
|
||||
connEncryption: [NOISE],
|
||||
peerDiscovery: [Bootstrap]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
[Bootstrap.tag]: {
|
||||
enabled: true,
|
||||
list: [`/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/${hardcodedPeerId}`]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const status = document.getElementById('status')
|
||||
const output = document.getElementById('output')
|
||||
|
||||
output.textContent = ''
|
||||
|
||||
function log (txt) {
|
||||
console.info(txt)
|
||||
output.textContent += `${txt.trim()}\n`
|
||||
}
|
||||
|
||||
// Listen for new peers
|
||||
libp2p.on('peer:discovery', (peerId) => {
|
||||
log(`Found peer ${peerId.toB58String()}`)
|
||||
})
|
||||
|
||||
// Listen for new connections to peers
|
||||
libp2p.connectionManager.on('peer:connect', (connection) => {
|
||||
log(`Connected to ${connection.remotePeer.toB58String()}`)
|
||||
})
|
||||
|
||||
// Listen for peers disconnecting
|
||||
libp2p.connectionManager.on('peer:disconnect', (connection) => {
|
||||
log(`Disconnected from ${connection.remotePeer.toB58String()}`)
|
||||
})
|
||||
|
||||
await libp2p.start()
|
||||
status.innerText = 'libp2p started!'
|
||||
log(`libp2p id is ${libp2p.peerId.toB58String()}`)
|
||||
|
||||
})
|
@@ -1,17 +0,0 @@
|
||||
<!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="./dialer.js"></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,44 +0,0 @@
|
||||
const Libp2p = require('libp2p')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
const WebRTCDirect = require('libp2p-webrtc-direct')
|
||||
const Mplex = require('libp2p-mplex')
|
||||
const {NOISE} = require('libp2p-noise')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
;(async () => {
|
||||
// hardcoded peer id to avoid copy-pasting of listener's peer id into the dialer's bootstrap list
|
||||
// generated with cmd `peer-id --type=ed25519`
|
||||
const hardcodedPeerId = await PeerId.createFromJSON({
|
||||
"id": "12D3KooWCuo3MdXfMgaqpLC5Houi1TRoFqgK9aoxok4NK5udMu8m",
|
||||
"privKey": "CAESQAG6Ld7ev6nnD0FKPs033/j0eQpjWilhxnzJ2CCTqT0+LfcWoI2Vr+zdc1vwk7XAVdyoCa2nwUR3RJebPWsF1/I=",
|
||||
"pubKey": "CAESIC33FqCNla/s3XNb8JO1wFXcqAmtp8FEd0SXmz1rBdfy"
|
||||
})
|
||||
const node = await Libp2p.create({
|
||||
peerId: hardcodedPeerId,
|
||||
addresses: {
|
||||
listen: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct']
|
||||
},
|
||||
modules: {
|
||||
transport: [WebRTCDirect],
|
||||
streamMuxer: [Mplex],
|
||||
connEncryption: [NOISE]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
[Bootstrap.tag]: {
|
||||
enabled: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
node.connectionManager.on('peer:connect', (connection) => {
|
||||
console.info(`Connected to ${connection.remotePeer.toB58String()}!`)
|
||||
})
|
||||
|
||||
await node.start()
|
||||
|
||||
console.log('Listening on:')
|
||||
node.multiaddrs.forEach((ma) => console.log(`${ma.toString()}/p2p/${node.peerId.toB58String()}`))
|
||||
|
||||
})()
|
@@ -1,31 +0,0 @@
|
||||
{
|
||||
"name": "webrtc-direct",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"description": "",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "parcel build index.html",
|
||||
"start": "parcel index.html"
|
||||
},
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.13.10",
|
||||
"@babel/core": "^7.13.10",
|
||||
"babel-plugin-syntax-async-functions": "^6.13.0",
|
||||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"parcel-bundler": "1.12.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"libp2p": "../../",
|
||||
"libp2p-bootstrap": "^0.12.1",
|
||||
"libp2p-mplex": "^0.10.1",
|
||||
"libp2p-noise": "^2.0.1",
|
||||
"libp2p-webrtc-direct": "^0.5.0",
|
||||
"peer-id": "^0.14.3"
|
||||
},
|
||||
"browser": {
|
||||
"ipfs": "ipfs/dist/index.min.js"
|
||||
}
|
||||
}
|
@@ -1,93 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
function startNode (name, args = []) {
|
||||
return execa('node', [path.join(__dirname, name), ...args], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
}
|
||||
|
||||
function startBrowser (name, args = []) {
|
||||
return execa('parcel', [path.join(__dirname, name), ...args], {
|
||||
preferLocal: true,
|
||||
localDir: __dirname,
|
||||
cwd: __dirname,
|
||||
all: true
|
||||
})
|
||||
}
|
||||
|
||||
async function test () {
|
||||
// Step 1, listener process
|
||||
const listenerProcReady = pDefer()
|
||||
let listenerOutput = ''
|
||||
process.stdout.write('listener.js\n')
|
||||
const listenerProc = startNode('listener.js')
|
||||
|
||||
listenerProc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
listenerOutput += uint8ArrayToString(data)
|
||||
if (listenerOutput.includes('Listening on:') && listenerOutput.includes('12D3KooWCuo3MdXfMgaqpLC5Houi1TRoFqgK9aoxok4NK5udMu8m')) {
|
||||
listenerProcReady.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await listenerProcReady.promise
|
||||
process.stdout.write('==================================================================\n')
|
||||
|
||||
// Step 2, dialer process
|
||||
process.stdout.write('dialer.js\n')
|
||||
let dialerUrl = ''
|
||||
const dialerProc = startBrowser('index.html')
|
||||
|
||||
dialerProc.all.on('data', async (chunk) => {
|
||||
/**@type {string} */
|
||||
const out = chunk.toString()
|
||||
|
||||
if (out.includes('Server running at')) {
|
||||
dialerUrl = out.replace('Server running at ', '')
|
||||
}
|
||||
|
||||
if (out.includes('✨ Built in ')) {
|
||||
try {
|
||||
const browser = await chromium.launch();
|
||||
const page = await browser.newPage();
|
||||
await page.goto(dialerUrl);
|
||||
await page.waitForFunction(selector => document.querySelector(selector).innerText === 'libp2p started!', '#status')
|
||||
await page.waitForFunction(
|
||||
selector => {
|
||||
const text = document.querySelector(selector).innerText
|
||||
return text.includes('libp2p id is') &&
|
||||
text.includes('Found peer') &&
|
||||
text.includes('Connected to')
|
||||
},
|
||||
'#output',
|
||||
{ timeout: 10000 }
|
||||
)
|
||||
await browser.close();
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
dialerProc.cancel()
|
||||
listenerProc.kill()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
listenerProc,
|
||||
dialerProc,
|
||||
]).catch((err) => {
|
||||
if (err.signal !== 'SIGTERM') {
|
||||
throw err
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = test
|
59
package.json
59
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "libp2p",
|
||||
"version": "0.30.13",
|
||||
"version": "0.30.6",
|
||||
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
|
||||
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||
"main": "src/index.js",
|
||||
@@ -63,7 +63,6 @@
|
||||
"class-is": "^1.1.0",
|
||||
"debug": "^4.3.1",
|
||||
"err-code": "^2.0.0",
|
||||
"es6-promisify": "^6.1.1",
|
||||
"events": "^3.2.0",
|
||||
"hashlru": "^2.3.0",
|
||||
"interface-datastore": "^3.0.3",
|
||||
@@ -98,19 +97,18 @@
|
||||
"p-settle": "^4.0.1",
|
||||
"peer-id": "^0.14.2",
|
||||
"private-ip": "^2.0.0",
|
||||
"promisify-es6": "^1.0.3",
|
||||
"protons": "^2.0.0",
|
||||
"retimer": "^2.0.0",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"set-delayed-interval": "^1.0.0",
|
||||
"streaming-iterables": "^5.0.2",
|
||||
"timeout-abort-controller": "^1.1.1",
|
||||
"uint8arrays": "^2.1.3",
|
||||
"varint": "^6.0.0",
|
||||
"xsalsa20": "^1.0.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nodeutils/defaults-deep": "^1.1.0",
|
||||
"@types/es6-promisify": "^6.0.0",
|
||||
"abortable-iterator": "^3.0.0",
|
||||
"aegir": "^29.2.0",
|
||||
"chai-bytes": "^0.1.2",
|
||||
@@ -158,60 +156,43 @@
|
||||
"Hugo Dias <mail@hugodias.me>",
|
||||
"Volker Mische <volker.mische@gmail.com>",
|
||||
"dirkmc <dirkmdev@gmail.com>",
|
||||
"Chris Dostert <chrisdostert@users.noreply.github.com>",
|
||||
"Richard Littauer <richard.littauer@gmail.com>",
|
||||
"a1300 <matthias-knopp@gmx.net>",
|
||||
"Elven <mon.samuel@qq.com>",
|
||||
"Andrew Nesbitt <andrewnez@gmail.com>",
|
||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
"Ryan Bell <ryan@piing.net>",
|
||||
"Thomas Eizinger <thomas@eizinger.io>",
|
||||
"Andrew Nesbitt <andrewnez@gmail.com>",
|
||||
"Elven <mon.samuel@qq.com>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
"Samlior <samlior@foxmail.com>",
|
||||
"acolytec3 <17355484+acolytec3@users.noreply.github.com>",
|
||||
"Thomas Eizinger <thomas@eizinger.io>",
|
||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
||||
"Didrik Nordström <didrik@betamos.se>",
|
||||
"John Rees <johnrees@users.noreply.github.com>",
|
||||
"João Santos <joaosantos15@users.noreply.github.com>",
|
||||
"Irakli Gozalishvili <rfobic@gmail.com>",
|
||||
"Joel Gustafson <joelg@mit.edu>",
|
||||
"Julien Bouquillon <contact@revolunet.com>",
|
||||
"Kevin Kwok <antimatter15@gmail.com>",
|
||||
"Kevin Lacker <lacker@gmail.com>",
|
||||
"Lars Gierth <lgierth@users.noreply.github.com>",
|
||||
"Marcin Tojek <mtojek@users.noreply.github.com>",
|
||||
"Michael Burns <5170+mburns@users.noreply.github.com>",
|
||||
"Miguel Mota <miguelmota2@gmail.com>",
|
||||
"Ethan Lam <elmemphis2000@gmail.com>",
|
||||
"Nuno Nogueira <nunofmn@gmail.com>",
|
||||
"Philipp Muens <raute1337@gmx.de>",
|
||||
"Dmitriy Ryajov <dryajov@gmail.com>",
|
||||
"RasmusErik Voel Jensen <github@solsort.com>",
|
||||
"Aditya Bose <13054902+adbose@users.noreply.github.com>",
|
||||
"Diogo Silva <fsdiogo@gmail.com>",
|
||||
"Smite Chow <xiaopengyou@live.com>",
|
||||
"Soeren <nikorpoulsen@gmail.com>",
|
||||
"Sönke Hahn <soenkehahn@gmail.com>",
|
||||
"TJKoury <TJKoury@gmail.com>",
|
||||
"Tiago Alves <alvesjtiago@gmail.com>",
|
||||
"Daijiro Wachi <daijiro.wachi@gmail.com>",
|
||||
"Cindy Wu <ciindy.wu@gmail.com>",
|
||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||
"Yusef Napora <yusef@napora.org>",
|
||||
"Zane Starr <zcstarr@gmail.com>",
|
||||
"Bernd Strehl <bernd.strehl@gmail.com>",
|
||||
"ebinks <elizabethjbinks@gmail.com>",
|
||||
"Ethan Lam <elmemphis2000@gmail.com>",
|
||||
"isan_rivkin <isanrivkin@gmail.com>",
|
||||
"mayerwin <mayerwin@users.noreply.github.com>",
|
||||
"phillmac <phillmac@users.noreply.github.com>",
|
||||
"robertkiel <robert.kiel@validitylabs.org>",
|
||||
"shresthagrawal <34920931+shresthagrawal@users.noreply.github.com>",
|
||||
"swedneck <40505480+swedneck@users.noreply.github.com>",
|
||||
"Aleksei <vozhdb@gmail.com>",
|
||||
"Fei Liu <liu.feiwood@gmail.com>",
|
||||
"Felipe Martins <felipebrasil93@gmail.com>",
|
||||
"Florian-Merle <florian.david.merle@gmail.com>",
|
||||
"Cindy Wu <ciindy.wu@gmail.com>",
|
||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||
"ebinks <elizabethjbinks@gmail.com>",
|
||||
"Francis Gulotta <wizard@roborooter.com>",
|
||||
"Dmitriy Ryajov <dryajov@gmail.com>",
|
||||
"Guy Sviry <32539816+guysv@users.noreply.github.com>",
|
||||
"Florian-Merle <florian.david.merle@gmail.com>",
|
||||
"Bernd Strehl <bernd.strehl@gmail.com>",
|
||||
"Henrique Dias <hacdias@gmail.com>",
|
||||
"Irakli Gozalishvili <rfobic@gmail.com>",
|
||||
"Diogo Silva <fsdiogo@gmail.com>",
|
||||
"Joel Gustafson <joelg@mit.edu>"
|
||||
"isan_rivkin <isanrivkin@gmail.com>",
|
||||
"Felipe Martins <felipebrasil93@gmail.com>",
|
||||
"Fei Liu <liu.feiwood@gmail.com>"
|
||||
]
|
||||
}
|
||||
|
@@ -31,14 +31,18 @@ class AddressManager extends EventEmitter {
|
||||
* @param {object} [options]
|
||||
* @param {Array<string>} [options.listen = []] - list of multiaddrs string representation to listen.
|
||||
* @param {Array<string>} [options.announce = []] - list of multiaddrs string representation to announce.
|
||||
* @param {object} [options.observedAddresses = { minConfidence: 4, maxLifetimeBeforeEviction: 600000 }] - configuration options for observed addresses
|
||||
*/
|
||||
constructor (peerId, { listen = [], announce = [] } = {}) {
|
||||
constructor (peerId, { listen = [], announce = [], observedAddresses = { minConfidence: 4, maxLifetimeBeforeEviction: (60 * 10) * 1000 } } = {}) {
|
||||
super()
|
||||
|
||||
this.peerId = peerId
|
||||
this.listen = new Set(listen.map(ma => ma.toString()))
|
||||
this.announce = new Set(announce.map(ma => ma.toString()))
|
||||
this.observed = new Set()
|
||||
this.observed = new Map()
|
||||
this.config = {
|
||||
observedAddresses
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,15 +69,25 @@ class AddressManager extends EventEmitter {
|
||||
* @returns {Array<Multiaddr>}
|
||||
*/
|
||||
getObservedAddrs () {
|
||||
return Array.from(this.observed).map((a) => multiaddr(a))
|
||||
const output = []
|
||||
|
||||
this.observed.forEach(({ confidence }, addr) => {
|
||||
if (confidence >= this.config.observedAddresses.minConfidence) {
|
||||
output.push(multiaddr(addr))
|
||||
}
|
||||
})
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
/**
|
||||
* Add peer observed addresses
|
||||
*
|
||||
* @param {string | Multiaddr} addr
|
||||
* @param {PeerId} reporter
|
||||
* @param {number} [confidence=1]
|
||||
*/
|
||||
addObservedAddr (addr) {
|
||||
addObservedAddr (addr, reporter, confidence = 1) {
|
||||
let ma = multiaddr(addr)
|
||||
const remotePeer = ma.getPeerId()
|
||||
|
||||
@@ -87,15 +101,41 @@ class AddressManager extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
const now = Date.now()
|
||||
const addrString = ma.toString()
|
||||
|
||||
// do not trigger the change:addresses event if we already know about this address
|
||||
if (this.observed.has(addrString)) {
|
||||
return
|
||||
const wasNewAddr = !this.observed.has(addrString)
|
||||
let addrRecord = {
|
||||
confidence,
|
||||
reporters: [
|
||||
reporter.toB58String()
|
||||
],
|
||||
expires: now + this.config.observedAddresses.maxLifetimeBeforeEviction
|
||||
}
|
||||
|
||||
this.observed.add(addrString)
|
||||
this.emit('change:addresses')
|
||||
// we've seen this address before, increase the confidence we have in it
|
||||
if (!wasNewAddr) {
|
||||
addrRecord = this.observed.get(addrString)
|
||||
|
||||
if (!addrRecord.reporters.includes(reporter.toB58String())) {
|
||||
addrRecord.confidence++
|
||||
addrRecord.reporters.push(reporter.toB58String())
|
||||
addrRecord.expires = now + this.config.observedAddresses.maxLifetimeBeforeEviction
|
||||
}
|
||||
}
|
||||
|
||||
this.observed.set(addrString, addrRecord)
|
||||
|
||||
// only emit event if we've reached the minimum confidence
|
||||
if (addrRecord.confidence === this.config.observedAddresses.minConfidence) {
|
||||
this.emit('change:addresses')
|
||||
}
|
||||
|
||||
// evict addresses older than MAX_LOW_CONFIDENCE_ADDR_LIFETIME_MS we are not confident in
|
||||
this.observed.forEach(({ confidence, expires }, key, map) => {
|
||||
if (confidence < this.config.observedAddresses.minConfidence && expires < now) {
|
||||
map.delete(key)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,12 @@ const DefaultConfig = {
|
||||
announce: [],
|
||||
noAnnounce: []
|
||||
},
|
||||
addressManager: {
|
||||
observedAddresses: {
|
||||
minConfidence: 4,
|
||||
maxLifetimeBeforeEviction: (60 * 10) * 1000
|
||||
}
|
||||
},
|
||||
connectionManager: {
|
||||
minConnections: 25
|
||||
},
|
||||
|
@@ -35,7 +35,7 @@ class ContentRouting {
|
||||
this.dht = libp2p._dht
|
||||
|
||||
// If we have the dht, add it to the available content routers
|
||||
if (this.dht && libp2p._config.dht.enabled) {
|
||||
if (this.dht) {
|
||||
this.routers.push(this.dht)
|
||||
}
|
||||
}
|
||||
|
@@ -202,9 +202,8 @@ class IdentifyService {
|
||||
this.peerStore.protoBook.set(id, protocols)
|
||||
this.peerStore.metadataBook.set(id, 'AgentVersion', uint8ArrayFromString(message.agentVersion))
|
||||
|
||||
// TODO: Add and score our observed addr
|
||||
log('received observed address of %s', observedAddr)
|
||||
// this.addressManager.addObservedAddr(observedAddr)
|
||||
this.addressManager.addObservedAddr(observedAddr, id)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -137,7 +137,10 @@ class Libp2p extends EventEmitter {
|
||||
|
||||
// Addresses {listen, announce, noAnnounce}
|
||||
this.addresses = this._options.addresses
|
||||
this.addressManager = new AddressManager(this.peerId, this._options.addresses)
|
||||
this.addressManager = new AddressManager(this.peerId, {
|
||||
...this._options.addresses,
|
||||
...this._options.addressManager
|
||||
})
|
||||
|
||||
// when addresses change, update our peer record
|
||||
this.addressManager.on('change:addresses', () => {
|
||||
|
@@ -14,7 +14,7 @@ require('node-forge/lib/sha512')
|
||||
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('interface-datastore').Datastore} Datastore
|
||||
* @typedef {import('interface-datastore/src/types').Datastore} Datastore
|
||||
*/
|
||||
|
||||
const keyPrefix = '/pkcs8/'
|
||||
|
@@ -82,7 +82,7 @@ class Stats extends EventEmitter {
|
||||
/**
|
||||
* Returns a clone of the internal movingAverages
|
||||
*
|
||||
* @returns {Object}
|
||||
* @returns {MovingAverage}
|
||||
*/
|
||||
get movingAverages () {
|
||||
return Object.assign({}, this._movingAverages)
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
const NatAPI = require('@motrix/nat-api')
|
||||
const debug = require('debug')
|
||||
const { promisify } = require('es6-promisify')
|
||||
const promisify = require('promisify-es6')
|
||||
const Multiaddr = require('multiaddr')
|
||||
const log = Object.assign(debug('libp2p:nat'), {
|
||||
error: debug('libp2p:nat:err')
|
||||
@@ -16,11 +16,11 @@ const {
|
||||
codes: { ERR_INVALID_PARAMETERS }
|
||||
} = require('./errors')
|
||||
const isLoopback = require('libp2p-utils/src/multiaddr/is-loopback')
|
||||
const AddressManager = require('./address-manager')
|
||||
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('./transport-manager')} TransportManager
|
||||
* @typedef {import('./address-manager')} AddressManager
|
||||
*/
|
||||
|
||||
function highPort (min = 1024, max = 65535) {
|
||||
@@ -118,11 +118,12 @@ class NatManager {
|
||||
protocol: transport.toUpperCase()
|
||||
})
|
||||
|
||||
// add with high confidence
|
||||
this._addressManager.addObservedAddr(Multiaddr.fromNodeAddress({
|
||||
family: 'IPv4',
|
||||
address: publicIp,
|
||||
port: `${publicPort}`
|
||||
}, transport))
|
||||
}, transport), this._peerId, this._addressManager.config.observedAddresses.minConfidence)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,32 +133,14 @@ class NatManager {
|
||||
}
|
||||
|
||||
const client = new NatAPI(this._options)
|
||||
const map = promisify(client.map, { context: client })
|
||||
const destroy = promisify(client.destroy, { context: client })
|
||||
const externalIp = promisify(client.externalIp, { context: client })
|
||||
|
||||
/** @type {(...any) => any} */
|
||||
const map = promisify(client.map.bind(client))
|
||||
/** @type {(...any) => any} */
|
||||
const destroy = promisify(client.destroy.bind(client))
|
||||
/** @type {(...any) => any} */
|
||||
const externalIp = promisify(client.externalIp.bind(client))
|
||||
|
||||
// these are all network operations so add a retry
|
||||
this._client = {
|
||||
/**
|
||||
* @param {...any} args
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
// these are all network operations so add a retry
|
||||
map: (...args) => retry(() => map(...args), { onFailedAttempt: log.error, unref: true }),
|
||||
|
||||
/**
|
||||
* @param {...any} args
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
destroy: (...args) => retry(() => destroy(...args), { onFailedAttempt: log.error, unref: true }),
|
||||
|
||||
/**
|
||||
* @param {...any} args
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
externalIp: (...args) => retry(() => externalIp(...args), { onFailedAttempt: log.error, unref: true })
|
||||
}
|
||||
|
||||
|
@@ -36,7 +36,7 @@ class PeerRouting {
|
||||
this._routers = libp2p._modules.peerRouting || []
|
||||
|
||||
// If we have the dht, add it to the available peer routers
|
||||
if (libp2p._dht && libp2p._config.dht.enabled) {
|
||||
if (libp2p._dht) {
|
||||
this._routers.push(libp2p._dht)
|
||||
}
|
||||
|
||||
|
@@ -196,7 +196,7 @@ class TransportManager {
|
||||
// listening on remote addresses as they may be offline. We could then potentially
|
||||
// just wait for any (`p-any`) listener to succeed on each transport before returning
|
||||
const isListening = results.find(r => r.isFulfilled === true)
|
||||
if (!isListening && this.faultTolerance !== FAULT_TOLERANCE.NO_FATAL) {
|
||||
if (!isListening) {
|
||||
throw errCode(new Error(`Transport (${key}) could not listen on any available address`), codes.ERR_NO_VALID_ADDRESSES)
|
||||
}
|
||||
}
|
||||
|
@@ -201,7 +201,7 @@ class Upgrader {
|
||||
* @private
|
||||
* @param {object} options
|
||||
* @param {string} options.cryptoProtocol - The crypto protocol that was negotiated
|
||||
* @param {'inbound' | 'outbound'} options.direction - One of ['inbound', 'outbound']
|
||||
* @param {string} options.direction - One of ['inbound', 'outbound']
|
||||
* @param {MultiaddrConnection} options.maConn - The transport layer connection
|
||||
* @param {MuxedStream | MultiaddrConnection} options.upgradedConn - A duplex connection returned from multiplexer and/or crypto selection
|
||||
* @param {MuxerFactory} [options.Muxer] - The muxer to be used for muxing
|
||||
|
@@ -15,9 +15,11 @@ const announceAddreses = ['/dns4/peer.io']
|
||||
|
||||
describe('Address Manager', () => {
|
||||
let peerId
|
||||
let peerIds
|
||||
|
||||
before(async () => {
|
||||
peerId = await PeerId.createFromJSON(Peers[0])
|
||||
peerIds = await Promise.all(Peers.slice(1).map(peerId => PeerId.createFromJSON(peerId)))
|
||||
})
|
||||
|
||||
it('should not need any addresses', () => {
|
||||
@@ -60,7 +62,7 @@ describe('Address Manager', () => {
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr('/ip4/123.123.123.123/tcp/39201')
|
||||
am.addObservedAddr('/ip4/123.123.123.123/tcp/39201', peerId)
|
||||
|
||||
expect(am.observed).to.have.property('size', 1)
|
||||
})
|
||||
@@ -71,12 +73,12 @@ describe('Address Manager', () => {
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(ma, peerId)
|
||||
am.addObservedAddr(ma, peerId)
|
||||
am.addObservedAddr(ma, peerId)
|
||||
|
||||
expect(am.observed).to.have.property('size', 1)
|
||||
expect(am.observed).to.include(ma)
|
||||
expect(Array.from(am.observed.keys())).to.include(ma)
|
||||
})
|
||||
|
||||
it('should only emit one change:addresses event', () => {
|
||||
@@ -88,11 +90,25 @@ describe('Address Manager', () => {
|
||||
eventCount++
|
||||
})
|
||||
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId.toB58String()}`)
|
||||
am.addObservedAddr(ma, peerIds[0])
|
||||
am.addObservedAddr(ma, peerIds[1])
|
||||
am.addObservedAddr(ma, peerIds[2])
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`, peerIds[3])
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId.toB58String()}`, peerIds[4])
|
||||
|
||||
expect(eventCount).to.equal(1)
|
||||
})
|
||||
|
||||
it('should emit one change:addresses event when specifying confidence', () => {
|
||||
const ma = '/ip4/123.123.123.123/tcp/39201'
|
||||
const am = new AddressManager(peerId)
|
||||
let eventCount = 0
|
||||
|
||||
am.on('change:addresses', () => {
|
||||
eventCount++
|
||||
})
|
||||
|
||||
am.addObservedAddr(ma, peerId, am.config.observedAddresses.minConfidence)
|
||||
|
||||
expect(eventCount).to.equal(1)
|
||||
})
|
||||
@@ -103,11 +119,12 @@ describe('Address Manager', () => {
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`)
|
||||
am.addObservedAddr(ma, peerId)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`, peerId)
|
||||
|
||||
expect(am.observed).to.have.property('size', 1)
|
||||
expect(am.observed).to.include(ma)
|
||||
|
||||
expect(Array.from(am.observed.keys())).to.include(ma)
|
||||
})
|
||||
|
||||
it('should strip our peer address from added observed addresses in difference formats', () => {
|
||||
@@ -116,12 +133,71 @@ describe('Address Manager', () => {
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`) // base32 CID
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId.toB58String()}`) // base58btc
|
||||
am.addObservedAddr(ma, peerId)
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId}`, peerId) // base32 CID
|
||||
am.addObservedAddr(`${ma}/p2p/${peerId.toB58String()}`, peerId) // base58btc
|
||||
|
||||
expect(am.observed).to.have.property('size', 1)
|
||||
expect(am.observed).to.include(ma)
|
||||
|
||||
expect(Array.from(am.observed.keys())).to.include(ma)
|
||||
})
|
||||
|
||||
it('should require a number of confirmations before believing address', () => {
|
||||
const ma = '/ip4/123.123.123.123/tcp/39201'
|
||||
const am = new AddressManager(peerId)
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma, peerId)
|
||||
|
||||
expect(am.getObservedAddrs().map(ma => ma.toString())).to.not.include(ma)
|
||||
|
||||
for (let i = 0; i < am.config.observedAddresses.minConfidence; i++) {
|
||||
am.addObservedAddr(ma, peerIds[i])
|
||||
}
|
||||
|
||||
expect(am.getObservedAddrs().map(ma => ma.toString())).to.include(ma)
|
||||
})
|
||||
|
||||
it('should require a number of confirmations from different peers', () => {
|
||||
const ma = '/ip4/123.123.123.123/tcp/39201'
|
||||
const am = new AddressManager(peerId)
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma, peerId)
|
||||
|
||||
expect(am.getObservedAddrs().map(ma => ma.toString())).to.not.include(ma)
|
||||
|
||||
for (let i = 0; i < am.config.observedAddresses.minConfidence; i++) {
|
||||
am.addObservedAddr(ma, peerIds[0])
|
||||
}
|
||||
|
||||
expect(am.getObservedAddrs().map(ma => ma.toString())).to.not.include(ma)
|
||||
})
|
||||
|
||||
it('should evict addresses that do not receive enough confirmations within the timeout', () => {
|
||||
const ma1 = '/ip4/123.123.123.123/tcp/39201'
|
||||
const ma2 = '/ip4/124.124.124.124/tcp/39202'
|
||||
const am = new AddressManager(peerId)
|
||||
|
||||
expect(am.observed).to.be.empty()
|
||||
|
||||
am.addObservedAddr(ma1, peerId)
|
||||
|
||||
const observedAddrs = Array.from(am.observed.values())
|
||||
|
||||
expect(Array.from(am.observed.keys())).to.include(ma1)
|
||||
|
||||
// make expiry date a while ago
|
||||
observedAddrs[0].expires = Date.now() - 1000
|
||||
|
||||
// will evict any old multiaddrs
|
||||
am.addObservedAddr(ma2, peerId)
|
||||
|
||||
// should have been evicted
|
||||
expect(Array.from(am.observed.keys())).to.not.include(ma1)
|
||||
expect(Array.from(am.observed.keys())).to.include(ma2)
|
||||
})
|
||||
})
|
||||
|
||||
|
@@ -164,7 +164,7 @@ describe('libp2p.multiaddrs', () => {
|
||||
|
||||
expect(libp2p.multiaddrs).to.have.lengthOf(listenAddresses.length)
|
||||
|
||||
libp2p.addressManager.addObservedAddr(ma)
|
||||
libp2p.addressManager.addObservedAddr(ma, libp2p.peerId, libp2p.addressManager.config.observedAddresses.minConfidence)
|
||||
|
||||
expect(libp2p.multiaddrs).to.have.lengthOf(listenAddresses.length + 1)
|
||||
expect(libp2p.multiaddrs.map(ma => ma.toString())).to.include(ma)
|
||||
|
@@ -107,7 +107,9 @@ describe('content-routing', () => {
|
||||
host: '0.0.0.0',
|
||||
protocol: 'http',
|
||||
port: 60197
|
||||
}))
|
||||
}), [
|
||||
multiaddr('/ip4/0.0.0.0/tcp/60197')
|
||||
])
|
||||
|
||||
;[node] = await peerUtils.createPeer({
|
||||
config: mergeOptions(baseOptions, {
|
||||
@@ -129,10 +131,6 @@ describe('content-routing', () => {
|
||||
|
||||
afterEach(() => node.stop())
|
||||
|
||||
it('should only have one router', () => {
|
||||
expect(node.contentRouting.routers).to.have.lengthOf(1)
|
||||
})
|
||||
|
||||
it('should use the delegate router to provide', () => {
|
||||
const deferred = pDefer()
|
||||
|
||||
@@ -255,7 +253,9 @@ describe('content-routing', () => {
|
||||
host: '0.0.0.0',
|
||||
protocol: 'http',
|
||||
port: 60197
|
||||
}))
|
||||
}), [
|
||||
multiaddr('/ip4/0.0.0.0/tcp/60197')
|
||||
])
|
||||
|
||||
;[node] = await peerUtils.createPeer({
|
||||
config: mergeOptions(routingOptions, {
|
||||
|
@@ -37,7 +37,7 @@ describe('Consume peer record', () => {
|
||||
done = resolve
|
||||
})
|
||||
|
||||
libp2p.addressManager.addObservedAddr('/ip4/123.123.123.123/tcp/3983')
|
||||
libp2p.addressManager.addObservedAddr('/ip4/123.123.123.123/tcp/3983', libp2p.peerId, libp2p.addressManager.config.observedAddresses.minConfidence)
|
||||
|
||||
await p
|
||||
|
||||
|
@@ -119,6 +119,7 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
|
||||
await expect(dialer.connectToPeer(unsupportedAddr))
|
||||
.to.eventually.be.rejectedWith(AggregateError)
|
||||
.and.to.have.nested.property('._errors[0].code', ErrorCodes.ERR_TRANSPORT_DIAL_FAILED)
|
||||
})
|
||||
|
||||
it('should be able to connect to a given peer', async () => {
|
||||
@@ -150,6 +151,7 @@ describe('Dialing (direct, WebSockets)', () => {
|
||||
|
||||
await expect(dialer.connectToPeer(peerId))
|
||||
.to.eventually.be.rejectedWith(AggregateError)
|
||||
.and.to.have.nested.property('._errors[0].code', ErrorCodes.ERR_TRANSPORT_DIAL_FAILED)
|
||||
})
|
||||
|
||||
it('should abort dials on queue task timeout', async () => {
|
||||
|
@@ -3,7 +3,6 @@
|
||||
|
||||
const { expect } = require('aegir/utils/chai')
|
||||
const sinon = require('sinon')
|
||||
const { networkInterfaces } = require('os')
|
||||
const AddressManager = require('../../src/address-manager')
|
||||
const TransportManager = require('../../src/transport-manager')
|
||||
const Transport = require('libp2p-tcp')
|
||||
@@ -157,7 +156,7 @@ describe('Nat Manager (TCP)', () => {
|
||||
natManager,
|
||||
addressManager
|
||||
} = await createNatManager([
|
||||
'/ip6/::/tcp/0'
|
||||
'/ip6/::/tcp/5001'
|
||||
])
|
||||
|
||||
let observed = addressManager.getObservedAddrs().map(ma => ma.toString())
|
||||
@@ -174,7 +173,7 @@ describe('Nat Manager (TCP)', () => {
|
||||
natManager,
|
||||
addressManager
|
||||
} = await createNatManager([
|
||||
'/ip6/::1/tcp/0'
|
||||
'/ip6/::1/tcp/5001'
|
||||
])
|
||||
|
||||
let observed = addressManager.getObservedAddrs().map(ma => ma.toString())
|
||||
@@ -208,7 +207,7 @@ describe('Nat Manager (TCP)', () => {
|
||||
natManager,
|
||||
addressManager
|
||||
} = await createNatManager([
|
||||
'/ip4/127.0.0.1/tcp/0'
|
||||
'/ip4/127.0.0.1/tcp/5900'
|
||||
])
|
||||
|
||||
let observed = addressManager.getObservedAddrs().map(ma => ma.toString())
|
||||
@@ -225,7 +224,7 @@ describe('Nat Manager (TCP)', () => {
|
||||
natManager,
|
||||
addressManager
|
||||
} = await createNatManager([
|
||||
'/ip4/0.0.0.0/tcp/0/sctp/0'
|
||||
'/ip4/0.0.0.0/tcp/5900/sctp/49832'
|
||||
])
|
||||
|
||||
let observed = addressManager.getObservedAddrs().map(ma => ma.toString())
|
||||
@@ -242,50 +241,4 @@ describe('Nat Manager (TCP)', () => {
|
||||
new NatManager({ ttl: 5 }) // eslint-disable-line no-new
|
||||
}).to.throw().with.property('code', ERR_INVALID_PARAMETERS)
|
||||
})
|
||||
|
||||
it('shuts the nat api down when stopping', async function () {
|
||||
function findRoutableAddress () {
|
||||
const interfaces = networkInterfaces()
|
||||
|
||||
for (const name of Object.keys(interfaces)) {
|
||||
for (const iface of interfaces[name]) {
|
||||
// Skip over non-IPv4 and internal (i.e. 127.0.0.1) addresses
|
||||
if (iface.family === 'IPv4' && !iface.internal) {
|
||||
return iface.address
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const addr = findRoutableAddress()
|
||||
|
||||
if (!addr) {
|
||||
// skip test if no non-loopback address is found
|
||||
this.skip()
|
||||
}
|
||||
|
||||
const {
|
||||
natManager
|
||||
} = await createNatManager([
|
||||
`/ip4/${addr}/tcp/0`
|
||||
], {
|
||||
// so we don't try to look up the current computer's external address
|
||||
externalIp: '184.12.31.4'
|
||||
})
|
||||
|
||||
// use the actual nat manager client not the stub
|
||||
delete natManager._client
|
||||
|
||||
await natManager._start()
|
||||
|
||||
const client = natManager._client
|
||||
expect(client).to.be.ok()
|
||||
|
||||
// ensure the client was stopped
|
||||
const spy = sinon.spy(client, 'destroy')
|
||||
|
||||
await natManager.stop()
|
||||
|
||||
expect(spy.called).to.be.true()
|
||||
})
|
||||
})
|
||||
|
@@ -132,10 +132,6 @@ describe('peer-routing', () => {
|
||||
|
||||
afterEach(() => node.stop())
|
||||
|
||||
it('should only have one router', () => {
|
||||
expect(node.peerRouting._routers).to.have.lengthOf(1)
|
||||
})
|
||||
|
||||
it('should use the delegate router to find peers', async () => {
|
||||
const deferred = pDefer()
|
||||
const [remotePeerId] = await peerUtils.createPeerId({ fixture: false })
|
||||
|
@@ -209,7 +209,7 @@ describe('libp2p.transportManager (dial only)', () => {
|
||||
throw new Error('it should fail to start if multiaddr fails to listen')
|
||||
})
|
||||
|
||||
it('does not fail to start if provided listen multiaddr are not compatible to configured transports (when supporting dial only mode)', async () => {
|
||||
it('does not fail to start if multiaddr fails to listen when supporting dial only mode', async () => {
|
||||
libp2p = new Libp2p({
|
||||
peerId,
|
||||
addresses: {
|
||||
@@ -226,22 +226,4 @@ describe('libp2p.transportManager (dial only)', () => {
|
||||
|
||||
await libp2p.start()
|
||||
})
|
||||
|
||||
it('does not fail to start if provided listen multiaddr fail to listen on configured transports (when supporting dial only mode)', async () => {
|
||||
libp2p = new Libp2p({
|
||||
peerId,
|
||||
addresses: {
|
||||
listen: [multiaddr('/ip4/127.0.0.1/tcp/12345/p2p/QmWDn2LY8nannvSWJzruUYoLZ4vV83vfCBwd8DipvdgQc3/p2p-circuit')]
|
||||
},
|
||||
transportManager: {
|
||||
faultTolerance: FaultTolerance.NO_FATAL
|
||||
},
|
||||
modules: {
|
||||
transport: [Transport],
|
||||
connEncryption: [Crypto]
|
||||
}
|
||||
})
|
||||
|
||||
await libp2p.start()
|
||||
})
|
||||
})
|
||||
|
Reference in New Issue
Block a user