package events import "sync" // Bus passes each published Event to every subscriber. Its zero value is // ready to use, and it is safe for concurrent use. type Bus struct { mu sync.RWMutex handlers []func(Event) } // Event is something that happened, for subscribers to react to. Type names // it (e.g. OpportunitiesUpdated) and says what Payload is. type Event struct { Type string Payload any } // Subscribe makes handler receive every event published from now on. // Subscribe before anything publishes, so no event is missed. func (b *Bus) Subscribe(handler func(Event)) { b.mu.Lock() defer b.mu.Unlock() b.handlers = append(b.handlers, handler) } // Publish passes event to every subscriber in turn, in the order they // subscribed, and returns once they all have. Handlers are called on the // publisher's goroutine, so they mustn't block; one with slow work to do // should queue it. Publish may be called from several goroutines at once. func (b *Bus) Publish(event Event) { b.mu.RLock() handlers := b.handlers b.mu.RUnlock() // Called outside the lock, so a handler may itself subscribe or publish. for _, handler := range handlers { handler(event) } }