Compare commits

...

69 Commits

Author SHA1 Message Date
Vasco Santos
d76356e56a chore: release version v0.31.0 2021-04-28 15:39:48 +02:00
Vasco Santos
e9543eb2e1 chore: update contributors 2021-04-28 15:39:48 +02:00
Vasco Santos
5282708263 chore: release version v0.31.0-rc.7 2021-04-27 17:18:12 +02:00
Vasco Santos
ed494f03ae chore: update contributors 2021-04-27 17:18:12 +02:00
Vasco Santos
ac370fc967 fix: address book guarantees no replicated entries are added (#927) 2021-04-27 17:14:48 +02:00
Vasco Santos
ef4393649f chore: remove chai deps (#929) 2021-04-27 17:13:34 +02:00
Vasco Santos
f23fd4b7c7 chore: update noise (#926) 2021-04-27 13:24:31 +02:00
Vasco Santos
5372f7af2f chore: release version v0.31.0-rc.6 2021-04-22 10:09:18 +02:00
Vasco Santos
97da0ba740 chore: update contributors 2021-04-22 10:09:18 +02:00
Vasco Santos
88b04156bf fix: keychain optional pw and use interfaces for validators and selectors instead (#924) 2021-04-22 09:53:55 +02:00
Vasco Santos
64f3af897b chore: release version v0.31.0-rc.5 2021-04-21 15:01:31 +02:00
Vasco Santos
54e502afcb chore: update contributors 2021-04-21 15:01:31 +02:00
Alex Potsides
086b0ec0df fix: demand pubsub subclass instead of pubsub instance (#922)
Changes the `Libp2pModules.pubsub` property to be a class that maybe
extends `PubsubBaseProtocol` instead of an instance of that class.
2021-04-21 14:55:21 +02:00
Vasco Santos
cc1f4af879 fix: dht configuration selectors and validators (#919) 2021-04-21 13:28:37 +02:00
Franck Royer
6456a0fff8 chore: browser example dependencies must be installed at the root first (#921)
Fixes #920
2021-04-21 10:45:50 +02:00
Vasco Santos
44463b9145 fix: address book should not emit peer event if no addresses are known #887 2021-04-21 09:14:01 +02:00
Vasco Santos
7eb2cea570 chore: release version v0.31.0-rc.4 2021-04-20 17:14:17 +02:00
Vasco Santos
c381be3510 chore: update contributors 2021-04-20 17:14:16 +02:00
Alex Potsides
975e77991e fix: add clientMode dht arg and upgrade interface-datastore (#918) 2021-04-20 17:11:23 +02:00
Vasco Santos
b043bca607 fix: specify pbjs root (#917) 2021-04-20 16:25:48 +02:00
Vasco Santos
3ffeb4ebe6 chore: apply suggestions from code review
Co-authored-by: Irakli Gozalishvili <contact@gozala.io>
2021-04-20 11:41:50 +02:00
Vasco Santos
06e8f3dd42 fix: do not add abort signals to useless addresses (#913) 2021-04-20 09:31:16 +02:00
Vasco Santos
3f7dde3e13 chore: release version v0.31.0-rc.3 2021-04-19 14:12:25 +02:00
Vasco Santos
6f4e7ceeac chore: update contributors 2021-04-19 14:12:25 +02:00
Alex Potsides
2af692fb4d fix: remove inline arg types from function definitions (#916)
Co-authored-by: Vasco Santos <vasco.santos@moxy.studio>
2021-04-19 14:08:00 +02:00
Vasco Santos
906315ce73 chore: release version v0.31.0-rc.2 2021-04-16 17:12:57 +02:00
Vasco Santos
49f04cbe70 chore: update contributors 2021-04-16 17:12:57 +02:00
Alex Potsides
3d0a79eff3 fix: metrics stats and moving averages types (#915)
* fix: give stats initial values

Otherwise the compiler cannot derive the type and thinks `stats.snapshot` returns `{}`

* fix: add type shape to moving averages as well
2021-04-16 17:10:22 +02:00
Vasco Santos
55ee332907 chore: release version v0.31.0-rc.1 2021-04-16 15:55:22 +02:00
Vasco Santos
ffe122d47e chore: update contributors 2021-04-16 15:55:22 +02:00
Vasco Santos
21c9aeecb1 fix: dial protocol should throw if no protocol is provided (#914)
BREAKING CHANGE: dialProtocol does not return connection when no protocols are provided
2021-04-16 15:49:57 +02:00
Vasco Santos
a93cca9178 chore: update release template with examples testing (#911) 2021-04-16 09:27:44 +02:00
Vasco Santos
828a32d4f5 chore: add jsdoc 2021-04-15 14:38:25 +02:00
Vasco Santos
b4fb9b7bf2 fix: address book should not emit peer event if no addresses are known 2021-04-15 14:19:59 +02:00
Vasco Santos
0aed9fe1b3 chore: release version v0.31.0-rc.0 2021-04-15 09:52:56 +02:00
Vasco Santos
9d1b917e8a chore: update contributors 2021-04-15 09:52:55 +02:00
Vasco Santos
8506414ea1 chore: config types and dependencies update (#904)
BREAKING CHANGES:

top level types were updated, multiaddr@9.0.0 is used, dialer and keychain internal property names changed and connectionManager minPeers is not supported anymore
2021-04-15 09:40:02 +02:00
Vasco Santos
8e1743cac4 chore: release version v0.30.12 2021-03-27 13:43:36 +01:00
Vasco Santos
3ea95ce642 chore: update contributors 2021-03-27 13:43:35 +01:00
Alex Potsides
c4cae29ef3 chore: do not look up external IP during test (#906)
The NAT manager test will throw if the current computer is behind a
double NAT as at runtime it won't be possible to map external ports.

We don't care about that during the test so configure a fake external
IP so the test will still test the shut-down functionality on a computer
that is behind a double NAT.
2021-03-27 13:15:35 +01:00
Alex Potsides
a7128f07ec fix: the API of es6-promisify is not the same as promisify-es6 (#905) 2021-03-26 18:13:07 +01:00
Vasco Santos
c3e147df6b chore: delegates config md properties for client (#903) 2021-03-24 09:35:17 +01:00
Vasco Santos
b89445274d chore: release version v0.30.11 2021-03-23 09:51:32 +01:00
Vasco Santos
b9e3bcd91e chore: update contributors 2021-03-23 09:51:32 +01:00
Vasco Santos
f5c1cd1fb0 fix: interface-datastore update 2021-03-23 09:39:28 +01:00
Vasco Santos
975e4b0fe0 chore: increase bundle size 2021-03-23 09:39:28 +01:00
Vasco Santos
9504f1951a fix: connection direction should be only inbound or outbound 2021-03-23 09:39:28 +01:00
Vasco Santos
8e1fc78353 chore: release version v0.30.10 2021-03-09 18:52:37 +01:00
Vasco Santos
8895a092b6 chore: update contributors 2021-03-09 18:52:37 +01:00
TJKoury
f2f361998d chore: swap promisify to maintained package (#896)
Co-authored-by: Vasco Santos <vasco.santos@moxy.studio>
2021-03-09 16:55:38 +01:00
Vasco Santos
5f702f3481 fix: conn mgr access to moving averages record object (#897)
* fix: conn mgr access to moving averages record object

* chore: remove node 12

* chore: add parcel workaround
2021-03-09 16:51:41 +01:00
Philipp Muens
03b34cac7d docs: fix link to connection encryption example (#894) 2021-03-02 13:07:52 +01:00
Aleksei
9c67364caa Add an example of webrtc-direct (#868)
Co-authored-by: Vasco Santos <vasco.santos@moxy.studio>
2021-02-25 16:34:02 +01:00
Vasco Santos
a1424826e7 chore: release version v0.30.9 2021-02-25 15:31:26 +01:00
Vasco Santos
3d5bba070b chore: update contributors 2021-02-25 15:31:26 +01:00
Vasco Santos
3f314d5e90 fix: transport manager fault tolerance should include tolerance to transport listen fail (#893) 2021-02-25 15:23:07 +01:00
Miguel Mota
4ee3e1973b chore: minor grammar fixes on discovery example (#890) 2021-02-18 11:36:35 +01:00
Vasco Santos
fc6558b897 chore: release version v0.30.8 2021-02-11 14:57:43 +01:00
Vasco Santos
3e302570e5 chore: update contributors 2021-02-11 14:57:43 +01:00
Vasco Santos
a34d2bbcc3 fix: routers should only use dht if enabled (#885) 2021-02-11 14:37:34 +01:00
Vasco Santos
9941414a91 chore: update delegates config docs to use http client (#853) 2021-02-11 11:42:10 +01:00
Vasco Santos
46cb46188a chore: add discovery example with relay and pubsub discovery (#855) 2021-02-11 11:37:11 +01:00
Vasco Santos
1af8472dc6 chore: add transports example (#851) 2021-02-11 11:12:23 +01:00
Vasco Santos
f6a4cad827 chore: add pubsub example tests (#850) 2021-02-10 21:00:40 +01:00
Vasco Santos
b1079474de chore: add protocol and stream muxing example tests (#849) 2021-02-10 15:40:19 +01:00
Vasco Santos
a150ea60c5 chore: add peer and content routing example tests (#848) 2021-02-08 11:03:42 +01:00
Vasco Santos
aec8e3d3bb chore: release version v0.30.7 2021-02-01 18:40:05 +01:00
Vasco Santos
3abf4aeb35 chore: update contributors 2021-02-01 18:40:05 +01:00
Alex Potsides
a36b2112aa fix: do not add observed address received from peers (#882) 2021-02-01 18:32:57 +01:00
146 changed files with 6013 additions and 903 deletions

View File

@@ -1,5 +1,6 @@
'use strict'
const path = require('path')
const Libp2p = require('./src')
const { MULTIADDRS_WEBSOCKETS } = require('./test/fixtures/browser')
const Peers = require('./test/fixtures/peers')
@@ -47,16 +48,23 @@ const after = async () => {
await libp2p.stop()
}
/** @type {import('aegir').Options["build"]["config"]} */
const esbuild = {
inject: [path.join(__dirname, './scripts/node-globals.js')]
}
/** @type {import('aegir').PartialOptions} */
module.exports = {
bundlesize: { maxSize: '215kB' },
hooks: {
pre: before,
post: after
build: {
bundlesizeMax: '253kB'
},
webpack: {
node: {
// needed by bcrypto
Buffer: true
test: {
before,
after,
browser: {
config: {
buildConfig: esbuild
}
}
}
}

102
.github/workflows/examples.yml vendored Normal file
View File

@@ -0,0 +1,102 @@
name: examples
on:
push:
branches:
- master
pull_request:
branches:
- '**'
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: npx aegir lint
- run: npx aegir ts -p check
- run: npx aegir build
test-auto-relay-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- auto-relay
test-chat-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- chat
test-connection-encryption-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- connection-encryption
test-discovery-mechanisms-example:
needs: check
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- discovery-mechanisms
test-echo-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- echo
test-libp2p-in-the-browser-example:
needs: check
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- libp2p-in-the-browser
test-peer-and-content-routing-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- peer-and-content-routing
test-pnet-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- pnet
test-protocol-and-stream-muxing-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- protocol-and-stream-muxing
test-pubsub-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- pubsub
test-transports-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- transports
test-webrtc-direct-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: cd examples && yarn && npm run test -- webrtc-direct

View File

@@ -12,11 +12,11 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: yarn lint
- run: npm install
- run: npx aegir lint
- uses: gozala/typescript-error-reporter-action@v1.0.8
- run: yarn build
- run: yarn aegir dep-check
- run: npx aegir build
- run: npx aegir dep-check
- uses: ipfs/aegir/actions/bundle-size@master
name: size
with:
@@ -27,83 +27,41 @@ jobs:
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
node: [12, 14]
node: [14]
fail-fast: true
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
- run: yarn
- run: npx nyc --reporter=lcov aegir test -t node -- --bail
- run: npm install
- run: npx aegir test -t node --cov --bail
- uses: codecov/codecov-action@v1
test-chrome:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: npm install
- run: npx aegir test -t browser -t webworker --bail
test-firefox:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: npx aegir test -t browser -t webworker --bail -- --browsers FirefoxHeadless
- run: npm install
- run: npx aegir test -t browser -t webworker --bail -- --browser firefox
test-ts:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: npm run test:ts
test-interop:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: npm install
- run: cd node_modules/interop-libp2p && yarn && LIBP2P_JS=${GITHUB_WORKSPACE}/src/index.js npx aegir test -t node --bail
test-auto-relay-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- auto-relay
test-chat-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- chat
test-connection-encryption-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- connection-encryption
test-echo-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- echo
test-libp2p-in-the-browser-example:
needs: check
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- libp2p-in-the-browser
test-discovery-mechanisms-example:
needs: check
runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- discovery-mechanisms
test-pnet-example:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: yarn
- run: cd examples && yarn && npm run test -- pnet

1
.gitignore vendored
View File

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

View File

@@ -1,3 +1,138 @@
# [0.31.0](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.7...v0.31.0) (2021-04-28)
# [0.31.0-rc.7](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.6...v0.31.0-rc.7) (2021-04-27)
### Bug Fixes
* address book guarantees no replicated entries are added ([#927](https://github.com/libp2p/js-libp2p/issues/927)) ([ac370fc](https://github.com/libp2p/js-libp2p/commit/ac370fc9679b51da8cee3791b6dd268d0695d136))
# [0.31.0-rc.6](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.5...v0.31.0-rc.6) (2021-04-22)
### Bug Fixes
* keychain optional pw and use interfaces for validators and selectors instead ([#924](https://github.com/libp2p/js-libp2p/issues/924)) ([88b0415](https://github.com/libp2p/js-libp2p/commit/88b04156bf614650c2b14d49b12e969c5eecf04d))
# [0.31.0-rc.5](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.4...v0.31.0-rc.5) (2021-04-21)
### Bug Fixes
* address book should not emit peer event if no addresses are known ([b4fb9b7](https://github.com/libp2p/js-libp2p/commit/b4fb9b7bf266ba03c4462c0a41b1c2691e4e88d4))
* demand pubsub subclass instead of pubsub instance ([#922](https://github.com/libp2p/js-libp2p/issues/922)) ([086b0ec](https://github.com/libp2p/js-libp2p/commit/086b0ec0df2fac93845d0a0a6b2e2464e869afcd))
* dht configuration selectors and validators ([#919](https://github.com/libp2p/js-libp2p/issues/919)) ([cc1f4af](https://github.com/libp2p/js-libp2p/commit/cc1f4af879a58e94538591851d0085ff98cd2641))
# [0.31.0-rc.4](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.3...v0.31.0-rc.4) (2021-04-20)
### Bug Fixes
* add clientMode dht arg and upgrade interface-datastore ([#918](https://github.com/libp2p/js-libp2p/issues/918)) ([975e779](https://github.com/libp2p/js-libp2p/commit/975e77991e67dd9bff790b83df7bd6fa5ddcfc67))
* do not add abort signals to useless addresses ([#913](https://github.com/libp2p/js-libp2p/issues/913)) ([06e8f3d](https://github.com/libp2p/js-libp2p/commit/06e8f3dd42432e4b37ab7904b02abde7d1cadda3))
* specify pbjs root ([#917](https://github.com/libp2p/js-libp2p/issues/917)) ([b043bca](https://github.com/libp2p/js-libp2p/commit/b043bca607565cf534771e6cf975288a8ff3030b))
# [0.31.0-rc.3](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.2...v0.31.0-rc.3) (2021-04-19)
### Bug Fixes
* remove inline arg types from function definitions ([#916](https://github.com/libp2p/js-libp2p/issues/916)) ([2af692f](https://github.com/libp2p/js-libp2p/commit/2af692fb4de572168524ae684608fc6526de4ef7))
# [0.31.0-rc.2](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.1...v0.31.0-rc.2) (2021-04-16)
### Bug Fixes
* metrics stats and moving averages types ([#915](https://github.com/libp2p/js-libp2p/issues/915)) ([3d0a79e](https://github.com/libp2p/js-libp2p/commit/3d0a79eff3bc34a5bdc8ffa31e9b09345a02ad9d))
# [0.31.0-rc.1](https://github.com/libp2p/js-libp2p/compare/v0.31.0-rc.0...v0.31.0-rc.1) (2021-04-16)
### Bug Fixes
* dial protocol should throw if no protocol is provided ([#914](https://github.com/libp2p/js-libp2p/issues/914)) ([21c9aee](https://github.com/libp2p/js-libp2p/commit/21c9aeecb13440238aa6b0fb5a6731d2f87d4938))
### BREAKING CHANGES
* dialProtocol does not return connection when no protocols are provided
# [0.31.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.30.12...v0.31.0-rc.0) (2021-04-15)
## [0.30.12](https://github.com/libp2p/js-libp2p/compare/v0.30.11...v0.30.12) (2021-03-27)
### Bug Fixes
* the API of es6-promisify is not the same as promisify-es6 ([#905](https://github.com/libp2p/js-libp2p/issues/905)) ([a7128f0](https://github.com/libp2p/js-libp2p/commit/a7128f07ec8d4b729145ecfc6ad1d585ffddea46))
## [0.30.11](https://github.com/libp2p/js-libp2p/compare/v0.30.10...v0.30.11) (2021-03-23)
### Bug Fixes
* connection direction should be only inbound or outbound ([9504f19](https://github.com/libp2p/js-libp2p/commit/9504f1951a3cca55bb7b4e25e4934e4024034ee8))
* interface-datastore update ([f5c1cd1](https://github.com/libp2p/js-libp2p/commit/f5c1cd1fb07bc73cf9d9da3c2eb4327bed4279a4))
## [0.30.10](https://github.com/libp2p/js-libp2p/compare/v0.30.9...v0.30.10) (2021-03-09)
### Bug Fixes
* conn mgr access to moving averages record object ([#897](https://github.com/libp2p/js-libp2p/issues/897)) ([5f702f3](https://github.com/libp2p/js-libp2p/commit/5f702f3481afd4ad4fbc89f0e9b75a6d56b03520))
## [0.30.9](https://github.com/libp2p/js-libp2p/compare/v0.30.8...v0.30.9) (2021-02-25)
### Bug Fixes
* transport manager fault tolerance should include tolerance to transport listen fail ([#893](https://github.com/libp2p/js-libp2p/issues/893)) ([3f314d5](https://github.com/libp2p/js-libp2p/commit/3f314d5e90f74583b721386d0c9c5d8363cd4de7))
## [0.30.8](https://github.com/libp2p/js-libp2p/compare/v0.30.7...v0.30.8) (2021-02-11)
### Bug Fixes
* routers should only use dht if enabled ([#885](https://github.com/libp2p/js-libp2p/issues/885)) ([a34d2bb](https://github.com/libp2p/js-libp2p/commit/a34d2bbcc3d69ec3006137a909a7e8c53b9d378e))
## [0.30.7](https://github.com/libp2p/js-libp2p/compare/v0.30.6...v0.30.7) (2021-02-01)
### Bug Fixes
* do not add observed address received from peers ([#882](https://github.com/libp2p/js-libp2p/issues/882)) ([a36b211](https://github.com/libp2p/js-libp2p/commit/a36b2112aafcee309a02de0cff5440cf69cd53a7))
## [0.30.6](https://github.com/libp2p/js-libp2p/compare/v0.30.5...v0.30.6) (2021-01-29)

View File

@@ -25,7 +25,6 @@
- [ ] [js-ipfs](https://github.com/ipfs/js-ipfs)
- Documentation
- [ ] Ensure that README.md is up to date
- [ ] Ensure that all the examples run
- [ ] Ensure [libp2p/js-libp2p-examples](https://github.com/libp2p/js-libp2p-examples) is updated
- [ ] Ensure that [libp2p/docs](https://github.com/libp2p/docs) is updated
- Communication

View File

@@ -391,6 +391,7 @@ const Libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const MPLEX = require('libp2p-mplex')
const { NOISE } = require('libp2p-noise')
const ipfsHttpClient = require('ipfs-http-client')
const DelegatedPeerRouter = require('libp2p-delegated-peer-routing')
const DelegatedContentRouter = require('libp2p-delegated-content-routing')
const PeerId = require('peer-id')
@@ -398,17 +399,25 @@ const PeerId = require('peer-id')
// create a peerId
const peerId = await PeerId.create()
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient({
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
protocol: 'https',
port: 443
}))
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient({
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
protocol: 'https',
port: 443
}))
const node = await Libp2p.create({
modules: {
transport: [TCP],
streamMuxer: [MPLEX],
connEncryption: [NOISE],
contentRouting: [
new DelegatedContentRouter(peerId)
],
peerRouting: [
new DelegatedPeerRouter()
],
contentRouting: [delegatedContentRouting],
peerRouting: [delegatedPeerRouting],
},
peerId,
peerRouting: { // Peer routing configuration
@@ -590,7 +599,7 @@ const TCP = require('libp2p-tcp')
const MPLEX = require('libp2p-mplex')
const { NOISE } = require('libp2p-noise')
const { FaultTolerance } = require('libp2p/src/transport-manager')}
const { FaultTolerance } = require('libp2p/src/transport-manager')
const node = await Libp2p.create({
modules: {

View File

@@ -8,7 +8,7 @@ Let us know if you find any issues, or if you want to contribute and add a new t
- [Transports](./transports)
- [Protocol and Stream Muxing](./protocol-and-stream-muxing)
- [Encrypted Communications](./encrypted-communications)
- [Connection Encryption](./connection-encryption)
- [Discovery Mechanisms](./discovery-mechanisms)
- [Peer and Content Routing](./peer-and-content-routing)
- [PubSub](./pubsub)

View File

@@ -0,0 +1,68 @@
/* eslint-disable no-console */
'use strict'
const Libp2p = require('../../')
const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex')
const { NOISE } = require('libp2p-noise')
const Gossipsub = require('libp2p-gossipsub')
const Bootstrap = require('libp2p-bootstrap')
const PubsubPeerDiscovery = require('libp2p-pubsub-peer-discovery')
const createRelayServer = require('libp2p-relay-server')
const createNode = async (bootstrapers) => {
const node = await Libp2p.create({
addresses: {
listen: ['/ip4/0.0.0.0/tcp/0']
},
modules: {
transport: [TCP],
streamMuxer: [Mplex],
connEncryption: [NOISE],
pubsub: Gossipsub,
peerDiscovery: [Bootstrap, PubsubPeerDiscovery]
},
config: {
peerDiscovery: {
[PubsubPeerDiscovery.tag]: {
interval: 1000,
enabled: true
},
[Bootstrap.tag]: {
enabled: true,
list: bootstrapers
}
}
}
})
return node
}
;(async () => {
const relay = await createRelayServer({
listenAddresses: ['/ip4/0.0.0.0/tcp/0']
})
console.log(`libp2p relay starting with id: ${relay.peerId.toB58String()}`)
await relay.start()
const relayMultiaddrs = relay.multiaddrs.map((m) => `${m.toString()}/p2p/${relay.peerId.toB58String()}`)
const [node1, node2] = await Promise.all([
createNode(relayMultiaddrs),
createNode(relayMultiaddrs)
])
node1.on('peer:discovery', (peerId) => {
console.log(`Peer ${node1.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
})
node2.on('peer:discovery', (peerId) => {
console.log(`Peer ${node2.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
})
;[node1, node2].forEach((node, index) => console.log(`Node ${index} starting with id: ${node.peerId.toB58String()}`))
await Promise.all([
node1.start(),
node2.start()
])
})();

View File

@@ -2,13 +2,13 @@
A Peer Discovery module enables libp2p to find peers to connect to. Think of these mechanisms as ways to join the rest of the network, as railing points.
With these system, a libp2p node can both have a set of nodes to always connect on boot (bootstraper nodes), discover nodes through locality (e.g connected in the same LAN) or through serendipity (random walks on a DHT).
With this system, a libp2p node can both have a set of nodes to always connect on boot (bootstraper nodes), discover nodes through locality (e.g connected in the same LAN) or through serendipity (random walks on a DHT).
These mechanisms save configuration and enable a node to operate without any explicit dials, it will just work. Once new peers are discovered, their known data is stored in the peer's PeerStore.
## 1. Bootstrap list of Peers when booting a node
For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, mplex and NOISE. You can see the complete example at [1.js](./1.js).
For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, mplex, and NOISE. You can see the complete example at [1.js](./1.js).
First, we create our libp2p node.
@@ -16,7 +16,7 @@ First, we create our libp2p node.
const Libp2p = require('libp2p')
const Bootstrap = require('libp2p-bootstrap')
const node = Libp2p.create({
const node = await Libp2p.create({
modules: {
transport: [ TCP ],
streamMuxer: [ Mplex ],
@@ -156,10 +156,103 @@ Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m
Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ
```
## 3. Where to find other Peer Discovery Mechanisms
## 3. Pubsub based Peer Discovery
For this example, we need [`libp2p-pubsub-peer-discovery`](https://github.com/libp2p/js-libp2p-pubsub-peer-discovery/), go ahead and `npm install` it. You also need to spin up a set of [`libp2p-relay-servers`](https://github.com/libp2p/js-libp2p-relay-server). These servers act as relay servers and a peer discovery source.
In the context of this example, we will create and run the `libp2p-relay-server` in the same code snippet. You can find the complete solution at [3.js](./3.js).
You can create your libp2p nodes as follows:
```js
const Libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const Mplex = require('libp2p-mplex')
const { NOISE } = require('libp2p-noise')
const Gossipsub = require('libp2p-gossipsub')
const Bootstrap = require('libp2p-bootstrap')
const PubsubPeerDiscovery = require('libp2p-pubsub-peer-discovery')
const createNode = async (bootstrapers) => {
const node = await Libp2p.create({
addresses: {
listen: ['/ip4/0.0.0.0/tcp/0']
},
modules: {
transport: [TCP],
streamMuxer: [Mplex],
connEncryption: [NOISE],
pubsub: Gossipsub,
peerDiscovery: [Bootstrap, PubsubPeerDiscovery]
},
config: {
peerDiscovery: {
[PubsubPeerDiscovery.tag]: {
interval: 1000,
enabled: true
},
[Bootstrap.tag]: {
enabled: true,
list: bootstrapers
}
}
}
})
return node
}
```
We will use the `libp2p-relay-server` as bootstrap nodes for the libp2p nodes, so that they establish a connection with the relay after starting. As a result, after they establish a connection with the relay, the pubsub discovery will kick in and the relay will advertise them.
```js
const relay = await createRelayServer({
listenAddresses: ['/ip4/0.0.0.0/tcp/0']
})
console.log(`libp2p relay starting with id: ${relay.peerId.toB58String()}`)
await relay.start()
const relayMultiaddrs = relay.multiaddrs.map((m) => `${m.toString()}/p2p/${relay.peerId.toB58String()}`)
const [node1, node2] = await Promise.all([
createNode(relayMultiaddrs),
createNode(relayMultiaddrs)
])
node1.on('peer:discovery', (peerId) => {
console.log(`Peer ${node1.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
})
node2.on('peer:discovery', (peerId) => {
console.log(`Peer ${node2.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
})
;[node1, node2].forEach((node, index) => console.log(`Node ${index} starting with id: ${node.peerId.toB58String()}`))
await Promise.all([
node1.start(),
node2.start()
])
```
If you run this example, you will see the other peers being discovered.
```bash
> node 3.js
libp2p relay starting with id: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
Node 0 starting with id: QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N
Node 1 starting with id: QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv
Peer QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N discovered: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
Peer QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv discovered: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
Peer QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv discovered: QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N
Peer QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N discovered: QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv
```
Taking into account the output, after the relay and both libp2p nodes start, both libp2p nodes will discover the bootstrap node (relay) and connect with it. After establishing a connection with the relay, they will discover each other.
This is really useful when running libp2p in constrained environments like a browser. You can run a set of `libp2p-relay-server` nodes that will be responsible for both relaying websocket connections between browser nodes and for discovering other browser peers.
## 4. Where to find other Peer Discovery Mechanisms
There are plenty more Peer Discovery Mechanisms out there, you can:
- Find one in [libp2p-webrtc-star](https://github.com/libp2p/js-libp2p-webrtc-star). Yes, a transport with discovery capabilities! This happens because WebRTC requires a rendezvous point for peers to exchange [SDP](https://tools.ietf.org/html/rfc4317) offer, which means we have one or more points that can introduce peers to each other. Think of it as MulticastDNS for the Web, as in MulticastDNS only works in LAN.
- Any DHT will offer you a discovery capability. You can simple _random-walk_ the routing tables to find other peers to connect to. For example [libp2p-kad-dht](https://github.com/libp2p/js-libp2p-kad-dht) can be used for peer discovery. An example how to configure it to enable random walks can be found [here](https://github.com/libp2p/js-libp2p/blob/v0.28.4/doc/CONFIGURATION.md#customizing-dht).
- Any DHT will offer you a discovery capability. You can simple _random-walk_ the routing tables to find other peers to connect to. For example [libp2p-kad-dht](https://github.com/libp2p/js-libp2p-kad-dht) can be used for peer discovery. An example of how to configure it to enable random walks can be found [here](https://github.com/libp2p/js-libp2p/blob/v0.28.4/doc/CONFIGURATION.md#customizing-dht).
- You can create your own Discovery service, a registry, a list, a radio beacon, you name it!

View File

@@ -0,0 +1,35 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pWaitFor = require('p-wait-for')
const uint8ArrayToString = require('uint8arrays/to-string')
const discoveredCopy = 'discovered:'
async function test() {
let discoverCount = 0
process.stdout.write('3.js\n')
const proc = execa('node', [path.join(__dirname, '3.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)
// Discovered or Connected
if (line.includes(discoveredCopy)) {
discoverCount++
}
})
await pWaitFor(() => discoverCount === 4)
proc.kill()
}
module.exports = test

View File

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

View File

@@ -4,9 +4,13 @@ This example leverages the [Parcel.js bundler](https://parceljs.org/) to compile
## Setup
In order to run the example, first install the dependencies from same directory as this README:
In order to run the example:
- Install dependencey at the root of the js-libp2p repository (if not already done),
- then, install the dependencies from same directory as this README:
```
npm install
cd ./examples/libp2p-in-the-browser
npm install
```

View File

@@ -2,7 +2,7 @@
"name": "libp2p-in-browser",
"version": "1.0.0",
"description": "A libp2p node running in the browser",
"main": "index.js",
"main": "dist/index.html",
"browserslist": [
"last 2 Chrome versions"
],
@@ -15,20 +15,20 @@
"author": "",
"license": "ISC",
"dependencies": {
"@babel/preset-env": "^7.8.3",
"@babel/preset-env": "^7.13.0",
"libp2p": "../../",
"libp2p-bootstrap": "^0.12.1",
"libp2p-mplex": "^0.10.0",
"libp2p-noise": "^2.0.0",
"libp2p-webrtc-star": "^0.20.0",
"libp2p-websockets": "^0.14.0"
"libp2p-webrtc-star": "^0.22.0",
"libp2p-websockets": "^0.15.0"
},
"devDependencies": {
"@babel/cli": "^7.8.3",
"@babel/core": "^7.8.3",
"@babel/cli": "^7.13.10",
"@babel/core": "^7.13.0",
"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"
"parcel": "next"
}
}

View File

@@ -17,10 +17,10 @@ async function run() {
const out = chunk.toString()
if (out.includes('Server running at')) {
url = out.replace('Server running at ', '')
url = out.split('Server running at ')[1]
}
if (out.includes('Built in ')) {
if (out.includes('Built in')) {
try {
const browser = await chromium.launch();
const page = await browser.newPage();

View File

@@ -10,6 +10,8 @@
"dependencies": {
"execa": "^2.1.0",
"fs-extra": "^8.1.0",
"libp2p-pubsub-peer-discovery": "^3.0.0",
"libp2p-relay-server": "^0.1.2",
"p-defer": "^3.0.0",
"which": "^2.0.1"
},

View File

@@ -0,0 +1,36 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pWaitFor = require('p-wait-for')
const uint8ArrayToString = require('uint8arrays/to-string')
async function test() {
process.stdout.write('1.js\n')
const addrs = []
let foundIt = false
const proc = execa('node', [path.join(__dirname, '1.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)
// Discovered peer
if (!foundIt && line.includes('Found it, multiaddrs are:')) {
foundIt = true
}
addrs.push(line)
})
await pWaitFor(() => addrs.length === 2)
proc.kill()
}
module.exports = test

View File

@@ -0,0 +1,40 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pDefer = require('p-defer')
const uint8ArrayToString = require('uint8arrays/to-string')
const providedCopy = 'is providing'
const foundCopy = 'Found provider:'
async function test() {
process.stdout.write('2.js\n')
const providedDefer = pDefer()
const foundDefer = pDefer()
const proc = execa('node', [path.join(__dirname, '2.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)
if (line.includes(providedCopy)) {
providedDefer.resolve()
} else if (line.includes(foundCopy)) {
foundDefer.resolve()
}
})
await Promise.all([
providedDefer.promise,
foundDefer.promise
])
proc.kill()
}
module.exports = test

View File

@@ -0,0 +1,11 @@
'use strict'
const test1 = require('./test-1')
const test2 = require('./test-2')
async function test() {
await test1()
await test2()
}
module.exports = test

View File

@@ -0,0 +1,31 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pDefer = require('p-defer')
const uint8ArrayToString = require('uint8arrays/to-string')
async function test() {
const messageDefer = pDefer()
process.stdout.write('1.js\n')
const proc = execa('node', [path.join(__dirname, '1.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)
if (line.includes('my own protocol, wow!')) {
messageDefer.resolve()
}
})
await messageDefer.promise
proc.kill()
}
module.exports = test

View File

@@ -0,0 +1,38 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pWaitFor = require('p-wait-for')
const uint8ArrayToString = require('uint8arrays/to-string')
const messages = [
'protocol (a)',
'protocol (b)',
'another stream on protocol (b)'
]
async function test() {
process.stdout.write('2.js\n')
let count = 0
const proc = execa('node', [path.join(__dirname, '2.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)
if (messages.find((m) => line.includes(m))) {
count += 1
}
})
await pWaitFor(() => count === messages.length)
proc.kill()
}
module.exports = test

View File

@@ -0,0 +1,37 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pWaitFor = require('p-wait-for')
const uint8ArrayToString = require('uint8arrays/to-string')
const messages = [
'from 1 to 2',
'from 2 to 1'
]
async function test() {
process.stdout.write('3.js\n')
let count = 0
const proc = execa('node', [path.join(__dirname, '3.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)
if (messages.find((m) => line.includes(m))) {
count += 1
}
})
await pWaitFor(() => count === messages.length)
proc.kill()
}
module.exports = test

View File

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

View File

@@ -0,0 +1,67 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pDefer = require('p-defer')
const uint8ArrayToString = require('uint8arrays/to-string')
const stdout = [
{
topic: 'banana',
messageCount: 2
},
{
topic: 'apple',
messageCount: 2
},
{
topic: 'car',
messageCount: 0
},
{
topic: 'orange',
messageCount: 2
},
]
async function test () {
const defer = pDefer()
let topicCount = 0
let topicMessageCount = 0
process.stdout.write('message-filtering/1.js\n')
const proc = execa('node', [path.join(__dirname, '1.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
// End
if (topicCount === stdout.length) {
defer.resolve()
proc.all.removeAllListeners('data')
}
process.stdout.write(data)
const line = uint8ArrayToString(data)
if (stdout[topicCount] && line.includes(stdout[topicCount].topic)) {
// Validate previous number of messages
if (topicCount > 0 && topicMessageCount > stdout[topicCount - 1].messageCount) {
defer.reject()
throw new Error(`topic ${stdout[topicCount - 1].topic} had ${topicMessageCount} messages instead of ${stdout[topicCount - 1].messageCount}`)
}
topicCount++
topicMessageCount = 0
} else {
topicMessageCount++
}
})
await defer.promise
proc.kill()
}
module.exports = test

30
examples/pubsub/test-1.js Normal file
View File

@@ -0,0 +1,30 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pDefer = require('p-defer')
const uint8ArrayToString = require('uint8arrays/to-string')
async function test () {
const defer = pDefer()
process.stdout.write('1.js\n')
const proc = execa('node', [path.join(__dirname, '1.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)
if (line.includes('node1 received: Bird bird bird, bird is the word!')) {
defer.resolve()
}
})
await defer.promise
proc.kill()
}
module.exports = test

11
examples/pubsub/test.js Normal file
View File

@@ -0,0 +1,11 @@
'use strict'
const test1 = require('./test-1')
const testMessageFiltering = require('./message-filtering/test')
async function test() {
await test1()
await testMessageFiltering()
}
module.exports = test

View File

@@ -0,0 +1,38 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pDefer = require('p-defer')
const uint8ArrayToString = require('uint8arrays/to-string')
async function test () {
const deferStarted = pDefer()
const deferListen = pDefer()
process.stdout.write('1.js\n')
const proc = execa('node', [path.join(__dirname, '1.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)
if (line.includes('node has started (true/false): true')) {
deferStarted.resolve()
} else if (line.includes('p2p')) {
deferListen.resolve()
}
})
await Promise.all([
deferStarted.promise,
deferListen.promise
])
proc.kill()
}
module.exports = test

View File

@@ -0,0 +1,30 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pDefer = require('p-defer')
const uint8ArrayToString = require('uint8arrays/to-string')
async function test () {
const defer = pDefer()
process.stdout.write('2.js\n')
const proc = execa('node', [path.join(__dirname, '2.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)
if (line.includes('Hello p2p world!')) {
defer.resolve()
}
})
await defer.promise
proc.kill()
}
module.exports = test

View File

@@ -0,0 +1,41 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pDefer = require('p-defer')
const uint8ArrayToString = require('uint8arrays/to-string')
async function test () {
const deferNode1 = pDefer()
const deferNode2 = pDefer()
const deferNode3 = pDefer()
process.stdout.write('3.js\n')
const proc = execa('node', [path.join(__dirname, '3.js')], {
cwd: path.resolve(__dirname),
all: true
})
proc.all.on('data', async (data) => {
process.stdout.write(data)
const line = uint8ArrayToString(data)
if (line.includes('node 1 dialed to node 2 successfully')) {
deferNode1.resolve()
} else if (line.includes('node 2 dialed to node 3 successfully')) {
deferNode2.resolve()
} else if (line.includes('node 3 failed to dial to node 1 with:')) {
deferNode3.resolve()
}
})
await Promise.all([
deferNode1.promise,
deferNode2.promise,
deferNode3.promise
])
proc.kill()
}
module.exports = test

View File

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

View File

@@ -0,0 +1,33 @@
### Webrtc-direct example
An example that uses [js-libp2p-webrtc-direct](https://github.com/libp2p/js-libp2p-webrtc-direct) for connecting
nodejs libp2p and browser libp2p clients. To run the example:
## 0. Run a nodejs libp2p listener
When in the root folder of this example, type `node listener.js` in terminal. You should see an address that listens for
incoming connections. Below is just an example of such address. In your case the suffix hash (`peerId`) will be different.
```bash
$ node listener.js
Listening on:
/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/QmUKQCzEUhhhobcNSrXU5uzxTqbvF1BjMCGNGZzZU14Kgd
```
## 1. Prepare a browser libp2p dialer
Confirm that the above address is the same as the field `list` in `public/dialer.js`:
```js
peerDiscovery: {
[Bootstrap.tag]: {
enabled: true,
// paste the address into `list`
list: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/QmUKQCzEUhhhobcNSrXU5uzxTqbvF1BjMCGNGZzZU14Kgd']
}
}
```
## 2. Run a browser libp2p dialer
When in the root folder of this example, type `npm run dev` in terminal. You should see an address where you can browse
the running client. Open this address in your browser. In console
logs you should see logs about successful connection with the node client. In the output of node client you should see
a log message about successful connection as well.

View File

@@ -0,0 +1,57 @@
import 'babel-polyfill'
const Libp2p = require('libp2p')
const WebRTCDirect = require('libp2p-webrtc-direct')
const Mplex = require('libp2p-mplex')
const {NOISE} = require('libp2p-noise')
const Bootstrap = require('libp2p-bootstrap')
document.addEventListener('DOMContentLoaded', async () => {
// use the same peer id as in `listener.js` to avoid copy-pasting of listener's peer id into `peerDiscovery`
const hardcodedPeerId = '12D3KooWCuo3MdXfMgaqpLC5Houi1TRoFqgK9aoxok4NK5udMu8m'
const libp2p = await Libp2p.create({
modules: {
transport: [WebRTCDirect],
streamMuxer: [Mplex],
connEncryption: [NOISE],
peerDiscovery: [Bootstrap]
},
config: {
peerDiscovery: {
[Bootstrap.tag]: {
enabled: true,
list: [`/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/${hardcodedPeerId}`]
}
}
}
})
const status = document.getElementById('status')
const output = document.getElementById('output')
output.textContent = ''
function log (txt) {
console.info(txt)
output.textContent += `${txt.trim()}\n`
}
// Listen for new peers
libp2p.on('peer:discovery', (peerId) => {
log(`Found peer ${peerId.toB58String()}`)
})
// Listen for new connections to peers
libp2p.connectionManager.on('peer:connect', (connection) => {
log(`Connected to ${connection.remotePeer.toB58String()}`)
})
// Listen for peers disconnecting
libp2p.connectionManager.on('peer:disconnect', (connection) => {
log(`Disconnected from ${connection.remotePeer.toB58String()}`)
})
await libp2p.start()
status.innerText = 'libp2p started!'
log(`libp2p id is ${libp2p.peerId.toB58String()}`)
})

View File

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

View File

@@ -0,0 +1,44 @@
const Libp2p = require('libp2p')
const Bootstrap = require('libp2p-bootstrap')
const WebRTCDirect = require('libp2p-webrtc-direct')
const Mplex = require('libp2p-mplex')
const {NOISE} = require('libp2p-noise')
const PeerId = require('peer-id')
;(async () => {
// hardcoded peer id to avoid copy-pasting of listener's peer id into the dialer's bootstrap list
// generated with cmd `peer-id --type=ed25519`
const hardcodedPeerId = await PeerId.createFromJSON({
"id": "12D3KooWCuo3MdXfMgaqpLC5Houi1TRoFqgK9aoxok4NK5udMu8m",
"privKey": "CAESQAG6Ld7ev6nnD0FKPs033/j0eQpjWilhxnzJ2CCTqT0+LfcWoI2Vr+zdc1vwk7XAVdyoCa2nwUR3RJebPWsF1/I=",
"pubKey": "CAESIC33FqCNla/s3XNb8JO1wFXcqAmtp8FEd0SXmz1rBdfy"
})
const node = await Libp2p.create({
peerId: hardcodedPeerId,
addresses: {
listen: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct']
},
modules: {
transport: [WebRTCDirect],
streamMuxer: [Mplex],
connEncryption: [NOISE]
},
config: {
peerDiscovery: {
[Bootstrap.tag]: {
enabled: false,
}
}
}
})
node.connectionManager.on('peer:connect', (connection) => {
console.info(`Connected to ${connection.remotePeer.toB58String()}!`)
})
await node.start()
console.log('Listening on:')
node.multiaddrs.forEach((ma) => console.log(`${ma.toString()}/p2p/${node.peerId.toB58String()}`))
})()

View File

@@ -0,0 +1,33 @@
{
"name": "webrtc-direct",
"version": "0.0.1",
"private": true,
"description": "",
"main": "dist/index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "parcel build index.html",
"start": "parcel index.html"
},
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.13.10",
"@babel/core": "^7.13.10",
"babel-plugin-syntax-async-functions": "^6.13.0",
"babel-plugin-transform-regenerator": "^6.26.0",
"babel-polyfill": "^6.26.0",
"parcel-bundler": "1.12.3",
"util": "^0.12.3"
},
"dependencies": {
"libp2p": "../../",
"libp2p-bootstrap": "^0.12.1",
"libp2p-mplex": "^0.10.1",
"libp2p-noise": "^2.0.1",
"libp2p-webrtc-direct": "^0.6.0",
"peer-id": "^0.14.3"
},
"browser": {
"ipfs": "ipfs/dist/index.min.js"
}
}

View File

@@ -0,0 +1,95 @@
'use strict'
const path = require('path')
const execa = require('execa')
const pDefer = require('p-defer')
const uint8ArrayToString = require('uint8arrays/to-string')
const { chromium } = require('playwright');
function startNode (name, args = []) {
return execa('node', [path.join(__dirname, name), ...args], {
cwd: path.resolve(__dirname),
all: true
})
}
function startBrowser (name, args = []) {
return execa('parcel', [path.join(__dirname, name), ...args], {
preferLocal: true,
localDir: __dirname,
cwd: __dirname,
all: true
})
}
async function test () {
// Step 1, listener process
const listenerProcReady = pDefer()
let listenerOutput = ''
process.stdout.write('listener.js\n')
const listenerProc = startNode('listener.js')
listenerProc.all.on('data', async (data) => {
process.stdout.write(data)
listenerOutput += uint8ArrayToString(data)
if (listenerOutput.includes('Listening on:') && listenerOutput.includes('12D3KooWCuo3MdXfMgaqpLC5Houi1TRoFqgK9aoxok4NK5udMu8m')) {
listenerProcReady.resolve()
}
})
await listenerProcReady.promise
process.stdout.write('==================================================================\n')
// Step 2, dialer process
process.stdout.write('dialer.js\n')
let dialerUrl = ''
const dialerProc = startBrowser('index.html')
dialerProc.all.on('data', async (chunk) => {
/**@type {string} */
const out = chunk.toString()
if (out.includes('Server running at')) {
dialerUrl = out.split('Server running at ')[1]
}
if (out.includes('Built in ')) {
try {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto(dialerUrl);
await page.waitForFunction(selector => document.querySelector(selector).innerText === 'libp2p started!', '#status')
await page.waitForFunction(
selector => {
const text = document.querySelector(selector).innerText
return text.includes('libp2p id is') &&
text.includes('Found peer') &&
text.includes('Connected to')
},
'#output',
{ timeout: 10000 }
)
await browser.close();
} catch (err) {
console.error(err)
process.exit(1)
} finally {
dialerProc.cancel()
listenerProc.kill()
}
}
})
await Promise.all([
listenerProc,
dialerProc,
]).catch((err) => {
if (err.signal !== 'SIGTERM') {
throw err
}
})
}
module.exports = test

View File

@@ -1,6 +1,6 @@
{
"name": "libp2p",
"version": "0.30.6",
"version": "0.31.0",
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"main": "src/index.js",
@@ -20,10 +20,28 @@
"scripts": {
"lint": "aegir lint",
"build": "aegir build",
"test": "npm run test:node && npm run test:browser",
"build:proto": "npm run build:proto:circuit && npm run build:proto:identify && npm run build:proto:plaintext && npm run build:proto:address-book && npm run build:proto:proto-book && npm run build:proto:peer-record && npm run build:proto:envelope",
"build:proto:circuit": "pbjs -t static-module -w commonjs -r libp2p-circuit --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/circuit/protocol/index.js ./src/circuit/protocol/index.proto",
"build:proto:identify": "pbjs -t static-module -w commonjs -r libp2p-identify --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/identify/message.js ./src/identify/message.proto",
"build:proto:plaintext": "pbjs -t static-module -w commonjs -r libp2p-plaintext --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/insecure/proto.js ./src/insecure/proto.proto",
"build:proto:address-book": "pbjs -t static-module -w commonjs -r libp2p-address-book --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/peer-store/persistent/pb/address-book.js ./src/peer-store/persistent/pb/address-book.proto",
"build:proto:proto-book": "pbjs -t static-module -w commonjs -r libp2p-proto-book --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/peer-store/persistent/pb/proto-book.js ./src/peer-store/persistent/pb/proto-book.proto",
"build:proto:peer-record": "pbjs -t static-module -w commonjs -r libp2p-peer-record --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/record/peer-record/peer-record.js ./src/record/peer-record/peer-record.proto",
"build:proto:envelope": "pbjs -t static-module -w commonjs -r libp2p-envelope --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/record/envelope/envelope.js ./src/record/envelope/envelope.proto",
"build:proto-types": "npm run build:proto-types:circuit && npm run build:proto-types:identify && npm run build:proto-types:plaintext && npm run build:proto-types:address-book && npm run build:proto-types:proto-book && npm run build:proto-types:peer-record && npm run build:proto-types:envelope",
"build:proto-types:circuit": "pbts -o src/circuit/protocol/index.d.ts src/circuit/protocol/index.js",
"build:proto-types:identify": "pbts -o src/identify/message.d.ts src/identify/message.js",
"build:proto-types:plaintext": "pbts -o src/insecure/proto.d.ts src/insecure/proto.js",
"build:proto-types:address-book": "pbts -o src/peer-store/persistent/pb/address-book.d.ts src/peer-store/persistent/pb/address-book.js",
"build:proto-types:proto-book": "pbts -o src/peer-store/persistent/pb/proto-book.d.ts src/peer-store/persistent/pb/proto-book.js",
"build:proto-types:peer-record": "pbts -o src/record/peer-record/peer-record.d.ts src/record/peer-record/peer-record.js",
"build:proto-types:envelope": "pbts -o src/record/envelope/envelope.d.ts src/record/envelope/envelope.js",
"test": "aegir test",
"test:ts": "aegir build --no-bundle && npm run test --prefix test/ts-use",
"test:node": "aegir test -t node -f \"./test/**/*.{node,spec}.js\"",
"test:browser": "aegir test -t browser",
"test:examples": "cd examples && npm run test:all",
"prepare": "aegir build --no-bundle",
"release": "aegir release -t node -t browser",
"release-minor": "aegir release --type minor -t node -t browser",
"release-major": "aegir release --type major -t node -t browser",
@@ -47,12 +65,18 @@
"homepage": "https://libp2p.io",
"license": "MIT",
"engines": {
"node": ">=12.0.0",
"npm": ">=6.0.0"
"node": ">=14.0.0"
},
"browser": {
"@motrix/nat-api": false
},
"eslintConfig": {
"extends": "ipfs",
"ignorePatterns": [
"!.aegir.js",
"test/ts-use"
]
},
"dependencies": {
"@motrix/nat-api": "^0.3.1",
"abort-controller": "^3.0.0",
@@ -62,137 +86,143 @@
"cids": "^1.1.5",
"class-is": "^1.1.0",
"debug": "^4.3.1",
"err-code": "^2.0.0",
"events": "^3.2.0",
"err-code": "^3.0.0",
"es6-promisify": "^6.1.1",
"events": "^3.3.0",
"hashlru": "^2.3.0",
"interface-datastore": "^3.0.3",
"interface-datastore": "^4.0.0",
"ipfs-utils": "^6.0.0",
"it-all": "^1.0.4",
"it-buffer": "^0.1.2",
"it-drain": "^1.0.3",
"it-filter": "^1.0.1",
"it-first": "^1.0.4",
"it-handshake": "^1.0.2",
"it-length-prefixed": "^3.1.0",
"it-handshake": "^2.0.0",
"it-length-prefixed": "^5.0.2",
"it-map": "^1.0.4",
"it-merge": "1.0.0",
"it-pipe": "^1.1.0",
"it-protocol-buffers": "^0.2.0",
"it-take": "1.0.0",
"libp2p-crypto": "^0.19.0",
"libp2p-interfaces": "^0.8.1",
"libp2p-utils": "^0.2.2",
"mafmt": "^8.0.0",
"libp2p-interfaces": "^0.10.3",
"libp2p-utils": "^0.3.1",
"mafmt": "^9.0.0",
"merge-options": "^3.0.4",
"moving-average": "^1.0.0",
"multiaddr": "^8.1.0",
"multicodec": "^2.1.0",
"multihashing-async": "^2.0.1",
"multistream-select": "^1.0.0",
"multiaddr": "^9.0.1",
"multicodec": "^3.0.1",
"multihashing-async": "^2.1.2",
"multistream-select": "^2.0.0",
"mutable-proxy": "^1.0.0",
"node-forge": "^0.10.0",
"p-any": "^3.0.0",
"p-fifo": "^1.0.0",
"p-retry": "^4.2.0",
"p-settle": "^4.0.1",
"p-retry": "^4.4.0",
"p-settle": "^4.1.1",
"peer-id": "^0.14.2",
"private-ip": "^2.0.0",
"promisify-es6": "^1.0.3",
"protons": "^2.0.0",
"retimer": "^2.0.0",
"private-ip": "^2.1.0",
"protobufjs": "^6.10.2",
"retimer": "^3.0.0",
"sanitize-filename": "^1.6.3",
"set-delayed-interval": "^1.0.0",
"streaming-iterables": "^5.0.2",
"timeout-abort-controller": "^1.1.1",
"varint": "^6.0.0",
"xsalsa20": "^1.0.2"
"xsalsa20": "^1.1.0"
},
"devDependencies": {
"@nodeutils/defaults-deep": "^1.1.0",
"@types/es6-promisify": "^6.0.0",
"@types/node-forge": "^0.9.7",
"@types/varint": "^6.0.0",
"abortable-iterator": "^3.0.0",
"aegir": "^29.2.0",
"chai-bytes": "^0.1.2",
"chai-string": "^1.5.0",
"delay": "^4.4.0",
"aegir": "^33.1.1",
"buffer": "^6.0.3",
"delay": "^5.0.0",
"interop-libp2p": "^0.3.0",
"into-stream": "^6.0.0",
"ipfs-http-client": "^48.2.2",
"ipfs-http-client": "^49.0.4",
"it-concat": "^1.0.0",
"it-pair": "^1.0.0",
"it-pushable": "^1.4.0",
"libp2p": ".",
"libp2p-bootstrap": "^0.12.0",
"libp2p-delegated-content-routing": "^0.9.0",
"libp2p-delegated-peer-routing": "^0.8.0",
"libp2p-floodsub": "^0.24.0",
"libp2p-bootstrap": "^0.12.3",
"libp2p-delegated-content-routing": "^0.10.0",
"libp2p-delegated-peer-routing": "^0.9.0",
"libp2p-floodsub": "^0.25.0",
"libp2p-gossipsub": "^0.8.0",
"libp2p-kad-dht": "^0.20.5",
"libp2p-mdns": "^0.15.0",
"libp2p-kad-dht": "^0.21.0",
"libp2p-mdns": "^0.16.0",
"libp2p-mplex": "^0.10.1",
"libp2p-noise": "^2.0.0",
"libp2p-secio": "^0.13.1",
"libp2p-noise": "^3.0.0",
"libp2p-tcp": "^0.15.1",
"libp2p-webrtc-star": "^0.20.0",
"libp2p-webrtc-star": "^0.22.0",
"libp2p-websockets": "^0.15.0",
"multihashes": "^3.0.1",
"multihashes": "^4.0.2",
"nock": "^13.0.3",
"p-defer": "^3.0.0",
"p-times": "^3.0.0",
"p-wait-for": "^3.2.0",
"rimraf": "^3.0.2",
"sinon": "^9.2.4",
"uint8arrays": "^2.0.5"
"sinon": "^10.0.0",
"uint8arrays": "^2.1.3",
"util": "^0.12.3"
},
"contributors": [
"David Dias <daviddias.p@gmail.com>",
"Jacob Heun <jacobheun@gmail.com>",
"Vasco Santos <vasco.santos@moxy.studio>",
"Alan Shaw <alan@tableflip.io>",
"Jacob Heun <jacobheun@gmail.com>",
"Alex Potsides <alex@achingbrain.net>",
"Alan Shaw <alan@tableflip.io>",
"Cayman <caymannava@gmail.com>",
"Pedro Teixeira <i@pgte.me>",
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
"Maciej Krüger <mkg20001@gmail.com>",
"Hugo Dias <mail@hugodias.me>",
"Volker Mische <volker.mische@gmail.com>",
"dirkmc <dirkmdev@gmail.com>",
"Volker Mische <volker.mische@gmail.com>",
"Richard Littauer <richard.littauer@gmail.com>",
"a1300 <matthias-knopp@gmx.net>",
"Ryan Bell <ryan@piing.net>",
"Andrew Nesbitt <andrewnez@gmail.com>",
"Elven <mon.samuel@qq.com>",
"Giovanni T. Parra <fiatjaf@gmail.com>",
"Samlior <samlior@foxmail.com>",
"Thomas Eizinger <thomas@eizinger.io>",
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
"Didrik Nordström <didrik@betamos.se>",
"Thomas Eizinger <thomas@eizinger.io>",
"Samlior <samlior@foxmail.com>",
"Ryan Bell <ryan@piing.net>",
"Andrew Nesbitt <andrewnez@gmail.com>",
"Didrik Nordström <didrik.nordstrom@gmail.com>",
"Nuno Nogueira <nunofmn@gmail.com>",
"Philipp Muens <raute1337@gmx.de>",
"Smite Chow <xiaopengyou@live.com>",
"Soeren <nikorpoulsen@gmail.com>",
"Sönke Hahn <soenkehahn@gmail.com>",
"TJKoury <TJKoury@gmail.com>",
"Tiago Alves <alvesjtiago@gmail.com>",
"Yusef Napora <yusef@napora.org>",
"Zane Starr <zcstarr@gmail.com>",
"ebinks <elizabethjbinks@gmail.com>",
"isan_rivkin <isanrivkin@gmail.com>",
"robertkiel <robert.kiel@validitylabs.org>",
"RasmusErik Voel Jensen <github@solsort.com>",
"Aleksei <vozhdb@gmail.com>",
"Bernd Strehl <bernd.strehl@gmail.com>",
"Chris Bratlien <chrisbratlien@gmail.com>",
"Cindy Wu <ciindy.wu@gmail.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"Ethan Lam <elmemphis2000@gmail.com>",
"Fei Liu <liu.feiwood@gmail.com>",
"Felipe Martins <felipebrasil93@gmail.com>",
"Florian-Merle <florian.david.merle@gmail.com>",
"Francis Gulotta <wizard@roborooter.com>",
"Franck Royer <franck@royer.one>",
"Henrique Dias <hacdias@gmail.com>",
"Irakli Gozalishvili <rfobic@gmail.com>",
"Joel Gustafson <joelg@mit.edu>",
"Julien Bouquillon <contact@revolunet.com>",
"Kevin Kwok <antimatter15@gmail.com>",
"Kevin Lacker <lacker@gmail.com>",
"Ethan Lam <elmemphis2000@gmail.com>",
"Nuno Nogueira <nunofmn@gmail.com>",
"Dmitriy Ryajov <dryajov@gmail.com>",
"RasmusErik Voel Jensen <github@solsort.com>",
"Diogo Silva <fsdiogo@gmail.com>",
"Smite Chow <xiaopengyou@live.com>",
"Soeren <nikorpoulsen@gmail.com>",
"Sönke Hahn <soenkehahn@gmail.com>",
"Tiago Alves <alvesjtiago@gmail.com>",
"Daijiro Wachi <daijiro.wachi@gmail.com>",
"Yusef Napora <yusef@napora.org>",
"Zane Starr <zcstarr@gmail.com>",
"robertkiel <robert.kiel@validitylabs.org>",
"Cindy Wu <ciindy.wu@gmail.com>",
"Chris Bratlien <chrisbratlien@gmail.com>",
"ebinks <elizabethjbinks@gmail.com>",
"Francis Gulotta <wizard@roborooter.com>",
"Florian-Merle <florian.david.merle@gmail.com>",
"Bernd Strehl <bernd.strehl@gmail.com>",
"Henrique Dias <hacdias@gmail.com>",
"isan_rivkin <isanrivkin@gmail.com>",
"Felipe Martins <felipebrasil93@gmail.com>",
"Fei Liu <liu.feiwood@gmail.com>"
"Miguel Mota <miguelmota2@gmail.com>"
]
}

2
scripts/node-globals.js Normal file
View File

@@ -0,0 +1,2 @@
// @ts-nocheck
export const { Buffer } = require('buffer')

View File

@@ -1,15 +1,9 @@
'use strict'
/** @typedef {import('../types').EventEmitterFactory} Events */
/** @type Events */
const EventEmitter = require('events')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const PeerId = require('peer-id')
/**
* @typedef {import('multiaddr')} Multiaddr
*/
/**
* @typedef {Object} AddressManagerOptions
* @property {string[]} [listen = []] - list of multiaddrs string representation to listen.
@@ -47,7 +41,7 @@ class AddressManager extends EventEmitter {
* @returns {Multiaddr[]}
*/
getListenAddrs () {
return Array.from(this.listen).map((a) => multiaddr(a))
return Array.from(this.listen).map((a) => new Multiaddr(a))
}
/**
@@ -56,7 +50,7 @@ class AddressManager extends EventEmitter {
* @returns {Multiaddr[]}
*/
getAnnounceAddrs () {
return Array.from(this.announce).map((a) => multiaddr(a))
return Array.from(this.announce).map((a) => new Multiaddr(a))
}
/**
@@ -65,7 +59,7 @@ class AddressManager extends EventEmitter {
* @returns {Array<Multiaddr>}
*/
getObservedAddrs () {
return Array.from(this.observed).map((a) => multiaddr(a))
return Array.from(this.observed).map((a) => new Multiaddr(a))
}
/**
@@ -74,7 +68,7 @@ class AddressManager extends EventEmitter {
* @param {string | Multiaddr} addr
*/
addObservedAddr (addr) {
let ma = multiaddr(addr)
let ma = new Multiaddr(addr)
const remotePeer = ma.getPeerId()
// strip our peer id if it has been passed
@@ -83,7 +77,7 @@ class AddressManager extends EventEmitter {
// use same encoding for comparison
if (remotePeerId.equals(this.peerId)) {
ma = ma.decapsulate(multiaddr(`/p2p/${this.peerId}`))
ma = ma.decapsulate(new Multiaddr(`/p2p/${this.peerId}`))
}
}

View File

@@ -37,7 +37,7 @@ Libp2p circuit configuration can be seen at [Setup with Relay](../../doc/CONFIGU
Once you have a circuit relay node running, you can configure other nodes to use it as a relay as follows:
```js
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const Libp2p = require('libp2p')
const TCP = require('libp2p-tcp')
const MPLEX = require('libp2p-mplex')
@@ -47,7 +47,7 @@ const relayAddr = ...
const node = await Libp2p.create({
addresses: {
listen: [multiaddr(`${relayAddr}/p2p-circuit`)]
listen: [new Multiaddr(`${relayAddr}/p2p-circuit`)]
},
modules: {
transport: [TCP],

View File

@@ -7,7 +7,7 @@ const log = Object.assign(debug('libp2p:auto-relay'), {
const uint8ArrayFromString = require('uint8arrays/from-string')
const uint8ArrayToString = require('uint8arrays/to-string')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const PeerId = require('peer-id')
const { relay: multicodec } = require('./multicodec')
@@ -31,6 +31,7 @@ const {
*
* @typedef {Object} AutoRelayOptions
* @property {number} [maxListeners = 1] - maximum number of relays to listen.
* @property {(error: Error, msg?: string) => {}} [onError]
*/
class AutoRelay {
@@ -40,7 +41,7 @@ class AutoRelay {
* @class
* @param {AutoRelayProperties & AutoRelayOptions} props
*/
constructor ({ libp2p, maxListeners = 1 }) {
constructor ({ libp2p, maxListeners = 1, onError }) {
this._libp2p = libp2p
this._peerId = libp2p.peerId
this._peerStore = libp2p.peerStore
@@ -60,6 +61,15 @@ class AutoRelay {
this._peerStore.on('change:protocols', this._onProtocolChange)
this._connectionManager.on('peer:disconnect', this._onPeerDisconnected)
/**
* @param {Error} error
* @param {string} [msg]
*/
this._onError = (error, msg) => {
log.error(msg || error)
onError && onError(error, msg)
}
}
/**
@@ -107,7 +117,7 @@ class AutoRelay {
await this._addListenRelay(connection, id)
}
} catch (err) {
log.error(err)
this._onError(err)
}
}
@@ -157,10 +167,10 @@ class AutoRelay {
// Attempt to listen on relay
try {
await this._transportManager.listen([multiaddr(listenAddr)])
await this._transportManager.listen([new Multiaddr(listenAddr)])
// Announce multiaddrs will update on listen success by TransportManager event being triggered
} catch (err) {
log.error(err)
this._onError(err)
this._listenRelays.delete(id)
}
}
@@ -231,8 +241,7 @@ class AutoRelay {
// Try to listen on known peers that are not connected
for (const peerId of knownHopsToDial) {
const connection = await this._libp2p.dial(peerId)
await this._addListenRelay(connection, peerId.toB58String())
await this._tryToListenOnRelay(peerId)
// Check if already listening on enough relays
if (this._listenRelays.size >= this.maxListeners) {
@@ -247,12 +256,11 @@ class AutoRelay {
if (!provider.multiaddrs.length) {
continue
}
const peerId = provider.id
this._peerStore.addressBook.add(peerId, provider.multiaddrs)
const connection = await this._libp2p.dial(peerId)
await this._addListenRelay(connection, peerId.toB58String())
await this._tryToListenOnRelay(peerId)
// Check if already listening on enough relays
if (this._listenRelays.size >= this.maxListeners) {
@@ -260,7 +268,19 @@ class AutoRelay {
}
}
} catch (err) {
log.error(err)
this._onError(err)
}
}
/**
* @param {PeerId} peerId
*/
async _tryToListenOnRelay (peerId) {
try {
const connection = await this._libp2p.dial(peerId)
await this._addListenRelay(connection, peerId.toB58String())
} catch (err) {
this._onError(err, `could not connect and listen on known hop relay ${peerId.toB58String()}`)
}
}
}

View File

@@ -18,17 +18,17 @@ const { stop } = require('./stop')
const multicodec = require('./../multicodec')
/**
* @typedef {import('../../types').CircuitRequest} CircuitRequest
* @typedef {import('../protocol').ICircuitRelay} ICircuitRelay
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
* @typedef {import('./stream-handler')<CircuitRequest>} StreamHandlerT
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
* @typedef {import('../transport')} Transport
*/
/**
* @typedef {Object} HopRequest
* @property {Connection} connection
* @property {CircuitRequest} request
* @property {StreamHandlerT} streamHandler
* @property {ICircuitRelay} request
* @property {StreamHandler} streamHandler
* @property {Transport} circuit
*/
@@ -58,6 +58,11 @@ async function handleHop ({
return log.error('invalid hop request via peer %s', connection.remotePeer.toB58String(), err)
}
if (!request.dstPeer) {
log('HOP request received but we do not receive a dstPeer')
return
}
// Get the connection to the destination (stop) peer
const destinationPeer = new PeerId(request.dstPeer.id)
@@ -113,8 +118,8 @@ async function handleHop ({
*
* @param {object} options
* @param {Connection} options.connection - Connection to the relay
* @param {CircuitRequest} options.request
* @returns {Promise<Connection>}
* @param {ICircuitRelay} options.request
* @returns {Promise<MuxedStream>}
*/
async function hop ({
connection,
@@ -128,6 +133,10 @@ async function hop ({
const response = await streamHandler.read()
if (!response) {
throw errCode(new Error('HOP request had no response'), Errors.ERR_HOP_REQUEST_FAILED)
}
if (response.code === CircuitPB.Status.SUCCESS) {
log('hop request was successful')
return streamHandler.rest()
@@ -159,7 +168,7 @@ async function canHop ({
const response = await streamHandler.read()
await streamHandler.close()
if (response.code !== CircuitPB.Status.SUCCESS) {
if (!response || response.code !== CircuitPB.Status.SUCCESS) {
return false
}
@@ -171,7 +180,7 @@ async function canHop ({
*
* @param {Object} options
* @param {Connection} options.connection
* @param {StreamHandlerT} options.streamHandler
* @param {StreamHandler} options.streamHandler
* @param {Transport} options.circuit
* @private
*/

View File

@@ -13,8 +13,7 @@ const { validateAddrs } = require('./utils')
/**
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
* @typedef {import('../../types').CircuitRequest} CircuitRequest
* @typedef {import('./stream-handler')<CircuitRequest>} StreamHandlerT
* @typedef {import('../protocol').ICircuitRelay} ICircuitRelay
*/
/**
@@ -23,8 +22,8 @@ const { validateAddrs } = require('./utils')
* @private
* @param {Object} options
* @param {Connection} options.connection
* @param {CircuitRequest} options.request - The CircuitRelay protobuf request (unencoded)
* @param {StreamHandlerT} options.streamHandler
* @param {ICircuitRelay} options.request - The CircuitRelay protobuf request (unencoded)
* @param {StreamHandler} options.streamHandler
* @returns {Promise<MuxedStream>|void} Resolves a duplex iterable
*/
module.exports.handleStop = function handleStop ({
@@ -54,7 +53,7 @@ module.exports.handleStop = function handleStop ({
* @private
* @param {Object} options
* @param {Connection} options.connection
* @param {CircuitRequest} options.request - The CircuitRelay protobuf request (unencoded)
* @param {ICircuitRelay} options.request - The CircuitRelay protobuf request (unencoded)
* @returns {Promise<MuxedStream|void>} Resolves a duplex iterable
*/
module.exports.stop = async function stop ({
@@ -68,6 +67,10 @@ module.exports.stop = async function stop ({
streamHandler.write(request)
const response = await streamHandler.read()
if (!response) {
return streamHandler.close()
}
if (response.code === CircuitPB.Status.SUCCESS) {
log('stop request to %s was successful', connection.remotePeer.toB58String())
return streamHandler.rest()

View File

@@ -6,16 +6,15 @@ const log = Object.assign(debug('libp2p:circuit:stream-handler'), {
})
const lp = require('it-length-prefixed')
// @ts-ignore it-handshake does not export types
const handshake = require('it-handshake')
const { CircuitRelay: CircuitPB } = require('../protocol')
const { CircuitRelay } = require('../protocol')
/**
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
* @typedef {import('../protocol').ICircuitRelay} ICircuitRelay
*/
/**
* @template T
*/
class StreamHandler {
/**
* Create a stream handler for connection
@@ -29,6 +28,7 @@ class StreamHandler {
this.stream = stream
this.shake = handshake(this.stream)
// @ts-ignore options are not optional
this.decoder = lp.decode.fromReader(this.shake.reader, { maxDataLength: maxLength })
}
@@ -36,12 +36,11 @@ class StreamHandler {
* Read and decode message
*
* @async
* @returns {Promise<T|undefined>}
*/
async read () {
const msg = await this.decoder.next()
if (msg.value) {
const value = CircuitPB.decode(msg.value.slice())
const value = CircuitRelay.decode(msg.value.slice())
log('read message type', value.type)
return value
}
@@ -54,13 +53,13 @@ class StreamHandler {
/**
* Encode and write array of buffers
*
* @param {CircuitPB} msg - An unencoded CircuitRelay protobuf message
* @param {ICircuitRelay} msg - An unencoded CircuitRelay protobuf message
* @returns {void}
*/
write (msg) {
log('write message type %s', msg.type)
// @ts-ignore lp.encode expects type type 'Buffer | BufferList', not 'Uint8Array'
this.shake.write(lp.encode.single(CircuitPB.encode(msg)))
this.shake.write(lp.encode.single(CircuitRelay.encode(msg).finish()))
}
/**
@@ -73,6 +72,9 @@ class StreamHandler {
return this.shake.stream
}
/**
* @param {ICircuitRelay} msg - An unencoded CircuitRelay protobuf message
*/
end (msg) {
this.write(msg)
this.close()

View File

@@ -1,18 +1,18 @@
'use strict'
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const { CircuitRelay } = require('../protocol')
/**
* @typedef {import('./stream-handler')} StreamHandler
* @typedef {import('../../types').CircuitStatus} CircuitStatus
* @typedef {import('../protocol').ICircuitRelay} ICircuitRelay
*/
/**
* Write a response
*
* @param {StreamHandler} streamHandler
* @param {CircuitStatus} status
* @param {import('../protocol').CircuitRelay.Status} status
*/
function writeResponse (streamHandler, status) {
streamHandler.write({
@@ -24,14 +24,16 @@ function writeResponse (streamHandler, status) {
/**
* Validate incomming HOP/STOP message
*
* @param {*} msg - A CircuitRelay unencoded protobuf message
* @param {ICircuitRelay} msg - A CircuitRelay unencoded protobuf message
* @param {StreamHandler} streamHandler
*/
function validateAddrs (msg, streamHandler) {
try {
msg.dstPeer.addrs.forEach((addr) => {
return multiaddr(addr)
})
if (msg.dstPeer && msg.dstPeer.addrs) {
msg.dstPeer.addrs.forEach((addr) => {
return new Multiaddr(addr)
})
}
} catch (err) {
writeResponse(streamHandler, msg.type === CircuitRelay.Type.HOP
? CircuitRelay.Status.HOP_DST_MULTIADDR_INVALID
@@ -40,9 +42,11 @@ function validateAddrs (msg, streamHandler) {
}
try {
msg.srcPeer.addrs.forEach((addr) => {
return multiaddr(addr)
})
if (msg.srcPeer && msg.srcPeer.addrs) {
msg.srcPeer.addrs.forEach((addr) => {
return new Multiaddr(addr)
})
}
} catch (err) {
writeResponse(streamHandler, msg.type === CircuitRelay.Type.HOP
? CircuitRelay.Status.HOP_SRC_MULTIADDR_INVALID

View File

@@ -8,13 +8,12 @@ const log = Object.assign(debug('libp2p:relay'), {
const {
setDelayedInterval,
clearDelayedInterval
// @ts-ignore set-delayed-interval does not export types
} = require('set-delayed-interval')
const AutoRelay = require('./auto-relay')
const { namespaceToCid } = require('./utils')
const {
ADVERTISE_BOOT_DELAY,
ADVERTISE_TTL,
RELAY_RENDEZVOUS_NS
} = require('./constants')
@@ -45,12 +44,6 @@ class Relay {
constructor (libp2p) {
this._libp2p = libp2p
this._options = {
advertise: {
bootDelay: ADVERTISE_BOOT_DELAY,
enabled: true,
ttl: ADVERTISE_TTL,
...libp2p._config.relay.advertise
},
...libp2p._config.relay
}

View File

@@ -1,10 +1,9 @@
'use strict'
const { EventEmitter } = require('events')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
/**
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('libp2p-interfaces/src/transport/types').Listener} Listener
*/
@@ -24,7 +23,7 @@ module.exports = (libp2p) => {
async function listen (addr) {
const addrString = String(addr).split('/p2p-circuit').find(a => a !== '')
const relayConn = await libp2p.dial(multiaddr(addrString))
const relayConn = await libp2p.dial(new Multiaddr(addrString))
const relayedAddr = relayConn.remoteAddr.encapsulate('/p2p-circuit')
listeningAddrs.set(relayConn.remotePeer.toB58String(), relayedAddr)

173
src/circuit/protocol/index.d.ts vendored Normal file
View File

@@ -0,0 +1,173 @@
import * as $protobuf from "protobufjs";
/** Properties of a CircuitRelay. */
export interface ICircuitRelay {
/** CircuitRelay type */
type?: (CircuitRelay.Type|null);
/** CircuitRelay srcPeer */
srcPeer?: (CircuitRelay.IPeer|null);
/** CircuitRelay dstPeer */
dstPeer?: (CircuitRelay.IPeer|null);
/** CircuitRelay code */
code?: (CircuitRelay.Status|null);
}
/** Represents a CircuitRelay. */
export class CircuitRelay implements ICircuitRelay {
/**
* Constructs a new CircuitRelay.
* @param [p] Properties to set
*/
constructor(p?: ICircuitRelay);
/** CircuitRelay type. */
public type: CircuitRelay.Type;
/** CircuitRelay srcPeer. */
public srcPeer?: (CircuitRelay.IPeer|null);
/** CircuitRelay dstPeer. */
public dstPeer?: (CircuitRelay.IPeer|null);
/** CircuitRelay code. */
public code: CircuitRelay.Status;
/**
* Encodes the specified CircuitRelay message. Does not implicitly {@link CircuitRelay.verify|verify} messages.
* @param m CircuitRelay message or plain object to encode
* @param [w] Writer to encode to
* @returns Writer
*/
public static encode(m: ICircuitRelay, w?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes a CircuitRelay message from the specified reader or buffer.
* @param r Reader or buffer to decode from
* @param [l] Message length if known beforehand
* @returns CircuitRelay
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): CircuitRelay;
/**
* Creates a CircuitRelay message from a plain object. Also converts values to their respective internal types.
* @param d Plain object
* @returns CircuitRelay
*/
public static fromObject(d: { [k: string]: any }): CircuitRelay;
/**
* Creates a plain object from a CircuitRelay message. Also converts values to other types if specified.
* @param m CircuitRelay
* @param [o] Conversion options
* @returns Plain object
*/
public static toObject(m: CircuitRelay, o?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this CircuitRelay to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}
export namespace CircuitRelay {
/** Status enum. */
enum Status {
SUCCESS = 100,
HOP_SRC_ADDR_TOO_LONG = 220,
HOP_DST_ADDR_TOO_LONG = 221,
HOP_SRC_MULTIADDR_INVALID = 250,
HOP_DST_MULTIADDR_INVALID = 251,
HOP_NO_CONN_TO_DST = 260,
HOP_CANT_DIAL_DST = 261,
HOP_CANT_OPEN_DST_STREAM = 262,
HOP_CANT_SPEAK_RELAY = 270,
HOP_CANT_RELAY_TO_SELF = 280,
STOP_SRC_ADDR_TOO_LONG = 320,
STOP_DST_ADDR_TOO_LONG = 321,
STOP_SRC_MULTIADDR_INVALID = 350,
STOP_DST_MULTIADDR_INVALID = 351,
STOP_RELAY_REFUSED = 390,
MALFORMED_MESSAGE = 400
}
/** Type enum. */
enum Type {
HOP = 1,
STOP = 2,
STATUS = 3,
CAN_HOP = 4
}
/** Properties of a Peer. */
interface IPeer {
/** Peer id */
id: Uint8Array;
/** Peer addrs */
addrs?: (Uint8Array[]|null);
}
/** Represents a Peer. */
class Peer implements IPeer {
/**
* Constructs a new Peer.
* @param [p] Properties to set
*/
constructor(p?: CircuitRelay.IPeer);
/** Peer id. */
public id: Uint8Array;
/** Peer addrs. */
public addrs: Uint8Array[];
/**
* Encodes the specified Peer message. Does not implicitly {@link CircuitRelay.Peer.verify|verify} messages.
* @param m Peer message or plain object to encode
* @param [w] Writer to encode to
* @returns Writer
*/
public static encode(m: CircuitRelay.IPeer, w?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes a Peer message from the specified reader or buffer.
* @param r Reader or buffer to decode from
* @param [l] Message length if known beforehand
* @returns Peer
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): CircuitRelay.Peer;
/**
* Creates a Peer message from a plain object. Also converts values to their respective internal types.
* @param d Plain object
* @returns Peer
*/
public static fromObject(d: { [k: string]: any }): CircuitRelay.Peer;
/**
* Creates a plain object from a Peer message. Also converts values to other types if specified.
* @param m Peer
* @param [o] Conversion options
* @returns Plain object
*/
public static toObject(m: CircuitRelay.Peer, o?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this Peer to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}
}

View File

@@ -1,46 +1,530 @@
'use strict'
const protobuf = require('protons')
/*eslint-disable*/
"use strict";
/** @type {{CircuitRelay: import('../../types').CircuitMessageProto}} */
module.exports = protobuf(`
message CircuitRelay {
var $protobuf = require("protobufjs/minimal");
enum Status {
SUCCESS = 100;
HOP_SRC_ADDR_TOO_LONG = 220;
HOP_DST_ADDR_TOO_LONG = 221;
HOP_SRC_MULTIADDR_INVALID = 250;
HOP_DST_MULTIADDR_INVALID = 251;
HOP_NO_CONN_TO_DST = 260;
HOP_CANT_DIAL_DST = 261;
HOP_CANT_OPEN_DST_STREAM = 262;
HOP_CANT_SPEAK_RELAY = 270;
HOP_CANT_RELAY_TO_SELF = 280;
STOP_SRC_ADDR_TOO_LONG = 320;
STOP_DST_ADDR_TOO_LONG = 321;
STOP_SRC_MULTIADDR_INVALID = 350;
STOP_DST_MULTIADDR_INVALID = 351;
STOP_RELAY_REFUSED = 390;
MALFORMED_MESSAGE = 400;
}
// Common aliases
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
enum Type { // RPC identifier, either HOP, STOP or STATUS
HOP = 1;
STOP = 2;
STATUS = 3;
CAN_HOP = 4;
}
// Exported root namespace
var $root = $protobuf.roots["libp2p-circuit"] || ($protobuf.roots["libp2p-circuit"] = {});
message Peer {
required bytes id = 1; // peer id
repeated bytes addrs = 2; // peer's known addresses
}
$root.CircuitRelay = (function() {
optional Type type = 1; // Type of the message
/**
* Properties of a CircuitRelay.
* @exports ICircuitRelay
* @interface ICircuitRelay
* @property {CircuitRelay.Type|null} [type] CircuitRelay type
* @property {CircuitRelay.IPeer|null} [srcPeer] CircuitRelay srcPeer
* @property {CircuitRelay.IPeer|null} [dstPeer] CircuitRelay dstPeer
* @property {CircuitRelay.Status|null} [code] CircuitRelay code
*/
optional Peer srcPeer = 2; // srcPeer and dstPeer are used when Type is HOP or STATUS
optional Peer dstPeer = 3;
/**
* Constructs a new CircuitRelay.
* @exports CircuitRelay
* @classdesc Represents a CircuitRelay.
* @implements ICircuitRelay
* @constructor
* @param {ICircuitRelay=} [p] Properties to set
*/
function CircuitRelay(p) {
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
optional Status code = 4; // Status code, used when Type is STATUS
}
`)
/**
* CircuitRelay type.
* @member {CircuitRelay.Type} type
* @memberof CircuitRelay
* @instance
*/
CircuitRelay.prototype.type = 1;
/**
* CircuitRelay srcPeer.
* @member {CircuitRelay.IPeer|null|undefined} srcPeer
* @memberof CircuitRelay
* @instance
*/
CircuitRelay.prototype.srcPeer = null;
/**
* CircuitRelay dstPeer.
* @member {CircuitRelay.IPeer|null|undefined} dstPeer
* @memberof CircuitRelay
* @instance
*/
CircuitRelay.prototype.dstPeer = null;
/**
* CircuitRelay code.
* @member {CircuitRelay.Status} code
* @memberof CircuitRelay
* @instance
*/
CircuitRelay.prototype.code = 100;
/**
* Encodes the specified CircuitRelay message. Does not implicitly {@link CircuitRelay.verify|verify} messages.
* @function encode
* @memberof CircuitRelay
* @static
* @param {ICircuitRelay} m CircuitRelay message or plain object to encode
* @param {$protobuf.Writer} [w] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
CircuitRelay.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
if (m.type != null && Object.hasOwnProperty.call(m, "type"))
w.uint32(8).int32(m.type);
if (m.srcPeer != null && Object.hasOwnProperty.call(m, "srcPeer"))
$root.CircuitRelay.Peer.encode(m.srcPeer, w.uint32(18).fork()).ldelim();
if (m.dstPeer != null && Object.hasOwnProperty.call(m, "dstPeer"))
$root.CircuitRelay.Peer.encode(m.dstPeer, w.uint32(26).fork()).ldelim();
if (m.code != null && Object.hasOwnProperty.call(m, "code"))
w.uint32(32).int32(m.code);
return w;
};
/**
* Decodes a CircuitRelay message from the specified reader or buffer.
* @function decode
* @memberof CircuitRelay
* @static
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
* @param {number} [l] Message length if known beforehand
* @returns {CircuitRelay} CircuitRelay
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
CircuitRelay.decode = function decode(r, l) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.CircuitRelay();
while (r.pos < c) {
var t = r.uint32();
switch (t >>> 3) {
case 1:
m.type = r.int32();
break;
case 2:
m.srcPeer = $root.CircuitRelay.Peer.decode(r, r.uint32());
break;
case 3:
m.dstPeer = $root.CircuitRelay.Peer.decode(r, r.uint32());
break;
case 4:
m.code = r.int32();
break;
default:
r.skipType(t & 7);
break;
}
}
return m;
};
/**
* Creates a CircuitRelay message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof CircuitRelay
* @static
* @param {Object.<string,*>} d Plain object
* @returns {CircuitRelay} CircuitRelay
*/
CircuitRelay.fromObject = function fromObject(d) {
if (d instanceof $root.CircuitRelay)
return d;
var m = new $root.CircuitRelay();
switch (d.type) {
case "HOP":
case 1:
m.type = 1;
break;
case "STOP":
case 2:
m.type = 2;
break;
case "STATUS":
case 3:
m.type = 3;
break;
case "CAN_HOP":
case 4:
m.type = 4;
break;
}
if (d.srcPeer != null) {
if (typeof d.srcPeer !== "object")
throw TypeError(".CircuitRelay.srcPeer: object expected");
m.srcPeer = $root.CircuitRelay.Peer.fromObject(d.srcPeer);
}
if (d.dstPeer != null) {
if (typeof d.dstPeer !== "object")
throw TypeError(".CircuitRelay.dstPeer: object expected");
m.dstPeer = $root.CircuitRelay.Peer.fromObject(d.dstPeer);
}
switch (d.code) {
case "SUCCESS":
case 100:
m.code = 100;
break;
case "HOP_SRC_ADDR_TOO_LONG":
case 220:
m.code = 220;
break;
case "HOP_DST_ADDR_TOO_LONG":
case 221:
m.code = 221;
break;
case "HOP_SRC_MULTIADDR_INVALID":
case 250:
m.code = 250;
break;
case "HOP_DST_MULTIADDR_INVALID":
case 251:
m.code = 251;
break;
case "HOP_NO_CONN_TO_DST":
case 260:
m.code = 260;
break;
case "HOP_CANT_DIAL_DST":
case 261:
m.code = 261;
break;
case "HOP_CANT_OPEN_DST_STREAM":
case 262:
m.code = 262;
break;
case "HOP_CANT_SPEAK_RELAY":
case 270:
m.code = 270;
break;
case "HOP_CANT_RELAY_TO_SELF":
case 280:
m.code = 280;
break;
case "STOP_SRC_ADDR_TOO_LONG":
case 320:
m.code = 320;
break;
case "STOP_DST_ADDR_TOO_LONG":
case 321:
m.code = 321;
break;
case "STOP_SRC_MULTIADDR_INVALID":
case 350:
m.code = 350;
break;
case "STOP_DST_MULTIADDR_INVALID":
case 351:
m.code = 351;
break;
case "STOP_RELAY_REFUSED":
case 390:
m.code = 390;
break;
case "MALFORMED_MESSAGE":
case 400:
m.code = 400;
break;
}
return m;
};
/**
* Creates a plain object from a CircuitRelay message. Also converts values to other types if specified.
* @function toObject
* @memberof CircuitRelay
* @static
* @param {CircuitRelay} m CircuitRelay
* @param {$protobuf.IConversionOptions} [o] Conversion options
* @returns {Object.<string,*>} Plain object
*/
CircuitRelay.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (o.defaults) {
d.type = o.enums === String ? "HOP" : 1;
d.srcPeer = null;
d.dstPeer = null;
d.code = o.enums === String ? "SUCCESS" : 100;
}
if (m.type != null && m.hasOwnProperty("type")) {
d.type = o.enums === String ? $root.CircuitRelay.Type[m.type] : m.type;
}
if (m.srcPeer != null && m.hasOwnProperty("srcPeer")) {
d.srcPeer = $root.CircuitRelay.Peer.toObject(m.srcPeer, o);
}
if (m.dstPeer != null && m.hasOwnProperty("dstPeer")) {
d.dstPeer = $root.CircuitRelay.Peer.toObject(m.dstPeer, o);
}
if (m.code != null && m.hasOwnProperty("code")) {
d.code = o.enums === String ? $root.CircuitRelay.Status[m.code] : m.code;
}
return d;
};
/**
* Converts this CircuitRelay to JSON.
* @function toJSON
* @memberof CircuitRelay
* @instance
* @returns {Object.<string,*>} JSON object
*/
CircuitRelay.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
/**
* Status enum.
* @name CircuitRelay.Status
* @enum {number}
* @property {number} SUCCESS=100 SUCCESS value
* @property {number} HOP_SRC_ADDR_TOO_LONG=220 HOP_SRC_ADDR_TOO_LONG value
* @property {number} HOP_DST_ADDR_TOO_LONG=221 HOP_DST_ADDR_TOO_LONG value
* @property {number} HOP_SRC_MULTIADDR_INVALID=250 HOP_SRC_MULTIADDR_INVALID value
* @property {number} HOP_DST_MULTIADDR_INVALID=251 HOP_DST_MULTIADDR_INVALID value
* @property {number} HOP_NO_CONN_TO_DST=260 HOP_NO_CONN_TO_DST value
* @property {number} HOP_CANT_DIAL_DST=261 HOP_CANT_DIAL_DST value
* @property {number} HOP_CANT_OPEN_DST_STREAM=262 HOP_CANT_OPEN_DST_STREAM value
* @property {number} HOP_CANT_SPEAK_RELAY=270 HOP_CANT_SPEAK_RELAY value
* @property {number} HOP_CANT_RELAY_TO_SELF=280 HOP_CANT_RELAY_TO_SELF value
* @property {number} STOP_SRC_ADDR_TOO_LONG=320 STOP_SRC_ADDR_TOO_LONG value
* @property {number} STOP_DST_ADDR_TOO_LONG=321 STOP_DST_ADDR_TOO_LONG value
* @property {number} STOP_SRC_MULTIADDR_INVALID=350 STOP_SRC_MULTIADDR_INVALID value
* @property {number} STOP_DST_MULTIADDR_INVALID=351 STOP_DST_MULTIADDR_INVALID value
* @property {number} STOP_RELAY_REFUSED=390 STOP_RELAY_REFUSED value
* @property {number} MALFORMED_MESSAGE=400 MALFORMED_MESSAGE value
*/
CircuitRelay.Status = (function() {
var valuesById = {}, values = Object.create(valuesById);
values[valuesById[100] = "SUCCESS"] = 100;
values[valuesById[220] = "HOP_SRC_ADDR_TOO_LONG"] = 220;
values[valuesById[221] = "HOP_DST_ADDR_TOO_LONG"] = 221;
values[valuesById[250] = "HOP_SRC_MULTIADDR_INVALID"] = 250;
values[valuesById[251] = "HOP_DST_MULTIADDR_INVALID"] = 251;
values[valuesById[260] = "HOP_NO_CONN_TO_DST"] = 260;
values[valuesById[261] = "HOP_CANT_DIAL_DST"] = 261;
values[valuesById[262] = "HOP_CANT_OPEN_DST_STREAM"] = 262;
values[valuesById[270] = "HOP_CANT_SPEAK_RELAY"] = 270;
values[valuesById[280] = "HOP_CANT_RELAY_TO_SELF"] = 280;
values[valuesById[320] = "STOP_SRC_ADDR_TOO_LONG"] = 320;
values[valuesById[321] = "STOP_DST_ADDR_TOO_LONG"] = 321;
values[valuesById[350] = "STOP_SRC_MULTIADDR_INVALID"] = 350;
values[valuesById[351] = "STOP_DST_MULTIADDR_INVALID"] = 351;
values[valuesById[390] = "STOP_RELAY_REFUSED"] = 390;
values[valuesById[400] = "MALFORMED_MESSAGE"] = 400;
return values;
})();
/**
* Type enum.
* @name CircuitRelay.Type
* @enum {number}
* @property {number} HOP=1 HOP value
* @property {number} STOP=2 STOP value
* @property {number} STATUS=3 STATUS value
* @property {number} CAN_HOP=4 CAN_HOP value
*/
CircuitRelay.Type = (function() {
var valuesById = {}, values = Object.create(valuesById);
values[valuesById[1] = "HOP"] = 1;
values[valuesById[2] = "STOP"] = 2;
values[valuesById[3] = "STATUS"] = 3;
values[valuesById[4] = "CAN_HOP"] = 4;
return values;
})();
CircuitRelay.Peer = (function() {
/**
* Properties of a Peer.
* @memberof CircuitRelay
* @interface IPeer
* @property {Uint8Array} id Peer id
* @property {Array.<Uint8Array>|null} [addrs] Peer addrs
*/
/**
* Constructs a new Peer.
* @memberof CircuitRelay
* @classdesc Represents a Peer.
* @implements IPeer
* @constructor
* @param {CircuitRelay.IPeer=} [p] Properties to set
*/
function Peer(p) {
this.addrs = [];
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
/**
* Peer id.
* @member {Uint8Array} id
* @memberof CircuitRelay.Peer
* @instance
*/
Peer.prototype.id = $util.newBuffer([]);
/**
* Peer addrs.
* @member {Array.<Uint8Array>} addrs
* @memberof CircuitRelay.Peer
* @instance
*/
Peer.prototype.addrs = $util.emptyArray;
/**
* Encodes the specified Peer message. Does not implicitly {@link CircuitRelay.Peer.verify|verify} messages.
* @function encode
* @memberof CircuitRelay.Peer
* @static
* @param {CircuitRelay.IPeer} m Peer message or plain object to encode
* @param {$protobuf.Writer} [w] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Peer.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
w.uint32(10).bytes(m.id);
if (m.addrs != null && m.addrs.length) {
for (var i = 0; i < m.addrs.length; ++i)
w.uint32(18).bytes(m.addrs[i]);
}
return w;
};
/**
* Decodes a Peer message from the specified reader or buffer.
* @function decode
* @memberof CircuitRelay.Peer
* @static
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
* @param {number} [l] Message length if known beforehand
* @returns {CircuitRelay.Peer} Peer
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Peer.decode = function decode(r, l) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.CircuitRelay.Peer();
while (r.pos < c) {
var t = r.uint32();
switch (t >>> 3) {
case 1:
m.id = r.bytes();
break;
case 2:
if (!(m.addrs && m.addrs.length))
m.addrs = [];
m.addrs.push(r.bytes());
break;
default:
r.skipType(t & 7);
break;
}
}
if (!m.hasOwnProperty("id"))
throw $util.ProtocolError("missing required 'id'", { instance: m });
return m;
};
/**
* Creates a Peer message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof CircuitRelay.Peer
* @static
* @param {Object.<string,*>} d Plain object
* @returns {CircuitRelay.Peer} Peer
*/
Peer.fromObject = function fromObject(d) {
if (d instanceof $root.CircuitRelay.Peer)
return d;
var m = new $root.CircuitRelay.Peer();
if (d.id != null) {
if (typeof d.id === "string")
$util.base64.decode(d.id, m.id = $util.newBuffer($util.base64.length(d.id)), 0);
else if (d.id.length)
m.id = d.id;
}
if (d.addrs) {
if (!Array.isArray(d.addrs))
throw TypeError(".CircuitRelay.Peer.addrs: array expected");
m.addrs = [];
for (var i = 0; i < d.addrs.length; ++i) {
if (typeof d.addrs[i] === "string")
$util.base64.decode(d.addrs[i], m.addrs[i] = $util.newBuffer($util.base64.length(d.addrs[i])), 0);
else if (d.addrs[i].length)
m.addrs[i] = d.addrs[i];
}
}
return m;
};
/**
* Creates a plain object from a Peer message. Also converts values to other types if specified.
* @function toObject
* @memberof CircuitRelay.Peer
* @static
* @param {CircuitRelay.Peer} m Peer
* @param {$protobuf.IConversionOptions} [o] Conversion options
* @returns {Object.<string,*>} Plain object
*/
Peer.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (o.arrays || o.defaults) {
d.addrs = [];
}
if (o.defaults) {
if (o.bytes === String)
d.id = "";
else {
d.id = [];
if (o.bytes !== Array)
d.id = $util.newBuffer(d.id);
}
}
if (m.id != null && m.hasOwnProperty("id")) {
d.id = o.bytes === String ? $util.base64.encode(m.id, 0, m.id.length) : o.bytes === Array ? Array.prototype.slice.call(m.id) : m.id;
}
if (m.addrs && m.addrs.length) {
d.addrs = [];
for (var j = 0; j < m.addrs.length; ++j) {
d.addrs[j] = o.bytes === String ? $util.base64.encode(m.addrs[j], 0, m.addrs[j].length) : o.bytes === Array ? Array.prototype.slice.call(m.addrs[j]) : m.addrs[j];
}
}
return d;
};
/**
* Converts this Peer to JSON.
* @function toJSON
* @memberof CircuitRelay.Peer
* @instance
* @returns {Object.<string,*>} JSON object
*/
Peer.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return Peer;
})();
return CircuitRelay;
})();
module.exports = $root;

View File

@@ -0,0 +1,42 @@
syntax = "proto2";
message CircuitRelay {
enum Status {
SUCCESS = 100;
HOP_SRC_ADDR_TOO_LONG = 220;
HOP_DST_ADDR_TOO_LONG = 221;
HOP_SRC_MULTIADDR_INVALID = 250;
HOP_DST_MULTIADDR_INVALID = 251;
HOP_NO_CONN_TO_DST = 260;
HOP_CANT_DIAL_DST = 261;
HOP_CANT_OPEN_DST_STREAM = 262;
HOP_CANT_SPEAK_RELAY = 270;
HOP_CANT_RELAY_TO_SELF = 280;
STOP_SRC_ADDR_TOO_LONG = 320;
STOP_DST_ADDR_TOO_LONG = 321;
STOP_SRC_MULTIADDR_INVALID = 350;
STOP_DST_MULTIADDR_INVALID = 351;
STOP_RELAY_REFUSED = 390;
MALFORMED_MESSAGE = 400;
}
enum Type { // RPC identifier, either HOP, STOP or STATUS
HOP = 1;
STOP = 2;
STATUS = 3;
CAN_HOP = 4;
}
message Peer {
required bytes id = 1; // peer id
repeated bytes addrs = 2; // peer's known addresses
}
optional Type type = 1; // Type of the message
optional Peer srcPeer = 2; // srcPeer and dstPeer are used when Type is HOP or STATUS
optional Peer dstPeer = 3;
optional Status code = 4; // Status code, used when Type is STATUS
}

View File

@@ -5,10 +5,12 @@ const log = Object.assign(debug('libp2p:circuit'), {
error: debug('libp2p:circuit:err')
})
const errCode = require('err-code')
const mafmt = require('mafmt')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const PeerId = require('peer-id')
const { CircuitRelay: CircuitPB } = require('./protocol')
const { codes } = require('../errors')
const toConnection = require('libp2p-utils/src/stream-to-ma-conn')
@@ -21,10 +23,8 @@ const StreamHandler = require('./circuit/stream-handler')
const transportSymbol = Symbol.for('@libp2p/js-libp2p-circuit/circuit')
/**
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
* @typedef {import('../types').CircuitRequest} CircuitRequest
*/
class Circuit {
@@ -54,7 +54,7 @@ class Circuit {
* @param {MuxedStream} props.stream
*/
async _onProtocol ({ connection, stream }) {
/** @type {import('./circuit/stream-handler')<CircuitRequest>} */
/** @type {import('./circuit/stream-handler')} */
const streamHandler = new StreamHandler({ stream })
const request = await streamHandler.read()
@@ -96,8 +96,10 @@ class Circuit {
}
if (virtualConnection) {
const remoteAddr = multiaddr(request.dstPeer.addrs[0])
const localAddr = multiaddr(request.srcPeer.addrs[0])
// @ts-ignore dst peer will not be undefined
const remoteAddr = new Multiaddr(request.dstPeer.addrs[0])
// @ts-ignore src peer will not be undefined
const localAddr = new Multiaddr(request.srcPeer.addrs[0])
const maConn = toConnection({
stream: virtualConnection,
remoteAddr,
@@ -123,10 +125,19 @@ class Circuit {
async dial (ma, options) {
// Check the multiaddr to see if it contains a relay and a destination peer
const addrs = ma.toString().split('/p2p-circuit')
const relayAddr = multiaddr(addrs[0])
const destinationAddr = multiaddr(addrs[addrs.length - 1])
const relayPeer = PeerId.createFromCID(relayAddr.getPeerId())
const destinationPeer = PeerId.createFromCID(destinationAddr.getPeerId())
const relayAddr = new Multiaddr(addrs[0])
const destinationAddr = new Multiaddr(addrs[addrs.length - 1])
const relayId = relayAddr.getPeerId()
const destinationId = destinationAddr.getPeerId()
if (!relayId || !destinationId) {
const errMsg = 'Circuit relay dial failed as addresses did not have peer id'
log.error(errMsg)
throw errCode(new Error(errMsg), codes.ERR_RELAYED_DIAL)
}
const relayPeer = PeerId.createFromCID(relayId)
const destinationPeer = PeerId.createFromCID(destinationId)
let disconnectOnFailure = false
let relayConnection = this._connectionManager.get(relayPeer)
@@ -146,7 +157,7 @@ class Circuit {
},
dstPeer: {
id: destinationPeer.toBytes(),
addrs: [multiaddr(destinationAddr).bytes]
addrs: [new Multiaddr(destinationAddr).bytes]
}
}
})

View File

@@ -1,6 +1,7 @@
'use strict'
const mergeOptions = require('merge-options')
// @ts-ignore no types in multiaddr path
const { dnsaddrResolver } = require('multiaddr/src/resolvers')
const Constants = require('./constants')
@@ -10,11 +11,18 @@ const RelayConstants = require('./circuit/constants')
const { publicAddressesFirst } = require('libp2p-utils/src/address-sort')
const { FaultTolerance } = require('./transport-manager')
/**
* @typedef {import('multiaddr').Multiaddr} Multiaddr
* @typedef {import('.').Libp2pOptions} Libp2pOptions
* @typedef {import('.').constructorOptions} constructorOptions
*/
const DefaultConfig = {
addresses: {
listen: [],
announce: [],
noAnnounce: []
noAnnounce: [],
announceFilter: (/** @type {Multiaddr[]} */ multiaddrs) => multiaddrs
},
connectionManager: {
minConnections: 25
@@ -95,10 +103,15 @@ const DefaultConfig = {
}
}
/**
* @param {Libp2pOptions} opts
* @returns {DefaultConfig & Libp2pOptions & constructorOptions}
*/
module.exports.validate = (opts) => {
opts = mergeOptions(DefaultConfig, opts)
/** @type {DefaultConfig & Libp2pOptions & constructorOptions} */
const resultingOptions = mergeOptions(DefaultConfig, opts)
if (opts.modules.transport.length < 1) throw new Error("'options.modules.transport' must contain at least 1 transport")
if (resultingOptions.modules.transport.length < 1) throw new Error("'options.modules.transport' must contain at least 1 transport")
return opts
return resultingOptions
}

View File

@@ -8,10 +8,9 @@ const log = Object.assign(debug('libp2p:connection-manager'), {
const errcode = require('err-code')
const mergeOptions = require('merge-options')
const LatencyMonitor = require('./latency-monitor')
// @ts-ignore retimer does not have types
const retimer = require('retimer')
/** @typedef {import('../types').EventEmitterFactory} Events */
/** @type Events */
const EventEmitter = require('events')
const PeerId = require('peer-id')
@@ -188,8 +187,10 @@ class ConnectionManager extends EventEmitter {
_checkMetrics () {
if (this._libp2p.metrics) {
const movingAverages = this._libp2p.metrics.global.movingAverages
// @ts-ignore moving averages object types
const received = movingAverages.dataReceived[this._options.movingAverageInterval].movingAverage()
this._checkMaxLimit('maxReceivedData', received)
// @ts-ignore moving averages object types
const sent = movingAverages.dataSent[this._options.movingAverageInterval].movingAverage()
this._checkMaxLimit('maxSentData', sent)
const total = received + sent
@@ -362,7 +363,7 @@ class ConnectionManager extends EventEmitter {
*/
_maybeDisconnectOne () {
if (this._options.minConnections < this.connections.size) {
const peerValues = Array.from(this._peerValues).sort(byPeerValue)
const peerValues = Array.from(new Map([...this._peerValues.entries()].sort((a, b) => a[1] - b[1])))
log('%s: sorted peer values: %j', this._peerId, peerValues)
const disconnectPeer = peerValues[0]
if (disconnectPeer) {
@@ -381,7 +382,3 @@ class ConnectionManager extends EventEmitter {
}
module.exports = ConnectionManager
function byPeerValue (peerValueEntryA, peerValueEntryB) {
return peerValueEntryA[1] - peerValueEntryB[1]
}

View File

@@ -5,8 +5,6 @@
* 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)
*/
/** @typedef {import('../types').EventEmitterFactory} Events */
/** @type Events */
const EventEmitter = require('events')
const VisibilityChangeEmitter = require('./visibility-change-emitter')
const debug = require('debug')('latency-monitor:LatencyMonitor')
@@ -59,7 +57,8 @@ class LatencyMonitor extends EventEmitter {
that._latecyCheckMultiply = 2 * (that.latencyRandomPercentage / 100.0) * that.latencyCheckIntervalMs
that._latecyCheckSubtract = that._latecyCheckMultiply / 2
that.dataEmitIntervalMs = (dataEmitIntervalMs === null || dataEmitIntervalMs === 0) ? undefined
that.dataEmitIntervalMs = (dataEmitIntervalMs === null || dataEmitIntervalMs === 0)
? undefined
: dataEmitIntervalMs || 5 * 1000 // 5s
debug('latencyCheckIntervalMs: %s dataEmitIntervalMs: %s',
that.latencyCheckIntervalMs, that.dataEmitIntervalMs)
@@ -174,7 +173,8 @@ class LatencyMonitor extends EventEmitter {
events: this._latencyData.events,
minMs: this._latencyData.minMs,
maxMs: this._latencyData.maxMs,
avgMs: this._latencyData.events ? this._latencyData.totalMs / this._latencyData.events
avgMs: this._latencyData.events
? this._latencyData.totalMs / this._latencyData.events
: Number.POSITIVE_INFINITY,
lengthMs: this.getDeltaMS(this._latencyData.startTime)
}

View File

@@ -6,8 +6,6 @@
*/
'use strict'
/** @typedef {import('../types').EventEmitterFactory} Events */
/** @type Events */
const EventEmitter = require('events')
const debug = require('debug')('latency-monitor:VisibilityChangeEmitter')

View File

@@ -14,8 +14,9 @@ const { pipe } = require('it-pipe')
/**
* @typedef {import('peer-id')} PeerId
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('multiaddr').Multiaddr} Multiaddr
* @typedef {import('cids')} CID
* @typedef {import('libp2p-interfaces/src/content-routing/types')} ContentRoutingModule
*/
/**
@@ -31,11 +32,12 @@ class ContentRouting {
*/
constructor (libp2p) {
this.libp2p = libp2p
/** @type {ContentRoutingModule[]} */
this.routers = libp2p._modules.contentRouting || []
this.dht = libp2p._dht
// If we have the dht, add it to the available content routers
if (this.dht) {
if (this.dht && libp2p._config.dht.enabled) {
this.routers.push(this.dht)
}
}

View File

@@ -7,7 +7,7 @@ const take = require('it-take')
/**
* @typedef {import('peer-id')} PeerId
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('multiaddr').Multiaddr} Multiaddr
*/
/**

View File

@@ -3,13 +3,14 @@
const errCode = require('err-code')
const AbortController = require('abort-controller').default
const { anySignal } = require('any-signal')
// @ts-ignore p-fifo does not export types
const FIFO = require('p-fifo')
const pAny = require('p-any')
/**
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
* @typedef {import('./')} Dialer
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('multiaddr').Multiaddr} Multiaddr
*/
/**

View File

@@ -5,7 +5,8 @@ const log = Object.assign(debug('libp2p:dialer'), {
error: debug('libp2p:dialer:err')
})
const errCode = require('err-code')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
// @ts-ignore timeout-abourt-controles does not export types
const TimeoutController = require('timeout-abort-controller')
const { anySignal } = require('any-signal')
@@ -22,7 +23,6 @@ const {
/**
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('peer-id')} PeerId
* @typedef {import('../peer-store')} PeerStore
* @typedef {import('../peer-store/address-book').Address} Address
@@ -38,9 +38,9 @@ const {
*
* @typedef {Object} DialerOptions
* @property {(addresses: Address[]) => Address[]} [options.addressSorter = publicAddressesFirst] - Sort the known addresses of a peer before trying to dial.
* @property {number} [concurrency = MAX_PARALLEL_DIALS] - Number of max concurrent dials.
* @property {number} [perPeerLimit = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
* @property {number} [timeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
* @property {number} [maxParallelDials = MAX_PARALLEL_DIALS] - Number of max concurrent dials.
* @property {number} [maxDialsPerPeer = MAX_PER_PEER_DIALS] - Number of max concurrent dials per peer.
* @property {number} [dialTimeout = DIAL_TIMEOUT] - How long a dial attempt is allowed to take.
* @property {Record<string, Resolver>} [resolvers = {}] - multiaddr resolvers to use when dialing
*
* @typedef DialTarget
@@ -50,7 +50,7 @@ const {
* @typedef PendingDial
* @property {DialRequest} dialRequest
* @property {TimeoutController} controller
* @property {Promise} promise
* @property {Promise<Connection>} promise
* @property {function():void} destroy
*/
@@ -63,22 +63,22 @@ class Dialer {
transportManager,
peerStore,
addressSorter = publicAddressesFirst,
concurrency = MAX_PARALLEL_DIALS,
timeout = DIAL_TIMEOUT,
perPeerLimit = MAX_PER_PEER_DIALS,
maxParallelDials = MAX_PARALLEL_DIALS,
dialTimeout = DIAL_TIMEOUT,
maxDialsPerPeer = MAX_PER_PEER_DIALS,
resolvers = {}
}) {
this.transportManager = transportManager
this.peerStore = peerStore
this.addressSorter = addressSorter
this.concurrency = concurrency
this.timeout = timeout
this.perPeerLimit = perPeerLimit
this.tokens = [...new Array(concurrency)].map((_, index) => index)
this.maxParallelDials = maxParallelDials
this.timeout = dialTimeout
this.maxDialsPerPeer = maxDialsPerPeer
this.tokens = [...new Array(maxParallelDials)].map((_, index) => index)
this._pendingDials = new Map()
for (const [key, value] of Object.entries(resolvers)) {
multiaddr.resolvers.set(key, value)
Multiaddr.resolvers.set(key, value)
}
}
@@ -110,7 +110,7 @@ class Dialer {
const dialTarget = await this._createDialTarget(peer)
if (!dialTarget.addrs.length) {
throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES)
throw errCode(new Error('The dial request has no valid addresses'), codes.ERR_NO_VALID_ADDRESSES)
}
const pendingDial = this._pendingDials.get(dialTarget.id) || this._createPendingDial(dialTarget, options)
@@ -134,6 +134,7 @@ class Dialer {
* Creates a DialTarget. The DialTarget is used to create and track
* the DialRequest to a given peer.
* If a multiaddr is received it should be the first address attempted.
* Multiaddrs not supported by the available transports will be filtered out.
*
* @private
* @param {PeerId|Multiaddr|string} peer - A PeerId or Multiaddr
@@ -150,20 +151,24 @@ class Dialer {
// If received a multiaddr to dial, it should be the first to use
// But, if we know other multiaddrs for the peer, we should try them too.
if (multiaddr.isMultiaddr(peer)) {
if (Multiaddr.isMultiaddr(peer)) {
knownAddrs = knownAddrs.filter((addr) => !peer.equals(addr))
knownAddrs.unshift(peer)
}
/** @type {Multiaddr[]} */
const addrs = []
for (const a of knownAddrs) {
const resolvedAddrs = await this._resolve(a)
resolvedAddrs.forEach(ra => addrs.push(ra))
}
// Multiaddrs not supported by the available transports will be filtered out.
const supportedAddrs = addrs.filter(a => this.transportManager.transportForMultiaddr(a))
return {
id: id.toB58String(),
addrs
addrs: supportedAddrs
}
}
@@ -177,6 +182,10 @@ class Dialer {
* @returns {PendingDial}
*/
_createPendingDial (dialTarget, options = {}) {
/**
* @param {Multiaddr} addr
* @param {{ signal: { aborted: any; }; }} options
*/
const dialAction = (addr, options) => {
if (options.signal.aborted) throw errCode(new Error('already aborted'), codes.ERR_ALREADY_ABORTED)
return this.transportManager.dial(addr, options)
@@ -207,13 +216,19 @@ class Dialer {
return pendingDial
}
/**
* @param {number} num
*/
getTokens (num) {
const total = Math.min(num, this.perPeerLimit, this.tokens.length)
const total = Math.min(num, this.maxDialsPerPeer, this.tokens.length)
const tokens = this.tokens.splice(0, total)
log('%d tokens request, returning %d, %d remaining', num, total, this.tokens.length)
return tokens
}
/**
* @param {number} token
*/
releaseToken (token) {
// Guard against duplicate releases
if (this.tokens.indexOf(token) > -1) return
@@ -259,7 +274,7 @@ class Dialer {
*/
async _resolveRecord (ma) {
try {
ma = multiaddr(ma.toString()) // Use current multiaddr module
ma = new Multiaddr(ma.toString()) // Use current multiaddr module
const multiaddrs = await ma.resolve()
return multiaddrs
} catch (_) {

View File

@@ -11,11 +11,13 @@ exports.codes = {
PUBSUB_NOT_STARTED: 'ERR_PUBSUB_NOT_STARTED',
DHT_NOT_STARTED: 'ERR_DHT_NOT_STARTED',
CONN_ENCRYPTION_REQUIRED: 'ERR_CONN_ENCRYPTION_REQUIRED',
ERR_INVALID_PROTOCOLS_FOR_STREAM: 'ERR_INVALID_PROTOCOLS_FOR_STREAM',
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_RELAYED_DIAL: 'ERR_RELAYED_DIAL',
ERR_DIALED_SELF: 'ERR_DIALED_SELF',
ERR_DISCOVERED_SELF: 'ERR_DISCOVERED_SELF',
ERR_DUPLICATE_TRANSPORT: 'ERR_DUPLICATE_TRANSPORT',

View File

@@ -1,15 +1,11 @@
'use strict'
const PeerId = require('peer-id')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const errCode = require('err-code')
const { codes } = require('./errors')
/**
* @typedef {import('multiaddr')} Multiaddr
*/
/**
* Converts the given `peer` to a `Peer` object.
* If a multiaddr is received, the addressBook is updated.
@@ -19,14 +15,23 @@ const { codes } = require('./errors')
*/
function getPeer (peer) {
if (typeof peer === 'string') {
peer = multiaddr(peer)
peer = new Multiaddr(peer)
}
let addr
if (multiaddr.isMultiaddr(peer)) {
if (Multiaddr.isMultiaddr(peer)) {
addr = peer
const idStr = peer.getPeerId()
if (!idStr) {
throw errCode(
new Error(`${peer} does not have a valid peer type`),
codes.ERR_INVALID_MULTIADDR
)
}
try {
peer = PeerId.createFromB58String(peer.getPeerId())
peer = PeerId.createFromB58String(idStr)
} catch (err) {
throw errCode(
new Error(`${peer} is not a valid peer type`),

View File

@@ -5,14 +5,14 @@ const log = Object.assign(debug('libp2p:identify'), {
error: debug('libp2p:identify:err')
})
const errCode = require('err-code')
const pb = require('it-protocol-buffers')
const lp = require('it-length-prefixed')
const { pipe } = require('it-pipe')
const { collect, take, consume } = require('streaming-iterables')
const uint8ArrayFromString = require('uint8arrays/from-string')
const PeerId = require('peer-id')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
// @ts-ignore it-buffer does not have types
const { toBuffer } = require('it-buffer')
const Message = require('./message')
@@ -23,7 +23,6 @@ const PeerRecord = require('../record/peer-record')
const {
MULTICODEC_IDENTIFY,
MULTICODEC_IDENTIFY_PUSH,
AGENT_VERSION,
PROTOCOL_VERSION
} = require('./consts')
@@ -34,6 +33,11 @@ const { codes } = require('../errors')
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
*/
/**
* @typedef {Object} HostProperties
* @property {string} agentVersion
*/
class IdentifyService {
/**
* @class
@@ -51,7 +55,6 @@ class IdentifyService {
// Store self host metadata
this._host = {
agentVersion: AGENT_VERSION,
protocolVersion: PROTOCOL_VERSION,
...libp2p._options.host
}
@@ -94,12 +97,12 @@ class IdentifyService {
const { stream } = await connection.newStream(MULTICODEC_IDENTIFY_PUSH)
await pipe(
[{
[Message.Identify.encode({
listenAddrs,
signedPeerRecord,
protocols
}],
pb.encode(Message),
}).finish()],
lp.encode(),
stream,
consume
)
@@ -160,12 +163,12 @@ class IdentifyService {
let message
try {
message = Message.decode(data)
message = Message.Identify.decode(data)
} catch (err) {
throw errCode(err, codes.ERR_INVALID_MESSAGE)
}
let {
const {
publicKey,
listenAddrs,
protocols,
@@ -180,7 +183,7 @@ class IdentifyService {
}
// Get the observedAddr if there is one
observedAddr = IdentifyService.getCleanMultiaddr(observedAddr)
const cleanObservedAddr = IdentifyService.getCleanMultiaddr(observedAddr)
try {
const envelope = await Envelope.openAndCertify(signedPeerRecord, PeerRecord.DOMAIN)
@@ -194,7 +197,7 @@ class IdentifyService {
// LEGACY: Update peers data in PeerStore
try {
this.peerStore.addressBook.set(id, listenAddrs.map((addr) => multiaddr(addr)))
this.peerStore.addressBook.set(id, listenAddrs.map((addr) => new Multiaddr(addr)))
} catch (err) {
log.error('received invalid addrs', err)
}
@@ -202,9 +205,9 @@ class IdentifyService {
this.peerStore.protoBook.set(id, protocols)
this.peerStore.metadataBook.set(id, 'AgentVersion', uint8ArrayFromString(message.agentVersion))
// TODO: Score our observed addr
log('received observed address of %s', observedAddr)
this.addressManager.addObservedAddr(observedAddr)
// TODO: Add and score our observed addr
log('received observed address of %s', cleanObservedAddr)
// this.addressManager.addObservedAddr(observedAddr)
}
/**
@@ -246,7 +249,7 @@ class IdentifyService {
const signedPeerRecord = await this.peerStore.addressBook.getRawEnvelope(this.peerId)
const protocols = this.peerStore.protoBook.get(this.peerId) || []
const message = Message.encode({
const message = Message.Identify.encode({
protocolVersion: this._host.protocolVersion,
agentVersion: this._host.agentVersion,
publicKey,
@@ -254,7 +257,7 @@ class IdentifyService {
signedPeerRecord,
observedAddr: connection.remoteAddr.bytes,
protocols
})
}).finish()
try {
await pipe(
@@ -288,7 +291,7 @@ class IdentifyService {
toBuffer,
collect
)
message = Message.decode(data)
message = Message.Identify.decode(data)
} catch (err) {
return log.error('received invalid message', err)
}
@@ -307,7 +310,8 @@ class IdentifyService {
// LEGACY: Update peers data in PeerStore
try {
this.peerStore.addressBook.set(id, message.listenAddrs.map((addr) => multiaddr(addr)))
this.peerStore.addressBook.set(id,
message.listenAddrs.map((addr) => new Multiaddr(addr)))
} catch (err) {
log.error('received invalid addrs', err)
}
@@ -320,12 +324,12 @@ class IdentifyService {
* Takes the `addr` and converts it to a Multiaddr if possible
*
* @param {Uint8Array | string} addr
* @returns {multiaddr|null}
* @returns {Multiaddr|null}
*/
static getCleanMultiaddr (addr) {
if (addr && addr.length > 0) {
try {
return multiaddr(addr)
return new Multiaddr(addr)
} catch (_) {
return null
}

95
src/identify/message.d.ts vendored Normal file
View File

@@ -0,0 +1,95 @@
import * as $protobuf from "protobufjs";
/** Properties of an Identify. */
export interface IIdentify {
/** Identify protocolVersion */
protocolVersion?: (string|null);
/** Identify agentVersion */
agentVersion?: (string|null);
/** Identify publicKey */
publicKey?: (Uint8Array|null);
/** Identify listenAddrs */
listenAddrs?: (Uint8Array[]|null);
/** Identify observedAddr */
observedAddr?: (Uint8Array|null);
/** Identify protocols */
protocols?: (string[]|null);
/** Identify signedPeerRecord */
signedPeerRecord?: (Uint8Array|null);
}
/** Represents an Identify. */
export class Identify implements IIdentify {
/**
* Constructs a new Identify.
* @param [p] Properties to set
*/
constructor(p?: IIdentify);
/** Identify protocolVersion. */
public protocolVersion: string;
/** Identify agentVersion. */
public agentVersion: string;
/** Identify publicKey. */
public publicKey: Uint8Array;
/** Identify listenAddrs. */
public listenAddrs: Uint8Array[];
/** Identify observedAddr. */
public observedAddr: Uint8Array;
/** Identify protocols. */
public protocols: string[];
/** Identify signedPeerRecord. */
public signedPeerRecord: Uint8Array;
/**
* Encodes the specified Identify message. Does not implicitly {@link Identify.verify|verify} messages.
* @param m Identify message or plain object to encode
* @param [w] Writer to encode to
* @returns Writer
*/
public static encode(m: IIdentify, w?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes an Identify message from the specified reader or buffer.
* @param r Reader or buffer to decode from
* @param [l] Message length if known beforehand
* @returns Identify
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Identify;
/**
* Creates an Identify message from a plain object. Also converts values to their respective internal types.
* @param d Plain object
* @returns Identify
*/
public static fromObject(d: { [k: string]: any }): Identify;
/**
* Creates a plain object from an Identify message. Also converts values to other types if specified.
* @param m Identify
* @param [o] Conversion options
* @returns Plain object
*/
public static toObject(m: Identify, o?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this Identify to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}

View File

@@ -1,35 +1,328 @@
'use strict'
/*eslint-disable*/
"use strict";
const protons = require('protons')
const schema = `
message Identify {
// protocolVersion determines compatibility between peers
optional string protocolVersion = 5; // e.g. ipfs/1.0.0
var $protobuf = require("protobufjs/minimal");
// agentVersion is like a UserAgent string in browsers, or client version in bittorrent
// includes the client name and client.
optional string agentVersion = 6; // e.g. go-ipfs/0.1.0
// Common aliases
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
// publicKey is this node's public key (which also gives its node.ID)
// - may not need to be sent, as secure channel implies it has been sent.
// - then again, if we change / disable secure channel, may still want it.
optional bytes publicKey = 1;
// Exported root namespace
var $root = $protobuf.roots["libp2p-identify"] || ($protobuf.roots["libp2p-identify"] = {});
// listenAddrs are the multiaddrs the sender node listens for open connections on
repeated bytes listenAddrs = 2;
$root.Identify = (function() {
// oservedAddr is the multiaddr of the remote endpoint that the sender node perceives
// this is useful information to convey to the other side, as it helps the remote endpoint
// determine whether its connection to the local peer goes through NAT.
optional bytes observedAddr = 4;
/**
* Properties of an Identify.
* @exports IIdentify
* @interface IIdentify
* @property {string|null} [protocolVersion] Identify protocolVersion
* @property {string|null} [agentVersion] Identify agentVersion
* @property {Uint8Array|null} [publicKey] Identify publicKey
* @property {Array.<Uint8Array>|null} [listenAddrs] Identify listenAddrs
* @property {Uint8Array|null} [observedAddr] Identify observedAddr
* @property {Array.<string>|null} [protocols] Identify protocols
* @property {Uint8Array|null} [signedPeerRecord] Identify signedPeerRecord
*/
repeated string protocols = 3;
/**
* Constructs a new Identify.
* @exports Identify
* @classdesc Represents an Identify.
* @implements IIdentify
* @constructor
* @param {IIdentify=} [p] Properties to set
*/
function Identify(p) {
this.listenAddrs = [];
this.protocols = [];
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
// signedPeerRecord contains a serialized SignedEnvelope containing a PeerRecord,
// signed by the sending node. It contains the same addresses as the listenAddrs field, but
// in a form that lets us share authenticated addrs with other peers.
optional bytes signedPeerRecord = 8;
}
`
/**
* Identify protocolVersion.
* @member {string} protocolVersion
* @memberof Identify
* @instance
*/
Identify.prototype.protocolVersion = "";
module.exports = protons(schema).Identify
/**
* Identify agentVersion.
* @member {string} agentVersion
* @memberof Identify
* @instance
*/
Identify.prototype.agentVersion = "";
/**
* Identify publicKey.
* @member {Uint8Array} publicKey
* @memberof Identify
* @instance
*/
Identify.prototype.publicKey = $util.newBuffer([]);
/**
* Identify listenAddrs.
* @member {Array.<Uint8Array>} listenAddrs
* @memberof Identify
* @instance
*/
Identify.prototype.listenAddrs = $util.emptyArray;
/**
* Identify observedAddr.
* @member {Uint8Array} observedAddr
* @memberof Identify
* @instance
*/
Identify.prototype.observedAddr = $util.newBuffer([]);
/**
* Identify protocols.
* @member {Array.<string>} protocols
* @memberof Identify
* @instance
*/
Identify.prototype.protocols = $util.emptyArray;
/**
* Identify signedPeerRecord.
* @member {Uint8Array} signedPeerRecord
* @memberof Identify
* @instance
*/
Identify.prototype.signedPeerRecord = $util.newBuffer([]);
/**
* Encodes the specified Identify message. Does not implicitly {@link Identify.verify|verify} messages.
* @function encode
* @memberof Identify
* @static
* @param {IIdentify} m Identify message or plain object to encode
* @param {$protobuf.Writer} [w] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Identify.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
if (m.publicKey != null && Object.hasOwnProperty.call(m, "publicKey"))
w.uint32(10).bytes(m.publicKey);
if (m.listenAddrs != null && m.listenAddrs.length) {
for (var i = 0; i < m.listenAddrs.length; ++i)
w.uint32(18).bytes(m.listenAddrs[i]);
}
if (m.protocols != null && m.protocols.length) {
for (var i = 0; i < m.protocols.length; ++i)
w.uint32(26).string(m.protocols[i]);
}
if (m.observedAddr != null && Object.hasOwnProperty.call(m, "observedAddr"))
w.uint32(34).bytes(m.observedAddr);
if (m.protocolVersion != null && Object.hasOwnProperty.call(m, "protocolVersion"))
w.uint32(42).string(m.protocolVersion);
if (m.agentVersion != null && Object.hasOwnProperty.call(m, "agentVersion"))
w.uint32(50).string(m.agentVersion);
if (m.signedPeerRecord != null && Object.hasOwnProperty.call(m, "signedPeerRecord"))
w.uint32(66).bytes(m.signedPeerRecord);
return w;
};
/**
* Decodes an Identify message from the specified reader or buffer.
* @function decode
* @memberof Identify
* @static
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
* @param {number} [l] Message length if known beforehand
* @returns {Identify} Identify
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Identify.decode = function decode(r, l) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.Identify();
while (r.pos < c) {
var t = r.uint32();
switch (t >>> 3) {
case 5:
m.protocolVersion = r.string();
break;
case 6:
m.agentVersion = r.string();
break;
case 1:
m.publicKey = r.bytes();
break;
case 2:
if (!(m.listenAddrs && m.listenAddrs.length))
m.listenAddrs = [];
m.listenAddrs.push(r.bytes());
break;
case 4:
m.observedAddr = r.bytes();
break;
case 3:
if (!(m.protocols && m.protocols.length))
m.protocols = [];
m.protocols.push(r.string());
break;
case 8:
m.signedPeerRecord = r.bytes();
break;
default:
r.skipType(t & 7);
break;
}
}
return m;
};
/**
* Creates an Identify message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof Identify
* @static
* @param {Object.<string,*>} d Plain object
* @returns {Identify} Identify
*/
Identify.fromObject = function fromObject(d) {
if (d instanceof $root.Identify)
return d;
var m = new $root.Identify();
if (d.protocolVersion != null) {
m.protocolVersion = String(d.protocolVersion);
}
if (d.agentVersion != null) {
m.agentVersion = String(d.agentVersion);
}
if (d.publicKey != null) {
if (typeof d.publicKey === "string")
$util.base64.decode(d.publicKey, m.publicKey = $util.newBuffer($util.base64.length(d.publicKey)), 0);
else if (d.publicKey.length)
m.publicKey = d.publicKey;
}
if (d.listenAddrs) {
if (!Array.isArray(d.listenAddrs))
throw TypeError(".Identify.listenAddrs: array expected");
m.listenAddrs = [];
for (var i = 0; i < d.listenAddrs.length; ++i) {
if (typeof d.listenAddrs[i] === "string")
$util.base64.decode(d.listenAddrs[i], m.listenAddrs[i] = $util.newBuffer($util.base64.length(d.listenAddrs[i])), 0);
else if (d.listenAddrs[i].length)
m.listenAddrs[i] = d.listenAddrs[i];
}
}
if (d.observedAddr != null) {
if (typeof d.observedAddr === "string")
$util.base64.decode(d.observedAddr, m.observedAddr = $util.newBuffer($util.base64.length(d.observedAddr)), 0);
else if (d.observedAddr.length)
m.observedAddr = d.observedAddr;
}
if (d.protocols) {
if (!Array.isArray(d.protocols))
throw TypeError(".Identify.protocols: array expected");
m.protocols = [];
for (var i = 0; i < d.protocols.length; ++i) {
m.protocols[i] = String(d.protocols[i]);
}
}
if (d.signedPeerRecord != null) {
if (typeof d.signedPeerRecord === "string")
$util.base64.decode(d.signedPeerRecord, m.signedPeerRecord = $util.newBuffer($util.base64.length(d.signedPeerRecord)), 0);
else if (d.signedPeerRecord.length)
m.signedPeerRecord = d.signedPeerRecord;
}
return m;
};
/**
* Creates a plain object from an Identify message. Also converts values to other types if specified.
* @function toObject
* @memberof Identify
* @static
* @param {Identify} m Identify
* @param {$protobuf.IConversionOptions} [o] Conversion options
* @returns {Object.<string,*>} Plain object
*/
Identify.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (o.arrays || o.defaults) {
d.listenAddrs = [];
d.protocols = [];
}
if (o.defaults) {
if (o.bytes === String)
d.publicKey = "";
else {
d.publicKey = [];
if (o.bytes !== Array)
d.publicKey = $util.newBuffer(d.publicKey);
}
if (o.bytes === String)
d.observedAddr = "";
else {
d.observedAddr = [];
if (o.bytes !== Array)
d.observedAddr = $util.newBuffer(d.observedAddr);
}
d.protocolVersion = "";
d.agentVersion = "";
if (o.bytes === String)
d.signedPeerRecord = "";
else {
d.signedPeerRecord = [];
if (o.bytes !== Array)
d.signedPeerRecord = $util.newBuffer(d.signedPeerRecord);
}
}
if (m.publicKey != null && m.hasOwnProperty("publicKey")) {
d.publicKey = o.bytes === String ? $util.base64.encode(m.publicKey, 0, m.publicKey.length) : o.bytes === Array ? Array.prototype.slice.call(m.publicKey) : m.publicKey;
}
if (m.listenAddrs && m.listenAddrs.length) {
d.listenAddrs = [];
for (var j = 0; j < m.listenAddrs.length; ++j) {
d.listenAddrs[j] = o.bytes === String ? $util.base64.encode(m.listenAddrs[j], 0, m.listenAddrs[j].length) : o.bytes === Array ? Array.prototype.slice.call(m.listenAddrs[j]) : m.listenAddrs[j];
}
}
if (m.protocols && m.protocols.length) {
d.protocols = [];
for (var j = 0; j < m.protocols.length; ++j) {
d.protocols[j] = m.protocols[j];
}
}
if (m.observedAddr != null && m.hasOwnProperty("observedAddr")) {
d.observedAddr = o.bytes === String ? $util.base64.encode(m.observedAddr, 0, m.observedAddr.length) : o.bytes === Array ? Array.prototype.slice.call(m.observedAddr) : m.observedAddr;
}
if (m.protocolVersion != null && m.hasOwnProperty("protocolVersion")) {
d.protocolVersion = m.protocolVersion;
}
if (m.agentVersion != null && m.hasOwnProperty("agentVersion")) {
d.agentVersion = m.agentVersion;
}
if (m.signedPeerRecord != null && m.hasOwnProperty("signedPeerRecord")) {
d.signedPeerRecord = o.bytes === String ? $util.base64.encode(m.signedPeerRecord, 0, m.signedPeerRecord.length) : o.bytes === Array ? Array.prototype.slice.call(m.signedPeerRecord) : m.signedPeerRecord;
}
return d;
};
/**
* Converts this Identify to JSON.
* @function toJSON
* @memberof Identify
* @instance
* @returns {Object.<string,*>} JSON object
*/
Identify.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return Identify;
})();
module.exports = $root;

View File

@@ -0,0 +1,30 @@
syntax = "proto3";
message Identify {
// protocolVersion determines compatibility between peers
optional string protocolVersion = 5; // e.g. ipfs/1.0.0
// agentVersion is like a UserAgent string in browsers, or client version in bittorrent
// includes the client name and client.
optional string agentVersion = 6; // e.g. go-ipfs/0.1.0
// publicKey is this node's public key (which also gives its node.ID)
// - may not need to be sent, as secure channel implies it has been sent.
// - then again, if we change / disable secure channel, may still want it.
optional bytes publicKey = 1;
// listenAddrs are the multiaddrs the sender node listens for open connections on
repeated bytes listenAddrs = 2;
// oservedAddr is the multiaddr of the remote endpoint that the sender node perceives
// this is useful information to convey to the other side, as it helps the remote endpoint
// determine whether its connection to the local peer goes through NAT.
optional bytes observedAddr = 4;
repeated string protocols = 3;
// signedPeerRecord contains a serialized SignedEnvelope containing a PeerRecord,
// signed by the sending node. It contains the same addresses as the listenAddrs field, but
// in a form that lets us share authenticated addrs with other peers.
optional bytes signedPeerRecord = 8;
}

View File

@@ -4,13 +4,11 @@ const debug = require('debug')
const log = Object.assign(debug('libp2p'), {
error: debug('libp2p:err')
})
/** @typedef {import('./types').EventEmitterFactory} Events */
/** @type Events */
const EventEmitter = require('events')
const errCode = require('err-code')
const PeerId = require('peer-id')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const PeerRouting = require('./peer-routing')
const ContentRouting = require('./content-routing')
@@ -38,29 +36,63 @@ const NatManager = require('./nat-manager')
const { updateSelfPeerRecord } = require('./record/utils')
/**
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
* @typedef {import('libp2p-interfaces/src/transport/types').TransportFactory} TransportFactory
* @typedef {import('libp2p-interfaces/src/transport/types').TransportFactory<any, any>} TransportFactory
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxerFactory} MuxerFactory
* @typedef {import('libp2p-interfaces/src/content-routing/types')} ContentRoutingModule
* @typedef {import('libp2p-interfaces/src/peer-discovery/types')} PeerDiscoveryModule
* @typedef {import('libp2p-interfaces/src/peer-routing/types')} PeerRoutingModule
* @typedef {import('libp2p-interfaces/src/crypto/types').Crypto} Crypto
* @typedef {import('libp2p-interfaces/src/pubsub')} Pubsub
* @typedef {import('libp2p-interfaces/src/pubsub').PubsubOptions} PubsubOptions
* @typedef {import('interface-datastore').Datastore} Datastore
* @typedef {import('./pnet')} Protector
*/
/**
* @typedef {Object} HandlerProps
* @property {Connection} connection
* @property {MuxedStream} stream
* @property {string} protocol
*
* @typedef {Object} RandomWalkOptions
* @property {boolean} [enabled = false]
* @property {number} [queriesPerPeriod = 1]
* @property {number} [interval = 300e3]
* @property {number} [timeout = 10e3]
*
* @typedef {Object} DhtOptions
* @property {boolean} [enabled = false]
* @property {number} [kBucketSize = 20]
* @property {RandomWalkOptions} [randomWalk]
* @property {boolean} [clientMode]
* @property {import('libp2p-interfaces/src/types').DhtSelectors} [selectors]
* @property {import('libp2p-interfaces/src/types').DhtValidators} [validators]
*
* @typedef {Object} KeychainOptions
* @property {Datastore} [datastore]
*
* @typedef {Object} PeerStoreOptions
* @property {boolean} persistence
*
* @typedef {Object} RelayOptions
* @typedef {Object} PubsubLocalOptions
* @property {boolean} enabled
* @property {import('./circuit').RelayAdvertiseOptions} advertise
* @property {import('./circuit').HopOptions} hop
* @property {import('./circuit').AutoRelayOptions} autoRelay
*
* @typedef {Object} MetricsOptions
* @property {boolean} enabled
*
* @typedef {Object} RelayOptions
* @property {boolean} [enabled = true]
* @property {import('./circuit').RelayAdvertiseOptions} [advertise]
* @property {import('./circuit').HopOptions} [hop]
* @property {import('./circuit').AutoRelayOptions} [autoRelay]
*
* @typedef {Object} Libp2pConfig
* @property {Object} [dht] dht module options
* @property {Object} [peerDiscovery]
* @property {Pubsub} [pubsub] pubsub module options
* @property {DhtOptions} [dht] dht module options
* @property {import('./nat-manager').NatManagerOptions} [nat]
* @property {Record<string, Object|boolean>} [peerDiscovery]
* @property {PubsubLocalOptions & PubsubOptions} [pubsub] pubsub module options
* @property {RelayOptions} [relay]
* @property {Record<string, Object>} [transport] transport options indexed by transport key
*
@@ -68,16 +100,25 @@ const { updateSelfPeerRecord } = require('./record/utils')
* @property {TransportFactory[]} transport
* @property {MuxerFactory[]} streamMuxer
* @property {Crypto[]} connEncryption
* @property {PeerDiscoveryModule[]} [peerDiscovery]
* @property {PeerRoutingModule[]} [peerRouting]
* @property {ContentRoutingModule[]} [contentRouting]
* @property {Object} [dht]
* @property {{new(...args: any[]): Pubsub}} [pubsub]
* @property {Protector} [connProtector]
*
* @typedef {Object} Libp2pOptions
* @property {Libp2pModules} modules libp2p modules to use
* @property {import('./address-manager').AddressManagerOptions} [addresses]
* @property {import('./connection-manager').ConnectionManagerOptions} [connectionManager]
* @property {Datastore} [datastore]
* @property {import('./dialer').DialerOptions} [dialer]
* @property {import('./metrics').MetricsOptions} [metrics]
* @property {Object} [keychain]
* @property {import('./transport-manager').TransportManagerOptions} [transportManager]
* @property {import('./identify/index').HostProperties} [host] libp2p host
* @property {KeychainOptions & import('./keychain/index').KeychainOptions} [keychain]
* @property {MetricsOptions & import('./metrics').MetricsOptions} [metrics]
* @property {import('./peer-routing').PeerRoutingOptions} [peerRouting]
* @property {PeerStoreOptions & import('./peer-store/persistent').PersistentPeerStoreOptions} [peerStore]
* @property {import('./transport-manager').TransportManagerOptions} [transportManager]
* @property {Libp2pConfig} [config]
*
* @typedef {Object} constructorOptions
@@ -152,9 +193,6 @@ class Libp2p extends EventEmitter {
this._discovery = new Map() // Discovery service instances/references
// Create the Connection Manager
if (this._options.connectionManager.minPeers) { // Remove in 0.29
this._options.connectionManager.minConnections = this._options.connectionManager.minPeers
}
this.connectionManager = new ConnectionManager(this, {
autoDial: this._config.peerDiscovery.autoDial,
...this._options.connectionManager
@@ -175,7 +213,6 @@ class Libp2p extends EventEmitter {
const keychainOpts = Keychain.generateOptions()
this.keychain = new Keychain(this._options.keychain.datastore, {
passPhrase: this._options.keychain.pass,
...keychainOpts,
...this._options.keychain
})
@@ -203,6 +240,7 @@ class Libp2p extends EventEmitter {
peerId: this.peerId,
addressManager: this.addressManager,
transportManager: this.transportManager,
// @ts-ignore Nat typedef is not understood as Object
...this._options.config.nat
})
@@ -227,11 +265,7 @@ class Libp2p extends EventEmitter {
this.dialer = new Dialer({
transportManager: this.transportManager,
peerStore: this.peerStore,
concurrency: this._options.dialer.maxParallelDials,
perPeerLimit: this._options.dialer.maxDialsPerPeer,
timeout: this._options.dialer.dialTimeout,
resolvers: this._options.dialer.resolvers,
addressSorter: this._options.dialer.addressSorter
...this._options.dialer
})
this._modules.transport.forEach((Transport) => {
@@ -268,6 +302,7 @@ class Libp2p extends EventEmitter {
// dht provided components (peerRouting, contentRouting, dht)
if (this._modules.dht) {
const DHT = this._modules.dht
// @ts-ignore Object is not constructable
this._dht = new DHT({
libp2p: this,
dialer: this.dialer,
@@ -426,22 +461,36 @@ class Libp2p extends EventEmitter {
* @returns {Promise<Connection>}
*/
dial (peer, options) {
return this.dialProtocol(peer, [], options)
return this._dial(peer, options)
}
/**
* Dials to the provided peer and handshakes with the given protocol.
* Dials to the provided peer and tries to handshake with the given protocols in order.
* If successful, the known metadata of the peer will be added to the nodes `peerStore`,
* and the `Connection` will be returned
* and the `MuxedStream` will be returned together with the successful negotiated protocol.
*
* @async
* @param {PeerId|Multiaddr|string} peer - The peer to dial
* @param {string[]|string} protocols
* @param {object} [options]
* @param {AbortSignal} [options.signal]
* @returns {Promise<Connection|*>}
*/
async dialProtocol (peer, protocols, options) {
if (!protocols || !protocols.length) {
throw errCode(new Error('no protocols were provided to open a stream'), codes.ERR_INVALID_PROTOCOLS_FOR_STREAM)
}
const connection = await this._dial(peer, options)
return connection.newStream(protocols)
}
/**
* @async
* @param {PeerId|Multiaddr|string} peer - The peer to dial
* @param {object} [options]
* @returns {Promise<Connection>}
*/
async _dial (peer, options) {
const { id, multiaddrs } = getPeer(peer)
if (id.equals(this.peerId)) {
@@ -456,11 +505,6 @@ class Libp2p extends EventEmitter {
this.peerStore.addressBook.add(id, multiaddrs)
}
// If a protocol was provided, create a new stream
if (protocols && protocols.length) {
return connection.newStream(protocols)
}
return connection
}
@@ -484,13 +528,13 @@ class Libp2p extends EventEmitter {
addrs = addrs.concat(this.addressManager.getObservedAddrs().map(ma => ma.toString()))
const announceFilter = this._options.addresses.announceFilter || ((multiaddrs) => multiaddrs)
const announceFilter = this._options.addresses.announceFilter
// dedupe multiaddrs
const addrSet = new Set(addrs)
// Create advertising list
return announceFilter(Array.from(addrSet).map(str => multiaddr(str)))
return announceFilter(Array.from(addrSet).map(str => new Multiaddr(str)))
}
/**
@@ -536,7 +580,7 @@ class Libp2p extends EventEmitter {
* Registers the `handler` for each protocol
*
* @param {string[]|string} protocols
* @param {({ connection: Connection, stream: MuxedStream, protocol: string }) => void} handler
* @param {(props: HandlerProps) => void} handler
*/
handle (protocols, handler) {
protocols = Array.isArray(protocols) ? protocols : [protocols]
@@ -656,7 +700,7 @@ class Libp2p extends EventEmitter {
try {
await this.dialer.connectToPeer(peerId)
} catch (err) {
log.error('could not connect to discovered peer', err)
log.error(`could not connect to discovered peer ${peerId.toB58String()} with ${err}`)
}
}
}
@@ -669,6 +713,9 @@ class Libp2p extends EventEmitter {
* @private
*/
async _setupPeerDiscovery () {
/**
* @param {PeerDiscoveryModule} DiscoveryService
*/
const setupService = (DiscoveryService) => {
let config = {
enabled: true // on by default
@@ -677,6 +724,7 @@ class Libp2p extends EventEmitter {
if (DiscoveryService.tag &&
this._config.peerDiscovery &&
this._config.peerDiscovery[DiscoveryService.tag]) {
// @ts-ignore PeerDiscovery not understood as an Object for spread
config = { ...config, ...this._config.peerDiscovery[DiscoveryService.tag] }
}
@@ -685,6 +733,7 @@ class Libp2p extends EventEmitter {
let discoveryService
if (typeof DiscoveryService === 'function') {
// @ts-ignore DiscoveryService has no constructor type inferred
discoveryService = new DiscoveryService(Object.assign({}, config, {
peerId: this.peerId,
libp2p: this

View File

@@ -4,6 +4,7 @@ const debug = require('debug')
const log = Object.assign(debug('libp2p:plaintext'), {
error: debug('libp2p:plaintext:err')
})
// @ts-ignore it-handshake do not export types
const handshake = require('it-handshake')
const lp = require('it-length-prefixed')
const PeerId = require('peer-id')
@@ -16,8 +17,12 @@ const protocol = '/plaintext/2.0.0'
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
*/
/**
* @param {import('./proto').IExchange} exchange
*/
function lpEncodeExchange (exchange) {
const pb = Exchange.encode(exchange)
const pb = Exchange.encode(exchange).finish()
// @ts-ignore TODO: Uint8Array not assignable to Buffer
return lp.encode.single(pb)
}
@@ -68,12 +73,23 @@ async function encrypt (localId, conn, remoteId) {
}
}
module.exports = {
protocol,
secureInbound: (localId, conn, remoteId) => {
return encrypt(localId, conn, remoteId)
},
secureOutbound: (localId, conn, remoteId) => {
return encrypt(localId, conn, remoteId)
}
}
module.exports =
{
protocol,
/**
* @param {PeerId} localId
* @param {Connection} conn
* @param {PeerId | undefined} remoteId
*/
secureInbound: (localId, conn, remoteId) => {
return encrypt(localId, conn, remoteId)
},
/**
* @param {PeerId} localId
* @param {Connection} conn
* @param {PeerId | undefined} remoteId
*/
secureOutbound: (localId, conn, remoteId) => {
return encrypt(localId, conn, remoteId)
}
}

128
src/insecure/proto.d.ts vendored Normal file
View File

@@ -0,0 +1,128 @@
import * as $protobuf from "protobufjs";
/** Properties of an Exchange. */
export interface IExchange {
/** Exchange id */
id?: (Uint8Array|null);
/** Exchange pubkey */
pubkey?: (IPublicKey|null);
}
/** Represents an Exchange. */
export class Exchange implements IExchange {
/**
* Constructs a new Exchange.
* @param [p] Properties to set
*/
constructor(p?: IExchange);
/** Exchange id. */
public id: Uint8Array;
/** Exchange pubkey. */
public pubkey?: (IPublicKey|null);
/**
* Encodes the specified Exchange message. Does not implicitly {@link Exchange.verify|verify} messages.
* @param m Exchange message or plain object to encode
* @param [w] Writer to encode to
* @returns Writer
*/
public static encode(m: IExchange, w?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes an Exchange message from the specified reader or buffer.
* @param r Reader or buffer to decode from
* @param [l] Message length if known beforehand
* @returns Exchange
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Exchange;
/**
* Creates an Exchange message from a plain object. Also converts values to their respective internal types.
* @param d Plain object
* @returns Exchange
*/
public static fromObject(d: { [k: string]: any }): Exchange;
/**
* Creates a plain object from an Exchange message. Also converts values to other types if specified.
* @param m Exchange
* @param [o] Conversion options
* @returns Plain object
*/
public static toObject(m: Exchange, o?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this Exchange to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}
/** KeyType enum. */
export enum KeyType {
RSA = 0,
Ed25519 = 1,
Secp256k1 = 2,
ECDSA = 3
}
/** Represents a PublicKey. */
export class PublicKey implements IPublicKey {
/**
* Constructs a new PublicKey.
* @param [p] Properties to set
*/
constructor(p?: IPublicKey);
/** PublicKey Type. */
public Type: KeyType;
/** PublicKey Data. */
public Data: Uint8Array;
/**
* Encodes the specified PublicKey message. Does not implicitly {@link PublicKey.verify|verify} messages.
* @param m PublicKey message or plain object to encode
* @param [w] Writer to encode to
* @returns Writer
*/
public static encode(m: IPublicKey, w?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes a PublicKey message from the specified reader or buffer.
* @param r Reader or buffer to decode from
* @param [l] Message length if known beforehand
* @returns PublicKey
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): PublicKey;
/**
* Creates a PublicKey message from a plain object. Also converts values to their respective internal types.
* @param d Plain object
* @returns PublicKey
*/
public static fromObject(d: { [k: string]: any }): PublicKey;
/**
* Creates a plain object from a PublicKey message. Also converts values to other types if specified.
* @param m PublicKey
* @param [o] Conversion options
* @returns Plain object
*/
public static toObject(m: PublicKey, o?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this PublicKey to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}

View File

@@ -1,22 +1,371 @@
'use strict'
/*eslint-disable*/
"use strict";
const protobuf = require('protons')
var $protobuf = require("protobufjs/minimal");
module.exports = protobuf(`
message Exchange {
optional bytes id = 1;
optional PublicKey pubkey = 2;
}
// Common aliases
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
enum KeyType {
RSA = 0;
Ed25519 = 1;
Secp256k1 = 2;
ECDSA = 3;
}
// Exported root namespace
var $root = $protobuf.roots["libp2p-plaintext"] || ($protobuf.roots["libp2p-plaintext"] = {});
message PublicKey {
required KeyType Type = 1;
required bytes Data = 2;
}
`)
$root.Exchange = (function() {
/**
* Properties of an Exchange.
* @exports IExchange
* @interface IExchange
* @property {Uint8Array|null} [id] Exchange id
* @property {IPublicKey|null} [pubkey] Exchange pubkey
*/
/**
* Constructs a new Exchange.
* @exports Exchange
* @classdesc Represents an Exchange.
* @implements IExchange
* @constructor
* @param {IExchange=} [p] Properties to set
*/
function Exchange(p) {
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
/**
* Exchange id.
* @member {Uint8Array} id
* @memberof Exchange
* @instance
*/
Exchange.prototype.id = $util.newBuffer([]);
/**
* Exchange pubkey.
* @member {IPublicKey|null|undefined} pubkey
* @memberof Exchange
* @instance
*/
Exchange.prototype.pubkey = null;
/**
* Encodes the specified Exchange message. Does not implicitly {@link Exchange.verify|verify} messages.
* @function encode
* @memberof Exchange
* @static
* @param {IExchange} m Exchange message or plain object to encode
* @param {$protobuf.Writer} [w] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Exchange.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
if (m.id != null && Object.hasOwnProperty.call(m, "id"))
w.uint32(10).bytes(m.id);
if (m.pubkey != null && Object.hasOwnProperty.call(m, "pubkey"))
$root.PublicKey.encode(m.pubkey, w.uint32(18).fork()).ldelim();
return w;
};
/**
* Decodes an Exchange message from the specified reader or buffer.
* @function decode
* @memberof Exchange
* @static
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
* @param {number} [l] Message length if known beforehand
* @returns {Exchange} Exchange
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Exchange.decode = function decode(r, l) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.Exchange();
while (r.pos < c) {
var t = r.uint32();
switch (t >>> 3) {
case 1:
m.id = r.bytes();
break;
case 2:
m.pubkey = $root.PublicKey.decode(r, r.uint32());
break;
default:
r.skipType(t & 7);
break;
}
}
return m;
};
/**
* Creates an Exchange message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof Exchange
* @static
* @param {Object.<string,*>} d Plain object
* @returns {Exchange} Exchange
*/
Exchange.fromObject = function fromObject(d) {
if (d instanceof $root.Exchange)
return d;
var m = new $root.Exchange();
if (d.id != null) {
if (typeof d.id === "string")
$util.base64.decode(d.id, m.id = $util.newBuffer($util.base64.length(d.id)), 0);
else if (d.id.length)
m.id = d.id;
}
if (d.pubkey != null) {
if (typeof d.pubkey !== "object")
throw TypeError(".Exchange.pubkey: object expected");
m.pubkey = $root.PublicKey.fromObject(d.pubkey);
}
return m;
};
/**
* Creates a plain object from an Exchange message. Also converts values to other types if specified.
* @function toObject
* @memberof Exchange
* @static
* @param {Exchange} m Exchange
* @param {$protobuf.IConversionOptions} [o] Conversion options
* @returns {Object.<string,*>} Plain object
*/
Exchange.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (o.defaults) {
if (o.bytes === String)
d.id = "";
else {
d.id = [];
if (o.bytes !== Array)
d.id = $util.newBuffer(d.id);
}
d.pubkey = null;
}
if (m.id != null && m.hasOwnProperty("id")) {
d.id = o.bytes === String ? $util.base64.encode(m.id, 0, m.id.length) : o.bytes === Array ? Array.prototype.slice.call(m.id) : m.id;
}
if (m.pubkey != null && m.hasOwnProperty("pubkey")) {
d.pubkey = $root.PublicKey.toObject(m.pubkey, o);
}
return d;
};
/**
* Converts this Exchange to JSON.
* @function toJSON
* @memberof Exchange
* @instance
* @returns {Object.<string,*>} JSON object
*/
Exchange.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return Exchange;
})();
/**
* KeyType enum.
* @exports KeyType
* @enum {number}
* @property {number} RSA=0 RSA value
* @property {number} Ed25519=1 Ed25519 value
* @property {number} Secp256k1=2 Secp256k1 value
* @property {number} ECDSA=3 ECDSA value
*/
$root.KeyType = (function() {
var valuesById = {}, values = Object.create(valuesById);
values[valuesById[0] = "RSA"] = 0;
values[valuesById[1] = "Ed25519"] = 1;
values[valuesById[2] = "Secp256k1"] = 2;
values[valuesById[3] = "ECDSA"] = 3;
return values;
})();
$root.PublicKey = (function() {
/**
* Properties of a PublicKey.
* @exports IPublicKey
* @interface IPublicKey
* @property {KeyType|null} [Type] PublicKey Type
* @property {Uint8Array|null} [Data] PublicKey Data
*/
/**
* Constructs a new PublicKey.
* @exports PublicKey
* @classdesc Represents a PublicKey.
* @implements IPublicKey
* @constructor
* @param {IPublicKey=} [p] Properties to set
*/
function PublicKey(p) {
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
/**
* PublicKey Type.
* @member {KeyType} Type
* @memberof PublicKey
* @instance
*/
PublicKey.prototype.Type = 0;
/**
* PublicKey Data.
* @member {Uint8Array} Data
* @memberof PublicKey
* @instance
*/
PublicKey.prototype.Data = $util.newBuffer([]);
/**
* Encodes the specified PublicKey message. Does not implicitly {@link PublicKey.verify|verify} messages.
* @function encode
* @memberof PublicKey
* @static
* @param {IPublicKey} m PublicKey message or plain object to encode
* @param {$protobuf.Writer} [w] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
PublicKey.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
if (m.Type != null && Object.hasOwnProperty.call(m, "Type"))
w.uint32(8).int32(m.Type);
if (m.Data != null && Object.hasOwnProperty.call(m, "Data"))
w.uint32(18).bytes(m.Data);
return w;
};
/**
* Decodes a PublicKey message from the specified reader or buffer.
* @function decode
* @memberof PublicKey
* @static
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
* @param {number} [l] Message length if known beforehand
* @returns {PublicKey} PublicKey
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
PublicKey.decode = function decode(r, l) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.PublicKey();
while (r.pos < c) {
var t = r.uint32();
switch (t >>> 3) {
case 1:
m.Type = r.int32();
break;
case 2:
m.Data = r.bytes();
break;
default:
r.skipType(t & 7);
break;
}
}
return m;
};
/**
* Creates a PublicKey message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof PublicKey
* @static
* @param {Object.<string,*>} d Plain object
* @returns {PublicKey} PublicKey
*/
PublicKey.fromObject = function fromObject(d) {
if (d instanceof $root.PublicKey)
return d;
var m = new $root.PublicKey();
switch (d.Type) {
case "RSA":
case 0:
m.Type = 0;
break;
case "Ed25519":
case 1:
m.Type = 1;
break;
case "Secp256k1":
case 2:
m.Type = 2;
break;
case "ECDSA":
case 3:
m.Type = 3;
break;
}
if (d.Data != null) {
if (typeof d.Data === "string")
$util.base64.decode(d.Data, m.Data = $util.newBuffer($util.base64.length(d.Data)), 0);
else if (d.Data.length)
m.Data = d.Data;
}
return m;
};
/**
* Creates a plain object from a PublicKey message. Also converts values to other types if specified.
* @function toObject
* @memberof PublicKey
* @static
* @param {PublicKey} m PublicKey
* @param {$protobuf.IConversionOptions} [o] Conversion options
* @returns {Object.<string,*>} Plain object
*/
PublicKey.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (o.defaults) {
d.Type = o.enums === String ? "RSA" : 0;
if (o.bytes === String)
d.Data = "";
else {
d.Data = [];
if (o.bytes !== Array)
d.Data = $util.newBuffer(d.Data);
}
}
if (m.Type != null && m.hasOwnProperty("Type")) {
d.Type = o.enums === String ? $root.KeyType[m.Type] : m.Type;
}
if (m.Data != null && m.hasOwnProperty("Data")) {
d.Data = o.bytes === String ? $util.base64.encode(m.Data, 0, m.Data.length) : o.bytes === Array ? Array.prototype.slice.call(m.Data) : m.Data;
}
return d;
};
/**
* Converts this PublicKey to JSON.
* @function toJSON
* @memberof PublicKey
* @instance
* @returns {Object.<string,*>} JSON object
*/
PublicKey.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return PublicKey;
})();
module.exports = $root;

18
src/insecure/proto.proto Normal file
View File

@@ -0,0 +1,18 @@
syntax = "proto3";
message Exchange {
optional bytes id = 1;
optional PublicKey pubkey = 2;
}
enum KeyType {
RSA = 0;
Ed25519 = 1;
Secp256k1 = 2;
ECDSA = 3;
}
message PublicKey {
KeyType Type = 1;
bytes Data = 2;
}

View File

@@ -1,7 +1,10 @@
'use strict'
// @ts-ignore node-forge types not exported
require('node-forge/lib/pkcs7')
// @ts-ignore node-forge types not exported
require('node-forge/lib/pbe')
// @ts-ignore node-forge types not exported
const forge = require('node-forge/lib/forge')
const { certificateForKey, findAsync } = require('./util')
const errcode = require('err-code')
@@ -85,6 +88,7 @@ class CMS {
try {
const buf = forge.util.createBuffer(uint8ArrayToString(cmsData, 'ascii'))
const obj = forge.asn1.fromDer(buf)
// @ts-ignore not defined
cms = forge.pkcs7.messageFromAsn1(obj)
} catch (err) {
throw errcode(new Error('Invalid CMS: ' + err.message), 'ERR_INVALID_CMS')
@@ -93,11 +97,15 @@ class CMS {
// Find a recipient whose key we hold. We only deal with recipient certs
// issued by ipfs (O=ipfs).
const recipients = cms.recipients
// @ts-ignore cms types not defined
.filter(r => r.issuer.find(a => a.shortName === 'O' && a.value === 'ipfs'))
// @ts-ignore cms types not defined
.filter(r => r.issuer.find(a => a.shortName === 'CN'))
// @ts-ignore cms types not defined
.map(r => {
return {
recipient: r,
// @ts-ignore cms types not defined
keyId: r.issuer.find(a => a.shortName === 'CN').value
}
})
@@ -113,6 +121,7 @@ class CMS {
})
if (!r) {
// @ts-ignore cms types not defined
const missingKeys = recipients.map(r => r.keyId)
throw errcode(new Error('Decryption needs one of the key(s): ' + missingKeys.join(', ')), 'ERR_MISSING_KEYS', {
missingKeys

View File

@@ -10,11 +10,32 @@ const errcode = require('err-code')
const uint8ArrayToString = require('uint8arrays/to-string')
const uint8ArrayFromString = require('uint8arrays/from-string')
// @ts-ignore node-forge sha512 types not exported
require('node-forge/lib/sha512')
/**
* @typedef {import('peer-id')} PeerId
* @typedef {import('interface-datastore/src/types').Datastore} Datastore
* @typedef {import('interface-datastore').Datastore} Datastore
*/
/**
* @typedef {Object} DekOptions
* @property {string} hash
* @property {string} salt
* @property {number} iterationCount
* @property {number} keyLength
*
* @typedef {Object} KeychainOptions
* @property {string} [pass]
* @property {DekOptions} [dek]
*/
/**
* Information about a key.
*
* @typedef {Object} KeyInfo
* @property {string} id - The universally unique key id.
* @property {string} name - The local key name.
*/
const keyPrefix = '/pkcs8/'
@@ -38,6 +59,9 @@ const defaultOptions = {
}
}
/**
* @param {string} name
*/
function validateKeyName (name) {
if (!name) return false
if (typeof name !== 'string') return false
@@ -85,14 +109,6 @@ function DsInfoName (name) {
return new Key(infoPrefix + name)
}
/**
* Information about a key.
*
* @typedef {Object} KeyInfo
* @property {string} id - The universally unique key id.
* @property {string} name - The local key name.
*/
/**
* Manages the lifecycle of a key. Keys are encrypted at rest using PKCS #8.
*
@@ -106,7 +122,7 @@ class Keychain {
* Creates a new instance of a key chain.
*
* @param {Datastore} store - where the key are.
* @param {object} options
* @param {KeychainOptions} options
* @class
*/
constructor (store, options) {
@@ -118,8 +134,8 @@ class Keychain {
this.opts = mergeOptions(defaultOptions, options)
// Enforce NIST SP 800-132
if (this.opts.passPhrase && this.opts.passPhrase.length < 20) {
throw new Error('passPhrase must be least 20 characters')
if (this.opts.pass && this.opts.pass.length < 20) {
throw new Error('pass must be least 20 characters')
}
if (this.opts.dek.keyLength < NIST.minKeyLength) {
throw new Error(`dek.keyLength must be least ${NIST.minKeyLength} bytes`)
@@ -131,12 +147,14 @@ class Keychain {
throw new Error(`dek.iterationCount must be least ${NIST.minIterationCount}`)
}
const dek = this.opts.passPhrase ? crypto.pbkdf2(
this.opts.passPhrase,
this.opts.dek.salt,
this.opts.dek.iterationCount,
this.opts.dek.keyLength,
this.opts.dek.hash) : ''
const dek = this.opts.pass
? crypto.pbkdf2(
this.opts.pass,
this.opts.dek.salt,
this.opts.dek.iterationCount,
this.opts.dek.keyLength,
this.opts.dek.hash)
: ''
privates.set(this, { dek })
}

View File

@@ -4,7 +4,6 @@
require('node-forge/lib/x509')
const forge = require('node-forge/lib/forge')
const pki = forge.pki
exports = module.exports
/**
* Gets a self-signed X.509 certificate for the key.
@@ -17,7 +16,7 @@ exports = module.exports
* @param {RsaPrivateKey} privateKey - The naked key
* @returns {Uint8Array}
*/
exports.certificateForKey = (key, privateKey) => {
const certificateForKey = (key, privateKey) => {
const publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e)
const cert = pki.createCertificate()
cert.publicKey = publicKey
@@ -87,4 +86,7 @@ async function findAsync (array, asyncCompare) {
return array[index]
}
module.exports.findAsync = findAsync
module.exports = {
certificateForKey,
findAsync
}

View File

@@ -1,10 +1,8 @@
// @ts-nocheck
'use strict'
/** @typedef {import('../types').EventEmitterFactory} Events */
/** @type Events */
const EventEmitter = require('events')
const Big = require('bignumber.js')
const { BigNumber: Big } = require('bignumber.js')
const MovingAverage = require('moving-average')
const retimer = require('retimer')
@@ -21,24 +19,30 @@ class Stats extends EventEmitter {
this._options = options
this._queue = []
this._stats = {}
/** @type {{ dataReceived: Big, dataSent: Big }} */
this._stats = {
dataReceived: Big(0),
dataSent: Big(0)
}
this._frequencyLastTime = Date.now()
this._frequencyAccumulators = {}
/** @type {{ dataReceived: MovingAverage[], dataSent: MovingAverage[] }} */
this._movingAverages = {}
this._update = this._update.bind(this)
const intervals = this._options.movingAverageIntervals
for (var i = 0; i < initialCounters.length; i++) {
var key = initialCounters[i]
for (let i = 0; i < initialCounters.length; i++) {
const key = initialCounters[i]
this._stats[key] = Big(0)
this._movingAverages[key] = {}
for (var k = 0; k < intervals.length; k++) {
var interval = intervals[k]
var ma = this._movingAverages[key][interval] = MovingAverage(interval)
for (let k = 0; k < intervals.length; k++) {
const interval = intervals[k]
const ma = this._movingAverages[key][interval] = MovingAverage(interval)
ma.push(this._frequencyLastTime, 0)
}
}
@@ -72,8 +76,6 @@ class Stats extends EventEmitter {
/**
* Returns a clone of the current stats.
*
* @returns {Object}
*/
get snapshot () {
return Object.assign({}, this._stats)
@@ -81,8 +83,6 @@ class Stats extends EventEmitter {
/**
* Returns a clone of the internal movingAverages
*
* @returns {MovingAverage}
*/
get movingAverages () {
return Object.assign({}, this._movingAverages)
@@ -219,9 +219,9 @@ class Stats extends EventEmitter {
const intervals = this._options.movingAverageIntervals
for (var i = 0; i < intervals.length; i++) {
var movingAverageInterval = intervals[i]
var movingAverage = movingAverages[movingAverageInterval]
for (let i = 0; i < intervals.length; i++) {
const movingAverageInterval = intervals[i]
let movingAverage = movingAverages[movingAverageInterval]
if (!movingAverage) {
movingAverage = movingAverages[movingAverageInterval] = MovingAverage(movingAverageInterval)
}

View File

@@ -1,14 +1,16 @@
'use strict'
// @ts-ignore nat-api does not export types
const NatAPI = require('@motrix/nat-api')
const debug = require('debug')
const promisify = require('promisify-es6')
const Multiaddr = require('multiaddr')
const { promisify } = require('es6-promisify')
const { Multiaddr } = require('multiaddr')
const log = Object.assign(debug('libp2p:nat'), {
error: debug('libp2p:nat:err')
})
const { isBrowser } = require('ipfs-utils/src/env')
const retry = require('p-retry')
// @ts-ignore private-api does not export types
const isPrivateIp = require('private-ip')
const pkg = require('../package.json')
const errcode = require('err-code')
@@ -17,33 +19,39 @@ const {
} = require('./errors')
const isLoopback = require('libp2p-utils/src/multiaddr/is-loopback')
const DEFAULT_TTL = 7200
/**
* @typedef {import('peer-id')} PeerId
* @typedef {import('./transport-manager')} TransportManager
* @typedef {import('./address-manager')} AddressManager
*/
/**
* @typedef {Object} NatManagerProperties
* @property {PeerId} peerId - The peer ID of the current node
* @property {TransportManager} transportManager - A transport manager
* @property {AddressManager} addressManager - An address manager
*
* @typedef {Object} NatManagerOptions
* @property {boolean} enabled - Whether to enable the NAT manager
* @property {string} [externalIp] - Pass a value to use instead of auto-detection
* @property {string} [description] - A string value to use for the port mapping description on the gateway
* @property {number} [ttl = DEFAULT_TTL] - How long UPnP port mappings should last for in seconds (minimum 1200)
* @property {boolean} [keepAlive] - Whether to automatically refresh UPnP port mappings when their TTL is reached
* @property {string} [gateway] - Pass a value to use instead of auto-detection
* @property {object} [pmp] - PMP options
* @property {boolean} [pmp.enabled] - Whether to enable PMP as well as UPnP
*/
function highPort (min = 1024, max = 65535) {
return Math.floor(Math.random() * (max - min + 1) + min)
}
const DEFAULT_TTL = 7200
class NatManager {
/**
* @class
* @param {object} options
* @param {PeerId} options.peerId - The peer ID of the current node
* @param {TransportManager} options.transportManager - A transport manager
* @param {AddressManager} options.addressManager - An address manager
* @param {boolean} options.enabled - Whether to enable the NAT manager
* @param {string} [options.externalIp] - Pass a value to use instead of auto-detection
* @param {string} [options.description] - A string value to use for the port mapping description on the gateway
* @param {number} [options.ttl] - How long UPnP port mappings should last for in seconds (minimum 1200)
* @param {boolean} [options.keepAlive] - Whether to automatically refresh UPnP port mappings when their TTL is reached
* @param {string} [options.gateway] - Pass a value to use instead of auto-detection
* @param {object} [options.pmp] - PMP options
* @param {boolean} [options.pmp.enabled] - Whether to enable PMP as well as UPnP
* @param {NatManagerProperties & NatManagerOptions} options
*/
constructor ({ peerId, addressManager, transportManager, ...options }) {
this._peerId = peerId
@@ -89,15 +97,18 @@ class NatManager {
if (!addr.isThinWaistAddress() || transport !== 'tcp') {
// only bare tcp addresses
// eslint-disable-next-line no-continue
continue
}
if (isLoopback(addr)) {
// eslint-disable-next-line no-continue
continue
}
if (family !== 'ipv4') {
if (family !== 4) {
// ignore ipv6
// eslint-disable-next-line no-continue
continue
}
@@ -119,9 +130,9 @@ class NatManager {
})
this._addressManager.addObservedAddr(Multiaddr.fromNodeAddress({
family: 'IPv4',
family: 4,
address: publicIp,
port: `${publicPort}`
port: publicPort
}, transport))
}
}
@@ -132,14 +143,32 @@ class NatManager {
}
const client = new NatAPI(this._options)
const map = promisify(client.map, { context: client })
const destroy = promisify(client.destroy, { context: client })
const externalIp = promisify(client.externalIp, { context: client })
/** @type {(...any: any) => any} */
const map = promisify(client.map.bind(client))
/** @type {(...any: any) => any} */
const destroy = promisify(client.destroy.bind(client))
/** @type {(...any: any) => any} */
const externalIp = promisify(client.externalIp.bind(client))
// these are all network operations so add a retry
this._client = {
// these are all network operations so add a retry
/**
* @param {...any} args
* @returns {Promise<void>}
*/
map: (...args) => retry(() => map(...args), { onFailedAttempt: log.error, unref: true }),
/**
* @param {...any} args
* @returns {Promise<void>}
*/
destroy: (...args) => retry(() => destroy(...args), { onFailedAttempt: log.error, unref: true }),
/**
* @param {...any} args
* @returns {Promise<string>}
*/
externalIp: (...args) => retry(() => externalIp(...args), { onFailedAttempt: log.error, unref: true })
}

View File

@@ -19,12 +19,25 @@ const filter = require('it-filter')
const {
setDelayedInterval,
clearDelayedInterval
// @ts-ignore module with no types
} = require('set-delayed-interval')
const PeerId = require('peer-id')
/**
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('peer-id')} PeerId
* @typedef {import('multiaddr').Multiaddr} Multiaddr
* @typedef {import('libp2p-interfaces/src/peer-routing/types')} PeerRoutingModule
*/
/**
* @typedef {Object} RefreshManagerOptions
* @property {boolean} [enabled = true] - Whether to enable the Refresh manager
* @property {number} [bootDelay = 6e5] - Boot delay to start the Refresh Manager (in ms)
* @property {number} [interval = 10e3] - Interval between each Refresh Manager run (in ms)
*
* @typedef {Object} PeerRoutingOptions
* @property {RefreshManagerOptions} [refreshManager]
*/
class PeerRouting {
/**
* @class
@@ -33,10 +46,11 @@ class PeerRouting {
constructor (libp2p) {
this._peerId = libp2p.peerId
this._peerStore = libp2p.peerStore
/** @type {PeerRoutingModule[]} */
this._routers = libp2p._modules.peerRouting || []
// If we have the dht, add it to the available peer routers
if (libp2p._dht) {
if (libp2p._dht && libp2p._config.dht.enabled) {
this._routers.push(libp2p._dht)
}
@@ -95,6 +109,7 @@ class PeerRouting {
...this._routers.map(router => [router.findPeer(id, options)])
),
(source) => filter(source, Boolean),
// @ts-ignore findPeer resolves a Promise
(source) => storeAddresses(source, this._peerStore),
(source) => first(source)
)

View File

@@ -6,7 +6,7 @@ const log = Object.assign(debug('libp2p:peer-store:address-book'), {
})
const errcode = require('err-code')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const PeerId = require('peer-id')
const Book = require('./book')
@@ -18,7 +18,6 @@ const {
const Envelope = require('../record/envelope')
/**
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('./')} PeerStore
*/
@@ -60,7 +59,7 @@ class AddressBook extends Book {
if (!data.addresses) {
return []
}
return data.addresses.map((address) => address.multiaddr)
return data.addresses.map((/** @type {Address} */ address) => address.multiaddr)
}
})
@@ -230,6 +229,11 @@ class AddressBook extends Book {
const addresses = this._toAddresses(multiaddrs)
const id = peerId.toB58String()
// No addresses to be added
if (!addresses.length) {
return this
}
const entry = this.data.get(id)
if (entry && entry.addresses) {
@@ -295,17 +299,21 @@ class AddressBook extends Book {
}
// create Address for each address
/** @type {Address[]} */
const addresses = []
multiaddrs.forEach((addr) => {
if (!multiaddr.isMultiaddr(addr)) {
if (!Multiaddr.isMultiaddr(addr)) {
log.error(`multiaddr ${addr} must be an instance of multiaddr`)
throw errcode(new Error(`multiaddr ${addr} must be an instance of multiaddr`), ERR_INVALID_PARAMETERS)
}
addresses.push({
multiaddr: addr,
isCertified
})
// Guarantee no replicates
if (!addresses.find((a) => a.multiaddr.equals(addr))) {
addresses.push({
multiaddr: addr,
isCertified
})
}
})
return addresses

View File

@@ -7,6 +7,9 @@ const {
codes: { ERR_INVALID_PARAMETERS }
} = require('../errors')
/**
* @param {any} data
*/
const passthrough = data => data
/**

View File

@@ -2,8 +2,6 @@
const errcode = require('err-code')
/** @typedef {import('../types').EventEmitterFactory} Events */
/** @type Events */
const EventEmitter = require('events')
const PeerId = require('peer-id')

View File

@@ -81,6 +81,9 @@ class MetadataBook extends Book {
* Set data into the datastructure
*
* @override
* @param {PeerId} peerId
* @param {string} key
* @param {Uint8Array} value
*/
_setValue (peerId, key, value, { emit = true } = {}) {
const id = peerId.toB58String()

View File

@@ -5,7 +5,7 @@ const log = Object.assign(debug('libp2p:persistent-peer-store'), {
error: debug('libp2p:persistent-peer-store:err')
})
const { Key } = require('interface-datastore')
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const PeerId = require('peer-id')
const PeerStore = require('..')
@@ -18,13 +18,18 @@ const {
NAMESPACE_PROTOCOL
} = require('./consts')
const Addresses = require('./pb/address-book.proto')
const Protocols = require('./pb/proto-book.proto')
const { Addresses } = require('./pb/address-book')
const { Protocols } = require('./pb/proto-book')
/**
* @typedef {import('interface-datastore').Batch} Batch
* @typedef {import('../address-book.js').Address} Address
*/
/**
* @typedef {Object} PersistentPeerStoreProperties
* @property {PeerId} peerId
* @property {any} datastore
* @property {import('interface-datastore').Datastore} datastore
*
* @typedef {Object} PersistentPeerStoreOptions
* @property {number} [threshold = 5] - Number of dirty peers allowed before commit data.
@@ -214,7 +219,7 @@ class PersistentPeerStore extends PeerStore {
*
* @private
* @param {PeerId} peerId
* @param {Object} batch
* @param {Batch} batch
*/
_batchAddressBook (peerId, batch) {
const b32key = peerId.toString()
@@ -234,11 +239,13 @@ class PersistentPeerStore extends PeerStore {
multiaddr: address.multiaddr.bytes,
isCertified: address.isCertified
})),
certified_record: entry.record ? {
seq: entry.record.seqNumber,
raw: entry.record.raw
} : undefined
})
certifiedRecord: entry.record
? {
seq: entry.record.seqNumber,
raw: entry.record.raw
}
: undefined
}).finish()
batch.put(key, encodedData)
} catch (err) {
@@ -251,7 +258,7 @@ class PersistentPeerStore extends PeerStore {
*
* @private
* @param {PeerId} peerId
* @param {Object} batch
* @param {Batch} batch
*/
_batchKeyBook (peerId, batch) {
const b32key = peerId.toString()
@@ -277,14 +284,14 @@ class PersistentPeerStore extends PeerStore {
*
* @private
* @param {PeerId} peerId
* @param {Object} batch
* @param {Batch} batch
*/
_batchMetadataBook (peerId, batch) {
const b32key = peerId.toString()
const dirtyMetada = this._dirtyMetadata.get(peerId.toB58String()) || []
try {
dirtyMetada.forEach((dirtyKey) => {
dirtyMetada.forEach((/** @type {string} */ dirtyKey) => {
const key = new Key(`${NAMESPACE_METADATA}${b32key}/${dirtyKey}`)
const dirtyValue = this.metadataBook.getValue(peerId, dirtyKey)
@@ -304,7 +311,7 @@ class PersistentPeerStore extends PeerStore {
*
* @private
* @param {PeerId} peerId
* @param {Object} batch
* @param {Batch} batch
*/
_batchProtoBook (peerId, batch) {
const b32key = peerId.toString()
@@ -319,7 +326,7 @@ class PersistentPeerStore extends PeerStore {
return
}
const encodedData = Protocols.encode({ protocols })
const encodedData = Protocols.encode({ protocols }).finish()
batch.put(key, encodedData)
} catch (err) {
@@ -351,13 +358,15 @@ class PersistentPeerStore extends PeerStore {
peerId,
{
addresses: decoded.addrs.map((address) => ({
multiaddr: multiaddr(address.multiaddr),
multiaddr: new Multiaddr(address.multiaddr),
isCertified: Boolean(address.isCertified)
})),
record: decoded.certified_record ? {
raw: decoded.certified_record.raw,
seqNumber: decoded.certified_record.seq
} : undefined
record: decoded.certifiedRecord
? {
raw: decoded.certifiedRecord.raw,
seqNumber: decoded.certifiedRecord.seq
}
: undefined
},
{ emit: false })
break

View File

@@ -0,0 +1,198 @@
import * as $protobuf from "protobufjs";
/** Properties of an Addresses. */
export interface IAddresses {
/** Addresses addrs */
addrs?: (Addresses.IAddress[]|null);
/** Addresses certifiedRecord */
certifiedRecord?: (Addresses.ICertifiedRecord|null);
}
/** Represents an Addresses. */
export class Addresses implements IAddresses {
/**
* Constructs a new Addresses.
* @param [p] Properties to set
*/
constructor(p?: IAddresses);
/** Addresses addrs. */
public addrs: Addresses.IAddress[];
/** Addresses certifiedRecord. */
public certifiedRecord?: (Addresses.ICertifiedRecord|null);
/**
* Encodes the specified Addresses message. Does not implicitly {@link Addresses.verify|verify} messages.
* @param m Addresses message or plain object to encode
* @param [w] Writer to encode to
* @returns Writer
*/
public static encode(m: IAddresses, w?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes an Addresses message from the specified reader or buffer.
* @param r Reader or buffer to decode from
* @param [l] Message length if known beforehand
* @returns Addresses
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Addresses;
/**
* Creates an Addresses message from a plain object. Also converts values to their respective internal types.
* @param d Plain object
* @returns Addresses
*/
public static fromObject(d: { [k: string]: any }): Addresses;
/**
* Creates a plain object from an Addresses message. Also converts values to other types if specified.
* @param m Addresses
* @param [o] Conversion options
* @returns Plain object
*/
public static toObject(m: Addresses, o?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this Addresses to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}
export namespace Addresses {
/** Properties of an Address. */
interface IAddress {
/** Address multiaddr */
multiaddr?: (Uint8Array|null);
/** Address isCertified */
isCertified?: (boolean|null);
}
/** Represents an Address. */
class Address implements IAddress {
/**
* Constructs a new Address.
* @param [p] Properties to set
*/
constructor(p?: Addresses.IAddress);
/** Address multiaddr. */
public multiaddr: Uint8Array;
/** Address isCertified. */
public isCertified: boolean;
/**
* Encodes the specified Address message. Does not implicitly {@link Addresses.Address.verify|verify} messages.
* @param m Address message or plain object to encode
* @param [w] Writer to encode to
* @returns Writer
*/
public static encode(m: Addresses.IAddress, w?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes an Address message from the specified reader or buffer.
* @param r Reader or buffer to decode from
* @param [l] Message length if known beforehand
* @returns Address
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Addresses.Address;
/**
* Creates an Address message from a plain object. Also converts values to their respective internal types.
* @param d Plain object
* @returns Address
*/
public static fromObject(d: { [k: string]: any }): Addresses.Address;
/**
* Creates a plain object from an Address message. Also converts values to other types if specified.
* @param m Address
* @param [o] Conversion options
* @returns Plain object
*/
public static toObject(m: Addresses.Address, o?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this Address to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}
/** Properties of a CertifiedRecord. */
interface ICertifiedRecord {
/** CertifiedRecord seq */
seq?: (number|null);
/** CertifiedRecord raw */
raw?: (Uint8Array|null);
}
/** Represents a CertifiedRecord. */
class CertifiedRecord implements ICertifiedRecord {
/**
* Constructs a new CertifiedRecord.
* @param [p] Properties to set
*/
constructor(p?: Addresses.ICertifiedRecord);
/** CertifiedRecord seq. */
public seq: number;
/** CertifiedRecord raw. */
public raw: Uint8Array;
/**
* Encodes the specified CertifiedRecord message. Does not implicitly {@link Addresses.CertifiedRecord.verify|verify} messages.
* @param m CertifiedRecord message or plain object to encode
* @param [w] Writer to encode to
* @returns Writer
*/
public static encode(m: Addresses.ICertifiedRecord, w?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes a CertifiedRecord message from the specified reader or buffer.
* @param r Reader or buffer to decode from
* @param [l] Message length if known beforehand
* @returns CertifiedRecord
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Addresses.CertifiedRecord;
/**
* Creates a CertifiedRecord message from a plain object. Also converts values to their respective internal types.
* @param d Plain object
* @returns CertifiedRecord
*/
public static fromObject(d: { [k: string]: any }): Addresses.CertifiedRecord;
/**
* Creates a plain object from a CertifiedRecord message. Also converts values to other types if specified.
* @param m CertifiedRecord
* @param [o] Conversion options
* @returns Plain object
*/
public static toObject(m: Addresses.CertifiedRecord, o?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this CertifiedRecord to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}
}

View File

@@ -0,0 +1,522 @@
/*eslint-disable*/
"use strict";
var $protobuf = require("protobufjs/minimal");
// Common aliases
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
// Exported root namespace
var $root = $protobuf.roots["libp2p-address-book"] || ($protobuf.roots["libp2p-address-book"] = {});
$root.Addresses = (function() {
/**
* Properties of an Addresses.
* @exports IAddresses
* @interface IAddresses
* @property {Array.<Addresses.IAddress>|null} [addrs] Addresses addrs
* @property {Addresses.ICertifiedRecord|null} [certifiedRecord] Addresses certifiedRecord
*/
/**
* Constructs a new Addresses.
* @exports Addresses
* @classdesc Represents an Addresses.
* @implements IAddresses
* @constructor
* @param {IAddresses=} [p] Properties to set
*/
function Addresses(p) {
this.addrs = [];
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
/**
* Addresses addrs.
* @member {Array.<Addresses.IAddress>} addrs
* @memberof Addresses
* @instance
*/
Addresses.prototype.addrs = $util.emptyArray;
/**
* Addresses certifiedRecord.
* @member {Addresses.ICertifiedRecord|null|undefined} certifiedRecord
* @memberof Addresses
* @instance
*/
Addresses.prototype.certifiedRecord = null;
/**
* Encodes the specified Addresses message. Does not implicitly {@link Addresses.verify|verify} messages.
* @function encode
* @memberof Addresses
* @static
* @param {IAddresses} m Addresses message or plain object to encode
* @param {$protobuf.Writer} [w] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Addresses.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
if (m.addrs != null && m.addrs.length) {
for (var i = 0; i < m.addrs.length; ++i)
$root.Addresses.Address.encode(m.addrs[i], w.uint32(10).fork()).ldelim();
}
if (m.certifiedRecord != null && Object.hasOwnProperty.call(m, "certifiedRecord"))
$root.Addresses.CertifiedRecord.encode(m.certifiedRecord, w.uint32(18).fork()).ldelim();
return w;
};
/**
* Decodes an Addresses message from the specified reader or buffer.
* @function decode
* @memberof Addresses
* @static
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
* @param {number} [l] Message length if known beforehand
* @returns {Addresses} Addresses
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Addresses.decode = function decode(r, l) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.Addresses();
while (r.pos < c) {
var t = r.uint32();
switch (t >>> 3) {
case 1:
if (!(m.addrs && m.addrs.length))
m.addrs = [];
m.addrs.push($root.Addresses.Address.decode(r, r.uint32()));
break;
case 2:
m.certifiedRecord = $root.Addresses.CertifiedRecord.decode(r, r.uint32());
break;
default:
r.skipType(t & 7);
break;
}
}
return m;
};
/**
* Creates an Addresses message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof Addresses
* @static
* @param {Object.<string,*>} d Plain object
* @returns {Addresses} Addresses
*/
Addresses.fromObject = function fromObject(d) {
if (d instanceof $root.Addresses)
return d;
var m = new $root.Addresses();
if (d.addrs) {
if (!Array.isArray(d.addrs))
throw TypeError(".Addresses.addrs: array expected");
m.addrs = [];
for (var i = 0; i < d.addrs.length; ++i) {
if (typeof d.addrs[i] !== "object")
throw TypeError(".Addresses.addrs: object expected");
m.addrs[i] = $root.Addresses.Address.fromObject(d.addrs[i]);
}
}
if (d.certifiedRecord != null) {
if (typeof d.certifiedRecord !== "object")
throw TypeError(".Addresses.certifiedRecord: object expected");
m.certifiedRecord = $root.Addresses.CertifiedRecord.fromObject(d.certifiedRecord);
}
return m;
};
/**
* Creates a plain object from an Addresses message. Also converts values to other types if specified.
* @function toObject
* @memberof Addresses
* @static
* @param {Addresses} m Addresses
* @param {$protobuf.IConversionOptions} [o] Conversion options
* @returns {Object.<string,*>} Plain object
*/
Addresses.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (o.arrays || o.defaults) {
d.addrs = [];
}
if (o.defaults) {
d.certifiedRecord = null;
}
if (m.addrs && m.addrs.length) {
d.addrs = [];
for (var j = 0; j < m.addrs.length; ++j) {
d.addrs[j] = $root.Addresses.Address.toObject(m.addrs[j], o);
}
}
if (m.certifiedRecord != null && m.hasOwnProperty("certifiedRecord")) {
d.certifiedRecord = $root.Addresses.CertifiedRecord.toObject(m.certifiedRecord, o);
}
return d;
};
/**
* Converts this Addresses to JSON.
* @function toJSON
* @memberof Addresses
* @instance
* @returns {Object.<string,*>} JSON object
*/
Addresses.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
Addresses.Address = (function() {
/**
* Properties of an Address.
* @memberof Addresses
* @interface IAddress
* @property {Uint8Array|null} [multiaddr] Address multiaddr
* @property {boolean|null} [isCertified] Address isCertified
*/
/**
* Constructs a new Address.
* @memberof Addresses
* @classdesc Represents an Address.
* @implements IAddress
* @constructor
* @param {Addresses.IAddress=} [p] Properties to set
*/
function Address(p) {
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
/**
* Address multiaddr.
* @member {Uint8Array} multiaddr
* @memberof Addresses.Address
* @instance
*/
Address.prototype.multiaddr = $util.newBuffer([]);
/**
* Address isCertified.
* @member {boolean} isCertified
* @memberof Addresses.Address
* @instance
*/
Address.prototype.isCertified = false;
/**
* Encodes the specified Address message. Does not implicitly {@link Addresses.Address.verify|verify} messages.
* @function encode
* @memberof Addresses.Address
* @static
* @param {Addresses.IAddress} m Address message or plain object to encode
* @param {$protobuf.Writer} [w] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Address.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
if (m.multiaddr != null && Object.hasOwnProperty.call(m, "multiaddr"))
w.uint32(10).bytes(m.multiaddr);
if (m.isCertified != null && Object.hasOwnProperty.call(m, "isCertified"))
w.uint32(16).bool(m.isCertified);
return w;
};
/**
* Decodes an Address message from the specified reader or buffer.
* @function decode
* @memberof Addresses.Address
* @static
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
* @param {number} [l] Message length if known beforehand
* @returns {Addresses.Address} Address
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Address.decode = function decode(r, l) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.Addresses.Address();
while (r.pos < c) {
var t = r.uint32();
switch (t >>> 3) {
case 1:
m.multiaddr = r.bytes();
break;
case 2:
m.isCertified = r.bool();
break;
default:
r.skipType(t & 7);
break;
}
}
return m;
};
/**
* Creates an Address message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof Addresses.Address
* @static
* @param {Object.<string,*>} d Plain object
* @returns {Addresses.Address} Address
*/
Address.fromObject = function fromObject(d) {
if (d instanceof $root.Addresses.Address)
return d;
var m = new $root.Addresses.Address();
if (d.multiaddr != null) {
if (typeof d.multiaddr === "string")
$util.base64.decode(d.multiaddr, m.multiaddr = $util.newBuffer($util.base64.length(d.multiaddr)), 0);
else if (d.multiaddr.length)
m.multiaddr = d.multiaddr;
}
if (d.isCertified != null) {
m.isCertified = Boolean(d.isCertified);
}
return m;
};
/**
* Creates a plain object from an Address message. Also converts values to other types if specified.
* @function toObject
* @memberof Addresses.Address
* @static
* @param {Addresses.Address} m Address
* @param {$protobuf.IConversionOptions} [o] Conversion options
* @returns {Object.<string,*>} Plain object
*/
Address.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (o.defaults) {
if (o.bytes === String)
d.multiaddr = "";
else {
d.multiaddr = [];
if (o.bytes !== Array)
d.multiaddr = $util.newBuffer(d.multiaddr);
}
d.isCertified = false;
}
if (m.multiaddr != null && m.hasOwnProperty("multiaddr")) {
d.multiaddr = o.bytes === String ? $util.base64.encode(m.multiaddr, 0, m.multiaddr.length) : o.bytes === Array ? Array.prototype.slice.call(m.multiaddr) : m.multiaddr;
}
if (m.isCertified != null && m.hasOwnProperty("isCertified")) {
d.isCertified = m.isCertified;
}
return d;
};
/**
* Converts this Address to JSON.
* @function toJSON
* @memberof Addresses.Address
* @instance
* @returns {Object.<string,*>} JSON object
*/
Address.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return Address;
})();
Addresses.CertifiedRecord = (function() {
/**
* Properties of a CertifiedRecord.
* @memberof Addresses
* @interface ICertifiedRecord
* @property {number|null} [seq] CertifiedRecord seq
* @property {Uint8Array|null} [raw] CertifiedRecord raw
*/
/**
* Constructs a new CertifiedRecord.
* @memberof Addresses
* @classdesc Represents a CertifiedRecord.
* @implements ICertifiedRecord
* @constructor
* @param {Addresses.ICertifiedRecord=} [p] Properties to set
*/
function CertifiedRecord(p) {
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
/**
* CertifiedRecord seq.
* @member {number} seq
* @memberof Addresses.CertifiedRecord
* @instance
*/
CertifiedRecord.prototype.seq = $util.Long ? $util.Long.fromBits(0,0,true) : 0;
/**
* CertifiedRecord raw.
* @member {Uint8Array} raw
* @memberof Addresses.CertifiedRecord
* @instance
*/
CertifiedRecord.prototype.raw = $util.newBuffer([]);
/**
* Encodes the specified CertifiedRecord message. Does not implicitly {@link Addresses.CertifiedRecord.verify|verify} messages.
* @function encode
* @memberof Addresses.CertifiedRecord
* @static
* @param {Addresses.ICertifiedRecord} m CertifiedRecord message or plain object to encode
* @param {$protobuf.Writer} [w] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
CertifiedRecord.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
if (m.seq != null && Object.hasOwnProperty.call(m, "seq"))
w.uint32(8).uint64(m.seq);
if (m.raw != null && Object.hasOwnProperty.call(m, "raw"))
w.uint32(18).bytes(m.raw);
return w;
};
/**
* Decodes a CertifiedRecord message from the specified reader or buffer.
* @function decode
* @memberof Addresses.CertifiedRecord
* @static
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
* @param {number} [l] Message length if known beforehand
* @returns {Addresses.CertifiedRecord} CertifiedRecord
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
CertifiedRecord.decode = function decode(r, l) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.Addresses.CertifiedRecord();
while (r.pos < c) {
var t = r.uint32();
switch (t >>> 3) {
case 1:
m.seq = r.uint64();
break;
case 2:
m.raw = r.bytes();
break;
default:
r.skipType(t & 7);
break;
}
}
return m;
};
/**
* Creates a CertifiedRecord message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof Addresses.CertifiedRecord
* @static
* @param {Object.<string,*>} d Plain object
* @returns {Addresses.CertifiedRecord} CertifiedRecord
*/
CertifiedRecord.fromObject = function fromObject(d) {
if (d instanceof $root.Addresses.CertifiedRecord)
return d;
var m = new $root.Addresses.CertifiedRecord();
if (d.seq != null) {
if ($util.Long)
(m.seq = $util.Long.fromValue(d.seq)).unsigned = true;
else if (typeof d.seq === "string")
m.seq = parseInt(d.seq, 10);
else if (typeof d.seq === "number")
m.seq = d.seq;
else if (typeof d.seq === "object")
m.seq = new $util.LongBits(d.seq.low >>> 0, d.seq.high >>> 0).toNumber(true);
}
if (d.raw != null) {
if (typeof d.raw === "string")
$util.base64.decode(d.raw, m.raw = $util.newBuffer($util.base64.length(d.raw)), 0);
else if (d.raw.length)
m.raw = d.raw;
}
return m;
};
/**
* Creates a plain object from a CertifiedRecord message. Also converts values to other types if specified.
* @function toObject
* @memberof Addresses.CertifiedRecord
* @static
* @param {Addresses.CertifiedRecord} m CertifiedRecord
* @param {$protobuf.IConversionOptions} [o] Conversion options
* @returns {Object.<string,*>} Plain object
*/
CertifiedRecord.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (o.defaults) {
if ($util.Long) {
var n = new $util.Long(0, 0, true);
d.seq = o.longs === String ? n.toString() : o.longs === Number ? n.toNumber() : n;
} else
d.seq = o.longs === String ? "0" : 0;
if (o.bytes === String)
d.raw = "";
else {
d.raw = [];
if (o.bytes !== Array)
d.raw = $util.newBuffer(d.raw);
}
}
if (m.seq != null && m.hasOwnProperty("seq")) {
if (typeof m.seq === "number")
d.seq = o.longs === String ? String(m.seq) : m.seq;
else
d.seq = o.longs === String ? $util.Long.prototype.toString.call(m.seq) : o.longs === Number ? new $util.LongBits(m.seq.low >>> 0, m.seq.high >>> 0).toNumber(true) : m.seq;
}
if (m.raw != null && m.hasOwnProperty("raw")) {
d.raw = o.bytes === String ? $util.base64.encode(m.raw, 0, m.raw.length) : o.bytes === Array ? Array.prototype.slice.call(m.raw) : m.raw;
}
return d;
};
/**
* Converts this CertifiedRecord to JSON.
* @function toJSON
* @memberof Addresses.CertifiedRecord
* @instance
* @returns {Object.<string,*>} JSON object
*/
CertifiedRecord.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return CertifiedRecord;
})();
return Addresses;
})();
module.exports = $root;

View File

@@ -1,12 +1,9 @@
'use strict'
syntax = "proto3";
const protons = require('protons')
const message = `
message Addresses {
// Address represents a single multiaddr.
message Address {
required bytes multiaddr = 1;
bytes multiaddr = 1;
// Flag to indicate if the address comes from a certified source.
optional bool isCertified = 2;
@@ -27,7 +24,4 @@ message Addresses {
// The most recently received signed PeerRecord.
CertifiedRecord certified_record = 2;
}
`
module.exports = protons(message).Addresses
}

View File

@@ -0,0 +1,59 @@
import * as $protobuf from "protobufjs";
/** Properties of a Protocols. */
export interface IProtocols {
/** Protocols protocols */
protocols?: (string[]|null);
}
/** Represents a Protocols. */
export class Protocols implements IProtocols {
/**
* Constructs a new Protocols.
* @param [p] Properties to set
*/
constructor(p?: IProtocols);
/** Protocols protocols. */
public protocols: string[];
/**
* Encodes the specified Protocols message. Does not implicitly {@link Protocols.verify|verify} messages.
* @param m Protocols message or plain object to encode
* @param [w] Writer to encode to
* @returns Writer
*/
public static encode(m: IProtocols, w?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes a Protocols message from the specified reader or buffer.
* @param r Reader or buffer to decode from
* @param [l] Message length if known beforehand
* @returns Protocols
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Protocols;
/**
* Creates a Protocols message from a plain object. Also converts values to their respective internal types.
* @param d Plain object
* @returns Protocols
*/
public static fromObject(d: { [k: string]: any }): Protocols;
/**
* Creates a plain object from a Protocols message. Also converts values to other types if specified.
* @param m Protocols
* @param [o] Conversion options
* @returns Plain object
*/
public static toObject(m: Protocols, o?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this Protocols to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}

View File

@@ -0,0 +1,157 @@
/*eslint-disable*/
"use strict";
var $protobuf = require("protobufjs/minimal");
// Common aliases
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
// Exported root namespace
var $root = $protobuf.roots["libp2p-proto-book"] || ($protobuf.roots["libp2p-proto-book"] = {});
$root.Protocols = (function() {
/**
* Properties of a Protocols.
* @exports IProtocols
* @interface IProtocols
* @property {Array.<string>|null} [protocols] Protocols protocols
*/
/**
* Constructs a new Protocols.
* @exports Protocols
* @classdesc Represents a Protocols.
* @implements IProtocols
* @constructor
* @param {IProtocols=} [p] Properties to set
*/
function Protocols(p) {
this.protocols = [];
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
/**
* Protocols protocols.
* @member {Array.<string>} protocols
* @memberof Protocols
* @instance
*/
Protocols.prototype.protocols = $util.emptyArray;
/**
* Encodes the specified Protocols message. Does not implicitly {@link Protocols.verify|verify} messages.
* @function encode
* @memberof Protocols
* @static
* @param {IProtocols} m Protocols message or plain object to encode
* @param {$protobuf.Writer} [w] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Protocols.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
if (m.protocols != null && m.protocols.length) {
for (var i = 0; i < m.protocols.length; ++i)
w.uint32(10).string(m.protocols[i]);
}
return w;
};
/**
* Decodes a Protocols message from the specified reader or buffer.
* @function decode
* @memberof Protocols
* @static
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
* @param {number} [l] Message length if known beforehand
* @returns {Protocols} Protocols
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Protocols.decode = function decode(r, l) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.Protocols();
while (r.pos < c) {
var t = r.uint32();
switch (t >>> 3) {
case 1:
if (!(m.protocols && m.protocols.length))
m.protocols = [];
m.protocols.push(r.string());
break;
default:
r.skipType(t & 7);
break;
}
}
return m;
};
/**
* Creates a Protocols message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof Protocols
* @static
* @param {Object.<string,*>} d Plain object
* @returns {Protocols} Protocols
*/
Protocols.fromObject = function fromObject(d) {
if (d instanceof $root.Protocols)
return d;
var m = new $root.Protocols();
if (d.protocols) {
if (!Array.isArray(d.protocols))
throw TypeError(".Protocols.protocols: array expected");
m.protocols = [];
for (var i = 0; i < d.protocols.length; ++i) {
m.protocols[i] = String(d.protocols[i]);
}
}
return m;
};
/**
* Creates a plain object from a Protocols message. Also converts values to other types if specified.
* @function toObject
* @memberof Protocols
* @static
* @param {Protocols} m Protocols
* @param {$protobuf.IConversionOptions} [o] Conversion options
* @returns {Object.<string,*>} Plain object
*/
Protocols.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (o.arrays || o.defaults) {
d.protocols = [];
}
if (m.protocols && m.protocols.length) {
d.protocols = [];
for (var j = 0; j < m.protocols.length; ++j) {
d.protocols[j] = m.protocols[j];
}
}
return d;
};
/**
* Converts this Protocols to JSON.
* @function toJSON
* @memberof Protocols
* @instance
* @returns {Object.<string,*>} JSON object
*/
Protocols.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return Protocols;
})();
module.exports = $root;

View File

@@ -0,0 +1,5 @@
syntax = "proto3";
message Protocols {
repeated string protocols = 1;
}

View File

@@ -1,12 +0,0 @@
'use strict'
const protons = require('protons')
/* eslint-disable no-tabs */
const message = `
message Protocols {
repeated string protocols = 1;
}
`
module.exports = protons(message).Protocols

View File

@@ -74,6 +74,10 @@ class ProtoBook extends Book {
const recSet = this.data.get(id)
const newSet = new Set(protocols)
/**
* @param {Set<string>} a
* @param {Set<string>} b
*/
const isSetEqual = (a, b) => a.size === b.size && [...a].every(value => b.has(value))
// Already knows the peer and the recorded protocols are the same?

View File

@@ -8,6 +8,7 @@ const errCode = require('err-code')
const crypto = require('libp2p-crypto')
const { pipe } = require('it-pipe')
// @ts-ignore it-buffer has no types exported
const { toBuffer } = require('it-buffer')
const { collect, take } = require('streaming-iterables')
const equals = require('uint8arrays/equals')
@@ -16,8 +17,9 @@ const { PROTOCOL, PING_LENGTH } = require('./constants')
/**
* @typedef {import('../')} Libp2p
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('multiaddr').Multiaddr} Multiaddr
* @typedef {import('peer-id')} PeerId
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
*/
/**
@@ -31,7 +33,8 @@ async function ping (node, peer) {
// @ts-ignore multiaddr might not have toB58String
log('dialing %s to %s', PROTOCOL, peer.toB58String ? peer.toB58String() : peer)
const { stream } = await node.dialProtocol(peer, PROTOCOL)
const connection = await node.dial(peer)
const { stream } = await connection.newStream(PROTOCOL)
const start = Date.now()
const data = crypto.randomBytes(PING_LENGTH)
@@ -39,7 +42,7 @@ async function ping (node, peer) {
const [result] = await pipe(
[data],
stream,
stream => take(1, stream),
(/** @type {MuxedStream} */ stream) => take(1, stream),
toBuffer,
collect
)

View File

@@ -3,11 +3,16 @@
const crypto = require('libp2p-crypto')
const constants = require('./constants')
exports = module.exports
exports.rnd = (length) => {
/**
* @param {number} length
*/
function rnd (length) {
if (!length) {
length = constants.PING_LENGTH
}
return crypto.randomBytes(length)
}
module.exports = {
rnd
}

View File

@@ -7,6 +7,7 @@ const log = Object.assign(debug('libp2p:pnet'), {
})
const Errors = require('./errors')
// @ts-ignore xsalsa20 has no types exported
const xsalsa20 = require('xsalsa20')
const KEY_LENGTH = require('./key-generator').KEY_LENGTH
const uint8ArrayFromString = require('uint8arrays/from-string')
@@ -21,7 +22,8 @@ const uint8ArrayToString = require('uint8arrays/to-string')
*/
module.exports.createBoxStream = (nonce, psk) => {
const xor = xsalsa20(nonce, psk)
return (source) => (async function * () {
return (/** @type {AsyncIterable<Uint8Array>} */ source) => (async function * () {
for await (const chunk of source) {
yield Uint8Array.from(xor.update(chunk.slice()))
}
@@ -36,7 +38,7 @@ module.exports.createBoxStream = (nonce, psk) => {
* @returns {*} a through iterable
*/
module.exports.createUnboxStream = (nonce, psk) => {
return (source) => (async function * () {
return (/** @type {AsyncIterable<Uint8Array>} */ source) => (async function * () {
const xor = xsalsa20(nonce, psk)
log.trace('Decryption enabled')
@@ -51,7 +53,7 @@ module.exports.createUnboxStream = (nonce, psk) => {
*
* @param {Uint8Array} pskBuffer
* @throws {INVALID_PSK}
* @returns {Object} The PSK metadata (tag, codecName, psk)
* @returns {{ tag?: string, codecName?: string, psk: Uint8Array }} The PSK metadata (tag, codecName, psk)
*/
module.exports.decodeV1PSK = (pskBuffer) => {
try {

View File

@@ -6,6 +6,7 @@ const log = Object.assign(debug('libp2p:pnet'), {
})
const { pipe } = require('it-pipe')
const errcode = require('err-code')
// @ts-ignore it-pair has no types exported
const duplexPair = require('it-pair/duplex')
const crypto = require('libp2p-crypto')
const Errors = require('./errors')
@@ -17,6 +18,7 @@ const {
createUnboxStream,
decodeV1PSK
} = require('./crypto')
// @ts-ignore it-handshake has no types exported
const handshake = require('it-handshake')
const { NONCE_LENGTH } = require('./key-generator')

View File

@@ -22,8 +22,12 @@ module.exports = generate
module.exports.NONCE_LENGTH = 24
module.exports.KEY_LENGTH = KEY_LENGTH
// @ts-ignore This condition will always return 'false' since the types 'Module | undefined'
if (require.main === module) {
// @ts-ignore
generate(process.stdout)
try {
// @ts-ignore This condition will always return 'false' since the types 'Module | undefined'
if (require.main === module) {
// @ts-ignore
generate(process.stdout)
}
} catch (error) {
}

View File

@@ -1,12 +1,19 @@
'use strict'
// Pubsub adapter to keep API with handlers while not removed.
/**
* @typedef {import('libp2p-interfaces/src/pubsub').InMessage} InMessage
* @typedef {import('libp2p-interfaces/src/pubsub')} PubsubRouter
*/
// Pubsub adapter to keep API with handlers while not removed.
/**
* @param {{new(...args: any[]): PubsubRouter}} PubsubRouter
* @param {import('.')} libp2p
* @param {{ enabled: boolean; } & import(".").PubsubLocalOptions & import("libp2p-interfaces/src/pubsub").PubsubOptions} options
*/
function pubsubAdapter (PubsubRouter, libp2p, options) {
/** @type {PubsubRouter & { _subscribeAdapter: PubsubRouter['subscribe'], _unsubscribeAdapter: PubsubRouter['unsubscribe'] }} */
// @ts-ignore we set the extra _subscribeAdapter and _unsubscribeAdapter properties afterwards
const pubsub = new PubsubRouter(libp2p, options)
pubsub._subscribeAdapter = pubsub.subscribe
pubsub._unsubscribeAdapter = pubsub.unsubscribe

77
src/record/envelope/envelope.d.ts vendored Normal file
View File

@@ -0,0 +1,77 @@
import * as $protobuf from "protobufjs";
/** Properties of an Envelope. */
export interface IEnvelope {
/** Envelope publicKey */
publicKey?: (Uint8Array|null);
/** Envelope payloadType */
payloadType?: (Uint8Array|null);
/** Envelope payload */
payload?: (Uint8Array|null);
/** Envelope signature */
signature?: (Uint8Array|null);
}
/** Represents an Envelope. */
export class Envelope implements IEnvelope {
/**
* Constructs a new Envelope.
* @param [p] Properties to set
*/
constructor(p?: IEnvelope);
/** Envelope publicKey. */
public publicKey: Uint8Array;
/** Envelope payloadType. */
public payloadType: Uint8Array;
/** Envelope payload. */
public payload: Uint8Array;
/** Envelope signature. */
public signature: Uint8Array;
/**
* Encodes the specified Envelope message. Does not implicitly {@link Envelope.verify|verify} messages.
* @param m Envelope message or plain object to encode
* @param [w] Writer to encode to
* @returns Writer
*/
public static encode(m: IEnvelope, w?: $protobuf.Writer): $protobuf.Writer;
/**
* Decodes an Envelope message from the specified reader or buffer.
* @param r Reader or buffer to decode from
* @param [l] Message length if known beforehand
* @returns Envelope
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Envelope;
/**
* Creates an Envelope message from a plain object. Also converts values to their respective internal types.
* @param d Plain object
* @returns Envelope
*/
public static fromObject(d: { [k: string]: any }): Envelope;
/**
* Creates a plain object from an Envelope message. Also converts values to other types if specified.
* @param m Envelope
* @param [o] Conversion options
* @returns Plain object
*/
public static toObject(m: Envelope, o?: $protobuf.IConversionOptions): { [k: string]: any };
/**
* Converts this Envelope to JSON.
* @returns JSON object
*/
public toJSON(): { [k: string]: any };
}

View File

@@ -0,0 +1,243 @@
/*eslint-disable*/
"use strict";
var $protobuf = require("protobufjs/minimal");
// Common aliases
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
// Exported root namespace
var $root = $protobuf.roots["libp2p-envelope"] || ($protobuf.roots["libp2p-envelope"] = {});
$root.Envelope = (function() {
/**
* Properties of an Envelope.
* @exports IEnvelope
* @interface IEnvelope
* @property {Uint8Array|null} [publicKey] Envelope publicKey
* @property {Uint8Array|null} [payloadType] Envelope payloadType
* @property {Uint8Array|null} [payload] Envelope payload
* @property {Uint8Array|null} [signature] Envelope signature
*/
/**
* Constructs a new Envelope.
* @exports Envelope
* @classdesc Represents an Envelope.
* @implements IEnvelope
* @constructor
* @param {IEnvelope=} [p] Properties to set
*/
function Envelope(p) {
if (p)
for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
if (p[ks[i]] != null)
this[ks[i]] = p[ks[i]];
}
/**
* Envelope publicKey.
* @member {Uint8Array} publicKey
* @memberof Envelope
* @instance
*/
Envelope.prototype.publicKey = $util.newBuffer([]);
/**
* Envelope payloadType.
* @member {Uint8Array} payloadType
* @memberof Envelope
* @instance
*/
Envelope.prototype.payloadType = $util.newBuffer([]);
/**
* Envelope payload.
* @member {Uint8Array} payload
* @memberof Envelope
* @instance
*/
Envelope.prototype.payload = $util.newBuffer([]);
/**
* Envelope signature.
* @member {Uint8Array} signature
* @memberof Envelope
* @instance
*/
Envelope.prototype.signature = $util.newBuffer([]);
/**
* Encodes the specified Envelope message. Does not implicitly {@link Envelope.verify|verify} messages.
* @function encode
* @memberof Envelope
* @static
* @param {IEnvelope} m Envelope message or plain object to encode
* @param {$protobuf.Writer} [w] Writer to encode to
* @returns {$protobuf.Writer} Writer
*/
Envelope.encode = function encode(m, w) {
if (!w)
w = $Writer.create();
if (m.publicKey != null && Object.hasOwnProperty.call(m, "publicKey"))
w.uint32(10).bytes(m.publicKey);
if (m.payloadType != null && Object.hasOwnProperty.call(m, "payloadType"))
w.uint32(18).bytes(m.payloadType);
if (m.payload != null && Object.hasOwnProperty.call(m, "payload"))
w.uint32(26).bytes(m.payload);
if (m.signature != null && Object.hasOwnProperty.call(m, "signature"))
w.uint32(42).bytes(m.signature);
return w;
};
/**
* Decodes an Envelope message from the specified reader or buffer.
* @function decode
* @memberof Envelope
* @static
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
* @param {number} [l] Message length if known beforehand
* @returns {Envelope} Envelope
* @throws {Error} If the payload is not a reader or valid buffer
* @throws {$protobuf.util.ProtocolError} If required fields are missing
*/
Envelope.decode = function decode(r, l) {
if (!(r instanceof $Reader))
r = $Reader.create(r);
var c = l === undefined ? r.len : r.pos + l, m = new $root.Envelope();
while (r.pos < c) {
var t = r.uint32();
switch (t >>> 3) {
case 1:
m.publicKey = r.bytes();
break;
case 2:
m.payloadType = r.bytes();
break;
case 3:
m.payload = r.bytes();
break;
case 5:
m.signature = r.bytes();
break;
default:
r.skipType(t & 7);
break;
}
}
return m;
};
/**
* Creates an Envelope message from a plain object. Also converts values to their respective internal types.
* @function fromObject
* @memberof Envelope
* @static
* @param {Object.<string,*>} d Plain object
* @returns {Envelope} Envelope
*/
Envelope.fromObject = function fromObject(d) {
if (d instanceof $root.Envelope)
return d;
var m = new $root.Envelope();
if (d.publicKey != null) {
if (typeof d.publicKey === "string")
$util.base64.decode(d.publicKey, m.publicKey = $util.newBuffer($util.base64.length(d.publicKey)), 0);
else if (d.publicKey.length)
m.publicKey = d.publicKey;
}
if (d.payloadType != null) {
if (typeof d.payloadType === "string")
$util.base64.decode(d.payloadType, m.payloadType = $util.newBuffer($util.base64.length(d.payloadType)), 0);
else if (d.payloadType.length)
m.payloadType = d.payloadType;
}
if (d.payload != null) {
if (typeof d.payload === "string")
$util.base64.decode(d.payload, m.payload = $util.newBuffer($util.base64.length(d.payload)), 0);
else if (d.payload.length)
m.payload = d.payload;
}
if (d.signature != null) {
if (typeof d.signature === "string")
$util.base64.decode(d.signature, m.signature = $util.newBuffer($util.base64.length(d.signature)), 0);
else if (d.signature.length)
m.signature = d.signature;
}
return m;
};
/**
* Creates a plain object from an Envelope message. Also converts values to other types if specified.
* @function toObject
* @memberof Envelope
* @static
* @param {Envelope} m Envelope
* @param {$protobuf.IConversionOptions} [o] Conversion options
* @returns {Object.<string,*>} Plain object
*/
Envelope.toObject = function toObject(m, o) {
if (!o)
o = {};
var d = {};
if (o.defaults) {
if (o.bytes === String)
d.publicKey = "";
else {
d.publicKey = [];
if (o.bytes !== Array)
d.publicKey = $util.newBuffer(d.publicKey);
}
if (o.bytes === String)
d.payloadType = "";
else {
d.payloadType = [];
if (o.bytes !== Array)
d.payloadType = $util.newBuffer(d.payloadType);
}
if (o.bytes === String)
d.payload = "";
else {
d.payload = [];
if (o.bytes !== Array)
d.payload = $util.newBuffer(d.payload);
}
if (o.bytes === String)
d.signature = "";
else {
d.signature = [];
if (o.bytes !== Array)
d.signature = $util.newBuffer(d.signature);
}
}
if (m.publicKey != null && m.hasOwnProperty("publicKey")) {
d.publicKey = o.bytes === String ? $util.base64.encode(m.publicKey, 0, m.publicKey.length) : o.bytes === Array ? Array.prototype.slice.call(m.publicKey) : m.publicKey;
}
if (m.payloadType != null && m.hasOwnProperty("payloadType")) {
d.payloadType = o.bytes === String ? $util.base64.encode(m.payloadType, 0, m.payloadType.length) : o.bytes === Array ? Array.prototype.slice.call(m.payloadType) : m.payloadType;
}
if (m.payload != null && m.hasOwnProperty("payload")) {
d.payload = o.bytes === String ? $util.base64.encode(m.payload, 0, m.payload.length) : o.bytes === Array ? Array.prototype.slice.call(m.payload) : m.payload;
}
if (m.signature != null && m.hasOwnProperty("signature")) {
d.signature = o.bytes === String ? $util.base64.encode(m.signature, 0, m.signature.length) : o.bytes === Array ? Array.prototype.slice.call(m.signature) : m.signature;
}
return d;
};
/**
* Converts this Envelope to JSON.
* @function toJSON
* @memberof Envelope
* @instance
* @returns {Object.<string,*>} JSON object
*/
Envelope.prototype.toJSON = function toJSON() {
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
};
return Envelope;
})();
module.exports = $root;

View File

@@ -1,9 +1,5 @@
'use strict'
syntax = "proto3";
const protons = require('protons')
/** @type {{Envelope: import('../../types').MessageProto}} */
module.exports = protons(`
message Envelope {
// public_key is the public key of the keypair the enclosed payload was
// signed with.
@@ -20,5 +16,4 @@ message Envelope {
// the enclosed public key, over the payload, prefixing a domain string for
// additional security.
bytes signature = 5;
}
`)
}

View File

@@ -3,13 +3,14 @@
const errCode = require('err-code')
const uint8arraysConcat = require('uint8arrays/concat')
const uint8arraysFromString = require('uint8arrays/from-string')
// @ts-ignore libp2p-crypto does not support types
const cryptoKeys = require('libp2p-crypto/src/keys')
const PeerId = require('peer-id')
const varint = require('varint')
const uint8arraysEquals = require('uint8arrays/equals')
const { codes } = require('../../errors')
const Protobuf = require('./envelope.proto')
const { Envelope: Protobuf } = require('./envelope')
/**
* @typedef {import('libp2p-interfaces/src/record/types').Record} Record
@@ -49,12 +50,12 @@ class Envelope {
const publicKey = cryptoKeys.marshalPublicKey(this.peerId.pubKey)
this._marshal = Protobuf.Envelope.encode({
public_key: publicKey,
payload_type: this.payloadType,
this._marshal = Protobuf.encode({
publicKey: publicKey,
payloadType: this.payloadType,
payload: this.payload,
signature: this.signature
})
}).finish()
return this._marshal
}
@@ -124,12 +125,12 @@ const formatSignaturePayload = (domain, payloadType, payload) => {
* @returns {Promise<Envelope>}
*/
Envelope.createFromProtobuf = async (data) => {
const envelopeData = Protobuf.Envelope.decode(data)
const peerId = await PeerId.createFromPubKey(envelopeData.public_key)
const envelopeData = Protobuf.decode(data)
const peerId = await PeerId.createFromPubKey(envelopeData.publicKey)
return new Envelope({
peerId,
payloadType: envelopeData.payload_type,
payloadType: envelopeData.payloadType,
payload: envelopeData.payload,
signature: envelopeData.signature
})

View File

@@ -1,18 +1,17 @@
'use strict'
const multiaddr = require('multiaddr')
const { Multiaddr } = require('multiaddr')
const PeerId = require('peer-id')
const arrayEquals = require('libp2p-utils/src/array-equals')
const Protobuf = require('./peer-record.proto')
const { PeerRecord: Protobuf } = require('./peer-record')
const {
ENVELOPE_DOMAIN_PEER_RECORD,
ENVELOPE_PAYLOAD_TYPE_PEER_RECORD
} = require('./consts')
/**
* @typedef {import('peer-id')} PeerId
* @typedef {import('multiaddr')} Multiaddr
* @typedef {import('../../peer-store/address-book.js').Address} Address
* @typedef {import('libp2p-interfaces/src/record/types').Record} Record
*/
@@ -52,13 +51,13 @@ class PeerRecord {
return this._marshal
}
this._marshal = Protobuf.PeerRecord.encode({
peer_id: this.peerId.toBytes(),
this._marshal = Protobuf.encode({
peerId: this.peerId.toBytes(),
seq: this.seqNumber,
addresses: this.multiaddrs.map((m) => ({
multiaddr: m.bytes
}))
})
}).finish()
return this._marshal
}
@@ -100,12 +99,11 @@ class PeerRecord {
* @returns {PeerRecord}
*/
PeerRecord.createFromProtobuf = (buf) => {
// Decode
const peerRecord = Protobuf.PeerRecord.decode(buf)
const peerRecord = Protobuf.decode(buf)
const peerId = PeerId.createFromBytes(peerRecord.peer_id)
const multiaddrs = (peerRecord.addresses || []).map((a) => multiaddr(a.multiaddr))
const seqNumber = peerRecord.seq
const peerId = PeerId.createFromBytes(peerRecord.peerId)
const multiaddrs = (peerRecord.addresses || []).map((a) => new Multiaddr(a.multiaddr))
const seqNumber = Number(peerRecord.seq)
return new PeerRecord({ peerId, multiaddrs, seqNumber })
}

Some files were not shown because too many files have changed in this diff Show More