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