WebSocketJSONStream
A nodejs stream wrapper for WebSocket connections. It works with browser WebSockets too.
Usage
const WebSocket = require('ws')
const WebSocketJSONStream = require('@teamwork/websocket-json-stream')
const stream = new WebSocketJSONStream(new WebSocket(url))
new WebSocket.Server({ server }).on('connection', ws => {
const stream = new WebSocketJSONStream(ws)
})
See example.js for a working usage example.
Error Handling
WebSocket error events are not handled by this module, so you should handle them yourself to avoid crashing the process unnecessarily in nodejs.
When writing to a stream when its associated WebSocket is already CLOSING or CLOSED, the stream emits an error event with the name
property value equal to Error [ERR_CLOSED]
.
Closing a WebSocket via its stream
Calling stream.end()
or stream.destroy()
will close the WebSocket connection.
When a WebSocket is closed either by the server or the client, a CloseEvent
will be emitted. CloseEvents have both a numeric code
and a string reason
property that may be used to indicate the type of closure.
stream.end()
Calling stream.end()
will close the WebSocket with the code 1000
and reason 'stream end'
. 1000
indicates a normal closure, meaning that the purpose for which the connection was established has been fulfilled. (https://tools.ietf.org/html/rfc6455#section-7.4.1)
Clients may implement this to mean that the server is closing the stream intentionally, and the client should not automatically reconnect.
const stream = new WebSocketJSONStream(ws)
stream.end()
The code 1000
may also be used when calling the webSocket.close(code)
method of WebSockets in browsers.
stream.destroy()
Calling stream.destroy()
without an error object will close the stream without a code. This results in the client emitting a CloseEvent that has code 1005
and reason ''
. 1005
is a reserved value and MUST NOT be set as a status code in a Close control frame by an endpoint. It is designated for use in applications expecting a status code to indicate that no status code was actually present. (https://tools.ietf.org/html/rfc6455#section-7.4.1)
const stream = new WebSocketJSONStream(ws)
stream.destroy()
Calling webSocket.close()
method of WebSockets in browsers without any arguments will produce a CloseEvent with the code 1005
. A reason string cannot be provided together with the code 1005
.
stream.destroy(error)
Calling stream.destroy(error)
with an error will emit an 'error'
event and close the stream with the code 1011
and reason 'stream error'
by default. 1011
indicates that a remote endpoint is terminating the connection because it encountered an unexpected condition that prevented it from fulfilling the request. (http://www.rfc-editor.org/errata_search.php?eid=3227)
const stream = new WebSocketJSONStream(ws)
stream.on('error', (error) => {
})
const error = new Error('Unexpected server error')
stream.destroy(error)
The code 1011
cannot be used when calling the webSocket.close(code)
method of WebSockets in browsers.
error.closeCode
and error.closeReason
Custom close code and reason values may be sent by setting error.closeCode
or error.closeReason
properties on the error argument passed to stream.destroy(error)
. For example:
const stream = new WebSocketJSONStream(ws)
stream.on('error', (error) => {
})
class CustomStreamError extends Error {
constructor(message) {
super(message)
this.name = this.constructor.name
Error.captureStackTrace(this, this.constructor)
this.closeCode = null
this.closeReason = null
}
}
const error = new CustomStreamError('Example error')
error.closeCode = 4000
error.closeReason = 'custom reason'
stream.destroy(error)
Browser WebSockets allow custom close codes between 3000 and 4999.