UNPKG

@renegade-fi/core

Version:
185 lines 6.25 kB
import { SIG_EXPIRATION_BUFFER_MS } from "../constants.js"; import { SocketClosedError, WebSocketConnectionError, WebSocketRequestError, } from "../errors/websocket.js"; import { addExpiringAuthToHeaders } from "./http.js"; export var AuthType; (function (AuthType) { AuthType["None"] = "None"; AuthType["Wallet"] = "Wallet"; AuthType["Admin"] = "Admin"; })(AuthType || (AuthType = {})); export class RelayerWebsocket { constructor(params) { Object.defineProperty(this, "config", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "topic", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "authType", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "onmessage", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "onopenCallback", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "oncloseCallback", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "onerrorCallback", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "ws", { enumerable: true, configurable: true, writable: true, value: null }); Object.defineProperty(this, "handleOpen", { enumerable: true, configurable: true, writable: true, value: (event) => { if (!this.ws) return; const message = this.buildSubscriptionMessage(); this.request(message); return this.onopenCallback?.call(this.ws, event); } }); Object.defineProperty(this, "handleClose", { enumerable: true, configurable: true, writable: true, value: (event) => { this.cleanup(); return this.oncloseCallback?.call(this.ws, event); } }); Object.defineProperty(this, "handleError", { enumerable: true, configurable: true, writable: true, value: (event) => { this.cleanup(); return this.onerrorCallback?.call(this.ws, event); } }); this.config = params.config; this.topic = params.topic; this.authType = params.authType; this.onmessage = params.onmessage; this.onopenCallback = params.onopenCallback ?? null; this.oncloseCallback = params.oncloseCallback ?? null; this.onerrorCallback = params.onerrorCallback ?? null; } // -------------- // | Public API | // -------------- async connect() { if (this.ws) { throw new Error("WebSocket connection attempt aborted: already connected."); } const WebSocket = await import("isows").then((module) => module.WebSocket); const url = this.config.getWebsocketBaseUrl(); this.ws = new WebSocket(url); this.ws.addEventListener("open", this.handleOpen); this.ws.addEventListener("message", this.onmessage); this.ws.addEventListener("close", this.handleClose); this.ws.addEventListener("error", this.handleError); // Wait for the socket to open. if (this.ws?.readyState === WebSocket.CONNECTING) { await new Promise((resolve, reject) => { if (!this.ws) return; this.ws.onopen = (event) => resolve(event); this.ws.onerror = (error) => reject(new WebSocketConnectionError({ url, cause: error, })); }); } } close() { if (!this.ws) { return; } const message = this.buildUnsubscriptionMessage(); this.request(message); this.ws.close(); } // --------------- // | Private API | // --------------- request(message) { if (!this.ws || this.ws.readyState !== this.ws.OPEN) { throw new WebSocketRequestError({ body: message, url: this.ws?.url || "", cause: new SocketClosedError({ url: this.ws?.url }), }); } this.ws?.send(JSON.stringify(message)); } buildSubscriptionMessage() { const body = { method: "subscribe", topic: this.topic, }; if (this.authType === AuthType.None) { return { body }; } const headers = this.buildAuthHeaders(body); return { headers, body, }; } buildUnsubscriptionMessage() { return { body: { method: "unsubscribe", topic: this.topic, }, }; } buildAuthHeaders(body) { const symmetricKey = this.config.getSymmetricKey(this.authType); return addExpiringAuthToHeaders(this.config, body.topic, {}, // Headers JSON.stringify(body), symmetricKey, SIG_EXPIRATION_BUFFER_MS); } cleanup() { // Remove all event listeners before nullifying the reference if (this.ws) { this.ws.removeEventListener("open", this.handleOpen); this.ws.removeEventListener("message", this.onmessage); this.ws.removeEventListener("close", this.handleClose); this.ws.removeEventListener("error", this.handleError); } // Nullify the WebSocket instance this.ws = null; } } //# sourceMappingURL=websocket.js.map