github.com/leg100/ots@v0.0.7-0.20210919080622-034055ced4bd/inmem/event.go (about) 1 package inmem 2 3 import ( 4 "sync" 5 6 "github.com/go-logr/logr" 7 "github.com/leg100/ots" 8 ) 9 10 // EventBufferSize is the buffer size of the channel for each subscription. 11 const EventBufferSize = 16 12 13 var _ ots.EventService = (*EventService)(nil) 14 15 type EventService struct { 16 mu sync.Mutex 17 subs map[string]*Subscription 18 logr.Logger 19 } 20 21 // NewEventService returns a new instance of EventService. 22 func NewEventService(logger logr.Logger) *EventService { 23 return &EventService{ 24 subs: make(map[string]*Subscription), 25 Logger: logger.WithValues("component", "event_service"), 26 } 27 } 28 29 func (e *EventService) Publish(event ots.Event) { 30 for _, sub := range e.subs { 31 select { 32 case sub.c <- event: 33 default: 34 e.unsubscribe(sub) 35 } 36 } 37 } 38 39 func (e *EventService) Subscribe(id string) ots.Subscription { 40 // Create new subscription 41 sub := &Subscription{ 42 service: e, 43 c: make(chan ots.Event, EventBufferSize), 44 } 45 46 // Add to list of user's subscriptions. Subscriptions are stored as a map 47 // for each user so we can easily delete them. 48 e.subs[id] = sub 49 50 e.Info("subscription created", "subscriber", id) 51 52 return sub 53 } 54 55 // Unsubscribe disconnects sub from the service. 56 func (e *EventService) Unsubscribe(sub *Subscription) { 57 e.mu.Lock() 58 defer e.mu.Unlock() 59 e.unsubscribe(sub) 60 } 61 62 func (e *EventService) unsubscribe(sub *Subscription) { 63 // Only close the underlying channel once. Otherwise Go will panic. 64 sub.once.Do(func() { 65 close(sub.c) 66 }) 67 68 delete(e.subs, sub.id) 69 } 70 71 // Subscription represents a stream of events. 72 type Subscription struct { 73 service *EventService // service subscription was created from 74 id string // Uniquely identifies subscription 75 76 c chan ots.Event // channel of events 77 once sync.Once // ensures c only closed once 78 } 79 80 // Close disconnects the subscription from the service it was created from. 81 func (s *Subscription) Close() error { 82 s.service.Unsubscribe(s) 83 return nil 84 } 85 86 // C returns a receive-only channel of user-related events. 87 func (s *Subscription) C() <-chan ots.Event { 88 return s.c 89 }