mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
fix(web): refactor pico chat flow and fix proxied websocket URLs (#1639)
- move chat controller, state, protocol, history, and websocket logic into a dedicated chat feature module - improve chat reconnection, session hydration, and send gating based on actual websocket state - preserve gateway status during transient SSE disconnects and update stop state immediately - generate wss websocket URLs behind HTTPS proxies and add backend tests for forwarded proto handling
This commit is contained in:
@@ -67,10 +67,9 @@ export function useGateway() {
|
||||
}
|
||||
|
||||
es.onerror = () => {
|
||||
// EventSource will auto-reconnect
|
||||
updateGatewayStore((prev) =>
|
||||
prev.status === "restarting" ? {} : { status: "unknown" },
|
||||
)
|
||||
// EventSource will auto-reconnect. Preserve the last known gateway
|
||||
// status so transient SSE disconnects do not suppress chat websocket
|
||||
// reconnects while polling catches up.
|
||||
}
|
||||
|
||||
return () => {
|
||||
@@ -105,6 +104,11 @@ export function useGateway() {
|
||||
setLoading(true)
|
||||
try {
|
||||
await stopGateway()
|
||||
updateGatewayStore({
|
||||
status: "stopped",
|
||||
canStart: true,
|
||||
restartRequired: false,
|
||||
})
|
||||
} catch (err) {
|
||||
console.error("Failed to stop gateway:", err)
|
||||
} finally {
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
newChatSession,
|
||||
sendChatMessage,
|
||||
switchChatSession,
|
||||
} from "@/lib/pico-chat-controller"
|
||||
} from "@/features/chat/controller"
|
||||
import { chatAtom } from "@/store/chat"
|
||||
|
||||
const UNIX_MS_THRESHOLD = 1e12
|
||||
@@ -33,7 +33,6 @@ function parseTimestamp(dateRaw: number | string | Date) {
|
||||
return dayjs(dateRaw)
|
||||
}
|
||||
|
||||
// Helper to format message timestamps
|
||||
export function formatMessageTime(dateRaw: number | string | Date): string {
|
||||
const date = parseTimestamp(dateRaw)
|
||||
if (!date.isValid()) {
|
||||
@@ -48,7 +47,6 @@ export function formatMessageTime(dateRaw: number | string | Date): string {
|
||||
return date.format("LT")
|
||||
}
|
||||
|
||||
// Cross-day formatting
|
||||
if (isThisYear) {
|
||||
return date.format("MMM D LT")
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react"
|
||||
|
||||
export function useWebSocket(path: string) {
|
||||
const [message, setMessage] = useState<string>("No messages yet")
|
||||
const [connected, setConnected] = useState(false)
|
||||
const wsRef = useRef<WebSocket | null>(null)
|
||||
|
||||
const connect = useCallback(() => {
|
||||
if (wsRef.current) {
|
||||
wsRef.current.close()
|
||||
}
|
||||
|
||||
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"
|
||||
const url = `${protocol}//${window.location.host}${path}`
|
||||
const socket = new WebSocket(url)
|
||||
|
||||
socket.onopen = () => {
|
||||
setConnected(true)
|
||||
setMessage("Connected to WebSocket server.")
|
||||
}
|
||||
|
||||
socket.onmessage = (event) => {
|
||||
setMessage(event.data)
|
||||
}
|
||||
|
||||
socket.onclose = () => {
|
||||
setConnected(false)
|
||||
setMessage("WebSocket connection closed.")
|
||||
}
|
||||
|
||||
socket.onerror = (error) => {
|
||||
setConnected(false)
|
||||
setMessage("WebSocket error occurred.")
|
||||
console.error("WebSocket Error:", error)
|
||||
}
|
||||
|
||||
wsRef.current = socket
|
||||
}, [path])
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
wsRef.current?.close()
|
||||
}
|
||||
}, [])
|
||||
|
||||
return { message, connected, connect }
|
||||
}
|
||||
Reference in New Issue
Block a user