https://github.com/multiformats/js-multistream-select
JavaScript implementation of multistream-select
https://github.com/multiformats/js-multistream-select
Last synced: 9 months ago
JSON representation
JavaScript implementation of multistream-select
- Host: GitHub
- URL: https://github.com/multiformats/js-multistream-select
- Owner: multiformats
- License: mit
- Archived: true
- Created: 2015-06-07T10:34:47.000Z (about 11 years ago)
- Default Branch: master
- Last Pushed: 2022-10-18T17:28:09.000Z (over 3 years ago)
- Last Synced: 2024-09-24T00:35:58.784Z (almost 2 years ago)
- Language: JavaScript
- Homepage: https://github.com/multiformats/multistream
- Size: 4.43 MB
- Stars: 29
- Watchers: 18
- Forks: 18
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
⛔️ ARCHIVED: multistream-select can now be found at [@libp2p/multistream-select](https://github.com/libp2p/js-libp2p-multistream-select)
=====
# js-multistream-select
[](https://protocol.ai)
[](https://github.com/multiformats/multiformats)
[](https://webchat.freenode.net/?channels=%23ipfs)
[](https://codecov.io/gh/multiformats/js-multistream-select)
[](https://travis-ci.com/multiformats/js-multistream-select)
[](https://david-dm.org/multiformats/js-multistream-select)
[](https://github.com/feross/standard)
> JavaScript implementation of [multistream-select](https://github.com/multiformats/multistream-select)
## Lead Maintainer
[Jacob Heun](https://github.com/jacobheun)
## Table of Contents
- [Background](#background)
- [What is `multistream-select`?](#what-is-multistream-select)
- [Select a protocol flow](#select-a-protocol-flow)
- [Install](#install)
- [Usage](#usage)
- [Dialer](#dialer)
- [Listener](#listener)
- [API](#api)
- [`new MSS.Dialer(duplex)`](#new-mssdialerduplex)
- [Parameters](#parameters)
- [Returns](#returns)
- [Examples](#examples)
- [`dialer.select(protocols, [options])`](#dialerselectprotocols-options)
- [Parameters](#parameters-1)
- [Returns](#returns-1)
- [Examples](#examples-1)
- [`dialer.ls([options])`](#dialerlsoptions)
- [Parameters](#parameters-2)
- [Returns](#returns-2)
- [Examples](#examples-2)
- [`new MSS.Listener(duplex)`](#new-msslistenerduplex)
- [Parameters](#parameters-3)
- [Returns](#returns-3)
- [Examples](#examples-3)
- [`listener.handle(protocols, [options])`](#listenerhandleprotocols-options)
- [Parameters](#parameters-4)
- [Returns](#returns-4)
- [Examples](#examples-4)
- [Contribute](#contribute)
- [License](#license)
## Background
### What is `multistream-select`?
TLDR; multistream-select is protocol multiplexing per connection/stream. [Full spec here](https://github.com/multiformats/multistream-select)
#### Select a protocol flow
The caller will send "interactive" messages, expecting for some acknowledgement from the callee, which will "select" the handler for the desired and supported protocol:
```console
< /multistream-select/0.3.0 # i speak multistream-select/0.3.0
> /multistream-select/0.3.0 # ok, let's speak multistream-select/0.3.0
> /ipfs-dht/0.2.3 # i want to speak ipfs-dht/0.2.3
< na # ipfs-dht/0.2.3 is not available
> /ipfs-dht/0.1.9 # What about ipfs-dht/0.1.9 ?
< /ipfs-dht/0.1.9 # ok let's speak ipfs-dht/0.1.9 -- in a sense acts as an ACK
>
>
>
```
This mode also packs a `ls` option, so that the callee can list the protocols it currently supports
## Install
```sh
npm i multistream-select
```
## Usage
```js
const MSS = require('multistream-select')
// You can now use
// MSS.Dialer - actively select a protocol with a remote
// MSS.Listener - handle a protocol with a remote
```
### Dialer
```js
const pipe = require('it-pipe')
const MSS = require('multistream-select')
const Mplex = require('libp2p-mplex')
const muxer = new Mplex()
const muxedStream = muxer.newStream()
const mss = new MSS.Dialer(muxedStream)
// mss.select(protocol(s))
// Select from one of the passed protocols (in priority order)
// Returns selected stream and protocol
const { stream: dhtStream, protocol } = await mss.select([
// This might just be different versions of DHT, but could be different impls
'/ipfs-dht/2.0.0', // Most of the time this will probably just be one item.
'/ipfs-dht/1.0.0'
])
// Typically this stream will be passed back to the caller of libp2p.dialProtocol
//
// ...it might then do something like this:
// try {
// await pipe(
// [uint8ArrayFromString('Some DHT data')]
// dhtStream,
// async source => {
// for await (const chunk of source)
// // DHT response data
// }
// )
// } catch (err) {
// // Error in stream
// }
```
### Listener
```js
const pipe = require('it-pipe')
const MSS = require('multistream-select')
const Mplex = require('libp2p-mplex')
const muxer = new Mplex({
async onStream (muxedStream) {
const mss = new MSS.Listener(muxedStream)
// mss.handle(handledProtocols)
// Returns selected stream and protocol
const { stream, protocol } = await mss.handle([
'/ipfs-dht/1.0.0',
'/ipfs-bitswap/1.0.0'
])
// Typically here we'd call the handler function that was registered in
// libp2p for the given protocol:
// e.g. handlers[protocol].handler(stream)
//
// If protocol was /ipfs-dht/1.0.0 it might do something like this:
// try {
// await pipe(
// dhtStream,
// source => (async function * () {
// for await (const chunk of source)
// // Incoming DHT data -> process and yield to respond
// })(),
// dhtStream
// )
// } catch (err) {
// // Error in stream
// }
}
})
```
## API
### `new MSS.Dialer(duplex)`
Create a new multistream select "dialer" instance which can be used to negotiate a protocol to use, list all available protocols the remote supports, or do both.
#### Parameters
* `duplex` (`Object`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to dial on.
#### Returns
A new multistream select dialer instance.
#### Examples
```js
const dialer = new MSS.Dialer(duplex)
```
### `dialer.select(protocols, [options])`
Negotiate a protocol to use from a list of protocols.
#### Parameters
* `protocols` (`String[]`/`String`) - A list of protocols (or single protocol) to negotiate with. Protocols are attempted in order until a match is made.
* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal
#### Returns
`Promise<{ stream, protocol }>` - A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.
Note that after a protocol is selected `dialer` can no longer be used.
#### Examples
```js
const { stream, protocol } = await dialer.select([
// This might just be different versions of DHT, but could be different impls
'/ipfs-dht/2.0.0', // Most of the time this will probably just be one item.
'/ipfs-dht/1.0.0'
])
// Now talk `protocol` on `stream`
```
### `dialer.ls([options])`
List protocols that the remote supports.
#### Parameters
* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal
#### Returns
`String[]` - A list of all the protocols the remote supports.
#### Examples
```js
const protocols = await dialer.ls()
const wantedProto = '/ipfs-dht/2.0.0'
if (!protocols.includes(wantedProto)) {
throw new Error('remote does not support ' + wantedProto)
}
// Now use dialer.select to use wantedProto, safe in the knowledge it is supported
```
### `new MSS.Listener(duplex)`
Construct a new multistream select "listener" instance which can be used to handle multistream protocol selections for particular protocols.
#### Parameters
* `duplex` (`Object`) - A [duplex iterable stream](https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it) to listen on.
#### Returns
A new multistream select listener instance.
#### Examples
```js
const listener = new MSS.Listener(duplex)
```
### `listener.handle(protocols, [options])`
Handle multistream protocol selections for the given list of protocols.
#### Parameters
* `protocols` (`String[]`/`String`) - A list of protocols (or single protocol) that this listener is able to speak.
* `options` (`{ signal: AbortSignal }`) - an options object containing an AbortSignal
#### Returns
`Promise<{ stream, protocol }>` - A stream for the selected protocol and the protocol that was selected from the list of protocols provided to `select`.
Note that after a protocol is handled `listener` can no longer be used.
#### Examples
```js
const { stream, protocol } = await listener.handle([
'/ipfs-dht/1.0.0',
'/ipfs-bitswap/1.0.0'
])
// Remote wants to speak `protocol`
```
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/multiformats/js-multistream-select/issues).
Check out our [contributing document](https://github.com/multiformats/multiformats/blob/master/contributing.md) for more information on how we work, and about contributing in general. Please be aware that all interactions related to multiformats are subject to the IPFS [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md).
Small note: If editing the README, please conform to the [standard-readme](https://github.com/RichardLitt/standard-readme) specification.
## License
[MIT](LICENSE)