From 8659a579f87b4450e492b28e0cbd53a4cd86cc89 Mon Sep 17 00:00:00 2001 From: michael1011 Date: Thu, 15 Aug 2024 19:16:37 +0200 Subject: [PATCH] feat: WebSocket fallback URL On regtest, when the backend is run without nginx and the WebSocket is on a different port than the rest of the API, we need to use a different endpoint for connecting to the WebSocket --- src/components/CreateButton.tsx | 7 ++- src/components/SwapChecker.tsx | 85 ++++++++++++++++++++------------- src/config.ts | 5 +- src/configs/regtest.json | 3 +- 4 files changed, 62 insertions(+), 38 deletions(-) diff --git a/src/components/CreateButton.tsx b/src/components/CreateButton.tsx index e80889db..a948c06e 100644 --- a/src/components/CreateButton.tsx +++ b/src/components/CreateButton.tsx @@ -269,8 +269,11 @@ export const CreateButton = () => { const buttonClick = async () => { setButtonDisable(true); - await create(); - setButtonDisable(false); + try { + await create(); + } finally { + setButtonDisable(false); + } }; const getButtonLabel = (label: ButtonLabelParams) => { diff --git a/src/components/SwapChecker.tsx b/src/components/SwapChecker.tsx index 18017d94..59392d11 100644 --- a/src/components/SwapChecker.tsx +++ b/src/components/SwapChecker.tsx @@ -2,6 +2,7 @@ import { OutputType } from "boltz-core"; import log from "loglevel"; import { createEffect, onCleanup, onMount } from "solid-js"; +import { config } from "../config"; import { RBTC } from "../consts/Assets"; import { SwapType } from "../consts/Enums"; import { @@ -41,45 +42,20 @@ class BoltzWebSocket { constructor( private readonly url: string, + private readonly wsFallback: string | undefined, private readonly relevantIds: Set, private readonly prepareSwap: (id: string, status: any) => void, private readonly claimSwap: (id: string, status: any) => Promise, ) {} public connect = () => { - this.isClosed = false; - clearTimeout(this.reconnectTimeout); - this.ws?.close(); - this.ws = new WebSocket( - `${BoltzWebSocket.formatWsUrl(this.url)}/v2/ws`, - ); - - this.ws.onopen = () => { - this.subscribeUpdates(Array.from(this.relevantIds.values())); - }; - this.ws.onclose = () => { - log.warn(`ws ${this.url} closed`); - this.handleClose(); - }; - this.ws.onmessage = async (msg) => { - const data = JSON.parse(msg.data); - if (data.event === "pong" || data.event === "ping") { - return; + log.debug("Opening WebSocket"); + this.openWebSocket(`${this.url}/v2/ws`).catch(() => { + if (this.wsFallback !== undefined) { + log.debug("Opening fallback WebSocket"); + this.openWebSocket(this.wsFallback).then().catch(); } - - log.debug(`ws ${this.url} message`, data); - - if (data.event === "update" && data.channel === "swap.update") { - const swapUpdates = data.args as SwapStatus[]; - for (const status of swapUpdates) { - this.relevantIds.add(status.id); - this.prepareSwap(status.id, status); - await this.swapClaimLock.acquire(() => - this.claimSwap(status.id, status), - ); - } - } - }; + }); }; public close = () => { @@ -106,6 +82,49 @@ class BoltzWebSocket { ); }; + private openWebSocket = async (url: string) => { + this.isClosed = false; + clearTimeout(this.reconnectTimeout); + this.ws?.close(); + + return new Promise((resolve, reject) => { + this.ws = new WebSocket(BoltzWebSocket.formatWsUrl(url)); + + this.ws.onopen = () => { + this.subscribeUpdates(Array.from(this.relevantIds.values())); + }; + this.ws.onclose = (error) => { + log.warn("WebSocket closed", error); + this.handleClose(); + + if (error.wasClean) { + resolve(); + } else { + reject(error); + } + }; + this.ws.onmessage = async (msg) => { + const data = JSON.parse(msg.data); + if (data.event === "pong" || data.event === "ping") { + return; + } + + log.debug("WebSocket message", data); + + if (data.event === "update" && data.channel === "swap.update") { + const swapUpdates = data.args as SwapStatus[]; + for (const status of swapUpdates) { + this.relevantIds.add(status.id); + this.prepareSwap(status.id, status); + await this.swapClaimLock.acquire(() => + this.claimSwap(status.id, status), + ); + } + } + }; + }); + }; + private handleClose = () => { // Don't reconnect when it has been closed manually if (this.isClosed) { @@ -249,9 +268,9 @@ export const SwapChecker = () => { s.claimTx === undefined), ); - log.debug(`Opening WebSocket: ${getApiUrl()}`); ws = new BoltzWebSocket( getApiUrl(), + config.apiUrl.wsFallback, new Set(swapsToCheck.map((s) => s.id)), prepareSwap, claimSwap, diff --git a/src/config.ts b/src/config.ts index b21bf959..11e10c09 100644 --- a/src/config.ts +++ b/src/config.ts @@ -27,7 +27,6 @@ const defaults = { }; type Asset = { - apiUrl?: Url; network?: any; blockExplorerUrl?: Url; @@ -45,7 +44,9 @@ type Url = { }; export type Config = { - apiUrl?: Url; + // The wsFallback is used on regtest when the backend is being run without + // nginx and the WebSocket is on a different port than the rest of the API + apiUrl?: Url & { wsFallback?: string }; network?: "mainnet" | "testnet" | "regtest"; isBoltzClient?: boolean; boltzClientApiUrl?: string; diff --git a/src/configs/regtest.json b/src/configs/regtest.json index a45aae77..02bb0cd7 100644 --- a/src/configs/regtest.json +++ b/src/configs/regtest.json @@ -2,7 +2,8 @@ "network": "regtest", "loglevel": "debug", "apiUrl": { - "normal": "http://localhost:9001" + "normal": "http://localhost:9001", + "wsFallback": "http://localhost:9004" }, "assets": { "BTC": {