UNPKG

ws-wrapper

Version:

Lightweight WebSocket wrapper lib with socket.io-like event handling, requests, and channels

141 lines (111 loc) 5.59 kB
# ws-wrapper Protocol By default, data passed over the native WebSocket should be valid JSON. [ws-wrapper](https://github.com/bminer/ws-wrapper/) parses inbound data as JSON and determines the message type based on properties in the parsed Object. This can be customized with `messageEncode` / `messageDecode` constructor options. The following message types are defined by ws-wrapper: 1. **Event Dispatch** - Identified by an Object with `a` key but no `i` key. The channel name is optional. ```javascript { "c": "channel_name", "a": ["event_name", "first_arg", "second_arg", "last_arg"] } ``` The client or server can send events. Events are nothing more than an event name and some data, passed as arguments to the event handler. 1. **Request** - Identified by an Object with `a` and `i` keys where `i` refers to the unique request identifier. `i` must be a positive integer. The channel name is optional. ```javascript { "i": 123, "c": "channel_name", "a": ["event_name", "first_arg", "second_arg", "last_arg"] } ``` The client or server can send a Request, which is essentially an Event that needs some sort of server Response. 1. **Response (Resolution)** - Identified by an Object with `i` and `d` keys where `i` is the request identifier and `d` is the response data. ```javascript { "i": 123, "d": {"resolved": "data", "hello": "world"} } ``` 1. **Response (Rejection)** - Identified by an Object with `i` and `e` keys where `i` is the request identifier and `e` is the rejected value. If `_` is set, `e` is an encoded Error object (with at least a `message` key) that is reconstructed as an `Error` instance upon receipt. `null` and `undefined` rejection values are replaced with a default `Error` object. All other values for `e` (strings, numbers, plain objects, etc.) are passed through as-is. ```javascript // Error instance (e.g. throw new Error("oops")) { "i": 123, "e": {"message": "oops"}, "_": 1 } // Any other thrown value (e.g. throw "oops" or throw {code: 42}) { "i": 123, "e": "oops" } ``` 1. **Request Cancellation** - Identified by an Object with `i` and `x` keys where `i` is the request identifier to cancel and `x` is the cancellation reason. The same rules as `e` apply: if `_` is set, `x` is an encoded Error object, and if the reason is nullish, a default Error is sent. Introduced in ws-wrapper v4. ```javascript // Default (no reason provided) { "i": 123, "x": {"message": "Request aborted"}, "_": 1 } // String reason { "i": 123, "x": "user cancelled" } ``` When a request is cancelled using an `AbortSignal`, a cancellation message is sent to the remote end. The `AbortSignal.reason` is forwarded as `x` (with `_: 1` when it is an Error instance). `null` and `undefined` reasons are replaced with a default `RequestAbortedError` (same rule as for `e`). All other reason values are sent exactly as-is. The remote end can use this information to stop processing the request and clean up any resources. Event handlers on the remote end can access the `AbortSignal` via `this.signal` to implement cooperative cancellation. Note: `{i, x}` is only meaningful while the handler is still processing the request (i.e. before it responds). Once a handler responds with an anonymous channel (`{i, h: 1}`), the original request is fully resolved and any subsequent `{i, x}` message with the same `i` is silently ignored. To close an anonymous channel after it has been created, use the **Anonymous Channel Abort** (`{h, x}`) message instead. 1. **Anonymous Channel Creation** - Identified by an Object with `i` and `h` keys where `h` is truthy. Sent by the handler's side in response to a request when the handler returns an anonymous channel via `this.channel()`. The channel ID is inferred from `i` (the original request ID). ```javascript { "i": 123, "h": 1 } ``` 1. **Anonymous Channel Event** - Like a named-channel event but uses `h` instead of `c`. The `h` value is the channel ID (a number matching the original request ID). ```javascript { "h": 123, "a": ["event_name", "arg1", "arg2"] } ``` 1. **Anonymous Channel Request** - Like a named-channel request but uses `h` instead of `c`. ```javascript { "i": 456, "h": 123, "a": ["event_name", "arg1"] } ``` Responses to requests made on anonymous channels use the standard **Response** format (`{i, d}` or `{i, e}`); no `h` field is needed in the response. 1. **Anonymous Channel Abort** - Identified by an Object with `h` and `x` keys. Can be sent by **either** side to abort the anonymous channel identified by `h`. The same encoding rules for `x` and `_` apply as for **Request Cancellation** above. Receiving this message closes the local anonymous channel (via `chan.close()`). ```javascript // Error abort (e.g. chan.abort(new Error("done"))) { "h": 123, "x": {"message": "done"}, "_": 1 } // Default abort (e.g. chan.abort()) { "h": 123, "x": {"message": "Request aborted"}, "_": 1 } ``` If the message received by the WebSocket is not valid JSON or if the parsed Object does not match one of the above message types, then the message is simply ignored by ws-wrapper. Also if the JSON message contains a `ws-wrapper` property with the value `false`, the message will be ignored. This allows other libraries to use the same WebSocket and send messages that will not be processed by ws-wrapper.