Serve /api/ws without Basic auth so the live feed connects
CI/CD / backend (pull_request) Successful in 5m58s
CI/CD / frontend (pull_request) Successful in 5m3s
CI/CD / build (pull_request) Skipped
CI/CD / deploy (pull_request) Skipped
CI/CD / cleanup (pull_request) Skipped

Browsers don't reliably replay Basic-auth credentials on a WebSocket upgrade,
so the dashboard's live feed was stuck on "reconnecting" (only the 5s REST
poll worked). Give /api/ws a higher-priority Traefik router that skips Basic
auth; the backend still requires API_TOKEN, which nginx injects on the
handshake. The deploy now fails closed unless CRYPTO_API_TOKEN is set.

Also: split the nginx /api/ws block so upgrade headers are only set there, and
add reconnect backoff (2s -> 30s) so a failing socket stops hammering.
This commit is contained in:
matitos committed 2026-09-19 12:52:06 +00:00
1 parent 97fbd5901e
commit 3e19612cc0
7 files changed
+101 -4

No files matched your search

+18 -3
View File
@@ -25,17 +25,32 @@ export const deletePreset = (id) => http.delete(`/presets/${id}`).then((r) => r.
export function openSocket({ onMessage, onOpen, onClose }) {
const proto = window.location.protocol === 'https:' ? 'wss' : 'ws'
const url = `${proto}://${window.location.host}/api/ws`
let socket
let retryTimer
let closed = false
let attempt = 0
const schedule = () => {
if (closed) return
// Back off from 2s up to 30s so a persistently failing socket (e.g. auth)
// does not hammer the server, while a brief blip still reconnects fast.
const delay = Math.min(2000 * 2 ** attempt, 30000)
attempt += 1
retryTimer = setTimeout(connect, delay)
}
const connect = () => {
socket = new WebSocket(`${proto}://${window.location.host}/api/ws`)
socket.onopen = () => onOpen?.()
if (closed) return
socket = new WebSocket(url)
socket.onopen = () => {
attempt = 0
onOpen?.()
}
socket.onmessage = (event) => onMessage?.(JSON.parse(event.data))
socket.onclose = () => {
onClose?.()
if (!closed) retryTimer = setTimeout(connect, 2000)
schedule()
}
socket.onerror = () => socket.close()
}