feat(master): in-process broker for live UI change signals
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
// Package events fans out "something changed" signals from the agent hub to
|
||||
// open browser streams.
|
||||
package events
|
||||
|
||||
import "sync"
|
||||
|
||||
// Topic names what changed. Subscribers refetch that part of the UI.
|
||||
type Topic string
|
||||
|
||||
// Topics.
|
||||
const (
|
||||
Services Topic = "services"
|
||||
Agents Topic = "agents"
|
||||
)
|
||||
|
||||
// Broker is an in-process publish/subscribe hub.
|
||||
type Broker struct {
|
||||
mu sync.Mutex
|
||||
subs map[chan Topic]struct{}
|
||||
}
|
||||
|
||||
// NewBroker returns an empty Broker.
|
||||
func NewBroker() *Broker {
|
||||
return &Broker{subs: make(map[chan Topic]struct{})}
|
||||
}
|
||||
|
||||
// Subscribe returns a channel of topics and a cancel function that must be
|
||||
// called when the subscriber goes away. Cancel is safe to call twice.
|
||||
func (b *Broker) Subscribe() (<-chan Topic, func()) {
|
||||
ch := make(chan Topic, 16)
|
||||
b.mu.Lock()
|
||||
b.subs[ch] = struct{}{}
|
||||
b.mu.Unlock()
|
||||
var once sync.Once
|
||||
return ch, func() {
|
||||
once.Do(func() {
|
||||
b.mu.Lock()
|
||||
delete(b.subs, ch)
|
||||
b.mu.Unlock()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Publish signals t to every subscriber. A subscriber whose buffer is full is
|
||||
// skipped rather than blocking the agent hub; it already has signals queued
|
||||
// and will refetch current state when it processes them.
|
||||
func (b *Broker) Publish(t Topic) {
|
||||
b.mu.Lock()
|
||||
defer b.mu.Unlock()
|
||||
for ch := range b.subs {
|
||||
select {
|
||||
case ch <- t:
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user