| 31 | } |
| 32 | |
| 33 | func (w *Watcher) handleWakeEventsSSE(rw http.ResponseWriter, r *http.Request) { |
| 34 | // Set SSE headers |
| 35 | rw.Header().Set("Content-Type", "text/event-stream") |
| 36 | setNoStoreHeaders(rw.Header()) |
| 37 | rw.Header().Set("Connection", "keep-alive") |
| 38 | rw.Header().Set("Access-Control-Allow-Origin", "*") |
| 39 | rw.Header().Set("Access-Control-Allow-Headers", "Cache-Control") |
| 40 | |
| 41 | controller := http.NewResponseController(rw) |
| 42 | ctx := r.Context() |
| 43 | |
| 44 | current, ch, cancel := w.events.SnapshotAndListen() |
| 45 | defer cancel() |
| 46 | |
| 47 | // Send historical events first |
| 48 | for _, evt := range current { |
| 49 | select { |
| 50 | case <-ctx.Done(): |
| 51 | return |
| 52 | default: |
| 53 | err := errors.Join(writeSSE(rw, evt), controller.Flush()) |
| 54 | if err != nil { |
| 55 | log.Err(err).Msg("Failed to write SSE event") |
| 56 | return |
| 57 | } |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | // Listen for new events and send them to client |
| 62 | for { |
| 63 | select { |
| 64 | case evt := <-ch: |
| 65 | err := errors.Join(writeSSE(rw, evt), controller.Flush()) |
| 66 | if err != nil { |
| 67 | log.Err(err).Msg("Failed to write SSE event") |
| 68 | return |
| 69 | } |
| 70 | case <-ctx.Done(): |
| 71 | return |
| 72 | } |
| 73 | } |
| 74 | } |
| 75 | |
| 76 | func (w *Watcher) getFavIcon(ctx context.Context) (result iconfetch.Result, err error) { |
| 77 | r := w.route |