mirror of
https://github.com/fluencelabs/js-libp2p-interfaces
synced 2025-07-06 17:21:42 +00:00
Compare commits
36 Commits
v0.5.2
...
chore/upda
Author | SHA1 | Date | |
---|---|---|---|
d224d15507 | |||
0b4fd039f8 | |||
0cb709635f | |||
edb8ca60e9 | |||
810642d8ff | |||
64a478d313 | |||
b948972c5b | |||
edcedf093d | |||
3b960d516f | |||
2429e7246f | |||
22a7f6a9f1 | |||
fb9fce8713 | |||
91dba97125 | |||
93d712bb0e | |||
ca520775eb | |||
ceb91c672e | |||
30ffad42c8 | |||
c365399e4f | |||
5b99e6b56b | |||
f4c19c9ef2 | |||
c36698f488 | |||
3ecbc3e889 | |||
e2419ea308 | |||
04e93d3f08 | |||
83d7d52d7e | |||
1a3ea82776 | |||
ad2dfa42dc | |||
b75f2cab48 | |||
8512997e76 | |||
269a6f5e0a | |||
14d09970ca | |||
c98c58e824 | |||
946b046440 | |||
d168c7d531 | |||
349c1174db | |||
e14844315b |
53
.github/workflows/main.yml
vendored
Normal file
53
.github/workflows/main.yml
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
name: ci
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- run: yarn
|
||||
- run: yarn lint
|
||||
- uses: gozala/typescript-error-reporter-action@v1.0.4
|
||||
- run: yarn build
|
||||
- run: yarn aegir dep-check
|
||||
- uses: ipfs/aegir/actions/bundle-size@master
|
||||
name: size
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
test-node:
|
||||
needs: check
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [windows-latest, ubuntu-latest, macos-latest]
|
||||
node: [14, 15]
|
||||
fail-fast: true
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
- run: yarn
|
||||
- run: npx nyc --reporter=lcov aegir test -t node -- --bail
|
||||
- uses: codecov/codecov-action@v1
|
||||
test-chrome:
|
||||
needs: check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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: yarn
|
||||
- run: npx aegir test -t browser -t webworker --bail -- --browsers FirefoxHeadless
|
40
.travis.yml
40
.travis.yml
@ -1,40 +0,0 @@
|
||||
language: node_js
|
||||
cache: npm
|
||||
stages:
|
||||
- check
|
||||
- test
|
||||
- cov
|
||||
|
||||
node_js:
|
||||
- '10'
|
||||
- '12'
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
|
||||
script: npx nyc -s npm run test:node -- --bail
|
||||
after_success: npx nyc report --reporter=text-lcov > coverage.lcov && npx codecov
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- stage: check
|
||||
script:
|
||||
- npx aegir dep-check
|
||||
- npm run lint
|
||||
|
||||
- stage: test
|
||||
name: chrome
|
||||
addons:
|
||||
chrome: stable
|
||||
script: npx aegir test -t browser -t webworker
|
||||
|
||||
- stage: test
|
||||
name: firefox
|
||||
addons:
|
||||
firefox: latest
|
||||
script: npx aegir test -t browser -t webworker -- --browsers FirefoxHeadless
|
||||
|
||||
notifications:
|
||||
email: false
|
94
CHANGELOG.md
94
CHANGELOG.md
@ -1,3 +1,97 @@
|
||||
# [0.9.0](https://github.com/libp2p/js-interfaces/compare/v0.8.4...v0.9.0) (2021-04-07)
|
||||
|
||||
|
||||
|
||||
## [0.8.4](https://github.com/libp2p/js-interfaces/compare/v0.8.3...v0.8.4) (2021-03-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* specify connection direction ([#86](https://github.com/libp2p/js-interfaces/issues/86)) ([3b960d5](https://github.com/libp2p/js-interfaces/commit/3b960d516f70f7e198574a736cb09000ddd7a94c))
|
||||
|
||||
|
||||
|
||||
## [0.8.3](https://github.com/libp2p/js-interfaces/compare/v0.8.2...v0.8.3) (2021-01-26)
|
||||
|
||||
|
||||
|
||||
## [0.8.2](https://github.com/libp2p/js-interfaces/compare/v0.8.1...v0.8.2) (2021-01-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* event emitter types with local types ([#80](https://github.com/libp2p/js-interfaces/issues/80)) ([ca52077](https://github.com/libp2p/js-interfaces/commit/ca520775eb26f5ed501375fdb24ba698c9a8c8c8))
|
||||
|
||||
|
||||
|
||||
## [0.8.1](https://github.com/libp2p/js-interfaces/compare/v0.8.0...v0.8.1) (2020-12-11)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* pubsub publish message should be uint8array ([#77](https://github.com/libp2p/js-interfaces/issues/77)) ([5b99e6b](https://github.com/libp2p/js-interfaces/commit/5b99e6b56b10439a82ee88fb4e31fb95c182264f))
|
||||
|
||||
|
||||
|
||||
# [0.8.0](https://github.com/libp2p/js-interfaces/compare/v0.7.2...v0.8.0) (2020-12-10)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add types ([#74](https://github.com/libp2p/js-interfaces/issues/74)) ([e2419ea](https://github.com/libp2p/js-interfaces/commit/e2419ea308b5db38966850ba6349602c93ce3b0e))
|
||||
|
||||
|
||||
|
||||
<a name="0.7.2"></a>
|
||||
## [0.7.2](https://github.com/libp2p/js-interfaces/compare/v0.7.1...v0.7.2) (2020-11-11)
|
||||
|
||||
|
||||
|
||||
<a name="0.7.1"></a>
|
||||
## [0.7.1](https://github.com/libp2p/js-interfaces/compare/v0.7.0...v0.7.1) (2020-11-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* typescript types ([#69](https://github.com/libp2p/js-interfaces/issues/69)) ([269a6f5](https://github.com/libp2p/js-interfaces/commit/269a6f5))
|
||||
|
||||
|
||||
|
||||
<a name="0.7.0"></a>
|
||||
# [0.7.0](https://github.com/libp2p/js-interfaces/compare/v0.5.2...v0.7.0) (2020-11-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* pubsub: add global signature policy ([#66](https://github.com/libp2p/js-interfaces/issues/66)) ([946b046](https://github.com/libp2p/js-interfaces/commit/946b046))
|
||||
* update pubsub getMsgId return type to Uint8Array ([#65](https://github.com/libp2p/js-interfaces/issues/65)) ([e148443](https://github.com/libp2p/js-interfaces/commit/e148443))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* `signMessages` and `strictSigning` pubsub configuration options replaced
|
||||
with a `globalSignaturePolicy` option
|
||||
* new getMsgId return type is not backwards compatible with prior `string`
|
||||
return type.
|
||||
|
||||
|
||||
|
||||
<a name="0.6.0"></a>
|
||||
# [0.6.0](https://github.com/libp2p/js-interfaces/compare/v0.5.2...v0.6.0) (2020-10-05)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* update pubsub getMsgId return type to Uint8Array ([#65](https://github.com/libp2p/js-interfaces/issues/65)) ([e148443](https://github.com/libp2p/js-interfaces/commit/e148443))
|
||||
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
* new getMsgId return type is not backwards compatible with prior `string`
|
||||
return type.
|
||||
|
||||
|
||||
|
||||
<a name="0.5.2"></a>
|
||||
## [0.5.2](https://github.com/libp2p/js-interfaces/compare/v0.3.1...v0.5.2) (2020-09-30)
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
[](http://libp2p.io/)
|
||||
[](http://webchat.freenode.net/?channels=%23libp2p)
|
||||
[](https://discuss.libp2p.io)
|
||||
[](https://codecov.io/gh/libp2p/js-libp2p-interfaces)
|
||||
[](https://github.com/libp2p/js-libp2p-interfaces/actions?query=branch%3Amaster+workflow%3Aci+)
|
||||
|
||||
> Contains test suites and interfaces you can use to implement the various components of libp2p.
|
||||
|
||||
@ -18,6 +20,7 @@
|
||||
- [Crypto](./src/crypto)
|
||||
- [Peer Discovery](./src/peer-discovery)
|
||||
- [Peer Routing](./src/peer-routing)
|
||||
- [Pubsub](./src/pubsub)
|
||||
- [Record](./src/record)
|
||||
- [Stream Muxer](./src/stream-muxer)
|
||||
- [Topology](./src/topology)
|
||||
@ -30,6 +33,7 @@ For posterity, here are links to the original repositories for each of the inter
|
||||
- [Content Routing](https://github.com/libp2p/interface-content-routing)
|
||||
- [Peer Discovery](https://github.com/libp2p/interface-peer-discovery)
|
||||
- [Peer Routing](https://github.com/libp2p/interface-peer-routing)
|
||||
- [Pubsub](https://github.com/libp2p/js-libp2p-pubsub)
|
||||
- [Stream Muxer](https://github.com/libp2p/interface-stream-muxer)
|
||||
- [Transport](https://github.com/libp2p/interface-transport)
|
||||
|
||||
|
75
package.json
75
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "libp2p-interfaces",
|
||||
"version": "0.5.2",
|
||||
"version": "0.9.0",
|
||||
"description": "Interfaces for JS Libp2p",
|
||||
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||
"main": "src/index.js",
|
||||
@ -9,15 +9,32 @@
|
||||
"types",
|
||||
"dist"
|
||||
],
|
||||
"types": "dist/src/index.d.ts",
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
"src/*": [
|
||||
"dist/src/*",
|
||||
"dist/src/*/index"
|
||||
]
|
||||
}
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "ipfs"
|
||||
},
|
||||
"scripts": {
|
||||
"prepare": "aegir build --no-bundle",
|
||||
"lint": "aegir lint",
|
||||
"build": "aegir build",
|
||||
"pregenerate:types": "rimraf './src/**/*.d.ts'",
|
||||
"generate:types": "tsc",
|
||||
"build": "npm run build:proto && npm run build:proto-types && npm run build:types",
|
||||
"build:types": "aegir build --no-bundle",
|
||||
"build:proto": "npm run build:proto:rpc && npm run build:proto:topic-descriptor",
|
||||
"build:proto:rpc": "pbjs -t static-module -w commonjs --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/pubsub/message/rpc.js ./src/pubsub/message/rpc.proto",
|
||||
"build:proto:topic-descriptor": "pbjs -t static-module -w commonjs --force-number --no-verify --no-delimited --no-create --no-beautify --no-defaults --lint eslint-disable -o src/pubsub/message/topic-descriptor.js ./src/pubsub/message/topic-descriptor.proto",
|
||||
"build:proto-types": "npm run build:proto-types:rpc && npm run build:proto-types:topic-descriptor",
|
||||
"build:proto-types:rpc": "pbts -o src/pubsub/message/rpc.d.ts src/pubsub/message/rpc.js",
|
||||
"build:proto-types:topic-descriptor": "pbts -o src/pubsub/message/topic-descriptor.d.ts src/pubsub/message/topic-descriptor.js",
|
||||
"test": "aegir test",
|
||||
"test:node": "aegir test --target node",
|
||||
"test:browser": "aegir test --target browser",
|
||||
"prepublishOnly": "npm run generate:types",
|
||||
"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"
|
||||
@ -37,39 +54,43 @@
|
||||
},
|
||||
"homepage": "https://github.com/libp2p/js-interfaces#readme",
|
||||
"dependencies": {
|
||||
"@types/bl": "^4.1.0",
|
||||
"abort-controller": "^3.0.0",
|
||||
"abortable-iterator": "^3.0.0",
|
||||
"chai": "^4.2.0",
|
||||
"chai": "^4.3.4",
|
||||
"chai-checkmark": "^1.0.1",
|
||||
"class-is": "^1.1.0",
|
||||
"debug": "^4.1.1",
|
||||
"delay": "^4.3.0",
|
||||
"debug": "^4.3.1",
|
||||
"delay": "^5.0.0",
|
||||
"detect-node": "^2.0.4",
|
||||
"dirty-chai": "^2.0.1",
|
||||
"err-code": "^2.0.0",
|
||||
"it-goodbye": "^2.0.1",
|
||||
"it-length-prefixed": "^3.1.0",
|
||||
"err-code": "^3.0.1",
|
||||
"it-goodbye": "^3.0.0",
|
||||
"it-length-prefixed": "^5.0.0",
|
||||
"it-pair": "^1.0.0",
|
||||
"it-pipe": "^1.1.0",
|
||||
"it-pushable": "^1.4.0",
|
||||
"libp2p-crypto": "^0.18.0",
|
||||
"libp2p-tcp": "^0.15.0",
|
||||
"multiaddr": "^8.0.0",
|
||||
"multibase": "^3.0.0",
|
||||
"it-pushable": "^1.4.2",
|
||||
"libp2p-crypto": "^0.19.0",
|
||||
"libp2p-tcp": "^0.15.3",
|
||||
"multiaddr": "^9.0.1",
|
||||
"multibase": "^4.0.2",
|
||||
"multihashes": "^4.0.2",
|
||||
"p-defer": "^3.0.0",
|
||||
"p-limit": "^2.3.0",
|
||||
"p-wait-for": "^3.1.0",
|
||||
"peer-id": "^0.14.0",
|
||||
"protons": "^2.0.0",
|
||||
"sinon": "^9.0.2",
|
||||
"streaming-iterables": "^5.0.2",
|
||||
"uint8arrays": "^1.1.0"
|
||||
"p-limit": "^3.1.0",
|
||||
"p-wait-for": "^3.2.0",
|
||||
"peer-id": "^0.14.2",
|
||||
"protobufjs": "^6.10.2",
|
||||
"sinon": "^10.0.0",
|
||||
"streaming-iterables": "^5.0.4",
|
||||
"uint8arrays": "^2.1.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"aegir": "^25.0.0",
|
||||
"it-handshake": "^1.0.1",
|
||||
"@types/debug": "^4.1.5",
|
||||
"aegir": "^33.0.0",
|
||||
"cids": "^1.1.6",
|
||||
"events": "^3.3.0",
|
||||
"it-handshake": "^1.0.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "3.7.5"
|
||||
"util": "^0.12.3"
|
||||
},
|
||||
"contributors": [
|
||||
"Alan Shaw <alan.shaw@protocol.ai>",
|
||||
|
149
src/connection/connection.d.ts
vendored
149
src/connection/connection.d.ts
vendored
@ -1,149 +0,0 @@
|
||||
declare const _exports: typeof Connection;
|
||||
export = _exports;
|
||||
/**
|
||||
* An implementation of the js-libp2p connection.
|
||||
* Any libp2p transport should use an upgrader to return this connection.
|
||||
*/
|
||||
declare class Connection {
|
||||
/**
|
||||
* Creates an instance of Connection.
|
||||
* @param {object} properties properties of the connection.
|
||||
* @param {multiaddr} [properties.localAddr] local multiaddr of the connection if known.
|
||||
* @param {multiaddr} [properties.remoteAddr] remote multiaddr of the connection.
|
||||
* @param {PeerId} properties.localPeer local peer-id.
|
||||
* @param {PeerId} properties.remotePeer remote peer-id.
|
||||
* @param {function} properties.newStream new stream muxer function.
|
||||
* @param {function} properties.close close raw connection function.
|
||||
* @param {function(): Stream[]} properties.getStreams get streams from muxer function.
|
||||
* @param {object} properties.stat metadata of the connection.
|
||||
* @param {string} properties.stat.direction connection establishment direction ("inbound" or "outbound").
|
||||
* @param {object} properties.stat.timeline connection relevant events timestamp.
|
||||
* @param {string} properties.stat.timeline.open connection opening timestamp.
|
||||
* @param {string} properties.stat.timeline.upgraded connection upgraded timestamp.
|
||||
* @param {string} [properties.stat.multiplexer] connection multiplexing identifier.
|
||||
* @param {string} [properties.stat.encryption] connection encryption method identifier.
|
||||
*/
|
||||
constructor({ localAddr, remoteAddr, localPeer, remotePeer, newStream, close, getStreams, stat }: {
|
||||
localAddr?: import("multiaddr");
|
||||
remoteAddr?: import("multiaddr");
|
||||
localPeer: import("peer-id");
|
||||
remotePeer: import("peer-id");
|
||||
newStream: Function;
|
||||
close: Function;
|
||||
getStreams: () => any[];
|
||||
stat: {
|
||||
direction: string;
|
||||
timeline: {
|
||||
open: string;
|
||||
upgraded: string;
|
||||
};
|
||||
multiplexer?: string;
|
||||
encryption?: string;
|
||||
};
|
||||
});
|
||||
/**
|
||||
* Connection identifier.
|
||||
*/
|
||||
id: any;
|
||||
/**
|
||||
* Observed multiaddr of the local peer
|
||||
*/
|
||||
localAddr: import("multiaddr");
|
||||
/**
|
||||
* Observed multiaddr of the remote peer
|
||||
*/
|
||||
remoteAddr: import("multiaddr");
|
||||
/**
|
||||
* Local peer id.
|
||||
*/
|
||||
localPeer: import("peer-id");
|
||||
/**
|
||||
* Remote peer id.
|
||||
*/
|
||||
remotePeer: import("peer-id");
|
||||
/**
|
||||
* Connection metadata.
|
||||
*/
|
||||
_stat: {
|
||||
status: string;
|
||||
direction: string;
|
||||
timeline: {
|
||||
open: string;
|
||||
upgraded: string;
|
||||
};
|
||||
multiplexer?: string;
|
||||
encryption?: string;
|
||||
};
|
||||
/**
|
||||
* Reference to the new stream function of the multiplexer
|
||||
*/
|
||||
_newStream: Function;
|
||||
/**
|
||||
* Reference to the close function of the raw connection
|
||||
*/
|
||||
_close: Function;
|
||||
/**
|
||||
* Reference to the getStreams function of the muxer
|
||||
*/
|
||||
_getStreams: () => any[];
|
||||
/**
|
||||
* Connection streams registry
|
||||
*/
|
||||
registry: Map<any, any>;
|
||||
/**
|
||||
* User provided tags
|
||||
* @type {string[]}
|
||||
*/
|
||||
tags: string[];
|
||||
/**
|
||||
* Get connection metadata
|
||||
* @this {Connection}
|
||||
*/
|
||||
get stat(): {
|
||||
status: string;
|
||||
direction: string;
|
||||
timeline: {
|
||||
open: string;
|
||||
upgraded: string;
|
||||
};
|
||||
multiplexer?: string;
|
||||
encryption?: string;
|
||||
};
|
||||
/**
|
||||
* Get all the streams of the muxer.
|
||||
* @this {Connection}
|
||||
*/
|
||||
get streams(): any[];
|
||||
/**
|
||||
* Create a new stream from this connection
|
||||
* @param {string[]} protocols intended protocol for the stream
|
||||
* @return {Promise<{stream: Stream, protocol: string}>} with muxed+multistream-selected stream and selected protocol
|
||||
*/
|
||||
newStream(protocols: string[]): Promise<{
|
||||
stream: any;
|
||||
protocol: string;
|
||||
}>;
|
||||
/**
|
||||
* Add a stream when it is opened to the registry.
|
||||
* @param {*} muxedStream a muxed stream
|
||||
* @param {object} properties the stream properties to be registered
|
||||
* @param {string} properties.protocol the protocol used by the stream
|
||||
* @param {object} properties.metadata metadata of the stream
|
||||
* @return {void}
|
||||
*/
|
||||
addStream(muxedStream: any, { protocol, metadata }: {
|
||||
protocol: string;
|
||||
metadata: any;
|
||||
}): void;
|
||||
/**
|
||||
* Remove stream registry after it is closed.
|
||||
* @param {string} id identifier of the stream
|
||||
*/
|
||||
removeStream(id: string): void;
|
||||
/**
|
||||
* Close the connection.
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
_closing: any;
|
||||
}
|
@ -1,13 +1,246 @@
|
||||
'use strict'
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const multiaddr = require('multiaddr')
|
||||
const withIs = require('class-is')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const errCode = require('err-code')
|
||||
const Status = require('./status')
|
||||
const { OPEN, CLOSING, CLOSED } = require('./status')
|
||||
|
||||
const connectionSymbol = Symbol.for('@libp2p/interface-connection/connection')
|
||||
|
||||
/**
|
||||
* @typedef {import('../stream-muxer/types').MuxedStream} MuxedStream
|
||||
* @typedef {import('./status').Status} Status
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Timeline
|
||||
* @property {number} open - connection opening timestamp.
|
||||
* @property {number} [upgraded] - connection upgraded timestamp.
|
||||
* @property {number} [close]
|
||||
*
|
||||
* @typedef {Object} ConectionStat
|
||||
* @property {'inbound' | 'outbound'} direction - connection establishment direction
|
||||
* @property {Timeline} timeline - connection relevant events timestamp.
|
||||
* @property {string} [multiplexer] - connection multiplexing identifier.
|
||||
* @property {string} [encryption] - connection encryption method identifier.
|
||||
*
|
||||
* @typedef {Object} ConnectionOptions
|
||||
* @property {Multiaddr} [localAddr] - local multiaddr of the connection if known.
|
||||
* @property {Multiaddr} remoteAddr - remote multiaddr of the connection.
|
||||
* @property {PeerId} localPeer - local peer-id.
|
||||
* @property {PeerId} remotePeer - remote peer-id.
|
||||
* @property {(protocols: string|string[]) => Promise<{stream: MuxedStream, protocol: string}>} newStream - new stream muxer function.
|
||||
* @property {() => Promise<void>} close - close raw connection function.
|
||||
* @property {() => MuxedStream[]} getStreams - get streams from muxer function.
|
||||
* @property {ConectionStat} stat - metadata of the connection.
|
||||
*
|
||||
* @typedef {Object} StreamData
|
||||
* @property {string} protocol - the protocol used by the stream
|
||||
* @property {Object} [metadata] - metadata of the stream
|
||||
*/
|
||||
|
||||
/**
|
||||
* An implementation of the js-libp2p connection.
|
||||
* Any libp2p transport should use an upgrader to return this connection.
|
||||
*/
|
||||
class Connection {
|
||||
/**
|
||||
* An implementation of the js-libp2p connection.
|
||||
* Any libp2p transport should use an upgrader to return this connection.
|
||||
*
|
||||
* @class
|
||||
* @param {ConnectionOptions} options
|
||||
*/
|
||||
constructor ({ localAddr, remoteAddr, localPeer, remotePeer, newStream, close, getStreams, stat }) {
|
||||
validateArgs(localAddr, localPeer, remotePeer, newStream, close, getStreams, stat)
|
||||
|
||||
/**
|
||||
* Connection identifier.
|
||||
*/
|
||||
this.id = (parseInt(String(Math.random() * 1e9))).toString(36) + Date.now()
|
||||
|
||||
/**
|
||||
* Observed multiaddr of the local peer
|
||||
*/
|
||||
this.localAddr = localAddr
|
||||
|
||||
/**
|
||||
* Observed multiaddr of the remote peer
|
||||
*/
|
||||
this.remoteAddr = remoteAddr
|
||||
|
||||
/**
|
||||
* Local peer id.
|
||||
*/
|
||||
this.localPeer = localPeer
|
||||
|
||||
/**
|
||||
* Remote peer id.
|
||||
*/
|
||||
this.remotePeer = remotePeer
|
||||
|
||||
/**
|
||||
* Connection metadata.
|
||||
*
|
||||
* @type {ConectionStat & {status: Status}}
|
||||
*/
|
||||
this._stat = {
|
||||
...stat,
|
||||
status: OPEN
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference to the new stream function of the multiplexer
|
||||
*/
|
||||
this._newStream = newStream
|
||||
|
||||
/**
|
||||
* Reference to the close function of the raw connection
|
||||
*/
|
||||
this._close = close
|
||||
|
||||
/**
|
||||
* Reference to the getStreams function of the muxer
|
||||
*/
|
||||
this._getStreams = getStreams
|
||||
|
||||
/**
|
||||
* Connection streams registry
|
||||
*/
|
||||
this.registry = new Map()
|
||||
|
||||
/**
|
||||
* User provided tags
|
||||
*
|
||||
* @type {string[]}
|
||||
*/
|
||||
this.tags = []
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag] () {
|
||||
return 'Connection'
|
||||
}
|
||||
|
||||
get [connectionSymbol] () {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given value is a `Connection` instance.
|
||||
*
|
||||
* @param {any} other
|
||||
* @returns {other is Connection}
|
||||
*/
|
||||
static isConnection (other) {
|
||||
return Boolean(other && other[connectionSymbol])
|
||||
}
|
||||
|
||||
/**
|
||||
* Get connection metadata
|
||||
*
|
||||
* @this {Connection}
|
||||
*/
|
||||
get stat () {
|
||||
return this._stat
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the streams of the muxer.
|
||||
*
|
||||
* @this {Connection}
|
||||
*/
|
||||
get streams () {
|
||||
return this._getStreams()
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new stream from this connection
|
||||
*
|
||||
* @param {string|string[]} protocols - intended protocol for the stream
|
||||
* @returns {Promise<{stream: MuxedStream, protocol: string}>} with muxed+multistream-selected stream and selected protocol
|
||||
*/
|
||||
async newStream (protocols) {
|
||||
if (this.stat.status === CLOSING) {
|
||||
throw errCode(new Error('the connection is being closed'), 'ERR_CONNECTION_BEING_CLOSED')
|
||||
}
|
||||
|
||||
if (this.stat.status === CLOSED) {
|
||||
throw errCode(new Error('the connection is closed'), 'ERR_CONNECTION_CLOSED')
|
||||
}
|
||||
|
||||
if (!Array.isArray(protocols)) protocols = [protocols]
|
||||
|
||||
const { stream, protocol } = await this._newStream(protocols)
|
||||
|
||||
this.addStream(stream, { protocol })
|
||||
|
||||
return {
|
||||
stream,
|
||||
protocol
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a stream when it is opened to the registry.
|
||||
*
|
||||
* @param {MuxedStream} muxedStream - a muxed stream
|
||||
* @param {StreamData} data - the stream data to be registered
|
||||
* @returns {void}
|
||||
*/
|
||||
addStream (muxedStream, { protocol, metadata = {} }) {
|
||||
// Add metadata for the stream
|
||||
this.registry.set(muxedStream.id, {
|
||||
protocol,
|
||||
...metadata
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove stream registry after it is closed.
|
||||
*
|
||||
* @param {string} id - identifier of the stream
|
||||
*/
|
||||
removeStream (id) {
|
||||
this.registry.delete(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection.
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async close () {
|
||||
if (this.stat.status === CLOSED) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this._closing) {
|
||||
return this._closing
|
||||
}
|
||||
|
||||
this.stat.status = CLOSING
|
||||
|
||||
// Close raw connection
|
||||
this._closing = await this._close()
|
||||
|
||||
this._stat.timeline.close = Date.now()
|
||||
this.stat.status = CLOSED
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Connection
|
||||
|
||||
/**
|
||||
* @param {Multiaddr|undefined} localAddr
|
||||
* @param {PeerId} localPeer
|
||||
* @param {PeerId} remotePeer
|
||||
* @param {(protocols: string | string[]) => Promise<{ stream: import("../stream-muxer/types").MuxedStream; protocol: string; }>} newStream
|
||||
* @param {() => Promise<void>} close
|
||||
* @param {() => import("../stream-muxer/types").MuxedStream[]} getStreams
|
||||
* @param {{ direction: any; timeline: any; multiplexer?: string | undefined; encryption?: string | undefined; }} stat
|
||||
*/
|
||||
function validateArgs (localAddr, localPeer, remotePeer, newStream, close, getStreams, stat) {
|
||||
if (localAddr && !multiaddr.isMultiaddr(localAddr)) {
|
||||
if (localAddr && !Multiaddr.isMultiaddr(localAddr)) {
|
||||
throw errCode(new Error('localAddr must be an instance of multiaddr'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
@ -51,184 +284,3 @@ function validateArgs (localAddr, localPeer, remotePeer, newStream, close, getSt
|
||||
throw errCode(new Error('connection upgraded timestamp must be provided'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An implementation of the js-libp2p connection.
|
||||
* Any libp2p transport should use an upgrader to return this connection.
|
||||
*/
|
||||
class Connection {
|
||||
/**
|
||||
* Creates an instance of Connection.
|
||||
* @param {object} properties properties of the connection.
|
||||
* @param {multiaddr} [properties.localAddr] local multiaddr of the connection if known.
|
||||
* @param {multiaddr} [properties.remoteAddr] remote multiaddr of the connection.
|
||||
* @param {PeerId} properties.localPeer local peer-id.
|
||||
* @param {PeerId} properties.remotePeer remote peer-id.
|
||||
* @param {function} properties.newStream new stream muxer function.
|
||||
* @param {function} properties.close close raw connection function.
|
||||
* @param {function(): Stream[]} properties.getStreams get streams from muxer function.
|
||||
* @param {object} properties.stat metadata of the connection.
|
||||
* @param {string} properties.stat.direction connection establishment direction ("inbound" or "outbound").
|
||||
* @param {object} properties.stat.timeline connection relevant events timestamp.
|
||||
* @param {string} properties.stat.timeline.open connection opening timestamp.
|
||||
* @param {string} properties.stat.timeline.upgraded connection upgraded timestamp.
|
||||
* @param {string} [properties.stat.multiplexer] connection multiplexing identifier.
|
||||
* @param {string} [properties.stat.encryption] connection encryption method identifier.
|
||||
*/
|
||||
constructor ({ localAddr, remoteAddr, localPeer, remotePeer, newStream, close, getStreams, stat }) {
|
||||
validateArgs(localAddr, localPeer, remotePeer, newStream, close, getStreams, stat)
|
||||
|
||||
/**
|
||||
* Connection identifier.
|
||||
*/
|
||||
this.id = (parseInt(Math.random() * 1e9)).toString(36) + Date.now()
|
||||
|
||||
/**
|
||||
* Observed multiaddr of the local peer
|
||||
*/
|
||||
this.localAddr = localAddr
|
||||
|
||||
/**
|
||||
* Observed multiaddr of the remote peer
|
||||
*/
|
||||
this.remoteAddr = remoteAddr
|
||||
|
||||
/**
|
||||
* Local peer id.
|
||||
*/
|
||||
this.localPeer = localPeer
|
||||
|
||||
/**
|
||||
* Remote peer id.
|
||||
*/
|
||||
this.remotePeer = remotePeer
|
||||
|
||||
/**
|
||||
* Connection metadata.
|
||||
*/
|
||||
this._stat = {
|
||||
...stat,
|
||||
status: Status.OPEN
|
||||
}
|
||||
|
||||
/**
|
||||
* Reference to the new stream function of the multiplexer
|
||||
*/
|
||||
this._newStream = newStream
|
||||
|
||||
/**
|
||||
* Reference to the close function of the raw connection
|
||||
*/
|
||||
this._close = close
|
||||
|
||||
/**
|
||||
* Reference to the getStreams function of the muxer
|
||||
*/
|
||||
this._getStreams = getStreams
|
||||
|
||||
/**
|
||||
* Connection streams registry
|
||||
*/
|
||||
this.registry = new Map()
|
||||
|
||||
/**
|
||||
* User provided tags
|
||||
* @type {string[]}
|
||||
*/
|
||||
this.tags = []
|
||||
}
|
||||
|
||||
/**
|
||||
* Get connection metadata
|
||||
* @this {Connection}
|
||||
*/
|
||||
get stat () {
|
||||
return this._stat
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the streams of the muxer.
|
||||
* @this {Connection}
|
||||
*/
|
||||
get streams () {
|
||||
return this._getStreams()
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new stream from this connection
|
||||
* @param {string[]} protocols intended protocol for the stream
|
||||
* @return {Promise<{stream: Stream, protocol: string}>} with muxed+multistream-selected stream and selected protocol
|
||||
*/
|
||||
async newStream (protocols) {
|
||||
if (this.stat.status === Status.CLOSING) {
|
||||
throw errCode(new Error('the connection is being closed'), 'ERR_CONNECTION_BEING_CLOSED')
|
||||
}
|
||||
|
||||
if (this.stat.status === Status.CLOSED) {
|
||||
throw errCode(new Error('the connection is closed'), 'ERR_CONNECTION_CLOSED')
|
||||
}
|
||||
|
||||
if (!Array.isArray(protocols)) protocols = [protocols]
|
||||
|
||||
const { stream, protocol } = await this._newStream(protocols)
|
||||
|
||||
this.addStream(stream, { protocol })
|
||||
|
||||
return {
|
||||
stream,
|
||||
protocol
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a stream when it is opened to the registry.
|
||||
* @param {*} muxedStream a muxed stream
|
||||
* @param {object} properties the stream properties to be registered
|
||||
* @param {string} properties.protocol the protocol used by the stream
|
||||
* @param {object} properties.metadata metadata of the stream
|
||||
* @return {void}
|
||||
*/
|
||||
addStream (muxedStream, { protocol, metadata = {} }) {
|
||||
// Add metadata for the stream
|
||||
this.registry.set(muxedStream.id, {
|
||||
protocol,
|
||||
...metadata
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove stream registry after it is closed.
|
||||
* @param {string} id identifier of the stream
|
||||
*/
|
||||
removeStream (id) {
|
||||
this.registry.delete(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the connection.
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
async close () {
|
||||
if (this.stat.status === Status.CLOSED) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this._closing) {
|
||||
return this._closing
|
||||
}
|
||||
|
||||
this.stat.status = Status.CLOSING
|
||||
|
||||
// Close raw connection
|
||||
this._closing = await this._close()
|
||||
|
||||
this._stat.timeline.close = Date.now()
|
||||
this.stat.status = Status.CLOSED
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @module
|
||||
* @type {typeof Connection}
|
||||
*/
|
||||
module.exports = withIs(Connection, { className: 'Connection', symbolName: '@libp2p/interface-connection/connection' })
|
||||
|
1
src/connection/index.d.ts
vendored
1
src/connection/index.d.ts
vendored
@ -1 +0,0 @@
|
||||
export var Connection: typeof import('./connection');
|
@ -1,7 +1,3 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* @module connection/index
|
||||
* @type {typeof import('./connection')}
|
||||
*/
|
||||
exports.Connection = require('./connection')
|
||||
|
3
src/connection/status.d.ts
vendored
3
src/connection/status.d.ts
vendored
@ -1,3 +0,0 @@
|
||||
export declare const OPEN: string;
|
||||
export declare const CLOSING: string;
|
||||
export declare const CLOSED: string;
|
@ -1,7 +1,12 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
OPEN: 'open',
|
||||
CLOSING: 'closing',
|
||||
CLOSED: 'closed'
|
||||
const STATUS = {
|
||||
OPEN: /** @type {'open'} */('open'),
|
||||
CLOSING: /** @type {'closing'} */('closing'),
|
||||
CLOSED: /** @type {'closed'} */('closed')
|
||||
}
|
||||
module.exports = STATUS
|
||||
|
||||
/**
|
||||
* @typedef {STATUS[keyof STATUS]} Status
|
||||
*/
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
|
||||
'use strict'
|
||||
@ -74,6 +75,7 @@ module.exports = (test) => {
|
||||
let timelineProxy
|
||||
const proxyHandler = {
|
||||
set () {
|
||||
// @ts-ignore - TS fails to infer here
|
||||
return Reflect.set(...arguments)
|
||||
}
|
||||
}
|
||||
@ -138,7 +140,9 @@ module.exports = (test) => {
|
||||
expect(connection.stat.timeline.close).to.not.exist()
|
||||
|
||||
await connection.close()
|
||||
// @ts-ignore - fails to infer callCount
|
||||
expect(proxyHandler.set.callCount).to.equal(1)
|
||||
// @ts-ignore - fails to infer getCall
|
||||
const [obj, key, value] = proxyHandler.set.getCall(0).args
|
||||
expect(obj).to.eql(connection.stat.timeline)
|
||||
expect(key).to.equal('close')
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
|
||||
'use strict'
|
||||
|
11
src/content-routing/types.d.ts
vendored
Normal file
11
src/content-routing/types.d.ts
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
export = ContentRouting;
|
||||
|
||||
import PeerId from 'peer-id'
|
||||
import Multiaddr from 'multiaddr'
|
||||
import CID from 'cids'
|
||||
|
||||
declare class ContentRouting {
|
||||
constructor (options: Object);
|
||||
provide (cid: CID): Promise<void>;
|
||||
findProviders (cid: CID, options: Object): AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>;
|
||||
}
|
15
src/crypto/errors.d.ts
vendored
15
src/crypto/errors.d.ts
vendored
@ -1,15 +0,0 @@
|
||||
export class UnexpectedPeerError extends Error {
|
||||
static get code(): string;
|
||||
constructor(message?: string);
|
||||
code: string;
|
||||
}
|
||||
export class InvalidCryptoExchangeError extends Error {
|
||||
static get code(): string;
|
||||
constructor(message?: string);
|
||||
code: string;
|
||||
}
|
||||
export class InvalidCryptoTransmissionError extends Error {
|
||||
static get code(): string;
|
||||
constructor(message?: string);
|
||||
code: string;
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
@ -6,7 +7,7 @@ const expect = chai.expect
|
||||
chai.use(require('dirty-chai'))
|
||||
|
||||
const duplexPair = require('it-pair/duplex')
|
||||
const pipe = require('it-pipe')
|
||||
const { pipe } = require('it-pipe')
|
||||
const PeerId = require('peer-id')
|
||||
const { collect } = require('streaming-iterables')
|
||||
const uint8arrayFromString = require('uint8arrays/from-string')
|
||||
|
24
src/crypto/types.d.ts
vendored
Normal file
24
src/crypto/types.d.ts
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
import PeerId from 'peer-id'
|
||||
import { MultiaddrConnection } from '../transport/types'
|
||||
|
||||
/**
|
||||
* A libp2p crypto module must be compliant to this interface
|
||||
* to ensure all exchanged data between two peers is encrypted.
|
||||
*/
|
||||
export interface Crypto {
|
||||
protocol: string;
|
||||
/**
|
||||
* Encrypt outgoing data to the remote party.
|
||||
*/
|
||||
secureOutbound(localPeer: PeerId, connection: MultiaddrConnection, remotePeer: PeerId): Promise<SecureOutbound>;
|
||||
/**
|
||||
* Decrypt incoming data.
|
||||
*/
|
||||
secureInbound(localPeer: PeerId, connection: MultiaddrConnection, remotePeer?: PeerId): Promise<SecureOutbound>;
|
||||
}
|
||||
|
||||
export type SecureOutbound = {
|
||||
conn: MultiaddrConnection;
|
||||
remoteEarlyData: Buffer;
|
||||
remotePeer: PeerId;
|
||||
}
|
0
src/index.d.ts
vendored
0
src/index.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
@ -5,7 +6,7 @@ const chai = require('chai')
|
||||
const expect = chai.expect
|
||||
chai.use(require('dirty-chai'))
|
||||
|
||||
const multiaddr = require('multiaddr')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const delay = require('delay')
|
||||
@ -54,7 +55,7 @@ module.exports = (common) => {
|
||||
expect(PeerId.isPeerId(id)).to.eql(true)
|
||||
expect(multiaddrs).to.exist()
|
||||
|
||||
multiaddrs.forEach((m) => expect(multiaddr.isMultiaddr(m)).to.eql(true))
|
||||
multiaddrs.forEach((m) => expect(Multiaddr.isMultiaddr(m)).to.eql(true))
|
||||
|
||||
defer.resolve()
|
||||
})
|
||||
|
10
src/peer-discovery/types.d.ts
vendored
Normal file
10
src/peer-discovery/types.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
export = PeerDiscovery;
|
||||
|
||||
import events from 'events';
|
||||
|
||||
declare class PeerDiscovery extends events.EventEmitter {
|
||||
constructor (options: Object);
|
||||
start (): Promise<void>;
|
||||
stop (): Promise<void>;
|
||||
tag: string;
|
||||
}
|
10
src/peer-routing/types.d.ts
vendored
Normal file
10
src/peer-routing/types.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
export = PeerRouting;
|
||||
|
||||
import PeerId from 'peer-id'
|
||||
import Multiaddr from 'multiaddr'
|
||||
|
||||
declare class PeerRouting {
|
||||
constructor (options?: Object);
|
||||
findPeer (peerId: PeerId, options?: Object): Promise<{ id: PeerId, multiaddrs: Multiaddr[] }>;
|
||||
getClosestPeers(key: Uint8Array, options?: Object): AsyncIterable<{ id: PeerId, multiaddrs: Multiaddr[] }>;
|
||||
}
|
@ -11,6 +11,9 @@ Table of Contents
|
||||
* [Extend interface](#extend-interface)
|
||||
* [Example](#example)
|
||||
* [API](#api)
|
||||
* [Constructor](#constructor)
|
||||
* [new Pubsub(options)](#new-pubsuboptions)
|
||||
* [Parameters](#parameters)
|
||||
* [Start](#start)
|
||||
* [pubsub.start()](#pubsubstart)
|
||||
* [Returns](#returns)
|
||||
@ -19,24 +22,24 @@ Table of Contents
|
||||
* [Returns](#returns-1)
|
||||
* [Publish](#publish)
|
||||
* [pubsub.publish(topics, message)](#pubsubpublishtopics-message)
|
||||
* [Parameters](#parameters)
|
||||
* [Parameters](#parameters-1)
|
||||
* [Returns](#returns-2)
|
||||
* [Subscribe](#subscribe)
|
||||
* [pubsub.subscribe(topic)](#pubsubsubscribetopic)
|
||||
* [Parameters](#parameters-1)
|
||||
* [Parameters](#parameters-2)
|
||||
* [Unsubscribe](#unsubscribe)
|
||||
* [pubsub.unsubscribe(topic)](#pubsubunsubscribetopic)
|
||||
* [Parameters](#parameters-2)
|
||||
* [Parameters](#parameters-3)
|
||||
* [Get Topics](#get-topics)
|
||||
* [pubsub.getTopics()](#pubsubgettopics)
|
||||
* [Returns](#returns-3)
|
||||
* [Get Peers Subscribed to a topic](#get-peers-subscribed-to-a-topic)
|
||||
* [pubsub.getSubscribers(topic)](#pubsubgetsubscriberstopic)
|
||||
* [Parameters](#parameters-3)
|
||||
* [Parameters](#parameters-4)
|
||||
* [Returns](#returns-4)
|
||||
* [Validate](#validate)
|
||||
* [pubsub.validate(message)](#pubsubvalidatemessage)
|
||||
* [Parameters](#parameters-4)
|
||||
* [Parameters](#parameters-5)
|
||||
* [Returns](#returns-5)
|
||||
* [Test suite usage](#test-suite-usage)
|
||||
|
||||
@ -49,7 +52,7 @@ You can check the following implementations as examples for building your own pu
|
||||
|
||||
## Interface usage
|
||||
|
||||
`interface-pubsub` abstracts the implementation protocol registration within `libp2p` and takes care of all the protocol connections and streams, as well as the subscription management. This way, a pubsub implementation can focus on its message routing algorithm, instead of also needing to create the setup for it.
|
||||
`interface-pubsub` abstracts the implementation protocol registration within `libp2p` and takes care of all the protocol connections and streams, as well as the subscription management and the features describe in the libp2p [pubsub specs](https://github.com/libp2p/specs/tree/master/pubsub). This way, a pubsub implementation can focus on its message routing algorithm, instead of also needing to create the setup for it.
|
||||
|
||||
### Extend interface
|
||||
|
||||
@ -74,7 +77,7 @@ All the remaining functions **MUST NOT** be overwritten.
|
||||
The following example aims to show how to create your pubsub implementation extending this base protocol. The pubsub implementation will handle the subscriptions logic.
|
||||
|
||||
```JavaScript
|
||||
const Pubsub = require('libp2p-pubsub')
|
||||
const Pubsub = require('libp2p-interfaces/src/pubsub')
|
||||
|
||||
class PubsubImplementation extends Pubsub {
|
||||
constructor({ libp2p, options })
|
||||
@ -82,8 +85,7 @@ class PubsubImplementation extends Pubsub {
|
||||
debugName: 'libp2p:pubsub',
|
||||
multicodecs: '/pubsub-implementation/1.0.0',
|
||||
libp2p,
|
||||
signMessages: options.signMessages,
|
||||
strictSigning: options.strictSigning
|
||||
globalSigningPolicy: options.globalSigningPolicy
|
||||
})
|
||||
}
|
||||
|
||||
@ -98,6 +100,23 @@ class PubsubImplementation extends Pubsub {
|
||||
|
||||
The interface aims to specify a common interface that all pubsub router implementation should follow. A pubsub router implementation should extend the [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter). When peers receive pubsub messages, these messages will be emitted by the event emitter where the `eventName` will be the `topic` associated with the message.
|
||||
|
||||
### Constructor
|
||||
|
||||
The base class constructor configures the pubsub instance for use with a libp2p instance. It includes settings for logging, signature policies, etc.
|
||||
|
||||
#### `new Pubsub({options})`
|
||||
|
||||
##### Parameters
|
||||
|
||||
| Name | Type | Description | Default |
|
||||
|------|------|-------------|---------|
|
||||
| options.libp2p | `Libp2p` | libp2p instance | required, no default |
|
||||
| options.debugName | `string` | log namespace | required, no default |
|
||||
| options.multicodecs | `string \| Array<string>` | protocol identifier(s) | required, no default |
|
||||
| options.globalSignaturePolicy | `'StrictSign' \| 'StrictNoSign'` | signature policy to be globally applied | `'StrictSign'` |
|
||||
| options.canRelayMessage | `boolean` | if can relay messages if not subscribed | `false` |
|
||||
| options.emitSelf | `boolean` | if `publish` should emit to self, if subscribed | `false` |
|
||||
|
||||
### Start
|
||||
|
||||
Starts the pubsub subsystem. The protocol will be registered to `libp2p`, which will result in pubsub being notified when peers who support the protocol connect/disconnect to `libp2p`.
|
||||
@ -185,7 +204,7 @@ Get a list of the [PeerId](https://github.com/libp2p/js-peer-id) strings that ar
|
||||
|
||||
### Validate
|
||||
|
||||
Validates the signature of a message.
|
||||
Validates a message according to the signature policy and topic-specific validation function.
|
||||
|
||||
#### `pubsub.validate(message)`
|
||||
|
||||
|
4
src/pubsub/errors.d.ts
vendored
4
src/pubsub/errors.d.ts
vendored
@ -1,4 +0,0 @@
|
||||
export namespace codes {
|
||||
export const ERR_MISSING_SIGNATURE: string;
|
||||
export const ERR_INVALID_SIGNATURE: string;
|
||||
}
|
@ -1,6 +1,46 @@
|
||||
'use strict'
|
||||
|
||||
exports.codes = {
|
||||
/**
|
||||
* Signature policy is invalid
|
||||
*/
|
||||
ERR_INVALID_SIGNATURE_POLICY: 'ERR_INVALID_SIGNATURE_POLICY',
|
||||
/**
|
||||
* Signature policy is unhandled
|
||||
*/
|
||||
ERR_UNHANDLED_SIGNATURE_POLICY: 'ERR_UNHANDLED_SIGNATURE_POLICY',
|
||||
|
||||
// Strict signing codes
|
||||
|
||||
/**
|
||||
* Message expected to have a `signature`, but doesn't
|
||||
*/
|
||||
ERR_MISSING_SIGNATURE: 'ERR_MISSING_SIGNATURE',
|
||||
ERR_INVALID_SIGNATURE: 'ERR_INVALID_SIGNATURE'
|
||||
/**
|
||||
* Message expected to have a `seqno`, but doesn't
|
||||
*/
|
||||
ERR_MISSING_SEQNO: 'ERR_MISSING_SEQNO',
|
||||
/**
|
||||
* Message `signature` is invalid
|
||||
*/
|
||||
ERR_INVALID_SIGNATURE: 'ERR_INVALID_SIGNATURE',
|
||||
|
||||
// Strict no-signing codes
|
||||
|
||||
/**
|
||||
* Message expected to not have a `from`, but does
|
||||
*/
|
||||
ERR_UNEXPECTED_FROM: 'ERR_UNEXPECTED_FROM',
|
||||
/**
|
||||
* Message expected to not have a `signature`, but does
|
||||
*/
|
||||
ERR_UNEXPECTED_SIGNATURE: 'ERR_UNEXPECTED_SIGNATURE',
|
||||
/**
|
||||
* Message expected to not have a `key`, but does
|
||||
*/
|
||||
ERR_UNEXPECTED_KEY: 'ERR_UNEXPECTED_KEY',
|
||||
/**
|
||||
* Message expected to not have a `seqno`, but does
|
||||
*/
|
||||
ERR_UNEXPECTED_SEQNO: 'ERR_UNEXPECTED_SEQNO'
|
||||
}
|
||||
|
307
src/pubsub/index.d.ts
vendored
307
src/pubsub/index.d.ts
vendored
@ -1,307 +0,0 @@
|
||||
export = PubsubBaseProtocol;
|
||||
/**
|
||||
* @typedef {Object} InMessage
|
||||
* @property {string} [from]
|
||||
* @property {string} receivedFrom
|
||||
* @property {string[]} topicIDs
|
||||
* @property {Uint8Array} [seqno]
|
||||
* @property {Uint8Array} data
|
||||
* @property {Uint8Array} [signature]
|
||||
* @property {Uint8Array} [key]
|
||||
*
|
||||
* @typedef PeerId
|
||||
* @type import('peer-id')
|
||||
*/
|
||||
/**
|
||||
* PubsubBaseProtocol handles the peers and connections logic for pubsub routers
|
||||
* and specifies the API that pubsub routers should have.
|
||||
*/
|
||||
declare class PubsubBaseProtocol {
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @param {String} props.debugName log namespace
|
||||
* @param {Array<string>|string} props.multicodecs protocol identificers to connect
|
||||
* @param {Libp2p} props.libp2p
|
||||
* @param {boolean} [props.signMessages = true] if messages should be signed
|
||||
* @param {boolean} [props.strictSigning = true] if message signing should be required
|
||||
* @param {boolean} [props.canRelayMessage = false] if can relay messages not subscribed
|
||||
* @param {boolean} [props.emitSelf = false] if publish should emit to self, if subscribed
|
||||
* @abstract
|
||||
*/
|
||||
constructor({ debugName, multicodecs, libp2p, signMessages, strictSigning, canRelayMessage, emitSelf }: {
|
||||
debugName: string;
|
||||
multicodecs: string | string[];
|
||||
libp2p: any;
|
||||
signMessages?: boolean;
|
||||
strictSigning?: boolean;
|
||||
canRelayMessage?: boolean;
|
||||
emitSelf?: boolean;
|
||||
});
|
||||
log: any;
|
||||
/**
|
||||
* @type {Array<string>}
|
||||
*/
|
||||
multicodecs: Array<string>;
|
||||
_libp2p: any;
|
||||
registrar: any;
|
||||
/**
|
||||
* @type {PeerId}
|
||||
*/
|
||||
peerId: PeerId;
|
||||
started: boolean;
|
||||
/**
|
||||
* Map of topics to which peers are subscribed to
|
||||
*
|
||||
* @type {Map<string, Set<string>>}
|
||||
*/
|
||||
topics: Map<string, Set<string>>;
|
||||
/**
|
||||
* List of our subscriptions
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
subscriptions: Set<string>;
|
||||
/**
|
||||
* Map of peer streams
|
||||
*
|
||||
* @type {Map<string, import('./peer-streams')>}
|
||||
*/
|
||||
peers: Map<string, import('./peer-streams')>;
|
||||
signMessages: boolean;
|
||||
/**
|
||||
* If message signing should be required for incoming messages
|
||||
* @type {boolean}
|
||||
*/
|
||||
strictSigning: boolean;
|
||||
/**
|
||||
* If router can relay received messages, even if not subscribed
|
||||
* @type {boolean}
|
||||
*/
|
||||
canRelayMessage: boolean;
|
||||
/**
|
||||
* if publish should emit to self, if subscribed
|
||||
* @type {boolean}
|
||||
*/
|
||||
emitSelf: boolean;
|
||||
/**
|
||||
* Topic validator function
|
||||
* @typedef {function(string, InMessage): Promise<void>} validator
|
||||
*/
|
||||
/**
|
||||
* Topic validator map
|
||||
*
|
||||
* Keyed by topic
|
||||
* Topic validators are functions with the following input:
|
||||
* @type {Map<string, validator>}
|
||||
*/
|
||||
topicValidators: Map<string, validator>;
|
||||
_registrarId: any;
|
||||
/**
|
||||
* On an inbound stream opened.
|
||||
* @private
|
||||
* @param {Object} props
|
||||
* @param {string} props.protocol
|
||||
* @param {DuplexIterableStream} props.stream
|
||||
* @param {Connection} props.connection connection
|
||||
*/
|
||||
_onIncomingStream({ protocol, stream, connection }: {
|
||||
protocol: string;
|
||||
stream: any;
|
||||
connection: any;
|
||||
}): void;
|
||||
/**
|
||||
* Registrar notifies an established connection with pubsub protocol.
|
||||
* @private
|
||||
* @param {PeerId} peerId remote peer-id
|
||||
* @param {Connection} conn connection to the peer
|
||||
*/
|
||||
_onPeerConnected(peerId: import("peer-id"), conn: any): Promise<void>;
|
||||
/**
|
||||
* Registrar notifies a closing connection with pubsub protocol.
|
||||
* @private
|
||||
* @param {PeerId} peerId peerId
|
||||
* @param {Error} err error for connection end
|
||||
*/
|
||||
_onPeerDisconnected(peerId: import("peer-id"), err: Error): void;
|
||||
/**
|
||||
* Register the pubsub protocol onto the libp2p node.
|
||||
* @returns {void}
|
||||
*/
|
||||
start(): void;
|
||||
/**
|
||||
* Unregister the pubsub protocol and the streams with other peers will be closed.
|
||||
* @returns {void}
|
||||
*/
|
||||
stop(): void;
|
||||
/**
|
||||
* Notifies the router that a peer has been connected
|
||||
* @private
|
||||
* @param {PeerId} peerId
|
||||
* @param {string} protocol
|
||||
* @returns {PeerStreams}
|
||||
*/
|
||||
_addPeer(peerId: import("peer-id"), protocol: string): import("./peer-streams");
|
||||
/**
|
||||
* Notifies the router that a peer has been disconnected.
|
||||
* @private
|
||||
* @param {PeerId} peerId
|
||||
* @returns {PeerStreams | undefined}
|
||||
*/
|
||||
_removePeer(peerId: import("peer-id")): import("./peer-streams");
|
||||
/**
|
||||
* Responsible for processing each RPC message received by other peers.
|
||||
* @param {string} idB58Str peer id string in base58
|
||||
* @param {DuplexIterableStream} stream inbound stream
|
||||
* @param {PeerStreams} peerStreams PubSub peer
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
_processMessages(idB58Str: string, stream: any, peerStreams: import("./peer-streams")): Promise<void>;
|
||||
/**
|
||||
* Handles an rpc request from a peer
|
||||
* @param {String} idB58Str
|
||||
* @param {PeerStreams} peerStreams
|
||||
* @param {RPC} rpc
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_processRpc(idB58Str: string, peerStreams: import("./peer-streams"), rpc: any): boolean;
|
||||
/**
|
||||
* Handles a subscription change from a peer
|
||||
* @param {string} id
|
||||
* @param {RPC.SubOpt} subOpt
|
||||
*/
|
||||
_processRpcSubOpt(id: string, subOpt: any): void;
|
||||
/**
|
||||
* Handles an message from a peer
|
||||
* @param {InMessage} msg
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
_processRpcMessage(msg: InMessage): Promise<void>;
|
||||
/**
|
||||
* Emit a message from a peer
|
||||
* @param {InMessage} message
|
||||
*/
|
||||
_emitMessage(message: InMessage): void;
|
||||
/**
|
||||
* The default msgID implementation
|
||||
* Child class can override this.
|
||||
* @param {RPC.Message} msg the message object
|
||||
* @returns {string} message id as string
|
||||
*/
|
||||
getMsgId(msg: any): string;
|
||||
/**
|
||||
* Whether to accept a message from a peer
|
||||
* Override to create a graylist
|
||||
* @override
|
||||
* @param {string} id
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_acceptFrom(id: string): boolean;
|
||||
/**
|
||||
* Decode Uint8Array into an RPC object.
|
||||
* This can be override to use a custom router protobuf.
|
||||
* @param {Uint8Array} bytes
|
||||
* @returns {RPC}
|
||||
*/
|
||||
_decodeRpc(bytes: Uint8Array): any;
|
||||
/**
|
||||
* Encode RPC object into a Uint8Array.
|
||||
* This can be override to use a custom router protobuf.
|
||||
* @param {RPC} rpc
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
_encodeRpc(rpc: any): Uint8Array;
|
||||
/**
|
||||
* Send an rpc object to a peer
|
||||
* @param {string} id peer id
|
||||
* @param {RPC} rpc
|
||||
* @returns {void}
|
||||
*/
|
||||
_sendRpc(id: string, rpc: any): void;
|
||||
/**
|
||||
* Send subscroptions to a peer
|
||||
* @param {string} id peer id
|
||||
* @param {string[]} topics
|
||||
* @param {boolean} subscribe set to false for unsubscriptions
|
||||
* @returns {void}
|
||||
*/
|
||||
_sendSubscriptions(id: string, topics: string[], subscribe: boolean): void;
|
||||
/**
|
||||
* Validates the given message. The signature will be checked for authenticity.
|
||||
* Throws an error on invalid messages
|
||||
* @param {InMessage} message
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
validate(message: InMessage): Promise<void>;
|
||||
/**
|
||||
* Normalizes the message and signs it, if signing is enabled.
|
||||
* Should be used by the routers to create the message to send.
|
||||
* @private
|
||||
* @param {Message} message
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
_buildMessage(message: any): Promise<any>;
|
||||
/**
|
||||
* Get a list of the peer-ids that are subscribed to one topic.
|
||||
* @param {string} topic
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
getSubscribers(topic: string): string[];
|
||||
/**
|
||||
* Publishes messages to all subscribed peers
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @param {Buffer} message
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
publish(topic: string, message: Buffer): Promise<void>;
|
||||
/**
|
||||
* Overriding the implementation of publish should handle the appropriate algorithms for the publish/subscriber implementation.
|
||||
* For example, a Floodsub implementation might simply publish each message to each topic for every peer
|
||||
* @abstract
|
||||
* @param {InMessage} message
|
||||
* @returns {Promise<void>}
|
||||
*
|
||||
*/
|
||||
_publish(message: InMessage): Promise<void>;
|
||||
/**
|
||||
* Subscribes to a given topic.
|
||||
* @abstract
|
||||
* @param {string} topic
|
||||
* @returns {void}
|
||||
*/
|
||||
subscribe(topic: string): void;
|
||||
/**
|
||||
* Unsubscribe from the given topic.
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @returns {void}
|
||||
*/
|
||||
unsubscribe(topic: string): void;
|
||||
/**
|
||||
* Get the list of topics which the peer is subscribed to.
|
||||
* @override
|
||||
* @returns {Array<String>}
|
||||
*/
|
||||
getTopics(): string[];
|
||||
}
|
||||
declare namespace PubsubBaseProtocol {
|
||||
export { message, utils, InMessage, PeerId };
|
||||
}
|
||||
type PeerId = import("peer-id");
|
||||
/**
|
||||
* Topic validator function
|
||||
*/
|
||||
type validator = (arg0: string, arg1: InMessage) => Promise<void>;
|
||||
type InMessage = {
|
||||
from?: string;
|
||||
receivedFrom: string;
|
||||
topicIDs: string[];
|
||||
seqno?: Uint8Array;
|
||||
data: Uint8Array;
|
||||
signature?: Uint8Array;
|
||||
key?: Uint8Array;
|
||||
};
|
||||
/**
|
||||
* @type {typeof import('./message')}
|
||||
*/
|
||||
declare const message: typeof import('./message');
|
||||
declare const utils: typeof import("./utils");
|
@ -1,18 +1,19 @@
|
||||
'use strict'
|
||||
|
||||
const debug = require('debug')
|
||||
/** @typedef {import('../types').EventEmitterFactory} Events */
|
||||
/** @type Events */
|
||||
const EventEmitter = require('events')
|
||||
const errcode = require('err-code')
|
||||
|
||||
const pipe = require('it-pipe')
|
||||
const { pipe } = require('it-pipe')
|
||||
|
||||
const MulticodecTopology = require('../topology/multicodec-topology')
|
||||
const { codes } = require('./errors')
|
||||
/**
|
||||
* @type {typeof import('./message')}
|
||||
*/
|
||||
const message = require('./message')
|
||||
|
||||
const { RPC } = require('./message/rpc')
|
||||
const PeerStreams = require('./peer-streams')
|
||||
const { SignaturePolicy } = require('./signature-policy')
|
||||
const utils = require('./utils')
|
||||
|
||||
const {
|
||||
@ -20,6 +21,18 @@ const {
|
||||
verifySignature
|
||||
} = require('./message/sign')
|
||||
|
||||
/**
|
||||
* @typedef {any} Libp2p
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('bl')} BufferList
|
||||
* @typedef {import('../stream-muxer/types').MuxedStream} MuxedStream
|
||||
* @typedef {import('../connection/connection')} Connection
|
||||
* @typedef {import('./signature-policy').SignaturePolicyType} SignaturePolicyType
|
||||
* @typedef {import('./message/rpc').IRPC} IRPC
|
||||
* @typedef {import('./message/rpc').RPC.SubOpts} RPCSubOpts
|
||||
* @typedef {import('./message/rpc').RPC.Message} RPCMessage
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} InMessage
|
||||
* @property {string} [from]
|
||||
@ -30,32 +43,31 @@ const {
|
||||
* @property {Uint8Array} [signature]
|
||||
* @property {Uint8Array} [key]
|
||||
*
|
||||
* @typedef PeerId
|
||||
* @type import('peer-id')
|
||||
* @typedef {Object} PubsubProperties
|
||||
* @property {string} debugName - log namespace
|
||||
* @property {Array<string>|string} multicodecs - protocol identificers to connect
|
||||
* @property {Libp2p} libp2p
|
||||
*
|
||||
* @typedef {Object} PubsubOptions
|
||||
* @property {SignaturePolicyType} [globalSignaturePolicy = SignaturePolicy.StrictSign] - defines how signatures should be handled
|
||||
* @property {boolean} [canRelayMessage = false] - if can relay messages not subscribed
|
||||
* @property {boolean} [emitSelf = false] - if publish should emit to self, if subscribed
|
||||
*/
|
||||
|
||||
/**
|
||||
* PubsubBaseProtocol handles the peers and connections logic for pubsub routers
|
||||
* and specifies the API that pubsub routers should have.
|
||||
*/
|
||||
* PubsubBaseProtocol handles the peers and connections logic for pubsub routers
|
||||
* and specifies the API that pubsub routers should have.
|
||||
*/
|
||||
class PubsubBaseProtocol extends EventEmitter {
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @param {String} props.debugName log namespace
|
||||
* @param {Array<string>|string} props.multicodecs protocol identificers to connect
|
||||
* @param {Libp2p} props.libp2p
|
||||
* @param {boolean} [props.signMessages = true] if messages should be signed
|
||||
* @param {boolean} [props.strictSigning = true] if message signing should be required
|
||||
* @param {boolean} [props.canRelayMessage = false] if can relay messages not subscribed
|
||||
* @param {boolean} [props.emitSelf = false] if publish should emit to self, if subscribed
|
||||
* @param {PubsubProperties & PubsubOptions} props
|
||||
* @abstract
|
||||
*/
|
||||
constructor ({
|
||||
debugName,
|
||||
multicodecs,
|
||||
libp2p,
|
||||
signMessages = true,
|
||||
strictSigning = true,
|
||||
globalSignaturePolicy = SignaturePolicy.StrictSign,
|
||||
canRelayMessage = false,
|
||||
emitSelf = false
|
||||
}) {
|
||||
@ -73,8 +85,9 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
super()
|
||||
|
||||
this.log = debug(debugName)
|
||||
this.log.err = debug(`${debugName}:error`)
|
||||
this.log = Object.assign(debug(debugName), {
|
||||
err: debug(`${debugName}:error`)
|
||||
})
|
||||
|
||||
/**
|
||||
* @type {Array<string>}
|
||||
@ -98,6 +111,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* List of our subscriptions
|
||||
*
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
this.subscriptions = new Set()
|
||||
@ -109,29 +123,35 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
*/
|
||||
this.peers = new Map()
|
||||
|
||||
// Message signing
|
||||
this.signMessages = signMessages
|
||||
// validate signature policy
|
||||
if (!SignaturePolicy[globalSignaturePolicy]) {
|
||||
throw errcode(new Error('Invalid global signature policy'), codes.ERR_INVALID_SIGNATURE_POLICY)
|
||||
}
|
||||
|
||||
/**
|
||||
* If message signing should be required for incoming messages
|
||||
* @type {boolean}
|
||||
* The signature policy to follow by default
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.strictSigning = strictSigning
|
||||
this.globalSignaturePolicy = globalSignaturePolicy
|
||||
|
||||
/**
|
||||
* If router can relay received messages, even if not subscribed
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.canRelayMessage = canRelayMessage
|
||||
|
||||
/**
|
||||
* if publish should emit to self, if subscribed
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.emitSelf = emitSelf
|
||||
|
||||
/**
|
||||
* Topic validator function
|
||||
*
|
||||
* @typedef {function(string, InMessage): Promise<void>} validator
|
||||
*/
|
||||
/**
|
||||
@ -139,6 +159,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
*
|
||||
* Keyed by topic
|
||||
* Topic validators are functions with the following input:
|
||||
*
|
||||
* @type {Map<string, validator>}
|
||||
*/
|
||||
this.topicValidators = new Map()
|
||||
@ -153,6 +174,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Register the pubsub protocol onto the libp2p node.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
start () {
|
||||
@ -182,6 +204,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Unregister the pubsub protocol and the streams with other peers will be closed.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
stop () {
|
||||
@ -203,26 +226,28 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* On an inbound stream opened.
|
||||
* @private
|
||||
*
|
||||
* @protected
|
||||
* @param {Object} props
|
||||
* @param {string} props.protocol
|
||||
* @param {DuplexIterableStream} props.stream
|
||||
* @param {Connection} props.connection connection
|
||||
* @param {MuxedStream} props.stream
|
||||
* @param {Connection} props.connection - connection
|
||||
*/
|
||||
_onIncomingStream ({ protocol, stream, connection }) {
|
||||
const peerId = connection.remotePeer
|
||||
const idB58Str = peerId.toB58String()
|
||||
const peer = this._addPeer(peerId, protocol)
|
||||
peer.attachInboundStream(stream)
|
||||
const inboundStream = peer.attachInboundStream(stream)
|
||||
|
||||
this._processMessages(idB58Str, peer.inboundStream, peer)
|
||||
this._processMessages(idB58Str, inboundStream, peer)
|
||||
}
|
||||
|
||||
/**
|
||||
* Registrar notifies an established connection with pubsub protocol.
|
||||
* @private
|
||||
* @param {PeerId} peerId remote peer-id
|
||||
* @param {Connection} conn connection to the peer
|
||||
*
|
||||
* @protected
|
||||
* @param {PeerId} peerId - remote peer-id
|
||||
* @param {Connection} conn - connection to the peer
|
||||
*/
|
||||
async _onPeerConnected (peerId, conn) {
|
||||
const idB58Str = peerId.toB58String()
|
||||
@ -242,9 +267,10 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Registrar notifies a closing connection with pubsub protocol.
|
||||
* @private
|
||||
* @param {PeerId} peerId peerId
|
||||
* @param {Error} err error for connection end
|
||||
*
|
||||
* @protected
|
||||
* @param {PeerId} peerId - peerId
|
||||
* @param {Error} [err] - error for connection end
|
||||
*/
|
||||
_onPeerDisconnected (peerId, err) {
|
||||
const idB58Str = peerId.toB58String()
|
||||
@ -255,7 +281,8 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Notifies the router that a peer has been connected
|
||||
* @private
|
||||
*
|
||||
* @protected
|
||||
* @param {PeerId} peerId
|
||||
* @param {string} protocol
|
||||
* @returns {PeerStreams}
|
||||
@ -285,7 +312,8 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Notifies the router that a peer has been disconnected.
|
||||
* @private
|
||||
*
|
||||
* @protected
|
||||
* @param {PeerId} peerId
|
||||
* @returns {PeerStreams | undefined}
|
||||
*/
|
||||
@ -315,9 +343,10 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Responsible for processing each RPC message received by other peers.
|
||||
* @param {string} idB58Str peer id string in base58
|
||||
* @param {DuplexIterableStream} stream inbound stream
|
||||
* @param {PeerStreams} peerStreams PubSub peer
|
||||
*
|
||||
* @param {string} idB58Str - peer id string in base58
|
||||
* @param {AsyncIterable<Uint8Array|BufferList>} stream - inbound stream
|
||||
* @param {PeerStreams} peerStreams - PubSub peer
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async _processMessages (idB58Str, stream, peerStreams) {
|
||||
@ -340,7 +369,8 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Handles an rpc request from a peer
|
||||
* @param {String} idB58Str
|
||||
*
|
||||
* @param {string} idB58Str
|
||||
* @param {PeerStreams} peerStreams
|
||||
* @param {RPC} rpc
|
||||
* @returns {boolean}
|
||||
@ -352,7 +382,9 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
if (subs.length) {
|
||||
// update peer subscriptions
|
||||
subs.forEach((subOpt) => this._processRpcSubOpt(idB58Str, subOpt))
|
||||
subs.forEach((subOpt) => {
|
||||
this._processRpcSubOpt(idB58Str, subOpt)
|
||||
})
|
||||
this.emit('pubsub:subscription-change', peerStreams.id, subs)
|
||||
}
|
||||
|
||||
@ -362,8 +394,9 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
}
|
||||
|
||||
if (msgs.length) {
|
||||
msgs.forEach(message => {
|
||||
if (!(this.canRelayMessage || message.topicIDs.some((topic) => this.subscriptions.has(topic)))) {
|
||||
// @ts-ignore RPC message is modified
|
||||
msgs.forEach((message) => {
|
||||
if (!(this.canRelayMessage || (message.topicIDs && message.topicIDs.some((topic) => this.subscriptions.has(topic))))) {
|
||||
this.log('received message we didn\'t subscribe to. Dropping.')
|
||||
return
|
||||
}
|
||||
@ -376,12 +409,17 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Handles a subscription change from a peer
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {RPC.SubOpt} subOpt
|
||||
* @param {RPC.ISubOpts} subOpt
|
||||
*/
|
||||
_processRpcSubOpt (id, subOpt) {
|
||||
const t = subOpt.topicID
|
||||
|
||||
if (!t) {
|
||||
return
|
||||
}
|
||||
|
||||
let topicSet = this.topics.get(t)
|
||||
if (!topicSet) {
|
||||
topicSet = new Set()
|
||||
@ -399,6 +437,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Handles an message from a peer
|
||||
*
|
||||
* @param {InMessage} msg
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
@ -423,6 +462,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Emit a message from a peer
|
||||
*
|
||||
* @param {InMessage} message
|
||||
*/
|
||||
_emitMessage (message) {
|
||||
@ -436,16 +476,27 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
/**
|
||||
* The default msgID implementation
|
||||
* Child class can override this.
|
||||
* @param {RPC.Message} msg the message object
|
||||
* @returns {string} message id as string
|
||||
*
|
||||
* @param {InMessage} msg - the message object
|
||||
* @returns {Uint8Array} message id as bytes
|
||||
*/
|
||||
getMsgId (msg) {
|
||||
return utils.msgId(msg.from, msg.seqno)
|
||||
const signaturePolicy = this.globalSignaturePolicy
|
||||
switch (signaturePolicy) {
|
||||
case SignaturePolicy.StrictSign:
|
||||
// @ts-ignore seqno is optional in protobuf definition but it will exist
|
||||
return utils.msgId(msg.from, msg.seqno)
|
||||
case SignaturePolicy.StrictNoSign:
|
||||
return utils.noSignMsgId(msg.data)
|
||||
default:
|
||||
throw errcode(new Error('Cannot get message id: unhandled signature policy: ' + signaturePolicy), codes.ERR_UNHANDLED_SIGNATURE_POLICY)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to accept a message from a peer
|
||||
* Override to create a graylist
|
||||
*
|
||||
* @override
|
||||
* @param {string} id
|
||||
* @returns {boolean}
|
||||
@ -457,27 +508,30 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
/**
|
||||
* Decode Uint8Array into an RPC object.
|
||||
* This can be override to use a custom router protobuf.
|
||||
*
|
||||
* @param {Uint8Array} bytes
|
||||
* @returns {RPC}
|
||||
*/
|
||||
_decodeRpc (bytes) {
|
||||
return message.rpc.RPC.decode(bytes)
|
||||
return RPC.decode(bytes)
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode RPC object into a Uint8Array.
|
||||
* This can be override to use a custom router protobuf.
|
||||
* @param {RPC} rpc
|
||||
*
|
||||
* @param {IRPC} rpc
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
_encodeRpc (rpc) {
|
||||
return message.rpc.RPC.encode(rpc)
|
||||
return RPC.encode(rpc).finish()
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an rpc object to a peer
|
||||
* @param {string} id peer id
|
||||
* @param {RPC} rpc
|
||||
*
|
||||
* @param {string} id - peer id
|
||||
* @param {IRPC} rpc
|
||||
* @returns {void}
|
||||
*/
|
||||
_sendRpc (id, rpc) {
|
||||
@ -493,9 +547,10 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Send subscroptions to a peer
|
||||
* @param {string} id peer id
|
||||
*
|
||||
* @param {string} id - peer id
|
||||
* @param {string[]} topics
|
||||
* @param {boolean} subscribe set to false for unsubscriptions
|
||||
* @param {boolean} subscribe - set to false for unsubscriptions
|
||||
* @returns {void}
|
||||
*/
|
||||
_sendSubscriptions (id, topics, subscribe) {
|
||||
@ -507,42 +562,69 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
/**
|
||||
* Validates the given message. The signature will be checked for authenticity.
|
||||
* Throws an error on invalid messages
|
||||
*
|
||||
* @param {InMessage} message
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async validate (message) { // eslint-disable-line require-await
|
||||
// If strict signing is on and we have no signature, abort
|
||||
if (this.strictSigning && !message.signature) {
|
||||
throw errcode(new Error('Signing required and no signature was present'), codes.ERR_MISSING_SIGNATURE)
|
||||
}
|
||||
|
||||
// Check the message signature if present
|
||||
if (message.signature && !(await verifySignature(message))) {
|
||||
throw errcode(new Error('Invalid message signature'), codes.ERR_INVALID_SIGNATURE)
|
||||
const signaturePolicy = this.globalSignaturePolicy
|
||||
switch (signaturePolicy) {
|
||||
case SignaturePolicy.StrictNoSign:
|
||||
if (message.from) {
|
||||
throw errcode(new Error('StrictNoSigning: from should not be present'), codes.ERR_UNEXPECTED_FROM)
|
||||
}
|
||||
if (message.signature) {
|
||||
throw errcode(new Error('StrictNoSigning: signature should not be present'), codes.ERR_UNEXPECTED_SIGNATURE)
|
||||
}
|
||||
if (message.key) {
|
||||
throw errcode(new Error('StrictNoSigning: key should not be present'), codes.ERR_UNEXPECTED_KEY)
|
||||
}
|
||||
if (message.seqno) {
|
||||
throw errcode(new Error('StrictNoSigning: seqno should not be present'), codes.ERR_UNEXPECTED_SEQNO)
|
||||
}
|
||||
break
|
||||
case SignaturePolicy.StrictSign:
|
||||
if (!message.signature) {
|
||||
throw errcode(new Error('StrictSigning: Signing required and no signature was present'), codes.ERR_MISSING_SIGNATURE)
|
||||
}
|
||||
if (!message.seqno) {
|
||||
throw errcode(new Error('StrictSigning: Signing required and no seqno was present'), codes.ERR_MISSING_SEQNO)
|
||||
}
|
||||
if (!(await verifySignature(message))) {
|
||||
throw errcode(new Error('StrictSigning: Invalid message signature'), codes.ERR_INVALID_SIGNATURE)
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw errcode(new Error('Cannot validate message: unhandled signature policy: ' + signaturePolicy), codes.ERR_UNHANDLED_SIGNATURE_POLICY)
|
||||
}
|
||||
|
||||
for (const topic of message.topicIDs) {
|
||||
const validatorFn = this.topicValidators.get(topic)
|
||||
if (!validatorFn) {
|
||||
continue
|
||||
if (validatorFn) {
|
||||
await validatorFn(topic, message)
|
||||
}
|
||||
await validatorFn(topic, message)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the message and signs it, if signing is enabled.
|
||||
* Should be used by the routers to create the message to send.
|
||||
* @private
|
||||
* @param {Message} message
|
||||
* @returns {Promise<Message>}
|
||||
*
|
||||
* @protected
|
||||
* @param {InMessage} message
|
||||
* @returns {Promise<InMessage>}
|
||||
*/
|
||||
_buildMessage (message) {
|
||||
const msg = utils.normalizeOutRpcMessage(message)
|
||||
if (this.signMessages) {
|
||||
return signMessage(this.peerId, msg)
|
||||
} else {
|
||||
return message
|
||||
const signaturePolicy = this.globalSignaturePolicy
|
||||
switch (signaturePolicy) {
|
||||
case SignaturePolicy.StrictSign:
|
||||
message.from = this.peerId.toB58String()
|
||||
message.seqno = utils.randomSeqno()
|
||||
return signMessage(this.peerId, utils.normalizeOutRpcMessage(message))
|
||||
case SignaturePolicy.StrictNoSign:
|
||||
return Promise.resolve(message)
|
||||
default:
|
||||
throw errcode(new Error('Cannot build message: unhandled signature policy: ' + signaturePolicy), codes.ERR_UNHANDLED_SIGNATURE_POLICY)
|
||||
}
|
||||
}
|
||||
|
||||
@ -550,6 +632,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Get a list of the peer-ids that are subscribed to one topic.
|
||||
*
|
||||
* @param {string} topic
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
@ -571,9 +654,10 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Publishes messages to all subscribed peers
|
||||
*
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @param {Buffer} message
|
||||
* @param {Uint8Array} message
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async publish (topic, message) {
|
||||
@ -584,30 +668,30 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
this.log('publish', topic, message)
|
||||
|
||||
const from = this.peerId.toB58String()
|
||||
let msgObject = {
|
||||
const msgObject = {
|
||||
receivedFrom: from,
|
||||
from: from,
|
||||
data: message,
|
||||
seqno: utils.randomSeqno(),
|
||||
topicIDs: [topic]
|
||||
}
|
||||
|
||||
// ensure that any operations performed on the message will include the signature
|
||||
// ensure that the message follows the signature policy
|
||||
const outMsg = await this._buildMessage(msgObject)
|
||||
msgObject = utils.normalizeInRpcMessage(outMsg)
|
||||
// @ts-ignore different type as from is converted
|
||||
const msg = utils.normalizeInRpcMessage(outMsg)
|
||||
|
||||
// Emit to self if I'm interested and emitSelf enabled
|
||||
this.emitSelf && this._emitMessage(msgObject)
|
||||
this.emitSelf && this._emitMessage(msg)
|
||||
|
||||
// send to all the other peers
|
||||
await this._publish(msgObject)
|
||||
await this._publish(msg)
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding the implementation of publish should handle the appropriate algorithms for the publish/subscriber implementation.
|
||||
* For example, a Floodsub implementation might simply publish each message to each topic for every peer
|
||||
*
|
||||
* @abstract
|
||||
* @param {InMessage} message
|
||||
* @param {InMessage|RPCMessage} message
|
||||
* @returns {Promise<void>}
|
||||
*
|
||||
*/
|
||||
@ -617,6 +701,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Subscribes to a given topic.
|
||||
*
|
||||
* @abstract
|
||||
* @param {string} topic
|
||||
* @returns {void}
|
||||
@ -634,6 +719,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Unsubscribe from the given topic.
|
||||
*
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @returns {void}
|
||||
@ -651,8 +737,9 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Get the list of topics which the peer is subscribed to.
|
||||
*
|
||||
* @override
|
||||
* @returns {Array<String>}
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
getTopics () {
|
||||
if (!this.started) {
|
||||
@ -663,6 +750,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
PubsubBaseProtocol.utils = utils
|
||||
PubsubBaseProtocol.SignaturePolicy = SignaturePolicy
|
||||
|
||||
module.exports = PubsubBaseProtocol
|
||||
module.exports.message = message
|
||||
module.exports.utils = utils
|
||||
|
5
src/pubsub/message/index.d.ts
vendored
5
src/pubsub/message/index.d.ts
vendored
@ -1,5 +0,0 @@
|
||||
export var rpc: any;
|
||||
export var td: any;
|
||||
export var RPC: any;
|
||||
export var Message: any;
|
||||
export var SubOpts: any;
|
@ -1,17 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const protons = require('protons')
|
||||
|
||||
const rpcProto = protons(require('./rpc.proto.js'))
|
||||
const RPC = rpcProto.RPC
|
||||
const topicDescriptorProto = protons(require('./topic-descriptor.proto.js'))
|
||||
|
||||
/**
|
||||
* @module pubsub/message/index
|
||||
*/
|
||||
exports = module.exports
|
||||
exports.rpc = rpcProto
|
||||
exports.td = topicDescriptorProto
|
||||
exports.RPC = RPC
|
||||
exports.Message = RPC.Message
|
||||
exports.SubOpts = RPC.SubOpts
|
222
src/pubsub/message/rpc.d.ts
vendored
Normal file
222
src/pubsub/message/rpc.d.ts
vendored
Normal file
@ -0,0 +1,222 @@
|
||||
import * as $protobuf from "protobufjs";
|
||||
/** Properties of a RPC. */
|
||||
export interface IRPC {
|
||||
|
||||
/** RPC subscriptions */
|
||||
subscriptions?: (RPC.ISubOpts[]|null);
|
||||
|
||||
/** RPC msgs */
|
||||
msgs?: (RPC.IMessage[]|null);
|
||||
}
|
||||
|
||||
/** Represents a RPC. */
|
||||
export class RPC implements IRPC {
|
||||
|
||||
/**
|
||||
* Constructs a new RPC.
|
||||
* @param [p] Properties to set
|
||||
*/
|
||||
constructor(p?: IRPC);
|
||||
|
||||
/** RPC subscriptions. */
|
||||
public subscriptions: RPC.ISubOpts[];
|
||||
|
||||
/** RPC msgs. */
|
||||
public msgs: RPC.IMessage[];
|
||||
|
||||
/**
|
||||
* Encodes the specified RPC message. Does not implicitly {@link RPC.verify|verify} messages.
|
||||
* @param m RPC message or plain object to encode
|
||||
* @param [w] Writer to encode to
|
||||
* @returns Writer
|
||||
*/
|
||||
public static encode(m: IRPC, w?: $protobuf.Writer): $protobuf.Writer;
|
||||
|
||||
/**
|
||||
* Decodes a RPC message from the specified reader or buffer.
|
||||
* @param r Reader or buffer to decode from
|
||||
* @param [l] Message length if known beforehand
|
||||
* @returns RPC
|
||||
* @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): RPC;
|
||||
|
||||
/**
|
||||
* Creates a RPC message from a plain object. Also converts values to their respective internal types.
|
||||
* @param d Plain object
|
||||
* @returns RPC
|
||||
*/
|
||||
public static fromObject(d: { [k: string]: any }): RPC;
|
||||
|
||||
/**
|
||||
* Creates a plain object from a RPC message. Also converts values to other types if specified.
|
||||
* @param m RPC
|
||||
* @param [o] Conversion options
|
||||
* @returns Plain object
|
||||
*/
|
||||
public static toObject(m: RPC, o?: $protobuf.IConversionOptions): { [k: string]: any };
|
||||
|
||||
/**
|
||||
* Converts this RPC to JSON.
|
||||
* @returns JSON object
|
||||
*/
|
||||
public toJSON(): { [k: string]: any };
|
||||
}
|
||||
|
||||
export namespace RPC {
|
||||
|
||||
/** Properties of a SubOpts. */
|
||||
interface ISubOpts {
|
||||
|
||||
/** SubOpts subscribe */
|
||||
subscribe?: (boolean|null);
|
||||
|
||||
/** SubOpts topicID */
|
||||
topicID?: (string|null);
|
||||
}
|
||||
|
||||
/** Represents a SubOpts. */
|
||||
class SubOpts implements ISubOpts {
|
||||
|
||||
/**
|
||||
* Constructs a new SubOpts.
|
||||
* @param [p] Properties to set
|
||||
*/
|
||||
constructor(p?: RPC.ISubOpts);
|
||||
|
||||
/** SubOpts subscribe. */
|
||||
public subscribe: boolean;
|
||||
|
||||
/** SubOpts topicID. */
|
||||
public topicID: string;
|
||||
|
||||
/**
|
||||
* Encodes the specified SubOpts message. Does not implicitly {@link RPC.SubOpts.verify|verify} messages.
|
||||
* @param m SubOpts message or plain object to encode
|
||||
* @param [w] Writer to encode to
|
||||
* @returns Writer
|
||||
*/
|
||||
public static encode(m: RPC.ISubOpts, w?: $protobuf.Writer): $protobuf.Writer;
|
||||
|
||||
/**
|
||||
* Decodes a SubOpts message from the specified reader or buffer.
|
||||
* @param r Reader or buffer to decode from
|
||||
* @param [l] Message length if known beforehand
|
||||
* @returns SubOpts
|
||||
* @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): RPC.SubOpts;
|
||||
|
||||
/**
|
||||
* Creates a SubOpts message from a plain object. Also converts values to their respective internal types.
|
||||
* @param d Plain object
|
||||
* @returns SubOpts
|
||||
*/
|
||||
public static fromObject(d: { [k: string]: any }): RPC.SubOpts;
|
||||
|
||||
/**
|
||||
* Creates a plain object from a SubOpts message. Also converts values to other types if specified.
|
||||
* @param m SubOpts
|
||||
* @param [o] Conversion options
|
||||
* @returns Plain object
|
||||
*/
|
||||
public static toObject(m: RPC.SubOpts, o?: $protobuf.IConversionOptions): { [k: string]: any };
|
||||
|
||||
/**
|
||||
* Converts this SubOpts to JSON.
|
||||
* @returns JSON object
|
||||
*/
|
||||
public toJSON(): { [k: string]: any };
|
||||
}
|
||||
|
||||
/** Properties of a Message. */
|
||||
interface IMessage {
|
||||
|
||||
/** Message from */
|
||||
from?: (Uint8Array|null);
|
||||
|
||||
/** Message data */
|
||||
data?: (Uint8Array|null);
|
||||
|
||||
/** Message seqno */
|
||||
seqno?: (Uint8Array|null);
|
||||
|
||||
/** Message topicIDs */
|
||||
topicIDs?: (string[]|null);
|
||||
|
||||
/** Message signature */
|
||||
signature?: (Uint8Array|null);
|
||||
|
||||
/** Message key */
|
||||
key?: (Uint8Array|null);
|
||||
}
|
||||
|
||||
/** Represents a Message. */
|
||||
class Message implements IMessage {
|
||||
|
||||
/**
|
||||
* Constructs a new Message.
|
||||
* @param [p] Properties to set
|
||||
*/
|
||||
constructor(p?: RPC.IMessage);
|
||||
|
||||
/** Message from. */
|
||||
public from: Uint8Array;
|
||||
|
||||
/** Message data. */
|
||||
public data: Uint8Array;
|
||||
|
||||
/** Message seqno. */
|
||||
public seqno: Uint8Array;
|
||||
|
||||
/** Message topicIDs. */
|
||||
public topicIDs: string[];
|
||||
|
||||
/** Message signature. */
|
||||
public signature: Uint8Array;
|
||||
|
||||
/** Message key. */
|
||||
public key: Uint8Array;
|
||||
|
||||
/**
|
||||
* Encodes the specified Message message. Does not implicitly {@link RPC.Message.verify|verify} messages.
|
||||
* @param m Message message or plain object to encode
|
||||
* @param [w] Writer to encode to
|
||||
* @returns Writer
|
||||
*/
|
||||
public static encode(m: RPC.IMessage, w?: $protobuf.Writer): $protobuf.Writer;
|
||||
|
||||
/**
|
||||
* Decodes a Message message from the specified reader or buffer.
|
||||
* @param r Reader or buffer to decode from
|
||||
* @param [l] Message length if known beforehand
|
||||
* @returns Message
|
||||
* @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): RPC.Message;
|
||||
|
||||
/**
|
||||
* Creates a Message message from a plain object. Also converts values to their respective internal types.
|
||||
* @param d Plain object
|
||||
* @returns Message
|
||||
*/
|
||||
public static fromObject(d: { [k: string]: any }): RPC.Message;
|
||||
|
||||
/**
|
||||
* Creates a plain object from a Message message. Also converts values to other types if specified.
|
||||
* @param m Message
|
||||
* @param [o] Conversion options
|
||||
* @returns Plain object
|
||||
*/
|
||||
public static toObject(m: RPC.Message, o?: $protobuf.IConversionOptions): { [k: string]: any };
|
||||
|
||||
/**
|
||||
* Converts this Message to JSON.
|
||||
* @returns JSON object
|
||||
*/
|
||||
public toJSON(): { [k: string]: any };
|
||||
}
|
||||
}
|
645
src/pubsub/message/rpc.js
Normal file
645
src/pubsub/message/rpc.js
Normal file
@ -0,0 +1,645 @@
|
||||
/*eslint-disable*/
|
||||
"use strict";
|
||||
|
||||
var $protobuf = require("protobufjs/minimal");
|
||||
|
||||
// Common aliases
|
||||
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
|
||||
|
||||
// Exported root namespace
|
||||
var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {});
|
||||
|
||||
$root.RPC = (function() {
|
||||
|
||||
/**
|
||||
* Properties of a RPC.
|
||||
* @exports IRPC
|
||||
* @interface IRPC
|
||||
* @property {Array.<RPC.ISubOpts>|null} [subscriptions] RPC subscriptions
|
||||
* @property {Array.<RPC.IMessage>|null} [msgs] RPC msgs
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructs a new RPC.
|
||||
* @exports RPC
|
||||
* @classdesc Represents a RPC.
|
||||
* @implements IRPC
|
||||
* @constructor
|
||||
* @param {IRPC=} [p] Properties to set
|
||||
*/
|
||||
function RPC(p) {
|
||||
this.subscriptions = [];
|
||||
this.msgs = [];
|
||||
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]];
|
||||
}
|
||||
|
||||
/**
|
||||
* RPC subscriptions.
|
||||
* @member {Array.<RPC.ISubOpts>} subscriptions
|
||||
* @memberof RPC
|
||||
* @instance
|
||||
*/
|
||||
RPC.prototype.subscriptions = $util.emptyArray;
|
||||
|
||||
/**
|
||||
* RPC msgs.
|
||||
* @member {Array.<RPC.IMessage>} msgs
|
||||
* @memberof RPC
|
||||
* @instance
|
||||
*/
|
||||
RPC.prototype.msgs = $util.emptyArray;
|
||||
|
||||
/**
|
||||
* Encodes the specified RPC message. Does not implicitly {@link RPC.verify|verify} messages.
|
||||
* @function encode
|
||||
* @memberof RPC
|
||||
* @static
|
||||
* @param {IRPC} m RPC message or plain object to encode
|
||||
* @param {$protobuf.Writer} [w] Writer to encode to
|
||||
* @returns {$protobuf.Writer} Writer
|
||||
*/
|
||||
RPC.encode = function encode(m, w) {
|
||||
if (!w)
|
||||
w = $Writer.create();
|
||||
if (m.subscriptions != null && m.subscriptions.length) {
|
||||
for (var i = 0; i < m.subscriptions.length; ++i)
|
||||
$root.RPC.SubOpts.encode(m.subscriptions[i], w.uint32(10).fork()).ldelim();
|
||||
}
|
||||
if (m.msgs != null && m.msgs.length) {
|
||||
for (var i = 0; i < m.msgs.length; ++i)
|
||||
$root.RPC.Message.encode(m.msgs[i], w.uint32(18).fork()).ldelim();
|
||||
}
|
||||
return w;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes a RPC message from the specified reader or buffer.
|
||||
* @function decode
|
||||
* @memberof RPC
|
||||
* @static
|
||||
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
|
||||
* @param {number} [l] Message length if known beforehand
|
||||
* @returns {RPC} RPC
|
||||
* @throws {Error} If the payload is not a reader or valid buffer
|
||||
* @throws {$protobuf.util.ProtocolError} If required fields are missing
|
||||
*/
|
||||
RPC.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.RPC();
|
||||
while (r.pos < c) {
|
||||
var t = r.uint32();
|
||||
switch (t >>> 3) {
|
||||
case 1:
|
||||
if (!(m.subscriptions && m.subscriptions.length))
|
||||
m.subscriptions = [];
|
||||
m.subscriptions.push($root.RPC.SubOpts.decode(r, r.uint32()));
|
||||
break;
|
||||
case 2:
|
||||
if (!(m.msgs && m.msgs.length))
|
||||
m.msgs = [];
|
||||
m.msgs.push($root.RPC.Message.decode(r, r.uint32()));
|
||||
break;
|
||||
default:
|
||||
r.skipType(t & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a RPC message from a plain object. Also converts values to their respective internal types.
|
||||
* @function fromObject
|
||||
* @memberof RPC
|
||||
* @static
|
||||
* @param {Object.<string,*>} d Plain object
|
||||
* @returns {RPC} RPC
|
||||
*/
|
||||
RPC.fromObject = function fromObject(d) {
|
||||
if (d instanceof $root.RPC)
|
||||
return d;
|
||||
var m = new $root.RPC();
|
||||
if (d.subscriptions) {
|
||||
if (!Array.isArray(d.subscriptions))
|
||||
throw TypeError(".RPC.subscriptions: array expected");
|
||||
m.subscriptions = [];
|
||||
for (var i = 0; i < d.subscriptions.length; ++i) {
|
||||
if (typeof d.subscriptions[i] !== "object")
|
||||
throw TypeError(".RPC.subscriptions: object expected");
|
||||
m.subscriptions[i] = $root.RPC.SubOpts.fromObject(d.subscriptions[i]);
|
||||
}
|
||||
}
|
||||
if (d.msgs) {
|
||||
if (!Array.isArray(d.msgs))
|
||||
throw TypeError(".RPC.msgs: array expected");
|
||||
m.msgs = [];
|
||||
for (var i = 0; i < d.msgs.length; ++i) {
|
||||
if (typeof d.msgs[i] !== "object")
|
||||
throw TypeError(".RPC.msgs: object expected");
|
||||
m.msgs[i] = $root.RPC.Message.fromObject(d.msgs[i]);
|
||||
}
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a plain object from a RPC message. Also converts values to other types if specified.
|
||||
* @function toObject
|
||||
* @memberof RPC
|
||||
* @static
|
||||
* @param {RPC} m RPC
|
||||
* @param {$protobuf.IConversionOptions} [o] Conversion options
|
||||
* @returns {Object.<string,*>} Plain object
|
||||
*/
|
||||
RPC.toObject = function toObject(m, o) {
|
||||
if (!o)
|
||||
o = {};
|
||||
var d = {};
|
||||
if (o.arrays || o.defaults) {
|
||||
d.subscriptions = [];
|
||||
d.msgs = [];
|
||||
}
|
||||
if (m.subscriptions && m.subscriptions.length) {
|
||||
d.subscriptions = [];
|
||||
for (var j = 0; j < m.subscriptions.length; ++j) {
|
||||
d.subscriptions[j] = $root.RPC.SubOpts.toObject(m.subscriptions[j], o);
|
||||
}
|
||||
}
|
||||
if (m.msgs && m.msgs.length) {
|
||||
d.msgs = [];
|
||||
for (var j = 0; j < m.msgs.length; ++j) {
|
||||
d.msgs[j] = $root.RPC.Message.toObject(m.msgs[j], o);
|
||||
}
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts this RPC to JSON.
|
||||
* @function toJSON
|
||||
* @memberof RPC
|
||||
* @instance
|
||||
* @returns {Object.<string,*>} JSON object
|
||||
*/
|
||||
RPC.prototype.toJSON = function toJSON() {
|
||||
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
|
||||
};
|
||||
|
||||
RPC.SubOpts = (function() {
|
||||
|
||||
/**
|
||||
* Properties of a SubOpts.
|
||||
* @memberof RPC
|
||||
* @interface ISubOpts
|
||||
* @property {boolean|null} [subscribe] SubOpts subscribe
|
||||
* @property {string|null} [topicID] SubOpts topicID
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructs a new SubOpts.
|
||||
* @memberof RPC
|
||||
* @classdesc Represents a SubOpts.
|
||||
* @implements ISubOpts
|
||||
* @constructor
|
||||
* @param {RPC.ISubOpts=} [p] Properties to set
|
||||
*/
|
||||
function SubOpts(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]];
|
||||
}
|
||||
|
||||
/**
|
||||
* SubOpts subscribe.
|
||||
* @member {boolean} subscribe
|
||||
* @memberof RPC.SubOpts
|
||||
* @instance
|
||||
*/
|
||||
SubOpts.prototype.subscribe = false;
|
||||
|
||||
/**
|
||||
* SubOpts topicID.
|
||||
* @member {string} topicID
|
||||
* @memberof RPC.SubOpts
|
||||
* @instance
|
||||
*/
|
||||
SubOpts.prototype.topicID = "";
|
||||
|
||||
/**
|
||||
* Encodes the specified SubOpts message. Does not implicitly {@link RPC.SubOpts.verify|verify} messages.
|
||||
* @function encode
|
||||
* @memberof RPC.SubOpts
|
||||
* @static
|
||||
* @param {RPC.ISubOpts} m SubOpts message or plain object to encode
|
||||
* @param {$protobuf.Writer} [w] Writer to encode to
|
||||
* @returns {$protobuf.Writer} Writer
|
||||
*/
|
||||
SubOpts.encode = function encode(m, w) {
|
||||
if (!w)
|
||||
w = $Writer.create();
|
||||
if (m.subscribe != null && Object.hasOwnProperty.call(m, "subscribe"))
|
||||
w.uint32(8).bool(m.subscribe);
|
||||
if (m.topicID != null && Object.hasOwnProperty.call(m, "topicID"))
|
||||
w.uint32(18).string(m.topicID);
|
||||
return w;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes a SubOpts message from the specified reader or buffer.
|
||||
* @function decode
|
||||
* @memberof RPC.SubOpts
|
||||
* @static
|
||||
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
|
||||
* @param {number} [l] Message length if known beforehand
|
||||
* @returns {RPC.SubOpts} SubOpts
|
||||
* @throws {Error} If the payload is not a reader or valid buffer
|
||||
* @throws {$protobuf.util.ProtocolError} If required fields are missing
|
||||
*/
|
||||
SubOpts.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.RPC.SubOpts();
|
||||
while (r.pos < c) {
|
||||
var t = r.uint32();
|
||||
switch (t >>> 3) {
|
||||
case 1:
|
||||
m.subscribe = r.bool();
|
||||
break;
|
||||
case 2:
|
||||
m.topicID = r.string();
|
||||
break;
|
||||
default:
|
||||
r.skipType(t & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a SubOpts message from a plain object. Also converts values to their respective internal types.
|
||||
* @function fromObject
|
||||
* @memberof RPC.SubOpts
|
||||
* @static
|
||||
* @param {Object.<string,*>} d Plain object
|
||||
* @returns {RPC.SubOpts} SubOpts
|
||||
*/
|
||||
SubOpts.fromObject = function fromObject(d) {
|
||||
if (d instanceof $root.RPC.SubOpts)
|
||||
return d;
|
||||
var m = new $root.RPC.SubOpts();
|
||||
if (d.subscribe != null) {
|
||||
m.subscribe = Boolean(d.subscribe);
|
||||
}
|
||||
if (d.topicID != null) {
|
||||
m.topicID = String(d.topicID);
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a plain object from a SubOpts message. Also converts values to other types if specified.
|
||||
* @function toObject
|
||||
* @memberof RPC.SubOpts
|
||||
* @static
|
||||
* @param {RPC.SubOpts} m SubOpts
|
||||
* @param {$protobuf.IConversionOptions} [o] Conversion options
|
||||
* @returns {Object.<string,*>} Plain object
|
||||
*/
|
||||
SubOpts.toObject = function toObject(m, o) {
|
||||
if (!o)
|
||||
o = {};
|
||||
var d = {};
|
||||
if (o.defaults) {
|
||||
d.subscribe = false;
|
||||
d.topicID = "";
|
||||
}
|
||||
if (m.subscribe != null && m.hasOwnProperty("subscribe")) {
|
||||
d.subscribe = m.subscribe;
|
||||
}
|
||||
if (m.topicID != null && m.hasOwnProperty("topicID")) {
|
||||
d.topicID = m.topicID;
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts this SubOpts to JSON.
|
||||
* @function toJSON
|
||||
* @memberof RPC.SubOpts
|
||||
* @instance
|
||||
* @returns {Object.<string,*>} JSON object
|
||||
*/
|
||||
SubOpts.prototype.toJSON = function toJSON() {
|
||||
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
|
||||
};
|
||||
|
||||
return SubOpts;
|
||||
})();
|
||||
|
||||
RPC.Message = (function() {
|
||||
|
||||
/**
|
||||
* Properties of a Message.
|
||||
* @memberof RPC
|
||||
* @interface IMessage
|
||||
* @property {Uint8Array|null} [from] Message from
|
||||
* @property {Uint8Array|null} [data] Message data
|
||||
* @property {Uint8Array|null} [seqno] Message seqno
|
||||
* @property {Array.<string>|null} [topicIDs] Message topicIDs
|
||||
* @property {Uint8Array|null} [signature] Message signature
|
||||
* @property {Uint8Array|null} [key] Message key
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructs a new Message.
|
||||
* @memberof RPC
|
||||
* @classdesc Represents a Message.
|
||||
* @implements IMessage
|
||||
* @constructor
|
||||
* @param {RPC.IMessage=} [p] Properties to set
|
||||
*/
|
||||
function Message(p) {
|
||||
this.topicIDs = [];
|
||||
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]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Message from.
|
||||
* @member {Uint8Array} from
|
||||
* @memberof RPC.Message
|
||||
* @instance
|
||||
*/
|
||||
Message.prototype.from = $util.newBuffer([]);
|
||||
|
||||
/**
|
||||
* Message data.
|
||||
* @member {Uint8Array} data
|
||||
* @memberof RPC.Message
|
||||
* @instance
|
||||
*/
|
||||
Message.prototype.data = $util.newBuffer([]);
|
||||
|
||||
/**
|
||||
* Message seqno.
|
||||
* @member {Uint8Array} seqno
|
||||
* @memberof RPC.Message
|
||||
* @instance
|
||||
*/
|
||||
Message.prototype.seqno = $util.newBuffer([]);
|
||||
|
||||
/**
|
||||
* Message topicIDs.
|
||||
* @member {Array.<string>} topicIDs
|
||||
* @memberof RPC.Message
|
||||
* @instance
|
||||
*/
|
||||
Message.prototype.topicIDs = $util.emptyArray;
|
||||
|
||||
/**
|
||||
* Message signature.
|
||||
* @member {Uint8Array} signature
|
||||
* @memberof RPC.Message
|
||||
* @instance
|
||||
*/
|
||||
Message.prototype.signature = $util.newBuffer([]);
|
||||
|
||||
/**
|
||||
* Message key.
|
||||
* @member {Uint8Array} key
|
||||
* @memberof RPC.Message
|
||||
* @instance
|
||||
*/
|
||||
Message.prototype.key = $util.newBuffer([]);
|
||||
|
||||
/**
|
||||
* Encodes the specified Message message. Does not implicitly {@link RPC.Message.verify|verify} messages.
|
||||
* @function encode
|
||||
* @memberof RPC.Message
|
||||
* @static
|
||||
* @param {RPC.IMessage} m Message message or plain object to encode
|
||||
* @param {$protobuf.Writer} [w] Writer to encode to
|
||||
* @returns {$protobuf.Writer} Writer
|
||||
*/
|
||||
Message.encode = function encode(m, w) {
|
||||
if (!w)
|
||||
w = $Writer.create();
|
||||
if (m.from != null && Object.hasOwnProperty.call(m, "from"))
|
||||
w.uint32(10).bytes(m.from);
|
||||
if (m.data != null && Object.hasOwnProperty.call(m, "data"))
|
||||
w.uint32(18).bytes(m.data);
|
||||
if (m.seqno != null && Object.hasOwnProperty.call(m, "seqno"))
|
||||
w.uint32(26).bytes(m.seqno);
|
||||
if (m.topicIDs != null && m.topicIDs.length) {
|
||||
for (var i = 0; i < m.topicIDs.length; ++i)
|
||||
w.uint32(34).string(m.topicIDs[i]);
|
||||
}
|
||||
if (m.signature != null && Object.hasOwnProperty.call(m, "signature"))
|
||||
w.uint32(42).bytes(m.signature);
|
||||
if (m.key != null && Object.hasOwnProperty.call(m, "key"))
|
||||
w.uint32(50).bytes(m.key);
|
||||
return w;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes a Message message from the specified reader or buffer.
|
||||
* @function decode
|
||||
* @memberof RPC.Message
|
||||
* @static
|
||||
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
|
||||
* @param {number} [l] Message length if known beforehand
|
||||
* @returns {RPC.Message} Message
|
||||
* @throws {Error} If the payload is not a reader or valid buffer
|
||||
* @throws {$protobuf.util.ProtocolError} If required fields are missing
|
||||
*/
|
||||
Message.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.RPC.Message();
|
||||
while (r.pos < c) {
|
||||
var t = r.uint32();
|
||||
switch (t >>> 3) {
|
||||
case 1:
|
||||
m.from = r.bytes();
|
||||
break;
|
||||
case 2:
|
||||
m.data = r.bytes();
|
||||
break;
|
||||
case 3:
|
||||
m.seqno = r.bytes();
|
||||
break;
|
||||
case 4:
|
||||
if (!(m.topicIDs && m.topicIDs.length))
|
||||
m.topicIDs = [];
|
||||
m.topicIDs.push(r.string());
|
||||
break;
|
||||
case 5:
|
||||
m.signature = r.bytes();
|
||||
break;
|
||||
case 6:
|
||||
m.key = r.bytes();
|
||||
break;
|
||||
default:
|
||||
r.skipType(t & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a Message message from a plain object. Also converts values to their respective internal types.
|
||||
* @function fromObject
|
||||
* @memberof RPC.Message
|
||||
* @static
|
||||
* @param {Object.<string,*>} d Plain object
|
||||
* @returns {RPC.Message} Message
|
||||
*/
|
||||
Message.fromObject = function fromObject(d) {
|
||||
if (d instanceof $root.RPC.Message)
|
||||
return d;
|
||||
var m = new $root.RPC.Message();
|
||||
if (d.from != null) {
|
||||
if (typeof d.from === "string")
|
||||
$util.base64.decode(d.from, m.from = $util.newBuffer($util.base64.length(d.from)), 0);
|
||||
else if (d.from.length)
|
||||
m.from = d.from;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (d.seqno != null) {
|
||||
if (typeof d.seqno === "string")
|
||||
$util.base64.decode(d.seqno, m.seqno = $util.newBuffer($util.base64.length(d.seqno)), 0);
|
||||
else if (d.seqno.length)
|
||||
m.seqno = d.seqno;
|
||||
}
|
||||
if (d.topicIDs) {
|
||||
if (!Array.isArray(d.topicIDs))
|
||||
throw TypeError(".RPC.Message.topicIDs: array expected");
|
||||
m.topicIDs = [];
|
||||
for (var i = 0; i < d.topicIDs.length; ++i) {
|
||||
m.topicIDs[i] = String(d.topicIDs[i]);
|
||||
}
|
||||
}
|
||||
if (d.signature != null) {
|
||||
if (typeof d.signature === "string")
|
||||
$util.base64.decode(d.signature, m.signature = $util.newBuffer($util.base64.length(d.signature)), 0);
|
||||
else if (d.signature.length)
|
||||
m.signature = d.signature;
|
||||
}
|
||||
if (d.key != null) {
|
||||
if (typeof d.key === "string")
|
||||
$util.base64.decode(d.key, m.key = $util.newBuffer($util.base64.length(d.key)), 0);
|
||||
else if (d.key.length)
|
||||
m.key = d.key;
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a plain object from a Message message. Also converts values to other types if specified.
|
||||
* @function toObject
|
||||
* @memberof RPC.Message
|
||||
* @static
|
||||
* @param {RPC.Message} m Message
|
||||
* @param {$protobuf.IConversionOptions} [o] Conversion options
|
||||
* @returns {Object.<string,*>} Plain object
|
||||
*/
|
||||
Message.toObject = function toObject(m, o) {
|
||||
if (!o)
|
||||
o = {};
|
||||
var d = {};
|
||||
if (o.arrays || o.defaults) {
|
||||
d.topicIDs = [];
|
||||
}
|
||||
if (o.defaults) {
|
||||
if (o.bytes === String)
|
||||
d.from = "";
|
||||
else {
|
||||
d.from = [];
|
||||
if (o.bytes !== Array)
|
||||
d.from = $util.newBuffer(d.from);
|
||||
}
|
||||
if (o.bytes === String)
|
||||
d.data = "";
|
||||
else {
|
||||
d.data = [];
|
||||
if (o.bytes !== Array)
|
||||
d.data = $util.newBuffer(d.data);
|
||||
}
|
||||
if (o.bytes === String)
|
||||
d.seqno = "";
|
||||
else {
|
||||
d.seqno = [];
|
||||
if (o.bytes !== Array)
|
||||
d.seqno = $util.newBuffer(d.seqno);
|
||||
}
|
||||
if (o.bytes === String)
|
||||
d.signature = "";
|
||||
else {
|
||||
d.signature = [];
|
||||
if (o.bytes !== Array)
|
||||
d.signature = $util.newBuffer(d.signature);
|
||||
}
|
||||
if (o.bytes === String)
|
||||
d.key = "";
|
||||
else {
|
||||
d.key = [];
|
||||
if (o.bytes !== Array)
|
||||
d.key = $util.newBuffer(d.key);
|
||||
}
|
||||
}
|
||||
if (m.from != null && m.hasOwnProperty("from")) {
|
||||
d.from = o.bytes === String ? $util.base64.encode(m.from, 0, m.from.length) : o.bytes === Array ? Array.prototype.slice.call(m.from) : m.from;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (m.seqno != null && m.hasOwnProperty("seqno")) {
|
||||
d.seqno = o.bytes === String ? $util.base64.encode(m.seqno, 0, m.seqno.length) : o.bytes === Array ? Array.prototype.slice.call(m.seqno) : m.seqno;
|
||||
}
|
||||
if (m.topicIDs && m.topicIDs.length) {
|
||||
d.topicIDs = [];
|
||||
for (var j = 0; j < m.topicIDs.length; ++j) {
|
||||
d.topicIDs[j] = m.topicIDs[j];
|
||||
}
|
||||
}
|
||||
if (m.signature != null && m.hasOwnProperty("signature")) {
|
||||
d.signature = o.bytes === String ? $util.base64.encode(m.signature, 0, m.signature.length) : o.bytes === Array ? Array.prototype.slice.call(m.signature) : m.signature;
|
||||
}
|
||||
if (m.key != null && m.hasOwnProperty("key")) {
|
||||
d.key = o.bytes === String ? $util.base64.encode(m.key, 0, m.key.length) : o.bytes === Array ? Array.prototype.slice.call(m.key) : m.key;
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts this Message to JSON.
|
||||
* @function toJSON
|
||||
* @memberof RPC.Message
|
||||
* @instance
|
||||
* @returns {Object.<string,*>} JSON object
|
||||
*/
|
||||
Message.prototype.toJSON = function toJSON() {
|
||||
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
|
||||
};
|
||||
|
||||
return Message;
|
||||
})();
|
||||
|
||||
return RPC;
|
||||
})();
|
||||
|
||||
module.exports = $root;
|
@ -1,5 +1,5 @@
|
||||
'use strict'
|
||||
module.exports = `
|
||||
syntax = "proto3";
|
||||
|
||||
message RPC {
|
||||
repeated SubOpts subscriptions = 1;
|
||||
repeated Message msgs = 2;
|
||||
@ -17,4 +17,4 @@ message RPC {
|
||||
optional bytes signature = 5;
|
||||
optional bytes key = 6;
|
||||
}
|
||||
}`
|
||||
}
|
2
src/pubsub/message/rpc.proto.d.ts
vendored
2
src/pubsub/message/rpc.proto.d.ts
vendored
@ -1,2 +0,0 @@
|
||||
declare const _exports: string;
|
||||
export = _exports;
|
23
src/pubsub/message/sign.d.ts
vendored
23
src/pubsub/message/sign.d.ts
vendored
@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Returns the PublicKey associated with the given message.
|
||||
* If no, valid PublicKey can be retrieved an error will be returned.
|
||||
*
|
||||
* @param {InMessage} message
|
||||
* @returns {Promise<PublicKey>}
|
||||
*/
|
||||
export function messagePublicKey(message: any): Promise<any>;
|
||||
/**
|
||||
* Signs the provided message with the given `peerId`
|
||||
*
|
||||
* @param {PeerId} peerId
|
||||
* @param {Message} message
|
||||
* @returns {Promise<Message>}
|
||||
*/
|
||||
export function signMessage(peerId: import("peer-id"), message: any): Promise<any>;
|
||||
export const SignPrefix: any;
|
||||
/**
|
||||
* Verifies the signature of the given message
|
||||
* @param {InMessage} message
|
||||
* @returns {Promise<Boolean>}
|
||||
*/
|
||||
export function verifySignature(message: any): Promise<boolean>;
|
@ -1,23 +1,27 @@
|
||||
'use strict'
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const { Message } = require('./index')
|
||||
const { RPC } = require('./rpc')
|
||||
const uint8ArrayConcat = require('uint8arrays/concat')
|
||||
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||
const SignPrefix = uint8ArrayFromString('libp2p-pubsub:')
|
||||
|
||||
/**
|
||||
* @typedef {import('..').InMessage}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Signs the provided message with the given `peerId`
|
||||
*
|
||||
* @param {PeerId} peerId
|
||||
* @param {Message} message
|
||||
* @returns {Promise<Message>}
|
||||
* @param {RPC.Message} message
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
async function signMessage (peerId, message) {
|
||||
// Get the message in bytes, and prepend with the pubsub prefix
|
||||
const bytes = uint8ArrayConcat([
|
||||
SignPrefix,
|
||||
Message.encode(message)
|
||||
RPC.Message.encode(message).finish()
|
||||
])
|
||||
|
||||
const signature = await peerId.privKey.sign(bytes)
|
||||
@ -31,18 +35,25 @@ async function signMessage (peerId, message) {
|
||||
|
||||
/**
|
||||
* Verifies the signature of the given message
|
||||
*
|
||||
* @param {InMessage} message
|
||||
* @returns {Promise<Boolean>}
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
async function verifySignature (message) {
|
||||
if (!message.signature) {
|
||||
throw new Error('Message must contain a signature to be verified')
|
||||
}
|
||||
|
||||
// Get message sans the signature
|
||||
const baseMessage = { ...message }
|
||||
delete baseMessage.signature
|
||||
delete baseMessage.key
|
||||
baseMessage.from = PeerId.createFromCID(baseMessage.from).toBytes()
|
||||
const bytes = uint8ArrayConcat([
|
||||
SignPrefix,
|
||||
Message.encode(baseMessage)
|
||||
RPC.Message.encode({
|
||||
...message,
|
||||
// @ts-ignore message.from needs to exist
|
||||
from: PeerId.createFromCID(message.from).toBytes(),
|
||||
signature: undefined,
|
||||
key: undefined
|
||||
}).finish()
|
||||
])
|
||||
|
||||
// Get the public key
|
||||
@ -61,13 +72,17 @@ async function verifySignature (message) {
|
||||
*/
|
||||
async function messagePublicKey (message) {
|
||||
// should be available in the from property of the message (peer id)
|
||||
if (!message.from) {
|
||||
throw new Error('Could not get the public key from the originator id')
|
||||
}
|
||||
|
||||
const from = PeerId.createFromCID(message.from)
|
||||
|
||||
if (message.key) {
|
||||
const keyPeerId = await PeerId.createFromPubKey(message.key)
|
||||
|
||||
// the key belongs to the sender, return the key
|
||||
if (keyPeerId.isEqual(from)) return keyPeerId.pubKey
|
||||
if (keyPeerId.equals(from)) return keyPeerId.pubKey
|
||||
// We couldn't validate pubkey is from the originator, error
|
||||
throw new Error('Public Key does not match the originator')
|
||||
} else if (from.pubKey) {
|
||||
@ -77,6 +92,11 @@ async function messagePublicKey (message) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {import('..').InMessage} InMessage
|
||||
* @typedef {import('libp2p-crypto').PublicKey} PublicKey
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
messagePublicKey,
|
||||
signMessage,
|
||||
|
224
src/pubsub/message/topic-descriptor.d.ts
vendored
Normal file
224
src/pubsub/message/topic-descriptor.d.ts
vendored
Normal file
@ -0,0 +1,224 @@
|
||||
import * as $protobuf from "protobufjs";
|
||||
/** Properties of a TopicDescriptor. */
|
||||
export interface ITopicDescriptor {
|
||||
|
||||
/** TopicDescriptor name */
|
||||
name?: (string|null);
|
||||
|
||||
/** TopicDescriptor auth */
|
||||
auth?: (TopicDescriptor.IAuthOpts|null);
|
||||
|
||||
/** TopicDescriptor enc */
|
||||
enc?: (TopicDescriptor.IEncOpts|null);
|
||||
}
|
||||
|
||||
/** Represents a TopicDescriptor. */
|
||||
export class TopicDescriptor implements ITopicDescriptor {
|
||||
|
||||
/**
|
||||
* Constructs a new TopicDescriptor.
|
||||
* @param [p] Properties to set
|
||||
*/
|
||||
constructor(p?: ITopicDescriptor);
|
||||
|
||||
/** TopicDescriptor name. */
|
||||
public name: string;
|
||||
|
||||
/** TopicDescriptor auth. */
|
||||
public auth?: (TopicDescriptor.IAuthOpts|null);
|
||||
|
||||
/** TopicDescriptor enc. */
|
||||
public enc?: (TopicDescriptor.IEncOpts|null);
|
||||
|
||||
/**
|
||||
* Encodes the specified TopicDescriptor message. Does not implicitly {@link TopicDescriptor.verify|verify} messages.
|
||||
* @param m TopicDescriptor message or plain object to encode
|
||||
* @param [w] Writer to encode to
|
||||
* @returns Writer
|
||||
*/
|
||||
public static encode(m: ITopicDescriptor, w?: $protobuf.Writer): $protobuf.Writer;
|
||||
|
||||
/**
|
||||
* Decodes a TopicDescriptor message from the specified reader or buffer.
|
||||
* @param r Reader or buffer to decode from
|
||||
* @param [l] Message length if known beforehand
|
||||
* @returns TopicDescriptor
|
||||
* @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): TopicDescriptor;
|
||||
|
||||
/**
|
||||
* Creates a TopicDescriptor message from a plain object. Also converts values to their respective internal types.
|
||||
* @param d Plain object
|
||||
* @returns TopicDescriptor
|
||||
*/
|
||||
public static fromObject(d: { [k: string]: any }): TopicDescriptor;
|
||||
|
||||
/**
|
||||
* Creates a plain object from a TopicDescriptor message. Also converts values to other types if specified.
|
||||
* @param m TopicDescriptor
|
||||
* @param [o] Conversion options
|
||||
* @returns Plain object
|
||||
*/
|
||||
public static toObject(m: TopicDescriptor, o?: $protobuf.IConversionOptions): { [k: string]: any };
|
||||
|
||||
/**
|
||||
* Converts this TopicDescriptor to JSON.
|
||||
* @returns JSON object
|
||||
*/
|
||||
public toJSON(): { [k: string]: any };
|
||||
}
|
||||
|
||||
export namespace TopicDescriptor {
|
||||
|
||||
/** Properties of an AuthOpts. */
|
||||
interface IAuthOpts {
|
||||
|
||||
/** AuthOpts mode */
|
||||
mode?: (TopicDescriptor.AuthOpts.AuthMode|null);
|
||||
|
||||
/** AuthOpts keys */
|
||||
keys?: (Uint8Array[]|null);
|
||||
}
|
||||
|
||||
/** Represents an AuthOpts. */
|
||||
class AuthOpts implements IAuthOpts {
|
||||
|
||||
/**
|
||||
* Constructs a new AuthOpts.
|
||||
* @param [p] Properties to set
|
||||
*/
|
||||
constructor(p?: TopicDescriptor.IAuthOpts);
|
||||
|
||||
/** AuthOpts mode. */
|
||||
public mode: TopicDescriptor.AuthOpts.AuthMode;
|
||||
|
||||
/** AuthOpts keys. */
|
||||
public keys: Uint8Array[];
|
||||
|
||||
/**
|
||||
* Encodes the specified AuthOpts message. Does not implicitly {@link TopicDescriptor.AuthOpts.verify|verify} messages.
|
||||
* @param m AuthOpts message or plain object to encode
|
||||
* @param [w] Writer to encode to
|
||||
* @returns Writer
|
||||
*/
|
||||
public static encode(m: TopicDescriptor.IAuthOpts, w?: $protobuf.Writer): $protobuf.Writer;
|
||||
|
||||
/**
|
||||
* Decodes an AuthOpts message from the specified reader or buffer.
|
||||
* @param r Reader or buffer to decode from
|
||||
* @param [l] Message length if known beforehand
|
||||
* @returns AuthOpts
|
||||
* @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): TopicDescriptor.AuthOpts;
|
||||
|
||||
/**
|
||||
* Creates an AuthOpts message from a plain object. Also converts values to their respective internal types.
|
||||
* @param d Plain object
|
||||
* @returns AuthOpts
|
||||
*/
|
||||
public static fromObject(d: { [k: string]: any }): TopicDescriptor.AuthOpts;
|
||||
|
||||
/**
|
||||
* Creates a plain object from an AuthOpts message. Also converts values to other types if specified.
|
||||
* @param m AuthOpts
|
||||
* @param [o] Conversion options
|
||||
* @returns Plain object
|
||||
*/
|
||||
public static toObject(m: TopicDescriptor.AuthOpts, o?: $protobuf.IConversionOptions): { [k: string]: any };
|
||||
|
||||
/**
|
||||
* Converts this AuthOpts to JSON.
|
||||
* @returns JSON object
|
||||
*/
|
||||
public toJSON(): { [k: string]: any };
|
||||
}
|
||||
|
||||
namespace AuthOpts {
|
||||
|
||||
/** AuthMode enum. */
|
||||
enum AuthMode {
|
||||
NONE = 0,
|
||||
KEY = 1,
|
||||
WOT = 2
|
||||
}
|
||||
}
|
||||
|
||||
/** Properties of an EncOpts. */
|
||||
interface IEncOpts {
|
||||
|
||||
/** EncOpts mode */
|
||||
mode?: (TopicDescriptor.EncOpts.EncMode|null);
|
||||
|
||||
/** EncOpts keyHashes */
|
||||
keyHashes?: (Uint8Array[]|null);
|
||||
}
|
||||
|
||||
/** Represents an EncOpts. */
|
||||
class EncOpts implements IEncOpts {
|
||||
|
||||
/**
|
||||
* Constructs a new EncOpts.
|
||||
* @param [p] Properties to set
|
||||
*/
|
||||
constructor(p?: TopicDescriptor.IEncOpts);
|
||||
|
||||
/** EncOpts mode. */
|
||||
public mode: TopicDescriptor.EncOpts.EncMode;
|
||||
|
||||
/** EncOpts keyHashes. */
|
||||
public keyHashes: Uint8Array[];
|
||||
|
||||
/**
|
||||
* Encodes the specified EncOpts message. Does not implicitly {@link TopicDescriptor.EncOpts.verify|verify} messages.
|
||||
* @param m EncOpts message or plain object to encode
|
||||
* @param [w] Writer to encode to
|
||||
* @returns Writer
|
||||
*/
|
||||
public static encode(m: TopicDescriptor.IEncOpts, w?: $protobuf.Writer): $protobuf.Writer;
|
||||
|
||||
/**
|
||||
* Decodes an EncOpts message from the specified reader or buffer.
|
||||
* @param r Reader or buffer to decode from
|
||||
* @param [l] Message length if known beforehand
|
||||
* @returns EncOpts
|
||||
* @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): TopicDescriptor.EncOpts;
|
||||
|
||||
/**
|
||||
* Creates an EncOpts message from a plain object. Also converts values to their respective internal types.
|
||||
* @param d Plain object
|
||||
* @returns EncOpts
|
||||
*/
|
||||
public static fromObject(d: { [k: string]: any }): TopicDescriptor.EncOpts;
|
||||
|
||||
/**
|
||||
* Creates a plain object from an EncOpts message. Also converts values to other types if specified.
|
||||
* @param m EncOpts
|
||||
* @param [o] Conversion options
|
||||
* @returns Plain object
|
||||
*/
|
||||
public static toObject(m: TopicDescriptor.EncOpts, o?: $protobuf.IConversionOptions): { [k: string]: any };
|
||||
|
||||
/**
|
||||
* Converts this EncOpts to JSON.
|
||||
* @returns JSON object
|
||||
*/
|
||||
public toJSON(): { [k: string]: any };
|
||||
}
|
||||
|
||||
namespace EncOpts {
|
||||
|
||||
/** EncMode enum. */
|
||||
enum EncMode {
|
||||
NONE = 0,
|
||||
SHAREDKEY = 1,
|
||||
WOT = 2
|
||||
}
|
||||
}
|
||||
}
|
586
src/pubsub/message/topic-descriptor.js
Normal file
586
src/pubsub/message/topic-descriptor.js
Normal file
@ -0,0 +1,586 @@
|
||||
/*eslint-disable*/
|
||||
"use strict";
|
||||
|
||||
var $protobuf = require("protobufjs/minimal");
|
||||
|
||||
// Common aliases
|
||||
var $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
|
||||
|
||||
// Exported root namespace
|
||||
var $root = $protobuf.roots["default"] || ($protobuf.roots["default"] = {});
|
||||
|
||||
$root.TopicDescriptor = (function() {
|
||||
|
||||
/**
|
||||
* Properties of a TopicDescriptor.
|
||||
* @exports ITopicDescriptor
|
||||
* @interface ITopicDescriptor
|
||||
* @property {string|null} [name] TopicDescriptor name
|
||||
* @property {TopicDescriptor.IAuthOpts|null} [auth] TopicDescriptor auth
|
||||
* @property {TopicDescriptor.IEncOpts|null} [enc] TopicDescriptor enc
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructs a new TopicDescriptor.
|
||||
* @exports TopicDescriptor
|
||||
* @classdesc Represents a TopicDescriptor.
|
||||
* @implements ITopicDescriptor
|
||||
* @constructor
|
||||
* @param {ITopicDescriptor=} [p] Properties to set
|
||||
*/
|
||||
function TopicDescriptor(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]];
|
||||
}
|
||||
|
||||
/**
|
||||
* TopicDescriptor name.
|
||||
* @member {string} name
|
||||
* @memberof TopicDescriptor
|
||||
* @instance
|
||||
*/
|
||||
TopicDescriptor.prototype.name = "";
|
||||
|
||||
/**
|
||||
* TopicDescriptor auth.
|
||||
* @member {TopicDescriptor.IAuthOpts|null|undefined} auth
|
||||
* @memberof TopicDescriptor
|
||||
* @instance
|
||||
*/
|
||||
TopicDescriptor.prototype.auth = null;
|
||||
|
||||
/**
|
||||
* TopicDescriptor enc.
|
||||
* @member {TopicDescriptor.IEncOpts|null|undefined} enc
|
||||
* @memberof TopicDescriptor
|
||||
* @instance
|
||||
*/
|
||||
TopicDescriptor.prototype.enc = null;
|
||||
|
||||
/**
|
||||
* Encodes the specified TopicDescriptor message. Does not implicitly {@link TopicDescriptor.verify|verify} messages.
|
||||
* @function encode
|
||||
* @memberof TopicDescriptor
|
||||
* @static
|
||||
* @param {ITopicDescriptor} m TopicDescriptor message or plain object to encode
|
||||
* @param {$protobuf.Writer} [w] Writer to encode to
|
||||
* @returns {$protobuf.Writer} Writer
|
||||
*/
|
||||
TopicDescriptor.encode = function encode(m, w) {
|
||||
if (!w)
|
||||
w = $Writer.create();
|
||||
if (m.name != null && Object.hasOwnProperty.call(m, "name"))
|
||||
w.uint32(10).string(m.name);
|
||||
if (m.auth != null && Object.hasOwnProperty.call(m, "auth"))
|
||||
$root.TopicDescriptor.AuthOpts.encode(m.auth, w.uint32(18).fork()).ldelim();
|
||||
if (m.enc != null && Object.hasOwnProperty.call(m, "enc"))
|
||||
$root.TopicDescriptor.EncOpts.encode(m.enc, w.uint32(26).fork()).ldelim();
|
||||
return w;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes a TopicDescriptor message from the specified reader or buffer.
|
||||
* @function decode
|
||||
* @memberof TopicDescriptor
|
||||
* @static
|
||||
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
|
||||
* @param {number} [l] Message length if known beforehand
|
||||
* @returns {TopicDescriptor} TopicDescriptor
|
||||
* @throws {Error} If the payload is not a reader or valid buffer
|
||||
* @throws {$protobuf.util.ProtocolError} If required fields are missing
|
||||
*/
|
||||
TopicDescriptor.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.TopicDescriptor();
|
||||
while (r.pos < c) {
|
||||
var t = r.uint32();
|
||||
switch (t >>> 3) {
|
||||
case 1:
|
||||
m.name = r.string();
|
||||
break;
|
||||
case 2:
|
||||
m.auth = $root.TopicDescriptor.AuthOpts.decode(r, r.uint32());
|
||||
break;
|
||||
case 3:
|
||||
m.enc = $root.TopicDescriptor.EncOpts.decode(r, r.uint32());
|
||||
break;
|
||||
default:
|
||||
r.skipType(t & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a TopicDescriptor message from a plain object. Also converts values to their respective internal types.
|
||||
* @function fromObject
|
||||
* @memberof TopicDescriptor
|
||||
* @static
|
||||
* @param {Object.<string,*>} d Plain object
|
||||
* @returns {TopicDescriptor} TopicDescriptor
|
||||
*/
|
||||
TopicDescriptor.fromObject = function fromObject(d) {
|
||||
if (d instanceof $root.TopicDescriptor)
|
||||
return d;
|
||||
var m = new $root.TopicDescriptor();
|
||||
if (d.name != null) {
|
||||
m.name = String(d.name);
|
||||
}
|
||||
if (d.auth != null) {
|
||||
if (typeof d.auth !== "object")
|
||||
throw TypeError(".TopicDescriptor.auth: object expected");
|
||||
m.auth = $root.TopicDescriptor.AuthOpts.fromObject(d.auth);
|
||||
}
|
||||
if (d.enc != null) {
|
||||
if (typeof d.enc !== "object")
|
||||
throw TypeError(".TopicDescriptor.enc: object expected");
|
||||
m.enc = $root.TopicDescriptor.EncOpts.fromObject(d.enc);
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a plain object from a TopicDescriptor message. Also converts values to other types if specified.
|
||||
* @function toObject
|
||||
* @memberof TopicDescriptor
|
||||
* @static
|
||||
* @param {TopicDescriptor} m TopicDescriptor
|
||||
* @param {$protobuf.IConversionOptions} [o] Conversion options
|
||||
* @returns {Object.<string,*>} Plain object
|
||||
*/
|
||||
TopicDescriptor.toObject = function toObject(m, o) {
|
||||
if (!o)
|
||||
o = {};
|
||||
var d = {};
|
||||
if (o.defaults) {
|
||||
d.name = "";
|
||||
d.auth = null;
|
||||
d.enc = null;
|
||||
}
|
||||
if (m.name != null && m.hasOwnProperty("name")) {
|
||||
d.name = m.name;
|
||||
}
|
||||
if (m.auth != null && m.hasOwnProperty("auth")) {
|
||||
d.auth = $root.TopicDescriptor.AuthOpts.toObject(m.auth, o);
|
||||
}
|
||||
if (m.enc != null && m.hasOwnProperty("enc")) {
|
||||
d.enc = $root.TopicDescriptor.EncOpts.toObject(m.enc, o);
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts this TopicDescriptor to JSON.
|
||||
* @function toJSON
|
||||
* @memberof TopicDescriptor
|
||||
* @instance
|
||||
* @returns {Object.<string,*>} JSON object
|
||||
*/
|
||||
TopicDescriptor.prototype.toJSON = function toJSON() {
|
||||
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
|
||||
};
|
||||
|
||||
TopicDescriptor.AuthOpts = (function() {
|
||||
|
||||
/**
|
||||
* Properties of an AuthOpts.
|
||||
* @memberof TopicDescriptor
|
||||
* @interface IAuthOpts
|
||||
* @property {TopicDescriptor.AuthOpts.AuthMode|null} [mode] AuthOpts mode
|
||||
* @property {Array.<Uint8Array>|null} [keys] AuthOpts keys
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructs a new AuthOpts.
|
||||
* @memberof TopicDescriptor
|
||||
* @classdesc Represents an AuthOpts.
|
||||
* @implements IAuthOpts
|
||||
* @constructor
|
||||
* @param {TopicDescriptor.IAuthOpts=} [p] Properties to set
|
||||
*/
|
||||
function AuthOpts(p) {
|
||||
this.keys = [];
|
||||
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]];
|
||||
}
|
||||
|
||||
/**
|
||||
* AuthOpts mode.
|
||||
* @member {TopicDescriptor.AuthOpts.AuthMode} mode
|
||||
* @memberof TopicDescriptor.AuthOpts
|
||||
* @instance
|
||||
*/
|
||||
AuthOpts.prototype.mode = 0;
|
||||
|
||||
/**
|
||||
* AuthOpts keys.
|
||||
* @member {Array.<Uint8Array>} keys
|
||||
* @memberof TopicDescriptor.AuthOpts
|
||||
* @instance
|
||||
*/
|
||||
AuthOpts.prototype.keys = $util.emptyArray;
|
||||
|
||||
/**
|
||||
* Encodes the specified AuthOpts message. Does not implicitly {@link TopicDescriptor.AuthOpts.verify|verify} messages.
|
||||
* @function encode
|
||||
* @memberof TopicDescriptor.AuthOpts
|
||||
* @static
|
||||
* @param {TopicDescriptor.IAuthOpts} m AuthOpts message or plain object to encode
|
||||
* @param {$protobuf.Writer} [w] Writer to encode to
|
||||
* @returns {$protobuf.Writer} Writer
|
||||
*/
|
||||
AuthOpts.encode = function encode(m, w) {
|
||||
if (!w)
|
||||
w = $Writer.create();
|
||||
if (m.mode != null && Object.hasOwnProperty.call(m, "mode"))
|
||||
w.uint32(8).int32(m.mode);
|
||||
if (m.keys != null && m.keys.length) {
|
||||
for (var i = 0; i < m.keys.length; ++i)
|
||||
w.uint32(18).bytes(m.keys[i]);
|
||||
}
|
||||
return w;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes an AuthOpts message from the specified reader or buffer.
|
||||
* @function decode
|
||||
* @memberof TopicDescriptor.AuthOpts
|
||||
* @static
|
||||
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
|
||||
* @param {number} [l] Message length if known beforehand
|
||||
* @returns {TopicDescriptor.AuthOpts} AuthOpts
|
||||
* @throws {Error} If the payload is not a reader or valid buffer
|
||||
* @throws {$protobuf.util.ProtocolError} If required fields are missing
|
||||
*/
|
||||
AuthOpts.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.TopicDescriptor.AuthOpts();
|
||||
while (r.pos < c) {
|
||||
var t = r.uint32();
|
||||
switch (t >>> 3) {
|
||||
case 1:
|
||||
m.mode = r.int32();
|
||||
break;
|
||||
case 2:
|
||||
if (!(m.keys && m.keys.length))
|
||||
m.keys = [];
|
||||
m.keys.push(r.bytes());
|
||||
break;
|
||||
default:
|
||||
r.skipType(t & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an AuthOpts message from a plain object. Also converts values to their respective internal types.
|
||||
* @function fromObject
|
||||
* @memberof TopicDescriptor.AuthOpts
|
||||
* @static
|
||||
* @param {Object.<string,*>} d Plain object
|
||||
* @returns {TopicDescriptor.AuthOpts} AuthOpts
|
||||
*/
|
||||
AuthOpts.fromObject = function fromObject(d) {
|
||||
if (d instanceof $root.TopicDescriptor.AuthOpts)
|
||||
return d;
|
||||
var m = new $root.TopicDescriptor.AuthOpts();
|
||||
switch (d.mode) {
|
||||
case "NONE":
|
||||
case 0:
|
||||
m.mode = 0;
|
||||
break;
|
||||
case "KEY":
|
||||
case 1:
|
||||
m.mode = 1;
|
||||
break;
|
||||
case "WOT":
|
||||
case 2:
|
||||
m.mode = 2;
|
||||
break;
|
||||
}
|
||||
if (d.keys) {
|
||||
if (!Array.isArray(d.keys))
|
||||
throw TypeError(".TopicDescriptor.AuthOpts.keys: array expected");
|
||||
m.keys = [];
|
||||
for (var i = 0; i < d.keys.length; ++i) {
|
||||
if (typeof d.keys[i] === "string")
|
||||
$util.base64.decode(d.keys[i], m.keys[i] = $util.newBuffer($util.base64.length(d.keys[i])), 0);
|
||||
else if (d.keys[i].length)
|
||||
m.keys[i] = d.keys[i];
|
||||
}
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a plain object from an AuthOpts message. Also converts values to other types if specified.
|
||||
* @function toObject
|
||||
* @memberof TopicDescriptor.AuthOpts
|
||||
* @static
|
||||
* @param {TopicDescriptor.AuthOpts} m AuthOpts
|
||||
* @param {$protobuf.IConversionOptions} [o] Conversion options
|
||||
* @returns {Object.<string,*>} Plain object
|
||||
*/
|
||||
AuthOpts.toObject = function toObject(m, o) {
|
||||
if (!o)
|
||||
o = {};
|
||||
var d = {};
|
||||
if (o.arrays || o.defaults) {
|
||||
d.keys = [];
|
||||
}
|
||||
if (o.defaults) {
|
||||
d.mode = o.enums === String ? "NONE" : 0;
|
||||
}
|
||||
if (m.mode != null && m.hasOwnProperty("mode")) {
|
||||
d.mode = o.enums === String ? $root.TopicDescriptor.AuthOpts.AuthMode[m.mode] : m.mode;
|
||||
}
|
||||
if (m.keys && m.keys.length) {
|
||||
d.keys = [];
|
||||
for (var j = 0; j < m.keys.length; ++j) {
|
||||
d.keys[j] = o.bytes === String ? $util.base64.encode(m.keys[j], 0, m.keys[j].length) : o.bytes === Array ? Array.prototype.slice.call(m.keys[j]) : m.keys[j];
|
||||
}
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts this AuthOpts to JSON.
|
||||
* @function toJSON
|
||||
* @memberof TopicDescriptor.AuthOpts
|
||||
* @instance
|
||||
* @returns {Object.<string,*>} JSON object
|
||||
*/
|
||||
AuthOpts.prototype.toJSON = function toJSON() {
|
||||
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
|
||||
};
|
||||
|
||||
/**
|
||||
* AuthMode enum.
|
||||
* @name TopicDescriptor.AuthOpts.AuthMode
|
||||
* @enum {number}
|
||||
* @property {number} NONE=0 NONE value
|
||||
* @property {number} KEY=1 KEY value
|
||||
* @property {number} WOT=2 WOT value
|
||||
*/
|
||||
AuthOpts.AuthMode = (function() {
|
||||
var valuesById = {}, values = Object.create(valuesById);
|
||||
values[valuesById[0] = "NONE"] = 0;
|
||||
values[valuesById[1] = "KEY"] = 1;
|
||||
values[valuesById[2] = "WOT"] = 2;
|
||||
return values;
|
||||
})();
|
||||
|
||||
return AuthOpts;
|
||||
})();
|
||||
|
||||
TopicDescriptor.EncOpts = (function() {
|
||||
|
||||
/**
|
||||
* Properties of an EncOpts.
|
||||
* @memberof TopicDescriptor
|
||||
* @interface IEncOpts
|
||||
* @property {TopicDescriptor.EncOpts.EncMode|null} [mode] EncOpts mode
|
||||
* @property {Array.<Uint8Array>|null} [keyHashes] EncOpts keyHashes
|
||||
*/
|
||||
|
||||
/**
|
||||
* Constructs a new EncOpts.
|
||||
* @memberof TopicDescriptor
|
||||
* @classdesc Represents an EncOpts.
|
||||
* @implements IEncOpts
|
||||
* @constructor
|
||||
* @param {TopicDescriptor.IEncOpts=} [p] Properties to set
|
||||
*/
|
||||
function EncOpts(p) {
|
||||
this.keyHashes = [];
|
||||
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]];
|
||||
}
|
||||
|
||||
/**
|
||||
* EncOpts mode.
|
||||
* @member {TopicDescriptor.EncOpts.EncMode} mode
|
||||
* @memberof TopicDescriptor.EncOpts
|
||||
* @instance
|
||||
*/
|
||||
EncOpts.prototype.mode = 0;
|
||||
|
||||
/**
|
||||
* EncOpts keyHashes.
|
||||
* @member {Array.<Uint8Array>} keyHashes
|
||||
* @memberof TopicDescriptor.EncOpts
|
||||
* @instance
|
||||
*/
|
||||
EncOpts.prototype.keyHashes = $util.emptyArray;
|
||||
|
||||
/**
|
||||
* Encodes the specified EncOpts message. Does not implicitly {@link TopicDescriptor.EncOpts.verify|verify} messages.
|
||||
* @function encode
|
||||
* @memberof TopicDescriptor.EncOpts
|
||||
* @static
|
||||
* @param {TopicDescriptor.IEncOpts} m EncOpts message or plain object to encode
|
||||
* @param {$protobuf.Writer} [w] Writer to encode to
|
||||
* @returns {$protobuf.Writer} Writer
|
||||
*/
|
||||
EncOpts.encode = function encode(m, w) {
|
||||
if (!w)
|
||||
w = $Writer.create();
|
||||
if (m.mode != null && Object.hasOwnProperty.call(m, "mode"))
|
||||
w.uint32(8).int32(m.mode);
|
||||
if (m.keyHashes != null && m.keyHashes.length) {
|
||||
for (var i = 0; i < m.keyHashes.length; ++i)
|
||||
w.uint32(18).bytes(m.keyHashes[i]);
|
||||
}
|
||||
return w;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decodes an EncOpts message from the specified reader or buffer.
|
||||
* @function decode
|
||||
* @memberof TopicDescriptor.EncOpts
|
||||
* @static
|
||||
* @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
|
||||
* @param {number} [l] Message length if known beforehand
|
||||
* @returns {TopicDescriptor.EncOpts} EncOpts
|
||||
* @throws {Error} If the payload is not a reader or valid buffer
|
||||
* @throws {$protobuf.util.ProtocolError} If required fields are missing
|
||||
*/
|
||||
EncOpts.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.TopicDescriptor.EncOpts();
|
||||
while (r.pos < c) {
|
||||
var t = r.uint32();
|
||||
switch (t >>> 3) {
|
||||
case 1:
|
||||
m.mode = r.int32();
|
||||
break;
|
||||
case 2:
|
||||
if (!(m.keyHashes && m.keyHashes.length))
|
||||
m.keyHashes = [];
|
||||
m.keyHashes.push(r.bytes());
|
||||
break;
|
||||
default:
|
||||
r.skipType(t & 7);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an EncOpts message from a plain object. Also converts values to their respective internal types.
|
||||
* @function fromObject
|
||||
* @memberof TopicDescriptor.EncOpts
|
||||
* @static
|
||||
* @param {Object.<string,*>} d Plain object
|
||||
* @returns {TopicDescriptor.EncOpts} EncOpts
|
||||
*/
|
||||
EncOpts.fromObject = function fromObject(d) {
|
||||
if (d instanceof $root.TopicDescriptor.EncOpts)
|
||||
return d;
|
||||
var m = new $root.TopicDescriptor.EncOpts();
|
||||
switch (d.mode) {
|
||||
case "NONE":
|
||||
case 0:
|
||||
m.mode = 0;
|
||||
break;
|
||||
case "SHAREDKEY":
|
||||
case 1:
|
||||
m.mode = 1;
|
||||
break;
|
||||
case "WOT":
|
||||
case 2:
|
||||
m.mode = 2;
|
||||
break;
|
||||
}
|
||||
if (d.keyHashes) {
|
||||
if (!Array.isArray(d.keyHashes))
|
||||
throw TypeError(".TopicDescriptor.EncOpts.keyHashes: array expected");
|
||||
m.keyHashes = [];
|
||||
for (var i = 0; i < d.keyHashes.length; ++i) {
|
||||
if (typeof d.keyHashes[i] === "string")
|
||||
$util.base64.decode(d.keyHashes[i], m.keyHashes[i] = $util.newBuffer($util.base64.length(d.keyHashes[i])), 0);
|
||||
else if (d.keyHashes[i].length)
|
||||
m.keyHashes[i] = d.keyHashes[i];
|
||||
}
|
||||
}
|
||||
return m;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a plain object from an EncOpts message. Also converts values to other types if specified.
|
||||
* @function toObject
|
||||
* @memberof TopicDescriptor.EncOpts
|
||||
* @static
|
||||
* @param {TopicDescriptor.EncOpts} m EncOpts
|
||||
* @param {$protobuf.IConversionOptions} [o] Conversion options
|
||||
* @returns {Object.<string,*>} Plain object
|
||||
*/
|
||||
EncOpts.toObject = function toObject(m, o) {
|
||||
if (!o)
|
||||
o = {};
|
||||
var d = {};
|
||||
if (o.arrays || o.defaults) {
|
||||
d.keyHashes = [];
|
||||
}
|
||||
if (o.defaults) {
|
||||
d.mode = o.enums === String ? "NONE" : 0;
|
||||
}
|
||||
if (m.mode != null && m.hasOwnProperty("mode")) {
|
||||
d.mode = o.enums === String ? $root.TopicDescriptor.EncOpts.EncMode[m.mode] : m.mode;
|
||||
}
|
||||
if (m.keyHashes && m.keyHashes.length) {
|
||||
d.keyHashes = [];
|
||||
for (var j = 0; j < m.keyHashes.length; ++j) {
|
||||
d.keyHashes[j] = o.bytes === String ? $util.base64.encode(m.keyHashes[j], 0, m.keyHashes[j].length) : o.bytes === Array ? Array.prototype.slice.call(m.keyHashes[j]) : m.keyHashes[j];
|
||||
}
|
||||
}
|
||||
return d;
|
||||
};
|
||||
|
||||
/**
|
||||
* Converts this EncOpts to JSON.
|
||||
* @function toJSON
|
||||
* @memberof TopicDescriptor.EncOpts
|
||||
* @instance
|
||||
* @returns {Object.<string,*>} JSON object
|
||||
*/
|
||||
EncOpts.prototype.toJSON = function toJSON() {
|
||||
return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
|
||||
};
|
||||
|
||||
/**
|
||||
* EncMode enum.
|
||||
* @name TopicDescriptor.EncOpts.EncMode
|
||||
* @enum {number}
|
||||
* @property {number} NONE=0 NONE value
|
||||
* @property {number} SHAREDKEY=1 SHAREDKEY value
|
||||
* @property {number} WOT=2 WOT value
|
||||
*/
|
||||
EncOpts.EncMode = (function() {
|
||||
var valuesById = {}, values = Object.create(valuesById);
|
||||
values[valuesById[0] = "NONE"] = 0;
|
||||
values[valuesById[1] = "SHAREDKEY"] = 1;
|
||||
values[valuesById[2] = "WOT"] = 2;
|
||||
return values;
|
||||
})();
|
||||
|
||||
return EncOpts;
|
||||
})();
|
||||
|
||||
return TopicDescriptor;
|
||||
})();
|
||||
|
||||
module.exports = $root;
|
@ -1,10 +1,10 @@
|
||||
'use strict'
|
||||
module.exports = `
|
||||
syntax = "proto3";
|
||||
|
||||
// topicCID = cid(merkledag_protobuf(topicDescriptor)); (not the topic.name)
|
||||
message TopicDescriptor {
|
||||
optional string name = 1;
|
||||
optional AuthOpts auth = 2;
|
||||
optional EncOpts enc = 2;
|
||||
optional EncOpts enc = 3;
|
||||
|
||||
message AuthOpts {
|
||||
optional AuthMode mode = 1;
|
||||
@ -27,4 +27,4 @@ message TopicDescriptor {
|
||||
WOT = 2; // web of trust, certificates can allow publisher set to grow
|
||||
}
|
||||
}
|
||||
}`
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
declare const _exports: string;
|
||||
export = _exports;
|
113
src/pubsub/peer-streams.d.ts
vendored
113
src/pubsub/peer-streams.d.ts
vendored
@ -1,113 +0,0 @@
|
||||
export = PeerStreams;
|
||||
/**
|
||||
* @callback Sink
|
||||
* @param {Uint8Array} source
|
||||
* @returns {Promise<Uint8Array>}
|
||||
*
|
||||
* @typedef {object} DuplexIterableStream
|
||||
* @property {Sink} sink
|
||||
* @property {() AsyncIterator<Uint8Array>} source
|
||||
*
|
||||
* @typedef PeerId
|
||||
* @type import('peer-id')
|
||||
*/
|
||||
/**
|
||||
* Thin wrapper around a peer's inbound / outbound pubsub streams
|
||||
*/
|
||||
declare class PeerStreams {
|
||||
/**
|
||||
* @param {object} properties properties of the PeerStreams.
|
||||
* @param {PeerId} properties.id
|
||||
* @param {string} properties.protocol
|
||||
*/
|
||||
constructor({ id, protocol }: {
|
||||
id: import("peer-id");
|
||||
protocol: string;
|
||||
});
|
||||
/**
|
||||
* @type {import('peer-id')}
|
||||
*/
|
||||
id: import('peer-id');
|
||||
/**
|
||||
* Established protocol
|
||||
* @type {string}
|
||||
*/
|
||||
protocol: string;
|
||||
/**
|
||||
* The raw outbound stream, as retrieved from conn.newStream
|
||||
* @private
|
||||
* @type {DuplexIterableStream}
|
||||
*/
|
||||
_rawOutboundStream: DuplexIterableStream;
|
||||
/**
|
||||
* The raw inbound stream, as retrieved from the callback from libp2p.handle
|
||||
* @private
|
||||
* @type {DuplexIterableStream}
|
||||
*/
|
||||
_rawInboundStream: DuplexIterableStream;
|
||||
/**
|
||||
* An AbortController for controlled shutdown of the inbound stream
|
||||
* @private
|
||||
* @type {typeof AbortController}
|
||||
*/
|
||||
_inboundAbortController: typeof AbortController;
|
||||
/**
|
||||
* Write stream -- its preferable to use the write method
|
||||
* @type {import('it-pushable').Pushable<Uint8Array>>}
|
||||
*/
|
||||
outboundStream: import('it-pushable').Pushable<Uint8Array>;
|
||||
/**
|
||||
* Read stream
|
||||
* @type {DuplexIterableStream}
|
||||
*/
|
||||
inboundStream: DuplexIterableStream;
|
||||
/**
|
||||
* Do we have a connection to read from?
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isReadable(): boolean;
|
||||
/**
|
||||
* Do we have a connection to write on?
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
get isWritable(): boolean;
|
||||
/**
|
||||
* Send a message to this peer.
|
||||
* Throws if there is no `stream` to write to available.
|
||||
*
|
||||
* @param {Uint8Array} data
|
||||
* @returns {void}
|
||||
*/
|
||||
write(data: Uint8Array): void;
|
||||
/**
|
||||
* Attach a raw inbound stream and setup a read stream
|
||||
*
|
||||
* @param {DuplexIterableStream} stream
|
||||
* @returns {void}
|
||||
*/
|
||||
attachInboundStream(stream: DuplexIterableStream): void;
|
||||
/**
|
||||
* Attach a raw outbound stream and setup a write stream
|
||||
*
|
||||
* @param {Stream} stream
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
attachOutboundStream(stream: any): Promise<void>;
|
||||
/**
|
||||
* Closes the open connection to peer
|
||||
* @returns {void}
|
||||
*/
|
||||
close(): void;
|
||||
}
|
||||
declare namespace PeerStreams {
|
||||
export { Sink, DuplexIterableStream, PeerId };
|
||||
}
|
||||
type DuplexIterableStream = {
|
||||
sink: Sink;
|
||||
source: () => AsyncIterator<Uint8Array, any, undefined>;
|
||||
};
|
||||
declare const AbortController: typeof import("abort-controller");
|
||||
type Sink = (source: Uint8Array) => Promise<Uint8Array>;
|
||||
type PeerId = import("peer-id");
|
@ -1,28 +1,26 @@
|
||||
'use strict'
|
||||
|
||||
const debug = require('debug')
|
||||
const log = Object.assign(debug('libp2p-pubsub:peer-streams'), {
|
||||
error: debug('libp2p-pubsub:peer-streams:err')
|
||||
})
|
||||
|
||||
/** @typedef {import('../types').EventEmitterFactory} Events */
|
||||
/** @type Events */
|
||||
const EventEmitter = require('events')
|
||||
|
||||
// @ts-ignore TODO: https://github.com/alanshaw/it-length-prefixed/pull/15
|
||||
const lp = require('it-length-prefixed')
|
||||
const pushable = require('it-pushable')
|
||||
const pipe = require('it-pipe')
|
||||
const abortable = require('abortable-iterator')
|
||||
const AbortController = require('abort-controller')
|
||||
const debug = require('debug')
|
||||
|
||||
const log = debug('libp2p-pubsub:peer-streams')
|
||||
log.error = debug('libp2p-pubsub:peer-streams:error')
|
||||
const pushable = require('it-pushable')
|
||||
const { pipe } = require('it-pipe')
|
||||
const { source: abortable } = require('abortable-iterator')
|
||||
const AbortController = require('abort-controller').default
|
||||
|
||||
/**
|
||||
* @callback Sink
|
||||
* @param {Uint8Array} source
|
||||
* @returns {Promise<Uint8Array>}
|
||||
*
|
||||
* @typedef {object} DuplexIterableStream
|
||||
* @property {Sink} sink
|
||||
* @property {() AsyncIterator<Uint8Array>} source
|
||||
*
|
||||
* @typedef PeerId
|
||||
* @type import('peer-id')
|
||||
* @typedef {import('../stream-muxer/types').MuxedStream} MuxedStream
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('it-pushable').Pushable<Uint8Array>} PushableStream
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -30,7 +28,7 @@ log.error = debug('libp2p-pubsub:peer-streams:error')
|
||||
*/
|
||||
class PeerStreams extends EventEmitter {
|
||||
/**
|
||||
* @param {object} properties properties of the PeerStreams.
|
||||
* @param {object} properties - properties of the PeerStreams.
|
||||
* @param {PeerId} properties.id
|
||||
* @param {string} properties.protocol
|
||||
*/
|
||||
@ -43,35 +41,41 @@ class PeerStreams extends EventEmitter {
|
||||
this.id = id
|
||||
/**
|
||||
* Established protocol
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
this.protocol = protocol
|
||||
/**
|
||||
* The raw outbound stream, as retrieved from conn.newStream
|
||||
*
|
||||
* @private
|
||||
* @type {DuplexIterableStream}
|
||||
* @type {null|MuxedStream}
|
||||
*/
|
||||
this._rawOutboundStream = null
|
||||
/**
|
||||
* The raw inbound stream, as retrieved from the callback from libp2p.handle
|
||||
*
|
||||
* @private
|
||||
* @type {DuplexIterableStream}
|
||||
* @type {null|MuxedStream}
|
||||
*/
|
||||
this._rawInboundStream = null
|
||||
/**
|
||||
* An AbortController for controlled shutdown of the inbound stream
|
||||
*
|
||||
* @private
|
||||
* @type {typeof AbortController}
|
||||
* @type {AbortController}
|
||||
*/
|
||||
this._inboundAbortController = null
|
||||
this._inboundAbortController = new AbortController()
|
||||
/**
|
||||
* Write stream -- its preferable to use the write method
|
||||
* @type {import('it-pushable').Pushable<Uint8Array>>}
|
||||
*
|
||||
* @type {null|PushableStream}
|
||||
*/
|
||||
this.outboundStream = null
|
||||
/**
|
||||
* Read stream
|
||||
* @type {DuplexIterableStream}
|
||||
*
|
||||
* @type {null| AsyncIterable<Uint8Array>}
|
||||
*/
|
||||
this.inboundStream = null
|
||||
}
|
||||
@ -102,7 +106,7 @@ class PeerStreams extends EventEmitter {
|
||||
* @returns {void}
|
||||
*/
|
||||
write (data) {
|
||||
if (!this.isWritable) {
|
||||
if (!this.outboundStream) {
|
||||
const id = this.id.toB58String()
|
||||
throw new Error('No writable connection to ' + id)
|
||||
}
|
||||
@ -113,15 +117,14 @@ class PeerStreams extends EventEmitter {
|
||||
/**
|
||||
* Attach a raw inbound stream and setup a read stream
|
||||
*
|
||||
* @param {DuplexIterableStream} stream
|
||||
* @returns {void}
|
||||
* @param {MuxedStream} stream
|
||||
* @returns {AsyncIterable<Uint8Array>}
|
||||
*/
|
||||
attachInboundStream (stream) {
|
||||
// Create and attach a new inbound stream
|
||||
// The inbound stream is:
|
||||
// - abortable, set to only return on abort, rather than throw
|
||||
// - transformed with length-prefix transform
|
||||
this._inboundAbortController = new AbortController()
|
||||
this._rawInboundStream = stream
|
||||
this.inboundStream = abortable(
|
||||
pipe(
|
||||
@ -133,31 +136,31 @@ class PeerStreams extends EventEmitter {
|
||||
)
|
||||
|
||||
this.emit('stream:inbound')
|
||||
return this.inboundStream
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a raw outbound stream and setup a write stream
|
||||
*
|
||||
* @param {Stream} stream
|
||||
* @param {MuxedStream} stream
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async attachOutboundStream (stream) {
|
||||
// If an outbound stream already exists,
|
||||
// gently close it
|
||||
// If an outbound stream already exists, gently close it
|
||||
const _prevStream = this.outboundStream
|
||||
if (_prevStream) {
|
||||
if (this.outboundStream) {
|
||||
// End the stream without emitting a close event
|
||||
await this.outboundStream.end(false)
|
||||
await this.outboundStream.end()
|
||||
}
|
||||
|
||||
this._rawOutboundStream = stream
|
||||
this.outboundStream = pushable({
|
||||
onEnd: (shouldEmit) => {
|
||||
// close writable side of the stream
|
||||
this._rawOutboundStream.reset && this._rawOutboundStream.reset()
|
||||
this._rawOutboundStream && this._rawOutboundStream.reset && this._rawOutboundStream.reset()
|
||||
this._rawOutboundStream = null
|
||||
this.outboundStream = null
|
||||
if (shouldEmit !== false) {
|
||||
if (shouldEmit) {
|
||||
this.emit('close')
|
||||
}
|
||||
}
|
||||
@ -167,7 +170,7 @@ class PeerStreams extends EventEmitter {
|
||||
this.outboundStream,
|
||||
lp.encode(),
|
||||
this._rawOutboundStream
|
||||
).catch(err => {
|
||||
).catch(/** @param {Error} err */ err => {
|
||||
log.error(err)
|
||||
})
|
||||
|
||||
@ -179,6 +182,7 @@ class PeerStreams extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Closes the open connection to peer
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
close () {
|
||||
|
33
src/pubsub/signature-policy.js
Normal file
33
src/pubsub/signature-policy.js
Normal file
@ -0,0 +1,33 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Enum for Signature Policy
|
||||
* Details how message signatures are produced/consumed
|
||||
*/
|
||||
const SignaturePolicy = {
|
||||
/**
|
||||
* On the producing side:
|
||||
* * Build messages with the signature, key (from may be enough for certain inlineable public key types), from and seqno fields.
|
||||
*
|
||||
* On the consuming side:
|
||||
* * Enforce the fields to be present, reject otherwise.
|
||||
* * Propagate only if the fields are valid and signature can be verified, reject otherwise.
|
||||
*/
|
||||
StrictSign: /** @type {'StrictSign'} */ ('StrictSign'),
|
||||
/**
|
||||
* On the producing side:
|
||||
* * Build messages without the signature, key, from and seqno fields.
|
||||
* * The corresponding protobuf key-value pairs are absent from the marshalled message, not just empty.
|
||||
*
|
||||
* On the consuming side:
|
||||
* * Enforce the fields to be absent, reject otherwise.
|
||||
* * Propagate only if the fields are absent, reject otherwise.
|
||||
* * A message_id function will not be able to use the above fields, and should instead rely on the data field. A commonplace strategy is to calculate a hash.
|
||||
*/
|
||||
StrictNoSign: /** @type {'StrictNoSign'} */ ('StrictNoSign')
|
||||
}
|
||||
exports.SignaturePolicy = SignaturePolicy
|
||||
|
||||
/**
|
||||
* @typedef {SignaturePolicy[keyof SignaturePolicy]} SignaturePolicyType
|
||||
*/
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
@ -76,7 +77,7 @@ module.exports = (common) => {
|
||||
const defer = pDefer()
|
||||
|
||||
const handler = (msg) => {
|
||||
expect(msg).to.exist()
|
||||
expect(msg).to.not.eql(undefined)
|
||||
defer.resolve()
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
@ -62,7 +63,7 @@ module.exports = (common) => {
|
||||
pubsub.publish(topic, data)
|
||||
|
||||
// Wait 1 second to guarantee that self is not noticed
|
||||
return new Promise((resolve) => setTimeout(() => resolve(), 1000))
|
||||
return new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
@ -10,6 +11,7 @@ const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||
|
||||
const { utils } = require('..')
|
||||
const PeerStreams = require('../peer-streams')
|
||||
const { SignaturePolicy } = require('../signature-policy')
|
||||
|
||||
const topic = 'foo'
|
||||
const data = uint8ArrayFromString('bar')
|
||||
@ -31,24 +33,17 @@ module.exports = (common) => {
|
||||
})
|
||||
|
||||
it('should emit normalized signed messages on publish', async () => {
|
||||
pubsub.globalSignaturePolicy = SignaturePolicy.StrictSign
|
||||
sinon.spy(pubsub, '_emitMessage')
|
||||
sinon.spy(utils, 'randomSeqno')
|
||||
|
||||
await pubsub.publish(topic, data)
|
||||
expect(pubsub._emitMessage.callCount).to.eql(1)
|
||||
|
||||
const [messageToEmit] = pubsub._emitMessage.getCall(0).args
|
||||
|
||||
const expected = utils.normalizeInRpcMessage(
|
||||
await pubsub._buildMessage({
|
||||
receivedFrom: pubsub.peerId.toB58String(),
|
||||
from: pubsub.peerId.toB58String(),
|
||||
data,
|
||||
seqno: utils.randomSeqno.getCall(0).returnValue,
|
||||
topicIDs: [topic]
|
||||
}))
|
||||
|
||||
expect(messageToEmit).to.eql(expected)
|
||||
expect(messageToEmit.seqno).to.not.eql(undefined)
|
||||
expect(messageToEmit.key).to.not.eql(undefined)
|
||||
expect(messageToEmit.signature).to.not.eql(undefined)
|
||||
})
|
||||
|
||||
it('should drop unsigned messages', async () => {
|
||||
@ -56,7 +51,10 @@ module.exports = (common) => {
|
||||
sinon.spy(pubsub, '_publish')
|
||||
sinon.spy(pubsub, 'validate')
|
||||
|
||||
const peerStream = new PeerStreams({ id: await PeerId.create() })
|
||||
const peerStream = new PeerStreams({
|
||||
id: await PeerId.create(),
|
||||
protocol: 'test'
|
||||
})
|
||||
const rpc = {
|
||||
subscriptions: [],
|
||||
msgs: [{
|
||||
@ -83,18 +81,20 @@ module.exports = (common) => {
|
||||
})
|
||||
|
||||
it('should not drop unsigned messages if strict signing is disabled', async () => {
|
||||
pubsub.globalSignaturePolicy = SignaturePolicy.StrictNoSign
|
||||
sinon.spy(pubsub, '_emitMessage')
|
||||
sinon.spy(pubsub, '_publish')
|
||||
sinon.spy(pubsub, 'validate')
|
||||
sinon.stub(pubsub, 'strictSigning').value(false)
|
||||
|
||||
const peerStream = new PeerStreams({ id: await PeerId.create() })
|
||||
const peerStream = new PeerStreams({
|
||||
id: await PeerId.create(),
|
||||
protocol: 'test'
|
||||
})
|
||||
|
||||
const rpc = {
|
||||
subscriptions: [],
|
||||
msgs: [{
|
||||
from: peerStream.id.toBytes(),
|
||||
data,
|
||||
seqno: utils.randomSeqno(),
|
||||
topicIDs: [topic]
|
||||
}]
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
/* eslint max-nested-callbacks: ["error", 6] */
|
||||
'use strict'
|
||||
@ -52,26 +53,20 @@ module.exports = (common) => {
|
||||
await common.teardown()
|
||||
})
|
||||
|
||||
it('subscribe to the topic on node a', () => {
|
||||
it('subscribe to the topic on node a', async () => {
|
||||
const topic = 'Z'
|
||||
const defer = pDefer()
|
||||
|
||||
psA.subscribe(topic)
|
||||
expectSet(psA.subscriptions, [topic])
|
||||
|
||||
psB.once('pubsub:subscription-change', () => {
|
||||
expect(psB.peers.size).to.equal(2)
|
||||
await new Promise((resolve) => psB.once('pubsub:subscription-change', resolve))
|
||||
expect(psB.peers.size).to.equal(2)
|
||||
|
||||
const aPeerId = psA.peerId.toB58String()
|
||||
expectSet(psB.topics.get(topic), [aPeerId])
|
||||
const aPeerId = psA.peerId.toB58String()
|
||||
expectSet(psB.topics.get(topic), [aPeerId])
|
||||
|
||||
expect(psC.peers.size).to.equal(1)
|
||||
expect(psC.topics.get(topic)).to.not.exist()
|
||||
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
return defer.promise
|
||||
expect(psC.peers.size).to.equal(1)
|
||||
expect(psC.topics.get(topic)).to.eql(undefined)
|
||||
})
|
||||
|
||||
it('subscribe to the topic on node b', async () => {
|
||||
@ -119,9 +114,9 @@ module.exports = (common) => {
|
||||
|
||||
// await subscription change
|
||||
await Promise.all([
|
||||
new Promise(resolve => psA.once('pubsub:subscription-change', () => resolve())),
|
||||
new Promise(resolve => psB.once('pubsub:subscription-change', () => resolve())),
|
||||
new Promise(resolve => psC.once('pubsub:subscription-change', () => resolve()))
|
||||
new Promise(resolve => psA.once('pubsub:subscription-change', () => resolve(null))),
|
||||
new Promise(resolve => psB.once('pubsub:subscription-change', () => resolve(null))),
|
||||
new Promise(resolve => psC.once('pubsub:subscription-change', () => resolve(null)))
|
||||
])
|
||||
|
||||
// await a cycle
|
||||
@ -172,9 +167,9 @@ module.exports = (common) => {
|
||||
|
||||
// await subscription change
|
||||
await Promise.all([
|
||||
new Promise(resolve => psA.once('pubsub:subscription-change', () => resolve())),
|
||||
new Promise(resolve => psB.once('pubsub:subscription-change', () => resolve())),
|
||||
new Promise(resolve => psC.once('pubsub:subscription-change', () => resolve()))
|
||||
new Promise(resolve => psA.once('pubsub:subscription-change', () => resolve(null))),
|
||||
new Promise(resolve => psB.once('pubsub:subscription-change', () => resolve(null))),
|
||||
new Promise(resolve => psC.once('pubsub:subscription-change', () => resolve(null)))
|
||||
])
|
||||
|
||||
psA.on(topic, incMsg)
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
/* eslint max-nested-callbacks: ["error", 6] */
|
||||
'use strict'
|
||||
@ -61,7 +62,9 @@ module.exports = (common) => {
|
||||
expect(psB.peers.size).to.equal(1)
|
||||
expectSet(psB.topics.get(topic), [psA.peerId.toB58String()])
|
||||
expect(changedPeerId.toB58String()).to.equal(first(psB.peers).id.toB58String())
|
||||
expect(changedSubs).to.be.eql([{ topicID: topic, subscribe: true }])
|
||||
expect(changedSubs).to.have.lengthOf(1)
|
||||
expect(changedSubs[0].topicID).to.equal(topic)
|
||||
expect(changedSubs[0].subscribe).to.equal(true)
|
||||
defer.resolve()
|
||||
})
|
||||
psA.subscribe(topic)
|
||||
@ -143,7 +146,9 @@ module.exports = (common) => {
|
||||
expect(psB.peers.size).to.equal(1)
|
||||
expectSet(psB.topics.get(topic), [])
|
||||
expect(changedPeerId.toB58String()).to.equal(first(psB.peers).id.toB58String())
|
||||
expect(changedSubs).to.be.eql([{ topicID: topic, subscribe: false }])
|
||||
expect(changedSubs).to.have.lengthOf(1)
|
||||
expect(changedSubs[0].topicID).to.equal(topic)
|
||||
expect(changedSubs[0].subscribe).to.equal(false)
|
||||
|
||||
defer.resolve()
|
||||
})
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
'use strict'
|
||||
|
||||
const { expect } = require('chai')
|
||||
|
6
src/pubsub/utils.d.ts
vendored
6
src/pubsub/utils.d.ts
vendored
@ -1,6 +0,0 @@
|
||||
export function randomSeqno(): Uint8Array;
|
||||
export function msgId(from: string, seqno: Uint8Array): string;
|
||||
export function anyMatch(a: any[] | Set<any>, b: any[] | Set<any>): boolean;
|
||||
export function ensureArray(maybeArray: any): any[];
|
||||
export function normalizeInRpcMessage(message: any, peerId: string): any;
|
||||
export function normalizeOutRpcMessage(message: any): any;
|
@ -1,9 +1,17 @@
|
||||
'use strict'
|
||||
|
||||
// @ts-ignore libp2p crypto has no types
|
||||
const randomBytes = require('libp2p-crypto/src/random-bytes')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||
exports = module.exports
|
||||
const PeerId = require('peer-id')
|
||||
const multihash = require('multihashes')
|
||||
|
||||
/**
|
||||
* @typedef {import('./message/rpc').RPC.IMessage} IMessage
|
||||
* @typedef {import('./message/rpc').RPC.Message} Message
|
||||
* @typedef {import('.').InMessage} NormalizedIMessage
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generatea random sequence number.
|
||||
@ -11,7 +19,7 @@ exports = module.exports
|
||||
* @returns {Uint8Array}
|
||||
* @private
|
||||
*/
|
||||
exports.randomSeqno = () => {
|
||||
const randomSeqno = () => {
|
||||
return randomBytes(8)
|
||||
}
|
||||
|
||||
@ -20,27 +28,46 @@ exports.randomSeqno = () => {
|
||||
*
|
||||
* @param {string} from
|
||||
* @param {Uint8Array} seqno
|
||||
* @returns {string}
|
||||
* @returns {Uint8Array}
|
||||
* @private
|
||||
*/
|
||||
exports.msgId = (from, seqno) => {
|
||||
return from + uint8ArrayToString(seqno, 'base16')
|
||||
const msgId = (from, seqno) => {
|
||||
const fromBytes = PeerId.createFromB58String(from).id
|
||||
const msgId = new Uint8Array(fromBytes.length + seqno.length)
|
||||
msgId.set(fromBytes, 0)
|
||||
msgId.set(seqno, fromBytes.length)
|
||||
return msgId
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a message id, based on message `data`.
|
||||
*
|
||||
* @param {Uint8Array} data
|
||||
* @returns {Uint8Array}
|
||||
* @private
|
||||
*/
|
||||
const noSignMsgId = (data) => multihash.encode(data, 'sha2-256')
|
||||
|
||||
/**
|
||||
* Check if any member of the first set is also a member
|
||||
* of the second set.
|
||||
*
|
||||
* @param {Set|Array} a
|
||||
* @param {Set|Array} b
|
||||
* @param {Set<number>|Array<number>} a
|
||||
* @param {Set<number>|Array<number>} b
|
||||
* @returns {boolean}
|
||||
* @private
|
||||
*/
|
||||
exports.anyMatch = (a, b) => {
|
||||
const anyMatch = (a, b) => {
|
||||
let bHas
|
||||
if (Array.isArray(b)) {
|
||||
/**
|
||||
* @param {number} val
|
||||
*/
|
||||
bHas = (val) => b.indexOf(val) > -1
|
||||
} else {
|
||||
/**
|
||||
* @param {number} val
|
||||
*/
|
||||
bHas = (val) => b.has(val)
|
||||
}
|
||||
|
||||
@ -56,11 +83,12 @@ exports.anyMatch = (a, b) => {
|
||||
/**
|
||||
* Make everything an array.
|
||||
*
|
||||
* @param {any} maybeArray
|
||||
* @returns {Array}
|
||||
* @template T
|
||||
* @param {T|T[]} maybeArray
|
||||
* @returns {T[]}
|
||||
* @private
|
||||
*/
|
||||
exports.ensureArray = (maybeArray) => {
|
||||
const ensureArray = (maybeArray) => {
|
||||
if (!Array.isArray(maybeArray)) {
|
||||
return [maybeArray]
|
||||
}
|
||||
@ -70,11 +98,15 @@ exports.ensureArray = (maybeArray) => {
|
||||
|
||||
/**
|
||||
* Ensures `message.from` is base58 encoded
|
||||
* @param {object} message
|
||||
* @param {String} peerId
|
||||
* @return {object}
|
||||
*
|
||||
* @template {{from?:any}} T
|
||||
* @param {T & IMessage} message
|
||||
* @param {string} [peerId]
|
||||
* @returns {NormalizedIMessage}
|
||||
*/
|
||||
exports.normalizeInRpcMessage = (message, peerId) => {
|
||||
const normalizeInRpcMessage = (message, peerId) => {
|
||||
/** @type {NormalizedIMessage} */
|
||||
// @ts-ignore receivedFrom not yet defined
|
||||
const m = Object.assign({}, message)
|
||||
if (message.from instanceof Uint8Array) {
|
||||
m.from = uint8ArrayToString(message.from, 'base58btc')
|
||||
@ -86,16 +118,30 @@ exports.normalizeInRpcMessage = (message, peerId) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} message
|
||||
* @return {object}
|
||||
* @template {{from?:any, data?:any}} T
|
||||
*
|
||||
* @param {T & NormalizedIMessage} message
|
||||
* @returns {Message}
|
||||
*/
|
||||
exports.normalizeOutRpcMessage = (message) => {
|
||||
const normalizeOutRpcMessage = (message) => {
|
||||
/** @type {Message} */
|
||||
// @ts-ignore from not yet defined
|
||||
const m = Object.assign({}, message)
|
||||
if (typeof message.from === 'string' || message.from instanceof String) {
|
||||
if (typeof message.from === 'string') {
|
||||
m.from = uint8ArrayFromString(message.from, 'base58btc')
|
||||
}
|
||||
if (typeof message.data === 'string' || message.data instanceof String) {
|
||||
if (typeof message.data === 'string') {
|
||||
m.data = uint8ArrayFromString(message.data)
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
randomSeqno,
|
||||
msgId,
|
||||
noSignMsgId,
|
||||
anyMatch,
|
||||
ensureArray,
|
||||
normalizeInRpcMessage,
|
||||
normalizeOutRpcMessage
|
||||
}
|
||||
|
@ -36,15 +36,30 @@ const fromString = require('uint8arrays/from-string')
|
||||
const ENVELOPE_DOMAIN_PEER_RECORD = 'libp2p-peer-record'
|
||||
const ENVELOPE_PAYLOAD_TYPE_PEER_RECORD = fromString('0301', 'hex')
|
||||
|
||||
class PeerRecord extends Record {
|
||||
/**
|
||||
* @implements {import('libp2p-interfaces/src/record/types').Record}
|
||||
*/
|
||||
class PeerRecord {
|
||||
constructor (peerId, multiaddrs, seqNumber) {
|
||||
super (ENVELOPE_DOMAIN_PEER_RECORD, ENVELOPE_PAYLOAD_TYPE_PEER_RECORD)
|
||||
this.domain = ENVELOPE_DOMAIN_PEER_RECORD
|
||||
this.codec = ENVELOPE_PAYLOAD_TYPE_PEER_RECORD
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal a record to be used in an envelope.
|
||||
*
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
marshal () {
|
||||
// Implement and return using Protobuf
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if `this` record equals the `other`.
|
||||
*
|
||||
* @param {PeerRecord} other
|
||||
* @returns {other is Record}
|
||||
*/
|
||||
equals (other) {
|
||||
// Verify
|
||||
}
|
||||
@ -73,4 +88,4 @@ Verifies if the other Record is identical to this one.
|
||||
- other is a `Record` to compare with the current instance.
|
||||
|
||||
**Returns**
|
||||
- `boolean`
|
||||
- `other is Record`
|
||||
|
23
src/record/index.d.ts
vendored
23
src/record/index.d.ts
vendored
@ -1,23 +0,0 @@
|
||||
export = Record;
|
||||
/**
|
||||
* Record is the base implementation of a record that can be used as the payload of a libp2p envelope.
|
||||
*/
|
||||
declare class Record {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {String} domain signature domain
|
||||
* @param {Uint8Array} codec identifier of the type of record
|
||||
*/
|
||||
constructor(domain: string, codec: Uint8Array);
|
||||
domain: string;
|
||||
codec: Uint8Array;
|
||||
/**
|
||||
* Marshal a record to be used in an envelope.
|
||||
*/
|
||||
marshal(): void;
|
||||
/**
|
||||
* Verifies if the other provided Record is identical to this one.
|
||||
* @param {Record} other
|
||||
*/
|
||||
equals(other: Record): void;
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
const errcode = require('err-code')
|
||||
|
||||
/**
|
||||
* Record is the base implementation of a record that can be used as the payload of a libp2p envelope.
|
||||
*/
|
||||
class Record {
|
||||
/**
|
||||
* @constructor
|
||||
* @param {String} domain signature domain
|
||||
* @param {Uint8Array} codec identifier of the type of record
|
||||
*/
|
||||
constructor (domain, codec) {
|
||||
this.domain = domain
|
||||
this.codec = codec
|
||||
}
|
||||
|
||||
/**
|
||||
* Marshal a record to be used in an envelope.
|
||||
*/
|
||||
marshal () {
|
||||
throw errcode(new Error('marshal must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if the other provided Record is identical to this one.
|
||||
* @param {Record} other
|
||||
*/
|
||||
equals (other) {
|
||||
throw errcode(new Error('equals must be implemented by the subclass'), 'ERR_NOT_IMPLEMENTED')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Record
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
|
||||
'use strict'
|
||||
|
21
src/record/types.d.ts
vendored
Normal file
21
src/record/types.d.ts
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Record is the base implementation of a record that can be used as the payload of a libp2p envelope.
|
||||
*/
|
||||
export interface Record {
|
||||
/**
|
||||
* signature domain.
|
||||
*/
|
||||
domain: string;
|
||||
/**
|
||||
* identifier of the type of record
|
||||
*/
|
||||
codec: Uint8Array;
|
||||
/**
|
||||
* Marshal a record to be used in an envelope.
|
||||
*/
|
||||
marshal(): Uint8Array;
|
||||
/**
|
||||
* Verifies if the other provided Record is identical to this one.
|
||||
*/
|
||||
equals(other: unknown): boolean
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
@ -5,7 +6,7 @@ const chai = require('chai')
|
||||
chai.use(require('chai-checkmark'))
|
||||
const { expect } = chai
|
||||
const pair = require('it-pair/duplex')
|
||||
const pipe = require('it-pipe')
|
||||
const { pipe } = require('it-pipe')
|
||||
const { collect, map, consume } = require('streaming-iterables')
|
||||
|
||||
function close (stream) {
|
||||
@ -20,8 +21,9 @@ async function closeAndWait (stream) {
|
||||
/**
|
||||
* A tick is considered valid if it happened between now
|
||||
* and `ms` milliseconds ago
|
||||
* @param {number} date Time in ticks
|
||||
* @param {number} ms max milliseconds that should have expired
|
||||
*
|
||||
* @param {number} date - Time in ticks
|
||||
* @param {number} ms - max milliseconds that should have expired
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isValidTick (date, ms = 5000) {
|
||||
|
@ -1,17 +1,18 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
/* eslint max-nested-callbacks: ["error", 8] */
|
||||
'use strict'
|
||||
|
||||
const pair = require('it-pair/duplex')
|
||||
const pipe = require('it-pipe')
|
||||
const { pipe } = require('it-pipe')
|
||||
const { consume } = require('streaming-iterables')
|
||||
const Tcp = require('libp2p-tcp')
|
||||
const multiaddr = require('multiaddr')
|
||||
const abortable = require('abortable-iterator')
|
||||
const AbortController = require('abort-controller')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const { source: abortable } = require('abortable-iterator')
|
||||
const AbortController = require('abort-controller').default
|
||||
const uint8arrayFromString = require('uint8arrays/from-string')
|
||||
|
||||
const mh = multiaddr('/ip4/127.0.0.1/tcp/0')
|
||||
const mh = new Multiaddr('/ip4/127.0.0.1/tcp/0')
|
||||
|
||||
function pause (ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
// @ts-nocheck interface tests
|
||||
'use strict'
|
||||
|
||||
const { expect } = require('chai')
|
||||
const pair = require('it-pair/duplex')
|
||||
const pipe = require('it-pipe')
|
||||
const { pipe } = require('it-pipe')
|
||||
|
||||
const pLimit = require('p-limit')
|
||||
const { collect, tap, consume } = require('streaming-iterables')
|
||||
|
||||
@ -61,8 +63,11 @@ module.exports = async (Muxer, nStreams, nMsg, limit) => {
|
||||
}
|
||||
|
||||
function marker (n) {
|
||||
/** @type {Function} */
|
||||
let check
|
||||
let i = 0
|
||||
|
||||
/** @type {Promise<void>} */
|
||||
const done = new Promise((resolve, reject) => {
|
||||
check = err => {
|
||||
i++
|
||||
@ -78,5 +83,7 @@ function marker (n) {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// @ts-ignore - TS can't see that assignement occured
|
||||
return { check, done }
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
|
51
src/stream-muxer/types.d.ts
vendored
Normal file
51
src/stream-muxer/types.d.ts
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
import BufferList from 'bl'
|
||||
|
||||
export interface MuxerFactory {
|
||||
new (options: MuxerOptions): Muxer;
|
||||
multicodec: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* A libp2p stream muxer
|
||||
*/
|
||||
export interface Muxer {
|
||||
readonly streams: Array<MuxedStream>;
|
||||
/**
|
||||
* Initiate a new stream with the given name. If no name is
|
||||
* provided, the id of th stream will be used.
|
||||
*/
|
||||
newStream (name?: string): MuxedStream;
|
||||
|
||||
/**
|
||||
* A function called when receiving a new stream from the remote.
|
||||
*/
|
||||
onStream (stream: MuxedStream): void;
|
||||
|
||||
/**
|
||||
* A function called when a stream ends.
|
||||
*/
|
||||
onStreamEnd (stream: MuxedStream): void;
|
||||
}
|
||||
|
||||
export type MuxerOptions = {
|
||||
onStream: (stream: MuxedStream) => void;
|
||||
onStreamEnd: (stream: MuxedStream) => void;
|
||||
maxMsgSize?: number;
|
||||
}
|
||||
|
||||
export type MuxedTimeline = {
|
||||
open: number;
|
||||
close?: number;
|
||||
}
|
||||
|
||||
export interface MuxedStream extends AsyncIterable<Uint8Array | BufferList> {
|
||||
close: () => void;
|
||||
abort: () => void;
|
||||
reset: () => void;
|
||||
sink: Sink;
|
||||
source: AsyncIterable<Uint8Array | BufferList>;
|
||||
timeline: MuxedTimeline;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export type Sink = (source: Uint8Array) => Promise<void>;
|
42
src/topology/index.d.ts
vendored
42
src/topology/index.d.ts
vendored
@ -1,42 +0,0 @@
|
||||
declare const _exports: Topology;
|
||||
export = _exports;
|
||||
declare class Topology {
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @param {number} props.min minimum needed connections (default: 0)
|
||||
* @param {number} props.max maximum needed connections (default: Infinity)
|
||||
* @param {Object} [props.handlers]
|
||||
* @param {function} [props.handlers.onConnect] protocol "onConnect" handler
|
||||
* @param {function} [props.handlers.onDisconnect] protocol "onDisconnect" handler
|
||||
* @constructor
|
||||
*/
|
||||
constructor({ min, max, handlers }: {
|
||||
min: number;
|
||||
max: number;
|
||||
handlers?: {
|
||||
onConnect?: Function;
|
||||
onDisconnect?: Function;
|
||||
};
|
||||
});
|
||||
min: number;
|
||||
max: number;
|
||||
_onConnect: Function;
|
||||
_onDisconnect: Function;
|
||||
/**
|
||||
* Set of peers that support the protocol.
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
peers: Set<string>;
|
||||
set registrar(arg: any);
|
||||
_registrar: any;
|
||||
/**
|
||||
* @typedef PeerId
|
||||
* @type {import('peer-id')}
|
||||
*/
|
||||
/**
|
||||
* Notify about peer disconnected event.
|
||||
* @param {PeerId} peerId
|
||||
* @returns {void}
|
||||
*/
|
||||
disconnect(peerId: import("peer-id")): void;
|
||||
}
|
@ -1,17 +1,28 @@
|
||||
'use strict'
|
||||
|
||||
const withIs = require('class-is')
|
||||
const noop = () => {}
|
||||
const topologySymbol = Symbol.for('@libp2p/js-interfaces/topology')
|
||||
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {number} [min=0] - minimum needed connections.
|
||||
* @property {number} [max=Infinity] - maximum needed connections.
|
||||
* @property {Handlers} [handlers]
|
||||
*
|
||||
* @typedef {Object} Handlers
|
||||
* @property {(peerId: PeerId, conn: Connection) => void} [onConnect] - protocol "onConnect" handler
|
||||
* @property {(peerId: PeerId, error?:Error) => void} [onDisconnect] - protocol "onDisconnect" handler
|
||||
*
|
||||
* @typedef {import('../connection/connection')} Connection
|
||||
*/
|
||||
|
||||
class Topology {
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @param {number} props.min minimum needed connections (default: 0)
|
||||
* @param {number} props.max maximum needed connections (default: Infinity)
|
||||
* @param {Object} [props.handlers]
|
||||
* @param {function} [props.handlers.onConnect] protocol "onConnect" handler
|
||||
* @param {function} [props.handlers.onDisconnect] protocol "onDisconnect" handler
|
||||
* @constructor
|
||||
* @param {Options} options
|
||||
*/
|
||||
constructor ({
|
||||
min = 0,
|
||||
@ -27,22 +38,40 @@ class Topology {
|
||||
|
||||
/**
|
||||
* Set of peers that support the protocol.
|
||||
*
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
this.peers = new Set()
|
||||
}
|
||||
|
||||
set registrar (registrar) {
|
||||
get [Symbol.toStringTag] () {
|
||||
return 'Topology'
|
||||
}
|
||||
|
||||
get [topologySymbol] () {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given value is a Topology instance.
|
||||
*
|
||||
* @param {any} other
|
||||
* @returns {other is Topology}
|
||||
*/
|
||||
static isTopology (other) {
|
||||
return Boolean(other && other[topologySymbol])
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} registrar
|
||||
*/
|
||||
set registrar (registrar) { // eslint-disable-line
|
||||
this._registrar = registrar
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef PeerId
|
||||
* @type {import('peer-id')}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Notify about peer disconnected event.
|
||||
*
|
||||
* @param {PeerId} peerId
|
||||
* @returns {void}
|
||||
*/
|
||||
@ -51,8 +80,4 @@ class Topology {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @module
|
||||
* @type {Topology}
|
||||
*/
|
||||
module.exports = withIs(Topology, { className: 'Topology', symbolName: '@libp2p/js-interfaces/topology' })
|
||||
module.exports = Topology
|
||||
|
52
src/topology/multicodec-topology.d.ts
vendored
52
src/topology/multicodec-topology.d.ts
vendored
@ -1,52 +0,0 @@
|
||||
declare const _exports: MulticodecTopology;
|
||||
export = _exports;
|
||||
declare class MulticodecTopology {
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @param {number} props.min minimum needed connections (default: 0)
|
||||
* @param {number} props.max maximum needed connections (default: Infinity)
|
||||
* @param {Array<string>} props.multicodecs protocol multicodecs
|
||||
* @param {Object} props.handlers
|
||||
* @param {function} props.handlers.onConnect protocol "onConnect" handler
|
||||
* @param {function} props.handlers.onDisconnect protocol "onDisconnect" handler
|
||||
* @constructor
|
||||
*/
|
||||
constructor({ min, max, multicodecs, handlers }: {
|
||||
min: number;
|
||||
max: number;
|
||||
multicodecs: string[];
|
||||
handlers: {
|
||||
onConnect: Function;
|
||||
onDisconnect: Function;
|
||||
};
|
||||
});
|
||||
multicodecs: string[];
|
||||
_registrar: any;
|
||||
/**
|
||||
* Check if a new peer support the multicodecs for this topology.
|
||||
* @param {Object} props
|
||||
* @param {PeerId} props.peerId
|
||||
* @param {Array<string>} props.protocols
|
||||
*/
|
||||
_onProtocolChange({ peerId, protocols }: {
|
||||
peerId: any;
|
||||
protocols: string[];
|
||||
}): void;
|
||||
/**
|
||||
* Verify if a new connected peer has a topology multicodec and call _onConnect.
|
||||
* @param {Connection} connection
|
||||
* @returns {void}
|
||||
*/
|
||||
_onPeerConnect(connection: any): void;
|
||||
set registrar(arg: any);
|
||||
/**
|
||||
* Update topology.
|
||||
* @param {Array<{id: PeerId, multiaddrs: Array<Multiaddr>, protocols: Array<string>}>} peerDataIterable
|
||||
* @returns {void}
|
||||
*/
|
||||
_updatePeers(peerDataIterable: {
|
||||
id: any;
|
||||
multiaddrs: any[];
|
||||
protocols: string[];
|
||||
}[]): void;
|
||||
}
|
@ -1,19 +1,11 @@
|
||||
'use strict'
|
||||
|
||||
const withIs = require('class-is')
|
||||
|
||||
const Topology = require('./index')
|
||||
const multicodecTopologySymbol = Symbol.for('@libp2p/js-interfaces/topology/multicodec-topology')
|
||||
|
||||
class MulticodecTopology extends Topology {
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @param {number} props.min minimum needed connections (default: 0)
|
||||
* @param {number} props.max maximum needed connections (default: Infinity)
|
||||
* @param {Array<string>} props.multicodecs protocol multicodecs
|
||||
* @param {Object} props.handlers
|
||||
* @param {function} props.handlers.onConnect protocol "onConnect" handler
|
||||
* @param {function} props.handlers.onDisconnect protocol "onDisconnect" handler
|
||||
* @constructor
|
||||
* @param {TopologyOptions & MulticodecOptions} props
|
||||
*/
|
||||
constructor ({
|
||||
min,
|
||||
@ -46,7 +38,28 @@ class MulticodecTopology extends Topology {
|
||||
this._onPeerConnect = this._onPeerConnect.bind(this)
|
||||
}
|
||||
|
||||
set registrar (registrar) {
|
||||
get [Symbol.toStringTag] () {
|
||||
return 'Topology'
|
||||
}
|
||||
|
||||
get [multicodecTopologySymbol] () {
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given value is a `MulticodecTopology` instance.
|
||||
*
|
||||
* @param {any} other
|
||||
* @returns {other is MulticodecTopology}
|
||||
*/
|
||||
static isMulticodecTopology (other) {
|
||||
return Boolean(other && other[multicodecTopologySymbol])
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} registrar
|
||||
*/
|
||||
set registrar (registrar) { // eslint-disable-line
|
||||
this._registrar = registrar
|
||||
this._registrar.peerStore.on('change:protocols', this._onProtocolChange)
|
||||
this._registrar.connectionManager.on('peer:connect', this._onPeerConnect)
|
||||
@ -57,6 +70,7 @@ class MulticodecTopology extends Topology {
|
||||
|
||||
/**
|
||||
* Update topology.
|
||||
*
|
||||
* @param {Array<{id: PeerId, multiaddrs: Array<Multiaddr>, protocols: Array<string>}>} peerDataIterable
|
||||
* @returns {void}
|
||||
*/
|
||||
@ -77,6 +91,7 @@ class MulticodecTopology extends Topology {
|
||||
|
||||
/**
|
||||
* Check if a new peer support the multicodecs for this topology.
|
||||
*
|
||||
* @param {Object} props
|
||||
* @param {PeerId} props.peerId
|
||||
* @param {Array<string>} props.protocols
|
||||
@ -102,10 +117,12 @@ class MulticodecTopology extends Topology {
|
||||
|
||||
/**
|
||||
* Verify if a new connected peer has a topology multicodec and call _onConnect.
|
||||
*
|
||||
* @param {Connection} connection
|
||||
* @returns {void}
|
||||
*/
|
||||
_onPeerConnect (connection) {
|
||||
// @ts-ignore - remotePeer does not existist on Connection
|
||||
const peerId = connection.remotePeer
|
||||
const protocols = this._registrar.peerStore.protoBook.get(peerId)
|
||||
|
||||
@ -121,7 +138,13 @@ class MulticodecTopology extends Topology {
|
||||
}
|
||||
|
||||
/**
|
||||
* @module
|
||||
* @type {MulticodecTopology}
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('multiaddr')} Multiaddr
|
||||
* @typedef {import('../connection/connection')} Connection
|
||||
* @typedef {import('.').Options} TopologyOptions
|
||||
* @typedef {Object} MulticodecOptions
|
||||
* @property {string[]} multicodecs - protocol multicodecs
|
||||
* @property {Required<Handlers>} handlers
|
||||
* @typedef {import('.').Handlers} Handlers
|
||||
*/
|
||||
module.exports = withIs(MulticodecTopology, { className: 'MulticodecTopology', symbolName: '@libp2p/js-interfaces/topology/multicodec-topology' })
|
||||
module.exports = MulticodecTopology
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
|
||||
'use strict'
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
|
||||
'use strict'
|
||||
|
6
src/transport/errors.d.ts
vendored
6
src/transport/errors.d.ts
vendored
@ -1,6 +0,0 @@
|
||||
export class AbortError extends Error {
|
||||
static get code(): string;
|
||||
static get type(): string;
|
||||
code: string;
|
||||
type: string;
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
@ -9,8 +10,8 @@ chai.use(dirtyChai)
|
||||
const { isValidTick } = require('./utils')
|
||||
const goodbye = require('it-goodbye')
|
||||
const { collect } = require('streaming-iterables')
|
||||
const pipe = require('it-pipe')
|
||||
const AbortController = require('abort-controller')
|
||||
const { pipe } = require('it-pipe')
|
||||
const AbortController = require('abort-controller').default
|
||||
const AbortError = require('../errors').AbortError
|
||||
const sinon = require('sinon')
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck interface tests
|
||||
/* eslint max-nested-callbacks: ["error", 8] */
|
||||
/* eslint-env mocha */
|
||||
'use strict'
|
||||
@ -9,7 +10,7 @@ chai.use(dirtyChai)
|
||||
const sinon = require('sinon')
|
||||
|
||||
const pWaitFor = require('p-wait-for')
|
||||
const pipe = require('it-pipe')
|
||||
const { pipe } = require('it-pipe')
|
||||
const uint8arrayFromString = require('uint8arrays/from-string')
|
||||
const { isValidTick } = require('./utils')
|
||||
|
||||
|
@ -4,8 +4,9 @@ module.exports = {
|
||||
/**
|
||||
* A tick is considered valid if it happened between now
|
||||
* and `ms` milliseconds ago
|
||||
* @param {number} date Time in ticks
|
||||
* @param {number} ms max milliseconds that should have expired
|
||||
*
|
||||
* @param {number} date - Time in ticks
|
||||
* @param {number} ms - max milliseconds that should have expired
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isValidTick: function isValidTick (date, ms = 5000) {
|
||||
|
72
src/transport/types.d.ts
vendored
Normal file
72
src/transport/types.d.ts
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
import BufferList from 'bl'
|
||||
import events from 'events'
|
||||
import Multiaddr from 'multiaddr'
|
||||
import Connection from '../connection/connection'
|
||||
import { Sink } from '../stream-muxer/types'
|
||||
|
||||
export interface TransportFactory<DialOptions extends { signal?: AbortSignal }, ListenerOptions> {
|
||||
new(upgrader: Upgrader): Transport<DialOptions, ListenerOptions>;
|
||||
}
|
||||
|
||||
/**
|
||||
* A libp2p transport is understood as something that offers a dial and listen interface to establish connections.
|
||||
*/
|
||||
export interface Transport <DialOptions extends { signal?: AbortSignal }, ListenerOptions> {
|
||||
/**
|
||||
* Dial a given multiaddr.
|
||||
*/
|
||||
dial(ma: Multiaddr, options?: DialOptions): Promise<Connection>;
|
||||
/**
|
||||
* Create transport listeners.
|
||||
*/
|
||||
createListener(options: ListenerOptions, handler?: (connection: Connection) => void): Listener;
|
||||
/**
|
||||
* Takes a list of `Multiaddr`s and returns only valid addresses for the transport
|
||||
*/
|
||||
filter(multiaddrs: Multiaddr[]): Multiaddr[];
|
||||
}
|
||||
|
||||
export interface Listener extends events.EventEmitter {
|
||||
/**
|
||||
* Start a listener
|
||||
*/
|
||||
listen(multiaddr: Multiaddr): Promise<void>;
|
||||
/**
|
||||
* Get listen addresses
|
||||
*/
|
||||
getAddrs(): Multiaddr[];
|
||||
/**
|
||||
* Close listener
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
||||
export interface Upgrader {
|
||||
/**
|
||||
* Upgrades an outbound connection on `transport.dial`.
|
||||
*/
|
||||
upgradeOutbound(maConn: MultiaddrConnection): Promise<Connection>;
|
||||
|
||||
/**
|
||||
* Upgrades an inbound connection on transport listener.
|
||||
*/
|
||||
upgradeInbound(maConn: MultiaddrConnection): Promise<Connection>;
|
||||
}
|
||||
|
||||
export type MultiaddrConnectionTimeline = {
|
||||
open: number;
|
||||
upgraded?: number;
|
||||
close?: number;
|
||||
}
|
||||
|
||||
export type MultiaddrConnection = {
|
||||
sink: Sink;
|
||||
source: AsyncIterable<Uint8Array | BufferList>;
|
||||
close: (err?: Error) => Promise<void>;
|
||||
conn: unknown;
|
||||
remoteAddr: Multiaddr;
|
||||
localAddr?: Multiaddr;
|
||||
timeline: MultiaddrConnectionTimeline;
|
||||
}
|
18
src/types.d.ts
vendored
Normal file
18
src/types.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
export interface EventEmitterFactory {
|
||||
new(): EventEmitter;
|
||||
}
|
||||
|
||||
export interface EventEmitter {
|
||||
addListener(event: string | symbol, listener: (...args: any[]) => void): EventEmitter;
|
||||
on(event: string | symbol, listener: (...args: any[]) => void): EventEmitter;
|
||||
once(event: string | symbol, listener: (...args: any[]) => void): EventEmitter;
|
||||
removeListener(event: string | symbol, listener: (...args: any[]) => void): EventEmitter;
|
||||
off(event: string | symbol, listener: (...args: any[]) => void): EventEmitter;
|
||||
removeAllListeners(event?: string | symbol): EventEmitter;
|
||||
setMaxListeners(n: number): EventEmitter;
|
||||
getMaxListeners(): number;
|
||||
listeners(event: string | symbol): Function[]; // eslint-disable-line @typescript-eslint/ban-types
|
||||
rawListeners(event: string | symbol): Function[]; // eslint-disable-line @typescript-eslint/ban-types
|
||||
emit(event: string | symbol, ...args: any[]): boolean;
|
||||
listenerCount(event: string | symbol): number;
|
||||
}
|
@ -5,7 +5,7 @@ const tests = require('../../src/connection/tests')
|
||||
const { Connection } = require('../../src/connection')
|
||||
const peers = require('../../src/utils/peers')
|
||||
const PeerId = require('peer-id')
|
||||
const multiaddr = require('multiaddr')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const pair = require('it-pair')
|
||||
|
||||
describe('compliance tests', () => {
|
||||
@ -13,11 +13,12 @@ describe('compliance tests', () => {
|
||||
/**
|
||||
* Test setup. `properties` allows the compliance test to override
|
||||
* certain values for testing.
|
||||
*
|
||||
* @param {*} properties
|
||||
*/
|
||||
async setup (properties) {
|
||||
const localAddr = multiaddr('/ip4/127.0.0.1/tcp/8080')
|
||||
const remoteAddr = multiaddr('/ip4/127.0.0.1/tcp/8081')
|
||||
const localAddr = new Multiaddr('/ip4/127.0.0.1/tcp/8080')
|
||||
const remoteAddr = new Multiaddr('/ip4/127.0.0.1/tcp/8081')
|
||||
const [localPeer, remotePeer] = await Promise.all([
|
||||
PeerId.createFromJSON(peers[0]),
|
||||
PeerId.createFromJSON(peers[1])
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
const { EventEmitter } = require('events')
|
||||
|
||||
const multiaddr = require('multiaddr')
|
||||
const { Multiaddr } = require('multiaddr')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
/**
|
||||
@ -41,7 +41,7 @@ class MockDiscovery extends EventEmitter {
|
||||
this._timer = setTimeout(() => {
|
||||
this.emit('peer', {
|
||||
id: peerId,
|
||||
multiaddrs: [multiaddr('/ip4/127.0.0.1/tcp/8000')]
|
||||
multiaddrs: [new Multiaddr('/ip4/127.0.0.1/tcp/8000')]
|
||||
})
|
||||
}, this.options.discoveryDelay || 1000)
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ const { expect } = require('aegir/utils/chai')
|
||||
const sinon = require('sinon')
|
||||
|
||||
const PubsubBaseImpl = require('../../src/pubsub')
|
||||
const { randomSeqno } = require('../../src/pubsub/utils')
|
||||
const { SignaturePolicy } = require('../../src/pubsub/signature-policy')
|
||||
const {
|
||||
createPeerId,
|
||||
mockRegistrar
|
||||
@ -34,9 +34,7 @@ describe('pubsub base messages', () => {
|
||||
it('_buildMessage normalizes and signs messages', async () => {
|
||||
const message = {
|
||||
receivedFrom: peerId.id,
|
||||
from: peerId.id,
|
||||
data: 'hello',
|
||||
seqno: randomSeqno(),
|
||||
topicIDs: ['test-topic']
|
||||
}
|
||||
|
||||
@ -44,27 +42,46 @@ describe('pubsub base messages', () => {
|
||||
expect(pubsub.validate(signedMessage)).to.not.be.rejected()
|
||||
})
|
||||
|
||||
it('validate with strict signing off will validate a present signature', async () => {
|
||||
it('validate with StrictNoSign will reject a message with from, signature, key, seqno present', async () => {
|
||||
const message = {
|
||||
receivedFrom: peerId.id,
|
||||
from: peerId.id,
|
||||
data: 'hello',
|
||||
seqno: randomSeqno(),
|
||||
topicIDs: ['test-topic']
|
||||
}
|
||||
|
||||
sinon.stub(pubsub, 'strictSigning').value(false)
|
||||
sinon.stub(pubsub, 'globalSignaturePolicy').value(SignaturePolicy.StrictSign)
|
||||
|
||||
const signedMessage = await pubsub._buildMessage(message)
|
||||
|
||||
sinon.stub(pubsub, 'globalSignaturePolicy').value(SignaturePolicy.StrictNoSign)
|
||||
await expect(pubsub.validate(signedMessage)).to.be.rejected()
|
||||
delete signedMessage.from
|
||||
await expect(pubsub.validate(signedMessage)).to.be.rejected()
|
||||
delete signedMessage.signature
|
||||
await expect(pubsub.validate(signedMessage)).to.be.rejected()
|
||||
delete signedMessage.key
|
||||
await expect(pubsub.validate(signedMessage)).to.be.rejected()
|
||||
delete signedMessage.seqno
|
||||
await expect(pubsub.validate(signedMessage)).to.not.be.rejected()
|
||||
})
|
||||
|
||||
it('validate with StrictNoSign will validate a message without a signature, key, and seqno', async () => {
|
||||
const message = {
|
||||
receivedFrom: peerId.id,
|
||||
data: 'hello',
|
||||
topicIDs: ['test-topic']
|
||||
}
|
||||
|
||||
sinon.stub(pubsub, 'globalSignaturePolicy').value(SignaturePolicy.StrictNoSign)
|
||||
|
||||
const signedMessage = await pubsub._buildMessage(message)
|
||||
expect(pubsub.validate(signedMessage)).to.not.be.rejected()
|
||||
})
|
||||
|
||||
it('validate with strict signing requires a signature', async () => {
|
||||
it('validate with StrictSign requires a signature', async () => {
|
||||
const message = {
|
||||
receivedFrom: peerId.id,
|
||||
from: peerId.id,
|
||||
data: 'hello',
|
||||
seqno: randomSeqno(),
|
||||
topicIDs: ['test-topic']
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ const { expect } = require('aegir/utils/chai')
|
||||
const uint8ArrayConcat = require('uint8arrays/concat')
|
||||
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||
|
||||
const { Message } = require('../../src/pubsub/message')
|
||||
const { RPC } = require('../../src/pubsub/message/rpc')
|
||||
const {
|
||||
signMessage,
|
||||
SignPrefix,
|
||||
@ -31,7 +31,7 @@ describe('message signing', () => {
|
||||
topicIDs: ['test-topic']
|
||||
}
|
||||
|
||||
const bytesToSign = uint8ArrayConcat([SignPrefix, Message.encode(message)])
|
||||
const bytesToSign = uint8ArrayConcat([SignPrefix, RPC.Message.encode(message).finish()])
|
||||
const expectedSignature = await peerId.privKey.sign(bytesToSign)
|
||||
|
||||
const signedMessage = await signMessage(peerId, message)
|
||||
@ -55,7 +55,7 @@ describe('message signing', () => {
|
||||
topicIDs: ['test-topic']
|
||||
}
|
||||
|
||||
const bytesToSign = uint8ArrayConcat([SignPrefix, Message.encode(message)])
|
||||
const bytesToSign = uint8ArrayConcat([SignPrefix, RPC.Message.encode(message).finish()])
|
||||
const expectedSignature = await secPeerId.privKey.sign(bytesToSign)
|
||||
|
||||
const signedMessage = await signMessage(secPeerId, message)
|
||||
@ -77,7 +77,7 @@ describe('message signing', () => {
|
||||
topicIDs: ['test-topic']
|
||||
}
|
||||
|
||||
const bytesToSign = uint8ArrayConcat([SignPrefix, Message.encode(message)])
|
||||
const bytesToSign = uint8ArrayConcat([SignPrefix, RPC.Message.encode(message).finish()])
|
||||
const expectedSignature = await peerId.privKey.sign(bytesToSign)
|
||||
|
||||
const signedMessage = await signMessage(peerId, message)
|
||||
|
@ -10,8 +10,8 @@ const PeerId = require('peer-id')
|
||||
const uint8ArrayEquals = require('uint8arrays/equals')
|
||||
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||
|
||||
const { utils } = require('../../src/pubsub')
|
||||
const PeerStreams = require('../../src/pubsub/peer-streams')
|
||||
const { SignaturePolicy } = require('../../src/pubsub/signature-policy')
|
||||
|
||||
const {
|
||||
createPeerId,
|
||||
@ -30,6 +30,8 @@ describe('topic validators', () => {
|
||||
pubsub = new PubsubImplementation(protocol, {
|
||||
peerId: peerId,
|
||||
registrar: mockRegistrar
|
||||
}, {
|
||||
globalSignaturePolicy: SignaturePolicy.StrictNoSign
|
||||
})
|
||||
|
||||
pubsub.start()
|
||||
@ -42,8 +44,6 @@ describe('topic validators', () => {
|
||||
it('should filter messages by topic validator', async () => {
|
||||
// use _publish.callCount() to see if a message is valid or not
|
||||
sinon.spy(pubsub, '_publish')
|
||||
// Disable strict signing
|
||||
sinon.stub(pubsub, 'strictSigning').value(false)
|
||||
sinon.stub(pubsub.peers, 'get').returns({})
|
||||
const filteredTopic = 't'
|
||||
const peer = new PeerStreams({ id: await PeerId.create() })
|
||||
@ -59,9 +59,7 @@ describe('topic validators', () => {
|
||||
const validRpc = {
|
||||
subscriptions: [],
|
||||
msgs: [{
|
||||
from: peer.id.toBytes(),
|
||||
data: uint8ArrayFromString('a message'),
|
||||
seqno: utils.randomSeqno(),
|
||||
topicIDs: [filteredTopic]
|
||||
}]
|
||||
}
|
||||
@ -76,9 +74,7 @@ describe('topic validators', () => {
|
||||
const invalidRpc = {
|
||||
subscriptions: [],
|
||||
msgs: [{
|
||||
from: peer.id.toBytes(),
|
||||
data: uint8ArrayFromString('a different message'),
|
||||
seqno: utils.randomSeqno(),
|
||||
topicIDs: [filteredTopic]
|
||||
}]
|
||||
}
|
||||
@ -94,9 +90,7 @@ describe('topic validators', () => {
|
||||
const invalidRpc2 = {
|
||||
subscriptions: [],
|
||||
msgs: [{
|
||||
from: peer.id.toB58String(),
|
||||
data: uint8ArrayFromString('a different message'),
|
||||
seqno: utils.randomSeqno(),
|
||||
topicIDs: [filteredTopic]
|
||||
}]
|
||||
}
|
||||
|
@ -15,15 +15,11 @@ describe('utils', () => {
|
||||
expect(first).to.not.eql(second)
|
||||
})
|
||||
|
||||
it('msgId', () => {
|
||||
expect(utils.msgId('hello', uint8ArrayFromString('world'))).to.be.eql('hello776f726c64')
|
||||
})
|
||||
|
||||
it('msgId should not generate same ID for two different Uint8Arrays', () => {
|
||||
const peerId = 'QmPNdSYk5Rfpo5euNqwtyizzmKXMNHdXeLjTQhcN4yfX22'
|
||||
const msgId0 = utils.msgId(peerId, uint8ArrayFromString('15603533e990dfde', 'base16'))
|
||||
const msgId1 = utils.msgId(peerId, uint8ArrayFromString('15603533e990dfe0', 'base16'))
|
||||
expect(msgId0).to.not.eql(msgId1)
|
||||
expect(msgId0).to.not.deep.equal(msgId1)
|
||||
})
|
||||
|
||||
it('anyMatch', () => {
|
||||
|
@ -5,7 +5,7 @@ const DuplexPair = require('it-pair/duplex')
|
||||
const PeerId = require('peer-id')
|
||||
|
||||
const PubsubBaseProtocol = require('../../../src/pubsub')
|
||||
const { message } = require('../../../src/pubsub')
|
||||
const { RPC } = require('../../../src/pubsub/message/rpc')
|
||||
|
||||
exports.createPeerId = async () => {
|
||||
const peerId = await PeerId.create({ bits: 1024 })
|
||||
@ -28,11 +28,11 @@ class PubsubImplementation extends PubsubBaseProtocol {
|
||||
}
|
||||
|
||||
_decodeRpc (bytes) {
|
||||
return message.rpc.RPC.decode(bytes)
|
||||
return RPC.decode(bytes)
|
||||
}
|
||||
|
||||
_encodeRpc (rpc) {
|
||||
return message.rpc.RPC.encode(rpc)
|
||||
return RPC.encode(rpc).finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,13 @@
|
||||
{
|
||||
"include": ["src/**/*.js"],
|
||||
"exclude": ["src/**/tests/*", "src/utils"],
|
||||
|
||||
"extends": "./node_modules/aegir/src/config/tsconfig.aegir.json",
|
||||
"compilerOptions": {
|
||||
// Tells TypeScript to read JS files, as
|
||||
// normally they are ignored as source files
|
||||
"allowJs": true,
|
||||
// Generate d.ts files
|
||||
"declaration": true,
|
||||
// This compiler run should
|
||||
// only output d.ts files
|
||||
"emitDeclarationOnly": true,
|
||||
"esModuleInterop": true,
|
||||
"rootDir": "./src",
|
||||
"outDir": "./src"
|
||||
}
|
||||
"outDir": "dist"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"exclude": [
|
||||
"src/pubsub/message/rpc.js", // exclude generated file
|
||||
"src/pubsub/message/topic-descriptor.js" // exclude generated file
|
||||
]
|
||||
}
|
||||
|
Reference in New Issue
Block a user