Compare commits

...

13 Commits

Author SHA1 Message Date
Vasco Santos
f7183e8afd chore: release version v0.31.7 2021-06-14 09:56:53 +02:00
Vasco Santos
b9988adce9 chore: update contributors 2021-06-14 09:56:53 +02:00
Vasco Santos
b291bc06ec fix: dialer leaking resources after stopping (#947)
* fix: dialer leaking resources after stopping

* chore: add error code to test
2021-06-14 09:19:23 +02:00
Vasco Santos
755eb909f2 chore: update gossipsub dep for example 2021-06-13 21:42:36 +02:00
Vasco Santos
afe0f854e8 chore: use node 16 2021-06-13 21:42:36 +02:00
Vasco Santos
50f7f32e53 chore: update branch 2021-06-13 21:42:36 +02:00
Vasco Santos
052aad4e06 chore: use node 15 in ci 2021-06-13 21:42:36 +02:00
Vasco Santos
2c4b567b00 chore: restructure pubsub tests 2021-06-13 21:42:36 +02:00
Alex Potsides
2a6a635f13 chore: remove ipfs-utils dep (#953)
* chore: remove ipfs-utils dep

We only use it for the env detection, so use [wherearewe](https://www.npmjs.com/package/wherearewe)
instead which is that, but pulled out into a tiny module.

The `TextDecoder` class is global everywhere we support so we don't
need to pull it in from `ipfs-utils` and it's been removed from v8
anyway.

* chore: update ipfs-http-client
2021-06-11 10:01:40 +02:00
Franck Royer
cd152f122f chore: add secure websockets example (#930)
* Add Secure WebSockets example

* Make dial accept self-signed cert
2021-06-11 09:45:47 +02:00
mcclure
2959794796 chore: add more details on DHT configuration in CONFIGURATION.md (#951) 2021-06-10 09:06:26 +02:00
Ryan Bell
2068c845cb chore: configuration format fix 2021-06-07 11:50:21 +02:00
Vasco Santos
d8ba284883 fix: chat example with new multiaddr (#946) 2021-05-28 13:46:08 +02:00
28 changed files with 508 additions and 543 deletions

View File

@@ -27,7 +27,7 @@ jobs:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
node: [14]
node: [14, 16]
fail-fast: true
steps:
- uses: actions/checkout@v2

View File

@@ -1,3 +1,13 @@
## [0.31.7](https://github.com/libp2p/js-libp2p/compare/v0.31.6...v0.31.7) (2021-06-14)
### Bug Fixes
* chat example with new multiaddr ([#946](https://github.com/libp2p/js-libp2p/issues/946)) ([d8ba284](https://github.com/libp2p/js-libp2p/commit/d8ba2848833d9fb8a963d1b7c8d27062c6f829da))
* dialer leaking resources after stopping ([#947](https://github.com/libp2p/js-libp2p/issues/947)) ([b291bc0](https://github.com/libp2p/js-libp2p/commit/b291bc06ec13feeb6e010730edfad754a3b2dc1b))
## [0.31.6](https://github.com/libp2p/js-libp2p/compare/v0.31.5...v0.31.6) (2021-05-27)

View File

@@ -282,7 +282,7 @@ const node = await Libp2p.create({
interval: 1000,
enabled: true
},
[Bootstrap.tag:] {
[Bootstrap.tag]: {
list: [ // A list of bootstrap peers to connect to starting up the node
"/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
"/dnsaddr/bootstrap.libp2p.io/ipfs/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
@@ -373,7 +373,7 @@ const node = await Libp2p.create({
config: {
dht: { // The DHT options (and defaults) can be found in its documentation
kBucketSize: 20,
enabled: true,
enabled: true, // This flag is required for DHT to run (disabled by default)
randomWalk: {
enabled: true, // Allows to disable discovery (enabled by default)
interval: 300e3,
@@ -399,13 +399,13 @@ const PeerId = require('peer-id')
// create a peerId
const peerId = await PeerId.create()
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient({
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient.create({
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
protocol: 'https',
port: 443
}))
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient({
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient.create({
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
protocol: 'https',
port: 443

View File

@@ -2,11 +2,11 @@
/* eslint-disable no-console */
const PeerId = require('peer-id')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const createLibp2p = require('./libp2p')
const { stdinToStream, streamToConsole } = require('./stream')
async function run() {
async function run () {
const [idDialer, idListener] = await Promise.all([
PeerId.createFromJSON(require('./peer-id-dialer')),
PeerId.createFromJSON(require('./peer-id-listener'))
@@ -30,7 +30,7 @@ async function run() {
})
// Dial to the remote peer (the "listener")
const listenerMa = multiaddr(`/ip4/127.0.0.1/tcp/10333/p2p/${idListener.toB58String()}`)
const listenerMa = new Multiaddr(`/ip4/127.0.0.1/tcp/10333/p2p/${idListener.toB58String()}`)
const { stream } = await nodeDialer.dialProtocol(listenerMa, '/chat/1.0.0')
console.log('Dialer dialed to listener on protocol: /chat/1.0.0')

View File

@@ -5,7 +5,7 @@ const PeerId = require('peer-id')
const createLibp2p = require('./libp2p.js')
const { stdinToStream, streamToConsole } = require('./stream')
async function run() {
async function run () {
// Create a new libp2p node with the given multi-address
const idListener = await PeerId.createFromJSON(require('./peer-id-listener'))
const nodeListener = await createLibp2p({

View File

@@ -10,12 +10,14 @@
"dependencies": {
"execa": "^2.1.0",
"fs-extra": "^8.1.0",
"libp2p-pubsub-peer-discovery": "^3.0.0",
"libp2p-relay-server": "^0.1.2",
"libp2p-pubsub-peer-discovery": "^4.0.0",
"libp2p-relay-server": "^0.2.0",
"libp2p-gossipsub": "^0.9.1",
"p-defer": "^3.0.0",
"which": "^2.0.1"
},
"devDependencies": {
"https": "^1.0.0",
"playwright": "^1.7.1"
}
}

View File

@@ -8,6 +8,10 @@ We've seen many interesting use cases appear with this, here are some highlights
- [IPFS PubSub (using libp2p-floodsub) for IoT](https://www.youtube.com/watch?v=qLpM5pBDGiE).
- [Real Time distributed Applications](https://www.youtube.com/watch?v=vQrbxyDPSXg)
## 0. Set up the example
Before moving into the examples, you should run `npm install` on the top level `js-libp2p` folder, in order to install all the dependencies needed for this example. In addition, you will need to install the example related dependencies by doing `cd examples && npm install`. Once the install finishes, you should move into the example folder with `cd pubsub`.
## 1. Setting up a simple PubSub network on top of libp2p
For this example, we will use MulticastDNS for automatic Peer Discovery. This example is based the previous examples found in [Discovery Mechanisms](../discovery-mechanisms). You can find the complete version at [1.js](./1.js).

89
examples/transports/4.js Normal file
View File

@@ -0,0 +1,89 @@
/* eslint-disable no-console */
'use strict'
const Libp2p = require('../..')
const TCP = require('libp2p-tcp')
const WebSockets = require('libp2p-websockets')
const { NOISE } = require('libp2p-noise')
const MPLEX = require('libp2p-mplex')
const fs = require('fs');
const https = require('https');
const pipe = require('it-pipe')
const transportKey = WebSockets.prototype[Symbol.toStringTag];
const httpServer = https.createServer({
cert: fs.readFileSync('./test_certs/cert.pem'),
key: fs.readFileSync('./test_certs/key.pem'),
});
const createNode = async (addresses = []) => {
if (!Array.isArray(addresses)) {
addresses = [addresses]
}
const node = await Libp2p.create({
addresses: {
listen: addresses
},
modules: {
transport: [WebSockets],
connEncryption: [NOISE],
streamMuxer: [MPLEX]
},
config: {
peerDiscovery: {
// Disable autoDial as it would fail because we are using a self-signed cert.
// `dialProtocol` does not fail because we pass `rejectUnauthorized: false`.
autoDial: false
},
transport: {
[transportKey]: {
listenerOptions: { server: httpServer },
},
},
}
})
await node.start()
return node
}
function printAddrs(node, number) {
console.log('node %s is listening on:', number)
node.multiaddrs.forEach((ma) => console.log(`${ma.toString()}/p2p/${node.peerId.toB58String()}`))
}
function print ({ stream }) {
pipe(
stream,
async function (source) {
for await (const msg of source) {
console.log(msg.toString())
}
}
)
}
;(async () => {
const [node1, node2] = await Promise.all([
createNode('/ip4/127.0.0.1/tcp/10000/wss'),
createNode([])
])
printAddrs(node1, '1')
printAddrs(node2, '2')
node1.handle('/print', print)
node2.handle('/print', print)
const targetAddr = `${node1.multiaddrs[0]}/p2p/${node1.peerId.toB58String()}`;
// node 2 (Secure WebSockets) dials to node 1 (Secure Websockets)
const { stream } = await node2.dialProtocol(targetAddr, '/print', { websocket: { rejectUnauthorized: false } })
await pipe(
['node 2 dialed to node 1 successfully'],
stream
)
})();

View File

@@ -0,0 +1,33 @@
'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()
process.stdout.write('4.js\n')
const proc = execa('node', [path.join(__dirname, '4.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 2 dialed to node 1 successfully')) {
deferNode1.resolve()
}
})
await Promise.all([
deferNode1.promise,
])
proc.kill()
}
module.exports = test

View File

@@ -3,11 +3,13 @@
const test1 = require('./test-1')
const test2 = require('./test-2')
const test3 = require('./test-3')
const test4 = require('./test-4')
async function test() {
await test1()
await test2()
await test3()
await test4()
}
module.exports = test

View File

@@ -0,0 +1,32 @@
-----BEGIN CERTIFICATE-----
MIIFlzCCA3+gAwIBAgIUMYedwb9L/BtvZ7Lhu71iSKrXsa4wDQYJKoZIhvcNAQEL
BQAwajELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAlZBMREwDwYDVQQHDAhTb21lQ2l0
eTESMBAGA1UECgwJTXlDb21wYW55MRMwEQYDVQQLDApNeURpdmlzaW9uMRIwEAYD
VQQDDAkxMjcuMC4wLjEwHhcNMjEwNDI4MDIzMjA5WhcNMjIwNDI4MDIzMjA5WjBq
MQswCQYDVQQGEwJVUzELMAkGA1UECAwCVkExETAPBgNVBAcMCFNvbWVDaXR5MRIw
EAYDVQQKDAlNeUNvbXBhbnkxEzARBgNVBAsMCk15RGl2aXNpb24xEjAQBgNVBAMM
CTEyNy4wLjAuMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANNhXBu0
GH1Kzl9iaQxCxEnyyAShS5FYScdKxqpYsgJT4poLWLQBZQEFLEqbdillIlTZqMss
jWqkFL2xmjqdcnOKFEZUarntVE2hxFYYQex2Fi8MYwFj+Pvt74d02xPyfzFNFgyX
a1EakoGBwClaf3I7jW7raPudjcf4HnwQ7r/NwiO8FqHFZgLcTnwI8bk+cxDoDAqu
mhqMB5nnerqvKEyR9Fb2PoL+8PwOPJOOKTDVwLMeMJu2WLR8AU2FzOj5SVI2qsu9
Ps5azysD8KQAMcw4y9s6do36SaMQS85fbvXBV7XBqMD34HPBUbFiCoFoaCzK9Zfb
pCXyVJMUNmw5hyq9nbjUt4Kvr/58bU2gjUKSdPf6KhBxFnDZwl+2qqPdVIb/qtwz
HExtJWq3upklXNOg3HoR6vcr1O9ReJHrzLRMEb51WP1aN/qJ2/lRskcZ4A806qwr
W67BvnOg6s3ZtxHN9v3bsyfsvC66w8PEfCnCVxugC7cUW0gtW54AU75T3ukg7X+m
vECr/+qIzNEBIxxCPgefCG/JAdJhQ5SCvoARAVPStUIWDmigDeOt7go5nKbdVIJ4
7bbBFUhHT2mTHu30fHhRqSDcHzwE7Zz6YJIJmKq29UmzUazFnKlLU67MjLJwiDPm
fC3GyOdAWkkZE5hjtkiy+3yWoEHhaJYRI1u3AgMBAAGjNTAzMAsGA1UdDwQEAwIE
MDATBgNVHSUEDDAKBggrBgEFBQcDATAPBgNVHREECDAGhwR/AAABMA0GCSqGSIb3
DQEBCwUAA4ICAQCx/ynu4iCQAK8VId/QQe7GqgOpFgx+6Mce9GQC6ZVEjAPgapsS
Pl+l6+11cFjHKv0+Z/iN2JgkFmNXfwJcfYI0tHbMK+0U9hgKb1eFgiIwCqb4cPOz
wMwusZ95BjIbtcEbL/+pMUpNhmjPz1fOILJZtDVq++lqJCv7t8+SoAmMVYtlcLNg
muuV/UYR3uqvnAJmjgJVWs4otDGrxCYJE48M+9L2Gm05Htpi9WL1bZaQ+fJ85m85
daedLc6R1/ZRTIH6i73sD4rYs0bx1fCJvkbcgXtKMHEkiHuG/MzR7Pa4cJAVKCx9
lRTgrO7Gkllt2+jp4qg0YhdNq89e0DNA5cyB9H4udRgHQOcrlVRiX9OD/Kz+F5m/
fQwMdbnqdg3ar5DSa8Q5g3bdLbNSCcI9sjCLTkNxUC/XTWGdG03RCVIt1qvBvZHk
JaG6xGpbRZ5CN0T9eindd38JBrkPAPfgl6qhwvcqh6uVFYua+7KmF9K+mKarlmMw
6RWaw2j4sMgUyRIS6fR9vDc20SrtoNvKQM1U6+0VYs1nizfkmsqqqRODmERKbKwc
ahKJFubXfr8gz+PipAKFZbxr2EPAyoiNkx+0eM6Eedo55oP2BoGHEfXEoAonyMFM
F/xTbpFtdRYE2hwsZCk86fpbcPTmdCY8txeZ7+4Bme2d9XXsTAxF64usqQ==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,52 @@
-----BEGIN PRIVATE KEY-----
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
xfk6H6FDZv4ao7QSrFR4hlTIz6V9/aqQkdOhsBSQyQKCAQEAzHwz4Qr5xVduGLbY
S6HV/7vHDI6Jf+3lBvqUidWa013w5yls3sZXsSckkgshRoVMszayIbystnXJMNcx
YlEDWn3iIItzHNHMKkzdOvsCETMIlvnkt6UTmK4xY+dSq4jp7Ty0N+qi8fdaCb2q
tyrYTnHHYId6bUHMBY5QZsYAaTNvYNAO96A0UaNyl42q84iTiLkJYg9SsQPad15W
7gU84Jk6rEMYdndQDvEAHpnZ1y0yA2vtySZYsbK0wj34tgTl+0/8izn7JgF4ezNH
6iQ7Z0OuDT763IrmIxBH0ZEi9YnwSYyIsr6iUYjlQIUuPFRnQYQXEdm5Xfw1pZsL
xhYoTwKCAQB9edDe4LX+0z9i4qr0iHV8H/WoyI5UD/Pc217PKkYM3+ewR9SL9D9z
TS78Sl7HgRgEmIu+MR/u5B2ePf7jkvB/oxyPwqAzJeJ72mV3Mevm27G/Ndd8lt5W
FBCGOx7ZeP4/Cv4mvPD979ix2IalDoWMSWJnpQPN+B1jGeCrUYAXQc1k/vU99gLa
8Tuu3WfBpVAsO7hAC9mu6tuLyfKVqiMOVs2aky9xLqiqW/6uIcGu+owrr+gkDDY/
JfBSUfxYKcjtJiHOEbFGrrRe93XsngmaTz/Hv9A/QLVCuJgWEHlt4WHSc+BtAtaV
9avp6VlyVNfe4KEKW7IekrI0cmfMdXkl
-----END PRIVATE KEY-----

View File

@@ -1,6 +1,6 @@
{
"name": "libp2p",
"version": "0.31.6",
"version": "0.31.7",
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"main": "src/index.js",
@@ -79,6 +79,7 @@
},
"dependencies": {
"@motrix/nat-api": "^0.3.1",
"@vascosantos/moving-average": "^1.1.0",
"abort-controller": "^3.0.0",
"aggregate-error": "^3.1.0",
"any-signal": "^2.1.1",
@@ -91,7 +92,6 @@
"events": "^3.3.0",
"hashlru": "^2.3.0",
"interface-datastore": "^4.0.0",
"ipfs-utils": "^7.0.0",
"it-all": "^1.0.4",
"it-buffer": "^0.1.2",
"it-drain": "^1.0.3",
@@ -108,7 +108,6 @@
"libp2p-utils": "^0.3.1",
"mafmt": "^9.0.0",
"merge-options": "^3.0.4",
"@vascosantos/moving-average": "^1.1.0",
"multiaddr": "^9.0.1",
"multicodec": "^3.0.1",
"multihashing-async": "^2.1.2",
@@ -128,6 +127,7 @@
"streaming-iterables": "^5.0.2",
"timeout-abort-controller": "^1.1.1",
"varint": "^6.0.0",
"wherearewe": "^1.0.0",
"xsalsa20": "^1.1.0"
},
"devDependencies": {
@@ -141,7 +141,7 @@
"delay": "^5.0.0",
"interop-libp2p": "^0.4.0",
"into-stream": "^6.0.0",
"ipfs-http-client": "^49.0.4",
"ipfs-http-client": "^50.1.1",
"it-concat": "^1.0.0",
"it-pair": "^1.0.0",
"it-pushable": "^1.4.0",
@@ -157,7 +157,7 @@
"libp2p-noise": "^3.0.0",
"libp2p-tcp": "^0.15.4",
"libp2p-webrtc-star": "^0.22.2",
"libp2p-websockets": "^0.15.6",
"libp2p-websockets": "^0.15.8",
"multihashes": "^4.0.2",
"nock": "^13.0.3",
"p-defer": "^3.0.0",
@@ -179,50 +179,51 @@
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Maciej Krüger <mkg20001@gmail.com>",
"Hugo Dias <mail@hugodias.me>",
"Volker Mische <volker.mische@gmail.com>",
"dirkmc <dirkmdev@gmail.com>",
"Volker Mische <volker.mische@gmail.com>",
"Richard Littauer <richard.littauer@gmail.com>",
"Ryan Bell <ryan@piing.net>",
"a1300 <matthias-knopp@gmx.net>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
"Andrew Nesbitt <andrewnez@gmail.com>",
"Elven <mon.samuel@qq.com>",
"Giovanni T. Parra <fiatjaf@gmail.com>",
"Ryan Bell <ryan@piing.net>",
"Samlior <samlior@foxmail.com>",
"Andrew Nesbitt <andrewnez@gmail.com>",
"Thomas Eizinger <thomas@eizinger.io>",
"Didrik Nordström <didrik@betamos.se>",
"Felipe Martins <felipebrasil93@gmail.com>",
"Fei Liu <liu.feiwood@gmail.com>",
"Joel Gustafson <joelg@mit.edu>",
"Julien Bouquillon <contact@revolunet.com>",
"Kevin Kwok <antimatter15@gmail.com>",
"Kevin Lacker <lacker@gmail.com>",
"Ethan Lam <elmemphis2000@gmail.com>",
"Miguel Mota <miguelmota2@gmail.com>",
"Nuno Nogueira <nunofmn@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Philipp Muens <raute1337@gmx.de>",
"Franck Royer <franck@royer.one>",
"Giovanni T. Parra <fiatjaf@gmail.com>",
"Elven <mon.samuel@qq.com>",
"Didrik Nordström <didrik.nordstrom@gmail.com>",
"RasmusErik Voel Jensen <github@solsort.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"robertkiel <robert.kiel@validitylabs.org>",
"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>",
"Yusef Napora <yusef@napora.org>",
"Zane Starr <zcstarr@gmail.com>",
"Aleksei <vozhdb@gmail.com>",
"Cindy Wu <ciindy.wu@gmail.com>",
"Chris Bratlien <chrisbratlien@gmail.com>",
"ebinks <elizabethjbinks@gmail.com>",
"Bernd Strehl <bernd.strehl@gmail.com>",
"Francis Gulotta <wizard@roborooter.com>",
"Franck Royer <franck@royer.one>",
"Florian-Merle <florian.david.merle@gmail.com>",
"isan_rivkin <isanrivkin@gmail.com>",
"mcclure <andi.m.mcclure@gmail.com>",
"robertkiel <robert.kiel@validitylabs.org>",
"Aleksei <vozhdb@gmail.com>",
"Bernd Strehl <bernd.strehl@gmail.com>",
"Chris Bratlien <chrisbratlien@gmail.com>",
"Cindy Wu <ciindy.wu@gmail.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Ethan Lam <elmemphis2000@gmail.com>",
"Fei Liu <liu.feiwood@gmail.com>",
"Felipe Martins <felipebrasil93@gmail.com>",
"Florian-Merle <florian.david.merle@gmail.com>",
"Francis Gulotta <wizard@roborooter.com>",
"Henrique Dias <hacdias@gmail.com>",
"Irakli Gozalishvili <rfobic@gmail.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>",
"Miguel Mota <miguelmota2@gmail.com>",
"Nuno Nogueira <nunofmn@gmail.com>",
"Philipp Muens <raute1337@gmx.de>"
]
}

View File

@@ -3,8 +3,6 @@
const CID = require('cids')
const multihashing = require('multihashing-async')
const TextEncoder = require('ipfs-utils/src/text-encoder')
/**
* Convert a namespace string into a cid.
*

View File

@@ -97,6 +97,11 @@ class ConnectionManager extends EventEmitter {
this._autoDialTimeout = null
this._checkMetrics = this._checkMetrics.bind(this)
this._autoDial = this._autoDial.bind(this)
this._latencyMonitor = new LatencyMonitor({
latencyCheckIntervalMs: this._options.pollInterval,
dataEmitIntervalMs: this._options.pollInterval
})
}
/**
@@ -117,10 +122,7 @@ class ConnectionManager extends EventEmitter {
}
// latency monitor
this._latencyMonitor = new LatencyMonitor({
latencyCheckIntervalMs: this._options.pollInterval,
dataEmitIntervalMs: this._options.pollInterval
})
this._latencyMonitor.start()
this._onLatencyMeasure = this._onLatencyMeasure.bind(this)
this._latencyMonitor.on('data', this._onLatencyMeasure)
@@ -138,7 +140,9 @@ class ConnectionManager extends EventEmitter {
async stop () {
this._autoDialTimeout && this._autoDialTimeout.clear()
this._timer && this._timer.clear()
this._latencyMonitor && this._latencyMonitor.removeListener('data', this._onLatencyMeasure)
this._latencyMonitor.removeListener('data', this._onLatencyMeasure)
this._latencyMonitor.stop()
this._started = false
await this._close()

View File

@@ -69,49 +69,55 @@ class LatencyMonitor extends EventEmitter {
}
that.asyncTestFn = asyncTestFn // If there is no asyncFn, we measure latency
}
start () {
// If process: use high resolution timer
if (globalThis.process && globalThis.process.hrtime) { // eslint-disable-line no-undef
debug('Using process.hrtime for timing')
that.now = globalThis.process.hrtime // eslint-disable-line no-undef
that.getDeltaMS = (startTime) => {
const hrtime = that.now(startTime)
this.now = globalThis.process.hrtime // eslint-disable-line no-undef
this.getDeltaMS = (startTime) => {
const hrtime = this.now(startTime)
return (hrtime[0] * 1000) + (hrtime[1] / 1000000)
}
// Let's try for a timer that only monotonically increases
} else if (typeof window !== 'undefined' && window.performance && window.performance.now) {
debug('Using performance.now for timing')
that.now = window.performance.now.bind(window.performance)
that.getDeltaMS = (startTime) => Math.round(that.now() - startTime)
this.now = window.performance.now.bind(window.performance)
this.getDeltaMS = (startTime) => Math.round(this.now() - startTime)
} else {
debug('Using Date.now for timing')
that.now = Date.now
that.getDeltaMS = (startTime) => that.now() - startTime
this.now = Date.now
this.getDeltaMS = (startTime) => this.now() - startTime
}
that._latencyData = that._initLatencyData()
this._latencyData = this._initLatencyData()
// We check for isBrowser because of browsers set max rates of timeouts when a page is hidden,
// so we fall back to another library
// See: http://stackoverflow.com/questions/6032429/chrome-timeouts-interval-suspended-in-background-tabs
if (isBrowser()) {
that._visibilityChangeEmitter = new VisibilityChangeEmitter()
this._visibilityChangeEmitter = new VisibilityChangeEmitter()
that._visibilityChangeEmitter.on('visibilityChange', (pageInFocus) => {
this._visibilityChangeEmitter.on('visibilityChange', (pageInFocus) => {
if (pageInFocus) {
that._startTimers()
this._startTimers()
} else {
that._emitSummary()
that._stopTimers()
this._emitSummary()
this._stopTimers()
}
})
}
if (!that._visibilityChangeEmitter || that._visibilityChangeEmitter.isVisible()) {
that._startTimers()
if (!this._visibilityChangeEmitter || this._visibilityChangeEmitter.isVisible()) {
this._startTimers()
}
}
stop () {
this._stopTimers()
}
/**
* Start internal timers
*

View File

@@ -8,6 +8,7 @@ const errCode = require('err-code')
const { Multiaddr } = require('multiaddr')
// @ts-ignore timeout-abourt-controles does not export types
const TimeoutController = require('timeout-abort-controller')
const { AbortError } = require('abortable-iterator')
const { anySignal } = require('any-signal')
const DialRequest = require('./dial-request')
@@ -76,6 +77,7 @@ class Dialer {
this.maxDialsPerPeer = maxDialsPerPeer
this.tokens = [...new Array(maxParallelDials)].map((_, index) => index)
this._pendingDials = new Map()
this._pendingDialTargets = new Map()
for (const [key, value] of Object.entries(resolvers)) {
Multiaddr.resolvers.set(key, value)
@@ -94,6 +96,11 @@ class Dialer {
}
}
this._pendingDials.clear()
for (const pendingTarget of this._pendingDialTargets.values()) {
pendingTarget.reject(new AbortError('Dialer was destroyed'))
}
this._pendingDialTargets.clear()
}
/**
@@ -107,7 +114,7 @@ class Dialer {
* @returns {Promise<Connection>}
*/
async connectToPeer (peer, options = {}) {
const dialTarget = await this._createDialTarget(peer)
const dialTarget = await this._createCancellableDialTarget(peer)
if (!dialTarget.addrs.length) {
throw errCode(new Error('The dial request has no valid addresses'), codes.ERR_NO_VALID_ADDRESSES)
@@ -130,6 +137,31 @@ class Dialer {
}
}
/**
* Connects to a given `peer` by dialing all of its known addresses.
* The dial to the first address that is successfully able to upgrade a connection
* will be used.
*
* @param {PeerId|Multiaddr|string} peer - The peer to dial
* @returns {Promise<DialTarget>}
*/
async _createCancellableDialTarget (peer) {
// Make dial target promise cancellable
const id = `${(parseInt(String(Math.random() * 1e9), 10)).toString() + Date.now()}`
const cancellablePromise = new Promise((resolve, reject) => {
this._pendingDialTargets.set(id, { resolve, reject })
})
const dialTarget = await Promise.race([
this._createDialTarget(peer),
cancellablePromise
])
this._pendingDialTargets.delete(id)
return dialTarget
}
/**
* Creates a DialTarget. The DialTarget is used to create and track
* the DialRequest to a given peer.

View File

@@ -8,7 +8,7 @@ const { Multiaddr } = require('multiaddr')
const log = Object.assign(debug('libp2p:nat'), {
error: debug('libp2p:nat:err')
})
const { isBrowser } = require('ipfs-utils/src/env')
const { isBrowser } = require('wherearewe')
const retry = require('p-retry')
// @ts-ignore private-api does not export types
const isPrivateIp = require('private-ip')

View File

@@ -3,14 +3,13 @@
const { expect } = require('aegir/utils/chai')
const mergeOptions = require('merge-options')
const { Multiaddr } = require('multiaddr')
const pDefer = require('p-defer')
const delay = require('delay')
const { create } = require('../../src')
const { baseOptions, subsystemOptions } = require('./utils')
const { baseOptions, pubsubSubsystemOptions } = require('./utils')
const peerUtils = require('../utils/creators/peer')
const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
describe('Pubsub subsystem is configurable', () => {
let libp2p
@@ -24,18 +23,15 @@ describe('Pubsub subsystem is configurable', () => {
})
it('should exist if the module is provided', async () => {
libp2p = await create(subsystemOptions)
libp2p = await create(pubsubSubsystemOptions)
expect(libp2p.pubsub).to.exist()
})
it('should start and stop by default once libp2p starts', async () => {
const [peerId] = await peerUtils.createPeerId()
const customOptions = mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
}
const customOptions = mergeOptions(pubsubSubsystemOptions, {
peerId
})
libp2p = await create(customOptions)
@@ -51,11 +47,8 @@ describe('Pubsub subsystem is configurable', () => {
it('should not start if disabled once libp2p starts', async () => {
const [peerId] = await peerUtils.createPeerId()
const customOptions = mergeOptions(subsystemOptions, {
const customOptions = mergeOptions(pubsubSubsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
config: {
pubsub: {
enabled: false
@@ -73,11 +66,8 @@ describe('Pubsub subsystem is configurable', () => {
it('should allow a manual start', async () => {
const [peerId] = await peerUtils.createPeerId()
const customOptions = mergeOptions(subsystemOptions, {
const customOptions = mergeOptions(pubsubSubsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
config: {
pubsub: {
enabled: false
@@ -93,3 +83,47 @@ describe('Pubsub subsystem is configurable', () => {
expect(libp2p.pubsub.started).to.equal(true)
})
})
describe('Pubsub subscription handlers adapter', () => {
let libp2p
beforeEach(async () => {
const [peerId] = await peerUtils.createPeerId()
libp2p = await create(mergeOptions(pubsubSubsystemOptions, {
peerId
}))
await libp2p.start()
})
afterEach(async () => {
libp2p && await libp2p.stop()
})
it('extends pubsub with subscribe handler', async () => {
let countMessages = 0
const topic = 'topic'
const defer = pDefer()
const handler = () => {
countMessages++
if (countMessages > 1) {
throw new Error('only one message should be received')
}
defer.resolve()
}
await libp2p.pubsub.subscribe(topic, handler)
libp2p.pubsub.emit(topic, 'useless-data')
await defer.promise
await libp2p.pubsub.unsubscribe(topic, handler)
libp2p.pubsub.emit(topic, 'useless-data')
// wait to guarantee that the handler is not called twice
await delay(100)
})
})

View File

@@ -0,0 +1,52 @@
'use strict'
const Pubsub = require('libp2p-interfaces/src/pubsub')
const { NOISE: Crypto } = require('libp2p-noise')
const Muxer = require('libp2p-mplex')
const Transport = require('libp2p-websockets')
const filters = require('libp2p-websockets/src/filters')
const transportKey = Transport.prototype[Symbol.toStringTag]
const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
const relayAddr = MULTIADDRS_WEBSOCKETS[0]
const mergeOptions = require('merge-options')
const baseOptions = {
modules: {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
}
}
module.exports.baseOptions = baseOptions
class MockPubsub extends Pubsub {
constructor (libp2p, options = {}) {
super({
debugName: 'mock-pubsub',
multicodecs: '/mock-pubsub',
libp2p,
...options
})
}
}
const pubsubSubsystemOptions = mergeOptions(baseOptions, {
modules: {
pubsub: MockPubsub
},
addresses: {
listen: [`${relayAddr}/p2p-circuit`]
},
config: {
transport: {
[transportKey]: {
filter: filters.all
}
}
}
})
module.exports.pubsubSubsystemOptions = pubsubSubsystemOptions

View File

@@ -105,7 +105,7 @@ describe('content-routing', () => {
beforeEach(async () => {
const [peerId] = await peerUtils.createPeerId({ fixture: true })
delegate = new DelegatedContentRouter(peerId, ipfsHttpClient({
delegate = new DelegatedContentRouter(peerId, ipfsHttpClient.create({
host: '0.0.0.0',
protocol: 'http',
port: 60197
@@ -253,7 +253,7 @@ describe('content-routing', () => {
beforeEach(async () => {
const [peerId] = await peerUtils.createPeerId({ fixture: true })
delegate = new DelegatedContentRouter(peerId, ipfsHttpClient({
delegate = new DelegatedContentRouter(peerId, ipfsHttpClient.create({
host: '0.0.0.0',
protocol: 'http',
port: 60197

View File

@@ -290,6 +290,34 @@ describe('Dialing (direct, WebSockets)', () => {
}
})
it('should cancel pending dial targets before proceeding', async () => {
const dialer = new Dialer({
transportManager: localTM,
peerStore: {
addressBook: {
set: () => { }
}
}
})
sinon.stub(dialer, '_createDialTarget').callsFake(() => {
const deferredDial = pDefer()
return deferredDial.promise
})
// Perform dial
const dialPromise = dialer.connectToPeer(peerId)
// Let the call stack run
await delay(0)
dialer.destroy()
await expect(dialPromise)
.to.eventually.be.rejected()
.and.to.have.property('code', 'ABORT_ERR')
})
describe('libp2p.dialer', () => {
const transportKey = Transport.prototype[Symbol.toStringTag]
let libp2p
@@ -462,6 +490,42 @@ describe('Dialing (direct, WebSockets)', () => {
await libp2p.hangUp(remoteAddr)
})
it('should cancel pending dial targets and stop', async () => {
const [, remotePeerId] = await createPeerId({ number: 2 })
libp2p = new Libp2p({
peerId,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
},
config: {
transport: {
[transportKey]: {
filter: filters.all
}
}
}
})
sinon.stub(libp2p.dialer, '_createDialTarget').callsFake(() => {
const deferredDial = pDefer()
return deferredDial.promise
})
// Perform dial
const dialPromise = libp2p.dial(remotePeerId)
// Let the call stack run
await delay(0)
await libp2p.stop()
await expect(dialPromise)
.to.eventually.be.rejected()
.and.to.have.property('code', 'ABORT_ERR')
})
it('should abort pending dials on stop', async () => {
libp2p = new Libp2p({
peerId,

View File

@@ -113,7 +113,7 @@ describe('peer-routing', () => {
let delegate
beforeEach(async () => {
delegate = new DelegatedPeerRouter(ipfsHttpClient({
delegate = new DelegatedPeerRouter(ipfsHttpClient.create({
host: '0.0.0.0',
protocol: 'http',
port: 60197
@@ -288,7 +288,7 @@ describe('peer-routing', () => {
let delegate
beforeEach(async () => {
delegate = new DelegatedPeerRouter(ipfsHttpClient({
delegate = new DelegatedPeerRouter(ipfsHttpClient.create({
host: '0.0.0.0',
protocol: 'http',
port: 60197

View File

@@ -1,95 +0,0 @@
'use strict'
/* eslint-env mocha */
const { expect } = require('aegir/utils/chai')
const pWaitFor = require('p-wait-for')
const pDefer = require('p-defer')
const mergeOptions = require('merge-options')
const Floodsub = require('libp2p-floodsub')
const Gossipsub = require('libp2p-gossipsub')
const { multicodec: floodsubMulticodec } = require('libp2p-floodsub')
const { multicodec: gossipsubMulticodec } = require('libp2p-gossipsub')
const uint8ArrayToString = require('uint8arrays/to-string')
const { Multiaddr } = require('multiaddr')
const { create } = require('../../src')
const { baseOptions } = require('./utils')
const peerUtils = require('../utils/creators/peer')
const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
const remoteListenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
describe('Pubsub subsystem is able to use different implementations', () => {
let peerId, remotePeerId
let libp2p, remoteLibp2p
beforeEach(async () => {
[peerId, remotePeerId] = await peerUtils.createPeerId({ number: 2 })
})
afterEach(() => Promise.all([
libp2p && libp2p.stop(),
remoteLibp2p && remoteLibp2p.stop()
]))
it('Floodsub nodes', () => {
return pubsubTest(floodsubMulticodec, Floodsub)
})
it('Gossipsub nodes', () => {
return pubsubTest(gossipsubMulticodec, Gossipsub)
})
const pubsubTest = async (multicodec, pubsub) => {
const defer = pDefer()
const topic = 'test-topic'
const data = 'hey!'
libp2p = await create(mergeOptions(baseOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
modules: {
pubsub: pubsub
}
}))
remoteLibp2p = await create(mergeOptions(baseOptions, {
peerId: remotePeerId,
addresses: {
listen: [remoteListenAddr]
},
modules: {
pubsub: pubsub
}
}))
await Promise.all([
libp2p.start(),
remoteLibp2p.start()
])
const libp2pId = libp2p.peerId.toB58String()
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
const connection = await libp2p.dialProtocol(remotePeerId, multicodec)
expect(connection).to.exist()
libp2p.pubsub.subscribe(topic, (msg) => {
expect(uint8ArrayToString(msg.data)).to.equal(data)
defer.resolve()
})
// wait for remoteLibp2p to know about libp2p subscription
await pWaitFor(() => {
const subscribedPeers = remoteLibp2p.pubsub.getSubscribers(topic)
return subscribedPeers.includes(libp2pId)
})
remoteLibp2p.pubsub.publish(topic, data)
await defer.promise
}
})

View File

@@ -1,326 +0,0 @@
'use strict'
/* eslint-env mocha */
const { expect } = require('aegir/utils/chai')
const sinon = require('sinon')
const pWaitFor = require('p-wait-for')
const pDefer = require('p-defer')
const mergeOptions = require('merge-options')
const { Multiaddr } = require('multiaddr')
const uint8ArrayToString = require('uint8arrays/to-string')
const { create } = require('../../src')
const { subsystemOptions, subsystemMulticodecs } = require('./utils')
const peerUtils = require('../utils/creators/peer')
const listenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
const remoteListenAddr = new Multiaddr('/ip4/127.0.0.1/tcp/0')
describe('Pubsub subsystem operates correctly', () => {
let peerId, remotePeerId
let libp2p, remoteLibp2p
beforeEach(async () => {
[peerId, remotePeerId] = await peerUtils.createPeerId({ number: 2 })
})
describe('pubsub started before connect', () => {
beforeEach(async () => {
libp2p = await create(mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
}
}))
remoteLibp2p = await create(mergeOptions(subsystemOptions, {
peerId: remotePeerId,
addresses: {
listen: [remoteListenAddr]
}
}))
await Promise.all([
libp2p.start(),
remoteLibp2p.start()
])
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
})
afterEach(() => Promise.all([
libp2p && libp2p.stop(),
remoteLibp2p && remoteLibp2p.stop()
]))
afterEach(() => {
sinon.restore()
})
it('should get notified of connected peers on dial', async () => {
const connection = await libp2p.dialProtocol(remotePeerId, subsystemMulticodecs)
expect(connection).to.exist()
return Promise.all([
pWaitFor(() => libp2p.pubsub.peers.size === 1),
pWaitFor(() => remoteLibp2p.pubsub.peers.size === 1)
])
})
it('should receive pubsub messages', async () => {
const defer = pDefer()
const topic = 'test-topic'
const data = 'hey!'
const libp2pId = libp2p.peerId.toB58String()
await libp2p.dialProtocol(remotePeerId, subsystemMulticodecs)
let subscribedTopics = libp2p.pubsub.getTopics()
expect(subscribedTopics).to.not.include(topic)
libp2p.pubsub.subscribe(topic, (msg) => {
expect(uint8ArrayToString(msg.data)).to.equal(data)
defer.resolve()
})
subscribedTopics = libp2p.pubsub.getTopics()
expect(subscribedTopics).to.include(topic)
// wait for remoteLibp2p to know about libp2p subscription
await pWaitFor(() => {
const subscribedPeers = remoteLibp2p.pubsub.getSubscribers(topic)
return subscribedPeers.includes(libp2pId)
})
remoteLibp2p.pubsub.publish(topic, data)
await defer.promise
})
})
describe('pubsub started after connect', () => {
beforeEach(async () => {
libp2p = await create(mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
}
}))
remoteLibp2p = await create(mergeOptions(subsystemOptions, {
peerId: remotePeerId,
addresses: {
listen: [remoteListenAddr]
},
config: {
pubsub: {
enabled: false
}
}
}))
await libp2p.start()
await remoteLibp2p.start()
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
})
afterEach(() => Promise.all([
libp2p && libp2p.stop(),
remoteLibp2p && remoteLibp2p.stop()
]))
afterEach(() => {
sinon.restore()
})
it('should get notified of connected peers after starting', async () => {
const connection = await libp2p.dial(remotePeerId)
expect(connection).to.exist()
expect(libp2p.pubsub.peers.size).to.be.eql(0)
expect(remoteLibp2p.pubsub.peers.size).to.be.eql(0)
remoteLibp2p.pubsub.start()
return Promise.all([
pWaitFor(() => libp2p.pubsub.peers.size === 1),
pWaitFor(() => remoteLibp2p.pubsub.peers.size === 1)
])
})
it('should receive pubsub messages', async function () {
this.timeout(10e3)
const defer = pDefer()
const libp2pId = libp2p.peerId.toB58String()
const topic = 'test-topic'
const data = 'hey!'
await libp2p.dial(remotePeerId)
remoteLibp2p.pubsub.start()
await Promise.all([
pWaitFor(() => libp2p.pubsub.peers.size === 1),
pWaitFor(() => remoteLibp2p.pubsub.peers.size === 1)
])
let subscribedTopics = libp2p.pubsub.getTopics()
expect(subscribedTopics).to.not.include(topic)
libp2p.pubsub.subscribe(topic, (msg) => {
expect(uint8ArrayToString(msg.data)).to.equal(data)
defer.resolve()
})
subscribedTopics = libp2p.pubsub.getTopics()
expect(subscribedTopics).to.include(topic)
// wait for remoteLibp2p to know about libp2p subscription
await pWaitFor(() => {
const subscribedPeers = remoteLibp2p.pubsub.getSubscribers(topic)
return subscribedPeers.includes(libp2pId)
})
remoteLibp2p.pubsub.publish(topic, data)
await defer.promise
})
})
describe('pubsub with intermittent connections', () => {
beforeEach(async () => {
libp2p = await create(mergeOptions(subsystemOptions, {
peerId,
addresses: {
listen: [listenAddr]
},
config: {
pubsub: {
enabled: true,
emitSelf: false
}
}
}))
remoteLibp2p = await create(mergeOptions(subsystemOptions, {
peerId: remotePeerId,
addresses: {
listen: [remoteListenAddr]
},
config: {
pubsub: {
enabled: true,
emitSelf: false
}
}
}))
await libp2p.start()
await remoteLibp2p.start()
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
})
afterEach(() => Promise.all([
libp2p && libp2p.stop(),
remoteLibp2p && remoteLibp2p.stop()
]))
afterEach(() => {
sinon.restore()
})
it('should receive pubsub messages after a node restart', async () => {
const topic = 'test-topic'
const data = 'hey!'
const libp2pId = libp2p.peerId.toB58String()
let counter = 0
const defer1 = pDefer()
const defer2 = pDefer()
const handler = (msg) => {
expect(uint8ArrayToString(msg.data)).to.equal(data)
counter++
counter === 1 ? defer1.resolve() : defer2.resolve()
}
await libp2p.dial(remotePeerId)
let subscribedTopics = libp2p.pubsub.getTopics()
expect(subscribedTopics).to.not.include(topic)
libp2p.pubsub.subscribe(topic, handler)
subscribedTopics = libp2p.pubsub.getTopics()
expect(subscribedTopics).to.include(topic)
// wait for remoteLibp2p to know about libp2p subscription
await pWaitFor(() => {
const subscribedPeers = remoteLibp2p.pubsub.getSubscribers(topic)
return subscribedPeers.includes(libp2pId)
})
remoteLibp2p.pubsub.publish(topic, data)
await defer1.promise
await remoteLibp2p.stop()
await remoteLibp2p.start()
libp2p.peerStore.addressBook.set(remotePeerId, remoteLibp2p.multiaddrs)
await libp2p.dial(remotePeerId)
// wait for remoteLibp2p to know about libp2p subscription
await pWaitFor(() => {
const subscribedPeers = remoteLibp2p.pubsub.getSubscribers(topic)
return subscribedPeers.includes(libp2pId)
})
remoteLibp2p.pubsub.publish(topic, data)
await defer2.promise
})
it('should handle quick reconnects with a delayed disconnect', async () => {
// Subscribe on both
const handlerSpy = sinon.spy()
const topic = 'reconnect-channel'
await Promise.all([
libp2p.pubsub.subscribe(topic, handlerSpy),
remoteLibp2p.pubsub.subscribe(topic, handlerSpy)
])
// Create two connections to the remote peer
const originalConnection = await libp2p.dialer.connectToPeer(remoteLibp2p.peerId)
// second connection
await libp2p.dialer.connectToPeer(remoteLibp2p.peerId)
expect(libp2p.connections.get(remoteLibp2p.peerId.toB58String())).to.have.length(2)
// Wait for subscriptions to occur
await pWaitFor(() => {
return libp2p.pubsub.getSubscribers(topic).includes(remoteLibp2p.peerId.toB58String()) &&
remoteLibp2p.pubsub.getSubscribers(topic).includes(libp2p.peerId.toB58String())
})
// Verify messages go both ways
libp2p.pubsub.publish(topic, 'message1')
remoteLibp2p.pubsub.publish(topic, 'message2')
await pWaitFor(() => handlerSpy.callCount === 2)
expect(handlerSpy.args.map(([message]) => uint8ArrayToString(message.data))).to.include.members(['message1', 'message2'])
// Disconnect the first connection (this acts as a delayed reconnect)
const libp2pConnUpdateSpy = sinon.spy(libp2p.connectionManager.connections, 'set')
const remoteLibp2pConnUpdateSpy = sinon.spy(remoteLibp2p.connectionManager.connections, 'set')
await originalConnection.close()
await pWaitFor(() => libp2pConnUpdateSpy.callCount === 1 && remoteLibp2pConnUpdateSpy.callCount === 1)
// Verify messages go both ways after the disconnect
handlerSpy.resetHistory()
libp2p.pubsub.publish(topic, 'message3')
remoteLibp2p.pubsub.publish(topic, 'message4')
await pWaitFor(() => handlerSpy.callCount === 2)
expect(handlerSpy.args.map(([message]) => uint8ArrayToString(message.data))).to.include.members(['message3', 'message4'])
})
})
})

View File

@@ -1,29 +0,0 @@
'use strict'
const Gossipsub = require('libp2p-gossipsub')
const { multicodec } = require('libp2p-gossipsub')
const Crypto = require('../../src/insecure/plaintext')
const Muxer = require('libp2p-mplex')
const Transport = require('libp2p-tcp')
const mergeOptions = require('merge-options')
const baseOptions = {
modules: {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
}
}
module.exports.baseOptions = baseOptions
const subsystemOptions = mergeOptions(baseOptions, {
modules: {
pubsub: Gossipsub
}
})
module.exports.subsystemOptions = subsystemOptions
module.exports.subsystemMulticodecs = [multicodec]

View File

@@ -515,7 +515,7 @@ describe('auto-relay', () => {
// Create 2 nodes, and turn HOP on for the relay
;[local, remote, relayLibp2p] = peerIds.map((peerId, index) => {
const delegate = new DelegatedContentRouter(peerId, ipfsHttpClient({
const delegate = new DelegatedContentRouter(peerId, ipfsHttpClient.create({
host: '0.0.0.0',
protocol: 'http',
port: 60197

View File

@@ -35,13 +35,13 @@ async function main() {
// create a peerId
const peerId = await PeerId.create()
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient({
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient.create({
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
protocol: 'https',
port: 443
}))
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient({
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient.create({
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
protocol: 'https',
port: 443