1 // Package store is an interface and ancillary helpers and types for defining a
2 // series of API elements for abstracting the event storage from the
3 // implementation.
4 //
5 // It is composed so that the top-level interface can be
6 // partially implemented if need be.
7 package store
8 9 import (
10 "context"
11 "io"
12 13 "next.orly.dev/app/config"
14 "next.orly.dev/pkg/database/indexes/types"
15 "next.orly.dev/pkg/nostr/encoders/event"
16 "next.orly.dev/pkg/nostr/encoders/filter"
17 "next.orly.dev/pkg/nostr/encoders/tag"
18 ntypes "next.orly.dev/pkg/nostr/types"
19 )
20 21 // I am a type for a persistence layer for nostr events handled by a relay.
22 type I interface {
23 Pather
24 io.Closer
25 Pather
26 Wiper
27 Querier
28 Querent
29 Deleter
30 Saver
31 Importer
32 Exporter
33 Syncer
34 LogLeveler
35 EventIdSerialer
36 Initer
37 SerialByIder
38 }
39 40 type Initer interface {
41 Init(path string) (err error)
42 }
43 44 type Pather interface {
45 // Path returns the directory of the database.
46 Path() (s string)
47 }
48 49 type Wiper interface {
50 // Wipe deletes everything in the database.
51 Wipe() (err error)
52 }
53 54 type Querent interface {
55 // QueryEvents is invoked upon a client's REQ as described in NIP-01. It
56 // returns the matching events in reverse chronological order in a slice.
57 QueryEvents(c context.Context, f *filter.F) (evs event.S, err error)
58 }
59 60 type Accountant interface {
61 EventCount() (count uint64, err error)
62 }
63 64 // IdPkTs holds event reference data using fixed-size arrays for stack allocation.
65 // Total size: 80 bytes (32+32+8+8), fits in a cache line.
66 // Copies of this struct stay on the stack and are value-safe.
67 type IdPkTs struct {
68 Id ntypes.EventID // 32 bytes - event ID
69 Pub ntypes.Pubkey // 32 bytes - author pubkey
70 Ts int64 // 8 bytes - created_at timestamp
71 Ser uint64 // 8 bytes - database serial number
72 }
73 74 // NewIdPkTs creates an IdPkTs from byte slices (copies into fixed arrays).
75 func NewIdPkTs(id, pub []byte, ts int64, ser uint64) IdPkTs {
76 return IdPkTs{
77 Id: ntypes.EventIDFromBytes(id),
78 Pub: ntypes.PubkeyFromBytes(pub),
79 Ts: ts,
80 Ser: ser,
81 }
82 }
83 84 // IDSlice returns the event ID as a byte slice (shares memory with array).
85 func (i *IdPkTs) IDSlice() []byte {
86 return i.Id[:]
87 }
88 89 // PubSlice returns the pubkey as a byte slice (shares memory with array).
90 func (i *IdPkTs) PubSlice() []byte {
91 return i.Pub[:]
92 }
93 94 // IDHex returns the event ID as a lowercase hex string.
95 func (i *IdPkTs) IDHex() string {
96 return i.Id.Hex()
97 }
98 99 // PubHex returns the pubkey as a lowercase hex string.
100 func (i *IdPkTs) PubHex() string {
101 return i.Pub.Hex()
102 }
103 104 // ToEventRef converts IdPkTs to an EventRef.
105 func (i *IdPkTs) ToEventRef() EventRef {
106 return EventRef{
107 id: i.Id,
108 pub: i.Pub,
109 ts: i.Ts,
110 ser: i.Ser,
111 }
112 }
113 114 // EventRef is a stack-friendly event reference using fixed-size arrays.
115 // Total size: 80 bytes (32+32+8+8), fits in a cache line, copies stay on stack.
116 // Use this type when you need safe, immutable event references.
117 type EventRef struct {
118 id ntypes.EventID // 32 bytes
119 pub ntypes.Pubkey // 32 bytes
120 ts int64 // 8 bytes
121 ser uint64 // 8 bytes
122 }
123 124 // NewEventRef creates an EventRef from byte slices.
125 // The slices are copied into fixed-size arrays.
126 func NewEventRef(id, pub []byte, ts int64, ser uint64) EventRef {
127 return EventRef{
128 id: ntypes.EventIDFromBytes(id),
129 pub: ntypes.PubkeyFromBytes(pub),
130 ts: ts,
131 ser: ser,
132 }
133 }
134 135 // ID returns the event ID (copy, stays on stack).
136 func (r EventRef) ID() ntypes.EventID { return r.id }
137 138 // Pub returns the pubkey (copy, stays on stack).
139 func (r EventRef) Pub() ntypes.Pubkey { return r.pub }
140 141 // Ts returns the timestamp.
142 func (r EventRef) Ts() int64 { return r.ts }
143 144 // Ser returns the serial number.
145 func (r EventRef) Ser() uint64 { return r.ser }
146 147 // IDHex returns the event ID as lowercase hex.
148 func (r EventRef) IDHex() string { return r.id.Hex() }
149 150 // PubHex returns the pubkey as lowercase hex.
151 func (r EventRef) PubHex() string { return r.pub.Hex() }
152 153 // IDSlice returns a slice view of the ID (shares memory, use carefully).
154 func (r *EventRef) IDSlice() []byte { return r.id.Bytes() }
155 156 // PubSlice returns a slice view of the pubkey (shares memory, use carefully).
157 func (r *EventRef) PubSlice() []byte { return r.pub.Bytes() }
158 159 // ToIdPkTs converts EventRef to IdPkTs.
160 func (r EventRef) ToIdPkTs() *IdPkTs {
161 return &IdPkTs{
162 Id: r.id,
163 Pub: r.pub,
164 Ts: r.ts,
165 Ser: r.ser,
166 }
167 }
168 169 type Querier interface {
170 QueryForIds(c context.Context, f *filter.F) (evs []*IdPkTs, err error)
171 }
172 173 type GetIdsWriter interface {
174 FetchIds(c context.Context, evIds *tag.T, out io.Writer) (err error)
175 }
176 177 type Deleter interface {
178 // DeleteEvent is used to handle deletion events, as per NIP-09.
179 DeleteEvent(c context.Context, ev []byte) (err error)
180 }
181 182 type Saver interface {
183 // SaveEvent is called once relay.AcceptEvent reports true. The owners
184 // parameter is for designating admins whose delete by e tag events apply
185 // the same as author's own.
186 SaveEvent(c context.Context, ev *event.E) (replaced bool, err error)
187 }
188 189 type Importer interface {
190 // Import reads in a stream of line-structured JSON the events to save into
191 // the store.
192 Import(r io.Reader)
193 }
194 195 type Exporter interface {
196 // Export writes a stream of line structured JSON of all events in the
197 // store.
198 //
199 // If pubkeys are present, only those with these pubkeys in the `pubkey`
200 // field and in `p` tags will be included.
201 Export(c context.Context, w io.Writer, pubkeys ...[]byte)
202 }
203 204 type Rescanner interface {
205 // Rescan triggers the regeneration of indexes of the database to enable old
206 // records to be found with new indexes.
207 Rescan() (err error)
208 }
209 210 type Syncer interface {
211 // Sync signals the event store to flush its buffers.
212 Sync() (err error)
213 }
214 215 type Configuration struct {
216 BlockList []string `json:"block_list" doc:"list of IP addresses that will be ignored"`
217 }
218 219 type Configurationer interface {
220 GetConfiguration() (c config.C, err error)
221 SetConfiguration(c config.C) (err error)
222 }
223 224 type LogLeveler interface {
225 SetLogLevel(level string)
226 }
227 228 type EventIdSerialer interface {
229 EventIdsBySerial(start uint64, count int) (
230 evs [][]byte,
231 err error,
232 )
233 }
234 235 type SerialByIder interface {
236 GetSerialById(id []byte) (ser *types.Uint40, err error)
237 }
238