package realtime import ( "encoding/json" "log/slog" "sync" ) type Event struct { Type string `json:"type"` Data any `json:"data"` } type Client struct { send chan []byte } type Hub struct { logger *slog.Logger mu sync.RWMutex clients map[*Client]struct{} } func NewHub(logger *slog.Logger) *Hub { return &Hub{ logger: logger, clients: make(map[*Client]struct{}), } } func (h *Hub) NewClient(buffer int) *Client { return &Client{send: make(chan []byte, buffer)} } func (h *Hub) Register(client *Client) { h.mu.Lock() defer h.mu.Unlock() h.clients[client] = struct{}{} } func (h *Hub) Unregister(client *Client) { h.mu.Lock() defer h.mu.Unlock() if _, ok := h.clients[client]; ok { delete(h.clients, client) close(client.send) } } func (h *Hub) Broadcast(event Event) { payload, err := json.Marshal(event) if err != nil { h.logger.Error("marshal realtime event", "error", err) return } h.mu.RLock() defer h.mu.RUnlock() for client := range h.clients { select { case client.send <- payload: default: h.logger.Warn("dropping realtime event for slow client") } } } func (c *Client) Send() <-chan []byte { return c.send }