package bus import ( "fmt" "sync" "log/slog" "git.savin.nyc/alex/go-receipt-tracker/config" ) // Bus should be created by New(). type Bus struct { opts *config.Bus log *slog.Logger channels map[string]*eventChannel mu sync.Mutex } // New creates new Bus instance. func New(opts *config.Bus, log *slog.Logger) *Bus { b := &Bus{ opts: opts, log: log, channels: make(map[string]*eventChannel), } return b } // Subscribe adds new subscriber to channel. func (b *Bus) Subscribe(channelName, subName string) (chan Event, error) { b.mu.Lock() defer b.mu.Unlock() if _, ok := b.channels[channelName]; !ok { b.channels[channelName] = newEventChannel() b.log.Debug("created a new channel", "channel", channelName) } ch := b.channels[channelName] if err := ch.addSubscriber(subName, b.opts.SubscriptionSize[channelName]); err != nil { return nil, err } b.log.Debug("added a new subscriber to a channel", "channel", channelName, "subscriber", subName) return ch.subscribers[subName], nil } // Unsubscribe removes subscriber from channel. // If this is last subscriber channel will be removed. func (b *Bus) Unsubscribe(channelName, subName string) { b.mu.Lock() defer b.mu.Unlock() channel, ok := b.channels[channelName] if !ok { return } channel.delSubscriber(subName) if len(channel.subscribers) == 0 { delete(b.channels, channelName) } } // Publish data to channel. func (b *Bus) Publish(channelName string, payload interface{}) error { channel, ok := b.channels[channelName] if !ok { return fmt.Errorf("channel %s don't exists", channelName) } e := Event{ ChannelName: channelName, Payload: payload, } for subName, subscriber := range channel.subscribers { b.log.Debug("some channel info", "channel", channelName, "cap", cap(subscriber), "len", len(subscriber)) if cap(subscriber) > 0 && len(subscriber) >= cap(subscriber) { b.log.Info("channel %s for subscriber %s is full, not publishing new messages", channelName, subName) continue } subscriber <- e b.log.Debug("published a new message to a channel", "channel", channelName, "subscriber", subName) // b.log.Debug("published a new message to a channel", "channel", channelName, "subscriber", subName, "payload", payload) } return nil }