UNPKG

it-ws

Version:

Simple async iterables for websocket client connections

274 lines (199 loc) 7.58 kB
# it-ws <!-- omit in toc --> [![codecov](https://img.shields.io/codecov/c/github/alanshaw/it-ws.svg?style=flat-square)](https://codecov.io/gh/alanshaw/it-ws) [![CI](https://img.shields.io/github/actions/workflow/status/alanshaw/it-ws/js-test-and-release.yml?branch=master\&style=flat-square)](https://github.com/alanshaw/it-ws/actions/workflows/js-test-and-release.yml?query=branch%3Amaster) > Simple async iterables for websocket client connections ## Table of contents <!-- omit in toc --> - [Install](#install) - [Browser `<script>` tag](#browser-script-tag) - [Usage](#usage) - [Example - client](#example---client) - [Example - server](#example---server) - [API](#api) - [`import { connect } from 'it-ws/client'`](#import--connect--from-it-wsclient) - [`import { createServer } from 'it-ws/server'`](#import--createserver--from-it-wsserver) - [Example](#example) - [use with an http server](#use-with-an-http-server) - [core, websocket wrapping functions](#core-websocket-wrapping-functions) - [`import duplex from 'it-ws/duplex'`](#import-duplex-from-it-wsduplex) - [`import sink from 'it-ws/sink'`](#import-sink-from-it-wssink) - [`import source from 'it-ws/source'`](#import-source-from-it-wssource) - [License](#license) - [Contribution](#contribution) ## Install ```console $ npm i it-ws ``` ### Browser `<script>` tag Loading this module through a script tag will make it's exports available as `ItWs` in the global namespace. ```html <script src="https://unpkg.com/it-ws/dist/index.min.js"></script> ``` ## Usage ### Example - client ```js import { connect } from 'it-ws/client' import { pipe } from 'it-pipe' const stream = connect(WS_URL) await stream.connected() // Wait for websocket to be connected (optional) pipe(source, stream, sink) ``` ### Example - server ```js import { createServer } from 'it-ws/server' import { pipe } from 'it-pipe' const server = createServer(stream => { //pipe the stream somewhere. //eg, echo server pipe(stream, stream) }) await server.listen(PORT) ``` ## API ### `import { connect } from 'it-ws/client'` `connect(url, { binary: boolean })` Create a websocket client connection. Set `binary: true` to get a stream of arrayBuffers (on the browser). Defaults to true on node, but to strings on the browser. This may cause a problems if your application assumes binary. For adding options to the WebSocket instance, as [websockets/ws/blob/master/doc/ws.md#new-websocketaddress-protocols-options](https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketaddress-protocols-options), you can provide an object with the `websocket` property into the connect options. ```js const stream = connect(url) // stream is duplex and is both a `source` and `sink`. // See this for more information: // https://gist.github.com/alanshaw/591dc7dd54e4f99338a347ef568d6ee9#duplex-it ``` ### `import { createServer } from 'it-ws/server'` Create async iterable websocket servers. `createServer(options?, onConnection)` `options` takes the same server options as [ws module](https://github.com/websockets/ws/blob/master/doc/ws.md#new-wsserveroptions-callback) `onConnection(stream)` is called every time a connection is received. #### Example One duplex service you may want to use this with is [muxrpc](https://github.com/dominictarr/muxrpc) ```js import { createServer } from 'it-ws/server' import { connect } from 'it-ws/client' import { pipe } from 'it-pipe' createServer({ onConnection: (stream) => { // pipe duplex style to your service pipe(stream, service.createStream(), stream) } }) .listen(9999) const stream = client.createStream() await pipe( stream, connect('ws://localhost:9999'), stream ) ``` if the connection fails, the stream will throw ```js try { await pipe( stream, connect('ws://localhost:9999'), stream ) } catch (err) { // handle err } ``` To run the server over TLS: ```js createServer({ key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'), cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem') // other options }) .listen(9999) ``` To add client-authentication to the server, you can set `verifyClient`. [Documentation here](https://github.com/websockets/ws/blob/master/doc/ws.md#optionsverifyclient). ```js function verifyClient (info) { return info.secure == true } createServer({ verifyClient: verifyClient // other options }) ``` ## use with an http server if you have an http server that you also need to serve stuff over, and want to use a single port, use the `server` option. ```js import http from 'http' const server = http.createServer(function(req, res){...}).listen(....) createServer({ server: server // other options }) ``` ### core, websocket wrapping functions these modules are used internally, to wrap a websocket. you probably won't need to touch these, but they are documented anyway. ### `import duplex from 'it-ws/duplex'` turn a websocket into a duplex stream. If provided, `opts` is passed to `sink(socket, opts)`. WebSockets do not support half open mode. [see allowHalfOpen option in net module](http://nodejs.org/api/net.html#net_net_createserver_options_connectionlistener) If you have a protocol that assumes halfOpen connections, but are using a networking protocol like websockets that does not support it, I suggest using [it-goodbye](https://github.com/alanshaw/it-goodbye) with your protocol. The duplex stream will also contain a copy of the properties from the http request that became the websocket. they are `method`, `url`, `headers` and `upgrade`. also exposed at: `import { duplex } from 'it-ws'` ### `import sink from 'it-ws/sink'` Create a `Sink` that will write data to the `socket`. `opts` may be `{closeOnEnd: true, onClose: onClose}`. `onClose` will be called when the sink ends. If `closeOnEnd=false` the stream will not close, it will just stop emitting data. (by default `closeOnEnd` is true) If `opts` is a function, then `onClose = opts; opts.closeOnEnd = true`. ```js import sink from 'it-ws/sink' import { pipe } from 'it-pipe' import each from 'it-foreach' import delay from 'delay' // connect to the echo endpoint for test/server.js var socket = new WebSocket('wss://echo.websocket.org') // write values to the socket pipe( async function * () { while (true) { yield 'hello @ ' + Date.now() } }(), // throttle so it doesn't go nuts (source) => each(source, () => delay(100)) sink(socket) ); socket.addEventListener('message', function(evt) { console.log('received: ' + evt.data); }); ``` also exposed at `import { sink } from 'it-ws'` ### `import source from 'it-ws/source'` Create a `Source` that will read data from the `socket`. ```js import { pipe } from 'it-pipe' import source from 'it-ws/source' import { toString } from 'uint8arrays/to-string' pipe( // connect to the test/server.js endpoint source(new WebSocket('ws://localhost:3000/read')), async (source) => { for await (const buf of source) { console.info(toString(buf)) } } ); ``` also exposed at `import { source } from 'it-ws'` ## 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.