115 lines
3.0 KiB
Go
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
|
|
}
|