mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-07-23 12:31:57 +00:00
Compare commits
34 Commits
v0.31.3
...
v0.30.0-rc
Author | SHA1 | Date | |
---|---|---|---|
|
0f451659df | ||
|
eaf4fb7ac6 | ||
|
4bbd915a6d | ||
|
64124f17ed | ||
|
117f2b97b0 | ||
|
bbdaae17ae | ||
|
7461d2a642 | ||
|
f82a972ab2 | ||
|
b73106eba2 | ||
|
6b434aeaf7 | ||
|
44f07033fe | ||
|
91b15b6790 | ||
|
9205fce34d | ||
|
a4e858cbf5 | ||
|
3f1dc20caf | ||
|
8351adff2b | ||
|
22e41f5047 | ||
|
48476d504a | ||
|
186f9b758e | ||
|
20d9d98b3a | ||
|
87dcd2ec47 | ||
|
b87d42c074 | ||
|
df5fe0e3ab | ||
|
5d79a137ee | ||
|
8b6c738937 | ||
|
9faf1bfcf6 | ||
|
f9235e2ff6 | ||
|
f9786c8ab8 | ||
|
b45ef6aa54 | ||
|
d79ef8420e | ||
|
fba9457011 | ||
|
c22508c3e4 | ||
|
0ac8252b4c | ||
|
65ec267e7f |
27
.aegir.js
27
.aegir.js
@@ -1,6 +1,5 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const Libp2p = require('./src')
|
||||
const { MULTIADDRS_WEBSOCKETS } = require('./test/fixtures/browser')
|
||||
const Peers = require('./test/fixtures/peers')
|
||||
@@ -32,9 +31,6 @@ const before = async () => {
|
||||
enabled: true,
|
||||
active: false
|
||||
}
|
||||
},
|
||||
nat: {
|
||||
enabled: false
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -48,23 +44,16 @@ 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 = {
|
||||
build: {
|
||||
bundlesizeMax: '253kB'
|
||||
bundlesize: { maxSize: '225kB' },
|
||||
hooks: {
|
||||
pre: before,
|
||||
post: after
|
||||
},
|
||||
test: {
|
||||
before,
|
||||
after,
|
||||
browser: {
|
||||
config: {
|
||||
buildConfig: esbuild
|
||||
}
|
||||
webpack: {
|
||||
node: {
|
||||
// needed by bcrypto
|
||||
Buffer: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
102
.github/workflows/examples.yml
vendored
102
.github/workflows/examples.yml
vendored
@@ -1,102 +0,0 @@
|
||||
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
|
36
.github/workflows/main.yml
vendored
36
.github/workflows/main.yml
vendored
@@ -12,11 +12,11 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: npm install
|
||||
- run: npx aegir lint
|
||||
- run: yarn
|
||||
- run: yarn lint
|
||||
- uses: gozala/typescript-error-reporter-action@v1.0.8
|
||||
- run: npx aegir build
|
||||
- run: npx aegir dep-check
|
||||
- run: yarn build
|
||||
- run: yarn aegir dep-check
|
||||
- uses: ipfs/aegir/actions/bundle-size@master
|
||||
name: size
|
||||
with:
|
||||
@@ -27,41 +27,41 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||
node: [14]
|
||||
node: [12, 14]
|
||||
fail-fast: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: npm install
|
||||
- run: npx aegir test -t node --cov --bail
|
||||
- run: yarn
|
||||
- run: npx nyc --reporter=lcov aegir test -t node -- --bail
|
||||
- uses: codecov/codecov-action@v1
|
||||
test-chrome:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: npm install
|
||||
- run: yarn
|
||||
- run: npx aegir test -t browser -t webworker --bail
|
||||
test-firefox:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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
|
||||
- run: yarn
|
||||
- run: npx aegir test -t browser -t webworker --bail -- --browsers FirefoxHeadless
|
||||
test-interop:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: npm install
|
||||
- run: yarn
|
||||
- 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
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,7 +4,6 @@ docs
|
||||
test/repo-tests*
|
||||
**/bundle.js
|
||||
.cache
|
||||
.parcel-cache
|
||||
|
||||
# Logs
|
||||
logs
|
||||
|
249
CHANGELOG.md
249
CHANGELOG.md
@@ -1,252 +1,3 @@
|
||||
## [0.31.3](https://github.com/libp2p/js-libp2p/compare/v0.31.2...v0.31.3) (2021-05-04)
|
||||
|
||||
|
||||
|
||||
## [0.31.2](https://github.com/libp2p/js-libp2p/compare/v0.31.1...v0.31.2) (2021-04-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* moving averages record types ([#935](https://github.com/libp2p/js-libp2p/issues/935)) ([b5a9eb2](https://github.com/libp2p/js-libp2p/commit/b5a9eb208763efa027d0b4caae87c515b6f5869b))
|
||||
|
||||
|
||||
|
||||
## [0.31.1](https://github.com/libp2p/js-libp2p/compare/v0.31.0...v0.31.1) (2021-04-30)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* event emitter and interfaces types for discovery and routing ([#934](https://github.com/libp2p/js-libp2p/issues/934)) ([302bb90](https://github.com/libp2p/js-libp2p/commit/302bb9005891aa06b70a5f354bfac6b2d5a3c3b8))
|
||||
|
||||
|
||||
|
||||
# [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)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* peer discovery type in config ([#878](https://github.com/libp2p/js-libp2p/issues/878)) ([3e7594f](https://github.com/libp2p/js-libp2p/commit/3e7594f69733bf374b374a6065458fa6cae81c5f))
|
||||
* unref nat manager retries ([#877](https://github.com/libp2p/js-libp2p/issues/877)) ([ce2a624](https://github.com/libp2p/js-libp2p/commit/ce2a624a09b3107c0b2b4752e666804ecea54fb5))
|
||||
|
||||
|
||||
|
||||
## [0.30.5](https://github.com/libp2p/js-libp2p/compare/v0.30.4...v0.30.5) (2021-01-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* create has optional peer id type ([#875](https://github.com/libp2p/js-libp2p/issues/875)) ([eeda056](https://github.com/libp2p/js-libp2p/commit/eeda05688330c17b810bf47544ef977386623317))
|
||||
|
||||
|
||||
|
||||
## [0.30.4](https://github.com/libp2p/js-libp2p/compare/v0.30.3...v0.30.4) (2021-01-27)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add UPnP NAT manager ([#810](https://github.com/libp2p/js-libp2p/issues/810)) ([0a6bc0d](https://github.com/libp2p/js-libp2p/commit/0a6bc0d1013dfd80ab600e8f74c1544b433ece29))
|
||||
|
||||
|
||||
|
||||
## [0.30.3](https://github.com/libp2p/js-libp2p/compare/v0.30.2...v0.30.3) (2021-01-27)
|
||||
|
||||
|
||||
|
||||
## [0.30.2](https://github.com/libp2p/js-libp2p/compare/v0.30.1...v0.30.2) (2021-01-21)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* store multiaddrs during content and peer routing queries ([#865](https://github.com/libp2p/js-libp2p/issues/865)) ([45c3367](https://github.com/libp2p/js-libp2p/commit/45c33675a7412c66d0fd4e113ef8506077b6f492))
|
||||
|
||||
|
||||
|
||||
## [0.30.1](https://github.com/libp2p/js-libp2p/compare/v0.30.0...v0.30.1) (2021-01-18)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* event emitter types with local types ([#864](https://github.com/libp2p/js-libp2p/issues/864)) ([6c41e30](https://github.com/libp2p/js-libp2p/commit/6c41e3045608bcae8061d20501be5751dad8157a))
|
||||
|
||||
|
||||
|
||||
# [0.30.0](https://github.com/libp2p/js-libp2p/compare/v0.29.4...v0.30.0) (2020-12-16)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* remove test/dialing/utils extra file ([689c35e](https://github.com/libp2p/js-libp2p/commit/689c35ed1c68e514293a9895d496e2e8440454e9))
|
||||
* types from ipfs integration ([#832](https://github.com/libp2p/js-libp2p/issues/832)) ([9ae1b75](https://github.com/libp2p/js-libp2p/commit/9ae1b758e99e3fc9067e26b4eae4c15ccb1ba303))
|
||||
|
||||
|
||||
### chore
|
||||
|
||||
* update pubsub ([#801](https://github.com/libp2p/js-libp2p/issues/801)) ([e50c6ab](https://github.com/libp2p/js-libp2p/commit/e50c6abcf2ebc80ebf2dfadd015ab21a20cffadc))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* auto relay ([#723](https://github.com/libp2p/js-libp2p/issues/723)) ([caf66ea](https://github.com/libp2p/js-libp2p/commit/caf66ea1439f6b75a0c321a16bd5c5d7d6a2bd47))
|
||||
* auto relay network query for new relays ([0bf0b7c](https://github.com/libp2p/js-libp2p/commit/0bf0b7cf8968d55002ac4c559ffb59985feeb092))
|
||||
* custom announce filter ([ef9d3ca](https://github.com/libp2p/js-libp2p/commit/ef9d3ca2c6f35d692d6079e74088c5146d46eebe))
|
||||
* custom dialer addr sorter ([#792](https://github.com/libp2p/js-libp2p/issues/792)) ([585ad52](https://github.com/libp2p/js-libp2p/commit/585ad52b4c71dd7514e99a287e0318b2b837ec48))
|
||||
* discover and connect to closest peers ([#798](https://github.com/libp2p/js-libp2p/issues/798)) ([baedf3f](https://github.com/libp2p/js-libp2p/commit/baedf3fe5ab946e938db1415d1662452cdfc0cc1))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* pubsub signing policy properties were changed according to libp2p-interfaces changes to a single property. The emitSelf option default value was also modified to match the routers value
|
||||
|
||||
|
||||
|
||||
# [0.30.0-rc.2](https://github.com/libp2p/js-libp2p/compare/v0.30.0-rc.1...v0.30.0-rc.2) (2020-12-15)
|
||||
|
||||
|
||||
|
||||
# [0.30.0-rc.1](https://github.com/libp2p/js-libp2p/compare/v0.30.0-rc.0...v0.30.0-rc.1) (2020-12-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* types from ipfs integration ([#832](https://github.com/libp2p/js-libp2p/issues/832)) ([216eb97](https://github.com/libp2p/js-libp2p/commit/216eb9730ef473f73a974c3dbaf306ecdc815c8b))
|
||||
|
||||
|
||||
|
||||
# [0.30.0-rc.0](https://github.com/libp2p/js-libp2p/compare/v0.29.4...v0.30.0-rc.0) (2020-12-10)
|
||||
|
||||
|
||||
|
@@ -16,8 +16,8 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/libp2p/js-libp2p/actions?query=branch%3Amaster+workflow%3Aci+"><img src="https://img.shields.io/github/workflow/status/libp2p/js-libp2p/ci?label=ci&style=flat-square" /></a>
|
||||
<a href="https://codecov.io/gh/libp2p/js-libp2p"><img src="https://img.shields.io/codecov/c/github/libp2p/js-libp2p/master.svg?style=flat-square"></a>
|
||||
<a href="https://travis-ci.com/libp2p/js-libp2p"><img src="https://flat.badgen.net/travis/libp2p/js-libp2p" /></a>
|
||||
<a href="https://codecov.io/gh/libp2p/js-libp2p"><img src="https://img.shields.io/codecov/c/github/ipfs/js-ipfs-multipart/master.svg?style=flat-square"></a>
|
||||
<a href="https://bundlephobia.com/result?p=ipfsd-ctl"><img src="https://flat.badgen.net/bundlephobia/minzip/ipfsd-ctl"></a>
|
||||
<br>
|
||||
<a href="https://david-dm.org/libp2p/js-libp2p"><img src="https://david-dm.org/libp2p/js-libp2p.svg?style=flat-square" /></a>
|
||||
@@ -147,6 +147,7 @@ List of packages currently in existence for libp2p
|
||||
| [`libp2p-websockets`](//github.com/libp2p/js-libp2p-websockets) | [](//github.com/libp2p/js-libp2p-websockets/releases) | [](https://david-dm.org/libp2p/js-libp2p-websockets) | [](https://travis-ci.com/libp2p/js-libp2p-websockets) | [](https://codecov.io/gh/libp2p/js-libp2p-websockets) | [Jacob Heun](mailto:jacobheun@gmail.com) |
|
||||
| **secure channels** |
|
||||
| [`libp2p-noise`](//github.com/NodeFactoryIo/js-libp2p-noise) | [](//github.com/NodeFactoryIo/js-libp2p-noise/releases) | [](https://david-dm.org/NodeFactoryIo/js-libp2p-noise) | [](https://travis-ci.com/NodeFactoryIo/js-libp2p-noise) | [](https://codecov.io/gh/NodeFactoryIo/js-libp2p-noise) | N/A |
|
||||
| [`libp2p-secio`](//github.com/libp2p/js-libp2p-secio) | [](//github.com/libp2p/js-libp2p-secio/releases) | [](https://david-dm.org/libp2p/js-libp2p-secio) | [](https://travis-ci.com/libp2p/js-libp2p-secio) | [](https://codecov.io/gh/libp2p/js-libp2p-secio) | [Friedel Ziegelmayer](mailto:dignifiedquire@gmail.com) |
|
||||
| **stream multiplexers** |
|
||||
| [`libp2p-mplex`](//github.com/libp2p/js-libp2p-mplex) | [](//github.com/libp2p/js-libp2p-mplex/releases) | [](https://david-dm.org/libp2p/js-libp2p-mplex) | [](https://travis-ci.com/libp2p/js-libp2p-mplex) | [](https://codecov.io/gh/libp2p/js-libp2p-mplex) | [Vasco Santos](mailto:vasco.santos@moxy.studio) |
|
||||
| **peer discovery** |
|
||||
|
@@ -25,6 +25,7 @@
|
||||
- [ ] [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
|
||||
|
@@ -2055,15 +2055,6 @@ This event will be triggered anytime we are disconnected from another peer, rega
|
||||
- `peerId`: instance of [`PeerId`][peer-id]
|
||||
- `protocols`: array of known, supported protocols for the peer (string identifiers)
|
||||
|
||||
### libp2p.addressManager
|
||||
|
||||
#### Our addresses have changed
|
||||
|
||||
This could be in response to a peer telling us about addresses they have observed, or
|
||||
the NatManager performing NAT hole punching.
|
||||
|
||||
`libp2p.addressManager.on('change:addresses', () => {})`
|
||||
|
||||
## Types
|
||||
|
||||
### Stats
|
||||
|
@@ -28,9 +28,6 @@
|
||||
- [Configuring Metrics](#configuring-metrics)
|
||||
- [Configuring PeerStore](#configuring-peerstore)
|
||||
- [Customizing Transports](#customizing-transports)
|
||||
- [Configuring the NAT Manager](#configuring-the-nat-manager)
|
||||
- [Browser support](#browser-support)
|
||||
- [UPnP and NAT-PMP](#upnp-and-nat-pmp)
|
||||
- [Configuration examples](#configuration-examples)
|
||||
|
||||
## Overview
|
||||
@@ -264,14 +261,13 @@ const TCP = require('libp2p-tcp')
|
||||
const MPLEX = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const MulticastDNS = require('libp2p-mdns')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
|
||||
const node = await Libp2p.create({
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
streamMuxer: [MPLEX],
|
||||
connEncryption: [NOISE],
|
||||
peerDiscovery: [MulticastDNS, Bootstrap]
|
||||
peerDiscovery: [MulticastDNS]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
@@ -281,15 +277,6 @@ const node = await Libp2p.create({
|
||||
[MulticastDNS.tag]: {
|
||||
interval: 1000,
|
||||
enabled: true
|
||||
},
|
||||
[Bootstrap.tag:] {
|
||||
list: [ // A list of bootstrap peers to connect to starting up the node
|
||||
"/ip4/104.131.131.82/tcp/4001/ipfs/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ",
|
||||
"/dnsaddr/bootstrap.libp2p.io/ipfs/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN",
|
||||
"/dnsaddr/bootstrap.libp2p.io/ipfs/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa",
|
||||
],
|
||||
interval: 2000,
|
||||
enabled: true
|
||||
}
|
||||
// .. other discovery module options.
|
||||
}
|
||||
@@ -391,7 +378,6 @@ const Libp2p = require('libp2p')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const MPLEX = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const ipfsHttpClient = require('ipfs-http-client')
|
||||
const DelegatedPeerRouter = require('libp2p-delegated-peer-routing')
|
||||
const DelegatedContentRouter = require('libp2p-delegated-content-routing')
|
||||
const PeerId = require('peer-id')
|
||||
@@ -399,25 +385,17 @@ const PeerId = require('peer-id')
|
||||
// create a peerId
|
||||
const peerId = await PeerId.create()
|
||||
|
||||
const delegatedPeerRouting = new DelegatedPeerRouter(ipfsHttpClient({
|
||||
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
|
||||
protocol: 'https',
|
||||
port: 443
|
||||
}))
|
||||
|
||||
const delegatedContentRouting = new DelegatedContentRouter(peerId, ipfsHttpClient({
|
||||
host: 'node0.delegate.ipfs.io', // In production you should setup your own delegates
|
||||
protocol: 'https',
|
||||
port: 443
|
||||
}))
|
||||
|
||||
const node = await Libp2p.create({
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
streamMuxer: [MPLEX],
|
||||
connEncryption: [NOISE],
|
||||
contentRouting: [delegatedContentRouting],
|
||||
peerRouting: [delegatedPeerRouting],
|
||||
contentRouting: [
|
||||
new DelegatedContentRouter(peerId)
|
||||
],
|
||||
peerRouting: [
|
||||
new DelegatedPeerRouter()
|
||||
],
|
||||
},
|
||||
peerId,
|
||||
peerRouting: { // Peer routing configuration
|
||||
@@ -599,7 +577,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: {
|
||||
@@ -745,40 +723,6 @@ const node = await Libp2p.create({
|
||||
})
|
||||
```
|
||||
|
||||
#### Configuring the NAT Manager
|
||||
|
||||
Network Address Translation (NAT) is a function performed by your router to enable multiple devices on your local network to share a single IPv4 address. It's done transparently for outgoing connections, ensuring the correct response traffic is routed to your computer, but if you wish to accept incoming connections some configuration is necessary.
|
||||
|
||||
The NAT manager can be configured as follows:
|
||||
|
||||
```js
|
||||
const node = await Libp2p.create({
|
||||
config: {
|
||||
nat: {
|
||||
description: 'my-node', // set as the port mapping description on the router, defaults the current libp2p version and your peer id
|
||||
enabled: true, // defaults to true
|
||||
gateway: '192.168.1.1', // leave unset to auto-discover
|
||||
externalIp: '80.1.1.1', // leave unset to auto-discover
|
||||
ttl: 7200, // TTL for port mappings (min 20 minutes)
|
||||
keepAlive: true, // Refresh port mapping after TTL expires
|
||||
pmp: {
|
||||
enabled: false, // defaults to false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
##### Browser support
|
||||
|
||||
Browsers cannot open TCP ports or send the UDP datagrams necessary to configure external port mapping - to accept incoming connections in the browser please use a WebRTC transport.
|
||||
|
||||
##### UPnP and NAT-PMP
|
||||
|
||||
By default under nodejs libp2p will attempt to use [UPnP](https://en.wikipedia.org/wiki/Universal_Plug_and_Play) to configure your router to allow incoming connections to any TCP transports that have been configured.
|
||||
|
||||
[NAT-PMP](http://miniupnp.free.fr/nat-pmp.html) is a feature of some modern routers which performs a similar job to UPnP. NAT-PMP is disabled by default, if enabled libp2p will try to use NAT-PMP and will fall back to UPnP if it fails.
|
||||
|
||||
## Configuration examples
|
||||
|
||||
As libp2p is designed to be a modular networking library, its usage will vary based on individual project needs. We've included links to some existing project configurations for your reference, in case you wish to replicate their configuration:
|
||||
|
@@ -1,123 +0,0 @@
|
||||
<!--Specify versions for migration below-->
|
||||
# Migrating to libp2p@31
|
||||
|
||||
A migration guide for refactoring your application code from libp2p v0.30.x to v0.31.0.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Types](#types)
|
||||
- [API](#api)
|
||||
- [Module Updates](#module-updates)
|
||||
|
||||
## Types
|
||||
|
||||
Most of the type definitions in the libp2p configuration were `any` or were not included before this release. This might cause breaking changes on upstream projects relying on the previous provided types, as well as to libp2p modules implemented by the libp2p community.
|
||||
|
||||
## API
|
||||
|
||||
### Core API
|
||||
|
||||
`libp2p.dialProtocol` does not accept empty or null protocols returning a connection anymore and `dial` must be used instead.
|
||||
|
||||
```js
|
||||
const connection = await libp2p.dialProtocol(peerId)
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
const connection = await libp2p.dial(peerId)
|
||||
```
|
||||
|
||||
### Connection Manager Options
|
||||
|
||||
We updated the connection manager options naming in `libp2p@0.29` but kept it backward compatible until now.
|
||||
|
||||
**Before**
|
||||
|
||||
```js
|
||||
const node = await Libp2p.create({
|
||||
connectionManager: {
|
||||
minPeers: 0
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
const node = await Libp2p.create({
|
||||
connectionManager: {
|
||||
minConnections: 0
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You can see full details on how to configure the connection manager [here](https://github.com/libp2p/js-libp2p/blob/master/doc/CONFIGURATION.md#configuring-connection-manager).
|
||||
|
||||
### Dialer and Keychain components
|
||||
|
||||
Internal property names to create a libp2p `Dialer` and `Keychain` were updated to reflect the properties naming in the libp2p configuration. These are internal modules of libp2p core and should not impact most of the users, but as it is possible to use them separately here follow the changes:
|
||||
|
||||
***Before**
|
||||
|
||||
```js
|
||||
const dialer = new Dialer({
|
||||
transportManager,
|
||||
peerStore,
|
||||
concurrency,
|
||||
perPeerLimit,
|
||||
timeout,
|
||||
resolvers,
|
||||
addressSorter
|
||||
})
|
||||
|
||||
const keychain = new Keychain(datastore, {
|
||||
passPhrase
|
||||
})
|
||||
```
|
||||
|
||||
**After**
|
||||
|
||||
```js
|
||||
this.dialer = new Dialer({
|
||||
transportManager,
|
||||
peerStore,
|
||||
maxParallelDials,
|
||||
maxDialsPerPeer,
|
||||
dialTimeout,
|
||||
resolvers,
|
||||
addressSorter
|
||||
})
|
||||
|
||||
const keychain = new Keychain(datastore, {
|
||||
pass
|
||||
})
|
||||
```
|
||||
|
||||
## Module Updates
|
||||
|
||||
With this release you should update the following libp2p modules if you are relying on them:
|
||||
|
||||
<!--Specify module versions in JSON for migration below.
|
||||
It's recommended to check package.json changes for this:
|
||||
`git diff <release> <prev> -- package.json`
|
||||
-->
|
||||
|
||||
```json
|
||||
"libp2p-bootstrap": "^0.12.3",
|
||||
"libp2p-crypto": "^0.19.4",
|
||||
"libp2p-interfaces": "^0.10.0",
|
||||
"libp2p-delegated-content-routing": "^0.10.0",
|
||||
"libp2p-delegated-peer-routing": "^0.9.0",
|
||||
"libp2p-floodsub": "^0.25.1",
|
||||
"libp2p-gossipsub": "^0.9.0",
|
||||
"libp2p-kad-dht": "^0.22.0",
|
||||
"libp2p-mdns": "^0.16.0",
|
||||
"libp2p-noise": "^3.0.0",
|
||||
"libp2p-tcp": "^0.15.4",
|
||||
"libp2p-webrtc-star": "^0.22.2",
|
||||
"libp2p-websockets": "^0.15.6"
|
||||
```
|
||||
|
||||
One of the main changes in this new release is the update to `multiaddr@9.0.0`. This should also be updated in upstream projects to avoid several multiaddr versions in the bundle and to avoid potential problems when libp2p interacts with provided outdated multiaddr instances.
|
@@ -8,7 +8,7 @@ Let us know if you find any issues, or if you want to contribute and add a new t
|
||||
|
||||
- [Transports](./transports)
|
||||
- [Protocol and Stream Muxing](./protocol-and-stream-muxing)
|
||||
- [Connection Encryption](./connection-encryption)
|
||||
- [Encrypted Communications](./encrypted-communications)
|
||||
- [Discovery Mechanisms](./discovery-mechanisms)
|
||||
- [Peer and Content Routing](./peer-and-content-routing)
|
||||
- [PubSub](./pubsub)
|
||||
|
@@ -3,7 +3,7 @@
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const multiaddr = require('multiaddr')
|
||||
const createLibp2p = require('./libp2p')
|
||||
const createLibp2p = require('./libp2p-bundle')
|
||||
const { stdinToStream, streamToConsole } = require('./stream')
|
||||
|
||||
async function run() {
|
||||
|
@@ -2,7 +2,7 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const createLibp2p = require('./libp2p.js')
|
||||
const createLibp2p = require('./libp2p-bundle.js')
|
||||
const { stdinToStream, streamToConsole } = require('./stream')
|
||||
|
||||
async function run() {
|
||||
|
@@ -1,77 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
function startProcess(name) {
|
||||
return execa('node', [path.join(__dirname, name)], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
}
|
||||
|
||||
async function test () {
|
||||
const message = 'test message'
|
||||
let listenerOutput = ''
|
||||
let dialerOutput = ''
|
||||
|
||||
let isListening = false
|
||||
let messageSent = false
|
||||
const listenerReady = pDefer()
|
||||
const dialerReady = pDefer()
|
||||
const messageReceived = pDefer()
|
||||
|
||||
// Step 1 process
|
||||
process.stdout.write('node listener.js\n')
|
||||
const listenerProc = startProcess('src/listener.js')
|
||||
listenerProc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
listenerOutput += uint8ArrayToString(data)
|
||||
|
||||
if (!isListening && listenerOutput.includes('Listener ready, listening on')) {
|
||||
listenerReady.resolve()
|
||||
isListening = true
|
||||
} else if (isListening && listenerOutput.includes(message)) {
|
||||
messageReceived.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await listenerReady.promise
|
||||
process.stdout.write('==================================================================\n')
|
||||
|
||||
// Step 2 process
|
||||
process.stdout.write('node dialer.js\n')
|
||||
const dialerProc = startProcess('src/dialer.js')
|
||||
dialerProc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
dialerOutput += uint8ArrayToString(data)
|
||||
|
||||
if (!messageSent && dialerOutput.includes('Type a message and see what happens')) {
|
||||
dialerReady.resolve()
|
||||
dialerProc.stdin.write(message)
|
||||
dialerProc.stdin.write('\n')
|
||||
messageSent = true
|
||||
}
|
||||
})
|
||||
|
||||
await dialerReady.promise
|
||||
process.stdout.write('==================================================================\n')
|
||||
await messageReceived.promise
|
||||
process.stdout.write('chat message received\n')
|
||||
|
||||
listenerProc.kill()
|
||||
dialerProc.kill()
|
||||
await Promise.all([
|
||||
listenerProc,
|
||||
dialerProc
|
||||
]).catch((err) => {
|
||||
if (err.signal !== 'SIGTERM') {
|
||||
throw err
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,30 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const messageReceived = 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 s = uint8ArrayToString(data)
|
||||
if (s.includes('This information is sent out encrypted to the other peer')) {
|
||||
messageReceived.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await messageReceived.promise
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -7,7 +7,15 @@ const Mplex = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
|
||||
const bootstrapers = require('./bootstrapers')
|
||||
// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/src/core/runtime/config-nodejs.json
|
||||
const bootstrapers = [
|
||||
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
||||
]
|
||||
|
||||
;(async () => {
|
||||
const node = await Libp2p.create({
|
||||
|
@@ -1,68 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
'use strict'
|
||||
|
||||
const Libp2p = require('../../')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const Mplex = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const Gossipsub = require('libp2p-gossipsub')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
const PubsubPeerDiscovery = require('libp2p-pubsub-peer-discovery')
|
||||
|
||||
const createRelayServer = require('libp2p-relay-server')
|
||||
|
||||
const createNode = async (bootstrapers) => {
|
||||
const node = await Libp2p.create({
|
||||
addresses: {
|
||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||
},
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
streamMuxer: [Mplex],
|
||||
connEncryption: [NOISE],
|
||||
pubsub: Gossipsub,
|
||||
peerDiscovery: [Bootstrap, PubsubPeerDiscovery]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
[PubsubPeerDiscovery.tag]: {
|
||||
interval: 1000,
|
||||
enabled: true
|
||||
},
|
||||
[Bootstrap.tag]: {
|
||||
enabled: true,
|
||||
list: bootstrapers
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
const relay = await createRelayServer({
|
||||
listenAddresses: ['/ip4/0.0.0.0/tcp/0']
|
||||
})
|
||||
console.log(`libp2p relay starting with id: ${relay.peerId.toB58String()}`)
|
||||
await relay.start()
|
||||
const relayMultiaddrs = relay.multiaddrs.map((m) => `${m.toString()}/p2p/${relay.peerId.toB58String()}`)
|
||||
|
||||
const [node1, node2] = await Promise.all([
|
||||
createNode(relayMultiaddrs),
|
||||
createNode(relayMultiaddrs)
|
||||
])
|
||||
|
||||
node1.on('peer:discovery', (peerId) => {
|
||||
console.log(`Peer ${node1.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
|
||||
})
|
||||
node2.on('peer:discovery', (peerId) => {
|
||||
console.log(`Peer ${node2.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
|
||||
})
|
||||
|
||||
;[node1, node2].forEach((node, index) => console.log(`Node ${index} starting with id: ${node.peerId.toB58String()}`))
|
||||
await Promise.all([
|
||||
node1.start(),
|
||||
node2.start()
|
||||
])
|
||||
})();
|
@@ -2,13 +2,13 @@
|
||||
|
||||
A Peer Discovery module enables libp2p to find peers to connect to. Think of these mechanisms as ways to join the rest of the network, as railing points.
|
||||
|
||||
With this system, a libp2p node can both have a set of nodes to always connect on boot (bootstraper nodes), discover nodes through locality (e.g connected in the same LAN) or through serendipity (random walks on a DHT).
|
||||
With these system, a libp2p node can both have a set of nodes to always connect on boot (bootstraper nodes), discover nodes through locality (e.g connected in the same LAN) or through serendipity (random walks on a DHT).
|
||||
|
||||
These mechanisms save configuration and enable a node to operate without any explicit dials, it will just work. Once new peers are discovered, their known data is stored in the peer's PeerStore.
|
||||
|
||||
## 1. Bootstrap list of Peers when booting a node
|
||||
|
||||
For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, mplex, and NOISE. You can see the complete example at [1.js](./1.js).
|
||||
For this demo, we will connect to IPFS default bootstrapper nodes and so, we will need to support the same set of features those nodes have, that are: TCP, mplex and NOISE. You can see the complete example at [1.js](./1.js).
|
||||
|
||||
First, we create our libp2p node.
|
||||
|
||||
@@ -16,7 +16,7 @@ First, we create our libp2p node.
|
||||
const Libp2p = require('libp2p')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
|
||||
const node = await Libp2p.create({
|
||||
const node = Libp2p.create({
|
||||
modules: {
|
||||
transport: [ TCP ],
|
||||
streamMuxer: [ Mplex ],
|
||||
@@ -156,103 +156,10 @@ Discovered: QmSSbQpuKrxkoXHm1v4Pi35hPN5hUHMZoBoawEs2Nhvi8m
|
||||
Discovered: QmRcXXhtG8vTqwVBRonKWtV4ovDoC1Fe56WYtcrw694eiJ
|
||||
```
|
||||
|
||||
## 3. Pubsub based Peer Discovery
|
||||
|
||||
For this example, we need [`libp2p-pubsub-peer-discovery`](https://github.com/libp2p/js-libp2p-pubsub-peer-discovery/), go ahead and `npm install` it. You also need to spin up a set of [`libp2p-relay-servers`](https://github.com/libp2p/js-libp2p-relay-server). These servers act as relay servers and a peer discovery source.
|
||||
|
||||
In the context of this example, we will create and run the `libp2p-relay-server` in the same code snippet. You can find the complete solution at [3.js](./3.js).
|
||||
|
||||
You can create your libp2p nodes as follows:
|
||||
|
||||
```js
|
||||
const Libp2p = require('libp2p')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const Mplex = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
||||
const Gossipsub = require('libp2p-gossipsub')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
const PubsubPeerDiscovery = require('libp2p-pubsub-peer-discovery')
|
||||
|
||||
const createNode = async (bootstrapers) => {
|
||||
const node = await Libp2p.create({
|
||||
addresses: {
|
||||
listen: ['/ip4/0.0.0.0/tcp/0']
|
||||
},
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
streamMuxer: [Mplex],
|
||||
connEncryption: [NOISE],
|
||||
pubsub: Gossipsub,
|
||||
peerDiscovery: [Bootstrap, PubsubPeerDiscovery]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
[PubsubPeerDiscovery.tag]: {
|
||||
interval: 1000,
|
||||
enabled: true
|
||||
},
|
||||
[Bootstrap.tag]: {
|
||||
enabled: true,
|
||||
list: bootstrapers
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return node
|
||||
}
|
||||
```
|
||||
|
||||
We will use the `libp2p-relay-server` as bootstrap nodes for the libp2p nodes, so that they establish a connection with the relay after starting. As a result, after they establish a connection with the relay, the pubsub discovery will kick in and the relay will advertise them.
|
||||
|
||||
```js
|
||||
const relay = await createRelayServer({
|
||||
listenAddresses: ['/ip4/0.0.0.0/tcp/0']
|
||||
})
|
||||
console.log(`libp2p relay starting with id: ${relay.peerId.toB58String()}`)
|
||||
await relay.start()
|
||||
const relayMultiaddrs = relay.multiaddrs.map((m) => `${m.toString()}/p2p/${relay.peerId.toB58String()}`)
|
||||
|
||||
const [node1, node2] = await Promise.all([
|
||||
createNode(relayMultiaddrs),
|
||||
createNode(relayMultiaddrs)
|
||||
])
|
||||
|
||||
node1.on('peer:discovery', (peerId) => {
|
||||
console.log(`Peer ${node1.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
|
||||
})
|
||||
node2.on('peer:discovery', (peerId) => {
|
||||
console.log(`Peer ${node2.peerId.toB58String()} discovered: ${peerId.toB58String()}`)
|
||||
})
|
||||
|
||||
;[node1, node2].forEach((node, index) => console.log(`Node ${index} starting with id: ${node.peerId.toB58String()}`))
|
||||
await Promise.all([
|
||||
node1.start(),
|
||||
node2.start()
|
||||
])
|
||||
```
|
||||
|
||||
If you run this example, you will see the other peers being discovered.
|
||||
|
||||
```bash
|
||||
> node 3.js
|
||||
libp2p relay starting with id: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
|
||||
Node 0 starting with id: QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N
|
||||
Node 1 starting with id: QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv
|
||||
Peer QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N discovered: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
|
||||
Peer QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv discovered: QmW6FqVV6RsyoGC5zaeFGW9gSWA3LcBRVZrjkKMruh38Bo
|
||||
Peer QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv discovered: QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N
|
||||
Peer QmezqDTmEjZ5BfMgVqjSpLY19mVVLTQ9bE9mRpZwtGxL8N discovered: QmYWeom2odTkm79DzB68NHULqVHDaNDqHhoyqLdcV1fqdv
|
||||
```
|
||||
|
||||
Taking into account the output, after the relay and both libp2p nodes start, both libp2p nodes will discover the bootstrap node (relay) and connect with it. After establishing a connection with the relay, they will discover each other.
|
||||
|
||||
This is really useful when running libp2p in constrained environments like a browser. You can run a set of `libp2p-relay-server` nodes that will be responsible for both relaying websocket connections between browser nodes and for discovering other browser peers.
|
||||
|
||||
## 4. Where to find other Peer Discovery Mechanisms
|
||||
## 3. Where to find other Peer Discovery Mechanisms
|
||||
|
||||
There are plenty more Peer Discovery Mechanisms out there, you can:
|
||||
|
||||
- Find one in [libp2p-webrtc-star](https://github.com/libp2p/js-libp2p-webrtc-star). Yes, a transport with discovery capabilities! This happens because WebRTC requires a rendezvous point for peers to exchange [SDP](https://tools.ietf.org/html/rfc4317) offer, which means we have one or more points that can introduce peers to each other. Think of it as MulticastDNS for the Web, as in MulticastDNS only works in LAN.
|
||||
- Any DHT will offer you a discovery capability. You can simple _random-walk_ the routing tables to find other peers to connect to. For example [libp2p-kad-dht](https://github.com/libp2p/js-libp2p-kad-dht) can be used for peer discovery. An example of how to configure it to enable random walks can be found [here](https://github.com/libp2p/js-libp2p/blob/v0.28.4/doc/CONFIGURATION.md#customizing-dht).
|
||||
- Any DHT will offer you a discovery capability. You can simple _random-walk_ the routing tables to find other peers to connect to. For example [libp2p-kad-dht](https://github.com/libp2p/js-libp2p-kad-dht) can be used for peer discovery. An example how to configure it to enable random walks can be found [here](https://github.com/libp2p/js-libp2p/blob/v0.28.4/doc/CONFIGURATION.md#customizing-dht).
|
||||
- You can create your own Discovery service, a registry, a list, a radio beacon, you name it!
|
||||
|
13
examples/discovery-mechanisms/bootstrapers.js
vendored
13
examples/discovery-mechanisms/bootstrapers.js
vendored
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
// Find this list at: https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs-core/src/runtime/config-nodejs.js
|
||||
const bootstrapers = [
|
||||
'/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmZa1sAxajnQjVM8WjWXoMbmPd7NsWhfKsPkErzpm9wGkp',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa',
|
||||
'/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt'
|
||||
]
|
||||
|
||||
module.exports = bootstrapers
|
@@ -1,42 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
const bootstrapers = require('./bootstrapers')
|
||||
|
||||
const discoveredCopy = 'Discovered:'
|
||||
const connectedCopy = 'Connection established to:'
|
||||
|
||||
async function test () {
|
||||
const discoveredNodes = []
|
||||
const connectedNodes = []
|
||||
|
||||
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)
|
||||
|
||||
// Discovered or Connected
|
||||
if (line.includes(discoveredCopy)) {
|
||||
const id = line.trim().split(discoveredCopy)[1]
|
||||
discoveredNodes.push(id)
|
||||
} else if (line.includes(connectedCopy)) {
|
||||
const id = line.trim().split(connectedCopy)[1]
|
||||
connectedNodes.push(id)
|
||||
}
|
||||
})
|
||||
|
||||
await pWaitFor(() => discoveredNodes.length === bootstrapers.length && connectedNodes.length === bootstrapers.length)
|
||||
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,35 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const discoveredCopy = 'Discovered:'
|
||||
|
||||
async function test() {
|
||||
const discoveredNodes = []
|
||||
|
||||
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(discoveredCopy)) {
|
||||
const id = line.trim().split(discoveredCopy)[1]
|
||||
discoveredNodes.push(id)
|
||||
}
|
||||
})
|
||||
|
||||
await pWaitFor(() => discoveredNodes.length === 2)
|
||||
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,35 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const discoveredCopy = 'discovered:'
|
||||
|
||||
async function test() {
|
||||
let discoverCount = 0
|
||||
|
||||
process.stdout.write('3.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '3.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
// Discovered or Connected
|
||||
if (line.includes(discoveredCopy)) {
|
||||
discoverCount++
|
||||
}
|
||||
})
|
||||
|
||||
await pWaitFor(() => discoverCount === 4)
|
||||
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const test1 = require('./test-1')
|
||||
const test2 = require('./test-2')
|
||||
const test3 = require('./test-3')
|
||||
|
||||
async function test () {
|
||||
await test1()
|
||||
await test2()
|
||||
await test3()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const createLibp2p = require('./libp2p')
|
||||
const createLibp2p = require('./libp2p-bundle')
|
||||
const pipe = require('it-pipe')
|
||||
|
||||
async function run() {
|
||||
|
@@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const createLibp2p = require('./libp2p')
|
||||
const createLibp2p = require('./libp2p-bundle')
|
||||
const pipe = require('it-pipe')
|
||||
|
||||
async function run() {
|
||||
|
@@ -1,61 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
function startProcess(name) {
|
||||
return execa('node', [path.join(__dirname, name)], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
}
|
||||
|
||||
async function test () {
|
||||
const listenerReady = pDefer()
|
||||
const messageReceived = pDefer()
|
||||
|
||||
// Step 1 process
|
||||
process.stdout.write('node listener.js\n')
|
||||
const listenerProc = startProcess('src/listener.js')
|
||||
listenerProc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const s = uint8ArrayToString(data)
|
||||
|
||||
if (s.includes('Listener ready, listening on:')) {
|
||||
listenerReady.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await listenerReady.promise
|
||||
process.stdout.write('==================================================================\n')
|
||||
|
||||
// Step 2 process
|
||||
process.stdout.write('node dialer.js\n')
|
||||
const dialerProc = startProcess('src/dialer.js')
|
||||
dialerProc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const s = uint8ArrayToString(data)
|
||||
|
||||
if (s.includes('received echo:')) {
|
||||
messageReceived.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await messageReceived.promise
|
||||
process.stdout.write('echo message received\n')
|
||||
|
||||
listenerProc.kill()
|
||||
dialerProc.kill()
|
||||
await Promise.all([
|
||||
listenerProc,
|
||||
dialerProc
|
||||
]).catch((err) => {
|
||||
if (err.signal !== 'SIGTERM') {
|
||||
throw err
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,6 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
const Libp2p = require('../..')
|
||||
const Libp2p = require('../../')
|
||||
const TCP = require('libp2p-tcp')
|
||||
const Mplex = require('libp2p-mplex')
|
||||
const { NOISE } = require('libp2p-noise')
|
@@ -1,4 +1,4 @@
|
||||
# Connection Encryption
|
||||
# Encrypted Communications
|
||||
|
||||
libp2p can leverage the encrypted communications from the transports it uses (i.e WebRTC). To ensure that every connection is encrypted, independently of how it was set up, libp2p also supports a set of modules that encrypt every communication established.
|
||||
|
@@ -4,13 +4,9 @@ This example leverages the [Parcel.js bundler](https://parceljs.org/) to compile
|
||||
|
||||
## Setup
|
||||
|
||||
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:
|
||||
In order to run the example, first install the dependencies from same directory as this README:
|
||||
|
||||
```
|
||||
npm install
|
||||
cd ./examples/libp2p-in-the-browser
|
||||
npm install
|
||||
```
|
||||
|
@@ -2,33 +2,32 @@
|
||||
"name": "libp2p-in-browser",
|
||||
"version": "1.0.0",
|
||||
"description": "A libp2p node running in the browser",
|
||||
"main": "dist/index.html",
|
||||
"main": "index.js",
|
||||
"browserslist": [
|
||||
"last 2 Chrome versions"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1",
|
||||
"build": "parcel build index.html",
|
||||
"start": "parcel index.html"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@babel/preset-env": "^7.13.0",
|
||||
"@babel/preset-env": "^7.8.3",
|
||||
"libp2p": "../../",
|
||||
"libp2p-bootstrap": "^0.12.1",
|
||||
"libp2p-mplex": "^0.10.0",
|
||||
"libp2p-noise": "^2.0.0",
|
||||
"libp2p-webrtc-star": "^0.22.0",
|
||||
"libp2p-websockets": "^0.15.0"
|
||||
"libp2p-webrtc-star": "^0.20.0",
|
||||
"libp2p-websockets": "^0.14.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.13.10",
|
||||
"@babel/core": "^7.13.0",
|
||||
"@babel/cli": "^7.8.3",
|
||||
"@babel/core": "^7.8.3",
|
||||
"babel-plugin-syntax-async-functions": "^6.13.0",
|
||||
"babel-plugin-transform-regenerator": "^6.26.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"parcel": "next"
|
||||
"parcel-bundler": "^1.12.4"
|
||||
}
|
||||
}
|
||||
|
@@ -1,52 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const execa = require('execa')
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
async function run() {
|
||||
let url = ''
|
||||
const proc = execa('parcel', ['./index.html'], {
|
||||
preferLocal: true,
|
||||
localDir: __dirname,
|
||||
cwd: __dirname,
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (chunk) => {
|
||||
/**@type {string} */
|
||||
const out = chunk.toString()
|
||||
|
||||
if (out.includes('Server running at')) {
|
||||
url = 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(url);
|
||||
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: 5000 }
|
||||
)
|
||||
await browser.close();
|
||||
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
} finally {
|
||||
proc.cancel()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
module.exports = run
|
@@ -10,12 +10,7 @@
|
||||
"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"
|
||||
},
|
||||
"devDependencies": {
|
||||
"playwright": "^1.7.1"
|
||||
}
|
||||
}
|
||||
|
@@ -1,36 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test() {
|
||||
process.stdout.write('1.js\n')
|
||||
|
||||
const addrs = []
|
||||
let foundIt = false
|
||||
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
// Discovered peer
|
||||
if (!foundIt && line.includes('Found it, multiaddrs are:')) {
|
||||
foundIt = true
|
||||
}
|
||||
|
||||
addrs.push(line)
|
||||
})
|
||||
|
||||
await pWaitFor(() => addrs.length === 2)
|
||||
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,40 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const providedCopy = 'is providing'
|
||||
const foundCopy = 'Found provider:'
|
||||
|
||||
async function test() {
|
||||
process.stdout.write('2.js\n')
|
||||
const providedDefer = pDefer()
|
||||
const foundDefer = pDefer()
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '2.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes(providedCopy)) {
|
||||
providedDefer.resolve()
|
||||
} else if (line.includes(foundCopy)) {
|
||||
foundDefer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
providedDefer.promise,
|
||||
foundDefer.promise
|
||||
])
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,11 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const test1 = require('./test-1')
|
||||
const test2 = require('./test-2')
|
||||
|
||||
async function test() {
|
||||
await test1()
|
||||
await test2()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,30 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const messageReceived = pDefer()
|
||||
process.stdout.write('index.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, 'index.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const s = uint8ArrayToString(data)
|
||||
if (s.includes('This message is sent on a private network')) {
|
||||
messageReceived.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await messageReceived.promise
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,31 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test() {
|
||||
const messageDefer = pDefer()
|
||||
process.stdout.write('1.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes('my own protocol, wow!')) {
|
||||
messageDefer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await messageDefer.promise
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,38 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const messages = [
|
||||
'protocol (a)',
|
||||
'protocol (b)',
|
||||
'another stream on protocol (b)'
|
||||
]
|
||||
|
||||
async function test() {
|
||||
process.stdout.write('2.js\n')
|
||||
|
||||
let count = 0
|
||||
const proc = execa('node', [path.join(__dirname, '2.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (messages.find((m) => line.includes(m))) {
|
||||
count += 1
|
||||
}
|
||||
})
|
||||
|
||||
await pWaitFor(() => count === messages.length)
|
||||
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,37 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const messages = [
|
||||
'from 1 to 2',
|
||||
'from 2 to 1'
|
||||
]
|
||||
|
||||
async function test() {
|
||||
process.stdout.write('3.js\n')
|
||||
|
||||
let count = 0
|
||||
const proc = execa('node', [path.join(__dirname, '3.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (messages.find((m) => line.includes(m))) {
|
||||
count += 1
|
||||
}
|
||||
})
|
||||
|
||||
await pWaitFor(() => count === messages.length)
|
||||
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const test1 = require('./test-1')
|
||||
const test2 = require('./test-2')
|
||||
const test3 = require('./test-3')
|
||||
|
||||
async function test() {
|
||||
await test1()
|
||||
await test2()
|
||||
await test3()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,67 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const stdout = [
|
||||
{
|
||||
topic: 'banana',
|
||||
messageCount: 2
|
||||
},
|
||||
{
|
||||
topic: 'apple',
|
||||
messageCount: 2
|
||||
},
|
||||
{
|
||||
topic: 'car',
|
||||
messageCount: 0
|
||||
},
|
||||
{
|
||||
topic: 'orange',
|
||||
messageCount: 2
|
||||
},
|
||||
]
|
||||
|
||||
async function test () {
|
||||
const defer = pDefer()
|
||||
let topicCount = 0
|
||||
let topicMessageCount = 0
|
||||
|
||||
process.stdout.write('message-filtering/1.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
// End
|
||||
if (topicCount === stdout.length) {
|
||||
defer.resolve()
|
||||
proc.all.removeAllListeners('data')
|
||||
}
|
||||
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (stdout[topicCount] && line.includes(stdout[topicCount].topic)) {
|
||||
// Validate previous number of messages
|
||||
if (topicCount > 0 && topicMessageCount > stdout[topicCount - 1].messageCount) {
|
||||
defer.reject()
|
||||
throw new Error(`topic ${stdout[topicCount - 1].topic} had ${topicMessageCount} messages instead of ${stdout[topicCount - 1].messageCount}`)
|
||||
}
|
||||
|
||||
topicCount++
|
||||
topicMessageCount = 0
|
||||
} else {
|
||||
topicMessageCount++
|
||||
}
|
||||
})
|
||||
|
||||
await defer.promise
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,30 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const defer = pDefer()
|
||||
process.stdout.write('1.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes('node1 received: Bird bird bird, bird is the word!')) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await defer.promise
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,11 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const test1 = require('./test-1')
|
||||
const testMessageFiltering = require('./message-filtering/test')
|
||||
|
||||
async function test() {
|
||||
await test1()
|
||||
await testMessageFiltering()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -22,6 +22,7 @@ async function testExample (dir) {
|
||||
await installDeps(dir)
|
||||
await build(dir)
|
||||
await runTest(dir)
|
||||
// TODO: add browser test setup
|
||||
}
|
||||
|
||||
async function installDeps (dir) {
|
||||
@@ -88,7 +89,7 @@ async function runTest (dir) {
|
||||
return
|
||||
}
|
||||
|
||||
const test = require(testFile)
|
||||
const runTest = require(testFile)
|
||||
|
||||
await test()
|
||||
}
|
||||
await runTest()
|
||||
}
|
@@ -1,38 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const deferStarted = pDefer()
|
||||
const deferListen = pDefer()
|
||||
|
||||
process.stdout.write('1.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '1.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
|
||||
if (line.includes('node has started (true/false): true')) {
|
||||
deferStarted.resolve()
|
||||
} else if (line.includes('p2p')) {
|
||||
deferListen.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
deferStarted.promise,
|
||||
deferListen.promise
|
||||
])
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,30 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const defer = pDefer()
|
||||
process.stdout.write('2.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '2.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes('Hello p2p world!')) {
|
||||
defer.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await defer.promise
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,41 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
async function test () {
|
||||
const deferNode1 = pDefer()
|
||||
const deferNode2 = pDefer()
|
||||
const deferNode3 = pDefer()
|
||||
|
||||
process.stdout.write('3.js\n')
|
||||
|
||||
const proc = execa('node', [path.join(__dirname, '3.js')], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
|
||||
proc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
const line = uint8ArrayToString(data)
|
||||
|
||||
if (line.includes('node 1 dialed to node 2 successfully')) {
|
||||
deferNode1.resolve()
|
||||
} else if (line.includes('node 2 dialed to node 3 successfully')) {
|
||||
deferNode2.resolve()
|
||||
} else if (line.includes('node 3 failed to dial to node 1 with:')) {
|
||||
deferNode3.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await Promise.all([
|
||||
deferNode1.promise,
|
||||
deferNode2.promise,
|
||||
deferNode3.promise
|
||||
])
|
||||
proc.kill()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,13 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const test1 = require('./test-1')
|
||||
const test2 = require('./test-2')
|
||||
const test3 = require('./test-3')
|
||||
|
||||
async function test() {
|
||||
await test1()
|
||||
await test2()
|
||||
await test3()
|
||||
}
|
||||
|
||||
module.exports = test
|
@@ -1,33 +0,0 @@
|
||||
### Webrtc-direct example
|
||||
|
||||
An example that uses [js-libp2p-webrtc-direct](https://github.com/libp2p/js-libp2p-webrtc-direct) for connecting
|
||||
nodejs libp2p and browser libp2p clients. To run the example:
|
||||
|
||||
## 0. Run a nodejs libp2p listener
|
||||
|
||||
When in the root folder of this example, type `node listener.js` in terminal. You should see an address that listens for
|
||||
incoming connections. Below is just an example of such address. In your case the suffix hash (`peerId`) will be different.
|
||||
|
||||
```bash
|
||||
$ node listener.js
|
||||
Listening on:
|
||||
/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/QmUKQCzEUhhhobcNSrXU5uzxTqbvF1BjMCGNGZzZU14Kgd
|
||||
```
|
||||
|
||||
## 1. Prepare a browser libp2p dialer
|
||||
Confirm that the above address is the same as the field `list` in `public/dialer.js`:
|
||||
```js
|
||||
peerDiscovery: {
|
||||
[Bootstrap.tag]: {
|
||||
enabled: true,
|
||||
// paste the address into `list`
|
||||
list: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/QmUKQCzEUhhhobcNSrXU5uzxTqbvF1BjMCGNGZzZU14Kgd']
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. Run a browser libp2p dialer
|
||||
When in the root folder of this example, type `npm run dev` in terminal. You should see an address where you can browse
|
||||
the running client. Open this address in your browser. In console
|
||||
logs you should see logs about successful connection with the node client. In the output of node client you should see
|
||||
a log message about successful connection as well.
|
@@ -1,57 +0,0 @@
|
||||
import 'babel-polyfill'
|
||||
const Libp2p = require('libp2p')
|
||||
const WebRTCDirect = require('libp2p-webrtc-direct')
|
||||
const Mplex = require('libp2p-mplex')
|
||||
const {NOISE} = require('libp2p-noise')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
// use the same peer id as in `listener.js` to avoid copy-pasting of listener's peer id into `peerDiscovery`
|
||||
const hardcodedPeerId = '12D3KooWCuo3MdXfMgaqpLC5Houi1TRoFqgK9aoxok4NK5udMu8m'
|
||||
const libp2p = await Libp2p.create({
|
||||
modules: {
|
||||
transport: [WebRTCDirect],
|
||||
streamMuxer: [Mplex],
|
||||
connEncryption: [NOISE],
|
||||
peerDiscovery: [Bootstrap]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
[Bootstrap.tag]: {
|
||||
enabled: true,
|
||||
list: [`/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct/p2p/${hardcodedPeerId}`]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const status = document.getElementById('status')
|
||||
const output = document.getElementById('output')
|
||||
|
||||
output.textContent = ''
|
||||
|
||||
function log (txt) {
|
||||
console.info(txt)
|
||||
output.textContent += `${txt.trim()}\n`
|
||||
}
|
||||
|
||||
// Listen for new peers
|
||||
libp2p.on('peer:discovery', (peerId) => {
|
||||
log(`Found peer ${peerId.toB58String()}`)
|
||||
})
|
||||
|
||||
// Listen for new connections to peers
|
||||
libp2p.connectionManager.on('peer:connect', (connection) => {
|
||||
log(`Connected to ${connection.remotePeer.toB58String()}`)
|
||||
})
|
||||
|
||||
// Listen for peers disconnecting
|
||||
libp2p.connectionManager.on('peer:disconnect', (connection) => {
|
||||
log(`Disconnected from ${connection.remotePeer.toB58String()}`)
|
||||
})
|
||||
|
||||
await libp2p.start()
|
||||
status.innerText = 'libp2p started!'
|
||||
log(`libp2p id is ${libp2p.peerId.toB58String()}`)
|
||||
|
||||
})
|
@@ -1,17 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>js-libp2p parcel.js browser example</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1 id="status">Starting libp2p...</h1>
|
||||
</header>
|
||||
<main>
|
||||
<pre id="output"></pre>
|
||||
</main>
|
||||
<script src="./dialer.js"></script>
|
||||
</body>
|
||||
</html>
|
@@ -1,44 +0,0 @@
|
||||
const Libp2p = require('libp2p')
|
||||
const Bootstrap = require('libp2p-bootstrap')
|
||||
const WebRTCDirect = require('libp2p-webrtc-direct')
|
||||
const Mplex = require('libp2p-mplex')
|
||||
const {NOISE} = require('libp2p-noise')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
;(async () => {
|
||||
// hardcoded peer id to avoid copy-pasting of listener's peer id into the dialer's bootstrap list
|
||||
// generated with cmd `peer-id --type=ed25519`
|
||||
const hardcodedPeerId = await PeerId.createFromJSON({
|
||||
"id": "12D3KooWCuo3MdXfMgaqpLC5Houi1TRoFqgK9aoxok4NK5udMu8m",
|
||||
"privKey": "CAESQAG6Ld7ev6nnD0FKPs033/j0eQpjWilhxnzJ2CCTqT0+LfcWoI2Vr+zdc1vwk7XAVdyoCa2nwUR3RJebPWsF1/I=",
|
||||
"pubKey": "CAESIC33FqCNla/s3XNb8JO1wFXcqAmtp8FEd0SXmz1rBdfy"
|
||||
})
|
||||
const node = await Libp2p.create({
|
||||
peerId: hardcodedPeerId,
|
||||
addresses: {
|
||||
listen: ['/ip4/127.0.0.1/tcp/9090/http/p2p-webrtc-direct']
|
||||
},
|
||||
modules: {
|
||||
transport: [WebRTCDirect],
|
||||
streamMuxer: [Mplex],
|
||||
connEncryption: [NOISE]
|
||||
},
|
||||
config: {
|
||||
peerDiscovery: {
|
||||
[Bootstrap.tag]: {
|
||||
enabled: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
node.connectionManager.on('peer:connect', (connection) => {
|
||||
console.info(`Connected to ${connection.remotePeer.toB58String()}!`)
|
||||
})
|
||||
|
||||
await node.start()
|
||||
|
||||
console.log('Listening on:')
|
||||
node.multiaddrs.forEach((ma) => console.log(`${ma.toString()}/p2p/${node.peerId.toB58String()}`))
|
||||
|
||||
})()
|
@@ -1,33 +0,0 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
@@ -1,95 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const path = require('path')
|
||||
const execa = require('execa')
|
||||
const pDefer = require('p-defer')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
const { chromium } = require('playwright');
|
||||
|
||||
function startNode (name, args = []) {
|
||||
return execa('node', [path.join(__dirname, name), ...args], {
|
||||
cwd: path.resolve(__dirname),
|
||||
all: true
|
||||
})
|
||||
}
|
||||
|
||||
function startBrowser (name, args = []) {
|
||||
return execa('parcel', [path.join(__dirname, name), ...args], {
|
||||
preferLocal: true,
|
||||
localDir: __dirname,
|
||||
cwd: __dirname,
|
||||
all: true
|
||||
})
|
||||
}
|
||||
|
||||
async function test () {
|
||||
// Step 1, listener process
|
||||
const listenerProcReady = pDefer()
|
||||
let listenerOutput = ''
|
||||
process.stdout.write('listener.js\n')
|
||||
const listenerProc = startNode('listener.js')
|
||||
|
||||
listenerProc.all.on('data', async (data) => {
|
||||
process.stdout.write(data)
|
||||
listenerOutput += uint8ArrayToString(data)
|
||||
if (listenerOutput.includes('Listening on:') && listenerOutput.includes('12D3KooWCuo3MdXfMgaqpLC5Houi1TRoFqgK9aoxok4NK5udMu8m')) {
|
||||
listenerProcReady.resolve()
|
||||
}
|
||||
})
|
||||
|
||||
await listenerProcReady.promise
|
||||
process.stdout.write('==================================================================\n')
|
||||
|
||||
// Step 2, dialer process
|
||||
process.stdout.write('dialer.js\n')
|
||||
let dialerUrl = ''
|
||||
const dialerProc = startBrowser('index.html')
|
||||
|
||||
dialerProc.all.on('data', async (chunk) => {
|
||||
/**@type {string} */
|
||||
const out = chunk.toString()
|
||||
|
||||
if (out.includes('Server running at')) {
|
||||
dialerUrl = out.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
|
@@ -23,6 +23,7 @@
|
||||
|
||||
"secure channels",
|
||||
["NodeFactoryIo/js-libp2p-noise", "libp2p-noise"],
|
||||
["libp2p/js-libp2p-secio", "libp2p-secio"],
|
||||
|
||||
"stream multiplexers",
|
||||
["libp2p/js-libp2p-mplex", "libp2p-mplex"],
|
||||
|
215
package.json
215
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "libp2p",
|
||||
"version": "0.31.3",
|
||||
"version": "0.30.0-rc.0",
|
||||
"description": "JavaScript implementation of libp2p, a modular peer to peer network stack",
|
||||
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||
"main": "src/index.js",
|
||||
@@ -20,28 +20,10 @@
|
||||
"scripts": {
|
||||
"lint": "aegir lint",
|
||||
"build": "aegir build",
|
||||
"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": "npm run test:node && npm run test:browser",
|
||||
"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",
|
||||
@@ -65,115 +47,96 @@
|
||||
"homepage": "https://libp2p.io",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"browser": {
|
||||
"@motrix/nat-api": false
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "ipfs",
|
||||
"ignorePatterns": [
|
||||
"!.aegir.js",
|
||||
"test/ts-use"
|
||||
]
|
||||
"node": ">=12.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@motrix/nat-api": "^0.3.1",
|
||||
"abort-controller": "^3.0.0",
|
||||
"aggregate-error": "^3.1.0",
|
||||
"any-signal": "^2.1.1",
|
||||
"bignumber.js": "^9.0.1",
|
||||
"cids": "^1.1.5",
|
||||
"aggregate-error": "^3.0.1",
|
||||
"any-signal": "^1.1.0",
|
||||
"bignumber.js": "^9.0.0",
|
||||
"cids": "^1.0.0",
|
||||
"class-is": "^1.1.0",
|
||||
"debug": "^4.3.1",
|
||||
"err-code": "^3.0.0",
|
||||
"es6-promisify": "^6.1.1",
|
||||
"events": "^3.3.0",
|
||||
"debug": "^4.1.1",
|
||||
"err-code": "^2.0.0",
|
||||
"events": "^3.1.0",
|
||||
"hashlru": "^2.3.0",
|
||||
"interface-datastore": "^4.0.0",
|
||||
"ipfs-utils": "^7.0.0",
|
||||
"it-all": "^1.0.4",
|
||||
"interface-datastore": "^2.0.0",
|
||||
"ipfs-utils": "^5.0.1",
|
||||
"it-all": "^1.0.1",
|
||||
"it-buffer": "^0.1.2",
|
||||
"it-drain": "^1.0.3",
|
||||
"it-filter": "^1.0.1",
|
||||
"it-first": "^1.0.4",
|
||||
"it-handshake": "^2.0.0",
|
||||
"it-length-prefixed": "^5.0.2",
|
||||
"it-map": "^1.0.4",
|
||||
"it-merge": "1.0.0",
|
||||
"it-handshake": "^1.0.1",
|
||||
"it-length-prefixed": "^3.0.1",
|
||||
"it-pipe": "^1.1.0",
|
||||
"it-take": "1.0.0",
|
||||
"libp2p-crypto": "^0.19.4",
|
||||
"libp2p-interfaces": "^0.10.4",
|
||||
"libp2p-utils": "^0.3.1",
|
||||
"mafmt": "^9.0.0",
|
||||
"merge-options": "^3.0.4",
|
||||
"@vascosantos/moving-average": "^1.1.0",
|
||||
"multiaddr": "^9.0.1",
|
||||
"multicodec": "^3.0.1",
|
||||
"multihashing-async": "^2.1.2",
|
||||
"multistream-select": "^2.0.0",
|
||||
"it-protocol-buffers": "^0.2.0",
|
||||
"libp2p-crypto": "^0.18.0",
|
||||
"libp2p-interfaces": "^0.8.0",
|
||||
"libp2p-utils": "^0.2.2",
|
||||
"mafmt": "^8.0.0",
|
||||
"merge-options": "^2.0.0",
|
||||
"moving-average": "^1.0.0",
|
||||
"multiaddr": "^8.1.0",
|
||||
"multicodec": "^2.0.0",
|
||||
"multihashing-async": "^2.0.1",
|
||||
"multistream-select": "^1.0.0",
|
||||
"mutable-proxy": "^1.0.0",
|
||||
"node-forge": "^0.10.0",
|
||||
"node-forge": "^0.9.1",
|
||||
"p-any": "^3.0.0",
|
||||
"p-fifo": "^1.0.0",
|
||||
"p-retry": "^4.4.0",
|
||||
"p-settle": "^4.1.1",
|
||||
"p-settle": "^4.0.1",
|
||||
"peer-id": "^0.14.2",
|
||||
"private-ip": "^2.1.0",
|
||||
"protobufjs": "^6.10.2",
|
||||
"retimer": "^3.0.0",
|
||||
"protons": "^2.0.0",
|
||||
"retimer": "^2.0.0",
|
||||
"sanitize-filename": "^1.6.3",
|
||||
"set-delayed-interval": "^1.0.0",
|
||||
"streaming-iterables": "^5.0.2",
|
||||
"timeout-abort-controller": "^1.1.1",
|
||||
"varint": "^6.0.0",
|
||||
"xsalsa20": "^1.1.0"
|
||||
"varint": "^5.0.0",
|
||||
"xsalsa20": "^1.0.2"
|
||||
},
|
||||
"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": "^33.1.1",
|
||||
"buffer": "^6.0.3",
|
||||
"delay": "^5.0.0",
|
||||
"aegir": "^29.2.0",
|
||||
"chai-bytes": "^0.1.2",
|
||||
"chai-string": "^1.5.0",
|
||||
"delay": "^4.3.0",
|
||||
"interop-libp2p": "^0.3.0",
|
||||
"into-stream": "^6.0.0",
|
||||
"ipfs-http-client": "^49.0.4",
|
||||
"ipfs-http-client": "^47.0.1",
|
||||
"it-concat": "^1.0.0",
|
||||
"it-pair": "^1.0.0",
|
||||
"it-pushable": "^1.4.0",
|
||||
"libp2p": ".",
|
||||
"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.9.0",
|
||||
"libp2p-kad-dht": "^0.22.0",
|
||||
"libp2p-mdns": "^0.16.0",
|
||||
"libp2p-bootstrap": "^0.12.0",
|
||||
"libp2p-delegated-content-routing": "^0.8.0",
|
||||
"libp2p-delegated-peer-routing": "^0.8.0",
|
||||
"libp2p-floodsub": "^0.24.0",
|
||||
"libp2p-gossipsub": "^0.7.0",
|
||||
"libp2p-kad-dht": "^0.20.0",
|
||||
"libp2p-mdns": "^0.15.0",
|
||||
"libp2p-mplex": "^0.10.1",
|
||||
"libp2p-noise": "^3.0.0",
|
||||
"libp2p-tcp": "^0.15.4",
|
||||
"libp2p-webrtc-star": "^0.22.2",
|
||||
"libp2p-websockets": "^0.15.6",
|
||||
"multihashes": "^4.0.2",
|
||||
"libp2p-noise": "^2.0.0",
|
||||
"libp2p-secio": "^0.13.1",
|
||||
"libp2p-tcp": "^0.15.1",
|
||||
"libp2p-webrtc-star": "^0.20.0",
|
||||
"libp2p-websockets": "^0.15.0",
|
||||
"multihashes": "^3.0.1",
|
||||
"nock": "^13.0.3",
|
||||
"p-defer": "^3.0.0",
|
||||
"p-times": "^3.0.0",
|
||||
"p-wait-for": "^3.2.0",
|
||||
"p-wait-for": "^3.1.0",
|
||||
"promisify-es6": "^1.0.3",
|
||||
"rimraf": "^3.0.2",
|
||||
"sinon": "^10.0.0",
|
||||
"uint8arrays": "^2.1.3",
|
||||
"util": "^0.12.3"
|
||||
"sinon": "^9.0.2",
|
||||
"uint8arrays": "^1.1.0"
|
||||
},
|
||||
"contributors": [
|
||||
"David Dias <daviddias.p@gmail.com>",
|
||||
"Vasco Santos <vasco.santos@moxy.studio>",
|
||||
"Jacob Heun <jacobheun@gmail.com>",
|
||||
"Alex Potsides <alex@achingbrain.net>",
|
||||
"Vasco Santos <vasco.santos@moxy.studio>",
|
||||
"Alan Shaw <alan@tableflip.io>",
|
||||
"Alex Potsides <alex@achingbrain.net>",
|
||||
"Cayman <caymannava@gmail.com>",
|
||||
"Pedro Teixeira <i@pgte.me>",
|
||||
"Friedel Ziegelmayer <dignifiedquire@gmail.com>",
|
||||
@@ -184,45 +147,39 @@
|
||||
"Richard Littauer <richard.littauer@gmail.com>",
|
||||
"a1300 <matthias-knopp@gmx.net>",
|
||||
"Elven <mon.samuel@qq.com>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
||||
"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>",
|
||||
"Giovanni T. Parra <fiatjaf@gmail.com>",
|
||||
"Ryan Bell <ryan@piing.net>",
|
||||
"Thomas Eizinger <thomas@eizinger.io>",
|
||||
"ᴠɪᴄᴛᴏʀ ʙᴊᴇʟᴋʜᴏʟᴍ <victorbjelkholm@gmail.com>",
|
||||
"Didrik Nordström <didrik@betamos.se>",
|
||||
"Irakli Gozalishvili <rfobic@gmail.com>",
|
||||
"Ethan Lam <elmemphis2000@gmail.com>",
|
||||
"Joel Gustafson <joelg@mit.edu>",
|
||||
"Julien Bouquillon <contact@revolunet.com>",
|
||||
"Kevin Kwok <antimatter15@gmail.com>",
|
||||
"Kevin Lacker <lacker@gmail.com>",
|
||||
"Miguel Mota <miguelmota2@gmail.com>"
|
||||
"Nuno Nogueira <nunofmn@gmail.com>",
|
||||
"Dmitriy Ryajov <dryajov@gmail.com>",
|
||||
"RasmusErik Voel Jensen <github@solsort.com>",
|
||||
"Diogo Silva <fsdiogo@gmail.com>",
|
||||
"Samlior <samlior@foxmail.com>",
|
||||
"Smite Chow <xiaopengyou@live.com>",
|
||||
"Soeren <nikorpoulsen@gmail.com>",
|
||||
"Sönke Hahn <soenkehahn@gmail.com>",
|
||||
"robertkiel <robert.kiel@validitylabs.org>",
|
||||
"Tiago Alves <alvesjtiago@gmail.com>",
|
||||
"Daijiro Wachi <daijiro.wachi@gmail.com>",
|
||||
"Yusef Napora <yusef@napora.org>",
|
||||
"Zane Starr <zcstarr@gmail.com>",
|
||||
"Cindy Wu <ciindy.wu@gmail.com>",
|
||||
"Chris Bratlien <chrisbratlien@gmail.com>",
|
||||
"ebinks <elizabethjbinks@gmail.com>",
|
||||
"Bernd Strehl <bernd.strehl@gmail.com>",
|
||||
"Florian-Merle <florian.david.merle@gmail.com>",
|
||||
"Francis Gulotta <wizard@roborooter.com>",
|
||||
"Felipe Martins <felipebrasil93@gmail.com>",
|
||||
"isan_rivkin <isanrivkin@gmail.com>",
|
||||
"Henrique Dias <hacdias@gmail.com>",
|
||||
"Fei Liu <liu.feiwood@gmail.com>"
|
||||
]
|
||||
}
|
||||
|
@@ -1,2 +0,0 @@
|
||||
// @ts-nocheck
|
||||
export const { Buffer } = require('buffer')
|
@@ -1,19 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const PeerId = require('peer-id')
|
||||
const multiaddr = require('multiaddr')
|
||||
|
||||
/**
|
||||
* @typedef {import('multiaddr')} Multiaddr
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} AddressManagerOptions
|
||||
* @property {string[]} [listen = []] - list of multiaddrs string representation to listen.
|
||||
* @property {string[]} [announce = []] - list of multiaddrs string representation to announce.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fires AddressManager#change:addresses Emitted when a addresses change.
|
||||
*/
|
||||
class AddressManager extends EventEmitter {
|
||||
class AddressManager {
|
||||
/**
|
||||
* Responsible for managing the peer addresses.
|
||||
* Peers can specify their listen and announce addresses.
|
||||
@@ -21,18 +19,11 @@ class AddressManager extends EventEmitter {
|
||||
* while the announce addresses will be used for the peer addresses' to other peers in the network.
|
||||
*
|
||||
* @class
|
||||
* @param {PeerId} peerId - The Peer ID of the node
|
||||
* @param {object} [options]
|
||||
* @param {Array<string>} [options.listen = []] - list of multiaddrs string representation to listen.
|
||||
* @param {Array<string>} [options.announce = []] - list of multiaddrs string representation to announce.
|
||||
* @param {AddressManagerOptions} [options]
|
||||
*/
|
||||
constructor (peerId, { listen = [], announce = [] } = {}) {
|
||||
super()
|
||||
|
||||
this.peerId = peerId
|
||||
this.listen = new Set(listen.map(ma => ma.toString()))
|
||||
this.announce = new Set(announce.map(ma => ma.toString()))
|
||||
this.observed = new Set()
|
||||
constructor ({ listen = [], announce = [] } = {}) {
|
||||
this.listen = new Set(listen)
|
||||
this.announce = new Set(announce)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +32,7 @@ class AddressManager extends EventEmitter {
|
||||
* @returns {Multiaddr[]}
|
||||
*/
|
||||
getListenAddrs () {
|
||||
return Array.from(this.listen).map((a) => new Multiaddr(a))
|
||||
return Array.from(this.listen).map((a) => multiaddr(a))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -50,46 +41,7 @@ class AddressManager extends EventEmitter {
|
||||
* @returns {Multiaddr[]}
|
||||
*/
|
||||
getAnnounceAddrs () {
|
||||
return Array.from(this.announce).map((a) => new Multiaddr(a))
|
||||
}
|
||||
|
||||
/**
|
||||
* Get observed multiaddrs.
|
||||
*
|
||||
* @returns {Array<Multiaddr>}
|
||||
*/
|
||||
getObservedAddrs () {
|
||||
return Array.from(this.observed).map((a) => new Multiaddr(a))
|
||||
}
|
||||
|
||||
/**
|
||||
* Add peer observed addresses
|
||||
*
|
||||
* @param {string | Multiaddr} addr
|
||||
*/
|
||||
addObservedAddr (addr) {
|
||||
let ma = new Multiaddr(addr)
|
||||
const remotePeer = ma.getPeerId()
|
||||
|
||||
// strip our peer id if it has been passed
|
||||
if (remotePeer) {
|
||||
const remotePeerId = PeerId.createFromB58String(remotePeer)
|
||||
|
||||
// use same encoding for comparison
|
||||
if (remotePeerId.equals(this.peerId)) {
|
||||
ma = ma.decapsulate(new Multiaddr(`/p2p/${this.peerId}`))
|
||||
}
|
||||
}
|
||||
|
||||
const addrString = ma.toString()
|
||||
|
||||
// do not trigger the change:addresses event if we already know about this address
|
||||
if (this.observed.has(addrString)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.observed.add(addrString)
|
||||
this.emit('change:addresses')
|
||||
return Array.from(this.announce).map((a) => multiaddr(a))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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: [new Multiaddr(`${relayAddr}/p2p-circuit`)]
|
||||
listen: [multiaddr(`${relayAddr}/p2p-circuit`)]
|
||||
},
|
||||
modules: {
|
||||
transport: [TCP],
|
||||
|
@@ -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,7 +31,6 @@ const {
|
||||
*
|
||||
* @typedef {Object} AutoRelayOptions
|
||||
* @property {number} [maxListeners = 1] - maximum number of relays to listen.
|
||||
* @property {(error: Error, msg?: string) => {}} [onError]
|
||||
*/
|
||||
|
||||
class AutoRelay {
|
||||
@@ -41,7 +40,7 @@ class AutoRelay {
|
||||
* @class
|
||||
* @param {AutoRelayProperties & AutoRelayOptions} props
|
||||
*/
|
||||
constructor ({ libp2p, maxListeners = 1, onError }) {
|
||||
constructor ({ libp2p, maxListeners = 1 }) {
|
||||
this._libp2p = libp2p
|
||||
this._peerId = libp2p.peerId
|
||||
this._peerStore = libp2p.peerStore
|
||||
@@ -61,15 +60,6 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +107,7 @@ class AutoRelay {
|
||||
await this._addListenRelay(connection, id)
|
||||
}
|
||||
} catch (err) {
|
||||
this._onError(err)
|
||||
log.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,10 +157,10 @@ class AutoRelay {
|
||||
|
||||
// Attempt to listen on relay
|
||||
try {
|
||||
await this._transportManager.listen([new Multiaddr(listenAddr)])
|
||||
await this._transportManager.listen([multiaddr(listenAddr)])
|
||||
// Announce multiaddrs will update on listen success by TransportManager event being triggered
|
||||
} catch (err) {
|
||||
this._onError(err)
|
||||
log.error(err)
|
||||
this._listenRelays.delete(id)
|
||||
}
|
||||
}
|
||||
@@ -241,7 +231,8 @@ class AutoRelay {
|
||||
|
||||
// Try to listen on known peers that are not connected
|
||||
for (const peerId of knownHopsToDial) {
|
||||
await this._tryToListenOnRelay(peerId)
|
||||
const connection = await this._libp2p.dial(peerId)
|
||||
await this._addListenRelay(connection, peerId.toB58String())
|
||||
|
||||
// Check if already listening on enough relays
|
||||
if (this._listenRelays.size >= this.maxListeners) {
|
||||
@@ -256,11 +247,12 @@ class AutoRelay {
|
||||
if (!provider.multiaddrs.length) {
|
||||
continue
|
||||
}
|
||||
|
||||
const peerId = provider.id
|
||||
this._peerStore.addressBook.add(peerId, provider.multiaddrs)
|
||||
|
||||
await this._tryToListenOnRelay(peerId)
|
||||
this._peerStore.addressBook.add(peerId, provider.multiaddrs)
|
||||
const connection = await this._libp2p.dial(peerId)
|
||||
|
||||
await this._addListenRelay(connection, peerId.toB58String())
|
||||
|
||||
// Check if already listening on enough relays
|
||||
if (this._listenRelays.size >= this.maxListeners) {
|
||||
@@ -268,19 +260,7 @@ class AutoRelay {
|
||||
}
|
||||
}
|
||||
} catch (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()}`)
|
||||
log.error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -18,17 +18,17 @@ const { stop } = require('./stop')
|
||||
const multicodec = require('./../multicodec')
|
||||
|
||||
/**
|
||||
* @typedef {import('../protocol').ICircuitRelay} ICircuitRelay
|
||||
* @typedef {import('../../types').CircuitRequest} CircuitRequest
|
||||
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
||||
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
|
||||
* @typedef {import('./stream-handler')<CircuitRequest>} StreamHandlerT
|
||||
* @typedef {import('../transport')} Transport
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} HopRequest
|
||||
* @property {Connection} connection
|
||||
* @property {ICircuitRelay} request
|
||||
* @property {StreamHandler} streamHandler
|
||||
* @property {CircuitRequest} request
|
||||
* @property {StreamHandlerT} streamHandler
|
||||
* @property {Transport} circuit
|
||||
*/
|
||||
|
||||
@@ -58,11 +58,6 @@ 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)
|
||||
|
||||
@@ -118,8 +113,8 @@ async function handleHop ({
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {Connection} options.connection - Connection to the relay
|
||||
* @param {ICircuitRelay} options.request
|
||||
* @returns {Promise<MuxedStream>}
|
||||
* @param {CircuitRequest} options.request
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
async function hop ({
|
||||
connection,
|
||||
@@ -133,10 +128,6 @@ 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()
|
||||
@@ -168,7 +159,7 @@ async function canHop ({
|
||||
const response = await streamHandler.read()
|
||||
await streamHandler.close()
|
||||
|
||||
if (!response || response.code !== CircuitPB.Status.SUCCESS) {
|
||||
if (response.code !== CircuitPB.Status.SUCCESS) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -180,7 +171,7 @@ async function canHop ({
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {Connection} options.connection
|
||||
* @param {StreamHandler} options.streamHandler
|
||||
* @param {StreamHandlerT} options.streamHandler
|
||||
* @param {Transport} options.circuit
|
||||
* @private
|
||||
*/
|
||||
|
@@ -13,7 +13,8 @@ const { validateAddrs } = require('./utils')
|
||||
/**
|
||||
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
||||
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
|
||||
* @typedef {import('../protocol').ICircuitRelay} ICircuitRelay
|
||||
* @typedef {import('../../types').CircuitRequest} CircuitRequest
|
||||
* @typedef {import('./stream-handler')<CircuitRequest>} StreamHandlerT
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -22,8 +23,8 @@ const { validateAddrs } = require('./utils')
|
||||
* @private
|
||||
* @param {Object} options
|
||||
* @param {Connection} options.connection
|
||||
* @param {ICircuitRelay} options.request - The CircuitRelay protobuf request (unencoded)
|
||||
* @param {StreamHandler} options.streamHandler
|
||||
* @param {CircuitRequest} options.request - The CircuitRelay protobuf request (unencoded)
|
||||
* @param {StreamHandlerT} options.streamHandler
|
||||
* @returns {Promise<MuxedStream>|void} Resolves a duplex iterable
|
||||
*/
|
||||
module.exports.handleStop = function handleStop ({
|
||||
@@ -53,7 +54,7 @@ module.exports.handleStop = function handleStop ({
|
||||
* @private
|
||||
* @param {Object} options
|
||||
* @param {Connection} options.connection
|
||||
* @param {ICircuitRelay} options.request - The CircuitRelay protobuf request (unencoded)
|
||||
* @param {CircuitRequest} options.request - The CircuitRelay protobuf request (unencoded)
|
||||
* @returns {Promise<MuxedStream|void>} Resolves a duplex iterable
|
||||
*/
|
||||
module.exports.stop = async function stop ({
|
||||
@@ -67,10 +68,6 @@ 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()
|
||||
|
@@ -6,15 +6,16 @@ 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 } = require('../protocol')
|
||||
const { CircuitRelay: CircuitPB } = 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
|
||||
@@ -28,7 +29,6 @@ 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,11 +36,12 @@ class StreamHandler {
|
||||
* Read and decode message
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<T|undefined>}
|
||||
*/
|
||||
async read () {
|
||||
const msg = await this.decoder.next()
|
||||
if (msg.value) {
|
||||
const value = CircuitRelay.decode(msg.value.slice())
|
||||
const value = CircuitPB.decode(msg.value.slice())
|
||||
log('read message type', value.type)
|
||||
return value
|
||||
}
|
||||
@@ -53,13 +54,13 @@ class StreamHandler {
|
||||
/**
|
||||
* Encode and write array of buffers
|
||||
*
|
||||
* @param {ICircuitRelay} msg - An unencoded CircuitRelay protobuf message
|
||||
* @param {CircuitPB} 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(CircuitRelay.encode(msg).finish()))
|
||||
this.shake.write(lp.encode.single(CircuitPB.encode(msg)))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,9 +73,6 @@ class StreamHandler {
|
||||
return this.shake.stream
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ICircuitRelay} msg - An unencoded CircuitRelay protobuf message
|
||||
*/
|
||||
end (msg) {
|
||||
this.write(msg)
|
||||
this.close()
|
||||
|
@@ -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('../protocol').ICircuitRelay} ICircuitRelay
|
||||
* @typedef {import('../../types').CircuitStatus} CircuitStatus
|
||||
*/
|
||||
|
||||
/**
|
||||
* Write a response
|
||||
*
|
||||
* @param {StreamHandler} streamHandler
|
||||
* @param {import('../protocol').CircuitRelay.Status} status
|
||||
* @param {CircuitStatus} status
|
||||
*/
|
||||
function writeResponse (streamHandler, status) {
|
||||
streamHandler.write({
|
||||
@@ -24,16 +24,14 @@ function writeResponse (streamHandler, status) {
|
||||
/**
|
||||
* Validate incomming HOP/STOP message
|
||||
*
|
||||
* @param {ICircuitRelay} msg - A CircuitRelay unencoded protobuf message
|
||||
* @param {*} msg - A CircuitRelay unencoded protobuf message
|
||||
* @param {StreamHandler} streamHandler
|
||||
*/
|
||||
function validateAddrs (msg, streamHandler) {
|
||||
try {
|
||||
if (msg.dstPeer && msg.dstPeer.addrs) {
|
||||
msg.dstPeer.addrs.forEach((addr) => {
|
||||
return new Multiaddr(addr)
|
||||
})
|
||||
}
|
||||
msg.dstPeer.addrs.forEach((addr) => {
|
||||
return multiaddr(addr)
|
||||
})
|
||||
} catch (err) {
|
||||
writeResponse(streamHandler, msg.type === CircuitRelay.Type.HOP
|
||||
? CircuitRelay.Status.HOP_DST_MULTIADDR_INVALID
|
||||
@@ -42,11 +40,9 @@ function validateAddrs (msg, streamHandler) {
|
||||
}
|
||||
|
||||
try {
|
||||
if (msg.srcPeer && msg.srcPeer.addrs) {
|
||||
msg.srcPeer.addrs.forEach((addr) => {
|
||||
return new Multiaddr(addr)
|
||||
})
|
||||
}
|
||||
msg.srcPeer.addrs.forEach((addr) => {
|
||||
return multiaddr(addr)
|
||||
})
|
||||
} catch (err) {
|
||||
writeResponse(streamHandler, msg.type === CircuitRelay.Type.HOP
|
||||
? CircuitRelay.Status.HOP_SRC_MULTIADDR_INVALID
|
||||
|
@@ -8,12 +8,13 @@ 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')
|
||||
|
||||
@@ -44,6 +45,12 @@ 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
|
||||
}
|
||||
|
||||
|
@@ -1,9 +1,10 @@
|
||||
'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
|
||||
*/
|
||||
|
||||
@@ -23,7 +24,7 @@ module.exports = (libp2p) => {
|
||||
async function listen (addr) {
|
||||
const addrString = String(addr).split('/p2p-circuit').find(a => a !== '')
|
||||
|
||||
const relayConn = await libp2p.dial(new Multiaddr(addrString))
|
||||
const relayConn = await libp2p.dial(multiaddr(addrString))
|
||||
const relayedAddr = relayConn.remoteAddr.encapsulate('/p2p-circuit')
|
||||
|
||||
listeningAddrs.set(relayConn.remotePeer.toB58String(), relayedAddr)
|
||||
|
173
src/circuit/protocol/index.d.ts
vendored
173
src/circuit/protocol/index.d.ts
vendored
@@ -1,173 +0,0 @@
|
||||
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 };
|
||||
}
|
||||
}
|
@@ -1,530 +1,46 @@
|
||||
/*eslint-disable*/
|
||||
"use strict";
|
||||
'use strict'
|
||||
const protobuf = require('protons')
|
||||
|
||||
var $protobuf = require("protobufjs/minimal");
|
||||
/** @type {{CircuitRelay: import('../../types').CircuitMessageProto}} */
|
||||
module.exports = protobuf(`
|
||||
message CircuitRelay {
|
||||
|
||||
// Common aliases
|
||||
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
|
||||
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;
|
||||
}
|
||||
|
||||
// Exported root namespace
|
||||
var $root = $protobuf.roots["libp2p-circuit"] || ($protobuf.roots["libp2p-circuit"] = {});
|
||||
enum Type { // RPC identifier, either HOP, STOP or STATUS
|
||||
HOP = 1;
|
||||
STOP = 2;
|
||||
STATUS = 3;
|
||||
CAN_HOP = 4;
|
||||
}
|
||||
|
||||
$root.CircuitRelay = (function() {
|
||||
message Peer {
|
||||
required bytes id = 1; // peer id
|
||||
repeated bytes addrs = 2; // peer's known addresses
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 Type type = 1; // Type of the message
|
||||
|
||||
/**
|
||||
* 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 Peer srcPeer = 2; // srcPeer and dstPeer are used when Type is HOP or STATUS
|
||||
optional Peer dstPeer = 3;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
optional Status code = 4; // Status code, used when Type is STATUS
|
||||
}
|
||||
`)
|
||||
|
@@ -1,42 +0,0 @@
|
||||
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
|
||||
}
|
@@ -5,12 +5,10 @@ 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')
|
||||
|
||||
@@ -23,8 +21,10 @@ 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')} */
|
||||
/** @type {import('./circuit/stream-handler')<CircuitRequest>} */
|
||||
const streamHandler = new StreamHandler({ stream })
|
||||
const request = await streamHandler.read()
|
||||
|
||||
@@ -96,10 +96,8 @@ class Circuit {
|
||||
}
|
||||
|
||||
if (virtualConnection) {
|
||||
// @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 remoteAddr = multiaddr(request.dstPeer.addrs[0])
|
||||
const localAddr = multiaddr(request.srcPeer.addrs[0])
|
||||
const maConn = toConnection({
|
||||
stream: virtualConnection,
|
||||
remoteAddr,
|
||||
@@ -125,19 +123,10 @@ 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 = 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)
|
||||
const relayAddr = multiaddr(addrs[0])
|
||||
const destinationAddr = multiaddr(addrs[addrs.length - 1])
|
||||
const relayPeer = PeerId.createFromCID(relayAddr.getPeerId())
|
||||
const destinationPeer = PeerId.createFromCID(destinationAddr.getPeerId())
|
||||
|
||||
let disconnectOnFailure = false
|
||||
let relayConnection = this._connectionManager.get(relayPeer)
|
||||
@@ -157,7 +146,7 @@ class Circuit {
|
||||
},
|
||||
dstPeer: {
|
||||
id: destinationPeer.toBytes(),
|
||||
addrs: [new Multiaddr(destinationAddr).bytes]
|
||||
addrs: [multiaddr(destinationAddr).bytes]
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@@ -12,7 +12,7 @@ const TextEncoder = require('ipfs-utils/src/text-encoder')
|
||||
* @returns {Promise<CID>}
|
||||
*/
|
||||
module.exports.namespaceToCid = async (namespace) => {
|
||||
const bytes = new TextEncoder().encode(namespace)
|
||||
const bytes = new TextEncoder('utf8').encode(namespace)
|
||||
const hash = await multihashing(bytes, 'sha2-256')
|
||||
|
||||
return new CID(hash)
|
||||
|
@@ -1,7 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
const mergeOptions = require('merge-options')
|
||||
// @ts-ignore no types in multiaddr path
|
||||
const { dnsaddrResolver } = require('multiaddr/src/resolvers')
|
||||
|
||||
const Constants = require('./constants')
|
||||
@@ -11,18 +10,11 @@ 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: [],
|
||||
announceFilter: (/** @type {Multiaddr[]} */ multiaddrs) => multiaddrs
|
||||
noAnnounce: []
|
||||
},
|
||||
connectionManager: {
|
||||
minConnections: 25
|
||||
@@ -67,16 +59,6 @@ const DefaultConfig = {
|
||||
timeout: 10e3
|
||||
}
|
||||
},
|
||||
nat: {
|
||||
enabled: true,
|
||||
ttl: 7200,
|
||||
keepAlive: true,
|
||||
gateway: null,
|
||||
externalIp: null,
|
||||
pmp: {
|
||||
enabled: false
|
||||
}
|
||||
},
|
||||
peerDiscovery: {
|
||||
autoDial: true
|
||||
},
|
||||
@@ -103,15 +85,10 @@ const DefaultConfig = {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Libp2pOptions} opts
|
||||
* @returns {DefaultConfig & Libp2pOptions & constructorOptions}
|
||||
*/
|
||||
module.exports.validate = (opts) => {
|
||||
/** @type {DefaultConfig & Libp2pOptions & constructorOptions} */
|
||||
const resultingOptions = mergeOptions(DefaultConfig, opts)
|
||||
opts = mergeOptions(DefaultConfig, opts)
|
||||
|
||||
if (resultingOptions.modules.transport.length < 1) throw new Error("'options.modules.transport' must contain at least 1 transport")
|
||||
if (opts.modules.transport.length < 1) throw new Error("'options.modules.transport' must contain at least 1 transport")
|
||||
|
||||
return resultingOptions
|
||||
return opts
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@ 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')
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
@@ -159,7 +158,7 @@ class ConnectionManager extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(tasks)
|
||||
await tasks
|
||||
this.connections.clear()
|
||||
}
|
||||
|
||||
@@ -187,10 +186,8 @@ 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
|
||||
@@ -363,7 +360,7 @@ class ConnectionManager extends EventEmitter {
|
||||
*/
|
||||
_maybeDisconnectOne () {
|
||||
if (this._options.minConnections < this.connections.size) {
|
||||
const peerValues = Array.from(new Map([...this._peerValues.entries()].sort((a, b) => a[1] - b[1])))
|
||||
const peerValues = Array.from(this._peerValues).sort(byPeerValue)
|
||||
log('%s: sorted peer values: %j', this._peerId, peerValues)
|
||||
const disconnectPeer = peerValues[0]
|
||||
if (disconnectPeer) {
|
||||
@@ -382,3 +379,7 @@ class ConnectionManager extends EventEmitter {
|
||||
}
|
||||
|
||||
module.exports = ConnectionManager
|
||||
|
||||
function byPeerValue (peerValueEntryA, peerValueEntryB) {
|
||||
return peerValueEntryA[1] - peerValueEntryB[1]
|
||||
}
|
||||
|
@@ -5,6 +5,8 @@
|
||||
* This code is based on `latency-monitor` (https://github.com/mlucool/latency-monitor) by `mlucool` (https://github.com/mlucool), available under Apache License 2.0 (https://github.com/mlucool/latency-monitor/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
/* global window */
|
||||
const globalThis = require('ipfs-utils/src/globalthis')
|
||||
const { EventEmitter } = require('events')
|
||||
const VisibilityChangeEmitter = require('./visibility-change-emitter')
|
||||
const debug = require('debug')('latency-monitor:LatencyMonitor')
|
||||
@@ -57,8 +59,7 @@ 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)
|
||||
@@ -71,9 +72,9 @@ class LatencyMonitor extends EventEmitter {
|
||||
that.asyncTestFn = asyncTestFn // If there is no asyncFn, we measure latency
|
||||
|
||||
// If process: use high resolution timer
|
||||
if (globalThis.process && globalThis.process.hrtime) { // eslint-disable-line no-undef
|
||||
if (globalThis.process && globalThis.process.hrtime) {
|
||||
debug('Using process.hrtime for timing')
|
||||
that.now = globalThis.process.hrtime // eslint-disable-line no-undef
|
||||
that.now = globalThis.process.hrtime
|
||||
that.getDeltaMS = (startTime) => {
|
||||
const hrtime = that.now(startTime)
|
||||
return (hrtime[0] * 1000) + (hrtime[1] / 1000000)
|
||||
@@ -173,8 +174,7 @@ 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)
|
||||
}
|
||||
|
@@ -1,22 +1,15 @@
|
||||
'use strict'
|
||||
|
||||
const errCode = require('err-code')
|
||||
const { messages, codes } = require('../errors')
|
||||
const {
|
||||
storeAddresses,
|
||||
uniquePeers,
|
||||
requirePeers,
|
||||
maybeLimitSource
|
||||
} = require('./utils')
|
||||
const { messages, codes } = require('./errors')
|
||||
|
||||
const merge = require('it-merge')
|
||||
const { pipe } = require('it-pipe')
|
||||
const all = require('it-all')
|
||||
const pAny = require('p-any')
|
||||
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
||||
* @typedef {import('multiaddr')} Multiaddr
|
||||
* @typedef {import('cids')} CID
|
||||
* @typedef {import('libp2p-interfaces/src/content-routing/types').ContentRouting} ContentRoutingModule
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -28,22 +21,22 @@ const { pipe } = require('it-pipe')
|
||||
class ContentRouting {
|
||||
/**
|
||||
* @class
|
||||
* @param {import('..')} libp2p
|
||||
* @param {import('./')} libp2p
|
||||
*/
|
||||
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 && libp2p._config.dht.enabled) {
|
||||
this.routers.push(this.dht)
|
||||
// If we have the dht, make it first
|
||||
if (this.dht) {
|
||||
this.routers.unshift(this.dht)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all content routers in parallel to find providers of the given key.
|
||||
* Iterates over all content routers in series to find providers of the given key.
|
||||
* Once a content router succeeds, iteration will stop.
|
||||
*
|
||||
* @param {CID} key - The CID key of the content to find
|
||||
* @param {object} [options]
|
||||
@@ -51,20 +44,25 @@ class ContentRouting {
|
||||
* @param {number} [options.maxNumProviders] - maximum number of providers to find
|
||||
* @returns {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>}
|
||||
*/
|
||||
async * findProviders (key, options = {}) {
|
||||
async * findProviders (key, options) {
|
||||
if (!this.routers.length) {
|
||||
throw errCode(new Error('No content this.routers available'), 'NO_ROUTERS_AVAILABLE')
|
||||
}
|
||||
|
||||
yield * pipe(
|
||||
merge(
|
||||
...this.routers.map(router => router.findProviders(key, options))
|
||||
),
|
||||
(source) => storeAddresses(source, this.libp2p.peerStore),
|
||||
(source) => uniquePeers(source),
|
||||
(source) => maybeLimitSource(source, options.maxNumProviders),
|
||||
(source) => requirePeers(source)
|
||||
const result = await pAny(
|
||||
this.routers.map(async (router) => {
|
||||
const provs = await all(router.findProviders(key, options))
|
||||
|
||||
if (!provs || !provs.length) {
|
||||
throw errCode(new Error('not found'), 'NOT_FOUND')
|
||||
}
|
||||
return provs
|
||||
})
|
||||
)
|
||||
|
||||
for (const peer of result) {
|
||||
yield peer
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
@@ -1,89 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const errCode = require('err-code')
|
||||
const filter = require('it-filter')
|
||||
const map = require('it-map')
|
||||
const take = require('it-take')
|
||||
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
||||
*/
|
||||
|
||||
/**
|
||||
* Store the multiaddrs from every peer in the passed peer store
|
||||
*
|
||||
* @param {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>} source
|
||||
* @param {import('../peer-store')} peerStore
|
||||
*/
|
||||
function storeAddresses (source, peerStore) {
|
||||
return map(source, (peer) => {
|
||||
// ensure we have the addresses for a given peer
|
||||
peerStore.addressBook.add(peer.id, peer.multiaddrs)
|
||||
|
||||
return peer
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter peers by unique peer id
|
||||
*
|
||||
* @param {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>} source
|
||||
*/
|
||||
function uniquePeers (source) {
|
||||
/** @type Set<string> */
|
||||
const seen = new Set()
|
||||
|
||||
return filter(source, (peer) => {
|
||||
// dedupe by peer id
|
||||
if (seen.has(peer.id.toString())) {
|
||||
return false
|
||||
}
|
||||
|
||||
seen.add(peer.id.toString())
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Require at least `min` peers to be yielded from `source`
|
||||
*
|
||||
* @param {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>} source
|
||||
* @param {number} min
|
||||
*/
|
||||
async function * requirePeers (source, min = 1) {
|
||||
let seen = 0
|
||||
|
||||
for await (const peer of source) {
|
||||
seen++
|
||||
|
||||
yield peer
|
||||
}
|
||||
|
||||
if (seen < min) {
|
||||
throw errCode(new Error('not found'), 'NOT_FOUND')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If `max` is passed, only take that number of peers from the source
|
||||
* otherwise take all the peers
|
||||
*
|
||||
* @param {AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>} source
|
||||
* @param {number} [max]
|
||||
*/
|
||||
function maybeLimitSource (source, max) {
|
||||
if (max) {
|
||||
return take(source, max)
|
||||
}
|
||||
|
||||
return source
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
storeAddresses,
|
||||
uniquePeers,
|
||||
requirePeers,
|
||||
maybeLimitSource
|
||||
}
|
@@ -2,15 +2,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 anySignal = require('any-signal')
|
||||
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} Multiaddr
|
||||
* @typedef {import('multiaddr')} Multiaddr
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -68,7 +67,7 @@ class DialRequest {
|
||||
let conn
|
||||
try {
|
||||
const signal = dialAbortControllers[i].signal
|
||||
conn = await this.dialAction(addr, { ...options, signal: options.signal ? anySignal([signal, options.signal]) : signal })
|
||||
conn = await this.dialAction(addr, { ...options, signal: anySignal([signal, options.signal]) })
|
||||
// Remove the successful AbortController so it is not aborted
|
||||
dialAbortControllers.splice(i, 1)
|
||||
} finally {
|
||||
|
@@ -5,10 +5,9 @@ const log = Object.assign(debug('libp2p:dialer'), {
|
||||
error: debug('libp2p:dialer:err')
|
||||
})
|
||||
const errCode = require('err-code')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
// @ts-ignore timeout-abourt-controles does not export types
|
||||
const multiaddr = require('multiaddr')
|
||||
const TimeoutController = require('timeout-abort-controller')
|
||||
const { anySignal } = require('any-signal')
|
||||
const anySignal = require('any-signal')
|
||||
|
||||
const DialRequest = require('./dial-request')
|
||||
const { publicAddressesFirst } = require('libp2p-utils/src/address-sort')
|
||||
@@ -23,6 +22,7 @@ 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} [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 {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 {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<Connection>} promise
|
||||
* @property {Promise} promise
|
||||
* @property {function():void} destroy
|
||||
*/
|
||||
|
||||
@@ -63,22 +63,22 @@ class Dialer {
|
||||
transportManager,
|
||||
peerStore,
|
||||
addressSorter = publicAddressesFirst,
|
||||
maxParallelDials = MAX_PARALLEL_DIALS,
|
||||
dialTimeout = DIAL_TIMEOUT,
|
||||
maxDialsPerPeer = MAX_PER_PEER_DIALS,
|
||||
concurrency = MAX_PARALLEL_DIALS,
|
||||
timeout = DIAL_TIMEOUT,
|
||||
perPeerLimit = MAX_PER_PEER_DIALS,
|
||||
resolvers = {}
|
||||
}) {
|
||||
this.transportManager = transportManager
|
||||
this.peerStore = peerStore
|
||||
this.addressSorter = addressSorter
|
||||
this.maxParallelDials = maxParallelDials
|
||||
this.timeout = dialTimeout
|
||||
this.maxDialsPerPeer = maxDialsPerPeer
|
||||
this.tokens = [...new Array(maxParallelDials)].map((_, index) => index)
|
||||
this.concurrency = concurrency
|
||||
this.timeout = timeout
|
||||
this.perPeerLimit = perPeerLimit
|
||||
this.tokens = [...new Array(concurrency)].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 valid addresses'), codes.ERR_NO_VALID_ADDRESSES)
|
||||
throw errCode(new Error('The dial request has no addresses'), codes.ERR_NO_VALID_ADDRESSES)
|
||||
}
|
||||
const pendingDial = this._pendingDials.get(dialTarget.id) || this._createPendingDial(dialTarget, options)
|
||||
|
||||
@@ -134,7 +134,6 @@ 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
|
||||
@@ -151,24 +150,20 @@ 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: supportedAddrs
|
||||
addrs
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,10 +177,6 @@ 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)
|
||||
@@ -216,19 +207,13 @@ class Dialer {
|
||||
return pendingDial
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} num
|
||||
*/
|
||||
getTokens (num) {
|
||||
const total = Math.min(num, this.maxDialsPerPeer, this.tokens.length)
|
||||
const total = Math.min(num, this.perPeerLimit, 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
|
||||
@@ -274,7 +259,7 @@ class Dialer {
|
||||
*/
|
||||
async _resolveRecord (ma) {
|
||||
try {
|
||||
ma = new Multiaddr(ma.toString()) // Use current multiaddr module
|
||||
ma = multiaddr(ma.toString()) // Use current multiaddr module
|
||||
const multiaddrs = await ma.resolve()
|
||||
return multiaddrs
|
||||
} catch (_) {
|
||||
|
@@ -11,13 +11,11 @@ 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',
|
||||
|
@@ -1,11 +1,15 @@
|
||||
'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.
|
||||
@@ -15,23 +19,14 @@ const { codes } = require('./errors')
|
||||
*/
|
||||
function getPeer (peer) {
|
||||
if (typeof peer === 'string') {
|
||||
peer = new Multiaddr(peer)
|
||||
peer = 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(idStr)
|
||||
peer = PeerId.createFromB58String(peer.getPeerId())
|
||||
} catch (err) {
|
||||
throw errCode(
|
||||
new Error(`${peer} is not a valid peer type`),
|
||||
|
@@ -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')
|
||||
// @ts-ignore it-buffer does not have types
|
||||
const multiaddr = require('multiaddr')
|
||||
const { toBuffer } = require('it-buffer')
|
||||
|
||||
const Message = require('./message')
|
||||
@@ -23,6 +23,7 @@ const PeerRecord = require('../record/peer-record')
|
||||
const {
|
||||
MULTICODEC_IDENTIFY,
|
||||
MULTICODEC_IDENTIFY_PUSH,
|
||||
AGENT_VERSION,
|
||||
PROTOCOL_VERSION
|
||||
} = require('./consts')
|
||||
|
||||
@@ -33,11 +34,6 @@ const { codes } = require('../errors')
|
||||
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} HostProperties
|
||||
* @property {string} agentVersion
|
||||
*/
|
||||
|
||||
class IdentifyService {
|
||||
/**
|
||||
* @class
|
||||
@@ -47,7 +43,6 @@ class IdentifyService {
|
||||
constructor ({ libp2p }) {
|
||||
this._libp2p = libp2p
|
||||
this.peerStore = libp2p.peerStore
|
||||
this.addressManager = libp2p.addressManager
|
||||
this.connectionManager = libp2p.connectionManager
|
||||
this.peerId = libp2p.peerId
|
||||
|
||||
@@ -55,6 +50,7 @@ class IdentifyService {
|
||||
|
||||
// Store self host metadata
|
||||
this._host = {
|
||||
agentVersion: AGENT_VERSION,
|
||||
protocolVersion: PROTOCOL_VERSION,
|
||||
...libp2p._options.host
|
||||
}
|
||||
@@ -97,12 +93,12 @@ class IdentifyService {
|
||||
const { stream } = await connection.newStream(MULTICODEC_IDENTIFY_PUSH)
|
||||
|
||||
await pipe(
|
||||
[Message.Identify.encode({
|
||||
[{
|
||||
listenAddrs,
|
||||
signedPeerRecord,
|
||||
protocols
|
||||
}).finish()],
|
||||
lp.encode(),
|
||||
}],
|
||||
pb.encode(Message),
|
||||
stream,
|
||||
consume
|
||||
)
|
||||
@@ -163,12 +159,12 @@ class IdentifyService {
|
||||
|
||||
let message
|
||||
try {
|
||||
message = Message.Identify.decode(data)
|
||||
message = Message.decode(data)
|
||||
} catch (err) {
|
||||
throw errCode(err, codes.ERR_INVALID_MESSAGE)
|
||||
}
|
||||
|
||||
const {
|
||||
let {
|
||||
publicKey,
|
||||
listenAddrs,
|
||||
protocols,
|
||||
@@ -183,7 +179,7 @@ class IdentifyService {
|
||||
}
|
||||
|
||||
// Get the observedAddr if there is one
|
||||
const cleanObservedAddr = IdentifyService.getCleanMultiaddr(observedAddr)
|
||||
observedAddr = IdentifyService.getCleanMultiaddr(observedAddr)
|
||||
|
||||
try {
|
||||
const envelope = await Envelope.openAndCertify(signedPeerRecord, PeerRecord.DOMAIN)
|
||||
@@ -197,7 +193,7 @@ class IdentifyService {
|
||||
|
||||
// LEGACY: Update peers data in PeerStore
|
||||
try {
|
||||
this.peerStore.addressBook.set(id, listenAddrs.map((addr) => new Multiaddr(addr)))
|
||||
this.peerStore.addressBook.set(id, listenAddrs.map((addr) => multiaddr(addr)))
|
||||
} catch (err) {
|
||||
log.error('received invalid addrs', err)
|
||||
}
|
||||
@@ -205,9 +201,8 @@ class IdentifyService {
|
||||
this.peerStore.protoBook.set(id, protocols)
|
||||
this.peerStore.metadataBook.set(id, 'AgentVersion', uint8ArrayFromString(message.agentVersion))
|
||||
|
||||
// TODO: Add and score our observed addr
|
||||
log('received observed address of %s', cleanObservedAddr)
|
||||
// this.addressManager.addObservedAddr(observedAddr)
|
||||
// TODO: Track our observed address so that we can score it
|
||||
log('received observed address of %s', observedAddr)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -249,7 +244,7 @@ class IdentifyService {
|
||||
const signedPeerRecord = await this.peerStore.addressBook.getRawEnvelope(this.peerId)
|
||||
const protocols = this.peerStore.protoBook.get(this.peerId) || []
|
||||
|
||||
const message = Message.Identify.encode({
|
||||
const message = Message.encode({
|
||||
protocolVersion: this._host.protocolVersion,
|
||||
agentVersion: this._host.agentVersion,
|
||||
publicKey,
|
||||
@@ -257,7 +252,7 @@ class IdentifyService {
|
||||
signedPeerRecord,
|
||||
observedAddr: connection.remoteAddr.bytes,
|
||||
protocols
|
||||
}).finish()
|
||||
})
|
||||
|
||||
try {
|
||||
await pipe(
|
||||
@@ -291,7 +286,7 @@ class IdentifyService {
|
||||
toBuffer,
|
||||
collect
|
||||
)
|
||||
message = Message.Identify.decode(data)
|
||||
message = Message.decode(data)
|
||||
} catch (err) {
|
||||
return log.error('received invalid message', err)
|
||||
}
|
||||
@@ -310,8 +305,7 @@ class IdentifyService {
|
||||
|
||||
// LEGACY: Update peers data in PeerStore
|
||||
try {
|
||||
this.peerStore.addressBook.set(id,
|
||||
message.listenAddrs.map((addr) => new Multiaddr(addr)))
|
||||
this.peerStore.addressBook.set(id, message.listenAddrs.map((addr) => multiaddr(addr)))
|
||||
} catch (err) {
|
||||
log.error('received invalid addrs', err)
|
||||
}
|
||||
@@ -324,12 +318,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 new Multiaddr(addr)
|
||||
return multiaddr(addr)
|
||||
} catch (_) {
|
||||
return null
|
||||
}
|
||||
|
95
src/identify/message.d.ts
vendored
95
src/identify/message.d.ts
vendored
@@ -1,95 +0,0 @@
|
||||
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 };
|
||||
}
|
@@ -1,328 +1,35 @@
|
||||
/*eslint-disable*/
|
||||
"use strict";
|
||||
'use strict'
|
||||
|
||||
var $protobuf = require("protobufjs/minimal");
|
||||
const protons = require('protons')
|
||||
const schema = `
|
||||
message Identify {
|
||||
// protocolVersion determines compatibility between peers
|
||||
optional string protocolVersion = 5; // e.g. ipfs/1.0.0
|
||||
|
||||
// Common aliases
|
||||
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
|
||||
// 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
|
||||
|
||||
// Exported root namespace
|
||||
var $root = $protobuf.roots["libp2p-identify"] || ($protobuf.roots["libp2p-identify"] = {});
|
||||
// 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;
|
||||
|
||||
$root.Identify = (function() {
|
||||
// listenAddrs are the multiaddrs the sender node listens for open connections on
|
||||
repeated bytes listenAddrs = 2;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* 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]];
|
||||
}
|
||||
repeated string protocols = 3;
|
||||
|
||||
/**
|
||||
* Identify protocolVersion.
|
||||
* @member {string} protocolVersion
|
||||
* @memberof Identify
|
||||
* @instance
|
||||
*/
|
||||
Identify.prototype.protocolVersion = "";
|
||||
// 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 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;
|
||||
module.exports = protons(schema).Identify
|
||||
|
@@ -1,30 +0,0 @@
|
||||
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;
|
||||
}
|
177
src/index.js
177
src/index.js
@@ -5,10 +5,10 @@ const log = Object.assign(debug('libp2p'), {
|
||||
error: debug('libp2p:err')
|
||||
})
|
||||
const { EventEmitter } = require('events')
|
||||
const globalThis = require('ipfs-utils/src/globalthis')
|
||||
|
||||
const errCode = require('err-code')
|
||||
const PeerId = require('peer-id')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
|
||||
const PeerRouting = require('./peer-routing')
|
||||
const ContentRouting = require('./content-routing')
|
||||
@@ -32,67 +32,34 @@ const Registrar = require('./registrar')
|
||||
const ping = require('./ping')
|
||||
const IdentifyService = require('./identify')
|
||||
const IDENTIFY_PROTOCOLS = IdentifyService.multicodecs
|
||||
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<any, any>} TransportFactory
|
||||
* @typedef {import('libp2p-interfaces/src/transport/types').TransportFactory} TransportFactory
|
||||
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxerFactory} MuxerFactory
|
||||
* @typedef {import('libp2p-interfaces/src/content-routing/types').ContentRouting} ContentRoutingModule
|
||||
* @typedef {import('libp2p-interfaces/src/peer-discovery/types').PeerDiscoveryFactory} PeerDiscoveryFactory
|
||||
* @typedef {import('libp2p-interfaces/src/peer-routing/types').PeerRouting} 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} PubsubLocalOptions
|
||||
* @property {boolean} enabled
|
||||
*
|
||||
* @typedef {Object} MetricsOptions
|
||||
* @property {boolean} enabled
|
||||
* @typedef {Object} PeerDiscoveryOptions
|
||||
* @property {boolean} autoDial
|
||||
*
|
||||
* @typedef {Object} RelayOptions
|
||||
* @property {boolean} [enabled = true]
|
||||
* @property {import('./circuit').RelayAdvertiseOptions} [advertise]
|
||||
* @property {import('./circuit').HopOptions} [hop]
|
||||
* @property {import('./circuit').AutoRelayOptions} [autoRelay]
|
||||
* @property {boolean} enabled
|
||||
* @property {import('./circuit').RelayAdvertiseOptions} advertise
|
||||
* @property {import('./circuit').HopOptions} hop
|
||||
* @property {import('./circuit').AutoRelayOptions} autoRelay
|
||||
*
|
||||
* @typedef {Object} Libp2pConfig
|
||||
* @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 {Object} [dht] dht module options
|
||||
* @property {PeerDiscoveryOptions} [peerDiscovery]
|
||||
* @property {Pubsub} [pubsub] pubsub module options
|
||||
* @property {RelayOptions} [relay]
|
||||
* @property {Record<string, Object>} [transport] transport options indexed by transport key
|
||||
*
|
||||
@@ -100,32 +67,21 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
||||
* @property {TransportFactory[]} transport
|
||||
* @property {MuxerFactory[]} streamMuxer
|
||||
* @property {Crypto[]} connEncryption
|
||||
* @property {PeerDiscoveryFactory[]} [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('./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('./metrics').MetricsOptions} [metrics]
|
||||
* @property {Object} [keychain]
|
||||
* @property {import('./transport-manager').TransportManagerOptions} [transportManager]
|
||||
* @property {PeerStoreOptions & import('./peer-store/persistent').PersistentPeerStoreOptions} [peerStore]
|
||||
* @property {Libp2pConfig} [config]
|
||||
*
|
||||
* @typedef {Object} constructorOptions
|
||||
* @property {PeerId} peerId
|
||||
*
|
||||
* @typedef {Object} CreateOptions
|
||||
* @property {PeerId} [peerId]
|
||||
* @property {PeerId} peerId
|
||||
*
|
||||
* @extends {EventEmitter}
|
||||
* @fires Libp2p#error Emitted when an error occurs
|
||||
@@ -141,14 +97,12 @@ class Libp2p extends EventEmitter {
|
||||
*/
|
||||
static async create (options) {
|
||||
if (options.peerId) {
|
||||
// @ts-ignore 'Libp2pOptions & CreateOptions' is not assignable to 'Libp2pOptions & constructorOptions'
|
||||
return new Libp2p(options)
|
||||
}
|
||||
|
||||
const peerId = await PeerId.create()
|
||||
|
||||
options.peerId = peerId
|
||||
// @ts-ignore 'Libp2pOptions & CreateOptions' is not assignable to 'Libp2pOptions & constructorOptions'
|
||||
return new Libp2p(options)
|
||||
}
|
||||
|
||||
@@ -156,7 +110,7 @@ class Libp2p extends EventEmitter {
|
||||
* Libp2p node.
|
||||
*
|
||||
* @class
|
||||
* @param {Libp2pOptions & constructorOptions} _options
|
||||
* @param {Libp2pOptions} _options
|
||||
*/
|
||||
constructor (_options) {
|
||||
super()
|
||||
@@ -178,14 +132,7 @@ class Libp2p extends EventEmitter {
|
||||
|
||||
// Addresses {listen, announce, noAnnounce}
|
||||
this.addresses = this._options.addresses
|
||||
this.addressManager = new AddressManager(this.peerId, this._options.addresses)
|
||||
|
||||
// when addresses change, update our peer record
|
||||
this.addressManager.on('change:addresses', () => {
|
||||
updateSelfPeerRecord(this).catch(err => {
|
||||
log.error('Error updating self peer record', err)
|
||||
})
|
||||
})
|
||||
this.addressManager = new AddressManager(this._options.addresses)
|
||||
|
||||
this._modules = this._options.modules
|
||||
this._config = this._options.config
|
||||
@@ -193,6 +140,9 @@ 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
|
||||
@@ -213,6 +163,7 @@ 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
|
||||
})
|
||||
@@ -235,15 +186,6 @@ class Libp2p extends EventEmitter {
|
||||
faultTolerance: this._options.transportManager.faultTolerance
|
||||
})
|
||||
|
||||
// Create the Nat Manager
|
||||
this.natManager = new NatManager({
|
||||
peerId: this.peerId,
|
||||
addressManager: this.addressManager,
|
||||
transportManager: this.transportManager,
|
||||
// @ts-ignore Nat typedef is not understood as Object
|
||||
...this._options.config.nat
|
||||
})
|
||||
|
||||
// Create the Registrar
|
||||
this.registrar = new Registrar({
|
||||
peerStore: this.peerStore,
|
||||
@@ -265,7 +207,11 @@ class Libp2p extends EventEmitter {
|
||||
this.dialer = new Dialer({
|
||||
transportManager: this.transportManager,
|
||||
peerStore: this.peerStore,
|
||||
...this._options.dialer
|
||||
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._modules.transport.forEach((Transport) => {
|
||||
@@ -295,14 +241,13 @@ class Libp2p extends EventEmitter {
|
||||
// Attach private network protector
|
||||
if (this._modules.connProtector) {
|
||||
this.upgrader.protector = this._modules.connProtector
|
||||
} else if (globalThis.process !== undefined && globalThis.process.env && globalThis.process.env.LIBP2P_FORCE_PNET) { // eslint-disable-line no-undef
|
||||
} else if (globalThis.process !== undefined && globalThis.process.env && globalThis.process.env.LIBP2P_FORCE_PNET) {
|
||||
throw new Error('Private network is enforced, but no protector was provided')
|
||||
}
|
||||
|
||||
// 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,
|
||||
@@ -404,7 +349,6 @@ class Libp2p extends EventEmitter {
|
||||
this.metrics && this.metrics.stop()
|
||||
])
|
||||
|
||||
await this.natManager.stop()
|
||||
await this.transportManager.close()
|
||||
|
||||
ping.unmount(this)
|
||||
@@ -461,36 +405,22 @@ class Libp2p extends EventEmitter {
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
dial (peer, options) {
|
||||
return this._dial(peer, options)
|
||||
return this.dialProtocol(peer, [], options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dials to the provided peer and tries to handshake with the given protocols in order.
|
||||
* Dials to the provided peer and handshakes with the given protocol.
|
||||
* If successful, the known metadata of the peer will be added to the nodes `peerStore`,
|
||||
* and the `MuxedStream` will be returned together with the successful negotiated protocol.
|
||||
* and the `Connection` will be returned
|
||||
*
|
||||
* @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)) {
|
||||
@@ -505,36 +435,31 @@ 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
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a deduplicated list of peer advertising multiaddrs by concatenating
|
||||
* the listen addresses used by transports with any configured
|
||||
* announce addresses as well as observed addresses reported by peers.
|
||||
*
|
||||
* If Announce addrs are specified, configured listen addresses will be
|
||||
* ignored though observed addresses will still be included.
|
||||
* Get peer advertising multiaddrs by concating the addresses used
|
||||
* by transports to listen with the announce addresses.
|
||||
* Duplicated addresses and noAnnounce addresses are filtered out.
|
||||
*
|
||||
* @returns {Multiaddr[]}
|
||||
*/
|
||||
get multiaddrs () {
|
||||
let addrs = this.addressManager.getAnnounceAddrs().map(ma => ma.toString())
|
||||
|
||||
if (!addrs.length) {
|
||||
// no configured announce addrs, add configured listen addresses
|
||||
addrs = this.transportManager.getAddrs().map(ma => ma.toString())
|
||||
const announceAddrs = this.addressManager.getAnnounceAddrs()
|
||||
if (announceAddrs.length) {
|
||||
return announceAddrs
|
||||
}
|
||||
|
||||
addrs = addrs.concat(this.addressManager.getObservedAddrs().map(ma => ma.toString()))
|
||||
|
||||
const announceFilter = this._options.addresses.announceFilter
|
||||
|
||||
// dedupe multiaddrs
|
||||
const addrSet = new Set(addrs)
|
||||
const announceFilter = this._options.addresses.announceFilter || ((multiaddrs) => multiaddrs)
|
||||
|
||||
// Create advertising list
|
||||
return announceFilter(Array.from(addrSet).map(str => new Multiaddr(str)))
|
||||
return announceFilter(this.transportManager.getAddrs())
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -580,7 +505,7 @@ class Libp2p extends EventEmitter {
|
||||
* Registers the `handler` for each protocol
|
||||
*
|
||||
* @param {string[]|string} protocols
|
||||
* @param {(props: HandlerProps) => void} handler
|
||||
* @param {({ connection: Connection, stream: MuxedStream, protocol: string }) => void} handler
|
||||
*/
|
||||
handle (protocols, handler) {
|
||||
protocols = Array.isArray(protocols) ? protocols : [protocols]
|
||||
@@ -613,9 +538,6 @@ class Libp2p extends EventEmitter {
|
||||
const addrs = this.addressManager.getListenAddrs()
|
||||
await this.transportManager.listen(addrs)
|
||||
|
||||
// Manage your NATs
|
||||
this.natManager.start()
|
||||
|
||||
// Start PeerStore
|
||||
await this.peerStore.start()
|
||||
|
||||
@@ -700,7 +622,7 @@ class Libp2p extends EventEmitter {
|
||||
try {
|
||||
await this.dialer.connectToPeer(peerId)
|
||||
} catch (err) {
|
||||
log.error(`could not connect to discovered peer ${peerId.toB58String()} with ${err}`)
|
||||
log.error('could not connect to discovered peer', err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -713,9 +635,6 @@ class Libp2p extends EventEmitter {
|
||||
* @private
|
||||
*/
|
||||
async _setupPeerDiscovery () {
|
||||
/**
|
||||
* @param {PeerDiscoveryFactory} DiscoveryService
|
||||
*/
|
||||
const setupService = (DiscoveryService) => {
|
||||
let config = {
|
||||
enabled: true // on by default
|
||||
@@ -724,7 +643,6 @@ 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] }
|
||||
}
|
||||
|
||||
@@ -733,7 +651,6 @@ 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
|
||||
|
@@ -4,7 +4,6 @@ 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')
|
||||
@@ -17,12 +16,8 @@ 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).finish()
|
||||
// @ts-ignore TODO: Uint8Array not assignable to Buffer
|
||||
const pb = Exchange.encode(exchange)
|
||||
return lp.encode.single(pb)
|
||||
}
|
||||
|
||||
@@ -73,23 +68,12 @@ async function 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)
|
||||
}
|
||||
}
|
||||
module.exports = {
|
||||
protocol,
|
||||
secureInbound: (localId, conn, remoteId) => {
|
||||
return encrypt(localId, conn, remoteId)
|
||||
},
|
||||
secureOutbound: (localId, conn, remoteId) => {
|
||||
return encrypt(localId, conn, remoteId)
|
||||
}
|
||||
}
|
||||
|
128
src/insecure/proto.d.ts
vendored
128
src/insecure/proto.d.ts
vendored
@@ -1,128 +0,0 @@
|
||||
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 };
|
||||
}
|
@@ -1,371 +1,22 @@
|
||||
/*eslint-disable*/
|
||||
"use strict";
|
||||
'use strict'
|
||||
|
||||
var $protobuf = require("protobufjs/minimal");
|
||||
const protobuf = require('protons')
|
||||
|
||||
// Common aliases
|
||||
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
|
||||
module.exports = protobuf(`
|
||||
message Exchange {
|
||||
optional bytes id = 1;
|
||||
optional PublicKey pubkey = 2;
|
||||
}
|
||||
|
||||
// Exported root namespace
|
||||
var $root = $protobuf.roots["libp2p-plaintext"] || ($protobuf.roots["libp2p-plaintext"] = {});
|
||||
enum KeyType {
|
||||
RSA = 0;
|
||||
Ed25519 = 1;
|
||||
Secp256k1 = 2;
|
||||
ECDSA = 3;
|
||||
}
|
||||
|
||||
$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;
|
||||
message PublicKey {
|
||||
required KeyType Type = 1;
|
||||
required bytes Data = 2;
|
||||
}
|
||||
`)
|
||||
|
@@ -1,18 +0,0 @@
|
||||
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;
|
||||
}
|
@@ -1,18 +1,14 @@
|
||||
// @ts-nocheck
|
||||
'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')
|
||||
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const privates = new WeakMap()
|
||||
|
||||
/**
|
||||
* Cryptographic Message Syntax (aka PKCS #7)
|
||||
*
|
||||
@@ -27,15 +23,13 @@ class CMS {
|
||||
* Creates a new instance with a keychain
|
||||
*
|
||||
* @param {import('./index')} keychain - the available keys
|
||||
* @param {string} dek
|
||||
*/
|
||||
constructor (keychain, dek) {
|
||||
constructor (keychain) {
|
||||
if (!keychain) {
|
||||
throw errcode(new Error('keychain is required'), 'ERR_KEYCHAIN_REQUIRED')
|
||||
}
|
||||
|
||||
this.keychain = keychain
|
||||
privates.set(this, { dek })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -54,9 +48,7 @@ class CMS {
|
||||
|
||||
const key = await this.keychain.findKeyByName(name)
|
||||
const pem = await this.keychain._getPrivateKey(name)
|
||||
/** @type {string} */
|
||||
const dek = privates.get(this).dek
|
||||
const privateKey = forge.pki.decryptRsaPrivateKey(pem, dek)
|
||||
const privateKey = forge.pki.decryptRsaPrivateKey(pem, this.keychain._())
|
||||
const certificate = await certificateForKey(key, privateKey)
|
||||
|
||||
// create a p7 enveloped message
|
||||
@@ -88,7 +80,6 @@ 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')
|
||||
@@ -97,15 +88,11 @@ 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
|
||||
}
|
||||
})
|
||||
@@ -121,7 +108,6 @@ 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
|
||||
@@ -129,14 +115,8 @@ class CMS {
|
||||
}
|
||||
|
||||
const key = await this.keychain.findKeyById(r.keyId)
|
||||
|
||||
if (!key) {
|
||||
throw errcode(new Error('No key available to decrypto'), 'ERR_NO_KEY')
|
||||
}
|
||||
|
||||
const pem = await this.keychain._getPrivateKey(key.name)
|
||||
const dek = privates.get(this).dek
|
||||
const privateKey = forge.pki.decryptRsaPrivateKey(pem, dek)
|
||||
const privateKey = forge.pki.decryptRsaPrivateKey(pem, this.keychain._())
|
||||
cms.decrypt(r.recipient, privateKey)
|
||||
return uint8ArrayFromString(cms.content.getBytes(), 'ascii')
|
||||
}
|
||||
|
@@ -1,46 +1,21 @@
|
||||
// @ts-nocheck
|
||||
/* eslint max-nested-callbacks: ["error", 5] */
|
||||
'use strict'
|
||||
|
||||
const sanitize = require('sanitize-filename')
|
||||
const mergeOptions = require('merge-options')
|
||||
const crypto = require('libp2p-crypto')
|
||||
const { Key } = require('interface-datastore')
|
||||
const DS = require('interface-datastore')
|
||||
const CMS = require('./cms')
|
||||
const errcode = require('err-code')
|
||||
const { Number } = require('ipfs-utils/src/globalthis')
|
||||
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').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/'
|
||||
const infoPrefix = '/info/'
|
||||
const privates = new WeakMap()
|
||||
|
||||
// NIST SP 800-132
|
||||
const NIST = {
|
||||
@@ -59,9 +34,6 @@ const defaultOptions = {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
function validateKeyName (name) {
|
||||
if (!name) return false
|
||||
if (typeof name !== 'string') return false
|
||||
@@ -74,8 +46,7 @@ function validateKeyName (name) {
|
||||
* This assumes than an error indicates that the keychain is under attack. Delay returning an
|
||||
* error to make brute force attacks harder.
|
||||
*
|
||||
* @param {string|Error} err - The error
|
||||
* @returns {Promise<never>}
|
||||
* @param {string | Error} err - The error
|
||||
* @private
|
||||
*/
|
||||
async function throwDelayed (err) {
|
||||
@@ -91,24 +62,33 @@ async function throwDelayed (err) {
|
||||
* Converts a key name into a datastore name.
|
||||
*
|
||||
* @param {string} name
|
||||
* @returns {Key}
|
||||
* @returns {DS.Key}
|
||||
* @private
|
||||
*/
|
||||
function DsName (name) {
|
||||
return new Key(keyPrefix + name)
|
||||
return new DS.Key(keyPrefix + name)
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a key name into a datastore info name.
|
||||
*
|
||||
* @param {string} name
|
||||
* @returns {Key}
|
||||
* @returns {DS.Key}
|
||||
* @private
|
||||
*/
|
||||
function DsInfoName (name) {
|
||||
return new Key(infoPrefix + name)
|
||||
return new DS.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.
|
||||
*
|
||||
@@ -121,8 +101,8 @@ class Keychain {
|
||||
/**
|
||||
* Creates a new instance of a key chain.
|
||||
*
|
||||
* @param {Datastore} store - where the key are.
|
||||
* @param {KeychainOptions} options
|
||||
* @param {DS} store - where the key are.
|
||||
* @param {object} options
|
||||
* @class
|
||||
*/
|
||||
constructor (store, options) {
|
||||
@@ -134,8 +114,8 @@ class Keychain {
|
||||
this.opts = mergeOptions(defaultOptions, options)
|
||||
|
||||
// Enforce NIST SP 800-132
|
||||
if (this.opts.pass && this.opts.pass.length < 20) {
|
||||
throw new Error('pass must be least 20 characters')
|
||||
if (this.opts.passPhrase && this.opts.passPhrase.length < 20) {
|
||||
throw new Error('passPhrase must be least 20 characters')
|
||||
}
|
||||
if (this.opts.dek.keyLength < NIST.minKeyLength) {
|
||||
throw new Error(`dek.keyLength must be least ${NIST.minKeyLength} bytes`)
|
||||
@@ -147,16 +127,14 @@ class Keychain {
|
||||
throw new Error(`dek.iterationCount must be least ${NIST.minIterationCount}`)
|
||||
}
|
||||
|
||||
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)
|
||||
: ''
|
||||
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) : ''
|
||||
|
||||
privates.set(this, { dek })
|
||||
Object.defineProperty(this, '_', { value: () => dek })
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -170,13 +148,13 @@ class Keychain {
|
||||
* @returns {CMS}
|
||||
*/
|
||||
get cms () {
|
||||
return new CMS(this, privates.get(this).dek)
|
||||
return new CMS(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the options for a keychain. A random salt is produced.
|
||||
*
|
||||
* @returns {Object}
|
||||
* @returns {object}
|
||||
*/
|
||||
static generateOptions () {
|
||||
const options = Object.assign({}, defaultOptions)
|
||||
@@ -189,7 +167,7 @@ class Keychain {
|
||||
* Gets an object that can encrypt/decrypt protected data.
|
||||
* The default options for a keychain.
|
||||
*
|
||||
* @returns {Object}
|
||||
* @returns {object}
|
||||
*/
|
||||
static get options () {
|
||||
return defaultOptions
|
||||
@@ -200,10 +178,10 @@ class Keychain {
|
||||
*
|
||||
* @param {string} name - The local key name; cannot already exist.
|
||||
* @param {string} type - One of the key types; 'rsa'.
|
||||
* @param {number} [size = 2048] - The key size in bits. Used for rsa keys only.
|
||||
* @returns {Promise<KeyInfo>}
|
||||
* @param {int} [size] - The key size in bits. Used for rsa keys only.
|
||||
* @returns {KeyInfo}
|
||||
*/
|
||||
async createKey (name, type, size = 2048) {
|
||||
async createKey (name, type, size) {
|
||||
const self = this
|
||||
|
||||
if (!validateKeyName(name) || name === 'self') {
|
||||
@@ -230,12 +208,9 @@ class Keychain {
|
||||
|
||||
let keyInfo
|
||||
try {
|
||||
// @ts-ignore Differences between several crypto return types need to be fixed in libp2p-crypto
|
||||
const keypair = await crypto.keys.generateKeyPair(type, size)
|
||||
const kid = await keypair.id()
|
||||
/** @type {string} */
|
||||
const dek = privates.get(this).dek
|
||||
const pem = await keypair.export(dek)
|
||||
const pem = await keypair.export(this._())
|
||||
keyInfo = {
|
||||
name: name,
|
||||
id: kid
|
||||
@@ -255,7 +230,7 @@ class Keychain {
|
||||
/**
|
||||
* List all the keys.
|
||||
*
|
||||
* @returns {Promise<KeyInfo[]>}
|
||||
* @returns {KeyInfo[]}
|
||||
*/
|
||||
async listKeys () {
|
||||
const self = this
|
||||
@@ -275,7 +250,7 @@ class Keychain {
|
||||
* Find a key by it's id.
|
||||
*
|
||||
* @param {string} id - The universally unique key identifier.
|
||||
* @returns {Promise<KeyInfo|undefined>}
|
||||
* @returns {KeyInfo}
|
||||
*/
|
||||
async findKeyById (id) {
|
||||
try {
|
||||
@@ -290,7 +265,7 @@ class Keychain {
|
||||
* Find a key by it's name.
|
||||
*
|
||||
* @param {string} name - The local key name.
|
||||
* @returns {Promise<KeyInfo>}
|
||||
* @returns {KeyInfo}
|
||||
*/
|
||||
async findKeyByName (name) {
|
||||
if (!validateKeyName(name)) {
|
||||
@@ -310,7 +285,7 @@ class Keychain {
|
||||
* Remove an existing key.
|
||||
*
|
||||
* @param {string} name - The local key name; must already exist.
|
||||
* @returns {Promise<KeyInfo>}
|
||||
* @returns {KeyInfo}
|
||||
*/
|
||||
async removeKey (name) {
|
||||
const self = this
|
||||
@@ -331,7 +306,7 @@ class Keychain {
|
||||
*
|
||||
* @param {string} oldName - The old local key name; must already exist.
|
||||
* @param {string} newName - The new local key name; must not already exist.
|
||||
* @returns {Promise<KeyInfo>}
|
||||
* @returns {KeyInfo}
|
||||
*/
|
||||
async renameKey (oldName, newName) {
|
||||
const self = this
|
||||
@@ -372,7 +347,7 @@ class Keychain {
|
||||
*
|
||||
* @param {string} name - The local key name; must already exist.
|
||||
* @param {string} password - The password
|
||||
* @returns {Promise<string>}
|
||||
* @returns {string}
|
||||
*/
|
||||
async exportKey (name, password) {
|
||||
if (!validateKeyName(name)) {
|
||||
@@ -386,9 +361,7 @@ class Keychain {
|
||||
try {
|
||||
const res = await this.store.get(dsname)
|
||||
const pem = uint8ArrayToString(res)
|
||||
/** @type {string} */
|
||||
const dek = privates.get(this).dek
|
||||
const privateKey = await crypto.keys.import(pem, dek)
|
||||
const privateKey = await crypto.keys.import(pem, this._())
|
||||
return privateKey.export(password)
|
||||
} catch (err) {
|
||||
return throwDelayed(err)
|
||||
@@ -401,7 +374,7 @@ class Keychain {
|
||||
* @param {string} name - The local key name; must not already exist.
|
||||
* @param {string} pem - The PEM encoded PKCS #8 string
|
||||
* @param {string} password - The password.
|
||||
* @returns {Promise<KeyInfo>}
|
||||
* @returns {KeyInfo}
|
||||
*/
|
||||
async importKey (name, pem, password) {
|
||||
const self = this
|
||||
@@ -425,9 +398,7 @@ class Keychain {
|
||||
let kid
|
||||
try {
|
||||
kid = await privateKey.id()
|
||||
/** @type {string} */
|
||||
const dek = privates.get(this).dek
|
||||
pem = await privateKey.export(dek)
|
||||
pem = await privateKey.export(this._())
|
||||
} catch (err) {
|
||||
return throwDelayed(err)
|
||||
}
|
||||
@@ -444,13 +415,6 @@ class Keychain {
|
||||
return keyInfo
|
||||
}
|
||||
|
||||
/**
|
||||
* Import a peer key
|
||||
*
|
||||
* @param {string} name - The local key name; must not already exist.
|
||||
* @param {PeerId} peer - The PEM encoded PKCS #8 string
|
||||
* @returns {Promise<KeyInfo>}
|
||||
*/
|
||||
async importPeer (name, peer) {
|
||||
const self = this
|
||||
if (!validateKeyName(name)) {
|
||||
@@ -467,9 +431,7 @@ class Keychain {
|
||||
|
||||
try {
|
||||
const kid = await privateKey.id()
|
||||
/** @type {string} */
|
||||
const dek = privates.get(this).dek
|
||||
const pem = await privateKey.export(dek)
|
||||
const pem = await privateKey.export(this._())
|
||||
const keyInfo = {
|
||||
name: name,
|
||||
id: kid
|
||||
@@ -488,7 +450,8 @@ class Keychain {
|
||||
* Gets the private key as PEM encoded PKCS #8 string.
|
||||
*
|
||||
* @param {string} name
|
||||
* @returns {Promise<string>}
|
||||
* @returns {string}
|
||||
* @private
|
||||
*/
|
||||
async _getPrivateKey (name) {
|
||||
if (!validateKeyName(name)) {
|
||||
|
@@ -4,6 +4,7 @@
|
||||
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.
|
||||
@@ -16,7 +17,7 @@ const pki = forge.pki
|
||||
* @param {RsaPrivateKey} privateKey - The naked key
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
const certificateForKey = (key, privateKey) => {
|
||||
exports.certificateForKey = (key, privateKey) => {
|
||||
const publicKey = pki.setRsaPublicKey(privateKey.n, privateKey.e)
|
||||
const cert = pki.createCertificate()
|
||||
cert.publicKey = publicKey
|
||||
@@ -86,7 +87,4 @@ async function findAsync (array, asyncCompare) {
|
||||
return array[index]
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
certificateForKey,
|
||||
findAsync
|
||||
}
|
||||
module.exports.findAsync = findAsync
|
||||
|
@@ -2,14 +2,10 @@
|
||||
'use strict'
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
const { BigNumber: Big } = require('bignumber.js')
|
||||
const MovingAverage = require('@vascosantos/moving-average')
|
||||
const Big = require('bignumber.js')
|
||||
const MovingAverage = require('moving-average')
|
||||
const retimer = require('retimer')
|
||||
|
||||
/**
|
||||
* @typedef {import('@vascosantos/moving-average').IMovingAverage} IMovingAverage
|
||||
*/
|
||||
|
||||
class Stats extends EventEmitter {
|
||||
/**
|
||||
* A queue based manager for stat processing
|
||||
@@ -23,30 +19,24 @@ class Stats extends EventEmitter {
|
||||
|
||||
this._options = options
|
||||
this._queue = []
|
||||
|
||||
/** @type {{ dataReceived: Big, dataSent: Big }} */
|
||||
this._stats = {
|
||||
dataReceived: Big(0),
|
||||
dataSent: Big(0)
|
||||
}
|
||||
this._stats = {}
|
||||
|
||||
this._frequencyLastTime = Date.now()
|
||||
this._frequencyAccumulators = {}
|
||||
|
||||
/** @type {{ dataReceived: IMovingAverage[], dataSent: IMovingAverage[] }} */
|
||||
this._movingAverages = {}
|
||||
|
||||
this._update = this._update.bind(this)
|
||||
|
||||
const intervals = this._options.movingAverageIntervals
|
||||
|
||||
for (let i = 0; i < initialCounters.length; i++) {
|
||||
const key = initialCounters[i]
|
||||
for (var i = 0; i < initialCounters.length; i++) {
|
||||
var key = initialCounters[i]
|
||||
this._stats[key] = Big(0)
|
||||
this._movingAverages[key] = {}
|
||||
for (let k = 0; k < intervals.length; k++) {
|
||||
const interval = intervals[k]
|
||||
const ma = this._movingAverages[key][interval] = MovingAverage(interval)
|
||||
for (var k = 0; k < intervals.length; k++) {
|
||||
var interval = intervals[k]
|
||||
var ma = this._movingAverages[key][interval] = MovingAverage(interval)
|
||||
ma.push(this._frequencyLastTime, 0)
|
||||
}
|
||||
}
|
||||
@@ -80,6 +70,8 @@ class Stats extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Returns a clone of the current stats.
|
||||
*
|
||||
* @returns {Object}
|
||||
*/
|
||||
get snapshot () {
|
||||
return Object.assign({}, this._stats)
|
||||
@@ -87,6 +79,8 @@ class Stats extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Returns a clone of the internal movingAverages
|
||||
*
|
||||
* @returns {MovingAverage}
|
||||
*/
|
||||
get movingAverages () {
|
||||
return Object.assign({}, this._movingAverages)
|
||||
@@ -223,9 +217,9 @@ class Stats extends EventEmitter {
|
||||
|
||||
const intervals = this._options.movingAverageIntervals
|
||||
|
||||
for (let i = 0; i < intervals.length; i++) {
|
||||
const movingAverageInterval = intervals[i]
|
||||
let movingAverage = movingAverages[movingAverageInterval]
|
||||
for (var i = 0; i < intervals.length; i++) {
|
||||
var movingAverageInterval = intervals[i]
|
||||
var movingAverage = movingAverages[movingAverageInterval]
|
||||
if (!movingAverage) {
|
||||
movingAverage = movingAverages[movingAverageInterval] = MovingAverage(movingAverageInterval)
|
||||
}
|
||||
|
@@ -1,197 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
// @ts-ignore nat-api does not export types
|
||||
const NatAPI = require('@motrix/nat-api')
|
||||
const debug = require('debug')
|
||||
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')
|
||||
const {
|
||||
codes: { ERR_INVALID_PARAMETERS }
|
||||
} = 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)
|
||||
}
|
||||
|
||||
class NatManager {
|
||||
/**
|
||||
* @class
|
||||
* @param {NatManagerProperties & NatManagerOptions} options
|
||||
*/
|
||||
constructor ({ peerId, addressManager, transportManager, ...options }) {
|
||||
this._peerId = peerId
|
||||
this._addressManager = addressManager
|
||||
this._transportManager = transportManager
|
||||
|
||||
this._enabled = options.enabled
|
||||
this._externalIp = options.externalIp
|
||||
this._options = {
|
||||
description: options.description || `${pkg.name}@${pkg.version} ${this._peerId}`,
|
||||
ttl: options.ttl || DEFAULT_TTL,
|
||||
autoUpdate: options.keepAlive || true,
|
||||
gateway: options.gateway,
|
||||
enablePMP: Boolean(options.pmp && options.pmp.enabled)
|
||||
}
|
||||
|
||||
if (this._options.ttl < DEFAULT_TTL) {
|
||||
throw errcode(new Error(`NatManager ttl should be at least ${DEFAULT_TTL} seconds`), ERR_INVALID_PARAMETERS)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the NAT manager
|
||||
*/
|
||||
start () {
|
||||
if (isBrowser || !this._enabled) {
|
||||
return
|
||||
}
|
||||
|
||||
// done async to not slow down startup
|
||||
this._start().catch((err) => {
|
||||
// hole punching errors are non-fatal
|
||||
log.error(err)
|
||||
})
|
||||
}
|
||||
|
||||
async _start () {
|
||||
const addrs = this._transportManager.getAddrs()
|
||||
|
||||
for (const addr of addrs) {
|
||||
// try to open uPnP ports for each thin waist address
|
||||
const { family, host, port, transport } = addr.toOptions()
|
||||
|
||||
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 !== 4) {
|
||||
// ignore ipv6
|
||||
// eslint-disable-next-line no-continue
|
||||
continue
|
||||
}
|
||||
|
||||
const client = this._getClient()
|
||||
const publicIp = this._externalIp || await client.externalIp()
|
||||
|
||||
if (isPrivateIp(publicIp)) {
|
||||
throw new Error(`${publicIp} is private - please set config.nat.externalIp to an externally routable IP or ensure you are not behind a double NAT`)
|
||||
}
|
||||
|
||||
const publicPort = highPort()
|
||||
|
||||
log(`opening uPnP connection from ${publicIp}:${publicPort} to ${host}:${port}`)
|
||||
|
||||
await client.map({
|
||||
publicPort,
|
||||
privatePort: port,
|
||||
protocol: transport.toUpperCase()
|
||||
})
|
||||
|
||||
this._addressManager.addObservedAddr(Multiaddr.fromNodeAddress({
|
||||
family: 4,
|
||||
address: publicIp,
|
||||
port: publicPort
|
||||
}, transport))
|
||||
}
|
||||
}
|
||||
|
||||
_getClient () {
|
||||
if (this._client) {
|
||||
return this._client
|
||||
}
|
||||
|
||||
const client = new NatAPI(this._options)
|
||||
|
||||
/** @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 = {
|
||||
/**
|
||||
* @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 })
|
||||
}
|
||||
|
||||
return this._client
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops the NAT manager
|
||||
*
|
||||
* @async
|
||||
*/
|
||||
async stop () {
|
||||
if (isBrowser || !this._client) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
await this._client.destroy()
|
||||
this._client = null
|
||||
} catch (err) {
|
||||
log.error(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = NatManager
|
@@ -5,39 +5,18 @@ const log = Object.assign(debug('libp2p:peer-routing'), {
|
||||
error: debug('libp2p:peer-routing:err')
|
||||
})
|
||||
const errCode = require('err-code')
|
||||
const {
|
||||
storeAddresses,
|
||||
uniquePeers,
|
||||
requirePeers
|
||||
} = require('./content-routing/utils')
|
||||
|
||||
const merge = require('it-merge')
|
||||
const { pipe } = require('it-pipe')
|
||||
const first = require('it-first')
|
||||
const drain = require('it-drain')
|
||||
const filter = require('it-filter')
|
||||
const all = require('it-all')
|
||||
const pAny = require('p-any')
|
||||
const {
|
||||
setDelayedInterval,
|
||||
clearDelayedInterval
|
||||
// @ts-ignore module with no types
|
||||
} = require('set-delayed-interval')
|
||||
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('multiaddr').Multiaddr} Multiaddr
|
||||
* @typedef {import('libp2p-interfaces/src/peer-routing/types').PeerRouting} PeerRoutingModule
|
||||
* @typedef {import('multiaddr')} Multiaddr
|
||||
*/
|
||||
|
||||
/**
|
||||
* @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
|
||||
@@ -46,12 +25,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 && libp2p._config.dht.enabled) {
|
||||
this._routers.push(libp2p._dht)
|
||||
// If we have the dht, make it first
|
||||
if (libp2p._dht) {
|
||||
this._routers.unshift(libp2p._dht)
|
||||
}
|
||||
|
||||
this._refreshManagerOptions = libp2p._options.peerRouting.refreshManager
|
||||
@@ -77,8 +55,9 @@ class PeerRouting {
|
||||
*/
|
||||
async _findClosestPeersTask () {
|
||||
try {
|
||||
// nb getClosestPeers adds the addresses to the address book
|
||||
await drain(this.getClosestPeers(this._peerId.id))
|
||||
for await (const { id, multiaddrs } of this.getClosestPeers(this._peerId.id)) {
|
||||
this._peerStore.addressBook.add(id, multiaddrs)
|
||||
}
|
||||
} catch (err) {
|
||||
log.error(err)
|
||||
}
|
||||
@@ -92,9 +71,9 @@ class PeerRouting {
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates over all peer routers in parallel to find the given peer.
|
||||
* Iterates over all peer routers in series to find the given peer.
|
||||
*
|
||||
* @param {PeerId} id - The id of the peer to find
|
||||
* @param {string} id - The id of the peer to find
|
||||
* @param {object} [options]
|
||||
* @param {number} [options.timeout] - How long the query should run
|
||||
* @returns {Promise<{ id: PeerId, multiaddrs: Multiaddr[] }>}
|
||||
@@ -104,21 +83,16 @@ class PeerRouting {
|
||||
throw errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE')
|
||||
}
|
||||
|
||||
const output = await pipe(
|
||||
merge(
|
||||
...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)
|
||||
)
|
||||
return pAny(this._routers.map(async (router) => {
|
||||
const result = await router.findPeer(id, options)
|
||||
|
||||
if (output) {
|
||||
return output
|
||||
}
|
||||
// If we don't have a result, we need to provide an error to keep trying
|
||||
if (!result || Object.keys(result).length === 0) {
|
||||
throw errCode(new Error('not found'), 'NOT_FOUND')
|
||||
}
|
||||
|
||||
throw errCode(new Error('not found'), 'NOT_FOUND')
|
||||
return result
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -134,14 +108,20 @@ class PeerRouting {
|
||||
throw errCode(new Error('No peer routers available'), 'NO_ROUTERS_AVAILABLE')
|
||||
}
|
||||
|
||||
yield * pipe(
|
||||
merge(
|
||||
...this._routers.map(router => router.getClosestPeers(key, options))
|
||||
),
|
||||
(source) => storeAddresses(source, this._peerStore),
|
||||
(source) => uniquePeers(source),
|
||||
(source) => requirePeers(source)
|
||||
const result = await pAny(
|
||||
this._routers.map(async (router) => {
|
||||
const peers = await all(router.getClosestPeers(key, options))
|
||||
|
||||
if (!peers || !peers.length) {
|
||||
throw errCode(new Error('not found'), 'NOT_FOUND')
|
||||
}
|
||||
return peers
|
||||
})
|
||||
)
|
||||
|
||||
for (const peer of result) {
|
||||
yield peer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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,6 +18,7 @@ const {
|
||||
const Envelope = require('../record/envelope')
|
||||
|
||||
/**
|
||||
* @typedef {import('multiaddr')} Multiaddr
|
||||
* @typedef {import('./')} PeerStore
|
||||
*/
|
||||
|
||||
@@ -59,7 +60,7 @@ class AddressBook extends Book {
|
||||
if (!data.addresses) {
|
||||
return []
|
||||
}
|
||||
return data.addresses.map((/** @type {Address} */ address) => address.multiaddr)
|
||||
return data.addresses.map((address) => address.multiaddr)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -229,11 +230,6 @@ 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) {
|
||||
@@ -299,21 +295,17 @@ 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)
|
||||
}
|
||||
|
||||
// Guarantee no replicates
|
||||
if (!addresses.find((a) => a.multiaddr.equals(addr))) {
|
||||
addresses.push({
|
||||
multiaddr: addr,
|
||||
isCertified
|
||||
})
|
||||
}
|
||||
addresses.push({
|
||||
multiaddr: addr,
|
||||
isCertified
|
||||
})
|
||||
})
|
||||
|
||||
return addresses
|
||||
|
@@ -7,9 +7,6 @@ const {
|
||||
codes: { ERR_INVALID_PARAMETERS }
|
||||
} = require('../errors')
|
||||
|
||||
/**
|
||||
* @param {any} data
|
||||
*/
|
||||
const passthrough = data => data
|
||||
|
||||
/**
|
||||
|
@@ -81,9 +81,6 @@ 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()
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user