UNPKG

@libp2p/interface-pubsub

Version:
324 lines (231 loc) 12.8 kB
# @libp2p/interface-pubsub <!-- omit in toc --> [![libp2p.io](https://img.shields.io/badge/project-libp2p-yellow.svg?style=flat-square)](http://libp2p.io/) [![Discuss](https://img.shields.io/discourse/https/discuss.libp2p.io/posts.svg?style=flat-square)](https://discuss.libp2p.io) [![codecov](https://img.shields.io/codecov/c/github/libp2p/js-libp2p-interfaces.svg?style=flat-square)](https://codecov.io/gh/libp2p/js-libp2p-interfaces) [![CI](https://img.shields.io/github/actions/workflow/status/libp2p/js-libp2p-interfaces/js-test-and-release.yml?branch=master\&style=flat-square)](https://github.com/libp2p/js-libp2p-interfaces/actions/workflows/js-test-and-release.yml?query=branch%3Amaster) > PubSub interface for libp2p ## Table of contents <!-- omit in toc --> - - [Install](#install) - [Table of Contents <!-- omit in toc -->](#table-of-contents----omit-in-toc---) - [Implementations using this interface](#implementations-using-this-interface) - [Interface usage](#interface-usage) - [Extend interface](#extend-interface) - [Example](#example) - [API](#api) - [Constructor](#constructor) - [`new Pubsub({options})`](#new-pubsuboptions) - [Parameters](#parameters) - [Start](#start) - [`pubsub.start()`](#pubsubstart) - [Stop](#stop) - [`pubsub.stop()`](#pubsubstop) - [Publish](#publish) - [`pubsub.publish(topic, message)`](#pubsubpublishtopic-message) - [Parameters](#parameters-1) - [Returns](#returns) - [Subscribe](#subscribe) - [`pubsub.subscribe(topic)`](#pubsubsubscribetopic) - [Parameters](#parameters-2) - [Unsubscribe](#unsubscribe) - [`pubsub.unsubscribe(topic)`](#pubsubunsubscribetopic) - [Parameters](#parameters-3) - [Get Topics](#get-topics) - [`pubsub.getTopics()`](#pubsubgettopics) - [Returns](#returns-1) - [Get Peers Subscribed to a topic](#get-peers-subscribed-to-a-topic) - [`pubsub.getSubscribers(topic)`](#pubsubgetsubscriberstopic) - [Parameters](#parameters-4) - [Returns](#returns-2) - [Validate](#validate) - [`pubsub.validate(message)`](#pubsubvalidatemessage) - [Parameters](#parameters-5) - [Returns](#returns-3) - [Test suite usage](#test-suite-usage) - [API Docs](#api-docs) - [License](#license) - [Contribution](#contribution) ## Install ```console $ npm i @libp2p/interface-pubsub ``` The `interface-pubsub` contains the base implementation for a libp2p pubsub router implementation. This interface should be used to implement a pubsub router compatible with libp2p. It includes a test suite that pubsub routers should run, in order to ensure compatibility with libp2p. # Table of Contents <!-- omit in toc --> - [Implementations using this interface](#implementations-using-this-interface) - [Interface usage](#interface-usage) - [Extend interface](#extend-interface) - [Example](#example) - [API](#api) - [Constructor](#constructor) - [`new Pubsub({options})`](#new-pubsuboptions) - [Parameters](#parameters) - [Start](#start) - [`pubsub.start()`](#pubsubstart) - [Stop](#stop) - [`pubsub.stop()`](#pubsubstop) - [Publish](#publish) - [`pubsub.publish(topic, message)`](#pubsubpublishtopic-message) - [Parameters](#parameters-1) - [Returns](#returns) - [Subscribe](#subscribe) - [`pubsub.subscribe(topic)`](#pubsubsubscribetopic) - [Parameters](#parameters-2) - [Unsubscribe](#unsubscribe) - [`pubsub.unsubscribe(topic)`](#pubsubunsubscribetopic) - [Parameters](#parameters-3) - [Get Topics](#get-topics) - [`pubsub.getTopics()`](#pubsubgettopics) - [Returns](#returns-1) - [Get Peers Subscribed to a topic](#get-peers-subscribed-to-a-topic) - [`pubsub.getSubscribers(topic)`](#pubsubgetsubscriberstopic) - [Parameters](#parameters-4) - [Returns](#returns-2) - [Validate](#validate) - [`pubsub.validate(message)`](#pubsubvalidatemessage) - [Parameters](#parameters-5) - [Returns](#returns-3) - [Test suite usage](#test-suite-usage) - [License](#license) - [Contribution](#contribution) ## Implementations using this interface You can check the following implementations as examples for building your own pubsub router. - [libp2p/js-libp2p-floodsub](https://github.com/libp2p/js-libp2p-floodsub) - [ChainSafe/js-libp2p-gossipsub](https://github.com/ChainSafe/js-libp2p-gossipsub) ## 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. ### Extend interface A pubsub router implementation should start by extending the `interface-pubsub` class and **MUST** override the `_publish` function, according to the router algorithms. This function is responsible for forwarding publish messages to other peers, as well as forwarding received messages if the router provides the `canRelayMessage` option to the base implementation. Other functions, such as `start`, `stop`, `subscribe`, `unsubscribe`, `_encodeRpc`, `_decodeRpc`, `_processRpcMessage`, `_addPeer` and `_removePeer` may be overwritten if the pubsub implementation needs to customize their logic. Implementations overriding these functions **MUST** call `super`. The `start` and `stop` functions are responsible for the registration of the pubsub protocol with libp2p. The `stop` function also guarantees that the open streams in the protocol are properly closed. The `subscribe` and `unsubscribe` functions take care of the subscription management and its inherent message propagation. When using a custom protobuf definition for message marshalling, you should override `_encodeRpc` and `_decodeRpc` to use the new protobuf instead of the default one. `_processRpcMessage` is responsible for handling messages received from other peers. This should be extended if further operations/validations are needed by the router. The `_addPeer` and `_removePeer` functions are called when new peers running the pubsub router protocol establish a connection with the peer. They are used for tracking the open streams between the peers. All the remaining functions **MUST NOT** be overwritten. ### Example 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') class PubsubImplementation extends Pubsub { constructor({ libp2p, options }) super({ debugName: 'libp2p:pubsub', multicodecs: '/pubsub-implementation/1.0.0', libp2p, globalSigningPolicy: options.globalSigningPolicy }) } _publish (message) { // Required to be implemented by the subclass // Routing logic for the message } } ``` ## API 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`. #### `pubsub.start()` ### Stop Stops the pubsub subsystem. The protocol will be unregistered from `libp2p`, which will remove all listeners for the protocol and the established connections will be closed. #### `pubsub.stop()` ### Publish Publish data message to pubsub topics. #### `pubsub.publish(topic, message)` ##### Parameters | Name | Type | Description | | ------- | ------------ | ------------------ | | topic | `string` | pubsub topic | | message | `Uint8Array` | message to publish | ##### Returns | Type | Description | | --------------- | ----------------------------------------------------- | | `Promise<void>` | resolves once the message is published to the network | ### Subscribe Subscribe to the given topic. #### `pubsub.subscribe(topic)` ##### Parameters | Name | Type | Description | | ----- | -------- | ------------ | | topic | `string` | pubsub topic | ### Unsubscribe Unsubscribe from the given topic. #### `pubsub.unsubscribe(topic)` ##### Parameters | Name | Type | Description | | ----- | -------- | ------------ | | topic | `string` | pubsub topic | ### Get Topics Get the list of topics which the peer is subscribed to. #### `pubsub.getTopics()` ##### Returns | Type | Description | | --------------- | -------------------------- | | `Array<String>` | Array of subscribed topics | ### Get Peers Subscribed to a topic Get a list of the [PeerId](https://github.com/libp2p/js-peer-id) strings that are subscribed to one topic. #### `pubsub.getSubscribers(topic)` ##### Parameters | Name | Type | Description | | ----- | -------- | ------------ | | topic | `string` | pubsub topic | ##### Returns | Type | Description | | --------------- | ------------------------- | | `Array<string>` | Array of base-58 PeerId's | ### Validate Validates a message according to the signature policy and topic-specific validation function. #### `pubsub.validate(message)` ##### Parameters | Name | Type | Description | | ------- | --------- | ---------------- | | message | `Message` | a pubsub message | #### Returns | Type | Description | | --------------- | -------------------------------- | | `Promise<void>` | resolves if the message is valid | ## Test suite usage ```js 'use strict' const tests = require('libp2p-interfaces-compliance-tests/pubsub') const YourPubsubRouter = require('../src') describe('compliance', () => { let peers let pubsubNodes = [] tests({ async setup (number = 1, options = {}) { // Create number pubsub nodes with libp2p peers = await createPeers({ number }) peers.forEach((peer) => { const ps = new YourPubsubRouter(peer, options) pubsubNodes.push(ps) }) return pubsubNodes }, async teardown () { // Clean up any resources created by setup() await Promise.all(pubsubNodes.map(ps => ps.stop())) peers.length && await Promise.all(peers.map(peer => peer.stop())) } }) }) ``` ## API Docs - <https://libp2p.github.io/js-libp2p-interfaces/modules/_libp2p_interface_pubsub.html> ## License Licensed under either of - Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / <http://www.apache.org/licenses/LICENSE-2.0>) - MIT ([LICENSE-MIT](LICENSE-MIT) / <http://opensource.org/licenses/MIT>) ## Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.