package nexus import ( "sync" "dynatron.me/x/stillbox/pkg/gordio/calls" "dynatron.me/x/stillbox/pkg/pb" "github.com/rs/zerolog/log" ) type Nexus struct { sync.RWMutex clients map[*client]struct{} *wsManager callCh chan *calls.Call } type Registry interface { NewClient(Connection) Client Register(Client) Unregister(Client) } func New() *Nexus { n := &Nexus{ clients: make(map[*client]struct{}), callCh: make(chan *calls.Call), } n.wsManager = newWsManager(n) return n } func (n *Nexus) Go(done <-chan struct{}) { for { select { case call, ok := <-n.callCh: log.Debug().Msg("call received from ch") if !ok { return } log.Debug().Msg("broadcasting call") n.broadcastCallToClients(call) case <-done: return } } } func (n *Nexus) BroadcastCall(call *calls.Call) { n.callCh <- call log.Debug().Msg("call sent to ch") } func (n *Nexus) broadcastCallToClients(call *calls.Call) { message := &pb.Message{ ToClientMessage: &pb.Message_Call{Call: call.ToPB()}, } n.Lock() defer n.Unlock() for cl, _ := range n.clients { log.Debug().Msg("sending") if cl.Send(message) { log.Debug().Msg("channel was closed") // we already hold the lock, and the channel is closed anyway delete(n.clients, cl) } } } func (n *Nexus) Register(c Client) { n.Lock() defer n.Unlock() n.clients[c.(*client)] = struct{}{} } func (n *Nexus) Unregister(c Client) { n.Lock() defer n.Unlock() cl := c.(*client) delete(n.clients, cl) }