mirror of
https://github.com/fluencelabs/js-libp2p
synced 2025-05-28 18:01:19 +00:00
chore: use new libp2p interface
This commit is contained in:
parent
28b9f8562c
commit
4b309ada54
@ -24,6 +24,7 @@ jobs:
|
||||
# Remove pull libs once ping is async
|
||||
- npx aegir dep-check -- -i pull-handshake -i pull-stream
|
||||
- npm run lint
|
||||
- npm run test:types
|
||||
|
||||
- stage: test
|
||||
name: chrome
|
||||
|
@ -63,7 +63,7 @@
|
||||
"events": "^3.1.0",
|
||||
"hashlru": "^2.3.0",
|
||||
"interface-datastore": "^2.0.0",
|
||||
"ipfs-utils": "^2.2.0",
|
||||
"ipfs-utils": "^5.0.1",
|
||||
"it-all": "^1.0.1",
|
||||
"it-buffer": "^0.1.2",
|
||||
"it-handshake": "^1.0.1",
|
||||
@ -71,7 +71,7 @@
|
||||
"it-pipe": "^1.1.0",
|
||||
"it-protocol-buffers": "^0.2.0",
|
||||
"libp2p-crypto": "^0.18.0",
|
||||
"libp2p-interfaces": "libp2p/js-libp2p-interfaces#chore/add-duplex-iterable-type-to-connection",
|
||||
"libp2p-interfaces": "libp2p/js-libp2p-interfaces#feat/add-types",
|
||||
"libp2p-utils": "^0.2.2",
|
||||
"mafmt": "^8.0.0",
|
||||
"merge-options": "^2.0.0",
|
||||
|
@ -90,6 +90,9 @@ class AutoRelay {
|
||||
// If protocol, check if can hop, store info in the metadataBook and listen on it
|
||||
try {
|
||||
const connection = this._connectionManager.get(peerId)
|
||||
if (!connection) {
|
||||
return
|
||||
}
|
||||
|
||||
// Do not hop on a relayed connection
|
||||
if (connection.remoteAddr.protoCodes().includes(CIRCUIT_PROTO_CODE)) {
|
||||
|
@ -21,7 +21,19 @@ const multicodec = require('./../multicodec')
|
||||
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
||||
*/
|
||||
|
||||
module.exports.handleHop = async function handleHop ({
|
||||
/**
|
||||
* @typedef {Object} HopRequest
|
||||
* @property {Connection} connection
|
||||
* @property {any} request
|
||||
* @property {any} streamHandler
|
||||
* @property {import('../transport')} circuit
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {HopRequest} options
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
async function handleHop ({
|
||||
connection,
|
||||
request,
|
||||
streamHandler,
|
||||
@ -56,6 +68,9 @@ module.exports.handleHop = async function handleHop ({
|
||||
}
|
||||
|
||||
// TODO: Handle being an active relay
|
||||
if (!destinationConnection) {
|
||||
return
|
||||
}
|
||||
|
||||
// Handle the incoming HOP request by performing a STOP request
|
||||
const stopRequest = {
|
||||
@ -68,8 +83,7 @@ module.exports.handleHop = async function handleHop ({
|
||||
try {
|
||||
destinationStream = await stop({
|
||||
connection: destinationConnection,
|
||||
request: stopRequest,
|
||||
circuit
|
||||
request: stopRequest
|
||||
})
|
||||
} catch (err) {
|
||||
return log.error(err)
|
||||
@ -96,10 +110,10 @@ module.exports.handleHop = async function handleHop ({
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {Connection} options.connection - Connection to the relay
|
||||
* @param {*} options.request
|
||||
* @param {CircuitPB} options.request
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
module.exports.hop = async function hop ({
|
||||
async function hop ({
|
||||
connection,
|
||||
request
|
||||
}) {
|
||||
@ -128,7 +142,7 @@ module.exports.hop = async function hop ({
|
||||
* @param {Connection} options.connection - Connection to the relay
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
module.exports.canHop = async function canHop ({
|
||||
async function canHop ({
|
||||
connection
|
||||
}) {
|
||||
// Create a new stream to the relay
|
||||
@ -155,10 +169,10 @@ module.exports.canHop = async function canHop ({
|
||||
* @param {Object} options
|
||||
* @param {Connection} options.connection
|
||||
* @param {StreamHandler} options.streamHandler
|
||||
* @param {Circuit} options.circuit
|
||||
* @param {import('../transport')} options.circuit
|
||||
* @private
|
||||
*/
|
||||
module.exports.handleCanHop = function handleCanHop ({
|
||||
function handleCanHop ({
|
||||
connection,
|
||||
streamHandler,
|
||||
circuit
|
||||
@ -170,3 +184,10 @@ module.exports.handleCanHop = function handleCanHop ({
|
||||
code: canHop ? CircuitPB.Status.SUCCESS : CircuitPB.Status.HOP_CANT_SPEAK_RELAY
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
handleHop,
|
||||
hop,
|
||||
canHop,
|
||||
handleCanHop
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ module.exports.handleStop = function handleStop ({
|
||||
* @private
|
||||
* @param {object} options
|
||||
* @param {Connection} options.connection
|
||||
* @param {*} options.request - The CircuitRelay protobuf request (unencoded)
|
||||
* @param {CircuitPB} options.request - The CircuitRelay protobuf request (unencoded)
|
||||
* @returns {Promise<*>} Resolves a duplex iterable
|
||||
*/
|
||||
module.exports.stop = async function stop ({
|
||||
|
@ -13,9 +13,10 @@ class StreamHandler {
|
||||
/**
|
||||
* Create a stream handler for connection
|
||||
*
|
||||
* @class
|
||||
* @param {object} options
|
||||
* @param {*} options.stream - A duplex iterable
|
||||
* @param {number} options.maxLength - max bytes length of message
|
||||
* @param {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} options.stream - A duplex iterable
|
||||
* @param {number} [options.maxLength = 4096] - max bytes length of message
|
||||
*/
|
||||
constructor ({ stream, maxLength = 4096 }) {
|
||||
this.stream = stream
|
||||
@ -28,7 +29,7 @@ class StreamHandler {
|
||||
* Read and decode message
|
||||
*
|
||||
* @async
|
||||
* @returns {Promise<void>}
|
||||
* @returns {Promise<CircuitPB>}
|
||||
*/
|
||||
async read () {
|
||||
const msg = await this.decoder.next()
|
||||
@ -50,6 +51,7 @@ class StreamHandler {
|
||||
*/
|
||||
write (msg) {
|
||||
log('write message type %s', msg.type)
|
||||
// @ts-ignore
|
||||
this.shake.write(lp.encode.single(CircuitPB.encode(msg)))
|
||||
}
|
||||
|
||||
|
@ -5,13 +5,14 @@ const { CircuitRelay } = require('../protocol')
|
||||
|
||||
/**
|
||||
* @typedef {import('./stream-handler')} StreamHandler
|
||||
* @typedef {import('../../types').CircuitStatus} CircuitStatus
|
||||
*/
|
||||
|
||||
/**
|
||||
* Write a response
|
||||
*
|
||||
* @param {StreamHandler} streamHandler
|
||||
* @param {CircuitRelay.Status} status
|
||||
* @param {CircuitStatus} status
|
||||
*/
|
||||
function writeResponse (streamHandler, status) {
|
||||
streamHandler.write({
|
||||
|
@ -5,6 +5,7 @@ const multiaddr = require('multiaddr')
|
||||
|
||||
/**
|
||||
* @typedef {import('multiaddr')} Multiaddr
|
||||
* @typedef {import('libp2p-interfaces/src/transport/types').Listener} Listener
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -12,26 +13,15 @@ const multiaddr = require('multiaddr')
|
||||
* @returns {Listener} a transport listener
|
||||
*/
|
||||
module.exports = (libp2p) => {
|
||||
const listener = new EventEmitter()
|
||||
const listeningAddrs = new Map()
|
||||
|
||||
// Remove listeningAddrs when a peer disconnects
|
||||
libp2p.connectionManager.on('peer:disconnect', (connection) => {
|
||||
const deleted = listeningAddrs.delete(connection.remotePeer.toB58String())
|
||||
|
||||
if (deleted) {
|
||||
// Announce listen addresses change
|
||||
listener.emit('close')
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Add swarm handler and listen for incoming connections
|
||||
*
|
||||
* @param {Multiaddr} addr
|
||||
* @returns {void}
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
listener.listen = async (addr) => {
|
||||
async function listen (addr) {
|
||||
const addrString = String(addr).split('/p2p-circuit').find(a => a !== '')
|
||||
|
||||
const relayConn = await libp2p.dial(multiaddr(addrString))
|
||||
@ -41,13 +31,6 @@ module.exports = (libp2p) => {
|
||||
listener.emit('listening')
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Remove the peers from our topology
|
||||
*
|
||||
* @returns {void}
|
||||
*/
|
||||
listener.close = () => {}
|
||||
|
||||
/**
|
||||
* Get fixed up multiaddrs
|
||||
*
|
||||
@ -64,7 +47,7 @@ module.exports = (libp2p) => {
|
||||
*
|
||||
* @returns {Multiaddr[]}
|
||||
*/
|
||||
listener.getAddrs = () => {
|
||||
function getAddrs () {
|
||||
const addrs = []
|
||||
for (const addr of listeningAddrs.values()) {
|
||||
addrs.push(addr)
|
||||
@ -72,5 +55,22 @@ module.exports = (libp2p) => {
|
||||
return addrs
|
||||
}
|
||||
|
||||
/** @type Listener */
|
||||
const listener = Object.assign(new EventEmitter(), {
|
||||
close: () => Promise.resolve(),
|
||||
listen,
|
||||
getAddrs
|
||||
})
|
||||
|
||||
// Remove listeningAddrs when a peer disconnects
|
||||
libp2p.connectionManager.on('peer:disconnect', (connection) => {
|
||||
const deleted = listeningAddrs.delete(connection.remotePeer.toB58String())
|
||||
|
||||
if (deleted) {
|
||||
// Announce listen addresses change
|
||||
listener.emit('close')
|
||||
}
|
||||
})
|
||||
|
||||
return listener
|
||||
}
|
||||
|
@ -1,5 +1,7 @@
|
||||
'use strict'
|
||||
const protobuf = require('protons')
|
||||
|
||||
/** @type {{CircuitRelay: import('../../types').CircuitMessageProto}} */
|
||||
module.exports = protobuf(`
|
||||
message CircuitRelay {
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
'use strict'
|
||||
|
||||
const debug = require('debug')
|
||||
const log = debug('libp2p:circuit')
|
||||
log.error = debug('libp2p:circuit:error')
|
||||
const log = Object.assign(debug('libp2p:circuit'), {
|
||||
error: debug('libp2p:circuit:err')
|
||||
})
|
||||
|
||||
const mafmt = require('mafmt')
|
||||
const multiaddr = require('multiaddr')
|
||||
@ -76,8 +77,7 @@ class Circuit {
|
||||
virtualConnection = await handleStop({
|
||||
connection,
|
||||
request,
|
||||
streamHandler,
|
||||
circuit
|
||||
streamHandler
|
||||
})
|
||||
break
|
||||
}
|
||||
@ -94,7 +94,7 @@ class Circuit {
|
||||
remoteAddr,
|
||||
localAddr
|
||||
})
|
||||
const type = CircuitPB.Type === CircuitPB.Type.HOP ? 'relay' : 'inbound'
|
||||
const type = request.Type === CircuitPB.Type.HOP ? 'relay' : 'inbound'
|
||||
log('new %s connection %s', type, maConn.remoteAddr)
|
||||
|
||||
const conn = await this._upgrader.upgradeInbound(maConn)
|
||||
@ -109,7 +109,7 @@ class Circuit {
|
||||
* @param {Multiaddr} ma - the multiaddr of the peer to dial
|
||||
* @param {Object} options - dial options
|
||||
* @param {AbortSignal} [options.signal] - An optional abort signal
|
||||
* @returns {Connection} - the connection
|
||||
* @returns {Promise<Connection>} - the connection
|
||||
*/
|
||||
async dial (ma, options) {
|
||||
// Check the multiaddr to see if it contains a relay and a destination peer
|
||||
@ -129,6 +129,7 @@ class Circuit {
|
||||
try {
|
||||
const virtualConnection = await hop({
|
||||
connection: relayConnection,
|
||||
// @ts-ignore
|
||||
circuit: this,
|
||||
request: {
|
||||
type: CircuitPB.Type.HOP,
|
||||
@ -164,7 +165,7 @@ class Circuit {
|
||||
*
|
||||
* @param {any} options
|
||||
* @param {Function} handler
|
||||
* @returns {listener}
|
||||
* @returns {import('libp2p-interfaces/src/transport/types').Listener}
|
||||
*/
|
||||
createListener (options, handler) {
|
||||
if (typeof options === 'function') {
|
||||
@ -175,7 +176,7 @@ class Circuit {
|
||||
// Called on successful HOP and STOP requests
|
||||
this.handler = handler
|
||||
|
||||
return createListener(this._libp2p, options)
|
||||
return createListener(this._libp2p)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3,6 +3,8 @@
|
||||
const CID = require('cids')
|
||||
const multihashing = require('multihashing-async')
|
||||
|
||||
const TextEncoder = require('ipfs-utils/src/text-encoder')
|
||||
|
||||
/**
|
||||
* Convert a namespace string into a cid.
|
||||
*
|
||||
|
@ -175,10 +175,7 @@ class ConnectionManager extends EventEmitter {
|
||||
if (value < 0 || value > 1) {
|
||||
throw new Error('value should be a number between 0 and 1')
|
||||
}
|
||||
if (peerId.toB58String) {
|
||||
peerId = peerId.toB58String()
|
||||
}
|
||||
this._peerValues.set(peerId, value)
|
||||
this._peerValues.set(peerId.toB58String(), value)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
/* global document */
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,7 @@ const pAny = require('p-any')
|
||||
* @property {function(Multiaddr):Promise<Connection>} dialAction
|
||||
* @property {Dialer} dialer
|
||||
*/
|
||||
|
||||
class DialRequest {
|
||||
/**
|
||||
* Manages running the `dialAction` on multiple provided `addrs` in parallel
|
||||
@ -54,6 +55,7 @@ class DialRequest {
|
||||
|
||||
const tokenHolder = new FIFO()
|
||||
tokens.forEach(token => tokenHolder.push(token))
|
||||
// @ts-ignore
|
||||
const dialAbortControllers = this.addrs.map(() => new AbortController())
|
||||
let completedDials = 0
|
||||
|
||||
@ -63,6 +65,7 @@ class DialRequest {
|
||||
let conn
|
||||
try {
|
||||
const signal = dialAbortControllers[i].signal
|
||||
// @ts-ignore
|
||||
conn = await this.dialAction(addr, { ...options, signal: anySignal([signal, options.signal]) })
|
||||
// Remove the successful AbortController so it is not aborted
|
||||
dialAbortControllers.splice(i, 1)
|
||||
@ -85,4 +88,4 @@ class DialRequest {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.DialRequest = DialRequest
|
||||
module.exports = DialRequest
|
||||
|
@ -9,7 +9,7 @@ const multiaddr = require('multiaddr')
|
||||
const TimeoutController = require('timeout-abort-controller')
|
||||
const anySignal = require('any-signal')
|
||||
|
||||
const { DialRequest } = require('./dial-request')
|
||||
const DialRequest = require('./dial-request')
|
||||
const { publicAddressesFirst } = require('libp2p-utils/src/address-sort')
|
||||
const getPeer = require('../get-peer')
|
||||
|
||||
@ -27,7 +27,6 @@ const {
|
||||
* @typedef {import('../peer-store')} PeerStore
|
||||
* @typedef {import('../peer-store/address-book').Address} Address
|
||||
* @typedef {import('../transport-manager')} TransportManager
|
||||
* @typedef {import('./dial-request')} DialRequest
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -241,12 +240,13 @@ class Dialer {
|
||||
return this._resolve(nm)
|
||||
}))
|
||||
|
||||
return recursiveMultiaddrs.flat().reduce((array, newM) => {
|
||||
if (!array.find(m => m.equals(newM))) {
|
||||
array.push(newM)
|
||||
}
|
||||
return array
|
||||
}, []) // Unique addresses
|
||||
return recursiveMultiaddrs.flat()
|
||||
.reduce((/** @type {Multiaddr[]} */ array, /** @type {Multiaddr} */ newM) => {
|
||||
if (!array.find(m => m.equals(newM))) {
|
||||
array.push(newM)
|
||||
}
|
||||
return array
|
||||
}, []) // Unique addresses
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
'use strict'
|
||||
|
||||
// @ts-ignore
|
||||
const libp2pVersion = require('../../package.json').version
|
||||
|
||||
module.exports.PROTOCOL_VERSION = 'ipfs/0.1.0'
|
||||
|
@ -31,7 +31,7 @@ const { codes } = require('../errors')
|
||||
|
||||
/**
|
||||
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
||||
* @typedef {import('libp2p-interfaces/src/connection/connection').DuplexIterableStream} DuplexIterableStream
|
||||
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
|
||||
*/
|
||||
|
||||
class IdentifyService {
|
||||
@ -200,9 +200,9 @@ class IdentifyService {
|
||||
* A handler to register with Libp2p to process identify messages.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {string} options.protocol
|
||||
* @param {DuplexIterableStream} options.stream
|
||||
* @param {Connection} options.connection
|
||||
* @param {MuxedStream} options.stream
|
||||
* @param {string} options.protocol
|
||||
* @returns {Promise<void>|undefined}
|
||||
*/
|
||||
handleMessage ({ connection, stream, protocol }) {
|
||||
@ -222,7 +222,7 @@ class IdentifyService {
|
||||
*
|
||||
* @private
|
||||
* @param {Object} options
|
||||
* @param {DuplexIterableStream} options.stream
|
||||
* @param {MuxedStream} options.stream
|
||||
* @param {Connection} options.connection
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
@ -262,7 +262,7 @@ class IdentifyService {
|
||||
*
|
||||
* @private
|
||||
* @param {object} options
|
||||
* @param {DuplexIterableStream} options.stream
|
||||
* @param {MuxedStream} options.stream
|
||||
* @param {Connection} options.connection
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
@ -323,14 +323,17 @@ class IdentifyService {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.IdentifyService = IdentifyService
|
||||
/**
|
||||
* The protocols the IdentifyService supports
|
||||
*
|
||||
* @property multicodecs
|
||||
*/
|
||||
module.exports.multicodecs = {
|
||||
const multicodecs = {
|
||||
IDENTIFY: MULTICODEC_IDENTIFY,
|
||||
IDENTIFY_PUSH: MULTICODEC_IDENTIFY_PUSH
|
||||
}
|
||||
module.exports.Message = Message
|
||||
|
||||
IdentifyService.multicodecs = multicodecs
|
||||
IdentifyService.Messsage = Message
|
||||
|
||||
module.exports = IdentifyService
|
||||
|
21
src/index.js
21
src/index.js
@ -30,10 +30,8 @@ const PubsubAdapter = require('./pubsub-adapter')
|
||||
const PersistentPeerStore = require('./peer-store/persistent')
|
||||
const Registrar = require('./registrar')
|
||||
const ping = require('./ping')
|
||||
const {
|
||||
IdentifyService,
|
||||
multicodecs: IDENTIFY_PROTOCOLS
|
||||
} = require('./identify')
|
||||
const IdentifyService = require('./identify')
|
||||
const IDENTIFY_PROTOCOLS = IdentifyService.multicodecs
|
||||
|
||||
/**
|
||||
* @typedef {import('multiaddr')} Multiaddr
|
||||
@ -193,6 +191,7 @@ class Libp2p extends EventEmitter {
|
||||
})
|
||||
|
||||
if (this._config.relay.enabled) {
|
||||
// @ts-ignore
|
||||
this.transportManager.add(Circuit.prototype[Symbol.toStringTag], Circuit)
|
||||
this.relay = new Relay(this)
|
||||
}
|
||||
@ -206,6 +205,7 @@ class Libp2p extends EventEmitter {
|
||||
|
||||
// Add the identify service since we can multiplex
|
||||
this.identifyService = new IdentifyService({ libp2p: this })
|
||||
// @ts-ignore
|
||||
this.handle(Object.values(IDENTIFY_PROTOCOLS), this.identifyService.handleMessage)
|
||||
}
|
||||
|
||||
@ -254,13 +254,16 @@ class Libp2p extends EventEmitter {
|
||||
*
|
||||
* @param {string} eventName
|
||||
* @param {...any} args
|
||||
* @returns {void}
|
||||
* @returns {boolean}
|
||||
*/
|
||||
emit (eventName, ...args) {
|
||||
// TODO: do we still need this?
|
||||
// @ts-ignore
|
||||
if (eventName === 'error' && !this._events.error) {
|
||||
log.error(...args)
|
||||
log.error(args)
|
||||
return false
|
||||
} else {
|
||||
super.emit(eventName, ...args)
|
||||
return super.emit(eventName, ...args)
|
||||
}
|
||||
}
|
||||
|
||||
@ -463,7 +466,7 @@ class Libp2p extends EventEmitter {
|
||||
* Registers the `handler` for each protocol
|
||||
*
|
||||
* @param {string[]|string} protocols
|
||||
* @param {function({ connection:*, stream:*, protocol:string })} handler
|
||||
* @param {({ connection: Connection, stream: any, protocol: string }) => void} handler
|
||||
*/
|
||||
handle (protocols, handler) {
|
||||
protocols = Array.isArray(protocols) ? protocols : [protocols]
|
||||
@ -629,7 +632,9 @@ class Libp2p extends EventEmitter {
|
||||
|
||||
// Transport modules with discovery
|
||||
for (const Transport of this.transportManager.getTransports()) {
|
||||
// @ts-ignore
|
||||
if (Transport.discovery) {
|
||||
// @ts-ignore
|
||||
setupService(Transport.discovery)
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
'use strict'
|
||||
|
||||
require('node-forge/lib/pkcs7')
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
/* eslint max-nested-callbacks: ["error", 5] */
|
||||
'use strict'
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
// @ts-nocheck
|
||||
'use strict'
|
||||
|
||||
require('node-forge/lib/x509')
|
||||
|
@ -1,7 +1,8 @@
|
||||
// @ts-nocheck
|
||||
'use strict'
|
||||
|
||||
const mergeOptions = require('merge-options')
|
||||
const pipe = require('it-pipe')
|
||||
const { pipe } = require('it-pipe')
|
||||
const { tap } = require('streaming-iterables')
|
||||
const oldPeerLRU = require('./old-peers')
|
||||
const { METRICS: defaultOptions } = require('../constants')
|
||||
@ -19,11 +20,12 @@ const directionToEvent = {
|
||||
|
||||
/**
|
||||
* @typedef {import('peer-id')} PeerId
|
||||
* @typedef {import('libp2p-interfaces/src/transport/types').MultiaddrConnection} MultiaddrConnection
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef MetricsProperties
|
||||
* @property {ConnectionManager} connectionManager
|
||||
* @property {import('../connection-manager')} connectionManager
|
||||
*
|
||||
* @typedef MetricsOptions
|
||||
* @property {number} [computeThrottleMaxQueueSize = defaultOptions.computeThrottleMaxQueueSize]
|
||||
@ -216,10 +218,10 @@ class Metrics {
|
||||
* with the placeholder string returned from here, and the known `PeerId`.
|
||||
*
|
||||
* @param {Object} options
|
||||
* @param {{ sink: function(*), source: function() }} options.stream - A duplex iterable stream
|
||||
* @param {MultiaddrConnection} options.stream - A duplex iterable stream
|
||||
* @param {PeerId} [options.remotePeer] - The id of the remote peer that's connected
|
||||
* @param {string} [options.protocol] - The protocol the stream is running
|
||||
* @returns {string} The peerId string or placeholder string
|
||||
* @returns {MultiaddrConnection} The peerId string or placeholder string
|
||||
*/
|
||||
trackStream ({ stream, remotePeer, protocol }) {
|
||||
const metrics = this
|
||||
|
@ -6,9 +6,10 @@ const LRU = require('hashlru')
|
||||
* Creates and returns a Least Recently Used Cache
|
||||
*
|
||||
* @param {number} maxSize
|
||||
* @returns {LRUCache}
|
||||
* @returns {any}
|
||||
*/
|
||||
module.exports = (maxSize) => {
|
||||
// @ts-ignore
|
||||
const patched = LRU(maxSize)
|
||||
patched.delete = patched.remove
|
||||
return patched
|
||||
|
@ -1,17 +1,19 @@
|
||||
// @ts-nocheck
|
||||
'use strict'
|
||||
|
||||
const EventEmitter = require('events')
|
||||
const { EventEmitter } = require('events')
|
||||
const Big = require('bignumber.js')
|
||||
const MovingAverage = require('moving-average')
|
||||
const retimer = require('retimer')
|
||||
|
||||
/**
|
||||
* A queue based manager for stat processing
|
||||
*
|
||||
* @param {string[]} initialCounters
|
||||
* @param {any} options
|
||||
*/
|
||||
class Stats extends EventEmitter {
|
||||
/**
|
||||
* A queue based manager for stat processing
|
||||
*
|
||||
* @class
|
||||
* @param {string[]} initialCounters
|
||||
* @param {any} options
|
||||
*/
|
||||
constructor (initialCounters, options) {
|
||||
super()
|
||||
|
||||
@ -21,6 +23,8 @@ class Stats extends EventEmitter {
|
||||
|
||||
this._frequencyLastTime = Date.now()
|
||||
this._frequencyAccumulators = {}
|
||||
|
||||
/** @type {{}} */
|
||||
this._movingAverages = {}
|
||||
|
||||
this._update = this._update.bind(this)
|
||||
@ -68,7 +72,7 @@ class Stats extends EventEmitter {
|
||||
/**
|
||||
* Returns a clone of the current stats.
|
||||
*
|
||||
* @returns {Map<string, Stat>}
|
||||
* @returns {Object}
|
||||
*/
|
||||
get snapshot () {
|
||||
return Object.assign({}, this._stats)
|
||||
@ -77,7 +81,7 @@ class Stats extends EventEmitter {
|
||||
/**
|
||||
* Returns a clone of the internal movingAverages
|
||||
*
|
||||
* @returns {MovingAverage[]}
|
||||
* @returns {MovingAverage}
|
||||
*/
|
||||
get movingAverages () {
|
||||
return Object.assign({}, this._movingAverages)
|
||||
@ -238,7 +242,7 @@ class Stats extends EventEmitter {
|
||||
const inc = op[1]
|
||||
|
||||
if (typeof inc !== 'number') {
|
||||
throw new Error('invalid increment number:', inc)
|
||||
throw new Error(`invalid increment number: ${inc}`)
|
||||
}
|
||||
|
||||
let n
|
||||
|
@ -20,7 +20,7 @@ const {
|
||||
class PeerRouting {
|
||||
/**
|
||||
* @class
|
||||
* @param {Libp2p} libp2p
|
||||
* @param {import('./')} libp2p
|
||||
*/
|
||||
constructor (libp2p) {
|
||||
this._peerId = libp2p.peerId
|
||||
|
@ -124,6 +124,7 @@ class AddressBook extends Book {
|
||||
|
||||
// Replace unsigned addresses by the new ones from the record
|
||||
// TODO: Once we have ttls for the addresses, we should merge these in.
|
||||
// @ts-ignore
|
||||
this._setData(peerId, {
|
||||
addresses,
|
||||
record: {
|
||||
@ -188,22 +189,22 @@ class AddressBook extends Book {
|
||||
}
|
||||
|
||||
const addresses = this._toAddresses(multiaddrs)
|
||||
const id = peerId.toB58String()
|
||||
const entry = this.data.get(id) || {}
|
||||
const rec = entry.addresses
|
||||
|
||||
// Not replace multiaddrs
|
||||
if (!addresses.length) {
|
||||
return this
|
||||
}
|
||||
|
||||
const id = peerId.toB58String()
|
||||
const entry = this.data.get(id)
|
||||
|
||||
// Already knows the peer
|
||||
if (rec && rec.length === addresses.length) {
|
||||
const intersection = rec.filter((addr) => addresses.some((newAddr) => addr.multiaddr.equals(newAddr.multiaddr)))
|
||||
if (entry && entry.addresses && entry.addresses.length === addresses.length) {
|
||||
const intersection = entry.addresses.filter((addr) => addresses.some((newAddr) => addr.multiaddr.equals(newAddr.multiaddr)))
|
||||
|
||||
// Are new addresses equal to the old ones?
|
||||
// If yes, no changes needed!
|
||||
if (intersection.length === rec.length) {
|
||||
if (intersection.length === entry.addresses.length) {
|
||||
log(`the addresses provided to store are equal to the already stored for ${id}`)
|
||||
return this
|
||||
}
|
||||
@ -211,12 +212,12 @@ class AddressBook extends Book {
|
||||
|
||||
this._setData(peerId, {
|
||||
addresses,
|
||||
record: entry.record
|
||||
record: entry && entry.record
|
||||
})
|
||||
log(`stored provided multiaddrs for ${id}`)
|
||||
|
||||
// Notify the existance of a new peer
|
||||
if (!rec) {
|
||||
if (!(entry && entry.addresses)) {
|
||||
this._ps.emit('peer', peerId)
|
||||
}
|
||||
|
||||
@ -240,32 +241,33 @@ class AddressBook extends Book {
|
||||
const addresses = this._toAddresses(multiaddrs)
|
||||
const id = peerId.toB58String()
|
||||
|
||||
const entry = this.data.get(id) || {}
|
||||
const rec = entry.addresses || []
|
||||
const entry = this.data.get(id)
|
||||
|
||||
// Add recorded uniquely to the new array (Union)
|
||||
rec.forEach((addr) => {
|
||||
if (!addresses.find(r => r.multiaddr.equals(addr.multiaddr))) {
|
||||
addresses.push(addr)
|
||||
if (entry && entry.addresses) {
|
||||
// Add recorded uniquely to the new array (Union)
|
||||
entry.addresses.forEach((addr) => {
|
||||
if (!addresses.find(r => r.multiaddr.equals(addr.multiaddr))) {
|
||||
addresses.push(addr)
|
||||
}
|
||||
})
|
||||
|
||||
// If the recorded length is equal to the new after the unique union
|
||||
// The content is the same, no need to update.
|
||||
if (entry.addresses.length === addresses.length) {
|
||||
log(`the addresses provided to store are already stored for ${id}`)
|
||||
return this
|
||||
}
|
||||
})
|
||||
|
||||
// If the recorded length is equal to the new after the unique union
|
||||
// The content is the same, no need to update.
|
||||
if (rec && rec.length === addresses.length) {
|
||||
log(`the addresses provided to store are already stored for ${id}`)
|
||||
return this
|
||||
}
|
||||
|
||||
this._setData(peerId, {
|
||||
addresses,
|
||||
record: entry.record
|
||||
record: entry && entry.record
|
||||
})
|
||||
|
||||
log(`added provided multiaddrs for ${id}`)
|
||||
|
||||
// Notify the existance of a new peer
|
||||
if (!entry.addresses) {
|
||||
if (!(entry && entry.addresses)) {
|
||||
this._ps.emit('peer', peerId)
|
||||
}
|
||||
|
||||
|
@ -54,7 +54,7 @@ class Book {
|
||||
/**
|
||||
* Set data into the datastructure, persistence and emit it using the provided transformers.
|
||||
*
|
||||
* @private
|
||||
* @protected
|
||||
* @param {PeerId} peerId - peerId of the data to store
|
||||
* @param {T} data - data to store.
|
||||
* @param {Object} [options] - storing options.
|
||||
@ -74,9 +74,9 @@ class Book {
|
||||
/**
|
||||
* Emit data.
|
||||
*
|
||||
* @private
|
||||
* @protected
|
||||
* @param {PeerId} peerId
|
||||
* @param {T} data
|
||||
* @param {any} [data]
|
||||
*/
|
||||
_emit (peerId, data) {
|
||||
this._ps.emit(this.eventName, {
|
||||
|
@ -35,7 +35,7 @@ class PeerStore extends EventEmitter {
|
||||
* @property {PeerId} id peer's peer-id instance.
|
||||
* @property {Address[]} addresses peer's addresses containing its multiaddrs and metadata.
|
||||
* @property {string[]} protocols peer's supported protocols.
|
||||
* @property {Map<string, Uint8Array>} metadata peer's metadata map.
|
||||
* @property {Map<string, Uint8Array>|undefined} metadata peer's metadata map.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -49,7 +49,7 @@ class KeyBook extends Book {
|
||||
*
|
||||
* @override
|
||||
* @param {PeerId} peerId
|
||||
* @param {RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey} publicKey
|
||||
* @param {any} publicKey
|
||||
* @returns {KeyBook}
|
||||
*/
|
||||
set (peerId, publicKey) {
|
||||
@ -79,7 +79,7 @@ class KeyBook extends Book {
|
||||
*
|
||||
* @override
|
||||
* @param {PeerId} peerId
|
||||
* @returns {RsaPublicKey|Ed25519PublicKey|Secp256k1PublicKey}
|
||||
* @returns {any}
|
||||
*/
|
||||
get (peerId) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
|
@ -60,6 +60,7 @@ class MetadataBook extends Book {
|
||||
* @param {Uint8Array} value - metadata value
|
||||
* @returns {MetadataBook}
|
||||
*/
|
||||
// @ts-ignore
|
||||
set (peerId, key, value) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
log.error('peerId must be an instance of peer-id to store data')
|
||||
@ -102,8 +103,9 @@ class MetadataBook extends Book {
|
||||
* Get the known data of a provided peer.
|
||||
*
|
||||
* @param {PeerId} peerId
|
||||
* @returns {Map<string, Uint8Array>}
|
||||
* @returns {Map<string, Uint8Array>|undefined}
|
||||
*/
|
||||
// @ts-ignore
|
||||
get (peerId) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
throw errcode(new Error('peerId must be an instance of peer-id'), ERR_INVALID_PARAMETERS)
|
||||
@ -117,7 +119,7 @@ class MetadataBook extends Book {
|
||||
*
|
||||
* @param {PeerId} peerId
|
||||
* @param {string} key
|
||||
* @returns {Uint8Array}
|
||||
* @returns {Uint8Array | undefined}
|
||||
*/
|
||||
getValue (peerId, key) {
|
||||
if (!PeerId.isPeerId(peerId)) {
|
||||
|
@ -24,7 +24,7 @@ const Protocols = require('./pb/proto-book.proto')
|
||||
/**
|
||||
* @typedef {Object} PersistentPeerStoreProperties
|
||||
* @property {PeerId} peerId
|
||||
* @property {Datastore} datastore
|
||||
* @property {any} datastore
|
||||
*
|
||||
* @typedef {Object} PersistentPeerStoreOptions
|
||||
* @property {number} [threshold = 5] - Number of dirty peers allowed before commit data.
|
||||
|
@ -21,8 +21,7 @@ const handshake = require('it-handshake')
|
||||
const { NONCE_LENGTH } = require('./key-generator')
|
||||
|
||||
/**
|
||||
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
||||
* @typedef {import('libp2p-interfaces/src/connection/connection').DuplexIterableStream} DuplexIterableStream
|
||||
* @typedef {import('libp2p-interfaces/src/transport/types').MultiaddrConnection} MultiaddrConnection
|
||||
*/
|
||||
|
||||
class Protector {
|
||||
@ -44,8 +43,8 @@ class Protector {
|
||||
* between its two peers from the PSK the Protector instance was
|
||||
* created with.
|
||||
*
|
||||
* @param {Connection} connection - The connection to protect
|
||||
* @returns {Promise<DuplexIterableStream>} A protected duplex iterable
|
||||
* @param {MultiaddrConnection} connection - The connection to protect
|
||||
* @returns {Promise<MultiaddrConnection>} A protected duplex iterable
|
||||
*/
|
||||
async protect (connection) {
|
||||
if (!connection) {
|
||||
|
@ -6,42 +6,49 @@
|
||||
*/
|
||||
|
||||
// Pubsub adapter to keep API with handlers while not removed.
|
||||
module.exports = (PubsubRouter, libp2p, options) => {
|
||||
class Pubsub extends PubsubRouter {
|
||||
/**
|
||||
* Subscribes to a given topic.
|
||||
*
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @param {(msg: InMessage) => void} [handler]
|
||||
* @returns {void}
|
||||
*/
|
||||
subscribe (topic, handler) {
|
||||
// Bind provided handler
|
||||
handler && this.on(topic, handler)
|
||||
super.subscribe(topic)
|
||||
function pubsubAdapter (PubsubRouter, libp2p, options) {
|
||||
const pubsub = new PubsubRouter(libp2p, options)
|
||||
pubsub._subscribeAdapter = pubsub.subscribe
|
||||
pubsub._unsubscribeAdapter = pubsub.unsubscribe
|
||||
|
||||
/**
|
||||
* Subscribes to a given topic.
|
||||
*
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @param {(msg: InMessage) => void} [handler]
|
||||
* @returns {void}
|
||||
*/
|
||||
function subscribe (topic, handler) {
|
||||
// Bind provided handler
|
||||
handler && pubsub.on(topic, handler)
|
||||
pubsub._subscribeAdapter(topic)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from the given topic.
|
||||
*
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @param {(msg: InMessage) => void} [handler]
|
||||
* @returns {void}
|
||||
*/
|
||||
function unsubscribe (topic, handler) {
|
||||
if (!handler) {
|
||||
pubsub.removeAllListeners(topic)
|
||||
} else {
|
||||
pubsub.removeListener(topic, handler)
|
||||
}
|
||||
|
||||
/**
|
||||
* Unsubscribe from the given topic.
|
||||
*
|
||||
* @override
|
||||
* @param {string} topic
|
||||
* @param {(msg: InMessage) => void} [handler]
|
||||
* @returns {void}
|
||||
*/
|
||||
unsubscribe (topic, handler) {
|
||||
if (!handler) {
|
||||
this.removeAllListeners(topic)
|
||||
} else {
|
||||
this.removeListener(topic, handler)
|
||||
}
|
||||
|
||||
if (this.listenerCount(topic) === 0) {
|
||||
super.unsubscribe(topic)
|
||||
}
|
||||
if (pubsub.listenerCount(topic) === 0) {
|
||||
pubsub._unsubscribeAdapter(topic)
|
||||
}
|
||||
}
|
||||
|
||||
return new Pubsub(libp2p, options)
|
||||
pubsub.subscribe = subscribe
|
||||
pubsub.unsubscribe = unsubscribe
|
||||
|
||||
return pubsub
|
||||
}
|
||||
|
||||
module.exports = pubsubAdapter
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
const protons = require('protons')
|
||||
|
||||
const message = `
|
||||
/** @type {{Envelope: import('../../types').MessageProto}} */
|
||||
module.exports = protons(`
|
||||
message Envelope {
|
||||
// public_key is the public key of the keypair the enclosed payload was
|
||||
// signed with.
|
||||
@ -20,6 +21,4 @@ message Envelope {
|
||||
// additional security.
|
||||
bytes signature = 5;
|
||||
}
|
||||
`
|
||||
|
||||
module.exports = protons(message).Envelope
|
||||
`)
|
||||
|
@ -49,7 +49,7 @@ class Envelope {
|
||||
|
||||
const publicKey = cryptoKeys.marshalPublicKey(this.peerId.pubKey)
|
||||
|
||||
this._marshal = Protobuf.encode({
|
||||
this._marshal = Protobuf.Envelope.encode({
|
||||
public_key: publicKey,
|
||||
payload_type: this.payloadType,
|
||||
payload: this.payload,
|
||||
@ -102,14 +102,14 @@ const formatSignaturePayload = (domain, payloadType, payload) => {
|
||||
// - The length of the payload field in bytes
|
||||
// - The value of the payload field
|
||||
|
||||
domain = uint8arraysFromString(domain)
|
||||
const domainLength = varint.encode(domain.byteLength)
|
||||
const domainUint8Array = uint8arraysFromString(domain)
|
||||
const domainLength = varint.encode(domainUint8Array.byteLength)
|
||||
const payloadTypeLength = varint.encode(payloadType.length)
|
||||
const payloadLength = varint.encode(payload.length)
|
||||
|
||||
return uint8arraysConcat([
|
||||
new Uint8Array(domainLength),
|
||||
domain,
|
||||
domainUint8Array,
|
||||
new Uint8Array(payloadTypeLength),
|
||||
payloadType,
|
||||
new Uint8Array(payloadLength),
|
||||
@ -124,7 +124,7 @@ const formatSignaturePayload = (domain, payloadType, payload) => {
|
||||
* @returns {Promise<Envelope>}
|
||||
*/
|
||||
Envelope.createFromProtobuf = async (data) => {
|
||||
const envelopeData = Protobuf.decode(data)
|
||||
const envelopeData = Protobuf.Envelope.decode(data)
|
||||
const peerId = await PeerId.createFromPubKey(envelopeData.public_key)
|
||||
|
||||
return new Envelope({
|
||||
|
@ -51,7 +51,7 @@ class PeerRecord extends Record {
|
||||
return this._marshal
|
||||
}
|
||||
|
||||
this._marshal = Protobuf.encode({
|
||||
this._marshal = Protobuf.PeerRecord.encode({
|
||||
peer_id: this.peerId.toBytes(),
|
||||
seq: this.seqNumber,
|
||||
addresses: this.multiaddrs.map((m) => ({
|
||||
@ -65,7 +65,7 @@ class PeerRecord extends Record {
|
||||
/**
|
||||
* Returns true if `this` record equals the `other`.
|
||||
*
|
||||
* @param {Record} other
|
||||
* @param {PeerRecord} other
|
||||
* @returns {boolean}
|
||||
*/
|
||||
equals (other) {
|
||||
@ -96,7 +96,7 @@ class PeerRecord extends Record {
|
||||
*/
|
||||
PeerRecord.createFromProtobuf = (buf) => {
|
||||
// Decode
|
||||
const peerRecord = Protobuf.decode(buf)
|
||||
const peerRecord = Protobuf.PeerRecord.decode(buf)
|
||||
|
||||
const peerId = PeerId.createFromBytes(peerRecord.peer_id)
|
||||
const multiaddrs = (peerRecord.addresses || []).map((a) => multiaddr(a.multiaddr))
|
||||
|
@ -7,7 +7,8 @@ const protons = require('protons')
|
||||
// is expected to expand to include other information in the future.
|
||||
// PeerRecords are designed to be serialized to bytes and placed inside of
|
||||
// SignedEnvelopes before sharing with other peers.
|
||||
const message = `
|
||||
/** @type {{PeerRecord: import('../../types').MessageProto}} */
|
||||
module.exports = protons(`
|
||||
message PeerRecord {
|
||||
// AddressInfo is a wrapper around a binary multiaddr. It is defined as a
|
||||
// separate message to allow us to add per-address metadata in the future.
|
||||
@ -24,6 +25,4 @@ message PeerRecord {
|
||||
// addresses is a list of public listen addresses for the peer.
|
||||
repeated AddressInfo addresses = 3;
|
||||
}
|
||||
`
|
||||
|
||||
module.exports = protons(message).PeerRecord
|
||||
`)
|
||||
|
@ -60,7 +60,7 @@ class Registrar {
|
||||
* Get a connection with a peer.
|
||||
*
|
||||
* @param {PeerId} peerId
|
||||
* @returns {Connection}
|
||||
* @returns {Connection | null}
|
||||
*/
|
||||
getConnection (peerId) {
|
||||
return this.connectionManager.get(peerId)
|
||||
|
@ -14,6 +14,7 @@ const { updateSelfPeerRecord } = require('./record/utils')
|
||||
/**
|
||||
* @typedef {import('multiaddr')} Multiaddr
|
||||
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
||||
* @typedef {import('libp2p-interfaces/src/transport/types').Transport} Transport
|
||||
*
|
||||
* @typedef {Object} TransportManagerProperties
|
||||
* @property {import('./')} libp2p
|
||||
@ -53,6 +54,7 @@ class TransportManager {
|
||||
throw errCode(new Error('There is already a transport with this key'), codes.ERR_DUPLICATE_TRANSPORT)
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const transport = new Transport({
|
||||
...transportOptions,
|
||||
libp2p: this.libp2p,
|
||||
|
65
src/types.ts
65
src/types.ts
@ -16,3 +16,68 @@ export type MessageExchange = {
|
||||
id: Uint8Array
|
||||
pubKey: MessagePublicKey
|
||||
}
|
||||
|
||||
// Protobufs
|
||||
export type MessageProto = {
|
||||
encode(value: any): Uint8Array
|
||||
decode(bytes: Uint8Array): any
|
||||
}
|
||||
|
||||
export type SUCCESS = 100;
|
||||
export type HOP_SRC_ADDR_TOO_LONG = 220;
|
||||
export type HOP_DST_ADDR_TOO_LONG = 221;
|
||||
export type HOP_SRC_MULTIADDR_INVALID = 250;
|
||||
export type HOP_DST_MULTIADDR_INVALID = 251;
|
||||
export type HOP_NO_CONN_TO_DST = 260;
|
||||
export type HOP_CANT_DIAL_DST = 261;
|
||||
export type HOP_CANT_OPEN_DST_STREAM = 262;
|
||||
export type HOP_CANT_SPEAK_RELAY = 270;
|
||||
export type HOP_CANT_RELAY_TO_SELF = 280;
|
||||
export type STOP_SRC_ADDR_TOO_LONG = 320;
|
||||
export type STOP_DST_ADDR_TOO_LONG = 321;
|
||||
export type STOP_SRC_MULTIADDR_INVALID = 350;
|
||||
export type STOP_DST_MULTIADDR_INVALID = 351;
|
||||
export type STOP_RELAY_REFUSED = 390;
|
||||
export type MALFORMED_MESSAGE = 400;
|
||||
|
||||
export type CircuitStatus = SUCCESS | HOP_SRC_ADDR_TOO_LONG | HOP_DST_ADDR_TOO_LONG
|
||||
| HOP_SRC_MULTIADDR_INVALID | HOP_DST_MULTIADDR_INVALID | HOP_NO_CONN_TO_DST
|
||||
| HOP_CANT_DIAL_DST | HOP_CANT_OPEN_DST_STREAM | HOP_CANT_SPEAK_RELAY | HOP_CANT_RELAY_TO_SELF
|
||||
| STOP_SRC_ADDR_TOO_LONG | STOP_DST_ADDR_TOO_LONG | STOP_SRC_MULTIADDR_INVALID
|
||||
| STOP_DST_MULTIADDR_INVALID | STOP_RELAY_REFUSED | MALFORMED_MESSAGE
|
||||
|
||||
export type HOP = 1;
|
||||
export type STOP = 2;
|
||||
export type STATUS = 3;
|
||||
export type CAN_HOP = 4;
|
||||
|
||||
export type CircuitType = HOP | STOP | STATUS | CAN_HOP
|
||||
|
||||
export type CircuitMessageProto = {
|
||||
encode(value: any): Uint8Array
|
||||
decode(bytes: Uint8Array): any
|
||||
Status: {
|
||||
SUCCESS: SUCCESS,
|
||||
HOP_SRC_ADDR_TOO_LONG: HOP_SRC_ADDR_TOO_LONG,
|
||||
HOP_DST_ADDR_TOO_LONG: HOP_DST_ADDR_TOO_LONG,
|
||||
HOP_SRC_MULTIADDR_INVALID: HOP_SRC_MULTIADDR_INVALID,
|
||||
HOP_DST_MULTIADDR_INVALID: HOP_DST_MULTIADDR_INVALID,
|
||||
HOP_NO_CONN_TO_DST: HOP_NO_CONN_TO_DST,
|
||||
HOP_CANT_DIAL_DST: HOP_CANT_DIAL_DST,
|
||||
HOP_CANT_OPEN_DST_STREAM: HOP_CANT_OPEN_DST_STREAM,
|
||||
HOP_CANT_SPEAK_RELAY: HOP_CANT_SPEAK_RELAY,
|
||||
HOP_CANT_RELAY_TO_SELF: HOP_CANT_RELAY_TO_SELF,
|
||||
STOP_SRC_ADDR_TOO_LONG: STOP_SRC_ADDR_TOO_LONG,
|
||||
STOP_DST_ADDR_TOO_LONG: STOP_DST_ADDR_TOO_LONG,
|
||||
STOP_SRC_MULTIADDR_INVALID: STOP_SRC_MULTIADDR_INVALID,
|
||||
STOP_DST_MULTIADDR_INVALID: STOP_DST_MULTIADDR_INVALID,
|
||||
STOP_RELAY_REFUSED: STOP_RELAY_REFUSED,
|
||||
MALFORMED_MESSAGE: MALFORMED_MESSAGE
|
||||
},
|
||||
Type: {
|
||||
HOP: HOP,
|
||||
STOP: STOP,
|
||||
STATUS: STATUS,
|
||||
CAN_HOP: CAN_HOP
|
||||
}
|
||||
}
|
||||
|
@ -9,27 +9,23 @@ const Multistream = require('multistream-select')
|
||||
const { Connection } = require('libp2p-interfaces/src/connection')
|
||||
const ConnectionStatus = require('libp2p-interfaces/src/connection/status')
|
||||
const PeerId = require('peer-id')
|
||||
const pipe = require('it-pipe')
|
||||
const { pipe } = require('it-pipe')
|
||||
const mutableProxy = require('mutable-proxy')
|
||||
|
||||
const { codes } = require('./errors')
|
||||
|
||||
/**
|
||||
* @typedef {import('libp2p-interfaces/src/connection').Connection} Connection
|
||||
* @typedef {import('libp2p-interfaces/src/transport/types').MultiaddrConnection} MultiaddrConnection
|
||||
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').Muxer} Muxer
|
||||
* @typedef {import('libp2p-interfaces/src/stream-muxer/types').MuxedStream} MuxedStream
|
||||
* @typedef {import('libp2p-interfaces/src/crypto/types').Crypto} Crypto
|
||||
* @typedef {import('multiaddr')} Multiaddr
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef MultiaddrConnection
|
||||
* @property {Function} sink
|
||||
* @property {AsyncIterator} source
|
||||
* @property {*} conn
|
||||
* @property {Multiaddr} remoteAddr
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef CryptoResult
|
||||
* @property {*} conn A duplex iterable
|
||||
* @property {MultiaddrConnection} conn A duplex iterable
|
||||
* @property {PeerId} remotePeer
|
||||
* @property {string} protocol
|
||||
*/
|
||||
@ -39,23 +35,23 @@ class Upgrader {
|
||||
* @param {object} options
|
||||
* @param {PeerId} options.localPeer
|
||||
* @param {import('./metrics')} [options.metrics]
|
||||
* @param {Map<string, Crypto>} options.cryptos
|
||||
* @param {Map<string, Muxer>} options.muxers
|
||||
* @param {Map<string, Crypto>} [options.cryptos]
|
||||
* @param {Map<string, Muxer>} [options.muxers]
|
||||
* @param {(Connection) => void} options.onConnection - Called when a connection is upgraded
|
||||
* @param {(Connection) => void} options.onConnectionEnd
|
||||
*/
|
||||
constructor ({
|
||||
localPeer,
|
||||
metrics,
|
||||
cryptos,
|
||||
muxers,
|
||||
cryptos = new Map(),
|
||||
muxers = new Map(),
|
||||
onConnectionEnd = () => {},
|
||||
onConnection = () => {}
|
||||
}) {
|
||||
this.localPeer = localPeer
|
||||
this.metrics = metrics
|
||||
this.cryptos = cryptos || new Map()
|
||||
this.muxers = muxers || new Map()
|
||||
this.cryptos = cryptos
|
||||
this.muxers = muxers
|
||||
this.protector = null
|
||||
this.protocols = new Map()
|
||||
this.onConnection = onConnection
|
||||
@ -138,12 +134,7 @@ class Upgrader {
|
||||
* @returns {Promise<Connection>}
|
||||
*/
|
||||
async upgradeOutbound (maConn) {
|
||||
let remotePeerId
|
||||
try {
|
||||
remotePeerId = PeerId.createFromB58String(maConn.remoteAddr.getPeerId())
|
||||
} catch (err) {
|
||||
log.error('multiaddr did not contain a valid peer id', err)
|
||||
}
|
||||
const remotePeerId = PeerId.createFromB58String(maConn.remoteAddr.getPeerId())
|
||||
|
||||
let encryptedConn
|
||||
let remotePeer
|
||||
@ -155,7 +146,7 @@ class Upgrader {
|
||||
|
||||
if (this.metrics) {
|
||||
({ setTarget: setPeer, proxy: proxyPeer } = mutableProxy())
|
||||
const idString = (parseInt(Math.random() * 1e9)).toString(36) + Date.now()
|
||||
const idString = (Math.random() * 1e9).toString(36) + Date.now()
|
||||
setPeer({ toB58String: () => idString })
|
||||
maConn = this.metrics.trackStream({ stream: maConn, remotePeer: proxyPeer })
|
||||
}
|
||||
@ -213,8 +204,8 @@ class Upgrader {
|
||||
* @param {string} options.cryptoProtocol - The crypto protocol that was negotiated
|
||||
* @param {string} options.direction - One of ['inbound', 'outbound']
|
||||
* @param {MultiaddrConnection} options.maConn - The transport layer connection
|
||||
* @param {*} options.upgradedConn - A duplex connection returned from multiplexer and/or crypto selection
|
||||
* @param {Muxer} options.Muxer - The muxer to be used for muxing
|
||||
* @param {MuxedStream | MultiaddrConnection} options.upgradedConn - A duplex connection returned from multiplexer and/or crypto selection
|
||||
* @param {Muxer} [options.Muxer] - The muxer to be used for muxing
|
||||
* @param {PeerId} options.remotePeer - The peer the connection is with
|
||||
* @returns {Connection}
|
||||
*/
|
||||
@ -233,6 +224,7 @@ class Upgrader {
|
||||
|
||||
if (Muxer) {
|
||||
// Create the muxer
|
||||
// @ts-ignore
|
||||
muxer = new Muxer({
|
||||
// Run anytime a remote stream is created
|
||||
onStream: async muxedStream => {
|
||||
@ -306,6 +298,7 @@ class Upgrader {
|
||||
remotePeer: remotePeer,
|
||||
stat: {
|
||||
direction,
|
||||
// @ts-ignore
|
||||
timeline: maConn.timeline,
|
||||
multiplexer: Muxer && Muxer.multicodec,
|
||||
encryption: cryptoProtocol
|
||||
@ -332,7 +325,7 @@ class Upgrader {
|
||||
* @private
|
||||
* @param {object} options
|
||||
* @param {Connection} options.connection - The connection the stream belongs to
|
||||
* @param {Stream} options.stream
|
||||
* @param {MuxedStream} options.stream
|
||||
* @param {string} options.protocol
|
||||
*/
|
||||
_onStream ({ connection, stream, protocol }) {
|
||||
@ -348,7 +341,7 @@ class Upgrader {
|
||||
* @param {PeerId} localPeer - The initiators PeerId
|
||||
* @param {*} connection
|
||||
* @param {Map<string, Crypto>} cryptos
|
||||
* @returns {CryptoResult} An encrypted connection, remote peer `PeerId` and the protocol of the `Crypto` used
|
||||
* @returns {Promise<CryptoResult>} An encrypted connection, remote peer `PeerId` and the protocol of the `Crypto` used
|
||||
*/
|
||||
async _encryptInbound (localPeer, connection, cryptos) {
|
||||
const mss = new Multistream.Listener(connection)
|
||||
@ -360,6 +353,10 @@ class Upgrader {
|
||||
const crypto = cryptos.get(protocol)
|
||||
log('encrypting inbound connection...')
|
||||
|
||||
if (!crypto) {
|
||||
throw new Error(`no crypto module found for ${protocol}`)
|
||||
}
|
||||
|
||||
return {
|
||||
...await crypto.secureInbound(localPeer, stream),
|
||||
protocol
|
||||
@ -379,7 +376,7 @@ class Upgrader {
|
||||
* @param {*} connection
|
||||
* @param {PeerId} remotePeerId
|
||||
* @param {Map<string, Crypto>} cryptos
|
||||
* @returns {CryptoResult} An encrypted connection, remote peer `PeerId` and the protocol of the `Crypto` used
|
||||
* @returns {Promise<CryptoResult>} An encrypted connection, remote peer `PeerId` and the protocol of the `Crypto` used
|
||||
*/
|
||||
async _encryptOutbound (localPeer, connection, remotePeerId, cryptos) {
|
||||
const mss = new Multistream.Dialer(connection)
|
||||
@ -391,6 +388,10 @@ class Upgrader {
|
||||
const crypto = cryptos.get(protocol)
|
||||
log('encrypting outbound connection to %j', remotePeerId)
|
||||
|
||||
if (!crypto) {
|
||||
throw new Error(`no crypto module found for ${protocol}`)
|
||||
}
|
||||
|
||||
return {
|
||||
...await crypto.secureOutbound(localPeer, stream, remotePeerId),
|
||||
protocol
|
||||
@ -406,9 +407,9 @@ class Upgrader {
|
||||
*
|
||||
* @private
|
||||
* @async
|
||||
* @param {*} connection - A basic duplex connection to multiplex
|
||||
* @param {MultiaddrConnection} connection - A basic duplex connection to multiplex
|
||||
* @param {Map<string, Muxer>} muxers - The muxers to attempt multiplexing with
|
||||
* @returns {*} A muxed connection
|
||||
* @returns {Promise<{ stream: MuxedStream, Muxer?: Muxer}>} A muxed connection
|
||||
*/
|
||||
async _multiplexOutbound (connection, muxers) {
|
||||
const dialer = new Multistream.Dialer(connection)
|
||||
@ -430,9 +431,9 @@ class Upgrader {
|
||||
*
|
||||
* @private
|
||||
* @async
|
||||
* @param {*} connection - A basic duplex connection to multiplex
|
||||
* @param {MultiaddrConnection} connection - A basic duplex connection to multiplex
|
||||
* @param {Map<string, Muxer>} muxers - The muxers to attempt multiplexing with
|
||||
* @returns {*} A muxed connection
|
||||
* @returns {Promise<{ stream: MuxedStream, Muxer?: Muxer}>} A muxed connection
|
||||
*/
|
||||
async _multiplexInbound (connection, muxers) {
|
||||
const listener = new Multistream.Listener(connection)
|
||||
|
@ -10,7 +10,7 @@ const AggregateError = require('aggregate-error')
|
||||
const pDefer = require('p-defer')
|
||||
const delay = require('delay')
|
||||
|
||||
const { DialRequest } = require('../../src/dialer/dial-request')
|
||||
const DialRequest = require('../../src/dialer/dial-request')
|
||||
const createMockConnection = require('../utils/mockConnection')
|
||||
const error = new Error('dial failes')
|
||||
|
||||
|
@ -12,7 +12,8 @@ const pWaitFor = require('p-wait-for')
|
||||
const unit8ArrayToString = require('uint8arrays/to-string')
|
||||
|
||||
const { codes: Errors } = require('../../src/errors')
|
||||
const { IdentifyService, multicodecs } = require('../../src/identify')
|
||||
const IdentifyService = require('../../src/identify')
|
||||
const multicodecs = IdentifyService.multicodecs
|
||||
const Peers = require('../fixtures/peers')
|
||||
const Libp2p = require('../../src')
|
||||
const Envelope = require('../../src/record/envelope')
|
||||
|
@ -56,28 +56,6 @@ describe('Upgrader', () => {
|
||||
sinon.restore()
|
||||
})
|
||||
|
||||
it('should ignore a missing remote peer id', async () => {
|
||||
const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer })
|
||||
|
||||
const muxers = new Map([[Muxer.multicodec, Muxer]])
|
||||
sinon.stub(localUpgrader, 'muxers').value(muxers)
|
||||
sinon.stub(remoteUpgrader, 'muxers').value(muxers)
|
||||
|
||||
const cryptos = new Map([[Crypto.protocol, Crypto]])
|
||||
sinon.stub(localUpgrader, 'cryptos').value(cryptos)
|
||||
sinon.stub(remoteUpgrader, 'cryptos').value(cryptos)
|
||||
|
||||
// Remove the peer id from the remote address
|
||||
outbound.remoteAddr = outbound.remoteAddr.decapsulateCode(421)
|
||||
|
||||
const connections = await Promise.all([
|
||||
localUpgrader.upgradeOutbound(outbound),
|
||||
remoteUpgrader.upgradeInbound(inbound)
|
||||
])
|
||||
|
||||
expect(connections).to.have.length(2)
|
||||
})
|
||||
|
||||
it('should upgrade with valid muxers and crypto', async () => {
|
||||
const { inbound, outbound } = mockMultiaddrConnPair({ addrs, remotePeer })
|
||||
|
||||
|
@ -1,7 +1,21 @@
|
||||
{
|
||||
"extends": "./node_modules/aegir/src/config/tsconfig.aegir.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist"
|
||||
"outDir": "dist",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitReturns": false,
|
||||
"noImplicitAny": false,
|
||||
"noImplicitThis": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": false,
|
||||
"strictFunctionTypes": true,
|
||||
"strictNullChecks": true,
|
||||
"strictPropertyInitialization": true,
|
||||
"strictBindCallApply": true,
|
||||
"strict": true,
|
||||
"alwaysStrict": true,
|
||||
"stripInternal": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
|
Loading…
x
Reference in New Issue
Block a user