package api import ( "fmt" "net/http" "time" "sprintpadawan/lib" ) func handleSSE(w http.ResponseWriter, r *http.Request) { roomID, err := getPathInt(r, "room_id") if err != nil { http.Error(w, "invalid room id", http.StatusBadRequest) return } user, ok := r.Context().Value(userKey).(*lib.User) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") w.Header().Set("X-Accel-Buffering", "no") flusher, ok := w.(http.Flusher) if !ok { http.Error(w, "streaming unsupported", http.StatusInternalServerError) return } ch := make(chan string, 10) addSSEClient(roomID, user.ID, ch) broadcast(roomID, "members") notify := r.Context().Done() heartbeat := time.NewTicker(25 * time.Second) defer heartbeat.Stop() fmt.Fprint(w, ": connected\n\n") flusher.Flush() for { select { case <-notify: removeSSEClient(roomID, ch) broadcast(roomID, "members") return case <-heartbeat.C: fmt.Fprint(w, ": keep-alive\n\n") flusher.Flush() case event := <-ch: fmt.Fprintf(w, "event: %s\ndata: true\n\n", event) flusher.Flush() } } }