mirror of
https://github.com/fluencelabs/js-libp2p-interfaces
synced 2025-07-06 22:21:43 +00:00
Compare commits
1 Commits
feat/types
...
fix/pubsub
Author | SHA1 | Date | |
---|---|---|---|
b15d77f64a |
34
CHANGELOG.md
34
CHANGELOG.md
@ -1,37 +1,3 @@
|
||||
<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)
|
||||
|
||||
|
17
package.json
17
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "libp2p-interfaces",
|
||||
"version": "0.7.2",
|
||||
"version": "0.6.0",
|
||||
"description": "Interfaces for JS Libp2p",
|
||||
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
|
||||
"main": "src/index.js",
|
||||
@ -12,15 +12,15 @@
|
||||
"scripts": {
|
||||
"lint": "aegir lint",
|
||||
"build": "aegir build",
|
||||
"pregenerate:types": "rimraf './src/**/*.d.ts'",
|
||||
"generate:types": "tsc",
|
||||
"test": "aegir test",
|
||||
"test:node": "aegir test --target node",
|
||||
"test:browser": "aegir test --target browser",
|
||||
"test:types": "aegir ts -p check",
|
||||
"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",
|
||||
"remove:types": "rimraf './src/**/*.d.ts'"
|
||||
"release-major": "aegir release --type major -t node -t browser"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -56,7 +56,6 @@
|
||||
"libp2p-tcp": "^0.15.0",
|
||||
"multiaddr": "^8.0.0",
|
||||
"multibase": "^3.0.0",
|
||||
"multihashes": "^3.0.1",
|
||||
"p-defer": "^3.0.0",
|
||||
"p-limit": "^2.3.0",
|
||||
"p-wait-for": "^3.1.0",
|
||||
@ -67,12 +66,10 @@
|
||||
"uint8arrays": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"aegir": "^29.2.0",
|
||||
"aegir": "^25.0.0",
|
||||
"it-handshake": "^1.0.1",
|
||||
"rimraf": "^3.0.2"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "ipfs"
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "3.7.5"
|
||||
},
|
||||
"contributors": [
|
||||
"Alan Shaw <alan.shaw@protocol.ai>",
|
||||
|
149
src/connection/connection.d.ts
vendored
Normal file
149
src/connection/connection.d.ts
vendored
Normal file
@ -0,0 +1,149 @@
|
||||
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;
|
||||
}
|
234
src/connection/connection.js
Normal file
234
src/connection/connection.js
Normal file
@ -0,0 +1,234 @@
|
||||
'use strict'
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const multiaddr = require('multiaddr')
|
||||
const withIs = require('class-is')
|
||||
const errCode = require('err-code')
|
||||
const Status = require('./status')
|
||||
|
||||
function validateArgs (localAddr, localPeer, remotePeer, newStream, close, getStreams, stat) {
|
||||
if (localAddr && !multiaddr.isMultiaddr(localAddr)) {
|
||||
throw errCode(new Error('localAddr must be an instance of multiaddr'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!PeerId.isPeerId(localPeer)) {
|
||||
throw errCode(new Error('localPeer must be an instance of peer-id'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!PeerId.isPeerId(remotePeer)) {
|
||||
throw errCode(new Error('remotePeer must be an instance of peer-id'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (typeof newStream !== 'function') {
|
||||
throw errCode(new Error('new stream must be a function'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (typeof close !== 'function') {
|
||||
throw errCode(new Error('close must be a function'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (typeof getStreams !== 'function') {
|
||||
throw errCode(new Error('getStreams must be a function'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!stat) {
|
||||
throw errCode(new Error('connection metadata object must be provided'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (stat.direction !== 'inbound' && stat.direction !== 'outbound') {
|
||||
throw errCode(new Error('direction must be "inbound" or "outbound"'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!stat.timeline) {
|
||||
throw errCode(new Error('connection timeline object must be provided in the stat object'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!stat.timeline.open) {
|
||||
throw errCode(new Error('connection open timestamp must be provided'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!stat.timeline.upgraded) {
|
||||
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' })
|
231
src/connection/index.d.ts
vendored
231
src/connection/index.d.ts
vendored
@ -1,230 +1 @@
|
||||
export = Connection;
|
||||
/**
|
||||
* @typedef {Object} ConectionStat
|
||||
* @property {string} direction - connection establishment direction ("inbound" or "outbound").
|
||||
* @property {object} timeline - connection relevant events timestamp.
|
||||
* @property {string} timeline.open - connection opening timestamp.
|
||||
* @property {string} timeline.upgraded - connection upgraded 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[]) => Promise<{stream: Stream, protocol: string}>} newStream - new stream muxer function.
|
||||
* @property {() => Promise<void>} close - close raw connection function.
|
||||
* @property {() => Stream[]} getStreams - get streams from muxer function.
|
||||
* @property {ConectionStat} stat - metadata of the connection.
|
||||
*/
|
||||
declare 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 }: ConnectionOptions);
|
||||
/**
|
||||
* Connection identifier.
|
||||
*/
|
||||
id: string;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* - connection establishment direction ("inbound" or "outbound").
|
||||
*/
|
||||
direction: string;
|
||||
/**
|
||||
* - connection relevant events timestamp.
|
||||
*/
|
||||
timeline: {
|
||||
open: string;
|
||||
upgraded: string;
|
||||
};
|
||||
/**
|
||||
* - connection multiplexing identifier.
|
||||
*/
|
||||
multiplexer?: string;
|
||||
/**
|
||||
* - connection encryption method identifier.
|
||||
*/
|
||||
encryption?: string;
|
||||
};
|
||||
/**
|
||||
* Reference to the new stream function of the multiplexer
|
||||
*/
|
||||
_newStream: (protocols: string[]) => Promise<{
|
||||
stream: any;
|
||||
protocol: string;
|
||||
}>;
|
||||
/**
|
||||
* Reference to the close function of the raw connection
|
||||
*/
|
||||
_close: () => Promise<void>;
|
||||
/**
|
||||
* 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;
|
||||
/**
|
||||
* - connection establishment direction ("inbound" or "outbound").
|
||||
*/
|
||||
direction: string;
|
||||
/**
|
||||
* - connection relevant events timestamp.
|
||||
*/
|
||||
timeline: {
|
||||
open: string;
|
||||
upgraded: string;
|
||||
};
|
||||
/**
|
||||
* - connection multiplexing identifier.
|
||||
*/
|
||||
multiplexer?: string;
|
||||
/**
|
||||
* - connection encryption method identifier.
|
||||
*/
|
||||
encryption?: string;
|
||||
};
|
||||
/**
|
||||
* Get all the streams of the muxer.
|
||||
*
|
||||
* @this {Connection}
|
||||
*/
|
||||
get streams(): any[];
|
||||
/**
|
||||
* Create a new stream from this connection
|
||||
*
|
||||
* @param {string[]|string} protocols - intended protocol for the stream
|
||||
* @returns {Promise<{stream: Stream, protocol: string}>} with muxed+multistream-selected stream and selected protocol
|
||||
*/
|
||||
newStream(protocols: string[] | 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
|
||||
* @returns {void}
|
||||
*/
|
||||
addStream(muxedStream: any, { protocol, metadata }: {
|
||||
protocol: string;
|
||||
metadata: object;
|
||||
}): void;
|
||||
/**
|
||||
* Remove stream registry after it is closed.
|
||||
*
|
||||
* @param {string} id - identifier of the stream
|
||||
*/
|
||||
removeStream(id: string): void;
|
||||
/**
|
||||
* Close the connection.
|
||||
*
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
_closing: void;
|
||||
}
|
||||
declare namespace Connection {
|
||||
export { ConectionStat, ConnectionOptions };
|
||||
}
|
||||
type ConnectionOptions = {
|
||||
/**
|
||||
* - local multiaddr of the connection if known.
|
||||
*/
|
||||
localAddr?: import("multiaddr");
|
||||
/**
|
||||
* - remote multiaddr of the connection.
|
||||
*/
|
||||
remoteAddr?: import("multiaddr");
|
||||
/**
|
||||
* - local peer-id.
|
||||
*/
|
||||
localPeer: import("peer-id");
|
||||
/**
|
||||
* - remote peer-id.
|
||||
*/
|
||||
remotePeer: import("peer-id");
|
||||
/**
|
||||
* - new stream muxer function.
|
||||
*/
|
||||
newStream: (protocols: string[]) => Promise<{
|
||||
stream: any;
|
||||
protocol: string;
|
||||
}>;
|
||||
/**
|
||||
* - close raw connection function.
|
||||
*/
|
||||
close: () => Promise<void>;
|
||||
/**
|
||||
* - get streams from muxer function.
|
||||
*/
|
||||
getStreams: () => any[];
|
||||
/**
|
||||
* - metadata of the connection.
|
||||
*/
|
||||
stat: ConectionStat;
|
||||
};
|
||||
type ConectionStat = {
|
||||
/**
|
||||
* - connection establishment direction ("inbound" or "outbound").
|
||||
*/
|
||||
direction: string;
|
||||
/**
|
||||
* - connection relevant events timestamp.
|
||||
*/
|
||||
timeline: {
|
||||
open: string;
|
||||
upgraded: string;
|
||||
};
|
||||
/**
|
||||
* - connection multiplexing identifier.
|
||||
*/
|
||||
multiplexer?: string;
|
||||
/**
|
||||
* - connection encryption method identifier.
|
||||
*/
|
||||
encryption?: string;
|
||||
};
|
||||
export var Connection: typeof import('./connection');
|
||||
|
@ -1,242 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
const PeerId = require('peer-id')
|
||||
const multiaddr = require('multiaddr')
|
||||
const withIs = require('class-is')
|
||||
const errCode = require('err-code')
|
||||
const Status = require('./status')
|
||||
|
||||
/**
|
||||
* @typedef {Object} ConectionStat
|
||||
* @property {string} direction - connection establishment direction ("inbound" or "outbound").
|
||||
* @property {object} timeline - connection relevant events timestamp.
|
||||
* @property {string} timeline.open - connection opening timestamp.
|
||||
* @property {string} timeline.upgraded - connection upgraded 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[]) => Promise<{stream: Stream, protocol: string}>} newStream - new stream muxer function.
|
||||
* @property {() => Promise<void>} close - close raw connection function.
|
||||
* @property {() => Stream[]} getStreams - get streams from muxer function.
|
||||
* @property {ConectionStat} stat - metadata of the connection.
|
||||
* @module connection/index
|
||||
* @type {typeof import('./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(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[]|string} protocols - intended protocol for the stream
|
||||
* @returns {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
|
||||
* @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 === 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.exports = Connection
|
||||
|
||||
function validateArgs (localAddr, localPeer, remotePeer, newStream, close, getStreams, stat) {
|
||||
if (localAddr && !multiaddr.isMultiaddr(localAddr)) {
|
||||
throw errCode(new Error('localAddr must be an instance of multiaddr'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!PeerId.isPeerId(localPeer)) {
|
||||
throw errCode(new Error('localPeer must be an instance of peer-id'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!PeerId.isPeerId(remotePeer)) {
|
||||
throw errCode(new Error('remotePeer must be an instance of peer-id'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (typeof newStream !== 'function') {
|
||||
throw errCode(new Error('new stream must be a function'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (typeof close !== 'function') {
|
||||
throw errCode(new Error('close must be a function'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (typeof getStreams !== 'function') {
|
||||
throw errCode(new Error('getStreams must be a function'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!stat) {
|
||||
throw errCode(new Error('connection metadata object must be provided'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (stat.direction !== 'inbound' && stat.direction !== 'outbound') {
|
||||
throw errCode(new Error('direction must be "inbound" or "outbound"'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!stat.timeline) {
|
||||
throw errCode(new Error('connection timeline object must be provided in the stat object'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!stat.timeline.open) {
|
||||
throw errCode(new Error('connection open timestamp must be provided'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
|
||||
if (!stat.timeline.upgraded) {
|
||||
throw errCode(new Error('connection upgraded timestamp must be provided'), 'ERR_INVALID_PARAMETERS')
|
||||
}
|
||||
}
|
||||
exports.Connection = require('./connection')
|
||||
|
6
src/connection/status.d.ts
vendored
6
src/connection/status.d.ts
vendored
@ -1,3 +1,3 @@
|
||||
export const OPEN: string;
|
||||
export const CLOSING: string;
|
||||
export const CLOSED: string;
|
||||
export declare const OPEN: string;
|
||||
export declare const CLOSING: string;
|
||||
export declare const CLOSED: string;
|
||||
|
@ -1,6 +0,0 @@
|
||||
export = ContentRouting;
|
||||
|
||||
declare class ContentRouting {
|
||||
findProviders(cid);
|
||||
provide(cid);
|
||||
}
|
@ -11,9 +11,6 @@ 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)
|
||||
@ -22,24 +19,24 @@ Table of Contents
|
||||
* [Returns](#returns-1)
|
||||
* [Publish](#publish)
|
||||
* [pubsub.publish(topics, message)](#pubsubpublishtopics-message)
|
||||
* [Parameters](#parameters-1)
|
||||
* [Parameters](#parameters)
|
||||
* [Returns](#returns-2)
|
||||
* [Subscribe](#subscribe)
|
||||
* [pubsub.subscribe(topic)](#pubsubsubscribetopic)
|
||||
* [Parameters](#parameters-2)
|
||||
* [Parameters](#parameters-1)
|
||||
* [Unsubscribe](#unsubscribe)
|
||||
* [pubsub.unsubscribe(topic)](#pubsubunsubscribetopic)
|
||||
* [Parameters](#parameters-3)
|
||||
* [Parameters](#parameters-2)
|
||||
* [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-4)
|
||||
* [Parameters](#parameters-3)
|
||||
* [Returns](#returns-4)
|
||||
* [Validate](#validate)
|
||||
* [pubsub.validate(message)](#pubsubvalidatemessage)
|
||||
* [Parameters](#parameters-5)
|
||||
* [Parameters](#parameters-4)
|
||||
* [Returns](#returns-5)
|
||||
* [Test suite usage](#test-suite-usage)
|
||||
|
||||
@ -52,7 +49,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 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.
|
||||
`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.
|
||||
|
||||
### Extend interface
|
||||
|
||||
@ -77,7 +74,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-interfaces/src/pubsub')
|
||||
const Pubsub = require('libp2p-pubsub')
|
||||
|
||||
class PubsubImplementation extends Pubsub {
|
||||
constructor({ libp2p, options })
|
||||
@ -85,7 +82,8 @@ class PubsubImplementation extends Pubsub {
|
||||
debugName: 'libp2p:pubsub',
|
||||
multicodecs: '/pubsub-implementation/1.0.0',
|
||||
libp2p,
|
||||
globalSigningPolicy: options.globalSigningPolicy
|
||||
signMessages: options.signMessages,
|
||||
strictSigning: options.strictSigning
|
||||
})
|
||||
}
|
||||
|
||||
@ -100,23 +98,6 @@ 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`.
|
||||
@ -204,7 +185,7 @@ Get a list of the [PeerId](https://github.com/libp2p/js-peer-id) strings that ar
|
||||
|
||||
### Validate
|
||||
|
||||
Validates a message according to the signature policy and topic-specific validation function.
|
||||
Validates the signature of a message.
|
||||
|
||||
#### `pubsub.validate(message)`
|
||||
|
||||
|
11
src/pubsub/errors.d.ts
vendored
11
src/pubsub/errors.d.ts
vendored
@ -1,11 +1,4 @@
|
||||
export namespace codes {
|
||||
const ERR_INVALID_SIGNATURE_POLICY: string;
|
||||
const ERR_UNHANDLED_SIGNATURE_POLICY: string;
|
||||
const ERR_MISSING_SIGNATURE: string;
|
||||
const ERR_MISSING_SEQNO: string;
|
||||
const ERR_INVALID_SIGNATURE: string;
|
||||
const ERR_UNEXPECTED_FROM: string;
|
||||
const ERR_UNEXPECTED_SIGNATURE: string;
|
||||
const ERR_UNEXPECTED_KEY: string;
|
||||
const ERR_UNEXPECTED_SEQNO: string;
|
||||
export const ERR_MISSING_SIGNATURE: string;
|
||||
export const ERR_INVALID_SIGNATURE: string;
|
||||
}
|
||||
|
@ -1,46 +1,6 @@
|
||||
'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',
|
||||
/**
|
||||
* 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'
|
||||
ERR_INVALID_SIGNATURE: 'ERR_INVALID_SIGNATURE'
|
||||
}
|
||||
|
127
src/pubsub/index.d.ts
vendored
127
src/pubsub/index.d.ts
vendored
@ -13,27 +13,29 @@ export = PubsubBaseProtocol;
|
||||
* @type import('peer-id')
|
||||
*/
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
declare class PubsubBaseProtocol {
|
||||
/**
|
||||
* @param {Object} props
|
||||
* @param {string} props.debugName - log namespace
|
||||
* @param {Array<string>|string} props.multicodecs - protocol identificers to connect
|
||||
* @param {String} props.debugName log namespace
|
||||
* @param {Array<string>|string} props.multicodecs protocol identificers to connect
|
||||
* @param {Libp2p} props.libp2p
|
||||
* @param {SignaturePolicy} [props.globalSignaturePolicy = SignaturePolicy.StrictSign] - defines how signatures should be handled
|
||||
* @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 {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, globalSignaturePolicy, canRelayMessage, emitSelf }: {
|
||||
constructor({ debugName, multicodecs, libp2p, signMessages, strictSigning, canRelayMessage, emitSelf }: {
|
||||
debugName: string;
|
||||
multicodecs: Array<string> | string;
|
||||
multicodecs: string | string[];
|
||||
libp2p: any;
|
||||
globalSignaturePolicy: any;
|
||||
canRelayMessage: boolean;
|
||||
emitSelf: boolean;
|
||||
signMessages?: boolean;
|
||||
strictSigning?: boolean;
|
||||
canRelayMessage?: boolean;
|
||||
emitSelf?: boolean;
|
||||
});
|
||||
log: any;
|
||||
/**
|
||||
@ -55,7 +57,6 @@ declare class PubsubBaseProtocol {
|
||||
topics: Map<string, Set<string>>;
|
||||
/**
|
||||
* List of our subscriptions
|
||||
*
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
subscriptions: Set<string>;
|
||||
@ -65,27 +66,24 @@ declare class PubsubBaseProtocol {
|
||||
* @type {Map<string, import('./peer-streams')>}
|
||||
*/
|
||||
peers: Map<string, import('./peer-streams')>;
|
||||
signMessages: boolean;
|
||||
/**
|
||||
* The signature policy to follow by default
|
||||
*
|
||||
* @type {string}
|
||||
* If message signing should be required for incoming messages
|
||||
* @type {boolean}
|
||||
*/
|
||||
globalSignaturePolicy: string;
|
||||
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
|
||||
*/
|
||||
/**
|
||||
@ -93,79 +91,73 @@ declare class PubsubBaseProtocol {
|
||||
*
|
||||
* Keyed by topic
|
||||
* Topic validators are functions with the following input:
|
||||
*
|
||||
* @type {Map<string, validator>}
|
||||
*/
|
||||
topicValidators: Map<string, (arg0: string, arg1: InMessage) => Promise<void>>;
|
||||
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
|
||||
* @param {Connection} props.connection connection
|
||||
*/
|
||||
private _onIncomingStream;
|
||||
_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
|
||||
* @param {PeerId} peerId remote peer-id
|
||||
* @param {Connection} conn connection to the peer
|
||||
*/
|
||||
private _onPeerConnected;
|
||||
_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
|
||||
* @param {PeerId} peerId peerId
|
||||
* @param {Error} err error for connection end
|
||||
*/
|
||||
private _onPeerDisconnected;
|
||||
_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}
|
||||
*/
|
||||
private _addPeer;
|
||||
_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}
|
||||
*/
|
||||
private _removePeer;
|
||||
_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
|
||||
* @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 {String} idB58Str
|
||||
* @param {PeerStreams} peerStreams
|
||||
* @param {RPC} rpc
|
||||
* @returns {boolean}
|
||||
@ -173,36 +165,31 @@ declare class PubsubBaseProtocol {
|
||||
_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
|
||||
* @param {RPC.Message} msg the message object
|
||||
* @returns {Uint8Array} message id as bytes
|
||||
*/
|
||||
getMsgId(msg: any): Uint8Array;
|
||||
/**
|
||||
* Whether to accept a message from a peer
|
||||
* Override to create a graylist
|
||||
*
|
||||
* @override
|
||||
* @param {string} id
|
||||
* @returns {boolean}
|
||||
@ -211,7 +198,6 @@ declare class PubsubBaseProtocol {
|
||||
/**
|
||||
* Decode Uint8Array into an RPC object.
|
||||
* This can be override to use a custom router protobuf.
|
||||
*
|
||||
* @param {Uint8Array} bytes
|
||||
* @returns {RPC}
|
||||
*/
|
||||
@ -219,32 +205,28 @@ declare class PubsubBaseProtocol {
|
||||
/**
|
||||
* 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 {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} 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: 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>}
|
||||
*/
|
||||
@ -252,22 +234,19 @@ declare class PubsubBaseProtocol {
|
||||
/**
|
||||
* 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>}
|
||||
*/
|
||||
private _buildMessage;
|
||||
_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): Array<string>;
|
||||
getSubscribers(topic: string): string[];
|
||||
/**
|
||||
* Publishes messages to all subscribed peers
|
||||
*
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @param {Buffer} message
|
||||
@ -277,7 +256,6 @@ declare class PubsubBaseProtocol {
|
||||
/**
|
||||
* 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>}
|
||||
@ -286,7 +264,6 @@ declare class PubsubBaseProtocol {
|
||||
_publish(message: InMessage): Promise<void>;
|
||||
/**
|
||||
* Subscribes to a given topic.
|
||||
*
|
||||
* @abstract
|
||||
* @param {string} topic
|
||||
* @returns {void}
|
||||
@ -294,7 +271,6 @@ declare class PubsubBaseProtocol {
|
||||
subscribe(topic: string): void;
|
||||
/**
|
||||
* Unsubscribe from the given topic.
|
||||
*
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @returns {void}
|
||||
@ -302,16 +278,19 @@ declare class PubsubBaseProtocol {
|
||||
unsubscribe(topic: string): void;
|
||||
/**
|
||||
* Get the list of topics which the peer is subscribed to.
|
||||
*
|
||||
* @override
|
||||
* @returns {Array<string>}
|
||||
* @returns {Array<String>}
|
||||
*/
|
||||
getTopics(): Array<string>;
|
||||
getTopics(): string[];
|
||||
}
|
||||
declare namespace PubsubBaseProtocol {
|
||||
export { message, utils, SignaturePolicy, InMessage, PeerId };
|
||||
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;
|
||||
@ -326,7 +305,3 @@ type InMessage = {
|
||||
*/
|
||||
declare const message: typeof import('./message');
|
||||
declare const utils: typeof import("./utils");
|
||||
declare const SignaturePolicy: {
|
||||
StrictSign: string;
|
||||
StrictNoSign: string;
|
||||
};
|
||||
|
@ -13,7 +13,6 @@ const { codes } = require('./errors')
|
||||
*/
|
||||
const message = require('./message')
|
||||
const PeerStreams = require('./peer-streams')
|
||||
const { SignaturePolicy } = require('./signature-policy')
|
||||
const utils = require('./utils')
|
||||
|
||||
const {
|
||||
@ -36,25 +35,27 @@ const {
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 {String} props.debugName log namespace
|
||||
* @param {Array<string>|string} props.multicodecs protocol identificers to connect
|
||||
* @param {Libp2p} props.libp2p
|
||||
* @param {SignaturePolicy} [props.globalSignaturePolicy = SignaturePolicy.StrictSign] - defines how signatures should be handled
|
||||
* @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 {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,
|
||||
globalSignaturePolicy = SignaturePolicy.StrictSign,
|
||||
signMessages = true,
|
||||
strictSigning = true,
|
||||
canRelayMessage = false,
|
||||
emitSelf = false
|
||||
}) {
|
||||
@ -97,7 +98,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* List of our subscriptions
|
||||
*
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
this.subscriptions = new Set()
|
||||
@ -109,35 +109,29 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
*/
|
||||
this.peers = new Map()
|
||||
|
||||
// validate signature policy
|
||||
if (!SignaturePolicy[globalSignaturePolicy]) {
|
||||
throw errcode(new Error('Invalid global signature policy'), codes.ERR_INVALID_SIGUATURE_POLICY)
|
||||
}
|
||||
// Message signing
|
||||
this.signMessages = signMessages
|
||||
|
||||
/**
|
||||
* The signature policy to follow by default
|
||||
*
|
||||
* @type {string}
|
||||
* If message signing should be required for incoming messages
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.globalSignaturePolicy = globalSignaturePolicy
|
||||
this.strictSigning = strictSigning
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
/**
|
||||
@ -145,7 +139,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
*
|
||||
* Keyed by topic
|
||||
* Topic validators are functions with the following input:
|
||||
*
|
||||
* @type {Map<string, validator>}
|
||||
*/
|
||||
this.topicValidators = new Map()
|
||||
@ -160,7 +153,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Register the pubsub protocol onto the libp2p node.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
start () {
|
||||
@ -190,7 +182,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Unregister the pubsub protocol and the streams with other peers will be closed.
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
stop () {
|
||||
@ -212,12 +203,11 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* On an inbound stream opened.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} props
|
||||
* @param {string} props.protocol
|
||||
* @param {DuplexIterableStream} props.stream
|
||||
* @param {Connection} props.connection - connection
|
||||
* @param {Connection} props.connection connection
|
||||
*/
|
||||
_onIncomingStream ({ protocol, stream, connection }) {
|
||||
const peerId = connection.remotePeer
|
||||
@ -230,10 +220,9 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Registrar notifies an established connection with pubsub protocol.
|
||||
*
|
||||
* @private
|
||||
* @param {PeerId} peerId - remote peer-id
|
||||
* @param {Connection} conn - connection to the peer
|
||||
* @param {PeerId} peerId remote peer-id
|
||||
* @param {Connection} conn connection to the peer
|
||||
*/
|
||||
async _onPeerConnected (peerId, conn) {
|
||||
const idB58Str = peerId.toB58String()
|
||||
@ -253,10 +242,9 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Registrar notifies a closing connection with pubsub protocol.
|
||||
*
|
||||
* @private
|
||||
* @param {PeerId} peerId - peerId
|
||||
* @param {Error} err - error for connection end
|
||||
* @param {PeerId} peerId peerId
|
||||
* @param {Error} err error for connection end
|
||||
*/
|
||||
_onPeerDisconnected (peerId, err) {
|
||||
const idB58Str = peerId.toB58String()
|
||||
@ -267,7 +255,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Notifies the router that a peer has been connected
|
||||
*
|
||||
* @private
|
||||
* @param {PeerId} peerId
|
||||
* @param {string} protocol
|
||||
@ -298,7 +285,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Notifies the router that a peer has been disconnected.
|
||||
*
|
||||
* @private
|
||||
* @param {PeerId} peerId
|
||||
* @returns {PeerStreams | undefined}
|
||||
@ -329,10 +315,9 @@ 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 {DuplexIterableStream} stream inbound stream
|
||||
* @param {PeerStreams} peerStreams PubSub peer
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async _processMessages (idB58Str, stream, peerStreams) {
|
||||
@ -349,14 +334,13 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
}
|
||||
)
|
||||
} catch (err) {
|
||||
this._onPeerDisconnected(peerStreams.id, err)
|
||||
this.log.err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles an rpc request from a peer
|
||||
*
|
||||
* @param {string} idB58Str
|
||||
* @param {String} idB58Str
|
||||
* @param {PeerStreams} peerStreams
|
||||
* @param {RPC} rpc
|
||||
* @returns {boolean}
|
||||
@ -392,7 +376,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Handles a subscription change from a peer
|
||||
*
|
||||
* @param {string} id
|
||||
* @param {RPC.SubOpt} subOpt
|
||||
*/
|
||||
@ -416,7 +399,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Handles an message from a peer
|
||||
*
|
||||
* @param {InMessage} msg
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
@ -441,7 +423,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Emit a message from a peer
|
||||
*
|
||||
* @param {InMessage} message
|
||||
*/
|
||||
_emitMessage (message) {
|
||||
@ -455,26 +436,16 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
/**
|
||||
* The default msgID implementation
|
||||
* Child class can override this.
|
||||
*
|
||||
* @param {RPC.Message} msg - the message object
|
||||
* @param {RPC.Message} msg the message object
|
||||
* @returns {Uint8Array} message id as bytes
|
||||
*/
|
||||
getMsgId (msg) {
|
||||
const signaturePolicy = this.globalSignaturePolicy
|
||||
switch (signaturePolicy) {
|
||||
case SignaturePolicy.StrictSign:
|
||||
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)
|
||||
}
|
||||
return utils.msgId(msg.from, msg.seqno)
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to accept a message from a peer
|
||||
* Override to create a graylist
|
||||
*
|
||||
* @override
|
||||
* @param {string} id
|
||||
* @returns {boolean}
|
||||
@ -486,7 +457,6 @@ 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}
|
||||
*/
|
||||
@ -497,7 +467,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
/**
|
||||
* Encode RPC object into a Uint8Array.
|
||||
* This can be override to use a custom router protobuf.
|
||||
*
|
||||
* @param {RPC} rpc
|
||||
* @returns {Uint8Array}
|
||||
*/
|
||||
@ -507,8 +476,7 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Send an rpc object to a peer
|
||||
*
|
||||
* @param {string} id - peer id
|
||||
* @param {string} id peer id
|
||||
* @param {RPC} rpc
|
||||
* @returns {void}
|
||||
*/
|
||||
@ -525,10 +493,9 @@ 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) {
|
||||
@ -540,41 +507,20 @@ 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
|
||||
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)
|
||||
// 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)
|
||||
}
|
||||
|
||||
for (const topic of message.topicIDs) {
|
||||
const validatorFn = this.topicValidators.get(topic)
|
||||
if (!validatorFn) {
|
||||
@ -587,22 +533,16 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
/**
|
||||
* 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) {
|
||||
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 message
|
||||
default:
|
||||
throw errcode(new Error('Cannot build message: unhandled signature policy: ' + signaturePolicy), codes.ERR_UNHANDLED_SIGNATURE_POLICY)
|
||||
const msg = utils.normalizeOutRpcMessage(message)
|
||||
if (this.signMessages) {
|
||||
return signMessage(this.peerId, msg)
|
||||
} else {
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
||||
@ -610,7 +550,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Get a list of the peer-ids that are subscribed to one topic.
|
||||
*
|
||||
* @param {string} topic
|
||||
* @returns {Array<string>}
|
||||
*/
|
||||
@ -632,7 +571,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Publishes messages to all subscribed peers
|
||||
*
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @param {Buffer} message
|
||||
@ -648,11 +586,13 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
const from = this.peerId.toB58String()
|
||||
let msgObject = {
|
||||
receivedFrom: from,
|
||||
from: from,
|
||||
data: message,
|
||||
seqno: utils.randomSeqno(),
|
||||
topicIDs: [topic]
|
||||
}
|
||||
|
||||
// ensure that the message follows the signature policy
|
||||
// ensure that any operations performed on the message will include the signature
|
||||
const outMsg = await this._buildMessage(msgObject)
|
||||
msgObject = utils.normalizeInRpcMessage(outMsg)
|
||||
|
||||
@ -666,7 +606,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
/**
|
||||
* 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>}
|
||||
@ -678,7 +617,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Subscribes to a given topic.
|
||||
*
|
||||
* @abstract
|
||||
* @param {string} topic
|
||||
* @returns {void}
|
||||
@ -696,7 +634,6 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Unsubscribe from the given topic.
|
||||
*
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @returns {void}
|
||||
@ -714,9 +651,8 @@ 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) {
|
||||
@ -730,4 +666,3 @@ class PubsubBaseProtocol extends EventEmitter {
|
||||
module.exports = PubsubBaseProtocol
|
||||
module.exports.message = message
|
||||
module.exports.utils = utils
|
||||
module.exports.SignaturePolicy = SignaturePolicy
|
||||
|
3
src/pubsub/message/sign.d.ts
vendored
3
src/pubsub/message/sign.d.ts
vendored
@ -17,8 +17,7 @@ export function signMessage(peerId: import("peer-id"), message: any): Promise<an
|
||||
export const SignPrefix: any;
|
||||
/**
|
||||
* Verifies the signature of the given message
|
||||
*
|
||||
* @param {InMessage} message
|
||||
* @returns {Promise<boolean>}
|
||||
* @returns {Promise<Boolean>}
|
||||
*/
|
||||
export function verifySignature(message: any): Promise<boolean>;
|
||||
|
@ -31,9 +31,8 @@ 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) {
|
||||
// Get message sans the signature
|
||||
|
22
src/pubsub/peer-streams.d.ts
vendored
22
src/pubsub/peer-streams.d.ts
vendored
@ -16,12 +16,12 @@ export = PeerStreams;
|
||||
*/
|
||||
declare class PeerStreams {
|
||||
/**
|
||||
* @param {object} properties - properties of the PeerStreams.
|
||||
* @param {object} properties properties of the PeerStreams.
|
||||
* @param {PeerId} properties.id
|
||||
* @param {string} properties.protocol
|
||||
*/
|
||||
constructor({ id, protocol }: {
|
||||
id: PeerId;
|
||||
id: import("peer-id");
|
||||
protocol: string;
|
||||
});
|
||||
/**
|
||||
@ -30,40 +30,34 @@ declare class PeerStreams {
|
||||
id: import('peer-id');
|
||||
/**
|
||||
* Established protocol
|
||||
*
|
||||
* @type {string}
|
||||
*/
|
||||
protocol: string;
|
||||
/**
|
||||
* The raw outbound stream, as retrieved from conn.newStream
|
||||
*
|
||||
* @private
|
||||
* @type {DuplexIterableStream}
|
||||
*/
|
||||
private _rawOutboundStream;
|
||||
_rawOutboundStream: DuplexIterableStream;
|
||||
/**
|
||||
* The raw inbound stream, as retrieved from the callback from libp2p.handle
|
||||
*
|
||||
* @private
|
||||
* @type {DuplexIterableStream}
|
||||
*/
|
||||
private _rawInboundStream;
|
||||
_rawInboundStream: DuplexIterableStream;
|
||||
/**
|
||||
* An AbortController for controlled shutdown of the inbound stream
|
||||
*
|
||||
* @private
|
||||
* @type {typeof AbortController}
|
||||
*/
|
||||
private _inboundAbortController;
|
||||
_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;
|
||||
@ -103,7 +97,6 @@ declare class PeerStreams {
|
||||
attachOutboundStream(stream: any): Promise<void>;
|
||||
/**
|
||||
* Closes the open connection to peer
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
close(): void;
|
||||
@ -113,7 +106,8 @@ declare namespace PeerStreams {
|
||||
}
|
||||
type DuplexIterableStream = {
|
||||
sink: Sink;
|
||||
source: () => AsyncIterator<Uint8Array>;
|
||||
source: () => AsyncIterator<Uint8Array, any, undefined>;
|
||||
};
|
||||
type PeerId = import("peer-id");
|
||||
declare const AbortController: typeof import("abort-controller");
|
||||
type Sink = (source: Uint8Array) => Promise<Uint8Array>;
|
||||
type PeerId = import("peer-id");
|
||||
|
@ -30,7 +30,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,40 +43,34 @@ 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}
|
||||
*/
|
||||
this._rawOutboundStream = null
|
||||
/**
|
||||
* The raw inbound stream, as retrieved from the callback from libp2p.handle
|
||||
*
|
||||
* @private
|
||||
* @type {DuplexIterableStream}
|
||||
*/
|
||||
this._rawInboundStream = null
|
||||
/**
|
||||
* An AbortController for controlled shutdown of the inbound stream
|
||||
*
|
||||
* @private
|
||||
* @type {typeof AbortController}
|
||||
*/
|
||||
this._inboundAbortController = null
|
||||
/**
|
||||
* Write stream -- its preferable to use the write method
|
||||
*
|
||||
* @type {import('it-pushable').Pushable<Uint8Array>>}
|
||||
*/
|
||||
this.outboundStream = null
|
||||
/**
|
||||
* Read stream
|
||||
*
|
||||
* @type {DuplexIterableStream}
|
||||
*/
|
||||
this.inboundStream = null
|
||||
@ -185,7 +179,6 @@ class PeerStreams extends EventEmitter {
|
||||
|
||||
/**
|
||||
* Closes the open connection to peer
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
close () {
|
||||
|
4
src/pubsub/signature-policy.d.ts
vendored
4
src/pubsub/signature-policy.d.ts
vendored
@ -1,4 +0,0 @@
|
||||
export namespace SignaturePolicy {
|
||||
const StrictSign: string;
|
||||
const StrictNoSign: string;
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* Enum for Signature Policy
|
||||
* Details how message signatures are produced/consumed
|
||||
*/
|
||||
exports.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: '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: 'StrictNoSign'
|
||||
}
|
@ -76,7 +76,7 @@ module.exports = (common) => {
|
||||
const defer = pDefer()
|
||||
|
||||
const handler = (msg) => {
|
||||
expect(msg).to.not.eql(undefined)
|
||||
expect(msg).to.exist()
|
||||
defer.resolve()
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,6 @@ 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')
|
||||
@ -32,17 +31,24 @@ 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
|
||||
|
||||
expect(messageToEmit.seqno).to.not.eql(undefined)
|
||||
expect(messageToEmit.key).to.not.eql(undefined)
|
||||
expect(messageToEmit.signature).to.not.eql(undefined)
|
||||
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)
|
||||
})
|
||||
|
||||
it('should drop unsigned messages', async () => {
|
||||
@ -77,16 +83,18 @@ 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 rpc = {
|
||||
subscriptions: [],
|
||||
msgs: [{
|
||||
from: peerStream.id.toBytes(),
|
||||
data,
|
||||
seqno: utils.randomSeqno(),
|
||||
topicIDs: [topic]
|
||||
}]
|
||||
}
|
||||
|
@ -52,20 +52,26 @@ module.exports = (common) => {
|
||||
await common.teardown()
|
||||
})
|
||||
|
||||
it('subscribe to the topic on node a', async () => {
|
||||
it('subscribe to the topic on node a', () => {
|
||||
const topic = 'Z'
|
||||
const defer = pDefer()
|
||||
|
||||
psA.subscribe(topic)
|
||||
expectSet(psA.subscriptions, [topic])
|
||||
|
||||
await new Promise((resolve) => psB.once('pubsub:subscription-change', resolve))
|
||||
expect(psB.peers.size).to.equal(2)
|
||||
psB.once('pubsub:subscription-change', () => {
|
||||
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.eql(undefined)
|
||||
expect(psC.peers.size).to.equal(1)
|
||||
expect(psC.topics.get(topic)).to.not.exist()
|
||||
|
||||
defer.resolve()
|
||||
})
|
||||
|
||||
return defer.promise
|
||||
})
|
||||
|
||||
it('subscribe to the topic on node b', async () => {
|
||||
|
7
src/pubsub/utils.d.ts
vendored
7
src/pubsub/utils.d.ts
vendored
@ -1,7 +1,6 @@
|
||||
export function randomSeqno(): Uint8Array;
|
||||
export function msgId(from: string, seqno: Uint8Array): Uint8Array;
|
||||
export function noSignMsgId(data: Uint8Array): Uint8Array;
|
||||
export function anyMatch(a: Set<any> | any[], b: Set<any> | any[]): boolean;
|
||||
export function anyMatch(a: any[] | Set<any>, b: any[] | Set<any>): boolean;
|
||||
export function ensureArray(maybeArray: any): any[];
|
||||
export function normalizeInRpcMessage(message: object, peerId: string): object;
|
||||
export function normalizeOutRpcMessage(message: object): object;
|
||||
export function normalizeInRpcMessage(message: any, peerId: string): any;
|
||||
export function normalizeOutRpcMessage(message: any): any;
|
||||
|
@ -4,7 +4,6 @@ const randomBytes = require('libp2p-crypto/src/random-bytes')
|
||||
const uint8ArrayToString = require('uint8arrays/to-string')
|
||||
const uint8ArrayFromString = require('uint8arrays/from-string')
|
||||
const PeerId = require('peer-id')
|
||||
const multihash = require('multihashes')
|
||||
exports = module.exports
|
||||
|
||||
/**
|
||||
@ -33,15 +32,6 @@ exports.msgId = (from, seqno) => {
|
||||
return msgId
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a message id, based on message `data`.
|
||||
*
|
||||
* @param {Uint8Array} data
|
||||
* @returns {Uint8Array}
|
||||
* @private
|
||||
*/
|
||||
exports.noSignMsgId = (data) => multihash.encode(data, 'sha2-256')
|
||||
|
||||
/**
|
||||
* Check if any member of the first set is also a member
|
||||
* of the second set.
|
||||
@ -85,10 +75,9 @@ exports.ensureArray = (maybeArray) => {
|
||||
|
||||
/**
|
||||
* Ensures `message.from` is base58 encoded
|
||||
*
|
||||
* @param {object} message
|
||||
* @param {string} peerId
|
||||
* @returns {object}
|
||||
* @param {String} peerId
|
||||
* @return {object}
|
||||
*/
|
||||
exports.normalizeInRpcMessage = (message, peerId) => {
|
||||
const m = Object.assign({}, message)
|
||||
@ -103,7 +92,7 @@ exports.normalizeInRpcMessage = (message, peerId) => {
|
||||
|
||||
/**
|
||||
* @param {object} message
|
||||
* @returns {object}
|
||||
* @return {object}
|
||||
*/
|
||||
exports.normalizeOutRpcMessage = (message) => {
|
||||
const m = Object.assign({}, message)
|
||||
|
7
src/record/index.d.ts
vendored
7
src/record/index.d.ts
vendored
@ -4,9 +4,9 @@ export = Record;
|
||||
*/
|
||||
declare class Record {
|
||||
/**
|
||||
* @class
|
||||
* @param {string} domain - signature domain
|
||||
* @param {Uint8Array} codec - identifier of the type of record
|
||||
* @constructor
|
||||
* @param {String} domain signature domain
|
||||
* @param {Uint8Array} codec identifier of the type of record
|
||||
*/
|
||||
constructor(domain: string, codec: Uint8Array);
|
||||
domain: string;
|
||||
@ -17,7 +17,6 @@ declare class Record {
|
||||
marshal(): void;
|
||||
/**
|
||||
* Verifies if the other provided Record is identical to this one.
|
||||
*
|
||||
* @param {Record} other
|
||||
*/
|
||||
equals(other: Record): void;
|
||||
|
@ -7,9 +7,9 @@ const errcode = require('err-code')
|
||||
*/
|
||||
class Record {
|
||||
/**
|
||||
* @class
|
||||
* @param {string} domain - signature domain
|
||||
* @param {Uint8Array} codec - identifier of the type of record
|
||||
* @constructor
|
||||
* @param {String} domain signature domain
|
||||
* @param {Uint8Array} codec identifier of the type of record
|
||||
*/
|
||||
constructor (domain, codec) {
|
||||
this.domain = domain
|
||||
@ -25,7 +25,6 @@ class Record {
|
||||
|
||||
/**
|
||||
* Verifies if the other provided Record is identical to this one.
|
||||
*
|
||||
* @param {Record} other
|
||||
*/
|
||||
equals (other) {
|
||||
|
@ -20,9 +20,8 @@ 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) {
|
||||
|
69
src/topology/index.d.ts
vendored
69
src/topology/index.d.ts
vendored
@ -1,63 +1,42 @@
|
||||
declare const _exports: Topology;
|
||||
export = _exports;
|
||||
export type PeerId = import("peer-id");
|
||||
export type TopologyHandlers = {
|
||||
/**
|
||||
* - protocol "onConnect" handler
|
||||
*/
|
||||
onConnect?: (peerId: PeerId, conn: import('../connection')) => void;
|
||||
/**
|
||||
* - protocol "onDisconnect" handler
|
||||
*/
|
||||
onDisconnect?: (peerId: PeerId) => void;
|
||||
};
|
||||
export type TopologyOptions = {
|
||||
/**
|
||||
* - minimum needed connections
|
||||
*/
|
||||
min?: number;
|
||||
/**
|
||||
* - maximum needed connections
|
||||
*/
|
||||
max?: number;
|
||||
handlers?: TopologyHandlers;
|
||||
};
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
*/
|
||||
/**
|
||||
* @typedef {Object} TopologyHandlers
|
||||
* @property {(peerId: PeerId, conn: import('../connection')) => void} [handlers.onConnect] - protocol "onConnect" handler
|
||||
* @property {(peerId: PeerId) => void} [handlers.onDisconnect] - protocol "onDisconnect" handler
|
||||
*
|
||||
* @typedef {Object} TopologyOptions
|
||||
* @property {number} [props.min = 0] - minimum needed connections
|
||||
* @property {number} [props.max = Infinity] - maximum needed connections
|
||||
* @property {TopologyHandlers} [props.handlers]
|
||||
*/
|
||||
declare class Topology {
|
||||
/**
|
||||
* @class
|
||||
* @param {TopologyHandlers} options
|
||||
* @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 }: TopologyHandlers);
|
||||
min: any;
|
||||
max: any;
|
||||
_onConnect: any;
|
||||
_onDisconnect: any;
|
||||
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: PeerId): void;
|
||||
disconnect(peerId: import("peer-id")): void;
|
||||
}
|
||||
|
@ -3,25 +3,15 @@
|
||||
const withIs = require('class-is')
|
||||
const noop = () => {}
|
||||
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} TopologyHandlers
|
||||
* @property {(peerId: PeerId, conn: import('../connection')) => void} [handlers.onConnect] - protocol "onConnect" handler
|
||||
* @property {(peerId: PeerId) => void} [handlers.onDisconnect] - protocol "onDisconnect" handler
|
||||
*
|
||||
* @typedef {Object} TopologyOptions
|
||||
* @property {number} [props.min = 0] - minimum needed connections
|
||||
* @property {number} [props.max = Infinity] - maximum needed connections
|
||||
* @property {TopologyHandlers} [props.handlers]
|
||||
*/
|
||||
|
||||
class Topology {
|
||||
/**
|
||||
* @class
|
||||
* @param {TopologyHandlers} options
|
||||
* @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 = 0,
|
||||
@ -37,19 +27,22 @@ class Topology {
|
||||
|
||||
/**
|
||||
* Set of peers that support the protocol.
|
||||
*
|
||||
* @type {Set<string>}
|
||||
*/
|
||||
this.peers = new Set()
|
||||
}
|
||||
|
||||
set registrar (registrar) { // eslint-disable-line
|
||||
set registrar (registrar) {
|
||||
this._registrar = registrar
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef PeerId
|
||||
* @type {import('peer-id')}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Notify about peer disconnected event.
|
||||
*
|
||||
* @param {PeerId} peerId
|
||||
* @returns {void}
|
||||
*/
|
||||
|
35
src/topology/multicodec-topology.d.ts
vendored
35
src/topology/multicodec-topology.d.ts
vendored
@ -2,26 +2,38 @@ declare const _exports: MulticodecTopology;
|
||||
export = _exports;
|
||||
declare class MulticodecTopology {
|
||||
/**
|
||||
* @class
|
||||
* @param {import('./').TopologyOptions} options
|
||||
* @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, handlers, multicodecs, }: import('./').TopologyOptions);
|
||||
multicodecs: any[];
|
||||
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: Array<string>;
|
||||
protocols: string[];
|
||||
}): void;
|
||||
/**
|
||||
* Verify if a new connected peer has a topology multicodec and call _onConnect.
|
||||
*
|
||||
* @param {Connection} connection
|
||||
* @returns {void}
|
||||
*/
|
||||
@ -29,13 +41,12 @@ declare class MulticodecTopology {
|
||||
set registrar(arg: any);
|
||||
/**
|
||||
* Update topology.
|
||||
*
|
||||
* @param {Array<{id: PeerId, multiaddrs: Array<Multiaddr>, protocols: Array<string>}>} peerDataIterable
|
||||
* @returns {void}
|
||||
*/
|
||||
_updatePeers(peerDataIterable: Array<{
|
||||
_updatePeers(peerDataIterable: {
|
||||
id: any;
|
||||
multiaddrs: Array<any>;
|
||||
protocols: Array<string>;
|
||||
}>): void;
|
||||
multiaddrs: any[];
|
||||
protocols: string[];
|
||||
}[]): void;
|
||||
}
|
||||
|
@ -6,14 +6,20 @@ const Topology = require('./index')
|
||||
|
||||
class MulticodecTopology extends Topology {
|
||||
/**
|
||||
* @class
|
||||
* @param {import('./').TopologyOptions} options
|
||||
* @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 = 0,
|
||||
max = Infinity,
|
||||
handlers = {},
|
||||
min,
|
||||
max,
|
||||
multicodecs,
|
||||
handlers
|
||||
}) {
|
||||
super({ min, max, handlers })
|
||||
|
||||
@ -40,7 +46,7 @@ class MulticodecTopology extends Topology {
|
||||
this._onPeerConnect = this._onPeerConnect.bind(this)
|
||||
}
|
||||
|
||||
set registrar (registrar) { // eslint-disable-line
|
||||
set registrar (registrar) {
|
||||
this._registrar = registrar
|
||||
this._registrar.peerStore.on('change:protocols', this._onProtocolChange)
|
||||
this._registrar.connectionManager.on('peer:connect', this._onPeerConnect)
|
||||
@ -51,7 +57,6 @@ class MulticodecTopology extends Topology {
|
||||
|
||||
/**
|
||||
* Update topology.
|
||||
*
|
||||
* @param {Array<{id: PeerId, multiaddrs: Array<Multiaddr>, protocols: Array<string>}>} peerDataIterable
|
||||
* @returns {void}
|
||||
*/
|
||||
@ -72,7 +77,6 @@ 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
|
||||
@ -98,7 +102,6 @@ class MulticodecTopology extends Topology {
|
||||
|
||||
/**
|
||||
* Verify if a new connected peer has a topology multicodec and call _onConnect.
|
||||
*
|
||||
* @param {Connection} connection
|
||||
* @returns {void}
|
||||
*/
|
||||
|
@ -4,9 +4,8 @@ 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) {
|
||||
|
@ -1,103 +0,0 @@
|
||||
export default Transport;
|
||||
|
||||
declare class Transport implements TransportInterface {
|
||||
constructor({ upgrader, ...others }: {
|
||||
upgrader: Upgrader;
|
||||
others: any;
|
||||
});
|
||||
/**
|
||||
* Dial a given multiaddr.
|
||||
* @param {Multiaddr} ma
|
||||
* @param {Object} [options]
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
dial(ma: Multiaddr, options?: Object): Promise<Connection>;
|
||||
/**
|
||||
* Create transport listeners.
|
||||
* @param {Object} options
|
||||
* @param {(Connection) => void} handler
|
||||
*/
|
||||
createListener(options: Object, handler: Function): Listener;
|
||||
/**
|
||||
* Takes a list of `Multiaddr`s and returns only valid addresses for the transport
|
||||
* @param {Multiaddr[]} multiaddrs
|
||||
* @returns {Multiaddr[]}
|
||||
*/
|
||||
filter(multiaddrs: Multiaddr[]): Multiaddr[];
|
||||
}
|
||||
|
||||
/**
|
||||
* A libp2p transport is understood as something that offers a dial and listen interface to establish connections.
|
||||
*/
|
||||
interface TransportInterface {
|
||||
/**
|
||||
* Dial a given multiaddr.
|
||||
* @param {Multiaddr} ma
|
||||
* @param {Object} [options]
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
dial(ma: Multiaddr, options?: Object): Promise<Connection>;
|
||||
/**
|
||||
* Create transport listeners.
|
||||
* @param {Object} options
|
||||
* @param {(Connection) => void} handler
|
||||
*/
|
||||
createListener(options: Object, handler: Function): Listener;
|
||||
/**
|
||||
* Takes a list of `Multiaddr`s and returns only valid addresses for the transport
|
||||
* @param {Multiaddr[]} multiaddrs
|
||||
* @returns {Multiaddr[]}
|
||||
*/
|
||||
filter(multiaddrs: Multiaddr[]): Multiaddr[];
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
/**
|
||||
* Start a listener
|
||||
* @param {Multiaddr} multiaddr
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
listen(multiaddr: Multiaddr): Promise<void>;
|
||||
/**
|
||||
* Get listen addresses
|
||||
* @returns {Multiaddr[]}
|
||||
*/
|
||||
getAddrs(): Multiaddr[];
|
||||
/**
|
||||
* Close listener
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
close(): Promise<void>;
|
||||
}
|
||||
|
||||
interface Upgrader {
|
||||
/**
|
||||
* Upgrades an outbound connection on `transport.dial`.
|
||||
* @param {MultiaddrConnection} maConn
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
upgradeOutbound(maConn: MultiaddrConnection): Promise<Connection>;
|
||||
|
||||
/**
|
||||
* Upgrades an inbound connection on transport listener.
|
||||
* @param {MultiaddrConnection} maConn
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
upgradeInbound(maConn: MultiaddrConnection): Promise<Connection>;
|
||||
}
|
||||
|
||||
type MultiaddrConnection = {
|
||||
connection: any;
|
||||
remoteAddr: Multiaddr;
|
||||
sink: Sink;
|
||||
source: () => AsyncIterator<Uint8Array, any, undefined>;
|
||||
}
|
||||
|
||||
type Sink = (source: Uint8Array) => Promise<Uint8Array>;
|
||||
type Connection = typeof import('../connection')
|
||||
|
||||
type Multiaddr = import('multiaddr');
|
||||
|
||||
declare namespace Transport {
|
||||
export { Upgrader, Listener, MultiaddrConnection };
|
||||
}
|
@ -13,7 +13,6 @@ describe('compliance tests', () => {
|
||||
/**
|
||||
* Test setup. `properties` allows the compliance test to override
|
||||
* certain values for testing.
|
||||
*
|
||||
* @param {*} properties
|
||||
*/
|
||||
async setup (properties) {
|
||||
|
@ -5,7 +5,7 @@ const { expect } = require('aegir/utils/chai')
|
||||
const sinon = require('sinon')
|
||||
|
||||
const PubsubBaseImpl = require('../../src/pubsub')
|
||||
const { SignaturePolicy } = require('../../src/pubsub/signature-policy')
|
||||
const { randomSeqno } = require('../../src/pubsub/utils')
|
||||
const {
|
||||
createPeerId,
|
||||
mockRegistrar
|
||||
@ -34,7 +34,9 @@ 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']
|
||||
}
|
||||
|
||||
@ -42,46 +44,27 @@ describe('pubsub base messages', () => {
|
||||
expect(pubsub.validate(signedMessage)).to.not.be.rejected()
|
||||
})
|
||||
|
||||
it('validate with StrictNoSign will reject a message with from, signature, key, seqno present', async () => {
|
||||
it('validate with strict signing off will validate a present signature', async () => {
|
||||
const message = {
|
||||
receivedFrom: peerId.id,
|
||||
from: peerId.id,
|
||||
data: 'hello',
|
||||
seqno: randomSeqno(),
|
||||
topicIDs: ['test-topic']
|
||||
}
|
||||
|
||||
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)
|
||||
sinon.stub(pubsub, 'strictSigning').value(false)
|
||||
|
||||
const signedMessage = await pubsub._buildMessage(message)
|
||||
expect(pubsub.validate(signedMessage)).to.not.be.rejected()
|
||||
})
|
||||
|
||||
it('validate with StrictSign requires a signature', async () => {
|
||||
it('validate with strict signing requires a signature', async () => {
|
||||
const message = {
|
||||
receivedFrom: peerId.id,
|
||||
from: peerId.id,
|
||||
data: 'hello',
|
||||
seqno: randomSeqno(),
|
||||
topicIDs: ['test-topic']
|
||||
}
|
||||
|
||||
|
@ -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,8 +30,6 @@ describe('topic validators', () => {
|
||||
pubsub = new PubsubImplementation(protocol, {
|
||||
peerId: peerId,
|
||||
registrar: mockRegistrar
|
||||
}, {
|
||||
globalSignaturePolicy: SignaturePolicy.StrictNoSign
|
||||
})
|
||||
|
||||
pubsub.start()
|
||||
@ -44,6 +42,8 @@ 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,7 +59,9 @@ describe('topic validators', () => {
|
||||
const validRpc = {
|
||||
subscriptions: [],
|
||||
msgs: [{
|
||||
from: peer.id.toBytes(),
|
||||
data: uint8ArrayFromString('a message'),
|
||||
seqno: utils.randomSeqno(),
|
||||
topicIDs: [filteredTopic]
|
||||
}]
|
||||
}
|
||||
@ -74,7 +76,9 @@ describe('topic validators', () => {
|
||||
const invalidRpc = {
|
||||
subscriptions: [],
|
||||
msgs: [{
|
||||
from: peer.id.toBytes(),
|
||||
data: uint8ArrayFromString('a different message'),
|
||||
seqno: utils.randomSeqno(),
|
||||
topicIDs: [filteredTopic]
|
||||
}]
|
||||
}
|
||||
@ -90,7 +94,9 @@ describe('topic validators', () => {
|
||||
const invalidRpc2 = {
|
||||
subscriptions: [],
|
||||
msgs: [{
|
||||
from: peer.id.toB58String(),
|
||||
data: uint8ArrayFromString('a different message'),
|
||||
seqno: utils.randomSeqno(),
|
||||
topicIDs: [filteredTopic]
|
||||
}]
|
||||
}
|
||||
|
Reference in New Issue
Block a user