package routing import "sync" const DefaultRingCapacity = 1 << 8 // Best if power of 2 (or so I am told) // Broker manages topics and issues publisher/subscriber handles. type Broker struct { mu sync.RWMutex topics map[string]*TopicRing } func NewBroker() *Broker { return &Broker{ topics: make(map[string]*TopicRing), } } // getOrCreateRing handles the race condition where a subscriber might attach // to a topic before the publisher has created it, and vice versa. // This is because we allow either a publisher or a subscriber to 'create' the topic func (b *Broker) getOrCreateRing(topicKey string, requestedCap int) *TopicRing { b.mu.Lock() defer b.mu.Unlock() ring, exists := b.topics[topicKey] if !exists { cap := requestedCap if cap <= 0 { cap = DefaultRingCapacity } ring = newTopicRing(cap) b.topics[topicKey] = ring } return ring } // RegisterPublisher returns a fast-path Publisher. func (b *Broker) RegisterPublisher(topicKey string, capacity int) Publisher { ring := b.getOrCreateRing(topicKey, capacity) return &ringPublisher{ ring: ring, } } // RegisterSubscriber attaches a consumer to a topic and returns a fast-path Subscriber. // We don't allow subscribrs to specify a buffer capacity size. // As a general rule, a publisher takes precedence over a subscriber func (b *Broker) RegisterSubscriber(topicKey string) Subscriber { ring := b.getOrCreateRing(topicKey, 0) consumer := ring.addConsumer() return &ringSubscriber{ ring: ring, consumer: consumer, } }