Files
eventstore/bolt/helpers.go
2024-02-08 12:36:34 -03:00

115 lines
3.0 KiB
Go

package bolt
import (
"encoding/binary"
"encoding/hex"
"github.com/fiatjaf/eventstore"
"github.com/nbd-wtf/go-nostr"
"golang.org/x/exp/slices"
)
// returns
// - the bucket id where this will be saved
// - the key with full length for created_at and idx at the end, but not filled with these
// - the offset -- i.e. where the prefix ends and the created_at and idx would start
func getTagIndexPrefix(tagValue string) (bucket []byte, key []byte, offset int) {
if kind, pkb, d := eventstore.GetAddrTagElements(tagValue); len(pkb) == 32 {
// store value in the new special "a" tag index
key = make([]byte, 2+8+len(d)+4)
binary.BigEndian.PutUint16(key[1:], kind)
copy(key[2:], pkb[0:8])
copy(key[2+8:], d)
offset = 2 + 8 + len(d)
bucket = bucketTagAddr
} else if vb, _ := hex.DecodeString(tagValue); len(vb) == 32 {
// store value as bytes
key = make([]byte, 8+4)
copy(key, vb[0:8])
offset = 8
bucket = bucketTag32
} else {
// store whatever as utf-8
key = make([]byte, len(tagValue)+4)
copy(key, tagValue)
offset = len(tagValue)
bucket = bucketTag
}
return bucket, key, offset
}
type keymeta struct {
bucket []byte
key []byte
}
func getIndexKeysForEvent(evt *nostr.Event) []keymeta {
keys := make([]keymeta, 0, 24)
// indexes
{
// ~ by id
idPrefix8, _ := hex.DecodeString(evt.ID[0 : 8*2])
k := idPrefix8
keys = append(keys, keymeta{bucket: bucketId, key: k})
}
{
// ~ by pubkey+date
pubkeyPrefix8, _ := hex.DecodeString(evt.PubKey[0 : 8*2])
k := make([]byte, 8+4)
copy(k[:], pubkeyPrefix8)
binary.BigEndian.PutUint32(k[8:], uint32(evt.CreatedAt))
keys = append(keys, keymeta{bucket: bucketPubkey, key: k})
}
{
// ~ by kind+date
k := make([]byte, 2+4)
binary.BigEndian.PutUint16(k[:], uint16(evt.Kind))
binary.BigEndian.PutUint32(k[2:], uint32(evt.CreatedAt))
keys = append(keys, keymeta{bucket: bucketKind, key: k})
}
{
// ~ by pubkey+kind+date
pubkeyPrefix8, _ := hex.DecodeString(evt.PubKey[0 : 8*2])
k := make([]byte, 8+2+4)
copy(k[:], pubkeyPrefix8)
binary.BigEndian.PutUint16(k[8:], uint16(evt.Kind))
binary.BigEndian.PutUint32(k[8+2:], uint32(evt.CreatedAt))
keys = append(keys, keymeta{bucket: bucketPubkeyKind, key: k})
}
// ~ by tagvalue+date
for i, tag := range evt.Tags {
if len(tag) < 2 || len(tag[0]) != 1 || len(tag[1]) == 0 || len(tag[1]) > 100 {
// not indexable
continue
}
firstIndex := slices.IndexFunc(evt.Tags, func(t nostr.Tag) bool { return len(t) >= 2 && t[1] == tag[1] })
if firstIndex != i {
// duplicate
continue
}
// get key prefix (with full length) and offset where to write the created_at
bucket, k, offset := getTagIndexPrefix(tag[1])
// write the created_at
binary.BigEndian.PutUint32(k[offset:], uint32(evt.CreatedAt))
keys = append(keys, keymeta{bucket: bucket, key: k})
}
{
// ~ by date only
k := make([]byte, 4)
binary.BigEndian.PutUint32(k[:], uint32(evt.CreatedAt))
keys = append(keys, keymeta{bucket: bucketCreatedAt, key: k})
}
return keys
}