Replace raw fmt/log calls with structured slog logger (Go) and console-based logger (TypeScript). Add request logging middleware. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
59 lines
1.5 KiB
Go
59 lines
1.5 KiB
Go
package events
|
|
|
|
import (
|
|
"log/slog"
|
|
"sync"
|
|
)
|
|
|
|
// Event represents a domain event published by handlers or services.
|
|
type Event struct {
|
|
Type string // e.g. "issue:created", "inbox:new"
|
|
WorkspaceID string // routes to correct Hub room
|
|
ActorType string // "member", "agent", or "system"
|
|
ActorID string
|
|
Payload any // JSON-serializable, same shape as current WS payloads
|
|
}
|
|
|
|
// Handler is a function that processes an event.
|
|
type Handler func(Event)
|
|
|
|
// Bus is an in-process synchronous pub/sub event bus.
|
|
type Bus struct {
|
|
mu sync.RWMutex
|
|
listeners map[string][]Handler
|
|
}
|
|
|
|
// New creates a new event bus.
|
|
func New() *Bus {
|
|
return &Bus{
|
|
listeners: make(map[string][]Handler),
|
|
}
|
|
}
|
|
|
|
// Subscribe registers a handler for a given event type.
|
|
// Handlers are called synchronously in registration order.
|
|
func (b *Bus) Subscribe(eventType string, h Handler) {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
b.listeners[eventType] = append(b.listeners[eventType], h)
|
|
}
|
|
|
|
// Publish dispatches an event to all registered handlers for that event type.
|
|
// Each handler is called synchronously. Panics in individual handlers are
|
|
// recovered so one failing handler does not prevent others from executing.
|
|
func (b *Bus) Publish(e Event) {
|
|
b.mu.RLock()
|
|
handlers := b.listeners[e.Type]
|
|
b.mu.RUnlock()
|
|
|
|
for _, h := range handlers {
|
|
func() {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
slog.Error("panic in event listener", "event_type", e.Type, "recovered", r)
|
|
}
|
|
}()
|
|
h(e)
|
|
}()
|
|
}
|
|
}
|