@@ -0,0 +1,100 @@
|
||||
// Package events implements a simple event broadcasting mechanism
|
||||
// for usage in broadcasting error messages, postbacks etc. various
|
||||
// channels.
|
||||
package events
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
TypeError = "error"
|
||||
)
|
||||
|
||||
// Event represents a single event in the system.
|
||||
type Event struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Message string `json:"message"`
|
||||
Data any `json:"data"`
|
||||
Channels []string `json:"-"`
|
||||
}
|
||||
|
||||
type Events struct {
|
||||
subs map[string]chan Event
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// New returns a new instance of Events.
|
||||
func New() *Events {
|
||||
return &Events{
|
||||
subs: make(map[string]chan Event),
|
||||
}
|
||||
}
|
||||
|
||||
// Subscribe returns a channel to which the given event `types` are streamed.
|
||||
// id is the unique identifier for the caller. A caller can only register
|
||||
// for subscription once.
|
||||
func (ev *Events) Subscribe(id string) (chan Event, error) {
|
||||
ev.Lock()
|
||||
defer ev.Unlock()
|
||||
|
||||
if ch, ok := ev.subs[id]; ok {
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
ch := make(chan Event, 100)
|
||||
ev.subs[id] = ch
|
||||
|
||||
return ch, nil
|
||||
}
|
||||
|
||||
// Unsubscribe unsubscribes a subscriber (obviously).
|
||||
func (ev *Events) Unsubscribe(id string) {
|
||||
ev.Lock()
|
||||
defer ev.Unlock()
|
||||
delete(ev.subs, id)
|
||||
}
|
||||
|
||||
// Publish publishes an event to all subscribers.
|
||||
func (ev *Events) Publish(e Event) error {
|
||||
ev.Lock()
|
||||
defer ev.Unlock()
|
||||
|
||||
for _, ch := range ev.subs {
|
||||
select {
|
||||
case ch <- e:
|
||||
default:
|
||||
return fmt.Errorf("event queue full for type: %s", e.Type)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// This implements an io.Writer specifically for receiving error messages
|
||||
// mirrored (io.MultiWriter) from error log writing.
|
||||
type wri struct {
|
||||
ev *Events
|
||||
}
|
||||
|
||||
func (w *wri) Write(b []byte) (n int, err error) {
|
||||
// Only broadcast error messages.
|
||||
if !bytes.Contains(b, []byte("error")) {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
w.ev.Publish(Event{
|
||||
Type: TypeError,
|
||||
Message: string(b),
|
||||
})
|
||||
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (ev *Events) ErrWriter() io.Writer {
|
||||
return &wri{ev: ev}
|
||||
}
|
||||
Reference in New Issue
Block a user