react-native-fast-io
Version:
Modern IO for React Native, built on top of Nitro and Web standards
179 lines (171 loc) • 4.94 kB
JavaScript
"use strict";
import { Event, EventTarget, getEventAttributeValue, setEventAttributeValue } from 'event-target-shim';
import { WebSocketManager } from "../native/ws.nitro.js";
import { Blob } from "./blob.js";
var WebSocketReadyState = /*#__PURE__*/function (WebSocketReadyState) {
WebSocketReadyState[WebSocketReadyState["CONNECTING"] = 0] = "CONNECTING";
WebSocketReadyState[WebSocketReadyState["OPEN"] = 1] = "OPEN";
WebSocketReadyState[WebSocketReadyState["CLOSING"] = 2] = "CLOSING";
WebSocketReadyState[WebSocketReadyState["CLOSED"] = 3] = "CLOSED";
return WebSocketReadyState;
}(WebSocketReadyState || {});
/**
* https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.5
*/
const ABNORMAL_CLOSURE = 1006;
/**
* Events
*/
export class MessageEvent extends Event {
constructor(data) {
super('message');
this.data = data;
}
}
export class ErrorEvent extends Event {
constructor(error) {
super('error');
this.error = error;
}
}
export class CloseEvent extends Event {
constructor(code = 0, reason = '') {
super('close');
this.code = code;
this.reason = reason;
}
get wasClean() {
throw new Error('Not implemented');
}
}
/**
* https://websockets.spec.whatwg.org/#interface-definition
*/
export class WebSocket extends EventTarget {
CONNECTING = WebSocketReadyState.CONNECTING;
OPEN = WebSocketReadyState.OPEN;
CLOSING = WebSocketReadyState.CLOSING;
CLOSED = WebSocketReadyState.CLOSED;
binaryType = 'blob';
#readyState = WebSocketReadyState.CONNECTING;
get readyState() {
return this.#readyState;
}
get bufferedAmount() {
throw new Error('Not implemented');
}
get extensions() {
throw new Error('Not implemented');
}
#protocol = '';
get protocol() {
return this.#protocol;
}
constructor(url, protocols = []) {
super();
this.url = url;
this.ws = WebSocketManager.create(url, Array.isArray(protocols) ? protocols : [protocols]);
this.ws.onOpen(protocol => {
this.#readyState = WebSocketReadyState.OPEN;
this.#protocol = protocol;
this.dispatchEvent(new Event('open'));
});
this.ws.onMessage(data => {
this.dispatchEvent(new MessageEvent(data));
});
this.ws.onArrayBuffer(buffer => {
if (this.binaryType === 'blob') {
this.dispatchEvent(new MessageEvent(new Blob([buffer])));
return;
}
this.dispatchEvent(new MessageEvent(buffer));
});
this.ws.onError(message => {
this.dispatchEvent(new ErrorEvent(message));
/**
* Sending `close` frame before proceeding to close the connection
* https://datatracker.ietf.org/doc/html/rfc6455#section-7.1.7
*/
this.#readyState = WebSocketReadyState.CLOSED;
this.dispatchEvent(new CloseEvent(ABNORMAL_CLOSURE));
this.close();
});
this.ws.onClose((code, reason) => {
this.#readyState = WebSocketReadyState.CLOSED;
this.dispatchEvent(new CloseEvent(code, reason));
});
this.ws.connect();
}
/**
* https://websockets.spec.whatwg.org/#dom-websocket-send
*/
send(message) {
if (this.#readyState === WebSocketReadyState.CONNECTING) {
throw new Error('InvalidStateError');
}
if (this.#readyState !== WebSocketReadyState.OPEN) {
return;
}
if (typeof message === 'string') {
this.ws.send(message);
return;
}
if (message instanceof ArrayBuffer) {
this.ws.sendArrayBuffer(message);
return;
}
if (ArrayBuffer.isView(message)) {
this.ws.sendArrayBuffer(message.buffer);
return;
}
if (message instanceof Blob) {
;
(async () => {
const arrayBuffer = await message.arrayBuffer();
this.ws.sendArrayBuffer(arrayBuffer);
})();
return;
}
}
/**
* https://websockets.spec.whatwg.org/#dom-websocket-close
*/
close(code = 1000, reason = '') {
if (this.#readyState === WebSocketReadyState.CLOSING || this.#readyState === WebSocketReadyState.CLOSED) {
return;
}
if (code !== 1000 && (code < 3000 || code > 4999)) {
throw new Error('Invalid close code. Must be 1000 or in range 3000-4999.');
}
this.#readyState = WebSocketReadyState.CLOSING;
this.ws.close(code, reason);
}
ping() {
this.ws.ping();
}
get onopen() {
return getEventAttributeValue(this, 'open');
}
set onopen(value) {
setEventAttributeValue(this, 'open', value);
}
get onmessage() {
return getEventAttributeValue(this, 'message');
}
set onmessage(value) {
setEventAttributeValue(this, 'message', value);
}
get onerror() {
return getEventAttributeValue(this, 'error');
}
set onerror(value) {
setEventAttributeValue(this, 'error', value);
}
get onclose() {
return getEventAttributeValue(this, 'close');
}
set onclose(value) {
setEventAttributeValue(this, 'close', value);
}
}
//# sourceMappingURL=ws.js.map