Replace EventSource with WebSocket for price streaming
- Switch from SSE EventSource to WebSocket client connecting to btcdata's new /api/price/ws endpoint - Add automatic reconnect on connection loss (3s delay) - Update Dockerfile BTCDATA_URL to use btcdata's new Docker port 4101 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# btcprice
|
# btcprice
|
||||||
|
|
||||||
Bitcoin price tracker UI — Clojure Kit web application. Serves the HTML/Tailwind UI. Connects to btcdata for live price data via SSE.
|
Bitcoin price tracker UI — Clojure Kit web application. Serves the HTML/Tailwind UI. Connects to btcdata for live price data via WebSocket.
|
||||||
|
|
||||||
## Build & Development Commands
|
## Build & Development Commands
|
||||||
|
|
||||||
@@ -36,9 +36,9 @@ btcprice's docker-compose includes btcdata via `include: ../btcdata/docker-compo
|
|||||||
- **Framework:** Kit (Integrant-based)
|
- **Framework:** Kit (Integrant-based)
|
||||||
- **Server:** Undertow
|
- **Server:** Undertow
|
||||||
- **Routing:** Reitit
|
- **Routing:** Reitit
|
||||||
- **Templates:** Hiccup + vanilla JS EventSource
|
- **Templates:** Hiccup + vanilla JS WebSocket
|
||||||
- **Styling:** Tailwind CSS v4
|
- **Styling:** Tailwind CSS v4
|
||||||
- **Data backend:** btcdata (separate service at BTCDATA_URL, default http://localhost:4100)
|
- **Data backend:** btcdata (separate service at BTCDATA_URL, default http://localhost:4100, WebSocket at ws://localhost:4100)
|
||||||
- **No database** — all data comes from btcdata
|
- **No database** — all data comes from btcdata
|
||||||
|
|
||||||
## Source Layout
|
## Source Layout
|
||||||
@@ -58,6 +58,6 @@ src/clj/pmagnus/btcprice/
|
|||||||
│ └── formats.clj # Content negotiation
|
│ └── formats.clj # Content negotiation
|
||||||
└── routes/
|
└── routes/
|
||||||
├── api.clj # /api routes (JSON)
|
├── api.clj # /api routes (JSON)
|
||||||
├── ui.clj # UI routes (HTML + EventSource)
|
├── ui.clj # UI routes (HTML + WebSocket)
|
||||||
└── utils.clj # Route utilities
|
└── utils.clj # Route utilities
|
||||||
```
|
```
|
||||||
|
|||||||
+1
-1
@@ -23,6 +23,6 @@ COPY --from=build /build/target/btcprice-standalone.jar /btcprice/btcprice-stand
|
|||||||
|
|
||||||
EXPOSE 4040
|
EXPOSE 4040
|
||||||
ENV PORT=4040
|
ENV PORT=4040
|
||||||
ENV BTCDATA_URL=http://btcdata:4100
|
ENV BTCDATA_URL=http://btcdata:4101
|
||||||
|
|
||||||
CMD ["java", "-jar", "/btcprice/btcprice-standalone.jar"]
|
CMD ["java", "-jar", "/btcprice/btcprice-standalone.jar"]
|
||||||
|
|||||||
@@ -23,11 +23,15 @@
|
|||||||
(str
|
(str
|
||||||
"document.addEventListener('DOMContentLoaded', function() {\n"
|
"document.addEventListener('DOMContentLoaded', function() {\n"
|
||||||
" var btcdataUrl = '" btcdata-url "';\n"
|
" var btcdataUrl = '" btcdata-url "';\n"
|
||||||
|
" var wsUrl = btcdataUrl.replace(/^http/, 'ws');\n"
|
||||||
" var display = document.getElementById('price-display');\n"
|
" var display = document.getElementById('price-display');\n"
|
||||||
" var source = new EventSource(btcdataUrl + '/api/price/stream');\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
" source.addEventListener('price-update', function(e) {\n"
|
" function connect() {\n"
|
||||||
|
" var ws = new WebSocket(wsUrl + '/api/price/ws');\n"
|
||||||
|
"\n"
|
||||||
|
" ws.onmessage = function(e) {\n"
|
||||||
" var d = JSON.parse(e.data);\n"
|
" var d = JSON.parse(e.data);\n"
|
||||||
|
" if (d.ping) return;\n"
|
||||||
" var price = parseFloat(d.price);\n"
|
" var price = parseFloat(d.price);\n"
|
||||||
" var prevPrice = d.prev_price ? parseFloat(d.prev_price) : null;\n"
|
" var prevPrice = d.prev_price ? parseFloat(d.prev_price) : null;\n"
|
||||||
" var color = 'text-gray-900';\n"
|
" var color = 'text-gray-900';\n"
|
||||||
@@ -44,12 +48,18 @@
|
|||||||
" '<p class=\"text-4xl font-bold ' + color + '\">' + fmt + '</p>' +\n"
|
" '<p class=\"text-4xl font-bold ' + color + '\">' + fmt + '</p>' +\n"
|
||||||
" '<p class=\"text-xs text-gray-400 mt-2\">Updated ' + timeStr + '</p>' +\n"
|
" '<p class=\"text-xs text-gray-400 mt-2\">Updated ' + timeStr + '</p>' +\n"
|
||||||
" '</div></div>';\n"
|
" '</div></div>';\n"
|
||||||
" });\n"
|
" };\n"
|
||||||
"\n"
|
"\n"
|
||||||
" source.onerror = function() {\n"
|
" ws.onclose = function() {\n"
|
||||||
" display.innerHTML = '<div class=\"bg-white rounded-2xl shadow-sm border border-gray-200 p-6\">' +\n"
|
" display.innerHTML = '<div class=\"bg-white rounded-2xl shadow-sm border border-gray-200 p-6\">' +\n"
|
||||||
" '<p class=\"text-center text-red-400 text-sm\">Connection lost. Reconnecting...</p></div>';\n"
|
" '<p class=\"text-center text-red-400 text-sm\">Connection lost. Reconnecting...</p></div>';\n"
|
||||||
|
" setTimeout(connect, 3000);\n"
|
||||||
" };\n"
|
" };\n"
|
||||||
|
"\n"
|
||||||
|
" ws.onerror = function() {};\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
|
" connect();\n"
|
||||||
"});\n"))]))
|
"});\n"))]))
|
||||||
|
|
||||||
(defn- ui-routes [opts]
|
(defn- ui-routes [opts]
|
||||||
|
|||||||
Reference in New Issue
Block a user