multica/server/internal/events/bus.go
Naiyuan Qing 8983a9fefa feat(logging): add structured logging across server and SDK
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>
2026-03-26 10:57:11 +08:00

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)
}()
}
}