func (r *Relay) Close() {
	r.mu.Lock()
	defer r.mu.Unlock()
	for _, client := range r.clients {
		r.closeRelay(client)
	}
	r.clients = nil
}
Close closes a relay.
This operation can be safely called in the meantime as Listener.Close()
package broadcast
import (
	"context"
	"sync"
)
type Relay struct {
	mu      sync.RWMutex
	n       uint32
	clients map[uint32]*Listener
}
func NewRelay() *Relay {
	return &Relay{
		clients: make(map[uint32]*Listener),
	}
}
func (r *Relay) Notify() {
	r.mu.RLock()
	defer r.mu.RUnlock()
	for _, client := range r.clients {
		client.ch <- struct{}{}
	}
}
func (r *Relay) NotifyCtx(ctx context.Context) {
	r.mu.RLock()
	defer r.mu.RUnlock()
	for _, client := range r.clients {
		select {
		case client.ch <- struct{}{}:
		case <-ctx.Done():
			return
		}
	}
}
func (r *Relay) Broadcast() {
	r.mu.RLock()
	defer r.mu.RUnlock()
	for _, client := range r.clients {
		select {
		case client.ch <- struct{}{}:
		default:
		}
	}
}
func (r *Relay) Listener(capacity int) *Listener {
	r.mu.Lock()
	defer r.mu.Unlock()
	listener := &Listener{
		ch:    make(chan struct{}, capacity),
		id:    r.n,
		relay: r,
	}
	r.clients[r.n] = listener
	r.n++
	return listener
}