Files

83 lines
1.4 KiB
Go
Raw Permalink Normal View History

2026-05-23 17:17:56 -07:00
package tools
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"
"sync"
"time"
)
var (
ErrEventsUnsupported = errors.New("events unsupported")
)
type EventHelper struct {
m sync.Mutex
c context.Context
w http.ResponseWriter
r *http.Request
f http.Flusher
}
func NewEventHelper(ctx context.Context, w http.ResponseWriter, r *http.Request) (*EventHelper, error) {
// Setup Connection
flusher, ok := w.(http.Flusher)
if !ok {
return nil, ErrEventsUnsupported
}
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
sse := &EventHelper{f: flusher, c: ctx, w: w, r: r}
// Heartbeat Generator
go func(h *EventHelper) {
t := time.NewTicker(5 * time.Second)
defer t.Stop()
for {
select {
case <-h.c.Done():
return
case <-t.C:
h.m.Lock()
fmt.Fprintf(h.w, ": ping\n\n")
h.f.Flush()
h.m.Unlock()
}
}
}(sse)
return sse, nil
}
func (h *EventHelper) SendJSON(eventName string, eventData any) {
b, err := json.Marshal(map[string]any{
"name": eventName,
"data": eventData,
})
if err != nil {
return
}
h.m.Lock()
fmt.Fprintf(h.w, "data: %s\n\n", b)
h.f.Flush()
h.m.Unlock()
}
func (h *EventHelper) SendServerError(err error) {
SendServerError(nil, h.r, err)
h.SendClientError(ERROR_GENERIC_SERVER)
}
func (h *EventHelper) SendClientError(err APIError) {
h.SendJSON("error", err)
}