Compare commits

..

151 Commits

Author SHA1 Message Date
Jacob Heun
6bfd2c7c46 fix: wrap newStream errors to improve debuggability 2020-06-05 13:53:36 +02:00
Jacob Heun
aadeb73c94 chore: release version v0.27.8 2020-05-06 13:21:55 +02:00
Jacob Heun
ea6b1ecce4 chore: update contributors 2020-05-06 13:21:54 +02:00
Vasco Santos
d3ab238738 chore: update aegir 2020-05-05 20:08:45 +02:00
Vasco Santos
97455957ac chore: remove wrtc devdep (#624) 2020-04-30 12:00:50 +02:00
David Dias
5255d87d0a docs: remove Tech Lead from README (#623) 2020-04-30 11:51:21 +02:00
dependabot-preview[bot]
03ce7c3103 chore(deps-dev): bump p-times from 2.1.0 to 3.0.0 (#620)
Bumps [p-times](https://github.com/sindresorhus/p-times) from 2.1.0 to 3.0.0.
- [Release notes](https://github.com/sindresorhus/p-times/releases)
- [Commits](https://github.com/sindresorhus/p-times/compare/v2.1.0...v3.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-04-28 13:16:41 +02:00
Didrik Nordström
ea0621b2f6 fix: reset discovery services upon stop (#618) 2020-04-27 12:07:30 +02:00
Jacob Heun
9197df309b chore: release version v0.27.7 2020-04-24 17:38:32 +02:00
Jacob Heun
8dd361338b chore: update contributors 2020-04-24 17:38:32 +02:00
Hugo Dias
9b13fe321a fix: remove node global (#587)
* fix: use new libp2p-crypto

* fix: remove node globals and reduce size

- adds buffer require
- adds globalThis where needed
- streaming-iterables was remove and new utils created, this will be consolidated in `ipfs-utils` and backported here to normalize all these iterator helper functions
- latency-monitor was copied inside the repo
- iso-random-stream is now used instead of node crypto
- the test `should ignore self on discovery` was moved to node only

Size: 172.97KB
47.03KB below the 220KB limit.

`aegir build --node false` and `aegir test -t browser --node false` now work 🎉

* fix: fix require path

* fix: feedback

* fix: update deps and bundle size

* chore: bump interfaces

* chore: update size
2020-04-24 17:10:40 +02:00
Jacob Heun
1f85e0213a chore: release version v0.27.6 2020-04-16 16:35:01 +02:00
Jacob Heun
09a604b5e5 chore: update contributors 2020-04-16 16:35:01 +02:00
Jacob Heun
ed16b69057 chore: update delegate routing deps to fix branches (#609)
* chore: update delegate routing deps to fix branches

* chore: bump delegate router versions
2020-04-16 15:48:13 +02:00
robertkiel
c940f2d384 fix: add null check in libp2p.hangUp()
test: add hangup test and fix linting
2020-04-15 14:49:47 +02:00
Vasco Santos
2620d46f01 chore: remove spdy from package table (#607) 2020-04-14 12:40:03 +02:00
Jacob Heun
e192eb6508 fix: make circuit relay listening addresses more forgiving (#604)
* test: dont be strict on nock mocking

* fix: be more forgiving with circuit listening addresses
2020-04-14 12:37:52 +02:00
Vasco Santos
b57de4ed0c chore: add discv5 peer-discovery module (#606) 2020-04-14 10:51:29 +02:00
Jacob Heun
760d8b4c3a chore: release version v0.27.5 2020-04-06 13:33:08 +02:00
Jacob Heun
7b56f559cb chore: update contributors 2020-04-06 13:33:08 +02:00
Jacob Heun
0fd5188176 test: dont use mdns in browser tests (#602)
* test(fix): dont use mdns in browser tests

* refactor: use async await consistently for _setupPeerDiscovery
2020-04-06 13:22:12 +02:00
Cayman
bd7fd0f755 fix: await peer discovery start in libp2p start (#600) 2020-04-06 12:32:12 +02:00
Jacob Heun
da83721d6d chore: release version v0.27.4 2020-03-31 13:47:41 +02:00
Jacob Heun
1414e45969 chore: update contributors 2020-03-31 13:47:41 +02:00
Jacob Heun
9e35fbc316 fix: pass libp2p to discovery services (#597)
* fix: include libp2p in the options passed to discovery creation

* fix: handle multiple peer addresses in get multiaddrs for peers

* test(peer-store): add test to verify returned relay multiaddrs
2020-03-31 13:43:27 +02:00
Jacob Heun
30728753cf fix: only use a single export (#596) 2020-03-31 13:01:06 +02:00
dependabot-preview[bot]
afdbe3deac chore(deps-dev): bump cids from 0.7.5 to 0.8.0 (#594)
Bumps [cids](https://github.com/multiformats/js-cid) from 0.7.5 to 0.8.0.
- [Release notes](https://github.com/multiformats/js-cid/releases)
- [Changelog](https://github.com/multiformats/js-cid/blob/master/CHANGELOG.md)
- [Commits](https://github.com/multiformats/js-cid/compare/v0.7.5...v0.8.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>

Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com>
2020-03-26 09:08:13 +01:00
Vasco Santos
ce58805e90 chore(deps): bump p-settle from 3.1.0 to 4.0.0 (#581)
Bumps [p-settle](https://github.com/sindresorhus/p-settle) from 3.1.0 to 4.0.0.
- [Release notes](https://github.com/sindresorhus/p-settle/releases)
- [Commits](https://github.com/sindresorhus/p-settle/compare/v3.1.0...v4.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-05 18:12:58 +01:00
Vasco Santos
b5303fd788 chore: add outdated notice on wip delegated-routing-example (#580) 2020-03-05 18:05:57 +01:00
David Dias
aa78d2ef15 Update README.md 2020-03-05 11:16:34 +01:00
Vasco Santos
5a4641980d chore: remove websocket star from package table (#565)
* chore: remove websocket star from package table

* chore: update package-table

* chore: remove not active modules

* chore: use package-table updated with correct ci badge url
2020-03-04 11:24:39 +01:00
Jacob Heun
f4ec35573e fix(test): improve flakey random walk discovery test (#574)
* test: improve stability of dht discovery test

* test: isolate who is random walking
2020-02-28 15:30:43 +01:00
Vasco Santos
524e6f8433 chore: issue template mentioning js-libp2p (#572) 2020-02-26 17:12:44 +01:00
dependabot-preview[bot]
fad9cb22e0 chore(deps): bump p-any from 2.1.0 to 3.0.0 (#570)
Bumps [p-any](https://github.com/sindresorhus/p-any) from 2.1.0 to 3.0.0.
- [Release notes](https://github.com/sindresorhus/p-any/releases)
- [Commits](https://github.com/sindresorhus/p-any/compare/v2.1.0...v3.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-26 11:23:26 +01:00
dependabot-preview[bot]
e1b158fbb9 chore(deps-dev): bump sinon from 8.1.1 to 9.0.0 (#566)
Bumps [sinon](https://github.com/sinonjs/sinon) from 8.1.1 to 9.0.0.
- [Release notes](https://github.com/sinonjs/sinon/releases)
- [Changelog](https://github.com/sinonjs/sinon/blob/master/CHANGELOG.md)
- [Commits](https://github.com/sinonjs/sinon/compare/v8.1.1...v9.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-26 11:10:34 +01:00
dependabot-preview[bot]
1837d6e95e chore(deps-dev): bump aegir from 20.6.1 to 21.3.0 (#567)
Bumps [aegir](https://github.com/ipfs/aegir) from 20.6.1 to 21.3.0.
- [Release notes](https://github.com/ipfs/aegir/releases)
- [Changelog](https://github.com/ipfs/aegir/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ipfs/aegir/compare/v20.6.1...v21.3.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-26 10:58:46 +01:00
Vasco Santos
4bce6aa0b9 chore: use libp2p utils (#559)
* chore: use libp2p utils

* chore: update libp2p-utils
2020-02-18 07:45:26 -05:00
dependabot-preview[bot]
4d11edd62c chore(deps-dev): bump nock from 11.9.1 to 12.0.0
Bumps [nock](https://github.com/nock/nock) from 11.9.1 to 12.0.0.
- [Release notes](https://github.com/nock/nock/releases)
- [Changelog](https://github.com/nock/nock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nock/nock/compare/v11.9.1...v12.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-18 07:44:45 -05:00
Alex Potsides
a8984c6cd3 fix: remove use of assert module (#561)
* fix: remove use of assert module

The polyfill is big, we can simulate it by throwing an Error and it doesn't work under React Native.

* chore: fix linting

* chore: export invalid param code

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-02-14 14:42:23 +01:00
Jacob Heun
0882dcea3b chore: release version v0.27.3 2020-02-11 17:15:59 +01:00
Jacob Heun
b3d8132ea6 chore: update contributors 2020-02-11 17:15:59 +01:00
Jacob Heun
a317a8b011 fix: dont allow multiaddr dials without a peer id (#558)
* fix: require peer ids when dialing multiaddrs

* chore: fix lint

* docs: add more info about multiaddr peer ids
2020-02-11 16:32:40 +01:00
Jacob Heun
8bed8f39ff chore: release version v0.27.2 2020-02-05 17:46:41 +01:00
Jacob Heun
58c0c7c03e chore: update contributors 2020-02-05 17:46:41 +01:00
Jacob Heun
f662fdcf36 fix: ensure identify streams are closed (#551)
* fix: ensure identify streams are closed

* fix: call connection.addStream properly

* chore: simplify stream closure

* test: improve durability of identify push test
2020-02-05 17:35:27 +01:00
Vasco Santos
5608178247 test: add interop tests job in ci (#526)
* chore: interop tests in ci

* chore: address review

* chore: use interop release
2020-02-05 12:01:46 +01:00
dependabot-preview[bot]
dcd58693f5 chore(deps): bump err-code from 1.1.2 to 2.0.0
Bumps [err-code](https://github.com/IndigoUnited/js-err-code) from 1.1.2 to 2.0.0.
- [Release notes](https://github.com/IndigoUnited/js-err-code/releases)
- [Commits](https://github.com/IndigoUnited/js-err-code/compare/1.1.2...v2.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-05 11:59:34 +01:00
dependabot-preview[bot]
8bf05e6db6 chore(deps-dev): bump abortable-iterator from 2.1.0 to 3.0.0
Bumps [abortable-iterator](https://github.com/alanshaw/abortable-iterator) from 2.1.0 to 3.0.0.
- [Release notes](https://github.com/alanshaw/abortable-iterator/releases)
- [Commits](https://github.com/alanshaw/abortable-iterator/compare/v2.1.0...v3.0.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-05 11:58:58 +01:00
dependabot-preview[bot]
0589d53616 chore(deps-dev): bump nock from 10.0.6 to 11.7.2
Bumps [nock](https://github.com/nock/nock) from 10.0.6 to 11.7.2.
- [Release notes](https://github.com/nock/nock/releases)
- [Changelog](https://github.com/nock/nock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nock/nock/compare/v10.0.6...v11.7.2)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-02-05 11:58:38 +01:00
David Dias
eb2528c1d6 docs: fix chat url (#550) 2020-02-05 11:58:04 +01:00
Vasco Santos
141cf90ca0 chore: remove pdd test stories (#546) 2020-02-04 11:52:23 +01:00
Jacob Heun
f4ec459a7b chore: release version v0.27.1 2020-02-03 15:55:46 +01:00
Jacob Heun
56a7842664 chore: update contributors 2020-02-03 15:55:45 +01:00
Alex Potsides
be8fc9daf1 fix: stop stream after first pong received (#545)
When connecting to go-IPFS from a webworker, the stream opened by
the ping protocol is never closed.

The change here uses `take` to only receive one buffer from the
remote node before closing the stream.
2020-02-03 15:50:40 +01:00
Jacob Heun
f39e8f0da9 docs: add migration guide from 0.26 to 0.27 (#543)
* docs: add migration guide from 0.26 to 0.27

* docs(fix): relative links

* chore(docs): apply suggestions from code review

* chore: apply review suggestions

* chore: remove unwanted log
2020-01-30 13:03:15 +01:00
shresthagrawal
ed0c2cb6c1 docs: redirect to the npm docs for latest release (#541)
* docs: redirect to the npm docs for latest release

* Apply suggestions from code review

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

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-01-29 15:53:57 +01:00
Cayman
c6592c5797 docs: fix api link formatting (#542) 2020-01-28 18:55:37 +01:00
Jacob Heun
33cef10721 chore: release version v0.27.0 2020-01-28 13:06:11 +01:00
Jacob Heun
2d6408eb30 chore: update contributors 2020-01-28 13:06:11 +01:00
Jacob Heun
29a96690ad test(fix): fix listening test for ci 2020-01-24 14:40:40 +01:00
Jacob Heun
8b94cd1e2e chore: release version v0.27.0-rc.0 2020-01-24 14:40:40 +01:00
Jacob Heun
b83880765f chore: update contributors 2020-01-24 14:40:40 +01:00
Vasco Santos
560d7084fe refactor: examples-browser (#508)
* refactor: examples-browser

* chore: add information to use signalling server

* chore: apply suggestions from code review

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

* chore: update deps

* docs: refactor libp2p browser example

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

docs(examples): redo the browser readme

* fix: handle edge case of connections closing early

* chore: fix lint

* chore: update example deps and readme

* chore: update webrtc-star

* chore: apply suggestions from code review

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

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

* docs: review getting started (#520)

* doc: initial review of getting started

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

* chore: move multiplexing to basic setup

* chore: add read more cta

* chore: apply suggestions from code review

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

* chore: just configure multiplexer

* chore: apply suggestions from code review

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

* chore: just use websockets and changed dht module introduction

* chore: add reference for events in the API doc

* docs: simplify getting started guide and clean up language

* chore: apply suggestions from code review

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

* docs(fix): address review comments

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
Co-authored-by: Alan Shaw <alan.shaw@protocol.ai>
2020-01-24 14:40:40 +01:00
Jacob Heun
c1038bec92 fix: use toB58String everywhere to be consistent (#537)
* chore: update deps

* fix: consistently use b58 peerid string

The migration to base32 will happen at a later date
2020-01-24 14:40:40 +01:00
Vasco Santos
bb2e56e6c7 fix: registrar should filter the disconnected conn (#532)
* fix: registrar on disconnect only when no connections

* chore: add test
2020-01-24 14:40:40 +01:00
Alan Shaw
4222c49556 fix: stop discoveries (#530)
* fix: stop discoveries

* test: add discovery stop test

* chore: fix lint

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-01-24 14:40:40 +01:00
Jacob Heun
2f2ba420ef chore: release version v0.27.0-pre.2 2020-01-24 14:40:40 +01:00
Jacob Heun
e9d16ba190 chore: update contributors 2020-01-24 14:40:40 +01:00
Vasco Santos
afb552c063 refactor: examples transports (#503)
* refactor: examples-transports

* chore: apply suggestions from code review

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

* chore: address review

* chore: address review

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-01-24 14:40:40 +01:00
Vasco Santos
721151b9fc refactor: examples/pnet (#523)
* refactor: examples/pnet

* chore: rename pnet-ipfs to pnet

* chore: address review
2020-01-24 14:40:40 +01:00
Vasco Santos
efc96c2f19 refactor: examples/discovery-mechanisms (#498)
* refactor: examples-discovery-mechanisms

* chore: apply suggestions from code review

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

* chore: suggestion interval

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

* chore: add peer connected event

Co-authored-by: Jacob Heun <jacobheun@gmail.com>
2020-01-24 14:40:40 +01:00
Alan Shaw
ba4681b312 fix: conn mngr min/max connection values (#528)
Fixes the case when options are passed with `maxConnections` and/or `minConnections` set to `undefined`:

```console
{
  defaultOptions: {
    maxConnections: Infinity,
    minConnections: 0,
    maxData: Infinity,
    maxSentData: Infinity,
    maxReceivedData: Infinity,
    maxEventLoopDelay: Infinity,
    pollInterval: 2000,
    movingAverageInterval: 60000,
    defaultPeerValue: 1
  },
  options: {
    minPeers: 25,
    maxConnections: undefined,
    minConnections: undefined
  }
}
{ maxConnections: undefined, minConnections: undefined }
      1) "before all" hook in "custom config"
(node:67176) UnhandledPromiseRejectionWarning: AssertionError [ERR_ASSERTION]: Connection Manager maxConnections must be greater than minConnections
    at new ConnectionManager (node_modules/libp2p/src/connection-manager/index.js:43:5)
    at new Libp2p (node_modules/libp2p/src/index.js:92:30)
    at Object.module.exports [as libp2p] (src/core/components/libp2p.js:27:10)
    at Proxy.start (src/core/components/start.js:48:31)
    at async Daemon.start (src/cli/daemon.js:63:31)
    at async startHttpAPI (test/http-api/routes.js:29:5)
    at async Context.<anonymous> (test/http-api/routes.js:48:7)
```
2020-01-24 14:40:40 +01:00
Vasco Santos
6b00eeab0a refactor: examples/protocol-and-stream-muxing (#502) 2020-01-24 14:40:40 +01:00
Jacob Heun
c339be10ee feat: allow transport options to be passed on creation (#524)
* feat: allow transport options to be passed on creation

* fix: only add circuit transport if enabled

* chore: fix lint
2020-01-24 14:40:40 +01:00
Vasco Santos
7b326cc525 refactor: examples/peer-and-content-routing (#500)
* refactor: examples-peer-and-content-routing

* chore: address review

* chore: review suggestions

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2020-01-24 14:40:40 +01:00
Vasco Santos
835a689965 refactor: examples/encrypted-communications (#499)
* refactor: examples/encrypted-communications

* chore: address review
2020-01-24 14:40:40 +01:00
Vasco Santos
b08d81cee7 refactor: examples-pubsub (#504) 2020-01-24 14:40:40 +01:00
Jacob Heun
6445fda050 feat: add libp2p.connections getter (#522)
* fix: make hangup accept what the API says it does

* feat: add libp2p.connections getter

* chore: fix typo
2020-01-24 14:40:40 +01:00
Jacob Heun
4ca481b869 fix: make dialer configurable (#521)
docs: update configuration and api docs
2020-01-24 14:40:40 +01:00
Vasco Santos
5d7ee50e76 fix: upgrader should not need muxers (#517)
* fix: upgrader should not need muxers

* chore: address review

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2020-01-24 14:40:40 +01:00
Jacob Heun
48fd64182b chore: release version v0.27.0-pre.1 2020-01-24 14:40:40 +01:00
Jacob Heun
58db09a9d3 chore: update contributors 2020-01-24 14:40:40 +01:00
Jacob Heun
15f7c2a974 feat: coalescing dial support (#518)
* docs: fix spelling in api

* fix: dont create peerstore twice

* feat: add support for dial coalescing

* doc(fix): add setPeerValue to API TOC

* docs: add more jsdocs to dialer

* chore: remove old comment

* fix: ensure connections are closed

* fix: registrar.getConnections returns first open conn

* fix: directly set the closed status

* chore: remove unneeded log

* refactor: peerStore.put takes an options object
2020-01-24 14:40:40 +01:00
Alan Shaw
4384d139d2 docs: add ToC link to pubsub.unsubscribe 2020-01-24 14:40:40 +01:00
Alan Shaw
bd1068e5d9 docs: fix the ToC links (#515) 2020-01-24 14:40:40 +01:00
Vasco Santos
854ac49a10 chore: update readme (#513) 2020-01-24 14:40:40 +01:00
Jacob Heun
f9d0047bf6 chore: release version v0.27.0-pre.0 2020-01-24 14:40:40 +01:00
Jacob Heun
ae5ce9a66f chore: update contributors 2020-01-24 14:40:40 +01:00
Jacob Heun
14a1955a78 refactor: connection manager (#511)
* refactor: initial refactor of the connection manager

* fix: start/stop issues

* fix: add tests and resolve pruning issues

* chore: fix lint

* test: move conn manager tests to node only for now

* chore: apply suggestions from code review

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

* fix: assert min max connection options

* test: fix assertion check for browser

* docs: add api and config docs for conn manager
2020-01-24 14:40:40 +01:00
Vasco Santos
f1eb373235 feat: discovery modules from transports should be added (#510)
* feat: discovery modules from transports should be added

* chore: apply suggestions from code review

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

* chore: address review

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2020-01-24 14:40:40 +01:00
Jacob Heun
dabee00127 refactor: stats (#501)
* docs: add initial notes on stats

* feat: initial refactor of stats to metrics

* feat: add support for placeholder metrics

This is helpful for tracking metrics prior to knowing the remote peers id

* fix: add metrics tests and fix issues

* fix: always clear the dial timeout timer

* docs: add metrics to api doc

* chore: apply suggestions from code review

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

* docs: update metrics docs

* fix: call metrics.onDisconnect

* docs(config): add example headers so they appear in the TOC

* docs(config): add metrics configuration

* docs(relay): fix relay configuration docs
2020-01-24 14:40:40 +01:00
Vasco Santos
17b6a3fd73 docs: config (#495)
* docs: new api

* chore: new iteration

* chore: apply suggestions from code review

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

* chore: apply suggestions from code review

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

* chore: address review

* docs: add events

* chore: apply suggestions from code review

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

* docs: configuration

* chore: apply suggestions from code review

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

* chore: update peer routing description

Co-Authored-By: Yusef Napora <yusef@protocol.ai>

* chore: decouple examples

* chore: address pr comment

* fix: connection encryption is required

* chore: apply review suggestion

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2020-01-24 14:40:40 +01:00
Vasco Santos
4f7586886c refactor: ping (#505)
* refactor: ping

* chore: ping is now a function

* chore: address review
2020-01-24 14:40:40 +01:00
Jacob Heun
71f46bf4a6 chore: it-all over async-iterator-all 2020-01-24 14:40:40 +01:00
Jacob Heun
cba035a75b chore: add bundlesize check back to ci 2020-01-24 14:40:40 +01:00
Jacob Heun
2c5183bd70 chore: remove uneeded dep check exclusions 2020-01-24 14:40:40 +01:00
Jacob Heun
a586efb5f7 chore: disable pull dep check until ping is refactored 2020-01-24 14:40:40 +01:00
Jacob Heun
1db69c5f27 chore: remove unused packages 2020-01-24 14:40:40 +01:00
Jacob Heun
9e1a9f04ae chore: move stats folder and delete old switch code 2020-01-24 14:40:40 +01:00
Vasco Santos
287f1b98e5 docs: new api (#472)
* docs: new api

* chore: new iteration

* chore: apply suggestions from code review

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

* chore: apply suggestions from code review

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

* chore: address review

* docs: add events

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2020-01-24 14:40:40 +01:00
Jacob Heun
90ecc57dbc fix: token release logic 2020-01-24 14:40:40 +01:00
Jacob Heun
ae52d483fc test: bump delay for ci 2020-01-24 14:40:40 +01:00
Jacob Heun
2570a1ba30 fix: release tokens as soon as they are available 2020-01-24 14:40:40 +01:00
Jacob Heun
633b0c291f fix: clean up pending dials abort per feedback 2020-01-24 14:40:40 +01:00
Jacob Heun
7d505494be docs: add DialRequest description 2020-01-24 14:40:40 +01:00
Jacob Heun
1df52ae205 test: remove timeout 2020-01-24 14:40:40 +01:00
Jacob Heun
ba02764c5f feat: abort all pending dials on stop 2020-01-24 14:40:40 +01:00
Jacob Heun
404fa69513 test: reduce randomwalk timeout 2020-01-24 14:40:40 +01:00
Jacob Heun
85988cfaab chore: fix lint
test: reduce interval of randomwalk in test

chore(test): glob fix
2020-01-24 14:40:40 +01:00
Jacob Heun
def3574ba0 test: add tests for DialRequest 2020-01-24 14:40:40 +01:00
Jacob Heun
6b1da8326f test(fix): fix support for it.only, it.skip, etc 2020-01-24 14:40:40 +01:00
Jacob Heun
a12006a4fa docs(release): point to libp2p weekly sync 2020-01-24 14:40:40 +01:00
Jacob Heun
466b4dfd70 chore: update per feedback 2020-01-24 14:40:40 +01:00
Jacob Heun
98e82df5e1 refactor: cleanup and reorganize 2020-01-24 14:40:40 +01:00
Jacob Heun
6ad840c3f3 chore: update docs
fix: protect against duplicate token releases
2020-01-24 14:40:40 +01:00
Jacob Heun
7ac5e42a1a chore: fix linting 2020-01-24 14:40:40 +01:00
Jacob Heun
b86ef64904 refactor: consolidation multiaddr dial methods 2020-01-24 14:40:40 +01:00
Jacob Heun
b6cd48b798 refactor: clean up dial timeout abort 2020-01-24 14:40:40 +01:00
Jacob Heun
a5b54a7017 feat: add early token recycling in 2020-01-24 14:40:40 +01:00
Jacob Heun
e1e3be8106 refactor: simplify DialRequest logic per feedback 2020-01-24 14:40:40 +01:00
Jacob Heun
b7432bd02b chore: use any-signal module 2020-01-24 14:40:40 +01:00
Jacob Heun
7c2fefda46 refactor: PER_PEER_LIMIT is now MAX_PER_PEER_DIALS 2020-01-24 14:40:40 +01:00
Jacob Heun
2788982c53 chore: apply suggestions from code review
Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>
Co-Authored-By: Alan Shaw <alan.shaw@protocol.ai>
2020-01-24 14:40:40 +01:00
Jacob Heun
76ec1ccd21 chore: remove commented code 2020-01-24 14:40:40 +01:00
Jacob Heun
e445a17278 feat: add token based dialer 2020-01-24 14:40:40 +01:00
Jacob Heun
2329ef3ea3 doc: add initial dialer readme 2020-01-24 14:40:40 +01:00
Jacob Heun
ce8e60bb0d fix: correct release readme 2020-01-24 14:40:40 +01:00
Jacob Heun
12fc069873 fix: clean up peer discovery flow (#494)
* fix: clean up peer discovery flow

* test(fix): let libp2p start after connecting

* test(fix): dont auto dial in disco tests
2020-01-24 14:40:40 +01:00
Vasco Santos
9a6e07d70b chore: update pubsub implementations (#493) 2020-01-24 14:40:40 +01:00
Vasco Santos
8da9fc97d4 feat: support peer-id instances in peer store operations (#491) 2020-01-24 14:40:40 +01:00
Vasco Santos
a020db183a refactor: async routing (#489)
* feat: async routing

* chore: put dht extra api commands under content routing

* chore: add default option to createPeerInfo

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

* chore: address review

* chore: rm dlv
2020-01-24 14:40:40 +01:00
Jacob Heun
f77ce39484 refactor: circuit relay to async (#477)
* refactor: add dialing over relay support

* chore: fix lint

* fix: dont clear listeners on close

* fix: if dial errors already have codes, just rethrow them

* fix: clear the registrar when libp2p stops

* fix: improve connection maintenance with circuit

* chore: correct feedback

* test: use chai as promised

* test(fix): reset multiaddrs on dial test
2020-01-24 14:40:40 +01:00
Vasco Santos
18a062ed12 feat: discovery modules (#486)
* feat: discovery modules

* chore: address review
2020-01-24 14:40:40 +01:00
dirkmc
1999606ecc fix: replace peerInfo addresses with listen addresses (#485)
* feat: replace peer info addresses with listen addresses

* test: add listening test

* chore: fix linting
2020-01-24 14:40:40 +01:00
dirkmc
472e14f2b4 refactor(docs): async await version of examples/chat (#482)
* fix: performance bottleneck in stat.js (#463)

Array.shift seems to be very slow, perhaps linear, on some
engines, resulting in  _update consuming a lot of CPU.

* docs(fix): correct docs and example for pnet (#464)

* docs(fix): correct docs and example for pnet

* docs(fix): correct pnet docs

* docs(fix): update README.md language (#468)

* docs: reciprocate (#474)

* docs(example): fix ipfs cat (#475)

`ipfs.files.cat` is incorrect. the correct function is `ipfs.cat`

* fix: async-await example chat

* fix: move handler before start

* fix: examples readme typos (#481)

* fix: simplify libp2p bundle for echo example

* chore: remove unused vars
2020-01-24 14:40:40 +01:00
dirkmc
953d185c39 refactor(docs): async await version of examples/echo (#483)
* fix: performance bottleneck in stat.js (#463)

Array.shift seems to be very slow, perhaps linear, on some
engines, resulting in  _update consuming a lot of CPU.

* docs(fix): correct docs and example for pnet (#464)

* docs(fix): correct docs and example for pnet

* docs(fix): correct pnet docs

* docs(fix): update README.md language (#468)

* docs: reciprocate (#474)

* docs(example): fix ipfs cat (#475)

`ipfs.files.cat` is incorrect. the correct function is `ipfs.cat`

* fix: async await examples/echo

* fix: examples readme typos (#481)

* fix: simplify libp2p bundle for echo example
2020-01-24 14:40:40 +01:00
Vasco Santos
c563e06a60 refactor: dht async/await (#480)
* refactor: core async (#478)

* refactor: cleanup core

test: auto dial on startup

* fix: make hangup work properly

* chore: fix lint

* chore: apply suggestions from code review

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

* fix: provide libp2p dialer to the dht

* chore: use dht release
2020-01-24 14:40:40 +01:00
Jacob Heun
f28b09fc0d refactor: update secio and tests to use it (#484)
* refactor: use async secio

* test: add secio to most test suites

* chore: update secio version
2020-01-24 14:40:40 +01:00
Jacob Heun
2104578924 refactor: core async (#478)
* refactor: cleanup core

test: auto dial on startup

* fix: make hangup work properly

* chore: fix lint

* chore: apply suggestions from code review

Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>
2020-01-24 14:40:40 +01:00
Vasco Santos
bcad60995e chore: use gossipsub release (#479) 2020-01-24 14:40:40 +01:00
Vasco Santos
432b0997ae refactor: pubsub (#467)
* feat: peer-store v0

* chore: apply suggestions from code review

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

* chore: address review

* refactor: pubsub subsystem

* chore: address review

* chore: use topology interface

* chore: address review

* chore: address review

* chore: simplify tests
2020-01-24 14:40:40 +01:00
Jacob Heun
2afdbb71b2 chore: update it-length-prefixed (#476)
fix: decode.fromReader usage
2020-01-24 14:40:40 +01:00
Jacob Heun
c7a54f34f7 refactor: async identify and identify push (#473)
* chore: add missing dep

* feat: import from identify push branch

https://github.com/libp2p/js-libp2p-identify/tree/feat/identify-push

* feat: add the connection to stream handlers

* refactor: identify to async/await

* chore: fix lint

* test: add identify tests

* refactor: add identify to the dialer flow

* feat: connect identify to the registrar

* fix: resolve review feedback

* fix: perform identify push when our protocols change
2020-01-24 14:40:40 +01:00
Vasco Santos
9d52b80c45 feat: registrar (#471)
* feat: peer-store v0

* feat: registrar

* chore: apply suggestions from code review

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

* chore: address review

* chore: support multiple conns

* chore: address review

* fix: no remote peer from topology on disconnect
2020-01-24 14:40:40 +01:00
Vasco Santos
582094a834 feat: peer store (#470)
* feat: peer-store v0

* chore: apply suggestions from code review

Co-Authored-By: Jacob Heun <jacobheun@gmail.com>
2020-01-24 14:40:40 +01:00
Jacob Heun
fe2a8eddbb refactor: crypto and pnet (#469)
* feat: add initial plaintext 2 module

* refactor: initial refactor of pnet

* chore: fix lint

* fix: update plaintext api usage

* test: use plaintext for test crypto

* chore: update deps

test: update dialer suite scope

* feat: add connection protection to the upgrader

* refactor: cleanup and lint fix

* chore: remove unncessary transforms

* chore: temporarily disable bundlesize

* chore: add missing dep

* fix: use it-handshake to prevent overreading

* chore(fix): PR feedback updates

* chore: apply suggestions from code review

Co-Authored-By: Vasco Santos <vasco.santos@moxy.studio>
2020-01-24 14:40:40 +01:00
Jacob Heun
5e1dbc21a2 refactor(async): add dialer and upgrader (#462)
* chore(deps): update connection and multistream

* feat: add basic dial support for addresses and peers

* test: automatically require all node test files

* fix: dont catch and log in the wrong place

* test: add direct spec test

fix: improve dial error consistency

* feat: add dial timeouts and concurrency

Queue timeouts will result in aborts of the dials

* chore: fix linting

* test: verify dialer defaults

* feat: add initial upgrader

* fix: add more test coverage and fix bugs

* feat: libp2p creates the upgrader

* feat: hook up handle to the upgrader

* feat: hook up the dialer to libp2p

test: add node dialer libp2p tests

* feat: add connection listeners to upgrader

* feat: emit connect and disconnect events

* chore: use libp2p-interfaces

* fix: address review feedback

* fix: correct import

* refactor: dedupe connection creation code
2020-01-24 14:40:40 +01:00
Jacob Heun
b37ccc7279 docs: add stream wrapping example (#466)
* docs: add duplex wrapping example

docs: add iterable types from @alanshaw's gist

* docs(fix): add feedback fix

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

* docs: clean up based on feedback
2020-01-24 14:40:40 +01:00
Jacob Heun
440fbf0c04 refactor(async): update transports subsystem (#461)
* test: remove all tests for a clean slate

The refactor will require a large number of updates to the tests. In order
to ensure we have done a decent deduplication, and have a cleaner suite of tests
we've removed all tests. This will also allow us to more easily see tests
for the refactored systems.

We have a record of the latest test suites in master, so we are not losing any history.

* chore: update tcp and websockets
* chore: remove other transports until they are converted
* chore: use mafmt and multiaddr async versions
* chore: add and fix dependencies
* chore: clean up travis file
* feat: add new transport manager
* docs: add constructor jsdocs
* refactor(config): check that transports exist
This also removes the other logic, it can be added when those subsystems are refactored

* chore(deps): use async peer-id and peer-info
* feat: wire up the transport manager with libp2p
* chore: remove superstruct dep
2020-01-24 14:40:40 +01:00
Jacob Heun
0cef51d4c2 Add streaming iterables guide (#459)
* docs: add streaming iterables guide placeholder

* chore: move peer discovery readme to doc fold:wqer

* docs: add link to async refactor issue
2020-01-24 14:40:40 +01:00
93 changed files with 1695 additions and 1190 deletions

View File

@@ -45,7 +45,7 @@ const after = async () => {
}
module.exports = {
bundlesize: { maxSize: '220kB' },
bundlesize: { maxSize: '179kB' },
hooks: {
pre: before,
post: after

1
.gitignore vendored
View File

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

View File

@@ -39,5 +39,12 @@ jobs:
script:
- npx aegir test -t browser -t webworker -- --browsers FirefoxHeadless
- stage: test
name: interop
script:
- cd node_modules/interop-libp2p
- npm install
- LIBP2P_JS=${TRAVIS_BUILD_DIR}/src/index.js npx aegir test -t node --bail
notifications:
email: false

View File

@@ -1,3 +1,137 @@
<a name="0.27.8"></a>
## [0.27.8](https://github.com/libp2p/js-libp2p/compare/v0.27.7...v0.27.8) (2020-05-06)
### Bug Fixes
* reset discovery services upon stop ([#618](https://github.com/libp2p/js-libp2p/issues/618)) ([ea0621b](https://github.com/libp2p/js-libp2p/commit/ea0621b))
<a name="0.27.7"></a>
## [0.27.7](https://github.com/libp2p/js-libp2p/compare/v0.27.6...v0.27.7) (2020-04-24)
### Bug Fixes
* remove node global ([#587](https://github.com/libp2p/js-libp2p/issues/587)) ([9b13fe3](https://github.com/libp2p/js-libp2p/commit/9b13fe3))
<a name="0.27.6"></a>
## [0.27.6](https://github.com/libp2p/js-libp2p/compare/v0.27.5...v0.27.6) (2020-04-16)
### Bug Fixes
* add null check in libp2p.hangUp() ([c940f2d](https://github.com/libp2p/js-libp2p/commit/c940f2d))
* make circuit relay listening addresses more forgiving ([#604](https://github.com/libp2p/js-libp2p/issues/604)) ([e192eb6](https://github.com/libp2p/js-libp2p/commit/e192eb6))
<a name="0.27.5"></a>
## [0.27.5](https://github.com/libp2p/js-libp2p/compare/v0.27.4...v0.27.5) (2020-04-06)
### Bug Fixes
* await peer discovery start in libp2p start ([#600](https://github.com/libp2p/js-libp2p/issues/600)) ([bd7fd0f](https://github.com/libp2p/js-libp2p/commit/bd7fd0f))
<a name="0.27.4"></a>
## [0.27.4](https://github.com/libp2p/js-libp2p/compare/v0.27.3...v0.27.4) (2020-03-31)
### Bug Fixes
* only use a single export ([#596](https://github.com/libp2p/js-libp2p/issues/596)) ([3072875](https://github.com/libp2p/js-libp2p/commit/3072875))
* pass libp2p to discovery services ([#597](https://github.com/libp2p/js-libp2p/issues/597)) ([9e35fbc](https://github.com/libp2p/js-libp2p/commit/9e35fbc))
* **test:** improve flakey random walk discovery test ([#574](https://github.com/libp2p/js-libp2p/issues/574)) ([f4ec355](https://github.com/libp2p/js-libp2p/commit/f4ec355))
* remove use of assert module ([#561](https://github.com/libp2p/js-libp2p/issues/561)) ([a8984c6](https://github.com/libp2p/js-libp2p/commit/a8984c6))
<a name="0.27.3"></a>
## [0.27.3](https://github.com/libp2p/js-libp2p/compare/v0.27.2...v0.27.3) (2020-02-11)
### Bug Fixes
* dont allow multiaddr dials without a peer id ([#558](https://github.com/libp2p/js-libp2p/issues/558)) ([a317a8b](https://github.com/libp2p/js-libp2p/commit/a317a8b))
<a name="0.27.2"></a>
## [0.27.2](https://github.com/libp2p/js-libp2p/compare/v0.27.1...v0.27.2) (2020-02-05)
### Bug Fixes
* ensure identify streams are closed ([#551](https://github.com/libp2p/js-libp2p/issues/551)) ([f662fdc](https://github.com/libp2p/js-libp2p/commit/f662fdc))
<a name="0.27.1"></a>
## [0.27.1](https://github.com/libp2p/js-libp2p/compare/v0.27.0...v0.27.1) (2020-02-03)
### Bug Fixes
* stop stream after first pong received ([#545](https://github.com/libp2p/js-libp2p/issues/545)) ([be8fc9d](https://github.com/libp2p/js-libp2p/commit/be8fc9d))
<a name="0.27.0"></a>
# [0.27.0](https://github.com/libp2p/js-libp2p/compare/v0.26.2...v0.27.0) (2020-01-28)
### Bug Fixes
* clean up peer discovery flow ([#494](https://github.com/libp2p/js-libp2p/issues/494)) ([12fc069](https://github.com/libp2p/js-libp2p/commit/12fc069))
* clean up pending dials abort per feedback ([633b0c2](https://github.com/libp2p/js-libp2p/commit/633b0c2))
* conn mngr min/max connection values ([#528](https://github.com/libp2p/js-libp2p/issues/528)) ([ba4681b](https://github.com/libp2p/js-libp2p/commit/ba4681b))
* correct release readme ([ce8e60b](https://github.com/libp2p/js-libp2p/commit/ce8e60b))
* examples readme typos ([#481](https://github.com/libp2p/js-libp2p/issues/481)) ([35ac02d](https://github.com/libp2p/js-libp2p/commit/35ac02d))
* make dialer configurable ([#521](https://github.com/libp2p/js-libp2p/issues/521)) ([4ca481b](https://github.com/libp2p/js-libp2p/commit/4ca481b))
* performance bottleneck in stat.js ([#463](https://github.com/libp2p/js-libp2p/issues/463)) ([93a1e42](https://github.com/libp2p/js-libp2p/commit/93a1e42))
* registrar should filter the disconnected conn ([#532](https://github.com/libp2p/js-libp2p/issues/532)) ([bb2e56e](https://github.com/libp2p/js-libp2p/commit/bb2e56e))
* release tokens as soon as they are available ([2570a1b](https://github.com/libp2p/js-libp2p/commit/2570a1b))
* replace peerInfo addresses with listen addresses ([#485](https://github.com/libp2p/js-libp2p/issues/485)) ([1999606](https://github.com/libp2p/js-libp2p/commit/1999606))
* stop discoveries ([#530](https://github.com/libp2p/js-libp2p/issues/530)) ([4222c49](https://github.com/libp2p/js-libp2p/commit/4222c49))
* token release logic ([90ecc57](https://github.com/libp2p/js-libp2p/commit/90ecc57))
* upgrader should not need muxers ([#517](https://github.com/libp2p/js-libp2p/issues/517)) ([5d7ee50](https://github.com/libp2p/js-libp2p/commit/5d7ee50))
* use toB58String everywhere to be consistent ([#537](https://github.com/libp2p/js-libp2p/issues/537)) ([c1038be](https://github.com/libp2p/js-libp2p/commit/c1038be))
### Features
* abort all pending dials on stop ([ba02764](https://github.com/libp2p/js-libp2p/commit/ba02764))
* add early token recycling in ([a5b54a7](https://github.com/libp2p/js-libp2p/commit/a5b54a7))
* add libp2p.connections getter ([#522](https://github.com/libp2p/js-libp2p/issues/522)) ([6445fda](https://github.com/libp2p/js-libp2p/commit/6445fda))
* add token based dialer ([e445a17](https://github.com/libp2p/js-libp2p/commit/e445a17))
* allow transport options to be passed on creation ([#524](https://github.com/libp2p/js-libp2p/issues/524)) ([c339be1](https://github.com/libp2p/js-libp2p/commit/c339be1))
* coalescing dial support ([#518](https://github.com/libp2p/js-libp2p/issues/518)) ([15f7c2a](https://github.com/libp2p/js-libp2p/commit/15f7c2a))
* discovery modules ([#486](https://github.com/libp2p/js-libp2p/issues/486)) ([18a062e](https://github.com/libp2p/js-libp2p/commit/18a062e))
* discovery modules from transports should be added ([#510](https://github.com/libp2p/js-libp2p/issues/510)) ([f1eb373](https://github.com/libp2p/js-libp2p/commit/f1eb373))
* peer store ([#470](https://github.com/libp2p/js-libp2p/issues/470)) ([582094a](https://github.com/libp2p/js-libp2p/commit/582094a))
* registrar ([#471](https://github.com/libp2p/js-libp2p/issues/471)) ([9d52b80](https://github.com/libp2p/js-libp2p/commit/9d52b80))
* support peer-id instances in peer store operations ([#491](https://github.com/libp2p/js-libp2p/issues/491)) ([8da9fc9](https://github.com/libp2p/js-libp2p/commit/8da9fc9))
<a name="0.27.0-rc.0"></a>
# [0.27.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.27.0-pre.2...v0.27.0-rc.0) (2020-01-24)
### Bug Fixes
* registrar should filter the disconnected conn ([#532](https://github.com/libp2p/js-libp2p/issues/532)) ([83409de](https://github.com/libp2p/js-libp2p/commit/83409de))
* stop discoveries ([#530](https://github.com/libp2p/js-libp2p/issues/530)) ([c44e6e3](https://github.com/libp2p/js-libp2p/commit/c44e6e3))
* use toB58String everywhere to be consistent ([#537](https://github.com/libp2p/js-libp2p/issues/537)) ([31d1b23](https://github.com/libp2p/js-libp2p/commit/31d1b23))
<a name="0.27.0-pre.2"></a>
# [0.27.0-pre.2](https://github.com/libp2p/js-libp2p/compare/v0.27.0-pre.1...v0.27.0-pre.2) (2020-01-07)

View File

@@ -37,7 +37,7 @@ One of following:
<!--
This is for you! Please read, and then delete this text before posting it.
The js-ipfs issues are only for bug reports and directly actionable features.
The js-libp2p issues are only for bug reports and directly actionable features.
Read https://github.com/ipfs/community/blob/master/CONTRIBUTING.md#reporting-issues if your issue doesn't fit either of those categories.
-->

View File

@@ -5,12 +5,14 @@
<h3 align="center">The JavaScript implementation of the libp2p Networking Stack.</h3>
<p align="center">
<a href="http://ipn.io"><img src="https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square" /></a>
<a href="http://protocol.ai"><img src="https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square" /></a>
<a href="http://libp2p.io/"><img src="https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square" /></a>
<a href="http://webchat.freenode.net/?channels=%23libp2p"><img src="https://img.shields.io/badge/freenode-%23libp2p-yellow.svg?style=flat-square" /></a>
<a href="https://riot.permaweb.io/#/room/#libp2p:permaweb.io"><img src="https://img.shields.io/badge/matrix-%23libp2p%3Apermaweb.io-blue.svg?style=flat-square" /> </a>
<a href="https://riot.im/app/#/room/#libp2p:matrix.org"><img src="https://img.shields.io/badge/matrix-%23libp2p%3Apermaweb.io-blue.svg?style=flat-square" /> </a>
<a href="https://discord.gg/66KBrm2"><img src="https://img.shields.io/discord/475789330380488707?color=blueviolet&label=discord&style=flat-square" /></a>
<a href="https://discuss.libp2p.io"><img src="https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg" /></a>
<a href="https://www.npmjs.com/package/libp2p"><img src="https://img.shields.io/npm/dm/libp2p.svg" /></a>
<a href="https://www.jsdelivr.com/package/npm/libp2p"><img src="https://data.jsdelivr.com/v1/package/npm/libp2p/badge"/></a>
</p>
<p align="center">
@@ -30,14 +32,13 @@
We've come a long way, but this project is still in Alpha, lots of development is happening, API might change, beware of the Dragons 🐉..
The documentation in the master branch may contain changes from a pre-release.
If you are looking for the documentation of the latest release, you can view the latest release on [**npm**](https://www.npmjs.com/package/libp2p), or select the tag in github that matches the version you are looking for.
**Want to get started?** Check our [examples folder](/examples).
[**`Weekly Core Dev Calls`**](https://github.com/ipfs/pm/issues/650)
## Tech Lead
[David Dias](https://github.com/diasdavid/)
## Lead Maintainer
[Jacob Heun](https://github.com/jacobheun/)
@@ -49,6 +50,7 @@ We've come a long way, but this project is still in Alpha, lots of development i
- [Usage](#usage)
- [Configuration](#configuration)
- [API](#api)
- [Getting Started](#getting-started)
- [Tutorials and Examples](#tutorials-and-examples)
- [Development](#development)
- [Tests](#tests)
@@ -89,6 +91,10 @@ For all the information on how you can configure libp2p see [CONFIGURATION.md](.
The specification is available on [API.md](./doc/API.md).
### Getting started
If you are starting your journey with `js-libp2p`, read the [GETTING_STARTED.md](./doc/GETTING_STARTED.md) guide.
### Tutorials and Examples
You can find multiple examples on the [examples folder](./examples) that will guide you through using libp2p for several scenarios.
@@ -127,49 +133,45 @@ List of packages currently in existence for libp2p
| Package | Version | Deps | CI | Coverage | Lead Maintainer |
| ---------|---------|---------|---------|---------|--------- |
| **libp2p** |
| [`libp2p`](//github.com/libp2p/js-libp2p) | [![npm](https://img.shields.io/npm/v/libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-daemon`](//github.com/libp2p/js-libp2p-daemon) | [![npm](https://img.shields.io/npm/v/libp2p-daemon.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-daemon/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-daemon.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-daemon) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-daemon.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-daemon) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-daemon/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-daemon) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-daemon-client`](//github.com/libp2p/js-libp2p-daemon-client) | [![npm](https://img.shields.io/npm/v/libp2p-daemon-client.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-daemon-client/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-daemon-client.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-daemon-client) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-daemon-client.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-daemon-client) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-daemon-client/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-daemon-client) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-interfaces`](//github.com/libp2p/js-interfaces) | [![npm](https://img.shields.io/npm/v/libp2p-interfaces.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-interfaces/releases) | [![Deps](https://david-dm.org/libp2p/js-interfaces.svg?style=flat-square)](https://david-dm.org/libp2p/js-interfaces) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-interfaces.svg?branch=master)](https://travis-ci.com/libp2p/js-interfaces) | [![codecov](https://codecov.io/gh/libp2p/js-interfaces/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-interfaces) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`interop-libp2p`](//github.com/libp2p/interop) | [![npm](https://img.shields.io/npm/v/interop-libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/interop/releases) | [![Deps](https://david-dm.org/libp2p/interop.svg?style=flat-square)](https://david-dm.org/libp2p/interop) | [![Travis CI](https://flat.badgen.net/travis/libp2p/interop.svg?branch=master)](https://travis-ci.com/libp2p/interop) | [![codecov](https://codecov.io/gh/libp2p/interop/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/interop) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p`](//github.com/libp2p/js-libp2p) | [![npm](https://img.shields.io/npm/v/libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p/master)](https://travis-ci.com/libp2p/js-libp2p) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-daemon`](//github.com/libp2p/js-libp2p-daemon) | [![npm](https://img.shields.io/npm/v/libp2p-daemon.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-daemon/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-daemon.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-daemon) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-daemon/master)](https://travis-ci.com/libp2p/js-libp2p-daemon) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-daemon/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-daemon) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-daemon-client`](//github.com/libp2p/js-libp2p-daemon-client) | [![npm](https://img.shields.io/npm/v/libp2p-daemon-client.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-daemon-client/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-daemon-client.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-daemon-client) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-daemon-client/master)](https://travis-ci.com/libp2p/js-libp2p-daemon-client) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-daemon-client/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-daemon-client) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-interfaces`](//github.com/libp2p/js-interfaces) | [![npm](https://img.shields.io/npm/v/libp2p-interfaces.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-interfaces/releases) | [![Deps](https://david-dm.org/libp2p/js-interfaces.svg?style=flat-square)](https://david-dm.org/libp2p/js-interfaces) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-interfaces/master)](https://travis-ci.com/libp2p/js-interfaces) | [![codecov](https://codecov.io/gh/libp2p/js-interfaces/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-interfaces) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`interop-libp2p`](//github.com/libp2p/interop) | [![npm](https://img.shields.io/npm/v/interop-libp2p.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/interop/releases) | [![Deps](https://david-dm.org/libp2p/interop.svg?style=flat-square)](https://david-dm.org/libp2p/interop) | [![Travis CI](https://flat.badgen.net/travis/libp2p/interop/master)](https://travis-ci.com/libp2p/interop) | [![codecov](https://codecov.io/gh/libp2p/interop/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/interop) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| **transports** |
| [`libp2p-tcp`](//github.com/libp2p/js-libp2p-tcp) | [![npm](https://img.shields.io/npm/v/libp2p-tcp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-tcp/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-tcp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-tcp) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-tcp.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-tcp) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-tcp/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-tcp) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-utp`](//github.com/libp2p/js-libp2p-utp) | [![npm](https://img.shields.io/npm/v/libp2p-utp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utp/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-utp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utp) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-utp.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-utp) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-utp/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-utp) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-webrtc-direct`](//github.com/libp2p/js-libp2p-webrtc-direct) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-direct.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-direct/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-direct.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-direct) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-direct.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-direct) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-direct/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-direct) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-star.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/libp2p-websockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-websockets.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-websockets) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-websockets/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-websockets) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-websocket-star`](//github.com/libp2p/js-libp2p-websocket-star) | [![npm](https://img.shields.io/npm/v/libp2p-websocket-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websocket-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-websocket-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-websocket-star.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-websocket-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-websocket-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-websocket-star) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-tcp`](//github.com/libp2p/js-libp2p-tcp) | [![npm](https://img.shields.io/npm/v/libp2p-tcp.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-tcp/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-tcp.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-tcp) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-tcp/master)](https://travis-ci.com/libp2p/js-libp2p-tcp) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-tcp/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-tcp) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-webrtc-direct`](//github.com/libp2p/js-libp2p-webrtc-direct) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-direct.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-direct/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-direct.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-direct) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-direct/master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-direct) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-direct/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-direct) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-star/master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [![npm](https://img.shields.io/npm/v/libp2p-websockets.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websockets/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-websockets.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websockets) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-websockets/master)](https://travis-ci.com/libp2p/js-libp2p-websockets) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-websockets/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-websockets) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| **secure channels** |
| [`libp2p-secio`](//github.com/libp2p/js-libp2p-secio) | [![npm](https://img.shields.io/npm/v/libp2p-secio.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-secio/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-secio.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-secio) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-secio.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-secio) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-secio/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-secio) | [Friedel Ziegelmayer](mailto:dignifiedquire@gmail.com) |
| [`libp2p-secio`](//github.com/libp2p/js-libp2p-secio) | [![npm](https://img.shields.io/npm/v/libp2p-secio.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-secio/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-secio.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-secio) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-secio/master)](https://travis-ci.com/libp2p/js-libp2p-secio) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-secio/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-secio) | [Friedel Ziegelmayer](mailto:dignifiedquire@gmail.com) |
| **stream multiplexers** |
| [`libp2p-mplex`](//github.com/libp2p/js-libp2p-mplex) | [![npm](https://img.shields.io/npm/v/libp2p-mplex.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mplex/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-mplex.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-mplex) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-mplex.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-mplex) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mplex/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mplex) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-spdy`](//github.com/libp2p/js-libp2p-spdy) | [![npm](https://img.shields.io/npm/v/libp2p-spdy.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-spdy/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-spdy.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-spdy) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-spdy.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-spdy) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-spdy/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-spdy) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-mplex`](//github.com/libp2p/js-libp2p-mplex) | [![npm](https://img.shields.io/npm/v/libp2p-mplex.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mplex/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-mplex.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-mplex) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-mplex/master)](https://travis-ci.com/libp2p/js-libp2p-mplex) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mplex/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mplex) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| **peer discovery** |
| [`libp2p-bootstrap`](//github.com/libp2p/js-libp2p-bootstrap) | [![npm](https://img.shields.io/npm/v/libp2p-bootstrap.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-bootstrap/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-bootstrap.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-bootstrap) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-bootstrap.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-bootstrap) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-bootstrap/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-bootstrap) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-mdns`](//github.com/libp2p/js-libp2p-mdns) | [![npm](https://img.shields.io/npm/v/libp2p-mdns.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mdns/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-mdns.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-mdns) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-mdns.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-mdns) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mdns/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mdns) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-rendezvous`](//github.com/libp2p/js-libp2p-rendezvous) | [![npm](https://img.shields.io/npm/v/libp2p-rendezvous.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-rendezvous/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-rendezvous.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-rendezvous) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-rendezvous.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-rendezvous) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-rendezvous/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-rendezvous) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-star.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-websocket-star`](//github.com/libp2p/js-libp2p-websocket-star) | [![npm](https://img.shields.io/npm/v/libp2p-websocket-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-websocket-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-websocket-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-websocket-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-websocket-star.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-websocket-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-websocket-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-websocket-star) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-bootstrap`](//github.com/libp2p/js-libp2p-bootstrap) | [![npm](https://img.shields.io/npm/v/libp2p-bootstrap.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-bootstrap/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-bootstrap.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-bootstrap) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-bootstrap/master)](https://travis-ci.com/libp2p/js-libp2p-bootstrap) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-bootstrap/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-bootstrap) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht/master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-mdns`](//github.com/libp2p/js-libp2p-mdns) | [![npm](https://img.shields.io/npm/v/libp2p-mdns.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-mdns/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-mdns.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-mdns) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-mdns/master)](https://travis-ci.com/libp2p/js-libp2p-mdns) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-mdns/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-mdns) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-webrtc-star`](//github.com/libp2p/js-libp2p-webrtc-star) | [![npm](https://img.shields.io/npm/v/libp2p-webrtc-star.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-webrtc-star/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-webrtc-star.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-webrtc-star) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-webrtc-star/master)](https://travis-ci.com/libp2p/js-libp2p-webrtc-star) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-webrtc-star) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`discv5`](//github.com/ChainSafe/discv5) | [![npm](https://img.shields.io/npm/v/discv5.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/discv5/releases) | [![Deps](https://david-dm.org/ChainSafe/discv5.svg?style=flat-square)](https://david-dm.org/ChainSafe/discv5) | [![Travis CI](https://flat.badgen.net/travis/ChainSafe/discv5/master)](https://travis-ci.com/ChainSafe/discv5) | [![codecov](https://codecov.io/gh/ChainSafe/discv5/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/discv5) | [Cayman Nava](mailto:caymannava@gmail.com) |
| **content routing** |
| [`libp2p-delegated-content-routing`](//github.com/libp2p/js-libp2p-delegated-content-routing) | [![npm](https://img.shields.io/npm/v/libp2p-delegated-content-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-content-routing/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-delegated-content-routing.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-delegated-content-routing) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-delegated-content-routing.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-delegated-content-routing) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-delegated-content-routing`](//github.com/libp2p/js-libp2p-delegated-content-routing) | [![npm](https://img.shields.io/npm/v/libp2p-delegated-content-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-content-routing/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-delegated-content-routing.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-delegated-content-routing) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-delegated-content-routing/master)](https://travis-ci.com/libp2p/js-libp2p-delegated-content-routing) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-content-routing) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht/master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| **peer routing** |
| [`libp2p-delegated-peer-routing`](//github.com/libp2p/js-libp2p-delegated-peer-routing) | [![npm](https://img.shields.io/npm/v/libp2p-delegated-peer-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-peer-routing/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-delegated-peer-routing.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-delegated-peer-routing) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-delegated-peer-routing.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-delegated-peer-routing) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-delegated-peer-routing`](//github.com/libp2p/js-libp2p-delegated-peer-routing) | [![npm](https://img.shields.io/npm/v/libp2p-delegated-peer-routing.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-delegated-peer-routing/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-delegated-peer-routing.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-delegated-peer-routing) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-delegated-peer-routing/master)](https://travis-ci.com/libp2p/js-libp2p-delegated-peer-routing) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-delegated-peer-routing) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-kad-dht`](//github.com/libp2p/js-libp2p-kad-dht) | [![npm](https://img.shields.io/npm/v/libp2p-kad-dht.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-kad-dht/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-kad-dht.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-kad-dht) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-kad-dht/master)](https://travis-ci.com/libp2p/js-libp2p-kad-dht) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-kad-dht/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-kad-dht) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| **utilities** |
| [`libp2p-crypto`](//github.com/libp2p/js-libp2p-crypto) | [![npm](https://img.shields.io/npm/v/libp2p-crypto.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-crypto.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-crypto.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-crypto) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-crypto/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-crypto-secp256k1`](//github.com/libp2p/js-libp2p-crypto-secp256k1) | [![npm](https://img.shields.io/npm/v/libp2p-crypto-secp256k1.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto-secp256k1/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-crypto-secp256k1.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto-secp256k1) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-crypto-secp256k1.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-crypto-secp256k1) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-crypto-secp256k1/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto-secp256k1) | [Friedel Ziegelmayer](mailto:dignifiedquire@gmail.com) |
| [`libp2p-crypto`](//github.com/libp2p/js-libp2p-crypto) | [![npm](https://img.shields.io/npm/v/libp2p-crypto.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-crypto.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-crypto/master)](https://travis-ci.com/libp2p/js-libp2p-crypto) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-crypto/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto) | [Jacob Heun](mailto:jacobheun@gmail.com) |
| [`libp2p-crypto-secp256k1`](//github.com/libp2p/js-libp2p-crypto-secp256k1) | [![npm](https://img.shields.io/npm/v/libp2p-crypto-secp256k1.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-crypto-secp256k1/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-crypto-secp256k1.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-crypto-secp256k1) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-crypto-secp256k1/master)](https://travis-ci.com/libp2p/js-libp2p-crypto-secp256k1) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-crypto-secp256k1/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-crypto-secp256k1) | [Friedel Ziegelmayer](mailto:dignifiedquire@gmail.com) |
| **data types** |
| [`peer-id`](//github.com/libp2p/js-peer-id) | [![npm](https://img.shields.io/npm/v/peer-id.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-peer-id/releases) | [![Deps](https://david-dm.org/libp2p/js-peer-id.svg?style=flat-square)](https://david-dm.org/libp2p/js-peer-id) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-peer-id.svg?branch=master)](https://travis-ci.com/libp2p/js-peer-id) | [![codecov](https://codecov.io/gh/libp2p/js-peer-id/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-peer-id) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`peer-info`](//github.com/libp2p/js-peer-info) | [![npm](https://img.shields.io/npm/v/peer-info.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-peer-info/releases) | [![Deps](https://david-dm.org/libp2p/js-peer-info.svg?style=flat-square)](https://david-dm.org/libp2p/js-peer-info) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-peer-info.svg?branch=master)](https://travis-ci.com/libp2p/js-peer-info) | [![codecov](https://codecov.io/gh/libp2p/js-peer-info/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-peer-info) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`peer-id`](//github.com/libp2p/js-peer-id) | [![npm](https://img.shields.io/npm/v/peer-id.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-peer-id/releases) | [![Deps](https://david-dm.org/libp2p/js-peer-id.svg?style=flat-square)](https://david-dm.org/libp2p/js-peer-id) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-peer-id/master)](https://travis-ci.com/libp2p/js-peer-id) | [![codecov](https://codecov.io/gh/libp2p/js-peer-id/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-peer-id) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`peer-info`](//github.com/libp2p/js-peer-info) | [![npm](https://img.shields.io/npm/v/peer-info.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-peer-info/releases) | [![Deps](https://david-dm.org/libp2p/js-peer-info.svg?style=flat-square)](https://david-dm.org/libp2p/js-peer-info) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-peer-info/master)](https://travis-ci.com/libp2p/js-peer-info) | [![codecov](https://codecov.io/gh/libp2p/js-peer-info/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-peer-info) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| **pubsub** |
| [`libp2p-pubsub`](//github.com/libp2p/js-libp2p-pubsub) | [![npm](https://img.shields.io/npm/v/libp2p-pubsub.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-pubsub/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-pubsub.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-pubsub) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-pubsub.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-pubsub) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-pubsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-pubsub) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-floodsub`](//github.com/libp2p/js-libp2p-floodsub) | [![npm](https://img.shields.io/npm/v/libp2p-floodsub.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-floodsub/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-floodsub.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-floodsub) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-floodsub.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-floodsub) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-floodsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-floodsub) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-gossipsub`](//github.com/ChainSafe/gossipsub-js) | [![npm](https://img.shields.io/npm/v/libp2p-gossipsub.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/gossipsub-js/releases) | [![Deps](https://david-dm.org/ChainSafe/gossipsub-js.svg?style=flat-square)](https://david-dm.org/ChainSafe/gossipsub-js) | [![Travis CI](https://flat.badgen.net/travis/ChainSafe/gossipsub-js.svg?branch=master)](https://travis-ci.com/ChainSafe/gossipsub-js) | [![codecov](https://codecov.io/gh/ChainSafe/gossipsub-js/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/gossipsub-js) | [Cayman Nava](mailto:caymannava@gmail.com) |
| [`libp2p-pubsub`](//github.com/libp2p/js-libp2p-pubsub) | [![npm](https://img.shields.io/npm/v/libp2p-pubsub.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-pubsub/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-pubsub.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-pubsub) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-pubsub/master)](https://travis-ci.com/libp2p/js-libp2p-pubsub) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-pubsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-pubsub) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-floodsub`](//github.com/libp2p/js-libp2p-floodsub) | [![npm](https://img.shields.io/npm/v/libp2p-floodsub.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-floodsub/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-floodsub.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-floodsub) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-floodsub/master)](https://travis-ci.com/libp2p/js-libp2p-floodsub) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-floodsub/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-floodsub) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
| [`libp2p-gossipsub`](//github.com/ChainSafe/gossipsub-js) | [![npm](https://img.shields.io/npm/v/libp2p-gossipsub.svg?maxAge=86400&style=flat-square)](//github.com/ChainSafe/gossipsub-js/releases) | [![Deps](https://david-dm.org/ChainSafe/gossipsub-js.svg?style=flat-square)](https://david-dm.org/ChainSafe/gossipsub-js) | [![Travis CI](https://flat.badgen.net/travis/ChainSafe/gossipsub-js/master)](https://travis-ci.com/ChainSafe/gossipsub-js) | [![codecov](https://codecov.io/gh/ChainSafe/gossipsub-js/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/ChainSafe/gossipsub-js) | [Cayman Nava](mailto:caymannava@gmail.com) |
| **extensions** |
| [`libp2p-nat-mgnr`](//github.com/libp2p/js-libp2p-nat-mgnr) | [![npm](https://img.shields.io/npm/v/libp2p-nat-mgnr.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-nat-mgnr/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-nat-mgnr.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-nat-mgnr) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-nat-mgnr.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-nat-mgnr) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-nat-mgnr/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-nat-mgnr) | N/A |
| [`libp2p-utils`](//github.com/libp2p/js-libp2p-utils) | [![npm](https://img.shields.io/npm/v/libp2p-utils.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utils/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-utils.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utils) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-utils.svg?branch=master)](https://travis-ci.com/libp2p/js-libp2p-utils) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-utils/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-utils) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
| [`libp2p-nat-mgnr`](//github.com/libp2p/js-libp2p-nat-mgnr) | [![npm](https://img.shields.io/npm/v/libp2p-nat-mgnr.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-nat-mgnr/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-nat-mgnr.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-nat-mgnr) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-nat-mgnr/master)](https://travis-ci.com/libp2p/js-libp2p-nat-mgnr) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-nat-mgnr/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-nat-mgnr) | N/A |
| [`libp2p-utils`](//github.com/libp2p/js-libp2p-utils) | [![npm](https://img.shields.io/npm/v/libp2p-utils.svg?maxAge=86400&style=flat-square)](//github.com/libp2p/js-libp2p-utils/releases) | [![Deps](https://david-dm.org/libp2p/js-libp2p-utils.svg?style=flat-square)](https://david-dm.org/libp2p/js-libp2p-utils) | [![Travis CI](https://flat.badgen.net/travis/libp2p/js-libp2p-utils/master)](https://travis-ci.com/libp2p/js-libp2p-utils) | [![codecov](https://codecov.io/gh/libp2p/js-libp2p-utils/branch/master/graph/badge.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-utils) | [Vasco Santos](mailto:santos.vasco10@gmail.com) |
## Contribute

View File

@@ -28,6 +28,7 @@
* [`metrics.protocols`](#metricsprotocols)
* [`metrics.forPeer`](#metricsforpeer)
* [`metrics.forProtocol`](#metricsforprotocol)
* [Events](#events)
* [Types](#types)
* [`Stats`](#stats)
@@ -50,7 +51,7 @@ Creates an instance of Libp2p.
| [options.datastore] | `Object` | must implement [ipfs/interface-datastore](https://github.com/ipfs/interface-datastore) (in memory datastore will be used if not provided) |
| [options.dialer] | `Object` | libp2p Dialer configuration
| [options.metrics] | `Object` | libp2p Metrics configuration
| [options.peerInfo] | [PeerInfo](https://github.com/libp2p/js-peer-info) | peerInfo instance (it will be created if not provided) |
| [options.peerInfo] | [`PeerInfo`][peer-info] | peerInfo instance (it will be created if not provided) |
For Libp2p configurations and modules details read the [Configuration Document](./CONFIGURATION.md).
@@ -72,7 +73,7 @@ const options = {}
const libp2p = await Libp2p.create(options)
```
Note: The `PeerInfo` option is not required and will be generated if it is not provided.
Note: The [`PeerInfo`][peer-info] option is not required and will be generated if it is not provided.
<details><summary>Alternative</summary>
As an alternative, it is possible to create a Libp2p instance with the constructor:
@@ -91,44 +92,11 @@ const libp2p = new Libp2p(options)
Required keys in the `options` object:
- `peerInfo`: instance of [PeerInfo][] that contains the [PeerId][], Keys and [multiaddrs][multiaddr] of the libp2p Node (optional when using `.create`).
- `peerInfo`: instance of [`PeerInfo`][peer-info] that contains the [`PeerId`][peer-id], Keys and [multiaddrs][multiaddr] of the libp2p Node (optional when using `.create`).
- `modules.transport`: An array that must include at least 1 compliant transport. See [modules that implement the transport interface](https://github.com/libp2p/js-interfaces/tree/master/src/transport#modules-that-implement-the-interface).
</details>
Once you have a libp2p instance, you are able to listen to several events it emits, so that you can be noticed of relevant network events.
<details><summary>Events</summary>
#### An error has occurred
`libp2p.on('error', (err) => {})`
- `err`: instance of `Error`
#### A peer has been discovered
`libp2p.on('peer:discovery', (peer) => {})`
If `autoDial` option is `true`, applications should **not** attempt to connect to the peer
unless they are performing a specific action. See [peer discovery and auto dial](./PEER_DISCOVERY.md) for more information.
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
#### We have a new connection to a peer
`libp2p.on('peer:connect', (peer) => {})`
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
#### We have closed a connection to a peer
`libp2p.on('peer:disconnect', (peer) => {})`
- `peer`: instance of [PeerInfo][https://github.com/libp2p/js-peer-info]
</details>
## Libp2p Instance Methods
### start
@@ -206,15 +174,13 @@ for (const [peerId, connections] of libp2p.connections) {
### dial
Dials to another peer in the network and establishes the connection.
`dial(peer, options)`
#### Parameters
| Name | Type | Description |
|------|------|-------------|
| peer | [PeerInfo](https://github.com/libp2p/js-peer-info), [PeerId][peer-id], [multiaddr](https://github.com/multiformats/js-multiaddr), `string` | peer to dial |
| peer | [`PeerInfo`][peer-info]\|[`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | The peer to dial. If a [`Multiaddr`][multiaddr] or its string is provided, it **must** include the peer id |
| [options] | `Object` | dial options |
| [options.signal] | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | An `AbortSignal` instance obtained from an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) that can be used to abort the connection before it completes |
@@ -249,7 +215,7 @@ Dials to another peer in the network and selects a protocol to communicate with
| Name | Type | Description |
|------|------|-------------|
| peer | [PeerInfo](https://github.com/libp2p/js-peer-info), [PeerId][peer-id], [multiaddr](https://github.com/multiformats/js-multiaddr), `string` | peer to dial |
| peer | [`PeerInfo`][peer-info]\|[`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | The peer to dial. If a [`Multiaddr`][multiaddr] or its string is provided, it **must** include the peer id |
| protocols | `String|Array<String>` | A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made. (e.g '/ipfs/bitswap/1.1.0') |
| [options] | `Object` | dial options |
| [options.signal] | [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) | An `AbortSignal` instance obtained from an [`AbortController`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) that can be used to abort the connection before it completes |
@@ -282,7 +248,7 @@ Attempts to gracefully close an open connection to the given peer. If the connec
| Name | Type | Description |
|------|------|-------------|
| peer | [PeerInfo](https://github.com/libp2p/js-peer-info), [PeerId][peer-id], [multiaddr](https://github.com/multiformats/js-multiaddr), `string` | peer to hang up |
| peer | [`PeerInfo`][peer-info]\|[`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | peer to hang up |
#### Returns
@@ -353,7 +319,7 @@ Pings a given peer and get the operation's latency.
| Name | Type | Description |
|------|------|-------------|
| peer | `PeerInfo|PeerId|Multiaddr|string` | peer to ping |
| peer | [`PeerInfo`][peer-info]\|[`PeerId`][peer-id]\|[`Multiaddr`][multiaddr]\|`string` | peer to ping |
#### Returns
@@ -406,7 +372,7 @@ Once a content router succeeds, the iteration will stop. If the DHT is enabled,
| Name | Type | Description |
|------|------|-------------|
| cid | [`CID`](https://github.com/multiformats/js-cid) | cid to find |
| cid | [`CID`][cid] | cid to find |
| options | `Object` | operation options |
| options.timeout | `number` | maximum time the query should run |
| options.maxNumProviders | `number` | maximum number of providers to find |
@@ -415,7 +381,7 @@ Once a content router succeeds, the iteration will stop. If the DHT is enabled,
| Type | Description |
|------|-------------|
| `AsyncIterator<PeerInfo>` | Async iterator for [`PeerInfo`](https://github.com/libp2p/js-peer-info) |
| `AsyncIterator<PeerInfo>` | Async iterator for [`PeerInfo`][peer-info] |
#### Example
@@ -436,7 +402,7 @@ Iterates over all content routers in parallel, in order to notify it is a provid
| Name | Type | Description |
|------|------|-------------|
| cid | [`CID`](https://github.com/multiformats/js-cid) | cid to provide |
| cid | [`CID`][cid] | cid to provide |
#### Returns
@@ -681,7 +647,7 @@ Enables users to change the value of certain peers in a range of 0 to 1. Peers w
| Name | Type | Description |
|------|------|-------------|
| peerId | `PeerId` | The peer to set the value for |
| peerId | [`PeerId`][peer-id] | The peer to set the value for |
| value | `number` | The value of the peer from 0 to 1 |
#### Returns
@@ -709,7 +675,7 @@ const peerIdStrings = libp2p.metrics.peers
### metrics.peers
An array of `PeerId` strings of each peer currently being tracked.
An array of [`PeerId`][peer-id] strings of each peer currently being tracked.
#### Example
@@ -729,7 +695,7 @@ const protocols = libp2p.metrics.protocols
### metrics.forPeer
Returns the [`Stats`](#stats) object for a given `PeerId` if it is being tracked.
Returns the [`Stats`](#stats) object for a given [`PeerId`][peer-id] if it is being tracked.
`libp2p.metrics.forPeer(peerId)`
@@ -737,7 +703,7 @@ Returns the [`Stats`](#stats) object for a given `PeerId` if it is being tracked
| Name | Type | Description |
|------|------|-------------|
| peerId | `PeerId` | The peer to get stats for |
| peerId | [`PeerId`][peer-id] | The peer to get stats for |
#### Returns
@@ -777,6 +743,41 @@ const peerStats = libp2p.metrics.forProtocol('/meshsub/1.0.0')
console.log(peerStats.toJSON())
```
## Events
Once you have a libp2p instance, you can listen to several events it emits, so that you can be notified of relevant network events.
#### An error has occurred
`libp2p.on('error', (err) => {})`
- `err`: instance of `Error`
#### A peer has been discovered
`libp2p.on('peer:discovery', (peer) => {})`
If `autoDial` option is `true`, applications should **not** attempt to connect to the peer
unless they are performing a specific action. See [peer discovery and auto dial](./PEER_DISCOVERY.md) for more information.
- `peer`: instance of [`PeerInfo`][peer-info]
#### A new connection to a peer has been opened
This event will be triggered anytime a new Connection is established to another peer.
`libp2p.on('peer:connect', (peer) => {})`
- `peer`: instance of [`PeerInfo`][peer-info]
#### An existing connection to a peer has been closed
This event will be triggered anytime we are disconnected from another peer, regardless of the circumstances of that disconnection. If we happen to have multiple connections to a peer, this event will **only** be triggered when the last connection is closed.
`libp2p.on('peer:disconnect', (peer) => {})`
- `peer`: instance of [`PeerInfo`][peer-info]
## Types
### Stats
@@ -797,5 +798,8 @@ console.log(peerStats.toJSON())
- `['300000']<MovingAverage>`: The [MovingAverage](https://www.npmjs.com/package/moving-averages) at a 5 minute interval.
- `['900000']<MovingAverage>`: The [MovingAverage](https://www.npmjs.com/package/moving-averages) at a 15 minute interval.
[cid]: https://github.com/multiformats/js-cid
[connection]: https://github.com/libp2p/js-interfaces/tree/master/src/connection
[multiaddr]: https://github.com/multiformats/js-multiaddr
[peer-id]: https://github.com/libp2p/js-peer-id
[peer-info]: https://github.com/libp2p/js-peer-info

View File

@@ -113,6 +113,7 @@ Some available peer discovery modules are:
- [js-libp2p-bootstrap](https://github.com/libp2p/js-libp2p-bootstrap)
- [js-libp2p-kad-dht](https://github.com/libp2p/js-libp2p-kad-dht)
- [js-libp2p-webrtc-star](https://github.com/libp2p/js-libp2p-webrtc-star)
- [discv5](https://github.com/chainsafe/discv5)
**Note**: `peer-discovery` services within transports (such as `js-libp2p-webrtc-star`) are automatically gathered from the `transport`, via it's `discovery` property. As such, they do not need to be added in the discovery modules. However, these transports can also be configured and disabled as the other ones.
@@ -129,7 +130,7 @@ If you want to know more about libp2p peer discovery, you should read the follow
Some available content routing modules are:
- [js-libp2p-kad-dht](https://github.com/libp2p/js-libp2p-kad-dht)
- [js-libp2p-delegated-peer-routing](https://github.com/libp2p/js-libp2p-delegated-peer-routing)
- [js-libp2p-delegated-content-routing](https://github.com/libp2p/js-libp2p-delegated-content-routing)
If none of the available content routing protocols fulfills your needs, you can create a libp2p compatible one. A libp2p content routing protocol just needs to be compliant with the [Content Routing Interface](https://github.com/libp2p/js-interfaces/tree/master/src/content-routing). **(WIP: This module is not yet implemented)**

247
doc/GETTING_STARTED.md Normal file
View File

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

View File

@@ -0,0 +1,178 @@
# Migrating to the new API
A migration guide for refactoring your application code from libp2p v0.26.x to v0.27.0.
## Table of Contents
- [Migrating from callbacks](#migrating-from-callbacks)
- [Pull Streams to Streaming Iterables](#pull-streams-to-streaming-iterables)
- [Sample API Migrations](#sample-api-migrations)
- [Registering Protocol Handlers](#registering-protocol-handlers)
- [Dialing and Sending Data](#dialing-and-sending-data)
- [Checking if a peer is connected](#checking-if-a-peer-is-connected)
- [Pinging another peer](#pinging-another-peer)
- [Pubsub](#pubsub)
- [Getting subscribers](#getting-subscribers)
- [Getting subscribed topics](#getting-subscribed-topics)
## Migrating from callbacks
Callbacks are no longer supported in the libp2p API, as the API has now fully moved to async / await. You can see a full list of the available methods in the [API readme][api]
**Before**
```js
libp2p.start((err) => {
if (err) throw err
console.log('libp2p started')
})
```
**After**
```js
await libp2p.start()
console.log('libp2p started')
```
## Pull Streams to Streaming Iterables
The libp2p API no longer supports Pull Streams and has migrated to [Streaming Iterables][streaming_iterable]. If you would like to continue using Pull Streams in your application code, or need additional time to migrate your code base, you can leverage the conversion modules [async-iterator-to-pull-stream](https://github.com/alanshaw/async-iterator-to-pull-stream) and [pull-stream-to-async-iterator](https://github.com/alanshaw/pull-stream-to-async-iterator).
For a growing list of async iterator modules, you should follow the [it-awesome repo][it_awesome].
## Sample API Migrations
### Registering Protocol Handlers
Protocol registration is very similar to how it previously was, however, the handler now takes a single parameter containing the incoming stream and its protocol. Additionally, you can now pass an array of protocols to `.handle`, but a single string is still supported.
**Before**
```js
const pull = require('pull-stream')
libp2p.handle('/echo/1.0.0', (protocol, conn) => pull(conn, conn))
```
**After**
```js
const pipe = require('it-pipe')
libp2p.handle(['/echo/1.0.0'], ({ protocol, stream }) => pipe(stream, stream))
```
### Dialing and Sending Data
`dialProtocol` no longer takes a callback, and will now return a [Streaming Iterable][streaming_iterable] and the protocol that was successfully negotiated. The new stream can be used with async iterator modules, see [it-awesome][it_awesome], instead of pull streams.
**Before**
```js
const pull = require('pull-stream')
libp2p.dialProtocol(peerInfo, '/echo/1.0.0', (err, conn) => {
if (err) { throw err }
pull(
pull.values(['hey']),
conn,
pull.drain((data) => {
console.log('received echo:', data.toString())
}, (err) => {
if (err) { throw err }
})
)
})
```
**After**
```js
const pipe = require('it-pipe')
const { protocol, stream } = await libp2p.dialProtocol(peerInfo, '/echo/1.0.0')
await pipe(
['hey'],
stream,
async function (source) {
for await (const data of source) {
console.log('received echo:', data.toString())
}
}
)
```
### Checking if a peer is connected
`peerInfo.isConnected` has been deprecated. libp2p now tracks all connections centrally and will no longer update the state of `peerInfo.isConnected`. Consumers should switch to using `libp2p.registrar.getConnection(peerInfo)`, which will return an open connection to that peer if one exists.
**Before**
```js
if (peerInfo.isConnected()) {
// ...do something if connected
}
```
**After**
```js
const connection = libp2p.registrar.getConnection(peerInfo)
if (connection) {
// ...do something if connected
}
```
### Pinging another peer
`libp2p.ping` will no longer callback with a `Ping` event emitter. The internal logic has been simplified to give more flexibility to the API. `libp2p.ping` will now execute a single ping and return the latency.
**Before**
```js
libp2p.ping(peerInfo, (err, ping) => {
if (err) throw err
ping.once('ping', (latency) => {
console.log('Latency is %s ms', latency)
ping.stop()
})
ping.start()
})
```
**After**
```js
const latency = await libp2p.ping(peerInfo)
console.log('Latency is %s ms', latency)
```
### Pubsub
#### Getting subscribers
`libp2p.pubsub.peers()` is now `libp2p.pubsub.getSubscribers()` and is no longer an asynchronous action.
**Before**
```js
libp2p.pubsub.peers(topic, (err, subscribers) => {
if (err) throw err
console.log('Subscribers:', subscribers)
})
```
**After**
```js
const subscribers = libp2p.pubsub.getSubscribers(topic)
console.log('Subscribers:', subscribers)
```
#### Getting subscribed topics
`libp2p.pubsub.ls()` is now `libp2p.pubsub.getTopics()` and is no longer an asynchronous action.
**Before**
```js
libp2p.pubsub.ls((err, topics) => {
if (err) throw err
console.log('Topics:', topics)
})
```
**After**
```js
const topics = libp2p.pubsub.getTopics()
console.log('Topics:', topics)
```
[api]: ../API.md
[it_awesome]: https://github.com/alanshaw/it-awesome
[streaming_iterable]: ../STREAMING_ITERABLES.md

View File

@@ -1,3 +1,7 @@
❗❗Outdated: This example is still not refactored with the `0.27.*` release.
WIP on [libp2p/js-libp2p#507](https://github.com/libp2p/js-libp2p/pull/507)
======
# Delegated Routing with Libp2p and IPFS
This example shows how to use delegated peer and content routing. The [Peer and Content Routing Example](../peer-and-content-routing) focuses

View File

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

View File

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

View File

@@ -1,32 +0,0 @@
{
"name": "libp2p-in-the-browser",
"version": "0.1.0",
"description": "See other nodes in the network using WebRTC Star discovery mechanism",
"main": "src/index.js",
"scripts": {
"bundle": "browserify src/index.js > public/bundle.js",
"serve": "static public -p 9090 -H '{\"Cache-Control\": \"no-cache, must-revalidate\"}'",
"start": "npm run bundle && npm run serve"
},
"license": "MIT",
"devDependencies": {
"browserify": "^14.5.0",
"concat-stream": "^1.6.0",
"detect-dom-ready": "^1.0.2",
"node-static": "~0.7.10"
},
"dependencies": {
"detect-dom-ready": "^1.0.2",
"libp2p": "../../../",
"libp2p-bootstrap": "~0.9.7",
"libp2p-gossipsub": "~0.0.4",
"libp2p-kad-dht": "^0.15.3",
"libp2p-mplex": "~0.8.5",
"libp2p-secio": "~0.11.1",
"libp2p-spdy": "~0.13.3",
"libp2p-webrtc-star": "~0.15.8",
"libp2p-websocket-star": "~0.10.2",
"libp2p-websockets": "~0.12.2",
"peer-info": "~0.15.1"
}
}

View File

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

View File

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

View File

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

View File

@@ -1,57 +0,0 @@
/* eslint no-console: ["error", { allow: ["log"] }] */
/* eslint max-nested-callbacks: ["error", 5] */
'use strict'
const domReady = require('detect-dom-ready')
const createNode = require('./create-node')
domReady(() => {
const myPeerDiv = document.getElementById('my-peer')
const swarmDiv = document.getElementById('swarm')
createNode((err, node) => {
if (err) {
return console.log('Could not create the Node, check if your browser has WebRTC Support', err)
}
node.on('peer:discovery', (peerInfo) => {
console.log('Discovered a peer:', peerInfo.id.toB58String())
})
node.on('peer:connect', (peerInfo) => {
const idStr = peerInfo.id.toB58String()
console.log('Got connection to: ' + idStr)
const connDiv = document.createElement('div')
connDiv.innerHTML = 'Connected to: ' + idStr
connDiv.id = idStr
swarmDiv.append(connDiv)
})
node.on('peer:disconnect', (peerInfo) => {
const idStr = peerInfo.id.toB58String()
const el = document.getElementById(idStr)
el && el.remove()
})
node.start((err) => {
if (err) {
return console.log(err)
}
const idStr = node.peerInfo.id.toB58String()
const idDiv = document
.createTextNode('Node is ready. ID: ' + idStr)
myPeerDiv.append(idDiv)
console.log('Node is listening o/')
node.peerInfo.multiaddrs.toArray().forEach(ma => {
console.log(ma.toString())
})
// NOTE: to stop the node
// node.stop((err) => {})
})
})
})

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
/* eslint no-console: ["off"] */
'use strict'
const { Buffer } = require('buffer')
const { generate } = require('libp2p/src/pnet')
const privateLibp2pNode = require('./libp2p-node')
@@ -17,7 +18,7 @@ generate(otherSwarmKey)
;(async () => {
const node1 = await privateLibp2pNode(swarmKey)
// TASK: switch the commented out line below so we're using a different key, to see the nodes fail to connect
// TASK: switch the commented out line below so we're using a different key, to see the nodes fail to connect
const node2 = await privateLibp2pNode(swarmKey)
// const node2 = await privateLibp2pNode(otherSwarmKey)
@@ -47,4 +48,4 @@ generate(otherSwarmKey)
['This message is sent on a private network'],
stream
)
})();
})()

View File

@@ -1,6 +1,7 @@
/* eslint-disable no-console */
'use strict'
const { Buffer } = require('buffer')
const Libp2p = require('../../')
const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex')
@@ -31,7 +32,7 @@ const createNode = async () => {
const [node1, node2] = await Promise.all([
createNode(),
createNode(),
createNode()
])
await node1.dial(node2.peerInfo)
@@ -48,4 +49,4 @@ const createNode = async () => {
setInterval(() => {
node2.pubsub.publish(topic, Buffer.from('Bird bird bird, bird is the word!'))
}, 1000)
})();
})()

View File

@@ -17,26 +17,22 @@
"transports",
["libp2p/js-libp2p-tcp", "libp2p-tcp"],
["libp2p/js-libp2p-utp", "libp2p-utp"],
["libp2p/js-libp2p-webrtc-direct", "libp2p-webrtc-direct"],
["libp2p/js-libp2p-webrtc-star", "libp2p-webrtc-star"],
["libp2p/js-libp2p-websockets", "libp2p-websockets"],
["libp2p/js-libp2p-websocket-star", "libp2p-websocket-star"],
"secure channels",
["libp2p/js-libp2p-secio", "libp2p-secio"],
"stream multiplexers",
["libp2p/js-libp2p-mplex", "libp2p-mplex"],
["libp2p/js-libp2p-spdy", "libp2p-spdy"],
"peer discovery",
["libp2p/js-libp2p-bootstrap", "libp2p-bootstrap"],
["libp2p/js-libp2p-kad-dht", "libp2p-kad-dht"],
["libp2p/js-libp2p-mdns", "libp2p-mdns"],
["libp2p/js-libp2p-rendezvous", "libp2p-rendezvous"],
["libp2p/js-libp2p-webrtc-star", "libp2p-webrtc-star"],
["libp2p/js-libp2p-websocket-star", "libp2p-websocket-star"],
["ChainSafe/discv5", "discv5"],
"content routing",
["libp2p/js-libp2p-delegated-content-routing", "libp2p-delegated-content-routing"],

View File

@@ -1,6 +1,6 @@
{
"name": "libp2p",
"version": "0.27.0-pre.2",
"version": "0.27.8",
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"main": "src/index.js",
@@ -47,119 +47,107 @@
"bignumber.js": "^9.0.0",
"class-is": "^1.1.0",
"debug": "^4.1.1",
"err-code": "^1.1.2",
"err-code": "^2.0.0",
"events": "^3.1.0",
"hashlru": "^2.3.0",
"ipfs-utils": "^2.2.0",
"it-all": "^1.0.1",
"it-buffer": "^0.1.1",
"it-buffer": "^0.1.2",
"it-handshake": "^1.0.1",
"it-length-prefixed": "^3.0.0",
"it-length-prefixed": "^3.0.1",
"it-pipe": "^1.1.0",
"it-protocol-buffers": "^0.2.0",
"latency-monitor": "~0.2.1",
"libp2p-crypto": "^0.17.1",
"libp2p-interfaces": "^0.1.5",
"libp2p-crypto": "^0.17.6",
"libp2p-interfaces": "^0.2.8",
"libp2p-utils": "^0.1.2",
"mafmt": "^7.0.0",
"merge-options": "^2.0.0",
"moving-average": "^1.0.0",
"multiaddr": "^7.2.1",
"multiaddr": "^7.4.3",
"multistream-select": "^0.15.0",
"mutable-proxy": "^1.0.0",
"p-any": "^2.1.0",
"p-any": "^3.0.0",
"p-fifo": "^1.0.0",
"p-settle": "^3.1.0",
"peer-id": "^0.13.4",
"p-settle": "^4.0.1",
"peer-id": "^0.13.11",
"peer-info": "^0.17.0",
"protons": "^1.0.1",
"retimer": "^2.0.0",
"streaming-iterables": "^4.1.0",
"timeout-abort-controller": "^1.0.0",
"xsalsa20": "^1.0.2"
},
"devDependencies": {
"@nodeutils/defaults-deep": "^1.1.0",
"abortable-iterator": "^2.1.0",
"aegir": "^20.4.1",
"abortable-iterator": "^3.0.0",
"aegir": "^21.10.1",
"chai": "^4.2.0",
"chai-as-promised": "^7.1.1",
"cids": "^0.7.1",
"cids": "^0.8.0",
"delay": "^4.3.0",
"dirty-chai": "^2.0.1",
"interop-libp2p": "~0.0.1",
"it-concat": "^1.0.0",
"it-pair": "^1.0.0",
"it-pushable": "^1.4.0",
"libp2p-bootstrap": "^0.10.3",
"libp2p-delegated-content-routing": "^0.4.1",
"libp2p-delegated-peer-routing": "^0.4.0",
"libp2p-delegated-content-routing": "^0.4.5",
"libp2p-delegated-peer-routing": "^0.4.3",
"libp2p-floodsub": "^0.20.0",
"libp2p-gossipsub": "^0.2.0",
"libp2p-kad-dht": "^0.18.2",
"libp2p-gossipsub": "^0.2.6",
"libp2p-kad-dht": "^0.18.6",
"libp2p-mdns": "^0.13.0",
"libp2p-mplex": "^0.9.1",
"libp2p-secio": "^0.12.1",
"libp2p-mplex": "^0.9.5",
"libp2p-secio": "^0.12.4",
"libp2p-tcp": "^0.14.1",
"libp2p-webrtc-star": "^0.17.0",
"libp2p-webrtc-star": "^0.17.9",
"libp2p-websockets": "^0.13.1",
"nock": "^10.0.6",
"nock": "^12.0.3",
"p-defer": "^3.0.0",
"p-times": "^2.1.0",
"p-times": "^3.0.0",
"p-wait-for": "^3.1.0",
"sinon": "^7.2.7",
"streaming-iterables": "^4.1.0",
"wrtc": "^0.4.1"
"sinon": "^9.0.2"
},
"contributors": [
"Aditya Bose <13054902+adbose@users.noreply.github.com>",
"Alan Shaw <alan.shaw@protocol.ai>",
"Alan Shaw <alan@tableflip.io>",
"Alex Potsides <alex@achingbrain.net>",
"Andrew Nesbitt <andrewnez@gmail.com>",
"Chris Bratlien <chrisbratlien@gmail.com>",
"Chris Dostert <chrisdostert@users.noreply.github.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>",
"David Dias <daviddias.p@gmail.com>",
"Didrik Nordström <didrik.nordstrom@gmail.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Elven <mon.samuel@qq.com>",
"Fei Liu <liu.feiwood@gmail.com>",
"Florian-Merle <florian.david.merle@gmail.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Giovanni T. Parra <fiatjaf@gmail.com>",
"Guy Sviry <32539816+guysv@users.noreply.github.com>",
"Henrique Dias <hacdias@gmail.com>",
"Hugo Dias <mail@hugodias.me>",
"Hugo Dias <hugomrdias@gmail.com>",
"Irakli Gozalishvili <rfobic@gmail.com>",
"Jacob Heun <jacobheun@gmail.com>",
"Joel Gustafson <joelg@mit.edu>",
"John Rees <johnrees@users.noreply.github.com>",
"João Santos <joaosantos15@users.noreply.github.com>",
"Kevin Kwok <antimatter15@gmail.com>",
"Lars Gierth <lgierth@users.noreply.github.com>",
"Maciej Krüger <mkg20001@gmail.com>",
"Marcin Tojek <mtojek@users.noreply.github.com>",
"Nuno Nogueira <nunofmn@gmail.com>",
"Pedro Teixeira <pedro@protocol.ai>",
"Vasco Santos <vasco.santos@moxy.studio>",
"Alan Shaw <alan@tableflip.io>",
"Pedro Teixeira <i@pgte.me>",
"RasmusErik Voel Jensen <github@solsort.com>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Maciej Krüger <mkg20001@gmail.com>",
"Alex Potsides <alex@achingbrain.net>",
"Hugo Dias <mail@hugodias.me>",
"dirkmc <dirkmdev@gmail.com>",
"Volker Mische <volker.mische@gmail.com>",
"Richard Littauer <richard.littauer@gmail.com>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
"Andrew Nesbitt <andrewnez@gmail.com>",
"Cayman <caymannava@gmail.com>",
"Elven <mon.samuel@qq.com>",
"Giovanni T. Parra <fiatjaf@gmail.com>",
"Ryan Bell <ryan@piing.net>",
"Thomas Eizinger <thomas@eizinger.io>",
"Didrik Nordström <didrik@betamos.se>",
"Joel Gustafson <joelg@mit.edu>",
"Kevin Kwok <antimatter15@gmail.com>",
"Nuno Nogueira <nunofmn@gmail.com>",
"Florian-Merle <florian.david.merle@gmail.com>",
"RasmusErik Voel Jensen <github@solsort.com>",
"Fei Liu <liu.feiwood@gmail.com>",
"Soeren <nikorpoulsen@gmail.com>",
"Sönke Hahn <soenkehahn@gmail.com>",
"Thomas Eizinger <thomas@eizinger.io>",
"Tiago Alves <alvesjtiago@gmail.com>",
"Vasco Santos <vasco.santos@moxy.studio>",
"Vasco Santos <vasco.santos@ua.pt>",
"Volker Mische <volker.mische@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"Yusef Napora <yusef@napora.org>",
"Zane Starr <zcstarr@gmail.com>",
"a1300 <a1300@users.noreply.github.com>",
"dirkmc <dirkmdev@gmail.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>",
"ebinks <elizabethjbinks@gmail.com>",
"greenkeeperio-bot <support@greenkeeper.io>",
"Chris Bratlien <chrisbratlien@gmail.com>",
"isan_rivkin <isanrivkin@gmail.com>",
"mayerwin <mayerwin@users.noreply.github.com>",
"phillmac <phillmac@users.noreply.github.com>",
"swedneck <40505480+swedneck@users.noreply.github.com>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>"
"robertkiel <robert.kiel@validitylabs.org>",
"Irakli Gozalishvili <rfobic@gmail.com>",
"Henrique Dias <hacdias@gmail.com>"
]
}

View File

@@ -1,3 +0,0 @@
# PDD Test Stories Implementation
> Implementation of the Compliance tests from https://github.com/libp2p/interop

View File

@@ -1,20 +0,0 @@
{
"name": "pdd-impl",
"version": "0.0.0",
"description": "PDD Test Stories implementation",
"repository": {
"type": "git",
"url": " "
},
"keywords": [
"PDD",
"libp2p"
],
"author": "David Dias <daviddias@ipfs.io>",
"license": "MIT",
"dependencies": {
"libp2p": "file:./..",
"libp2p-interop": "github:libp2p/interop#master",
"tape": "^4.8.0"
}
}

View File

@@ -1,104 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const WebSockets = require('libp2p-websockets')
const SECIO = require('libp2p-secio')
const Multiplex = require('libp2p-multiplex')
const Railing = require('libp2p-railing')
const MulticastDNS = require('libp2p-mdns')
const KadDHT = require('libp2p-kad-dht')
const PeerInfo = require('peer-info')
const pull = require('pull-stream')
const waterfall = require('async/waterfall')
const series = require('async/series')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class IPFSBundle extends libp2p {
constructor (peerInfo, options) {
options = Object.assign({ bootstrap: [] }, options)
const modules = {
transport: [
new TCP(),
new WebSockets()
],
connection: {
muxer: [
Multiplex
],
crypto: [
SECIO
]
},
discovery: [
new MulticastDNS(peerInfo, 'ipfs.local'),
new Railing(options.bootstrap)
],
DHT: KadDHT
}
super(modules, peerInfo, undefined, options)
}
}
test('story 1 - peerA', (t) => {
t.plan(10)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000')
node = new IPFSBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node successfully')
t.ok(node.isStarted(), 'PeerA is Running')
const peerBAddr = `/ip4/127.0.0.1/tcp/10001/p2p/${PeerB.id}`
node.handle('/time/1.0.0', (protocol, conn) => {
pull(
pull.values([Date.now().toString()]),
conn,
pull.onEnd((err) => {
t.ifErr(err)
t.pass('Sent time successfully')
})
)
})
series([
(cb) => setTimeout(cb, 5 * 1000), // time to run both scripts
(cb) => node.ping(peerBAddr, (err, p) => {
t.ifErr(err, 'initiated Ping to PeerB')
p.once('error', (err) => t.ifErr(err, 'Ping should not fail'))
p.once('ping', (time) => {
t.pass('ping PeerB successfully')
p.stop()
cb()
})
}),
(cb) => node.dial(peerBAddr, '/echo/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
const data = Buffer.from('Hey')
pull(
pull.values([data]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received echo back')
t.deepEqual(values[0], data)
cb()
})
)
}),
(cb) => setTimeout(cb, 2 * 1000) // time to both finish
], () => node.stop((err) => t.ifErr(err, 'PeerA has stopped')))
})
})

View File

@@ -1,98 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const WebSockets = require('libp2p-websockets')
const SECIO = require('libp2p-secio')
const Multiplex = require('libp2p-multiplex')
const Railing = require('libp2p-railing')
const MulticastDNS = require('libp2p-mdns')
const KadDHT = require('libp2p-kad-dht')
const PeerInfo = require('peer-info')
const pull = require('pull-stream')
const waterfall = require('async/waterfall')
const series = require('async/series')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class IPFSBundle extends libp2p {
constructor (peerInfo, options) {
options = Object.assign({ bootstrap: [] }, options)
const modules = {
transport: [
new TCP(),
new WebSockets()
],
connection: {
muxer: [
Multiplex
],
crypto: [
SECIO
]
},
discovery: [
new MulticastDNS(peerInfo, 'ipfs.local'),
new Railing(options.bootstrap)
],
DHT: KadDHT
}
super(modules, peerInfo, undefined, options)
}
}
test('story 1 - peerA', (t) => {
t.plan(8)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10001')
node = new IPFSBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node successfully')
t.ok(node.isStarted(), 'PeerB is Running')
const peerAAddr = `/ip4/127.0.0.1/tcp/10000/p2p/${PeerA.id}`
node.handle('/echo/1.0.0', (protocol, conn) => {
pull(
conn,
conn,
pull.onEnd((err) => t.ifErr(err, 'echo was successful'))
)
})
series([
(cb) => setTimeout(cb, 5 * 1000), // time to run both scripts
(cb) => node.ping(peerAAddr, (err, p) => {
t.ifErr(err, 'initiated Ping to PeerA')
p.once('error', (err) => t.ifErr(err, 'Ping should not fail'))
p.once('ping', (time) => {
t.pass('ping PeerA successfully')
p.stop()
cb()
})
}),
(cb) => node.dial(peerAAddr, '/time/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
pull(
pull.values([]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received time')
cb()
})
)
}),
(cb) => setTimeout(cb, 2 * 1000) // time to both finish
], () => node.stop((err) => t.ifErr(err, 'PeerB has stopped')))
})
})

View File

@@ -1,54 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new TCP()]
}
super(modules, peerInfo)
}
}
test('story 1 - peerA', (t) => {
t.plan(6)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerBAddr = `/ip4/127.0.0.1/tcp/10001/p2p/${PeerB.id}`
node.dial(PeerBAddr, '/echo/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
const data = Buffer.from('Heey')
pull(
pull.values([data]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received echo back')
t.deepEqual(values[0], data)
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
})
)
})
})
})

View File

@@ -1,49 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new TCP()]
}
super(modules, peerInfo)
}
}
test('story 1 - peerB', (t) => {
t.plan(5)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10001')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err)
t.ok(node.isStarted(), 'PeerB is running')
node.handle('/echo/1.0.0', (protocol, conn) => {
pull(
conn,
conn,
pull.onEnd((err) => {
t.ifErr(err)
t.pass('Received End of Connection')
node.stop((err) => {
t.ifErr(err, 'PeerB has stopped')
})
})
)
})
})
})

View File

@@ -1,54 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new WebSockets()]
}
super(modules, peerInfo)
}
}
test('story 2 - peerA', (t) => {
t.plan(6)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000/ws')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerBAddr = `/ip4/127.0.0.1/tcp/10001/p2p/${PeerB.id}`
node.dial(PeerBAddr, '/echo/1.0.0', (err, conn) => {
t.ifErr(err, 'dial successful')
const data = Buffer.from('Heey')
pull(
pull.values([data]),
conn,
pull.collect((err, values) => {
t.ifErr(err, 'Received echo back')
t.deepEqual(values[0], data)
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
})
)
})
})
})

View File

@@ -1,49 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const pull = require('pull-stream')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new WebSockets()]
}
super(modules, peerInfo)
}
}
test('story 2 - peerB', (t) => {
t.plan(5)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10001/ws')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err)
t.ok(node.isStarted(), 'PeerB is running')
node.handle('/echo/1.0.0', (protocol, conn) => {
pull(
conn,
pull.through(v => v, err => {
t.ifErr(err)
t.pass('Received End of Connection')
node.stop((err) => {
t.ifErr(err, 'PeerB has stopped')
})
}),
conn
)
})
})
})

View File

@@ -1,42 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new TCP()]
}
super(modules, peerInfo)
}
}
test('story 3 - peerA', (t) => {
t.plan(4)
let node
waterfall([
(cb) => PeerInfo.create(PeerA, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerBAddr = `/ip4/127.0.0.1/tcp/10001/ws/p2p/${PeerB.id}`
setTimeout(() => node.dial(PeerBAddr, '/echo/1.0.0', (err, conn) => {
t.ok(err, 'dial failed')
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
}), 1000)
})
})

View File

@@ -1,42 +0,0 @@
'use strict'
const test = require('tape')
const libp2p = require('libp2p')
const WebSockets = require('libp2p-websockets')
const PeerInfo = require('peer-info')
const waterfall = require('async/waterfall')
const PeerA = require('libp2p-interop/peer-a.json')
const PeerB = require('libp2p-interop/peer-b.json')
class MyBundle extends libp2p {
constructor (peerInfo) {
const modules = {
transport: [new WebSockets()]
}
super(modules, peerInfo)
}
}
test('story 3 - peerB', (t) => {
t.plan(4)
let node
waterfall([
(cb) => PeerInfo.create(PeerB, cb),
(peerInfo, cb) => {
peerInfo.multiaddrs.add('/ip4/127.0.0.1/tcp/10000/ws')
node = new MyBundle(peerInfo)
node.start(cb)
}
], (err) => {
t.ifErr(err, 'created Node')
t.ok(node.isStarted(), 'PeerA is running')
const PeerAAddr = `/ip4/127.0.0.1/tcp/10000/ws/p2p/${PeerA.id}`
setTimeout(() => node.dial(PeerAAddr, '/echo/1.0.0', (err, conn) => {
t.ok(err, 'dial failed')
node.stop((err) => t.ifErr(err, 'PeerA has stopped'))
}), 1000)
})
})

View File

@@ -10,13 +10,13 @@ const { CircuitRelay: CircuitPB } = require('./protocol')
const debug = require('debug')
const log = debug('libp2p:circuit')
log.error = debug('libp2p:circuit:error')
const toConnection = require('libp2p-utils/src/stream-to-ma-conn')
const { relay: multicodec } = require('./multicodec')
const createListener = require('./listener')
const { handleCanHop, handleHop, hop } = require('./circuit/hop')
const { handleStop } = require('./circuit/stop')
const StreamHandler = require('./circuit/stream-handler')
const toConnection = require('./stream-to-conn')
class Circuit {
/**

View File

@@ -22,7 +22,7 @@ module.exports = (circuit) => {
* @return {void}
*/
listener.listen = async (addr) => {
const [addrString] = String(addr).split('/p2p-circuit').slice(-1)
const addrString = String(addr).split('/p2p-circuit').find(a => a !== '')
const relayConn = await circuit._dialer.connectToPeer(multiaddr(addrString))
const relayedAddr = relayConn.remoteAddr.encapsulate('/p2p-circuit')

View File

@@ -1,49 +0,0 @@
'use strict'
const abortable = require('abortable-iterator')
const log = require('debug')('libp2p:circuit:stream')
// Convert a duplex iterable into a MultiaddrConnection
// https://github.com/libp2p/interface-transport#multiaddrconnection
module.exports = ({ stream, remoteAddr, localAddr }, options = {}) => {
const { sink, source } = stream
const maConn = {
async sink (source) {
if (options.signal) {
source = abortable(source, options.signal)
}
try {
await sink(source)
} catch (err) {
// If aborted we can safely ignore
if (err.type !== 'aborted') {
// If the source errored the socket will already have been destroyed by
// toIterable.duplex(). If the socket errored it will already be
// destroyed. There's nothing to do here except log the error & return.
log(err)
}
}
close()
},
source: options.signal ? abortable(source, options.signal) : source,
conn: stream,
localAddr,
remoteAddr,
timeline: { open: Date.now() },
close () {
sink([])
close()
}
}
function close () {
if (!maConn.timeline.close) {
maConn.timeline.close = Date.now()
}
}
return maConn
}

View File

@@ -1,11 +1,15 @@
'use strict'
const assert = require('assert')
const errcode = require('err-code')
const mergeOptions = require('merge-options')
const LatencyMonitor = require('latency-monitor').default
const LatencyMonitor = require('./latency-monitor')
const debug = require('debug')('libp2p:connection-manager')
const retimer = require('retimer')
const {
ERR_INVALID_PARAMETERS
} = require('../errors')
const defaultOptions = {
maxConnections: Infinity,
minConnections: 0,
@@ -36,12 +40,11 @@ class ConnectionManager {
constructor (libp2p, options) {
this._libp2p = libp2p
this._registrar = libp2p.registrar
this._peerId = libp2p.peerInfo.id.toString()
this._peerId = libp2p.peerInfo.id.toB58String()
this._options = mergeOptions.call({ ignoreUndefined: true }, defaultOptions, options)
assert(
this._options.maxConnections > this._options.minConnections,
'Connection Manager maxConnections must be greater than minConnections'
)
if (this._options.maxConnections < this._options.minConnections) {
throw errcode(new Error('Connection Manager maxConnections must be greater than minConnections'), ERR_INVALID_PARAMETERS)
}
debug('options: %j', this._options)
@@ -91,8 +94,8 @@ class ConnectionManager {
if (value < 0 || value > 1) {
throw new Error('value should be a number between 0 and 1')
}
if (peerId.toString) {
peerId = peerId.toString()
if (peerId.toB58String) {
peerId = peerId.toB58String()
}
this._peerValues.set(peerId, value)
}
@@ -119,7 +122,7 @@ class ConnectionManager {
* @param {Connection} connection
*/
onConnect (connection) {
const peerId = connection.remotePeer.toString()
const peerId = connection.remotePeer.toB58String()
this._connections.set(connection.id, connection)
if (!this._peerValues.has(peerId)) {
this._peerValues.set(peerId, this._options.defaultPeerValue)
@@ -133,7 +136,7 @@ class ConnectionManager {
*/
onDisconnect (connection) {
this._connections.delete(connection.id)
this._peerValues.delete(connection.remotePeer.toString())
this._peerValues.delete(connection.remotePeer.toB58String())
}
/**
@@ -175,7 +178,7 @@ class ConnectionManager {
debug('%s: lowest value peer is %s', this._peerId, peerId)
debug('%s: closing a connection to %j', this._peerId, peerId)
for (const connection of this._connections.values()) {
if (connection.remotePeer.toString() === peerId) {
if (connection.remotePeer.toB58String() === peerId) {
connection.close()
break
}

View File

@@ -0,0 +1,246 @@
'use strict'
/**
* This code is based on `latency-monitor` (https://github.com/mlucool/latency-monitor) by `mlucool` (https://github.com/mlucool), available under Apache License 2.0 (https://github.com/mlucool/latency-monitor/blob/master/LICENSE)
*/
/* global window */
const globalThis = require('ipfs-utils/src/globalthis')
const EventEmitter = require('events')
const VisibilityChangeEmitter = require('./visibility-change-emitter')
const debug = require('debug')('latency-monitor:LatencyMonitor')
/**
* @typedef {Object} SummaryObject
* @property {Number} events How many events were called
* @property {Number} minMS What was the min time for a cb to be called
* @property {Number} maxMS What was the max time for a cb to be called
* @property {Number} avgMs What was the average time for a cb to be called
* @property {Number} lengthMs How long this interval was in ms
*/
/**
* A class to monitor latency of any async function which works in a browser or node. This works by periodically calling
* the asyncTestFn and timing how long it takes the callback to be called. It can also periodically emit stats about this.
* This can be disabled and stats can be pulled via setting dataEmitIntervalMs = 0.
*
* The default implementation is an event loop latency monitor. This works by firing periodic events into the event loop
* and timing how long it takes to get back.
*
* @example
* const monitor = new LatencyMonitor();
* monitor.on('data', (summary) => console.log('Event Loop Latency: %O', summary));
*
* @example
* const monitor = new LatencyMonitor({latencyCheckIntervalMs: 1000, dataEmitIntervalMs: 60000, asyncTestFn:ping});
* monitor.on('data', (summary) => console.log('Ping Pong Latency: %O', summary));
*/
class LatencyMonitor extends EventEmitter {
/**
* @param {Number} [latencyCheckIntervalMs=500] How often to add a latency check event (ms)
* @param {Number} [dataEmitIntervalMs=5000] How often to summarize latency check events. null or 0 disables event firing
* @param {function} [asyncTestFn] What cb-style async function to use
* @param {Number} [latencyRandomPercentage=5] What percent (+/-) of latencyCheckIntervalMs should we randomly use? This helps avoid alignment to other events.
*/
constructor ({ latencyCheckIntervalMs, dataEmitIntervalMs, asyncTestFn, latencyRandomPercentage } = {}) {
super()
const that = this
// 0 isn't valid here, so its ok to use ||
that.latencyCheckIntervalMs = latencyCheckIntervalMs || 500 // 0.5s
that.latencyRandomPercentage = latencyRandomPercentage || 10
that._latecyCheckMultiply = 2 * (that.latencyRandomPercentage / 100.0) * that.latencyCheckIntervalMs
that._latecyCheckSubtract = that._latecyCheckMultiply / 2
that.dataEmitIntervalMs = (dataEmitIntervalMs === null || dataEmitIntervalMs === 0) ? undefined
: dataEmitIntervalMs || 5 * 1000 // 5s
debug('latencyCheckIntervalMs: %s dataEmitIntervalMs: %s',
that.latencyCheckIntervalMs, that.dataEmitIntervalMs)
if (that.dataEmitIntervalMs) {
debug('Expecting ~%s events per summary', that.latencyCheckIntervalMs / that.dataEmitIntervalMs)
} else {
debug('Not emitting summaries')
}
that.asyncTestFn = asyncTestFn // If there is no asyncFn, we measure latency
// If process: use high resolution timer
if (globalThis.process && globalThis.process.hrtime) {
debug('Using process.hrtime for timing')
that.now = globalThis.process.hrtime
that.getDeltaMS = (startTime) => {
const hrtime = that.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)
} else {
debug('Using Date.now for timing')
that.now = Date.now
that.getDeltaMS = (startTime) => that.now() - startTime
}
that._latencyData = that._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()
that._visibilityChangeEmitter.on('visibilityChange', (pageInFocus) => {
if (pageInFocus) {
that._startTimers()
} else {
that._emitSummary()
that._stopTimers()
}
})
}
if (!that._visibilityChangeEmitter || that._visibilityChangeEmitter.isVisible()) {
that._startTimers()
}
}
/**
* Start internal timers
* @private
*/
_startTimers () {
// Timer already started, ignore this
if (this._checkLatencyID) {
return
}
this._checkLatency()
if (this.dataEmitIntervalMs) {
this._emitIntervalID = setInterval(() => this._emitSummary(), this.dataEmitIntervalMs)
if (typeof this._emitIntervalID.unref === 'function') {
this._emitIntervalID.unref() // Doesn't block exit
}
}
}
/**
* Stop internal timers
* @private
*/
_stopTimers () {
if (this._checkLatencyID) {
clearTimeout(this._checkLatencyID)
this._checkLatencyID = undefined
}
if (this._emitIntervalID) {
clearInterval(this._emitIntervalID)
this._emitIntervalID = undefined
}
}
/**
* Emit summary only if there were events. It might not have any events if it was forced via a page hidden/show
* @private
*/
_emitSummary () {
const summary = this.getSummary()
if (summary.events > 0) {
this.emit('data', summary)
}
}
/**
* Calling this function will end the collection period. If a timing event was already fired and somewhere in the queue,
* it will not count for this time period
* @returns {SummaryObject}
*/
getSummary () {
// We might want to adjust for the number of expected events
// Example: first 1 event it comes back, then such a long blocker that the next emit check comes
// Then this fires - looks like no latency!!
const latency = {
events: this._latencyData.events,
minMs: this._latencyData.minMs,
maxMs: this._latencyData.maxMs,
avgMs: this._latencyData.events ? this._latencyData.totalMs / this._latencyData.events
: Number.POSITIVE_INFINITY,
lengthMs: this.getDeltaMS(this._latencyData.startTime)
}
this._latencyData = this._initLatencyData() // Clear
debug('Summary: %O', latency)
return latency
}
/**
* Randomly calls an async fn every roughly latencyCheckIntervalMs (plus some randomness). If no async fn is found,
* it will simply report on event loop latency.
*
* @private
*/
_checkLatency () {
const that = this
// Randomness is needed to avoid alignment by accident to regular things in the event loop
const randomness = (Math.random() * that._latecyCheckMultiply) - that._latecyCheckSubtract
// We use this to ensure that in case some overlap somehow, we don't take the wrong startTime/offset
const localData = {
deltaOffset: Math.ceil(that.latencyCheckIntervalMs + randomness),
startTime: that.now()
}
const cb = () => {
// We are already stopped, ignore this datapoint
if (!this._checkLatencyID) {
return
}
const deltaMS = that.getDeltaMS(localData.startTime) - localData.deltaOffset
that._checkLatency() // Start again ASAP
// Add the data point. If this gets complex, refactor it
that._latencyData.events++
that._latencyData.minMs = Math.min(that._latencyData.minMs, deltaMS)
that._latencyData.maxMs = Math.max(that._latencyData.maxMs, deltaMS)
that._latencyData.totalMs += deltaMS
debug('MS: %s Data: %O', deltaMS, that._latencyData)
}
debug('localData: %O', localData)
this._checkLatencyID = setTimeout(() => {
// This gets rid of including event loop
if (that.asyncTestFn) {
// Clear timing related things
localData.deltaOffset = 0
localData.startTime = that.now()
that.asyncTestFn(cb)
} else {
// setTimeout is not more accurate than 1ms, so this will ensure positive numbers. Add 1 to emitted data to remove.
// This is not the best, but for now it'll be just fine. This isn't meant to be sub ms accurate.
localData.deltaOffset -= 1
// If there is no function to test, we mean check latency which is a special case that is really cb => cb()
// We avoid that for the few extra function all overheads. Also, we want to keep the timers different
cb()
}
}, localData.deltaOffset)
if (typeof this._checkLatencyID.unref === 'function') {
this._checkLatencyID.unref() // Doesn't block exit
}
}
_initLatencyData () {
return {
startTime: this.now(),
minMs: Number.POSITIVE_INFINITY,
maxMs: Number.NEGATIVE_INFINITY,
events: 0,
totalMs: 0
}
}
}
function isBrowser () {
return typeof window !== 'undefined'
}
module.exports = LatencyMonitor

View File

@@ -0,0 +1,118 @@
/* global document */
/**
* This code is based on `latency-monitor` (https://github.com/mlucool/latency-monitor) by `mlucool` (https://github.com/mlucool), available under Apache License 2.0 (https://github.com/mlucool/latency-monitor/blob/master/LICENSE)
*/
'use strict'
const EventEmitter = require('events')
const debug = require('debug')('latency-monitor:VisibilityChangeEmitter')
/**
* Listen to page visibility change events (i.e. when the page is focused / blurred) by an event emitter.
*
* Warning: This does not work on all browsers, but should work on all modern browsers
*
* @example
*
* const myVisibilityEmitter = new VisibilityChangeEmitter();
*
* myVisibilityEmitter.on('visibilityChange', (pageInFocus) => {
* if ( pageInFocus ){
* // Page is in focus
* console.log('In focus');
* }
* else {
* // Page is blurred
* console.log('Out of focus');
* }
* });
* // To access the visibility state directly, call:
* console.log('Am I focused now? ' + myVisibilityEmitter.isVisible());
*
* @class VisibilityChangeEmitter
*/
module.exports = class VisibilityChangeEmitter extends EventEmitter {
/**
* Creates a VisibilityChangeEmitter
*/
constructor () {
super()
if (typeof document === 'undefined') {
debug('This is not a browser, no "document" found. Stopping.')
return
}
this._initializeVisibilityVarNames()
this._addVisibilityChangeListener()
}
/**
* document.hidden and document.visibilityChange are the two variables we need to check for;
* Since these variables are named differently in different browsers, this function sets
* the appropriate name based on the browser being used. Once executed, tha actual names of
* document.hidden and document.visibilityChange are found in this._hidden and this._visibilityChange
* respectively
* @private
*/
_initializeVisibilityVarNames () {
let hidden
let visibilityChange
if (typeof document.hidden !== 'undefined') { // Opera 12.10 and Firefox 18 and later support
hidden = 'hidden'
visibilityChange = 'visibilitychange'
} else if (typeof document.mozHidden !== 'undefined') {
hidden = 'mozHidden'
visibilityChange = 'mozvisibilitychange'
} else if (typeof document.msHidden !== 'undefined') {
hidden = 'msHidden'
visibilityChange = 'msvisibilitychange'
} else if (typeof document.webkitHidden !== 'undefined') {
hidden = 'webkitHidden'
visibilityChange = 'webkitvisibilitychange'
}
this._hidden = hidden
this._visibilityChange = visibilityChange
}
/**
* Adds an event listener on the document that listens to changes in document.visibilityChange
* (or whatever name by which the visibilityChange variable is known in the browser)
* @private
*/
_addVisibilityChangeListener () {
if (typeof document.addEventListener === 'undefined' ||
typeof document[this._hidden] === 'undefined') {
debug('Checking page visibility requires a browser that supports the Page Visibility API.')
} else {
// Handle page visibility change
document.addEventListener(this._visibilityChange, this._handleVisibilityChange.bind(this), false)
}
}
/**
* The function returns ```true``` if the page is visible or ```false``` if the page is not visible and
* ```undefined``` if the page visibility API is not supported by the browser.
* @returns {Boolean|void} whether the page is now visible or not (undefined is unknown)
*/
isVisible () {
if (this._hidden === undefined || document[this._hidden] === undefined) {
return undefined
}
return !document[this._hidden]
}
/**
* The function that is called when document.visibilityChange has changed
* It emits an event called visibilityChange and sends the value of document.hidden as a
* parameter
*
* @private
*/
_handleVisibilityChange () {
const visible = !document[this._hidden]
debug(visible ? 'Page Visible' : 'Page Hidden')
// Emit the event
this.emit('visibilityChange', visible)
}
}

View File

@@ -70,7 +70,7 @@ class Dialer {
async connectToPeer (peer, options = {}) {
const dialTarget = this._createDialTarget(peer)
if (dialTarget.addrs.length === 0) {
throw errCode(new Error('The dial request has no addresses'), 'ERR_NO_DIAL_MULTIADDRS')
throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES)
}
const pendingDial = this._pendingDials.get(dialTarget.id) || this._createPendingDial(dialTarget, options)
@@ -113,7 +113,7 @@ class Dialer {
}
const addrs = this.peerStore.multiaddrsForPeer(dialable)
return {
id: dialable.id.toString(),
id: dialable.id.toB58String(),
addrs
}
}
@@ -136,7 +136,7 @@ class Dialer {
*/
_createPendingDial (dialTarget, options) {
const dialAction = (addr, options) => {
if (options.signal.aborted) throw errCode(new Error('already aborted'), 'ERR_ALREADY_ABORTED')
if (options.signal.aborted) throw errCode(new Error('already aborted'), codes.ERR_ALREADY_ABORTED)
return this.transportManager.dial(addr, options)
}
@@ -197,8 +197,7 @@ class Dialer {
try {
peer = PeerId.createFromCID(peer.getPeerId())
} catch (err) {
// Couldn't get the PeerId, just use the address
return peer
throw errCode(new Error('The multiaddr did not contain a valid peer id'), codes.ERR_INVALID_PEER)
}
}

View File

@@ -12,6 +12,7 @@ exports.codes = {
ERR_CONNECTION_ENDED: 'ERR_CONNECTION_ENDED',
ERR_CONNECTION_FAILED: 'ERR_CONNECTION_FAILED',
ERR_NODE_NOT_STARTED: 'ERR_NODE_NOT_STARTED',
ERR_ALREADY_ABORTED: 'ERR_ALREADY_ABORTED',
ERR_NO_VALID_ADDRESSES: 'ERR_NO_VALID_ADDRESSES',
ERR_DISCOVERED_SELF: 'ERR_DISCOVERED_SELF',
ERR_DUPLICATE_TRANSPORT: 'ERR_DUPLICATE_TRANSPORT',
@@ -19,6 +20,7 @@ exports.codes = {
ERR_HOP_REQUEST_FAILED: 'ERR_HOP_REQUEST_FAILED',
ERR_INVALID_KEY: 'ERR_INVALID_KEY',
ERR_INVALID_MESSAGE: 'ERR_INVALID_MESSAGE',
ERR_INVALID_PARAMETERS: 'ERR_INVALID_PARAMETERS',
ERR_INVALID_PEER: 'ERR_INVALID_PEER',
ERR_MUXER_UNAVAILABLE: 'ERR_MUXER_UNAVAILABLE',
ERR_TIMEOUT: 'ERR_TIMEOUT',

View File

@@ -1,10 +1,11 @@
'use strict'
const { Buffer } = require('buffer')
const debug = require('debug')
const pb = require('it-protocol-buffers')
const lp = require('it-length-prefixed')
const pipe = require('it-pipe')
const { collect, take } = require('streaming-iterables')
const { collect, take, consume } = require('streaming-iterables')
const PeerInfo = require('peer-info')
const PeerId = require('peer-id')
@@ -114,7 +115,8 @@ class IdentifyService {
protocols: Array.from(this._protocols.keys())
}],
pb.encode(Message),
stream
stream,
consume
)
} catch (err) {
// Just log errors
@@ -153,6 +155,7 @@ class IdentifyService {
async identify (connection) {
const { stream } = await connection.newStream(MULTICODEC_IDENTIFY)
const [data] = await pipe(
[],
stream,
lp.decode(),
take(1),
@@ -180,7 +183,7 @@ class IdentifyService {
const id = await PeerId.createFromPubKey(publicKey)
const peerInfo = new PeerInfo(id)
if (connection.remotePeer.toString() !== id.toString()) {
if (connection.remotePeer.toB58String() !== id.toB58String()) {
throw errCode(new Error('identified peer does not match the expected peer'), codes.ERR_INVALID_PEER)
}
@@ -242,7 +245,8 @@ class IdentifyService {
pipe(
[message],
lp.encode(),
stream
stream,
consume
)
}
@@ -255,6 +259,7 @@ class IdentifyService {
*/
async _handlePush ({ connection, stream }) {
const [data] = await pipe(
[],
stream,
lp.decode(),
take(1),

View File

@@ -2,6 +2,7 @@
const { EventEmitter } = require('events')
const debug = require('debug')
const globalThis = require('ipfs-utils/src/globalthis')
const log = debug('libp2p')
log.error = debug('libp2p:error')
@@ -142,7 +143,7 @@ class Libp2p extends EventEmitter {
// Attach private network protector
if (this._modules.connProtector) {
this.upgrader.protector = this._modules.connProtector
} else if (process.env.LIBP2P_FORCE_PNET) {
} else if (globalThis.process !== undefined && globalThis.process.env && globalThis.process.env.LIBP2P_FORCE_PNET) {
throw new Error('Private network is enforced, but no protector was provided')
}
@@ -218,7 +219,16 @@ class Libp2p extends EventEmitter {
log('libp2p is stopping')
try {
for (const service of this._discovery.values()) {
service.removeListener('peer', this._onDiscoveryPeer)
}
await Promise.all(Array.from(this._discovery.values(), s => s.stop()))
this._discovery = new Map()
this.connectionManager.stop()
await Promise.all([
this.pubsub && this.pubsub.stop(),
this._dht && this._dht.stop(),
@@ -304,10 +314,17 @@ class Libp2p extends EventEmitter {
* @param {PeerInfo|PeerId|multiaddr|string} peer the peer to close connections to
* @returns {Promise<void>}
*/
hangUp (peer) {
async hangUp (peer) {
const peerInfo = getPeerInfo(peer, this.peerStore)
return Promise.all(
this.registrar.connections.get(peerInfo.id.toString()).map(connection => {
const connections = this.registrar.connections.get(peerInfo.id.toB58String())
if (!connections) {
return
}
await Promise.all(
connections.map(connection => {
return connection.close()
})
)
@@ -392,7 +409,7 @@ class Libp2p extends EventEmitter {
* Called when libp2p has started and before it returns
* @private
*/
_onDidStart () {
async _onDidStart () {
this._isStarted = true
this.connectionManager.start()
@@ -403,7 +420,7 @@ class Libp2p extends EventEmitter {
})
// Peer discovery
this._setupPeerDiscovery()
await this._setupPeerDiscovery()
// Once we start, emit and dial any peers we may have already discovered
for (const peerInfo of this.peerStore.peers.values()) {
@@ -419,7 +436,7 @@ class Libp2p extends EventEmitter {
* @param {PeerInfo} peerInfo
*/
_onDiscoveryPeer (peerInfo) {
if (peerInfo.id.toString() === this.peerInfo.id.toString()) {
if (peerInfo.id.toB58String() === this.peerInfo.id.toB58String()) {
log.error(new Error(codes.ERR_DISCOVERED_SELF))
return
}
@@ -438,7 +455,7 @@ class Libp2p extends EventEmitter {
if (this._config.peerDiscovery.autoDial === true && !this.registrar.getConnection(peerInfo)) {
const minPeers = this._options.connectionManager.minPeers || 0
if (minPeers > this.connectionManager._connections.size) {
log('connecting to discovered peer %s', peerInfo.id.toString())
log('connecting to discovered peer %s', peerInfo.id.toB58String())
try {
await this.dialer.connectToPeer(peerInfo)
} catch (err) {
@@ -451,10 +468,10 @@ class Libp2p extends EventEmitter {
/**
* Initializes and starts peer discovery services
*
* @async
* @private
* @returns {Promise<void>}
*/
_setupPeerDiscovery () {
async _setupPeerDiscovery () {
const setupService = (DiscoveryService) => {
let config = {
enabled: true // on by default
@@ -471,7 +488,7 @@ class Libp2p extends EventEmitter {
let discoveryService
if (typeof DiscoveryService === 'function') {
discoveryService = new DiscoveryService(Object.assign({}, config, { peerInfo: this.peerInfo }))
discoveryService = new DiscoveryService(Object.assign({}, config, { peerInfo: this.peerInfo, libp2p: this }))
} else {
discoveryService = DiscoveryService
}
@@ -493,18 +510,17 @@ class Libp2p extends EventEmitter {
}
}
return Promise.all(Array.from(this._discovery.values(), d => d.start()))
await Promise.all(Array.from(this._discovery.values(), d => d.start()))
}
}
module.exports = Libp2p
/**
* Like `new Libp2p(options)` except it will create a `PeerInfo`
* instance if one is not provided in options.
* @param {object} options Libp2p configuration options
* @returns {Libp2p}
*/
module.exports.create = async (options = {}) => {
Libp2p.create = async function create (options = {}) {
if (options.peerInfo) {
return new Libp2p(options)
}
@@ -514,3 +530,5 @@ module.exports.create = async (options = {}) => {
options.peerInfo = peerInfo
return new Libp2p(options)
}
module.exports = Libp2p

View File

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

View File

@@ -1,6 +1,6 @@
'use strict'
const assert = require('assert')
const errcode = require('err-code')
const debug = require('debug')
const log = debug('libp2p:peer-store')
log.error = debug('libp2p:peer-store:error')
@@ -9,6 +9,9 @@ const { EventEmitter } = require('events')
const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const {
ERR_INVALID_PARAMETERS
} = require('../errors')
/**
* Responsible for managing known peers, as well as their addresses and metadata
@@ -46,7 +49,9 @@ class PeerStore extends EventEmitter {
* @return {PeerInfo}
*/
put (peerInfo, options = { silent: false }) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
if (!PeerInfo.isPeerInfo(peerInfo)) {
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
}
let peer
// Already know the peer?
@@ -67,7 +72,9 @@ class PeerStore extends EventEmitter {
* @return {PeerInfo}
*/
add (peerInfo) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
if (!PeerInfo.isPeerInfo(peerInfo)) {
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
}
// Create new instance and add values to it
const newPeerInfo = new PeerInfo(peerInfo.id)
@@ -105,7 +112,10 @@ class PeerStore extends EventEmitter {
* @return {PeerInfo}
*/
update (peerInfo) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
if (!PeerInfo.isPeerInfo(peerInfo)) {
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
}
const id = peerInfo.id.toB58String()
const recorded = this.peers.get(id)
@@ -207,7 +217,9 @@ class PeerStore extends EventEmitter {
* @returns {void}
*/
replace (peerInfo) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
if (!PeerInfo.isPeerInfo(peerInfo)) {
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
}
this.remove(peerInfo.id.toB58String())
this.add(peerInfo)
@@ -224,12 +236,17 @@ class PeerStore extends EventEmitter {
}
/**
* Returns the known multiaddrs for a given `PeerInfo`
* Returns the known multiaddrs for a given `PeerInfo`. All returned multiaddrs
* will include the encapsulated `PeerId` of the peer.
* @param {PeerInfo} peer
* @returns {Array<Multiaddr>}
*/
multiaddrsForPeer (peer) {
return this.put(peer, true).multiaddrs.toArray()
return this.put(peer, true).multiaddrs.toArray().map(addr => {
const idString = addr.getPeerId()
if (idString && idString === peer.id.toB58String()) return addr
return addr.encapsulate(`/p2p/${peer.id.toB58String()}`)
})
}
}

View File

@@ -8,7 +8,7 @@ const errCode = require('err-code')
const crypto = require('libp2p-crypto')
const pipe = require('it-pipe')
const { toBuffer } = require('it-buffer')
const { collect } = require('streaming-iterables')
const { collect, take } = require('streaming-iterables')
const { PROTOCOL, PING_LENGTH } = require('./constants')
@@ -29,6 +29,7 @@ async function ping (node, peer) {
const [result] = await pipe(
[data],
stream,
stream => take(1, stream),
toBuffer,
collect
)

View File

@@ -1,5 +1,6 @@
'use strict'
const { Buffer } = require('buffer')
const debug = require('debug')
const Errors = require('./errors')
const xsalsa20 = require('xsalsa20')

View File

@@ -1,10 +1,13 @@
'use strict'
const pipe = require('it-pipe')
const assert = require('assert')
const errcode = require('err-code')
const duplexPair = require('it-pair/duplex')
const crypto = require('libp2p-crypto')
const Errors = require('./errors')
const {
ERR_INVALID_PARAMETERS
} = require('../errors')
const {
createBoxStream,
createUnboxStream,
@@ -40,7 +43,9 @@ class Protector {
* @returns {*} A protected duplex iterable
*/
async protect (connection) {
assert(connection, Errors.NO_HANDSHAKE_CONNECTION)
if (!connection) {
throw errcode(new Error(Errors.NO_HANDSHAKE_CONNECTION), ERR_INVALID_PARAMETERS)
}
// Exchange nonces
log('protecting the connection')

View File

@@ -1,6 +1,6 @@
'use strict'
const crypto = require('crypto')
const crypto = require('libp2p-crypto')
const KEY_LENGTH = 32
/**

View File

@@ -1,5 +1,6 @@
'use strict'
const { Buffer } = require('buffer')
const errCode = require('err-code')
const { messages, codes } = require('./errors')

View File

@@ -1,10 +1,13 @@
'use strict'
const assert = require('assert')
const debug = require('debug')
const errcode = require('err-code')
const log = debug('libp2p:peer-store')
log.error = debug('libp2p:peer-store:error')
const {
ERR_INVALID_PARAMETERS
} = require('./errors')
const Topology = require('libp2p-interfaces/src/topology')
const { Connection } = require('libp2p-interfaces/src/connection')
const PeerInfo = require('peer-info')
@@ -71,10 +74,15 @@ class Registrar {
* @returns {void}
*/
onConnect (peerInfo, conn) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
assert(Connection.isConnection(conn), 'conn must be an instance of interface-connection')
if (!PeerInfo.isPeerInfo(peerInfo)) {
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
}
const id = peerInfo.id.toString()
if (!Connection.isConnection(conn)) {
throw errcode(new Error('conn must be an instance of interface-connection'), ERR_INVALID_PARAMETERS)
}
const id = peerInfo.id.toB58String()
const storedConn = this.connections.get(id)
if (storedConn) {
@@ -93,20 +101,22 @@ class Registrar {
* @returns {void}
*/
onDisconnect (peerInfo, connection, error) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
if (!PeerInfo.isPeerInfo(peerInfo)) {
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
}
const id = peerInfo.id.toString()
const id = peerInfo.id.toB58String()
let storedConn = this.connections.get(id)
if (storedConn && storedConn.length > 1) {
storedConn = storedConn.filter((conn) => conn.id === connection.id)
storedConn = storedConn.filter((conn) => conn.id !== connection.id)
this.connections.set(id, storedConn)
} else if (storedConn) {
for (const [, topology] of this.topologies) {
topology.disconnect(peerInfo, error)
}
this.connections.delete(peerInfo.id.toString())
this.connections.delete(peerInfo.id.toB58String())
}
}
@@ -116,9 +126,11 @@ class Registrar {
* @returns {Connection}
*/
getConnection (peerInfo) {
assert(PeerInfo.isPeerInfo(peerInfo), 'peerInfo must be an instance of peer-info')
if (!PeerInfo.isPeerInfo(peerInfo)) {
throw errcode(new Error('peerInfo must be an instance of peer-info'), ERR_INVALID_PARAMETERS)
}
const connections = this.connections.get(peerInfo.id.toString())
const connections = this.connections.get(peerInfo.id.toB58String())
// Return the first, open connection
if (connections) {
return connections.find(connection => connection.stat.status === 'open')
@@ -132,9 +144,9 @@ class Registrar {
* @return {string} registrar identifier
*/
register (topology) {
assert(
Topology.isTopology(topology),
'topology must be an instance of interfaces/topology')
if (!Topology.isTopology(topology)) {
throw errcode(new Error('topology must be an instance of interfaces/topology'), ERR_INVALID_PARAMETERS)
}
// Create topology
const id = (parseInt(Math.random() * 1e9)).toString(36) + Date.now()

View File

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

View File

@@ -73,7 +73,7 @@ class Upgrader {
if (this.metrics) {
({ setTarget: setPeer, proxy: proxyPeer } = mutableProxy())
const idString = (parseInt(Math.random() * 1e9)).toString(36) + Date.now()
setPeer({ toString: () => idString })
setPeer({ toB58String: () => idString })
maConn = this.metrics.trackStream({ stream: maConn, remotePeer: proxyPeer })
}
@@ -147,7 +147,7 @@ class Upgrader {
if (this.metrics) {
({ setTarget: setPeer, proxy: proxyPeer } = mutableProxy())
const idString = (parseInt(Math.random() * 1e9)).toString(36) + Date.now()
setPeer({ toString: () => idString })
setPeer({ toB58String: () => idString })
maConn = this.metrics.trackStream({ stream: maConn, remotePeer: proxyPeer })
}
@@ -216,7 +216,10 @@ class Upgrader {
Muxer,
remotePeer
}) {
let muxer, newStream
let muxer
let newStream
// eslint-disable-next-line prefer-const
let connection
if (Muxer) {
// Create the muxer
@@ -228,7 +231,7 @@ class Upgrader {
const { stream, protocol } = await mss.handle(Array.from(this.protocols.keys()))
log('%s: incoming stream opened on %s', direction, protocol)
if (this.metrics) this.metrics.trackStream({ stream, remotePeer, protocol })
connection.addStream(stream, protocol)
connection.addStream(muxedStream, { protocol })
this._onStream({ connection, stream, protocol })
} catch (err) {
log.error(err)
@@ -250,7 +253,7 @@ class Upgrader {
return { stream: { ...muxedStream, ...stream }, protocol }
} catch (err) {
log.error('could not create new stream', err)
throw errCode(err, codes.ERR_UNSUPPORTED_PROTOCOL)
throw errCode(new Error('Could not create a new stream'), codes.ERR_UNSUPPORTED_PROTOCOL, { cause: err })
}
}
@@ -261,7 +264,7 @@ class Upgrader {
const _timeline = maConn.timeline
maConn.timeline = new Proxy(_timeline, {
set: (...args) => {
if (args[1] === 'close' && args[2] && !_timeline.close) {
if (connection && args[1] === 'close' && args[2] && !_timeline.close) {
connection.stat.status = 'closed'
this.onConnectionEnd(connection)
}
@@ -276,7 +279,7 @@ class Upgrader {
}
// Create the connection
const connection = new Connection({
connection = new Connection({
localAddr: maConn.localAddr,
remoteAddr: maConn.remoteAddr,
localPeer: this.localPeer,

View File

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

View File

@@ -155,10 +155,7 @@ describe('content-routing', () => {
const mockApi = nock('http://0.0.0.0:60197')
// mock the refs call
.post('/api/v0/refs')
.query({
recursive: false,
arg: cid.toBaseEncodedString()
})
.query(true)
.reply(200, null, [
'Content-Type', 'application/json',
'X-Chunked-Output', '1'
@@ -174,10 +171,7 @@ describe('content-routing', () => {
const mockApi = nock('http://0.0.0.0:60197')
// mock the refs call
.post('/api/v0/refs')
.query({
recursive: false,
arg: cid.toBaseEncodedString()
})
.query(true)
.reply(502, 'Bad Gateway', ['Content-Type', 'application/json'])
await expect(node.contentRouting.provide(cid))
@@ -192,9 +186,7 @@ describe('content-routing', () => {
const mockApi = nock('http://0.0.0.0:60197')
.post('/api/v0/dht/findprovs')
.query({
arg: cid.toBaseEncodedString()
})
.query(true)
.reply(200, `{"Extra":"","ID":"QmWKqWXCtRXEeCQTo3FoZ7g4AfnGiauYYiczvNxFCHicbB","Responses":[{"Addrs":["/ip4/0.0.0.0/tcp/0"],"ID":"${provider}"}],"Type":4}\n`, [
'Content-Type', 'application/json',
'X-Chunked-Output', '1'
@@ -214,9 +206,7 @@ describe('content-routing', () => {
const cid = new CID('QmU621oD8AhHw6t25vVyfYKmL9VV3PTgc52FngEhTGACFB')
const mockApi = nock('http://0.0.0.0:60197')
.post('/api/v0/dht/findprovs')
.query({
arg: cid.toBaseEncodedString()
})
.query(true)
.reply(502, 'Bad Gateway', [
'X-Chunked-Output', '1'
])

View File

@@ -1,6 +1,7 @@
'use strict'
/* eslint-env mocha */
const { Buffer } = require('buffer')
const chai = require('chai')
chai.use(require('dirty-chai'))
const { expect } = chai
@@ -43,7 +44,7 @@ describe('DHT subsystem operates correctly', () => {
remoteLibp2p.start()
])
remAddr = remoteLibp2p.transportManager.getAddrs()[0]
remAddr = libp2p.peerStore.multiaddrsForPeer(remotePeerInfo)[0]
})
afterEach(() => Promise.all([
@@ -98,7 +99,7 @@ describe('DHT subsystem operates correctly', () => {
await libp2p.start()
await remoteLibp2p.start()
remAddr = remoteLibp2p.transportManager.getAddrs()[0]
remAddr = libp2p.peerStore.multiaddrsForPeer(remotePeerInfo)[0]
})
afterEach(() => Promise.all([

View File

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

View File

@@ -6,9 +6,11 @@ chai.use(require('dirty-chai'))
const { expect } = chai
const pTimes = require('p-times')
const pipe = require('it-pipe')
const peerUtils = require('../utils/creators/peer')
const baseOptions = require('../utils/base-options')
const { PROTOCOL } = require('../../src/ping/constants')
describe('ping', () => {
let nodes
@@ -32,4 +34,40 @@ describe('ping', () => {
const averageLatency = latencies.reduce((p, c) => p + c, 0) / latencies.length
expect(averageLatency).to.be.a('Number')
})
it('only waits for the first response to arrive', async () => {
nodes[1].handle(PROTOCOL, async ({ connection, stream }) => {
let firstInvocation = true
await pipe(
stream,
function (stream) {
const output = {
[Symbol.asyncIterator]: () => output,
next: async () => {
if (firstInvocation) {
firstInvocation = false
for await (const data of stream) {
return {
value: data,
done: false
}
}
} else {
return new Promise() // never resolve
}
}
}
return output
},
stream
)
})
const latency = await nodes[0].ping(nodes[1].peerInfo)
expect(latency).to.be.a('Number')
})
})

View File

@@ -1,6 +1,7 @@
'use strict'
/* eslint-env mocha */
const { Buffer } = require('buffer')
const chai = require('chai')
chai.use(require('dirty-chai'))
chai.use(require('chai-as-promised'))
@@ -34,20 +35,25 @@ const Peers = require('../fixtures/peers')
const { createPeerInfo } = require('../utils/creators/peer')
const listenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
const unsupportedAddr = multiaddr('/ip4/127.0.0.1/tcp/9999/ws')
const unsupportedAddr = multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN')
describe('Dialing (direct, TCP)', () => {
let remoteTM
let localTM
let peerStore
let remoteAddr
before(async () => {
const [remotePeerId] = await Promise.all([
PeerId.createFromJSON(Peers[0])
])
remoteTM = new TransportManager({
libp2p: {},
upgrader: mockUpgrader
})
remoteTM.add(Transport.prototype[Symbol.toStringTag], Transport)
peerStore = new PeerStore()
localTM = new TransportManager({
libp2p: {},
upgrader: mockUpgrader
@@ -56,7 +62,7 @@ describe('Dialing (direct, TCP)', () => {
await remoteTM.listen([listenAddr])
remoteAddr = remoteTM.getAddrs()[0]
remoteAddr = remoteTM.getAddrs()[0].encapsulate(`/p2p/${remotePeerId.toB58String()}`)
})
after(() => remoteTM.close())
@@ -66,7 +72,7 @@ describe('Dialing (direct, TCP)', () => {
})
it('should be able to connect to a remote node via its multiaddr', async () => {
const dialer = new Dialer({ transportManager: localTM })
const dialer = new Dialer({ transportManager: localTM, peerStore })
const connection = await dialer.connectToPeer(remoteAddr)
expect(connection).to.exist()
@@ -74,7 +80,7 @@ describe('Dialing (direct, TCP)', () => {
})
it('should be able to connect to a remote node via its stringified multiaddr', async () => {
const dialer = new Dialer({ transportManager: localTM })
const dialer = new Dialer({ transportManager: localTM, peerStore })
const dialable = Dialer.getDialable(remoteAddr.toString())
const connection = await dialer.connectToPeer(dialable)
@@ -83,7 +89,7 @@ describe('Dialing (direct, TCP)', () => {
})
it('should fail to connect to an unsupported multiaddr', async () => {
const dialer = new Dialer({ transportManager: localTM })
const dialer = new Dialer({ transportManager: localTM, peerStore })
await expect(dialer.connectToPeer(unsupportedAddr))
.to.eventually.be.rejectedWith(AggregateError)
@@ -140,6 +146,7 @@ describe('Dialing (direct, TCP)', () => {
it('should abort dials on queue task timeout', async () => {
const dialer = new Dialer({
transportManager: localTM,
peerStore,
timeout: 50
})
sinon.stub(localTM, 'dial').callsFake(async (addr, options) => {
@@ -224,7 +231,7 @@ describe('Dialing (direct, TCP)', () => {
remoteLibp2p.handle('/echo/1.0.0', ({ stream }) => pipe(stream, stream))
await remoteLibp2p.start()
remoteAddr = remoteLibp2p.transportManager.getAddrs()[0]
remoteAddr = remoteLibp2p.transportManager.getAddrs()[0].encapsulate(`/p2p/${remotePeerId.toB58String()}`)
})
afterEach(async () => {
@@ -235,6 +242,28 @@ describe('Dialing (direct, TCP)', () => {
after(() => remoteLibp2p.stop())
it('should fail if no peer id is provided', async () => {
libp2p = new Libp2p({
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
}
})
sinon.spy(libp2p.dialer, 'connectToPeer')
try {
await libp2p.dial(remoteLibp2p.transportManager.getAddrs()[0])
} catch (err) {
expect(err).to.have.property('code', ErrorCodes.ERR_INVALID_PEER)
return
}
expect.fail('dial should have failed')
})
it('should use the dialer for connecting to a multiaddr', async () => {
libp2p = new Libp2p({
peerInfo,
@@ -267,10 +296,8 @@ describe('Dialing (direct, TCP)', () => {
})
sinon.spy(libp2p.dialer, 'connectToPeer')
const remotePeer = new PeerInfo(remoteLibp2p.peerInfo.id)
remotePeer.multiaddrs.add(remoteAddr)
const connection = await libp2p.dial(remotePeer)
const connection = await libp2p.dial(remotePeerInfo)
expect(connection).to.exist()
const { stream, protocol } = await connection.newStream('/echo/1.0.0')
expect(stream).to.exist()
@@ -306,7 +333,7 @@ describe('Dialing (direct, TCP)', () => {
}
})
const connection = await libp2p.dial(`${remoteAddr.toString()}/p2p/${remotePeerInfo.id.toString()}`)
const connection = await libp2p.dial(`${remoteAddr.toString()}`)
expect(connection).to.exist()
expect(connection.stat.timeline.close).to.not.exist()
await libp2p.hangUp(connection.remotePeer)
@@ -337,33 +364,6 @@ describe('Dialing (direct, TCP)', () => {
expect(libp2p.upgrader.protector.protect.callCount).to.equal(1)
})
it('should coalesce parallel dials to the same peer (no id in multiaddr)', async () => {
libp2p = new Libp2p({
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
}
})
const dials = 10
const dialResults = await Promise.all([...new Array(dials)].map((_, index) => {
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerInfo)
return libp2p.dial(remoteLibp2p.peerInfo.multiaddrs.toArray()[0])
}))
// All should succeed and we should have ten results
expect(dialResults).to.have.length(10)
for (const connection of dialResults) {
expect(Connection.isConnection(connection)).to.equal(true)
}
// We will have two connections, since the multiaddr dial doesn't have a peer id
expect(libp2p.connectionManager._connections.size).to.equal(2)
expect(remoteLibp2p.connectionManager._connections.size).to.equal(2)
})
it('should coalesce parallel dials to the same peer (id in multiaddr)', async () => {
libp2p = new Libp2p({
peerInfo,
@@ -375,7 +375,7 @@ describe('Dialing (direct, TCP)', () => {
})
const dials = 10
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerInfo.id.toString()}`)
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerInfo.id.toB58String()}`)
const dialResults = await Promise.all([...new Array(dials)].map((_, index) => {
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerInfo)
return libp2p.dial(fullAddress)
@@ -405,10 +405,9 @@ describe('Dialing (direct, TCP)', () => {
const error = new Error('Boom')
sinon.stub(libp2p.transportManager, 'dial').callsFake(() => Promise.reject(error))
const fullAddress = remoteAddr.encapsulate(`/p2p/${remoteLibp2p.peerInfo.id.toString()}`)
const dialResults = await pSettle([...new Array(dials)].map((_, index) => {
if (index % 2 === 0) return libp2p.dial(remoteLibp2p.peerInfo)
return libp2p.dial(fullAddress)
return libp2p.dial(remoteAddr)
}))
// All should succeed and we should have ten results

View File

@@ -21,6 +21,7 @@ const { AbortError } = require('libp2p-interfaces/src/transport/errors')
const { codes: ErrorCodes } = require('../../src/errors')
const Constants = require('../../src/constants')
const Dialer = require('../../src/dialer')
const PeerStore = require('../../src/peer-store')
const TransportManager = require('../../src/transport-manager')
const Libp2p = require('../../src')
@@ -29,13 +30,15 @@ const { MULTIADDRS_WEBSOCKETS } = require('../fixtures/browser')
const mockUpgrader = require('../utils/mockUpgrader')
const createMockConnection = require('../utils/mockConnection')
const { createPeerId } = require('../utils/creators/peer')
const unsupportedAddr = multiaddr('/ip4/127.0.0.1/tcp/9999/ws')
const unsupportedAddr = multiaddr('/ip4/127.0.0.1/tcp/9999/ws/p2p/QmckxVrJw1Yo8LqvmDJNUmdAsKtSbiKWmrXJFyKmUraBoN')
const remoteAddr = MULTIADDRS_WEBSOCKETS[0]
describe('Dialing (direct, WebSockets)', () => {
let localTM
let peerStore
before(() => {
peerStore = new PeerStore()
localTM = new TransportManager({
libp2p: {},
upgrader: mockUpgrader,
@@ -49,13 +52,13 @@ describe('Dialing (direct, WebSockets)', () => {
})
it('should have appropriate defaults', () => {
const dialer = new Dialer({ transportManager: localTM })
const dialer = new Dialer({ transportManager: localTM, peerStore })
expect(dialer.concurrency).to.equal(Constants.MAX_PARALLEL_DIALS)
expect(dialer.timeout).to.equal(Constants.DIAL_TIMEOUT)
})
it('should limit the number of tokens it provides', () => {
const dialer = new Dialer({ transportManager: localTM })
const dialer = new Dialer({ transportManager: localTM, peerStore })
const maxPerPeer = Constants.MAX_PER_PEER_DIALS
expect(dialer.tokens).to.have.length(Constants.MAX_PARALLEL_DIALS)
const tokens = dialer.getTokens(maxPerPeer + 1)
@@ -64,14 +67,14 @@ describe('Dialing (direct, WebSockets)', () => {
})
it('should not return tokens if non are left', () => {
const dialer = new Dialer({ transportManager: localTM })
const dialer = new Dialer({ transportManager: localTM, peerStore })
sinon.stub(dialer, 'tokens').value([])
const tokens = dialer.getTokens(1)
expect(tokens.length).to.equal(0)
})
it('should NOT be able to return a token twice', () => {
const dialer = new Dialer({ transportManager: localTM })
const dialer = new Dialer({ transportManager: localTM, peerStore })
const tokens = dialer.getTokens(1)
expect(tokens).to.have.length(1)
expect(dialer.tokens).to.have.length(Constants.MAX_PARALLEL_DIALS - 1)
@@ -107,7 +110,7 @@ describe('Dialing (direct, WebSockets)', () => {
})
it('should fail to connect to an unsupported multiaddr', async () => {
const dialer = new Dialer({ transportManager: localTM })
const dialer = new Dialer({ transportManager: localTM, peerStore })
await expect(dialer.connectToPeer(unsupportedAddr))
.to.eventually.be.rejectedWith(AggregateError)
@@ -368,6 +371,19 @@ describe('Dialing (direct, WebSockets)', () => {
expect(connection.stat.timeline.close).to.exist()
})
it('should be able to use hangup when no connection exists', async () => {
libp2p = new Libp2p({
peerInfo,
modules: {
transport: [Transport],
streamMuxer: [Muxer],
connEncryption: [Crypto]
}
})
await libp2p.hangUp(remoteAddr)
})
it('should abort pending dials on stop', async () => {
libp2p = new Libp2p({
peerInfo,

View File

@@ -1,6 +1,7 @@
'use strict'
/* eslint-env mocha */
const { Buffer } = require('buffer')
const chai = require('chai')
chai.use(require('dirty-chai'))
chai.use(require('chai-as-promised'))
@@ -59,11 +60,11 @@ describe('Dialing (via relay, TCP)', () => {
it('should be able to connect to a peer over a relay with active connections', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toString()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toString()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
const tcpAddrs = dstLibp2p.transportManager.getAddrs()
await dstLibp2p.transportManager.listen([multiaddr(`/p2p-circuit${relayAddr}/p2p/${relayIdString}`)])
@@ -94,11 +95,11 @@ describe('Dialing (via relay, TCP)', () => {
it('should fail to connect to a peer over a relay with inactive connections', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toString()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toString()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
await expect(srcLibp2p.dial(dialAddr))
.to.eventually.be.rejectedWith(AggregateError)
@@ -107,11 +108,11 @@ describe('Dialing (via relay, TCP)', () => {
it('should not stay connected to a relay when not already connected and HOP fails', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toString()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toString()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
await expect(srcLibp2p.dial(dialAddr))
.to.eventually.be.rejectedWith(AggregateError)
@@ -123,12 +124,11 @@ describe('Dialing (via relay, TCP)', () => {
})
it('dialer should stay connected to an already connected relay on hop failure', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toString()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const relayAddr = relayLibp2p.transportManager.getAddrs()[0].encapsulate(`/p2p/${relayIdString}`)
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toString()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
await srcLibp2p.dial(relayAddr)
@@ -142,16 +142,15 @@ describe('Dialing (via relay, TCP)', () => {
})
it('destination peer should stay connected to an already connected relay on hop failure', async () => {
const relayAddr = relayLibp2p.transportManager.getAddrs()[0]
const relayIdString = relayLibp2p.peerInfo.id.toString()
const relayIdString = relayLibp2p.peerInfo.id.toB58String()
const relayAddr = relayLibp2p.transportManager.getAddrs()[0].encapsulate(`/p2p/${relayIdString}`)
const dialAddr = relayAddr
.encapsulate(`/p2p/${relayIdString}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toString()}`)
.encapsulate(`/p2p-circuit/p2p/${dstLibp2p.peerInfo.id.toB58String()}`)
// Connect the destination peer and the relay
const tcpAddrs = dstLibp2p.transportManager.getAddrs()
await dstLibp2p.transportManager.listen([multiaddr(`/p2p-circuit${relayAddr}/p2p/${relayIdString}`)])
await dstLibp2p.transportManager.listen([multiaddr(`${relayAddr}/p2p-circuit`)])
expect(dstLibp2p.transportManager.getAddrs()).to.have.deep.members([...tcpAddrs, dialAddr.decapsulate('p2p')])
// Tamper with the our multiaddrs for the circuit message

View File

@@ -12,6 +12,7 @@ const PeerId = require('peer-id')
const PeerInfo = require('peer-info')
const duplexPair = require('it-pair/duplex')
const multiaddr = require('multiaddr')
const pWaitFor = require('p-wait-for')
const { codes: Errors } = require('../../src/errors')
const { IdentifyService, multicodecs } = require('../../src/identify')
@@ -84,7 +85,12 @@ describe('Identify', () => {
it('should throw if identified peer is the wrong peer', async () => {
const localIdentify = new IdentifyService({
peerInfo: localPeer,
protocols
protocols,
registrar: {
peerStore: {
replace: () => {}
}
}
})
const remoteIdentify = new IdentifyService({
peerInfo: remotePeer,
@@ -92,7 +98,7 @@ describe('Identify', () => {
})
const observedAddr = multiaddr('/ip4/127.0.0.1/tcp/1234')
const localConnectionMock = { newStream: () => {}, remotePeer }
const localConnectionMock = { newStream: () => {}, remotePeer: localPeer.id }
const remoteConnectionMock = { remoteAddr: observedAddr }
const [local, remote] = duplexPair()
@@ -198,16 +204,17 @@ describe('Identify', () => {
})
sinon.spy(libp2p.identifyService, 'identify')
sinon.spy(libp2p.peerStore, 'replace')
const peerStoreSpy = sinon.spy(libp2p.peerStore, 'replace')
const connection = await libp2p.dialer.connectToPeer(remoteAddr)
expect(connection).to.exist()
// Wait for nextTick to trigger the identify call
await delay(1)
expect(libp2p.identifyService.identify.callCount).to.equal(1)
await libp2p.identifyService.identify.firstCall.returnValue
expect(libp2p.peerStore.replace.callCount).to.equal(1)
// Wait for peer store to be updated
await pWaitFor(() => peerStoreSpy.callCount === 1)
expect(libp2p.identifyService.identify.callCount).to.equal(1)
// The connection should have no open streams
expect(connection.streams).to.have.length(0)
await connection.close()
})
@@ -242,6 +249,9 @@ describe('Identify', () => {
const results = await call.returnValue
expect(results.length).to.equal(1)
}
// Verify the streams close
await pWaitFor(() => connection.streams.length === 0)
})
})
})

View File

@@ -1,6 +1,7 @@
'use strict'
/* eslint-env mocha */
const { Buffer } = require('buffer')
const chai = require('chai')
chai.use(require('dirty-chai'))
const { expect } = chai

View File

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

View File

@@ -3,7 +3,8 @@
const chai = require('chai')
chai.use(require('dirty-chai'))
const { expect } = chai
const sinon = require('sinon')
const defer = require('p-defer')
const mergeOptions = require('merge-options')
@@ -32,6 +33,21 @@ describe('peer discovery scenarios', () => {
afterEach(async () => {
libp2p && await libp2p.stop()
})
it('should ignore self on discovery', async () => {
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerInfo,
modules: {
peerDiscovery: [MulticastDNS]
}
}))
await libp2p.start()
const discoverySpy = sinon.spy()
libp2p.on('peer:discovery', discoverySpy)
libp2p._discovery.get('mdns').emit('peer', libp2p.peerInfo)
expect(discoverySpy.called).to.eql(false)
})
it('bootstrap should discover all peers in the list', async () => {
const deferred = defer()
@@ -139,17 +155,21 @@ describe('peer discovery scenarios', () => {
},
dht: {
randomWalk: {
enabled: true,
enabled: false,
delay: 1000, // start the first query quickly
interval: 10000,
timeout: 1000
timeout: 5000
},
enabled: true
}
}
})
libp2p = new Libp2p(getConfig(peerInfo))
const localConfig = getConfig(peerInfo)
// Only run random walk on our local node
localConfig.config.dht.randomWalk.enabled = true
libp2p = new Libp2p(localConfig)
const remoteLibp2p1 = new Libp2p(getConfig(remotePeerInfo1))
const remoteLibp2p2 = new Libp2p(getConfig(remotePeerInfo2))
@@ -161,6 +181,7 @@ describe('peer discovery scenarios', () => {
})
await Promise.all([
libp2p.start(),
remoteLibp2p1.start(),
remoteLibp2p2.start()
])
@@ -173,8 +194,6 @@ describe('peer discovery scenarios', () => {
remoteLibp2p2.dial(remotePeerInfo1)
])
libp2p.start()
await deferred.promise
return Promise.all([
remoteLibp2p1.stop(),

View File

@@ -9,7 +9,6 @@ const sinon = require('sinon')
const defer = require('p-defer')
const mergeOptions = require('merge-options')
const MulticastDNS = require('libp2p-mdns')
const WebRTCStar = require('libp2p-webrtc-star')
const Libp2p = require('../../src')
@@ -50,20 +49,30 @@ describe('peer discovery', () => {
expect(spy.getCall(0).args).to.eql([remotePeerInfo])
})
it('should ignore self on discovery', async () => {
it('should stop discovery on libp2p start/stop', async () => {
const mockDiscovery = {
tag: 'mock',
start: () => {},
stop: () => {},
on: () => {},
removeListener: () => {}
}
const startSpy = sinon.spy(mockDiscovery, 'start')
const stopSpy = sinon.spy(mockDiscovery, 'stop')
libp2p = new Libp2p(mergeOptions(baseOptions, {
peerInfo,
modules: {
peerDiscovery: [MulticastDNS]
peerDiscovery: [mockDiscovery]
}
}))
await libp2p.start()
const discoverySpy = sinon.spy()
libp2p.on('peer:discovery', discoverySpy)
libp2p._discovery.get('mdns').emit('peer', libp2p.peerInfo)
expect(discoverySpy.called).to.eql(false)
expect(startSpy).to.have.property('callCount', 1)
expect(stopSpy).to.have.property('callCount', 0)
await libp2p.stop()
expect(startSpy).to.have.property('callCount', 1)
expect(stopSpy).to.have.property('callCount', 1)
})
})

View File

@@ -115,9 +115,7 @@ describe('peer-routing', () => {
const peerKey = 'QmTp9VkYvnHyrqKQuFPiuZkiX9gPcqj6x5LJ1rmWuSySnL'
const mockApi = nock('http://0.0.0.0:60197')
.post('/api/v0/dht/findpeer')
.query({
arg: peerKey
})
.query(true)
.reply(200, `{"Extra":"","ID":"some other id","Responses":null,"Type":0}\n{"Extra":"","ID":"","Responses":[{"Addrs":["/ip4/127.0.0.1/tcp/4001"],"ID":"${peerKey}"}],"Type":2}\n`, [
'Content-Type', 'application/json',
'X-Chunked-Output', '1'
@@ -133,9 +131,7 @@ describe('peer-routing', () => {
const peerKey = 'key of a peer not on the network'
const mockApi = nock('http://0.0.0.0:60197')
.post('/api/v0/dht/findpeer')
.query({
arg: peerKey
})
.query(true)
.reply(200, '{"Extra":"","ID":"some other id","Responses":null,"Type":6}\n{"Extra":"","ID":"yet another id","Responses":null,"Type":0}\n{"Extra":"routing:not found","ID":"","Responses":null,"Type":3}\n', [
'Content-Type', 'application/json',
'X-Chunked-Output', '1'
@@ -151,9 +147,7 @@ describe('peer-routing', () => {
const peerKey = 'key of a peer not on the network'
const mockApi = nock('http://0.0.0.0:60197')
.post('/api/v0/dht/findpeer')
.query({
arg: peerKey
})
.query(true)
.reply(502)
await expect(node.peerRouting.findPeer(peerKey))

View File

@@ -160,6 +160,27 @@ describe('peer-store', () => {
expect(removed).to.eql(true)
expect(peerStore.peers.size).to.equal(0)
})
it('should be able to get the multiaddrs for a peer', async () => {
const [peerInfo, relayInfo] = await peerUtils.createPeerInfo({ number: 2 })
const id = peerInfo.id
const ma1 = multiaddr('/ip4/127.0.0.1/tcp/4001')
const ma2 = multiaddr('/ip4/127.0.0.1/tcp/4002/ws')
const ma3 = multiaddr(`/ip4/127.0.0.1/tcp/4003/ws/p2p/${relayInfo.id.toB58String()}/p2p-circuit`)
peerInfo.multiaddrs.add(ma1)
peerInfo.multiaddrs.add(ma2)
peerInfo.multiaddrs.add(ma3)
const multiaddrs = peerStore.multiaddrsForPeer(peerInfo)
const expectedAddrs = [
ma1.encapsulate(`/p2p/${id.toB58String()}`),
ma2.encapsulate(`/p2p/${id.toB58String()}`),
ma3.encapsulate(`/p2p/${id.toB58String()}`)
]
expect(multiaddrs).to.eql(expectedAddrs)
})
})
describe('peer-store on discovery', () => {

View File

@@ -1,6 +1,7 @@
/* eslint-env mocha */
'use strict'
const { Buffer } = require('buffer')
const chai = require('chai')
const dirtyChai = require('dirty-chai')
chai.use(dirtyChai)

View File

@@ -26,7 +26,6 @@ const remoteListenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
describe('Pubsub subsystem is able to use different implementations', () => {
let peerInfo, remotePeerInfo
let libp2p, remoteLibp2p
let remAddr
beforeEach(async () => {
[peerInfo, remotePeerInfo] = await peerUtils.createPeerInfo({ number: 2 })
@@ -73,9 +72,8 @@ describe('Pubsub subsystem is able to use different implementations', () => {
])
const libp2pId = libp2p.peerInfo.id.toB58String()
remAddr = remoteLibp2p.transportManager.getAddrs()[0]
const connection = await libp2p.dialProtocol(remAddr, multicodec)
const connection = await libp2p.dialProtocol(remotePeerInfo, multicodec)
expect(connection).to.exist()
libp2p.pubsub.subscribe(topic, (msg) => {

View File

@@ -21,7 +21,6 @@ const remoteListenAddr = multiaddr('/ip4/127.0.0.1/tcp/0')
describe('Pubsub subsystem operates correctly', () => {
let peerInfo, remotePeerInfo
let libp2p, remoteLibp2p
let remAddr
beforeEach(async () => {
[peerInfo, remotePeerInfo] = await peerUtils.createPeerInfo({ number: 2 })
@@ -44,8 +43,6 @@ describe('Pubsub subsystem operates correctly', () => {
libp2p.start(),
remoteLibp2p.start()
])
remAddr = remoteLibp2p.transportManager.getAddrs()[0]
})
afterEach(() => Promise.all([
@@ -58,7 +55,7 @@ describe('Pubsub subsystem operates correctly', () => {
})
it('should get notified of connected peers on dial', async () => {
const connection = await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
const connection = await libp2p.dialProtocol(remotePeerInfo, subsystemMulticodecs)
expect(connection).to.exist()
@@ -74,7 +71,7 @@ describe('Pubsub subsystem operates correctly', () => {
const data = 'hey!'
const libp2pId = libp2p.peerInfo.id.toB58String()
await libp2p.dialProtocol(remAddr, subsystemMulticodecs)
await libp2p.dialProtocol(remotePeerInfo, subsystemMulticodecs)
let subscribedTopics = libp2p.pubsub.getTopics()
expect(subscribedTopics).to.not.include(topic)
@@ -115,8 +112,6 @@ describe('Pubsub subsystem operates correctly', () => {
await libp2p.start()
await remoteLibp2p.start()
remAddr = remoteLibp2p.transportManager.getAddrs()[0]
})
afterEach(() => Promise.all([
@@ -129,7 +124,7 @@ describe('Pubsub subsystem operates correctly', () => {
})
it('should get notified of connected peers after starting', async () => {
const connection = await libp2p.dial(remAddr)
const connection = await libp2p.dial(remotePeerInfo)
expect(connection).to.exist()
expect(libp2p.pubsub._pubsub.peers.size).to.be.eql(0)
@@ -150,7 +145,7 @@ describe('Pubsub subsystem operates correctly', () => {
const topic = 'test-topic'
const data = 'hey!'
await libp2p.dial(remAddr)
await libp2p.dial(remotePeerInfo)
remoteLibp2p.pubsub.start()

View File

@@ -29,7 +29,7 @@ describe('registrar on dial', () => {
}))
await remoteLibp2p.transportManager.listen([listenAddr])
remoteAddr = remoteLibp2p.transportManager.getAddrs()[0]
remoteAddr = remoteLibp2p.transportManager.getAddrs()[0].encapsulate(`/p2p/${remotePeerInfo.id.toB58String()}`)
})
after(async () => {

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
'use strict'
/* eslint-env mocha */
const { Buffer } = require('buffer')
const chai = require('chai')
chai.use(require('dirty-chai'))
const { expect } = chai
@@ -338,6 +339,7 @@ describe('Upgrader', () => {
results.forEach(result => {
expect(result.isRejected).to.equal(true)
expect(result.reason.code).to.equal(codes.ERR_UNSUPPORTED_PROTOCOL)
expect(result.reason.cause).to.exist()
})
})
})