Some checks failed
Go / build-and-release (push) Has been cancelled
Major refactoring of event handling into clean, testable domain services: - Add pkg/event/validation: JSON hex validation, signature verification, timestamp bounds, NIP-70 protected tag validation - Add pkg/event/authorization: Policy and ACL authorization decisions, auth challenge handling, access level determination - Add pkg/event/routing: Event router registry with ephemeral and delete handlers, kind-based dispatch - Add pkg/event/processing: Event persistence, delivery to subscribers, and post-save hooks (ACL reconfig, sync, relay groups) - Reduce handle-event.go from 783 to 296 lines (62% reduction) - Add comprehensive unit tests for all new domain services - Refactor database tests to use shared TestMain setup - Fix blossom URL test expectations (missing "/" separator) - Add go-memory-optimization skill and analysis documentation - Update DDD_ANALYSIS.md to reflect completed decomposition Files modified: - app/handle-event.go: Slim orchestrator using domain services - app/server.go: Service initialization and interface wrappers - app/handle-event-types.go: Shared types (OkHelper, result types) - pkg/event/validation/*: New validation service package - pkg/event/authorization/*: New authorization service package - pkg/event/routing/*: New routing service package - pkg/event/processing/*: New processing service package - pkg/database/*_test.go: Refactored to shared TestMain - pkg/blossom/http_test.go: Fixed URL format expectations 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
123 lines
3.2 KiB
Go
123 lines
3.2 KiB
Go
// Package routing provides event routing services for the ORLY relay.
|
|
// It dispatches events to specialized handlers based on event kind.
|
|
package routing
|
|
|
|
import (
|
|
"git.mleku.dev/mleku/nostr/encoders/event"
|
|
)
|
|
|
|
// Action indicates what to do after routing.
|
|
type Action int
|
|
|
|
const (
|
|
// Continue means continue to normal processing.
|
|
Continue Action = iota
|
|
// Handled means event was fully handled, return success.
|
|
Handled
|
|
// Error means an error occurred.
|
|
Error
|
|
)
|
|
|
|
// Result contains the routing decision.
|
|
type Result struct {
|
|
Action Action
|
|
Message string // Success or error message
|
|
Error error // Error if Action == Error
|
|
}
|
|
|
|
// ContinueResult returns a result indicating normal processing should continue.
|
|
func ContinueResult() Result {
|
|
return Result{Action: Continue}
|
|
}
|
|
|
|
// HandledResult returns a result indicating the event was fully handled.
|
|
func HandledResult(msg string) Result {
|
|
return Result{Action: Handled, Message: msg}
|
|
}
|
|
|
|
// ErrorResult returns a result indicating an error occurred.
|
|
func ErrorResult(err error) Result {
|
|
return Result{Action: Error, Error: err}
|
|
}
|
|
|
|
// Handler processes a specific event kind.
|
|
// authedPubkey is the authenticated pubkey of the connection (may be nil).
|
|
type Handler func(ev *event.E, authedPubkey []byte) Result
|
|
|
|
// KindCheck tests whether an event kind matches a category (e.g., ephemeral).
|
|
type KindCheck struct {
|
|
Name string
|
|
Check func(kind uint16) bool
|
|
Handler Handler
|
|
}
|
|
|
|
// Router dispatches events to specialized handlers.
|
|
type Router interface {
|
|
// Route checks if event should be handled specially.
|
|
Route(ev *event.E, authedPubkey []byte) Result
|
|
|
|
// Register adds a handler for a specific kind.
|
|
Register(kind uint16, handler Handler)
|
|
|
|
// RegisterKindCheck adds a handler for a kind category.
|
|
RegisterKindCheck(name string, check func(uint16) bool, handler Handler)
|
|
}
|
|
|
|
// DefaultRouter implements Router with a handler registry.
|
|
type DefaultRouter struct {
|
|
handlers map[uint16]Handler
|
|
kindChecks []KindCheck
|
|
}
|
|
|
|
// New creates a new DefaultRouter.
|
|
func New() *DefaultRouter {
|
|
return &DefaultRouter{
|
|
handlers: make(map[uint16]Handler),
|
|
kindChecks: make([]KindCheck, 0),
|
|
}
|
|
}
|
|
|
|
// Register adds a handler for a specific kind.
|
|
func (r *DefaultRouter) Register(kind uint16, handler Handler) {
|
|
r.handlers[kind] = handler
|
|
}
|
|
|
|
// RegisterKindCheck adds a handler for a kind category.
|
|
func (r *DefaultRouter) RegisterKindCheck(name string, check func(uint16) bool, handler Handler) {
|
|
r.kindChecks = append(r.kindChecks, KindCheck{
|
|
Name: name,
|
|
Check: check,
|
|
Handler: handler,
|
|
})
|
|
}
|
|
|
|
// Route checks if event should be handled specially.
|
|
func (r *DefaultRouter) Route(ev *event.E, authedPubkey []byte) Result {
|
|
// Check exact kind matches first (higher priority)
|
|
if handler, ok := r.handlers[ev.Kind]; ok {
|
|
return handler(ev, authedPubkey)
|
|
}
|
|
|
|
// Check kind property handlers (ephemeral, replaceable, etc.)
|
|
for _, kc := range r.kindChecks {
|
|
if kc.Check(ev.Kind) {
|
|
return kc.Handler(ev, authedPubkey)
|
|
}
|
|
}
|
|
|
|
return ContinueResult()
|
|
}
|
|
|
|
// HasHandler returns true if a handler is registered for the given kind.
|
|
func (r *DefaultRouter) HasHandler(kind uint16) bool {
|
|
if _, ok := r.handlers[kind]; ok {
|
|
return true
|
|
}
|
|
for _, kc := range r.kindChecks {
|
|
if kc.Check(kind) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|