diff --git a/server/server.go b/server/server.go index 4e440c0..7fddad8 100644 --- a/server/server.go +++ b/server/server.go @@ -6,6 +6,7 @@ import ( "net/http" "strconv" "sync/atomic" + "time" "github.com/dpup/prefab" "github.com/dpup/prefab/logging" @@ -139,6 +140,10 @@ func (s *Server) handleStream(w http.ResponseWriter, r *http.Request) { // Signal when the client disconnects notify := ctx.Done() + // Set up a ticker for heartbeat messages every 30 seconds + heartbeatTicker := time.NewTicker(30 * time.Second) + defer heartbeatTicker.Stop() + // Send an initial message with an additional 1.5k payload. This force buffer // flush so the client knows the connection is open. w.WriteHeader(http.StatusOK) @@ -174,6 +179,13 @@ func (s *Server) handleStream(w http.ResponseWriter, r *http.Request) { http.Error(w, "Server is shutting down", http.StatusServiceUnavailable) return + case <-heartbeatTicker.C: + // Send a heartbeat message + logger.Debug("Sending heartbeat") + heartbeatMsg := fmt.Sprintf("Heartbeat: %s", time.Now().Format(time.RFC3339)) + fmt.Fprintf(w, "event: info\ndata: %s\n\n", heartbeatMsg) + flusher.Flush() + case packet, ok := <-packetChan: if !ok { // Channel closed, probably shutting down diff --git a/web/src/components/ConnectionStatus.tsx b/web/src/components/ConnectionStatus.tsx index a474298..f259bfa 100644 --- a/web/src/components/ConnectionStatus.tsx +++ b/web/src/components/ConnectionStatus.tsx @@ -29,7 +29,7 @@ export const ConnectionStatus: React.FC = ({ text: "Connecting", colorClass: "text-blue-400", }; - } else if (status.includes("Connected")) { + } else if (status.includes("Connected") || status.includes("Heartbeat")) { return { icon: , text: "Connected",