ollie/session/event.go

75 lines
1.7 KiB
Go

package session
import (
"context"
"strings"
"github.com/simonfxr/pubsub"
)
var eventBus = pubsub.NewBus()
// Event represents a published event with topic and payload.
type Event struct {
Topic string
Payload string
}
// PublishEvent publishes an event to a specific topic.
// Topic hierarchy:
//
// session.{sid}.new/kill/pause/resume/rename
// session.{sid}.agent.{aid}.new/kill/state
//
// Wildcard routing publishes to all ancestor wildcards:
//
// session.{sid}.agent.{aid}.state -> also publishes to:
// session.{sid}.agent.{aid}.*
// session.{sid}.agent.*
// session.{sid}.*
// session.*
// *
func PublishEvent(topic, payload string) {
ev := Event{Topic: topic, Payload: payload}
eventBus.Publish(topic, ev)
// Publish to hierarchical wildcards
parts := strings.Split(topic, ".")
for i := len(parts) - 1; i >= 1; i-- {
wildcard := strings.Join(parts[:i], ".") + ".*"
eventBus.Publish(wildcard, ev)
}
eventBus.Publish("*", ev)
}
// SubscribeEvents returns a channel that receives all events matching the topic.
// Use "*" for all events, "session.*" for all session events, etc.
func SubscribeEvents(ctx context.Context, topic string) <-chan Event {
ch := make(chan Event, 64)
sub := eventBus.SubscribeChan(topic, ch, pubsub.KeepOpen)
go func() {
<-ctx.Done()
eventBus.Unsubscribe(sub)
close(ch)
}()
return ch
}
// WaitEvent blocks until an event is available. Returns the event as "topic payload\n".
func WaitEvent(ctx context.Context) ([]byte, string, error) {
ch := SubscribeEvents(ctx, "*")
select {
case ev, ok := <-ch:
if !ok {
return nil, "", nil
}
line := ev.Topic
if ev.Payload != "" {
line += " " + ev.Payload
}
return []byte(line + "\n"), "", nil
case <-ctx.Done():
return nil, "", nil
}
}