package core import ( "errors" "github.com/sirupsen/logrus" "golang.org/x/sync/semaphore" ) type dispatcher struct { listeners map[int16]chan string counter int16 sem *semaphore.Weighted } func NewDispatcher() *dispatcher { return &dispatcher{ listeners: make(map[int16]chan string), counter: 0, sem: semaphore.NewWeighted(1), } } func (d *dispatcher) SetStreaming(s bool) bool { if ok := d.sem.TryAcquire(1); s && ok { // if i want to turn on and can get semaphore then return success return true } else if !s && !ok { // if i want to turn off and cant get semaphore, i can safely turn off by releasing semaphore and return success d.sem.Release(1) return true } return false } func (d *dispatcher) IsClosed() bool { if d.sem.TryAcquire(1) { d.sem.Release(1) return true } return false } func (d *dispatcher) Publish(message string) { if d.IsClosed() { return } logrus.Tracef("publishing to %v listeners\n", len(d.listeners)) logrus.Trace(message) for _, ch := range d.listeners { select { case ch <- message: default: logrus.Traceln("dispatcher: skip closed channel") } } } func (d *dispatcher) Subscribe() (id int16, receiver <-chan string) { key := d.counter d.counter++ rec := make(chan string) d.listeners[key] = rec return key, rec } func (d *dispatcher) Unsubscribe(id int16) error { receiver, ok := d.listeners[id] if !ok { return errors.New("no subscription with id") } delete(d.listeners, id) close(receiver) return nil }