package main import ( "fmt" "log" "net/http" "sync" "time" "github.com/gin-gonic/gin" ) type Message struct { Data interface{} `json:"data"` Id string `json:"id"` } type Client struct { Channel chan Message `json:"clients"` } var ( clients = make(map[*Client]bool) clientsMutex sync.Mutex broadcast = make(chan Message) ) func SSEHandler(c *gin.Context) { client := &Client{ Channel: make(chan Message), } log.Printf("events: %+v", client) AddClient(client) defer unregisterClient(client) log.Printf("Client %s connected", client) 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") for { select { case msg := <-client.Channel: fmt.Fprintf(c.Writer, "data: %s\n\n", msg.Data) c.Writer.Flush() case <-c.Writer.CloseNotify(): return } } } func AddClient(client *Client) { clientsMutex.Lock() clients[client] = true clientsMutex.Unlock() } func unregisterClient(client *Client) { clientsMutex.Lock() delete(clients, client) close(client.Channel) clientsMutex.Unlock() } func SendMsg(c *gin.Context) { var msg Message c.ShouldBind(&msg) msg.Id = time.Now().Format(time.RFC3339) broadcast <- msg c.JSON(http.StatusOK, gin.H{"status": "sent"}) } func handleMessages() { for { msg := <-broadcast clientsMutex.Lock() for client := range clients { client.Channel <- msg } clientsMutex.Unlock() } }