UNPKG

it-ws

Version:

Simple async iterables for websocket client connections

86 lines 3.27 kB
import { EventIterator } from 'event-iterator'; import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'; // copied from github.com/feross/buffer // Some ArrayBuffers are not passing the instanceof check, so we need to do a bit more work :( function isArrayBuffer(obj) { return (obj instanceof ArrayBuffer) || (obj?.constructor?.name === 'ArrayBuffer' && typeof obj?.byteLength === 'number'); } export default (socket) => { socket.binaryType = 'arraybuffer'; const connected = async () => { await new Promise((resolve, reject) => { if (isConnected) { resolve(); return; } if (connError != null) { reject(connError); return; } const cleanUp = (cont) => { socket.removeEventListener('open', onOpen); socket.removeEventListener('error', onError); cont(); }; const onOpen = () => { cleanUp(resolve); }; const onError = (event) => { cleanUp(() => { reject(event.error ?? new Error(`connect ECONNREFUSED ${socket.url}`)); }); }; socket.addEventListener('open', onOpen); socket.addEventListener('error', onError); }); }; const source = (async function* () { const messages = new EventIterator(({ push, stop, fail }) => { const onMessage = (event) => { let data = null; if (typeof event.data === 'string') { data = uint8ArrayFromString(event.data); } if (isArrayBuffer(event.data)) { data = new Uint8Array(event.data); } if (event.data instanceof Uint8Array) { data = event.data; } if (data == null) { return; } push(data); }; const onError = (event) => { fail(event.error ?? new Error('Socket error')); }; socket.addEventListener('message', onMessage); socket.addEventListener('error', onError); socket.addEventListener('close', stop); return () => { socket.removeEventListener('message', onMessage); socket.removeEventListener('error', onError); socket.removeEventListener('close', stop); }; }, { highWaterMark: Infinity }); await connected(); for await (const chunk of messages) { yield isArrayBuffer(chunk) ? new Uint8Array(chunk) : chunk; } }()); let isConnected = socket.readyState === 1; let connError; socket.addEventListener('open', () => { isConnected = true; connError = null; }); socket.addEventListener('close', () => { isConnected = false; connError = null; }); socket.addEventListener('error', event => { if (!isConnected) { connError = event.error ?? new Error(`connect ECONNREFUSED ${socket.url}`); } }); return Object.assign(source, { connected }); }; //# sourceMappingURL=source.js.map