package main import ( "encoding/json" "fmt" "net/http" "screenmark/screenmark/middleware" "screenmark/screenmark/notifications" "strconv" "github.com/google/uuid" ) /* * TODO: We have channels open every a user sends an image. * We never close these channels. * * What is a reasonable default? Close the channel after 1 minute of inactivity? */ func CreateEventsHandler(notifier *notifications.Notifier[notifications.Notification]) http.HandlerFunc { counter := 0 userSplitters := make(map[string]*notifications.ChannelSplitter[notifications.Notification]) return func(w http.ResponseWriter, r *http.Request) { _userId := r.Context().Value(middleware.USER_ID).(uuid.UUID) if _userId == uuid.Nil { w.WriteHeader(http.StatusUnauthorized) return } userId := _userId.String() w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") // w.(http.Flusher).Flush() if _, exists := notifier.Listeners[userId]; !exists { notifier.Create(userId) } userNotifications := notifier.Listeners[userId] if _, exists := userSplitters[userId]; !exists { splitter := notifications.NewChannelSplitter(userNotifications) userSplitters[userId] = &splitter splitter.Listen() } splitter := userSplitters[userId] id := strconv.Itoa(counter) counter += 1 notifications := splitter.Add(id) defer splitter.Remove(id) for { select { case <-r.Context().Done(): fmt.Fprint(w, "event: close\ndata: Connection closed\n\n") w.(http.Flusher).Flush() return case msg := <-notifications: msgString, err := json.Marshal(msg) if err != nil { w.WriteHeader(http.StatusInternalServerError) return } fmt.Printf("Sending msg %s\n", msgString) fmt.Fprintf(w, "event: data\ndata: %s\n\n", string(msgString)) w.(http.Flusher).Flush() } } } }