store_interface.go raw

   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