registry.go raw

   1  // Package specialkinds provides a registry for handling special event kinds
   2  // that require custom processing before normal storage/delivery.
   3  // This includes NIP-43 join/leave requests, policy configuration, and
   4  // curating configuration events.
   5  package specialkinds
   6  
   7  import (
   8  	"context"
   9  
  10  	"next.orly.dev/pkg/nostr/encoders/event"
  11  )
  12  
  13  // Result represents the outcome of handling a special kind event.
  14  type Result struct {
  15  	// Handled indicates the event was fully processed by a handler.
  16  	// If true, normal event processing should be skipped.
  17  	Handled bool
  18  
  19  	// Continue indicates processing should continue to normal event handling.
  20  	Continue bool
  21  
  22  	// Error is set if the handler encountered an error.
  23  	Error error
  24  
  25  	// Message is an optional message to include in the OK response.
  26  	Message string
  27  
  28  	// SaveEvent indicates the event should still be saved even if handled.
  29  	SaveEvent bool
  30  }
  31  
  32  // HandlerContext provides access to connection-specific data needed by handlers.
  33  type HandlerContext struct {
  34  	// AuthedPubkey is the authenticated pubkey for this connection (may be nil).
  35  	AuthedPubkey []byte
  36  
  37  	// Remote is the remote address of the connection.
  38  	Remote string
  39  
  40  	// ConnectionID uniquely identifies this connection.
  41  	ConnectionID string
  42  }
  43  
  44  // Handler processes special event kinds.
  45  type Handler interface {
  46  	// CanHandle returns true if this handler can process the given event.
  47  	// This is typically based on the event kind and possibly tag values.
  48  	CanHandle(ev *event.E) bool
  49  
  50  	// Handle processes the event.
  51  	// Returns a Result indicating the outcome.
  52  	Handle(ctx context.Context, ev *event.E, hctx *HandlerContext) Result
  53  
  54  	// Name returns a descriptive name for this handler (for logging).
  55  	Name() string
  56  }
  57  
  58  // Registry holds registered special kind handlers.
  59  type Registry struct {
  60  	handlers []Handler
  61  }
  62  
  63  // NewRegistry creates a new special kind registry.
  64  func NewRegistry() *Registry {
  65  	return &Registry{
  66  		handlers: make([]Handler, 0),
  67  	}
  68  }
  69  
  70  // Register adds a handler to the registry.
  71  // Handlers are checked in registration order.
  72  func (r *Registry) Register(h Handler) {
  73  	r.handlers = append(r.handlers, h)
  74  }
  75  
  76  // TryHandle attempts to handle an event with registered handlers.
  77  // Returns (result, true) if a handler processed the event.
  78  // Returns (nil, false) if no handler matched.
  79  func (r *Registry) TryHandle(ctx context.Context, ev *event.E, hctx *HandlerContext) (*Result, bool) {
  80  	for _, h := range r.handlers {
  81  		if h.CanHandle(ev) {
  82  			result := h.Handle(ctx, ev, hctx)
  83  			return &result, true
  84  		}
  85  	}
  86  	return nil, false
  87  }
  88  
  89  // ListHandlers returns the names of all registered handlers.
  90  func (r *Registry) ListHandlers() []string {
  91  	names := make([]string, len(r.handlers))
  92  	for i, h := range r.handlers {
  93  		names[i] = h.Name()
  94  	}
  95  	return names
  96  }
  97  
  98  // HandlerCount returns the number of registered handlers.
  99  func (r *Registry) HandlerCount() int {
 100  	return len(r.handlers)
 101  }
 102  
 103  // =============================================================================
 104  // Handler Function Adapter
 105  // =============================================================================
 106  
 107  // HandlerFunc is a function adapter that implements Handler.
 108  type HandlerFunc struct {
 109  	name         string
 110  	canHandleFn  func(*event.E) bool
 111  	handleFn     func(context.Context, *event.E, *HandlerContext) Result
 112  }
 113  
 114  // NewHandlerFunc creates a Handler from functions.
 115  func NewHandlerFunc(
 116  	name string,
 117  	canHandle func(*event.E) bool,
 118  	handle func(context.Context, *event.E, *HandlerContext) Result,
 119  ) *HandlerFunc {
 120  	return &HandlerFunc{
 121  		name:        name,
 122  		canHandleFn: canHandle,
 123  		handleFn:    handle,
 124  	}
 125  }
 126  
 127  // CanHandle implements Handler.
 128  func (h *HandlerFunc) CanHandle(ev *event.E) bool {
 129  	return h.canHandleFn(ev)
 130  }
 131  
 132  // Handle implements Handler.
 133  func (h *HandlerFunc) Handle(ctx context.Context, ev *event.E, hctx *HandlerContext) Result {
 134  	return h.handleFn(ctx, ev, hctx)
 135  }
 136  
 137  // Name implements Handler.
 138  func (h *HandlerFunc) Name() string {
 139  	return h.name
 140  }
 141  
 142  // =============================================================================
 143  // Convenience Result Constructors
 144  // =============================================================================
 145  
 146  // Handled returns a Result indicating the event was fully handled.
 147  func Handled(message string) Result {
 148  	return Result{
 149  		Handled: true,
 150  		Message: message,
 151  	}
 152  }
 153  
 154  // HandledWithSave returns a Result indicating the event was handled but should also be saved.
 155  func HandledWithSave(message string) Result {
 156  	return Result{
 157  		Handled:   true,
 158  		SaveEvent: true,
 159  		Message:   message,
 160  	}
 161  }
 162  
 163  // ContinueProcessing returns a Result indicating normal processing should continue.
 164  func ContinueProcessing() Result {
 165  	return Result{
 166  		Continue: true,
 167  	}
 168  }
 169  
 170  // ErrorResult returns a Result with an error.
 171  func ErrorResult(err error) Result {
 172  	return Result{
 173  		Error: err,
 174  	}
 175  }
 176