Use idiomatic undertow/websocket maps instead of raw WebSocket API

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-06 07:50:53 +01:00
co-authored by Claude Opus 4.6
parent 32a1509482
commit a9b7874f36
2 changed files with 16 additions and 22 deletions
@@ -4,11 +4,12 @@
(defn- wrap-nil-guard (defn- wrap-nil-guard
"Discard responses with no :status — these are artifacts of ring-defaults "Discard responses with no :status — these are artifacts of ring-defaults
middleware wrapping a nil response (e.g., from a raw WebSocket upgrade)." middleware wrapping a nil response (e.g., from a raw WebSocket upgrade).
Passes through :undertow/websocket responses for the adapter to handle."
[handler] [handler]
(fn [request] (fn [request]
(let [resp (handler request)] (let [resp (handler request)]
(when (:status resp) resp)))) (when (or (:status resp) (:undertow/websocket resp)) resp))))
(defn wrap-base [{:keys [site-defaults-config]}] (defn wrap-base [{:keys [site-defaults-config]}]
(fn [handler] (fn [handler]
@@ -3,9 +3,7 @@
[clojure.tools.logging :as log] [clojure.tools.logging :as log]
[integrant.core :as ig]) [integrant.core :as ig])
(:import (:import
[io.undertow.server HttpServerExchange] [io.undertow.websockets.core WebSockets WebSocketChannel]
[io.undertow.websockets WebSocketConnectionCallback WebSocketProtocolHandshakeHandler]
[io.undertow.websockets.core AbstractReceiveListener WebSockets WebSocketChannel]
[java.net URI] [java.net URI]
[java.net.http HttpClient WebSocket$Builder WebSocket$Listener] [java.net.http HttpClient WebSocket$Builder WebSocket$Listener]
[java.util.concurrent CompletableFuture])) [java.util.concurrent CompletableFuture]))
@@ -47,24 +45,19 @@
(.buildAsync (URI. btcdata-ws-url) listener) (.buildAsync (URI. btcdata-ws-url) listener)
(.join)))) (.join))))
(defn- ws-proxy-handler [{:keys [btcdata-url]} req] (defn- ws-proxy-handler [{:keys [btcdata-url]} _req]
(let [^HttpServerExchange exchange (:server-exchange req) (let [btcdata-ws-url (str (.replaceFirst ^String btcdata-url "^http" "ws")
btcdata-ws-url (str (.replaceFirst ^String btcdata-url "^http" "ws")
"/api/price/ws") "/api/price/ws")
callback (proxy [WebSocketConnectionCallback] [] upstream-atom (atom nil)]
(onConnect [_ws-exchange browser-ch] {:undertow/websocket
(log/info "Browser connected, proxying to" btcdata-ws-url) {:on-open
(let [upstream (connect-upstream btcdata-ws-url browser-ch)] (fn [{:keys [^WebSocketChannel channel]}]
;; Listen for browser close to tear down upstream (log/info "Browser connected, proxying to" btcdata-ws-url)
(.set (.getReceiveSetter ^WebSocketChannel browser-ch) (reset! upstream-atom (connect-upstream btcdata-ws-url channel)))
(proxy [AbstractReceiveListener] [] :on-close-message
(onCloseMessage [_this _msg _ch] (fn [_]
(log/debug "Browser closed") (log/debug "Browser closed")
(close-upstream-quietly upstream)))) (close-upstream-quietly @upstream-atom))}}))
(.resumeReceives ^WebSocketChannel browser-ch))))
handler (WebSocketProtocolHandshakeHandler. callback)]
(.handleRequest handler exchange)
nil))
(defn- ws-proxy-routes [opts] (defn- ws-proxy-routes [opts]
[["/ws/price" [["/ws/price"