feat: implement websocket-stream for journal server
Integrate `websocket-stream` to handle MQTT broker upgrades in the CLI and add granular connection status tracking to the UI. - Add `websocket-stream` dependency - Update CLI to use `websocket-stream` for socket upgrades - Enhance `journalStream` store with `connectionStatus` and `connectionError` states - Add visual connection status indicators to `App` and `JournalPanel`
This commit is contained in:
@@ -38,12 +38,17 @@ export const JournalPanel: Component<JournalPanelProps> = (props) => {
|
||||
<div class="flex items-center justify-between px-3 py-2 border-b border-gray-200">
|
||||
<div class="flex items-center gap-2">
|
||||
<h2 class="text-sm font-semibold text-gray-700">Journal</h2>
|
||||
<Show when={stream.connected}>
|
||||
<span
|
||||
class="w-2 h-2 rounded-full bg-green-500"
|
||||
title="Connected"
|
||||
/>
|
||||
</Show>
|
||||
<span
|
||||
class="w-2 h-2 rounded-full"
|
||||
classList={{
|
||||
"bg-gray-400": stream.connectionStatus === "disconnected",
|
||||
"bg-yellow-400 animate-pulse":
|
||||
stream.connectionStatus === "connecting",
|
||||
"bg-green-500": stream.connectionStatus === "connected",
|
||||
"bg-red-500": stream.connectionStatus === "error",
|
||||
}}
|
||||
title={stream.connectionStatus}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={props.onClose}
|
||||
@@ -104,7 +109,10 @@ const ConnectDialog: Component = () => {
|
||||
await hydrateFromServer(sessionId);
|
||||
await connectStream(sessionId, brokerUrl);
|
||||
} catch (e) {
|
||||
setError(e instanceof Error ? e.message : "Connection failed");
|
||||
const msg = e instanceof Error ? e.message : "Connection failed";
|
||||
setError(msg);
|
||||
// If connectStream threw, the error handler also sets connectionStatus to error.
|
||||
// Make sure the error message is captured.
|
||||
} finally {
|
||||
setConnecting(false);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,10 @@ export interface JournalStreamState {
|
||||
revealedPaths: Set<string>;
|
||||
/** MQTT connection status */
|
||||
connected: boolean;
|
||||
/** Granular connection state for UI indicators */
|
||||
connectionStatus: "disconnected" | "connecting" | "connected" | "error";
|
||||
/** Last connection error message, if any */
|
||||
connectionError: string | null;
|
||||
/** This client's identity */
|
||||
myName: string;
|
||||
/** Broker URL, set after connect */
|
||||
@@ -84,6 +88,8 @@ const [state, setState] = createStore<JournalStreamState>({
|
||||
senderSeq: {},
|
||||
revealedPaths: new Set(),
|
||||
connected: false,
|
||||
connectionStatus: "disconnected",
|
||||
connectionError: null,
|
||||
myName: persisted.myName,
|
||||
brokerUrl: persisted.brokerUrl,
|
||||
});
|
||||
@@ -189,6 +195,9 @@ export async function connectStream(
|
||||
): Promise<void> {
|
||||
const { default: mqtt } = await import("mqtt");
|
||||
|
||||
setState("connectionStatus", "connecting");
|
||||
setState("connectionError", null);
|
||||
|
||||
const client = mqtt.connect(brokerUrl, {
|
||||
clientId: `${state.myName}-${Date.now()}`,
|
||||
protocol: brokerUrl.startsWith("wss") ? "wss" : "ws",
|
||||
@@ -200,6 +209,8 @@ export async function connectStream(
|
||||
client.on("connect", () => {
|
||||
_mqttConnected = true;
|
||||
setState("connected", true);
|
||||
setState("connectionStatus", "connected");
|
||||
setState("connectionError", null);
|
||||
setState("brokerUrl", brokerUrl);
|
||||
|
||||
// Persist connection info for next time
|
||||
@@ -251,10 +262,13 @@ export async function connectStream(
|
||||
client.on("close", () => {
|
||||
_mqttConnected = false;
|
||||
setState("connected", false);
|
||||
setState("connectionStatus", "disconnected");
|
||||
});
|
||||
|
||||
client.on("error", (err) => {
|
||||
console.error("[stream] mqtt error:", err);
|
||||
setState("connectionStatus", "error");
|
||||
setState("connectionError", err.message);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -416,6 +430,7 @@ export function disconnectStream(): void {
|
||||
_mqttConnected = false;
|
||||
}
|
||||
setState("connected", false);
|
||||
setState("connectionStatus", "disconnected");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user