package chat import ( "context" "log/slog" "sync" "time" ) type Channel struct { Name string Users map[*User]struct{} Events chan any mu sync.RWMutex } func (c *Channel) Listen(ctx context.Context) { for { select { case <-ctx.Done(): return case ev := <-c.Events: c.processEvent(ev) } } } func (c *Channel) processEvent(ev any) { slog.Info("channel event", slog.String("channel", c.Name), slog.Any("event", ev)) for u := range c.Users { select { case u.Events <- ev: default: } } } func (c *Channel) Join(u *User) { c.mu.Lock() defer c.mu.Unlock() if _, ok := c.Users[u]; ok { return } c.Events <- UserJoined{ User: u, Time: time.Now(), Chan: c, } c.Users[u] = struct{}{} } func (c *Channel) Leave(u *User) { c.mu.Lock() defer c.mu.Unlock() if _, ok := c.Users[u]; !ok { return } c.Events <- UserLeft{ User: u, Time: time.Now(), Chan: c, } delete(c.Users, u) }