Skip to content
This repository has been archived by the owner on Oct 19, 2022. It is now read-only.

Commit

Permalink
fix: make mss abortable (#142)
Browse files Browse the repository at this point in the history
Allows passing an options object to `dialer.select` that can contain an `AbortSignal` that will throw if the operation is aborted due to a timeout or other criteria.

Also adds types and swaps travis for gh actions.

BREAKING CHANGE: This module now has types
  • Loading branch information
achingbrain committed Dec 21, 2021
1 parent cf4e297 commit 2165038
Show file tree
Hide file tree
Showing 15 changed files with 340 additions and 109 deletions.
8 changes: 8 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: npm
directory: "/"
schedule:
interval: daily
time: "11:00"
open-pull-requests-limit: 10
78 changes: 78 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
name: ci
on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npm install
- run: npm run lint
- run: npm run build
- run: npm run dep-check
test-node:
needs: check
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest, ubuntu-latest, macos-latest]
node: [16]
fail-fast: true
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node }}
- run: npm install
- run: npm run build
- run: npm run test:node -- --bail --cov
- uses: codecov/codecov-action@v1
test-chrome:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16
- run: npm install
- run: npm run build
- run: npm run test:browser -- -t browser -t webworker --bail
test-firefox:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16
- run: npm install
- run: npm run build
- run: npm run test:browser -- -t browser -t webworker --bail -- --browser firefox
test-electron-main:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16
- run: npm install
- run: npm run build
- run: npx xvfb-maybe npm run test:electron --bail
test-electron-renderer:
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: 16
- run: npm install
- run: npx xvfb-maybe aegir test -t electron-renderer --bail
50 changes: 0 additions & 50 deletions .travis.yml

This file was deleted.

45 changes: 35 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# js-multistream-select
# js-multistream-select <!-- omit in toc -->

[![](https://img.shields.io/badge/made%20by-Protocol%20Labs-blue.svg?style=flat-square)](https://protocol.ai)
[![](https://img.shields.io/badge/project-multiformats-blue.svg?style=flat-square)](https://github.com/multiformats/multiformats)
Expand All @@ -10,21 +10,40 @@

> JavaScript implementation of [multistream-select](https://github.com/multiformats/multistream-select)
## Lead Maintainer
## Lead Maintainer <!-- omit in toc -->

[Jacob Heun](https://github.com/jacobheun)

## Table of Contents
## Table of Contents <!-- omit in toc -->

- [Background](#background)
- [What is multistream-select?](#what-is-multistream-select)
- [What is `multistream-select`?](#what-is-multistream-select)
- [Select a protocol flow](#select-a-protocol-flow)
- [Install](#install)
- [Usage](#usage)
- [Dialer](#dialer)
- [Listener](#listener)
- [Dialer](#dialer)
- [Listener](#listener)
- [API](#api)
- [Maintainers](#maintainers)
- [`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)

Expand Down Expand Up @@ -164,13 +183,14 @@ A new multistream select dialer instance.
const dialer = new MSS.Dialer(duplex)
```

### `dialer.select(protocols)`
### `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

Expand All @@ -189,10 +209,14 @@ const { stream, protocol } = await dialer.select([
// Now talk `protocol` on `stream`
```

### `dialer.ls()`
### `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.
Expand Down Expand Up @@ -228,13 +252,14 @@ A new multistream select listener instance.
const listener = new MSS.Listener(duplex)
```

### `listener.handle(protocols)`
### `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

Expand Down
16 changes: 10 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,25 @@
"leadMaintainer": "Jacob Heun <jacobheun@gmail.com>",
"description": "JavaScript implementation of multistream-select",
"main": "src/index.js",
"types": "dist/src/index.d.ts",
"files": [
"dist",
"src"
],
"scripts": {
"lint": "aegir lint",
"lint": "aegir ts -p check && aegir lint",
"build": "aegir build",
"test": "aegir test",
"test:node": "aegir test -t node",
"test:browser": "aegir test -t browser",
"test:webworker": "aegir test -t webworker",
"test:electron": "aegir test -t electron-main",
"test:electron-renderer": "aegir test -t electron-renderer",
"coverage": "nyc --reporter=text --reporter=lcov npm run test:node",
"release": "aegir release -t node -t browser",
"release-minor": "aegir release --type minor -t node -t browser",
"release-major": "aegir release --type major -t node -t browser"
"release-major": "aegir release --type major -t node -t browser",
"dep-check": "aegir dep-check"
},
"repository": {
"type": "git",
Expand All @@ -40,6 +44,7 @@
},
"homepage": "https://github.com/multiformats/js-multistream-select#readme",
"dependencies": {
"abortable-iterator": "^3.0.0",
"bl": "^5.0.0",
"debug": "^4.1.1",
"err-code": "^3.0.1",
Expand All @@ -53,13 +58,12 @@
},
"devDependencies": {
"@types/bl": "^5.0.1",
"aegir": "^35.0.1",
"chai": "^4.3.4",
"dirty-chai": "^2.0.1",
"@types/debug": "^4.1.7",
"aegir": "^36.1.1",
"it-pair": "^1.0.0",
"mocha": "^8.1.1",
"p-timeout": "^4.0.0",
"streaming-iterables": "^5.0.2",
"timeout-abort-controller": "^2.0.0",
"util": "^0.12.4",
"varint": "^6.0.0"
},
Expand Down
22 changes: 19 additions & 3 deletions src/handle.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
'use strict'

const log = require('debug')('mss:handle')
const debug = require('debug')
const BufferList = require('bl/BufferList')
const multistream = require('./multistream')
// @ts-expect-error no types
const handshake = require('it-handshake')
const { PROTOCOL_ID } = require('./constants')

module.exports = async (stream, protocols) => {
const log = Object.assign(debug('mss:handle'), {
error: debug('mss:handle:error')
})

/**
* @typedef {import('./types').DuplexStream<Uint8Array>} DuplexStream
*/

/**
* @param {DuplexStream} stream
* @param {string | string[]} protocols
* @param {object} [options]
* @param {AbortSignal} options.signal
*/
module.exports = async function handle (stream, protocols, options) {
protocols = Array.isArray(protocols) ? protocols : [protocols]
const { writer, reader, rest, stream: shakeStream } = handshake(stream)

while (true) {
const protocol = (await multistream.read(reader)).toString()
const protocol = (await multistream.read(reader, options)).toString()
log('read "%s"', protocol)

if (protocol === PROTOCOL_ID) {
Expand All @@ -30,6 +45,7 @@ module.exports = async (stream, protocols) => {
if (protocol === 'ls') {
// <varint-msg-len><varint-proto-name-len><proto-name>\n<varint-proto-name-len><proto-name>\n\n
multistream.write(writer, new BufferList(
// @ts-expect-error BufferList does not accept Uint8Array[] as a constructor arg
protocols.map(p => multistream.encode(p))
))
log('respond with "%s" for %s', protocols, protocol)
Expand Down
Loading

0 comments on commit 2165038

Please sign in to comment.