package main import ( "crypto/sha256" "fmt" "io" "log" "net/http" "slices" "strconv" "strings" "github.com/gin-gonic/gin" ) func InitSse() *SseStream { sse := &SseStream{ Clients: make([]Client, 0), MsgId: map[string]int{}, Events: events, } for i := range events { sse.MsgId[events[i]] = 0 } return sse } func (sse *SseStream) SseHeadersMiddleware() gin.HandlerFunc { return func(c *gin.Context) { c.Writer.Header().Set("Content-Type", "text/event-stream") c.Writer.Header().Set("Cache-Control", "no-cache") c.Writer.Header().Set("Connection", "keep-alive") c.Writer.Header().Set("Transfer-Encoding", "chunked") c.Next() } } func (sse *SseStream) Stream(c *gin.Context) { client := &Client{ Ip: c.Request.RemoteAddr, Chan: make(ClientChan), Events: c.QueryArray("event"), } log.Printf("events: %+v", client.Events) client.Id = generateClientId(client.Ip, client.Events, 8) sse.AddClient(*client) defer func() { sse.RemoveClient(client) close(client.Chan) log.Printf("Client %s disconnected", client.Ip) }() log.Printf("Client %s connected - TOT %+v", client.Ip, sse.Clients) c.Stream(func(w io.Writer) bool { msg, ok := <-client.Chan if !ok { return false } c.SSEvent(msg.Event, msg) return true }) } func (sse *SseStream) AddClient(client Client) { sse.Clients = append(sse.Clients, client) } func (sse *SseStream) RemoveClient(client *Client) { for i, c := range sse.Clients { if c.Id == client.Id { sse.Clients = append(sse.Clients[:i], sse.Clients[i+1:]...) return } } } func (sse *SseStream) Send(msg Message) { sse.MsgId[msg.Event]++ msg.Id = strconv.Itoa(sse.MsgId[msg.Event]) for _, client := range sse.Clients { if slices.Contains(client.Events, msg.Event) || slices.Contains(client.Events, "*") { client.Chan <- msg log.Printf("sent: %+v -> %+v", msg, client.Ip) } } } func (sse *SseStream) SendMsg(c *gin.Context) { var msg Message c.ShouldBind(&msg) sse.Send(msg) c.JSON(http.StatusOK, gin.H{"status": "msg"}) } func generateClientId(ip string, events []string, len int) string { str := ip + strings.Join(events, "|") id := sha256.Sum256([]byte(str)) return fmt.Sprintf("%X", id)[0:len] }