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:
@@ -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"
|
||||||
|
|||||||
Reference in New Issue
Block a user