You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
175 lines
4.7 KiB
175 lines
4.7 KiB
// Package specialkinds provides a registry for handling special event kinds |
|
// that require custom processing before normal storage/delivery. |
|
// This includes NIP-43 join/leave requests, policy configuration, and |
|
// curating configuration events. |
|
package specialkinds |
|
|
|
import ( |
|
"context" |
|
|
|
"git.mleku.dev/mleku/nostr/encoders/event" |
|
) |
|
|
|
// Result represents the outcome of handling a special kind event. |
|
type Result struct { |
|
// Handled indicates the event was fully processed by a handler. |
|
// If true, normal event processing should be skipped. |
|
Handled bool |
|
|
|
// Continue indicates processing should continue to normal event handling. |
|
Continue bool |
|
|
|
// Error is set if the handler encountered an error. |
|
Error error |
|
|
|
// Message is an optional message to include in the OK response. |
|
Message string |
|
|
|
// SaveEvent indicates the event should still be saved even if handled. |
|
SaveEvent bool |
|
} |
|
|
|
// HandlerContext provides access to connection-specific data needed by handlers. |
|
type HandlerContext struct { |
|
// AuthedPubkey is the authenticated pubkey for this connection (may be nil). |
|
AuthedPubkey []byte |
|
|
|
// Remote is the remote address of the connection. |
|
Remote string |
|
|
|
// ConnectionID uniquely identifies this connection. |
|
ConnectionID string |
|
} |
|
|
|
// Handler processes special event kinds. |
|
type Handler interface { |
|
// CanHandle returns true if this handler can process the given event. |
|
// This is typically based on the event kind and possibly tag values. |
|
CanHandle(ev *event.E) bool |
|
|
|
// Handle processes the event. |
|
// Returns a Result indicating the outcome. |
|
Handle(ctx context.Context, ev *event.E, hctx *HandlerContext) Result |
|
|
|
// Name returns a descriptive name for this handler (for logging). |
|
Name() string |
|
} |
|
|
|
// Registry holds registered special kind handlers. |
|
type Registry struct { |
|
handlers []Handler |
|
} |
|
|
|
// NewRegistry creates a new special kind registry. |
|
func NewRegistry() *Registry { |
|
return &Registry{ |
|
handlers: make([]Handler, 0), |
|
} |
|
} |
|
|
|
// Register adds a handler to the registry. |
|
// Handlers are checked in registration order. |
|
func (r *Registry) Register(h Handler) { |
|
r.handlers = append(r.handlers, h) |
|
} |
|
|
|
// TryHandle attempts to handle an event with registered handlers. |
|
// Returns (result, true) if a handler processed the event. |
|
// Returns (nil, false) if no handler matched. |
|
func (r *Registry) TryHandle(ctx context.Context, ev *event.E, hctx *HandlerContext) (*Result, bool) { |
|
for _, h := range r.handlers { |
|
if h.CanHandle(ev) { |
|
result := h.Handle(ctx, ev, hctx) |
|
return &result, true |
|
} |
|
} |
|
return nil, false |
|
} |
|
|
|
// ListHandlers returns the names of all registered handlers. |
|
func (r *Registry) ListHandlers() []string { |
|
names := make([]string, len(r.handlers)) |
|
for i, h := range r.handlers { |
|
names[i] = h.Name() |
|
} |
|
return names |
|
} |
|
|
|
// HandlerCount returns the number of registered handlers. |
|
func (r *Registry) HandlerCount() int { |
|
return len(r.handlers) |
|
} |
|
|
|
// ============================================================================= |
|
// Handler Function Adapter |
|
// ============================================================================= |
|
|
|
// HandlerFunc is a function adapter that implements Handler. |
|
type HandlerFunc struct { |
|
name string |
|
canHandleFn func(*event.E) bool |
|
handleFn func(context.Context, *event.E, *HandlerContext) Result |
|
} |
|
|
|
// NewHandlerFunc creates a Handler from functions. |
|
func NewHandlerFunc( |
|
name string, |
|
canHandle func(*event.E) bool, |
|
handle func(context.Context, *event.E, *HandlerContext) Result, |
|
) *HandlerFunc { |
|
return &HandlerFunc{ |
|
name: name, |
|
canHandleFn: canHandle, |
|
handleFn: handle, |
|
} |
|
} |
|
|
|
// CanHandle implements Handler. |
|
func (h *HandlerFunc) CanHandle(ev *event.E) bool { |
|
return h.canHandleFn(ev) |
|
} |
|
|
|
// Handle implements Handler. |
|
func (h *HandlerFunc) Handle(ctx context.Context, ev *event.E, hctx *HandlerContext) Result { |
|
return h.handleFn(ctx, ev, hctx) |
|
} |
|
|
|
// Name implements Handler. |
|
func (h *HandlerFunc) Name() string { |
|
return h.name |
|
} |
|
|
|
// ============================================================================= |
|
// Convenience Result Constructors |
|
// ============================================================================= |
|
|
|
// Handled returns a Result indicating the event was fully handled. |
|
func Handled(message string) Result { |
|
return Result{ |
|
Handled: true, |
|
Message: message, |
|
} |
|
} |
|
|
|
// HandledWithSave returns a Result indicating the event was handled but should also be saved. |
|
func HandledWithSave(message string) Result { |
|
return Result{ |
|
Handled: true, |
|
SaveEvent: true, |
|
Message: message, |
|
} |
|
} |
|
|
|
// ContinueProcessing returns a Result indicating normal processing should continue. |
|
func ContinueProcessing() Result { |
|
return Result{ |
|
Continue: true, |
|
} |
|
} |
|
|
|
// ErrorResult returns a Result with an error. |
|
func ErrorResult(err error) Result { |
|
return Result{ |
|
Error: err, |
|
} |
|
}
|
|
|