'use strict' const debug = require('debug') const log = Object.assign(debug('libp2p:registrar'), { error: debug('libp2p:registrar:err') }) const errcode = require('err-code') const { codes: { ERR_INVALID_PARAMETERS } } = require('./errors') const Topology = require('libp2p-interfaces/src/topology') /** * @typedef {import('peer-id')} PeerId * @typedef {import('./peer-store')} PeerStore * @typedef {import('./connection-manager')} ConnectionManager * @typedef {import('libp2p-interfaces/src/connection').Connection} Connection * @typedef {import('./').HandlerProps} HandlerProps */ /** * */ /** * Responsible for notifying registered protocols of events in the network. */ class Registrar { /** * @param {Object} props * @param {PeerStore} props.peerStore * @param {ConnectionManager} props.connectionManager * @class */ constructor ({ peerStore, connectionManager }) { // Used on topology to listen for protocol changes this.peerStore = peerStore this.connectionManager = connectionManager /** * Map of topologies * * @type {Map} */ this.topologies = new Map() /** @type {(protocols: string[]|string, handler: (props: HandlerProps) => void) => void} */ // @ts-ignore handle is not optional this._handle = undefined this._onDisconnect = this._onDisconnect.bind(this) this.connectionManager.on('peer:disconnect', this._onDisconnect) } /** * @returns {(protocols: string[]|string, handler: (props: HandlerProps) => void) => void} */ get handle () { return this._handle } /** * @param {(protocols: string[]|string, handler: (props: HandlerProps) => void) => void} handle */ set handle (handle) { this._handle = handle } /** * Get a connection with a peer. * * @param {PeerId} peerId * @returns {Connection | null} */ getConnection (peerId) { return this.connectionManager.get(peerId) } /** * Register handlers for a set of multicodecs given * * @param {Topology} topology - protocol topology * @returns {string} registrar identifier */ register (topology) { if (!Topology.isTopology(topology)) { log.error('topology must be an instance of interfaces/topology') throw errcode(new Error('topology must be an instance of interfaces/topology'), ERR_INVALID_PARAMETERS) } // Create topology const id = (Math.random() * 1e9).toString(36) + Date.now() this.topologies.set(id, topology) // Set registrar topology.registrar = this return id } /** * Unregister topology. * * @param {string} id - registrar identifier * @returns {boolean} unregistered successfully */ unregister (id) { return this.topologies.delete(id) } /** * Remove a disconnected peer from the record * * @param {Connection} connection * @returns {void} */ _onDisconnect (connection) { for (const [, topology] of this.topologies) { topology.disconnect(connection.remotePeer) } } } module.exports = Registrar