Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions src/shared/utils/wsPath.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,61 @@ export function resolveLiveWsPublicUrl(env: NodeJS.ProcessEnv = process.env): st
export function getLiveWsPath(): string {
return deriveLiveWsPath(resolveLiveWsPublicUrl() ?? undefined);
}

/** A port the handshake may report, or null when it is not usable. */
export function sanitizeLiveWsPort(port: unknown): number | null {
const value = typeof port === "string" ? Number(port) : port;
if (typeof value !== "number" || !Number.isInteger(value)) return null;
return value > 0 && value < 65536 ? value : null;
}

export interface LiveWsUrlParts {
/** Explicit `wsUrl` passed by the caller - always wins. */
explicit?: string | null;
/** `live.publicUrl` from the handshake - a complete URL, used as-is. */
handshakeUrl?: string | null;
/** `live.port` from the handshake, i.e. the running LIVE_WS_PORT. */
handshakePort?: number | null;
/** `live.path` from the handshake. */
handshakePath?: string | null;
/** The compiled-in default, used for everything the handshake does not say. */
defaultUrl: string;
}

/**
* Resolve the live dashboard WebSocket URL.
*
* The handshake reports the port the live server is actually listening on, but
* the client read only `publicUrl` and `path` from it. An operator who moved
* the server with `LIVE_WS_PORT` still got the compiled-in 20132, and the
* dashboard sat on "Live disabled - WebSocket disconnected" with no way to
* correct it short of rebuilding the image (#11331).
*
* Precedence: an explicit `wsUrl` wins, then a complete `publicUrl` from the
* handshake, then the default URL with whatever port and path the handshake
* reported applied to it.
*/
export function resolveLiveWsUrl({
explicit,
handshakeUrl,
handshakePort,
handshakePath,
defaultUrl,
}: LiveWsUrlParts): string {
if (explicit) return explicit;
if (handshakeUrl) return handshakeUrl;

const port = sanitizeLiveWsPort(handshakePort);
const path =
typeof handshakePath === "string" && handshakePath.startsWith("/") ? handshakePath : null;
if (port === null && path === null) return defaultUrl;

try {
const url = new URL(defaultUrl);
if (port !== null) url.port = String(port);
if (path !== null) url.pathname = path;
return url.toString();
} catch {
return defaultUrl;
}
}