Skip to content
This repository has been archived by the owner on Jun 26, 2023. It is now read-only.

Commit

Permalink
feat: interface pubsub
Browse files Browse the repository at this point in the history
  • Loading branch information
vasco-santos committed Aug 17, 2020
1 parent a60ae09 commit db97b73
Show file tree
Hide file tree
Showing 18 changed files with 1,837 additions and 1 deletion.
9 changes: 8 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,28 @@
"chai": "^4.2.0",
"chai-checkmark": "^1.0.1",
"class-is": "^1.1.0",
"debug": "^4.1.1",
"delay": "^4.3.0",
"detect-node": "^2.0.4",
"dirty-chai": "^2.0.1",
"err-code": "^2.0.0",
"it-goodbye": "^2.0.1",
"it-length-prefixed": "^3.1.0",
"it-pair": "^1.0.0",
"it-pipe": "^1.1.0",
"it-pushable": "^1.4.0",
"libp2p-crypto": "^0.17.9",
"libp2p-tcp": "^0.15.0",
"multiaddr": "^8.0.0",
"multibase": "^3.0.0",
"p-defer": "^3.0.0",
"p-limit": "^2.3.0",
"p-wait-for": "^3.1.0",
"peer-id": "^0.14.0",
"protons": "^2.0.0",
"sinon": "^9.0.2",
"streaming-iterables": "^5.0.2"
"streaming-iterables": "^5.0.2",
"uint8arrays": "^1.1.0"
},
"devDependencies": {
"aegir": "^25.0.0",
Expand Down
209 changes: 209 additions & 0 deletions src/pubsub/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
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.

## Implementations using this base protocol

You can use 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. This way, a pubsub implementation can focus on its routing algorithm, instead of also needing to create the setup for it.

A pubsub router implementation should start by extending the `interface-pubsub` class and **MUST** override the `_processMessages`, `publish`, `subscribe`, `unsubscribe` and `getTopics` functions, according to the router algorithms.

Other functions, such as `_onPeerConnected`, `_onPeerDisconnected`, `_addPeer`, `_removePeer`, `start` and `stop` may be overwritten if the pubsub implementation needs to customize their logic. Implementations overriding `start` and `stop` **MUST** call `super`. The `start` function is responsible for registering the pubsub protocol with libp2p, while the `stop` function is responsible for unregistering the pubsub protocol and closing pubsub connections.

All the remaining functions **MUST NOT** be overwritten.

The following example aims to show how to create your pubsub implementation extending this base protocol. The pubsub implementation will handle the subscriptions logic.

```JavaScript
const Pubsub = require('libp2p-pubsub')

class PubsubImplementation extends Pubsub {
constructor({ peerId, registrar, ...options })
super({
debugName: 'libp2p:pubsub',
multicodecs: '/pubsub-implementation/1.0.0',
peerId: peerId,
registrar: registrar,
signMessages: options.signMessages,
strictSigning: options.strictSigning
})
}

_processMessages(idB58Str, conn, peer) {
// Required to be implemented by the subclass
// Process each message accordingly
}

publish() {
// Required to be implemented by the subclass
}

subscribe() {
// Required to be implemented by the subclass
}

unsubscribe() {
// Required to be implemented by the subclass
}

getTopics() {
// Required to be implemented by the subclass
}
}
```

## API

The interface aims to specify a common interface that all pubsub router implementation should follow.

### 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()`

##### Returns

| Type | Description |
|------|-------------|
| `Promise<void>` | resolves once pubsub starts |

### 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()`

##### Returns

| Type | Description |
|------|-------------|
| `Promise<void>` | resolves once pubsub stops |

### Publish

Publish data message to pubsub topics.

#### `pubsub.publish(topics, message)`

##### Parameters

| Name | Type | Description |
|------|------|-------------|
| topics | `Array<string>|string` | set of pubsub topics |
| 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(s).

#### `pubsub.subscribe(topics, [handler])`

##### Parameters

| Name | Type | Description |
|------|------|-------------|
| topics | `Array<string>|string` | set of pubsub topics |
| [handler] | `function (msg)` | handler for messages received in the given topics |

### Unsubscribe

Unsubscribe from the given topic(s).

#### `pubsub.unsubscribe(topics, [handler])`

##### Parameters

| Name | Type | Description |
|------|------|-------------|
| topics | `Array<string>|string` | set of pubsub topics |
| [handler] | `function (msg)` | handler for messages received in the given topics |

If **NO** `handler` is provided, all registered handlers to the given topics will be removed.

### 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 the signature of a message.

#### `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
/* eslint-env mocha */
'use strict'

const tests = require('libp2p-interfaces/src/pubsub/tests')
const multiaddr = require('multiaddr')
const YourTransport = require('../src')

describe('compliance', () => {
tests({
setup (options) {
// Create 5 libp2p nodes with pubsub

// TODO
return
},
teardown () {
// Clean up any resources created by setup()
}
})
})
```
6 changes: 6 additions & 0 deletions src/pubsub/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
'use strict'

exports.codes = {
ERR_MISSING_SIGNATURE: 'ERR_MISSING_SIGNATURE',
ERR_INVALID_SIGNATURE: 'ERR_INVALID_SIGNATURE'
}
Loading

0 comments on commit db97b73

Please sign in to comment.