You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

179 lines
4.4 KiB

//go:build !(js && wasm)
package bbolt
import (
"bytes"
"errors"
bolt "go.etcd.io/bbolt"
"next.orly.dev/pkg/database"
"next.orly.dev/pkg/database/indexes/types"
"next.orly.dev/pkg/interfaces/store"
"git.mleku.dev/mleku/nostr/encoders/event"
"git.mleku.dev/mleku/nostr/encoders/tag"
)
// GetSerialById gets the serial for an event ID.
func (b *B) GetSerialById(id []byte) (ser *types.Uint40, err error) {
if len(id) < 8 {
return nil, errors.New("bbolt: invalid event ID length")
}
idHash := hashEventId(id)
err = b.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(bucketEid)
if bucket == nil {
return errors.New("id not found in database")
}
// Scan for matching ID hash prefix
c := bucket.Cursor()
for k, _ := c.Seek(idHash); k != nil && bytes.HasPrefix(k, idHash); k, _ = c.Next() {
// Key format: id_hash(8) | serial(5)
if len(k) >= 13 {
ser = new(types.Uint40)
ser.Set(decodeUint40(k[8:13]))
return nil
}
}
return errors.New("id not found in database")
})
return
}
// GetSerialsByIds gets serials for multiple event IDs.
func (b *B) GetSerialsByIds(ids *tag.T) (serials map[string]*types.Uint40, err error) {
serials = make(map[string]*types.Uint40, ids.Len())
if ids == nil || ids.Len() == 0 {
return
}
err = b.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(bucketEid)
if bucket == nil {
return nil
}
// Iterate over the tag entries using the .T field
for _, id := range ids.T {
if len(id) < 8 {
continue
}
idHash := hashEventId(id)
c := bucket.Cursor()
for k, _ := c.Seek(idHash); k != nil && bytes.HasPrefix(k, idHash); k, _ = c.Next() {
if len(k) >= 13 {
ser := new(types.Uint40)
ser.Set(decodeUint40(k[8:13]))
serials[string(id)] = ser
break
}
}
}
return nil
})
return
}
// GetSerialsByIdsWithFilter gets serials with a filter function.
func (b *B) GetSerialsByIdsWithFilter(ids *tag.T, fn func(ev *event.E, ser *types.Uint40) bool) (serials map[string]*types.Uint40, err error) {
// For now, just call GetSerialsByIds - full implementation would apply filter
return b.GetSerialsByIds(ids)
}
// GetSerialsByRange gets serials within a key range.
func (b *B) GetSerialsByRange(idx database.Range) (serials types.Uint40s, err error) {
if len(idx.Start) < 3 {
return nil, errors.New("bbolt: invalid range start")
}
// Extract bucket name from prefix
bucketName := idx.Start[:3]
startKey := idx.Start[3:]
endKey := idx.End[3:]
err = b.db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(bucketName)
if bucket == nil {
return nil
}
c := bucket.Cursor()
for k, _ := c.Seek(startKey); k != nil; k, _ = c.Next() {
// Check if we've passed the end
if len(endKey) > 0 && bytes.Compare(k, endKey) >= 0 {
break
}
// Extract serial from end of key (last 5 bytes)
if len(k) >= 5 {
ser := new(types.Uint40)
ser.Set(decodeUint40(k[len(k)-5:]))
serials = append(serials, ser)
}
}
return nil
})
return
}
// GetFullIdPubkeyBySerial gets full event ID and pubkey by serial.
func (b *B) GetFullIdPubkeyBySerial(ser *types.Uint40) (fidpk *store.IdPkTs, err error) {
if ser == nil {
return nil, errors.New("bbolt: nil serial")
}
serial := ser.Get()
key := makeSerialKey(serial)
err = b.db.View(func(tx *bolt.Tx) error {
// Get full ID/pubkey from fpc bucket
fpcBucket := tx.Bucket(bucketFpc)
if fpcBucket == nil {
return errors.New("bbolt: fpc bucket not found")
}
// Scan for matching serial prefix
c := fpcBucket.Cursor()
for k, _ := c.Seek(key); k != nil && bytes.HasPrefix(k, key); k, _ = c.Next() {
// Key format: serial(5) | id(32) | pubkey_hash(8) | created_at(8)
if len(k) >= 53 {
fidpk = &store.IdPkTs{
Ser: serial,
}
fidpk.Id = make([]byte, 32)
copy(fidpk.Id, k[5:37])
// Pubkey is only hash here, need to look up full pubkey
// For now return what we have
fidpk.Pub = make([]byte, 8)
copy(fidpk.Pub, k[37:45])
fidpk.Ts = int64(decodeUint64(k[45:53]))
return nil
}
}
return errors.New("bbolt: serial not found in fpc index")
})
return
}
// GetFullIdPubkeyBySerials gets full event IDs and pubkeys for multiple serials.
func (b *B) GetFullIdPubkeyBySerials(sers []*types.Uint40) (fidpks []*store.IdPkTs, err error) {
fidpks = make([]*store.IdPkTs, 0, len(sers))
for _, ser := range sers {
fidpk, e := b.GetFullIdPubkeyBySerial(ser)
if e == nil && fidpk != nil {
fidpks = append(fidpks, fidpk)
}
}
return
}