it never ends.

This commit is contained in:
fiatjaf
2025-04-16 02:59:47 -03:00
parent cb0dd45a32
commit 5b8954461f
53 changed files with 396 additions and 673 deletions

View File

@@ -10,8 +10,8 @@ import (
"github.com/dgraph-io/badger/v4"
)
func (b *BadgerBackend) CountEvents(filter nostr.Filter) (int64, error) {
var count int64 = 0
func (b *BadgerBackend) CountEvents(filter nostr.Filter) (uint32, error) {
var count uint32 = 0
queries, extraFilter, since, err := prepareQueries(filter)
if err != nil {
@@ -86,8 +86,8 @@ func (b *BadgerBackend) CountEvents(filter nostr.Filter) (int64, error) {
return count, err
}
func (b *BadgerBackend) CountEventsHLL(filter nostr.Filter, offset int) (int64, *hyperloglog.HyperLogLog, error) {
var count int64 = 0
func (b *BadgerBackend) CountEventsHLL(filter nostr.Filter, offset int) (uint32, *hyperloglog.HyperLogLog, error) {
var count uint32 = 0
queries, extraFilter, since, err := prepareQueries(filter)
if err != nil {

View File

@@ -53,6 +53,6 @@ func (b *BlugeBackend) Init() error {
return nil
}
func (b *BlugeBackend) CountEvents(nostr.Filter) (int64, error) {
func (b *BlugeBackend) CountEvents(nostr.Filter) (uint32, error) {
return 0, errors.New("not supported")
}

View File

@@ -5,8 +5,8 @@ import (
"fmt"
"os"
"github.com/urfave/cli/v3"
"fiatjaf.com/nostr"
"github.com/urfave/cli/v3"
)
var delete_ = &cli.Command{
@@ -17,17 +17,15 @@ var delete_ = &cli.Command{
Action: func(ctx context.Context, c *cli.Command) error {
hasError := false
for line := range getStdinLinesOrFirstArgument(c) {
f := nostr.Filter{IDs: []string{line}}
ch, err := db.QueryEvents(ctx, f)
id, err := nostr.IDFromHex(line)
if err != nil {
fmt.Fprintf(os.Stderr, "error querying for %s: %s\n", f, err)
fmt.Fprintf(os.Stderr, "invalid id '%s': %s\n", line, err)
hasError = true
}
for evt := range ch {
if err := db.DeleteEvent(ctx, evt); err != nil {
fmt.Fprintf(os.Stderr, "error deleting %s: %s\n", evt, err)
hasError = true
}
if err := db.DeleteEvent(id); err != nil {
fmt.Fprintf(os.Stderr, "error deleting '%s': %s\n", id.Hex(), err)
hasError = true
}
}

View File

@@ -96,7 +96,7 @@ var app = &cli.Command{
if err := json.Unmarshal(scanner.Bytes(), &evt); err != nil {
log.Printf("invalid event read at line %d: %s (`%s`)\n", i, err, scanner.Text())
}
db.SaveEvent(ctx, &evt)
db.SaveEvent(evt)
i++
}
}()

View File

@@ -6,8 +6,8 @@ import (
"fmt"
"os"
"github.com/urfave/cli/v3"
"fiatjaf.com/nostr"
"github.com/urfave/cli/v3"
)
// this is the default command when no subcommands are given, we will just try everything
@@ -21,16 +21,14 @@ var queryOrSave = &cli.Command{
re := &nostr.ReqEnvelope{}
e := &nostr.Event{}
f := &nostr.Filter{}
if json.Unmarshal([]byte(line), ee) == nil && ee.Event.ID != "" {
e = &ee.Event
return doSave(ctx, line, e)
if json.Unmarshal([]byte(line), ee) == nil && ee.Event.ID != nostr.ZeroID {
return doSave(ctx, line, ee.Event)
}
if json.Unmarshal([]byte(line), e) == nil && e.ID != "" {
return doSave(ctx, line, e)
if json.Unmarshal([]byte(line), e) == nil && e.ID != nostr.ZeroID {
return doSave(ctx, line, *e)
}
if json.Unmarshal([]byte(line), re) == nil && len(re.Filters) > 0 {
f = &re.Filters[0]
return doQuery(ctx, f)
if json.Unmarshal([]byte(line), re) == nil {
return doQuery(ctx, &re.Filter)
}
if json.Unmarshal([]byte(line), f) == nil && len(f.String()) > 2 {
return doQuery(ctx, f)
@@ -40,21 +38,16 @@ var queryOrSave = &cli.Command{
},
}
func doSave(ctx context.Context, line string, e *nostr.Event) error {
if err := db.SaveEvent(ctx, e); err != nil {
func doSave(ctx context.Context, line string, evt nostr.Event) error {
if err := db.SaveEvent(evt); err != nil {
return fmt.Errorf("failed to save event '%s': %s", line, err)
}
fmt.Fprintf(os.Stderr, "saved %s", e.ID)
fmt.Fprintf(os.Stderr, "saved %s", evt.ID)
return nil
}
func doQuery(ctx context.Context, f *nostr.Filter) error {
ch, err := db.QueryEvents(ctx, *f)
if err != nil {
return fmt.Errorf("error querying: %w", err)
}
for evt := range ch {
for evt := range db.QueryEvents(*f) {
fmt.Println(evt)
}
return nil

View File

@@ -13,8 +13,8 @@ import (
"golang.org/x/exp/slices"
)
func (b *LMDBBackend) CountEvents(filter nostr.Filter) (int64, error) {
var count int64 = 0
func (b *LMDBBackend) CountEvents(filter nostr.Filter) (uint32, error) {
var count uint32 = 0
queries, extraAuthors, extraKinds, extraTagKey, extraTagValues, since, err := b.prepareQueries(filter)
if err != nil {
@@ -95,12 +95,12 @@ func (b *LMDBBackend) CountEvents(filter nostr.Filter) (int64, error) {
// CountEventsHLL is like CountEvents, but it will build a hyperloglog value while iterating through results,
// following NIP-45
func (b *LMDBBackend) CountEventsHLL(filter nostr.Filter, offset int) (int64, *hyperloglog.HyperLogLog, error) {
func (b *LMDBBackend) CountEventsHLL(filter nostr.Filter, offset int) (uint32, *hyperloglog.HyperLogLog, error) {
if useCache, _ := b.EnableHLLCacheFor(filter.Kinds[0]); useCache {
return b.countEventsHLLCached(filter)
}
var count int64 = 0
var count uint32 = 0
// this is different than CountEvents because some of these extra checks are not applicable in HLL-valid filters
queries, _, extraKinds, extraTagKey, extraTagValues, since, err := b.prepareQueries(filter)
@@ -180,7 +180,7 @@ func (b *LMDBBackend) CountEventsHLL(filter nostr.Filter, offset int) (int64, *h
}
// countEventsHLLCached will just return a cached value from disk (and presumably we don't even have the events required to compute this anymore).
func (b *LMDBBackend) countEventsHLLCached(filter nostr.Filter) (int64, *hyperloglog.HyperLogLog, error) {
func (b *LMDBBackend) countEventsHLLCached(filter nostr.Filter) (uint32, *hyperloglog.HyperLogLog, error) {
cacheKey := make([]byte, 2+8)
binary.BigEndian.PutUint16(cacheKey[0:2], uint16(filter.Kinds[0]))
switch filter.Kinds[0] {
@@ -192,7 +192,7 @@ func (b *LMDBBackend) countEventsHLLCached(filter nostr.Filter) (int64, *hyperlo
hex.Decode(cacheKey[2:2+8], []byte(filter.Tags["E"][0][0:8*2]))
}
var count int64
var count uint32
var hll *hyperloglog.HyperLogLog
err := b.lmdbEnv.View(func(txn *lmdb.Txn) error {
@@ -204,7 +204,7 @@ func (b *LMDBBackend) countEventsHLLCached(filter nostr.Filter) (int64, *hyperlo
return err
}
hll = hyperloglog.NewWithRegisters(val, 0) // offset doesn't matter here
count = int64(hll.Count())
count = uint32(hll.Count())
return nil
})

View File

@@ -5,9 +5,9 @@ import (
"encoding/hex"
"fmt"
"github.com/PowerDNS/lmdb-go/lmdb"
"fiatjaf.com/nostr/eventstore/internal"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/eventstore/internal"
"github.com/PowerDNS/lmdb-go/lmdb"
)
type query struct {
@@ -143,7 +143,7 @@ func (b *LMDBBackend) prepareQueries(filter nostr.Filter) (
if filter.Authors != nil {
extraAuthors = make([][32]byte, len(filter.Authors))
for i, pk := range filter.Authors {
hex.Decode(extraAuthors[i][:], []byte(pk))
extraAuthors[i] = pk
}
}

View File

@@ -31,7 +31,7 @@ func (b *LMDBBackend) ReplaceEvent(evt nostr.Event) error {
shouldStore := true
for _, previous := range results {
if internal.IsOlder(previous.Event, evt) {
if err := b.delete(txn, previous.Event); err != nil {
if err := b.delete(txn, previous.Event.ID); err != nil {
return fmt.Errorf("failed to delete event %s for replacing: %w", previous.Event.ID, err)
}
} else {

View File

@@ -10,8 +10,8 @@ import (
"github.com/PowerDNS/lmdb-go/lmdb"
)
func (il *IndexingLayer) CountEvents(filter nostr.Filter) (int64, error) {
var count int64 = 0
func (il *IndexingLayer) CountEvents(filter nostr.Filter) (uint32, error) {
var count uint32 = 0
queries, extraAuthors, extraKinds, extraTagKey, extraTagValues, since, err := il.prepareQueries(filter)
if err != nil {

View File

@@ -1,10 +1,10 @@
package nullstore
import (
"context"
"iter"
"fiatjaf.com/nostr/eventstore"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/eventstore"
)
var _ eventstore.Store = NullStore{}
@@ -17,20 +17,22 @@ func (b NullStore) Init() error {
func (b NullStore) Close() {}
func (b NullStore) DeleteEvent(ctx context.Context, evt *nostr.Event) error {
func (b NullStore) DeleteEvent(id nostr.ID) error {
return nil
}
func (b NullStore) QueryEvents(ctx context.Context, filter nostr.Filter) (chan *nostr.Event, error) {
ch := make(chan *nostr.Event)
close(ch)
return ch, nil
func (b NullStore) QueryEvents(filter nostr.Filter) iter.Seq[nostr.Event] {
return func(yield func(nostr.Event) bool) {}
}
func (b NullStore) SaveEvent(ctx context.Context, evt *nostr.Event) error {
func (b NullStore) SaveEvent(evt nostr.Event) error {
return nil
}
func (b NullStore) ReplaceEvent(ctx context.Context, evt *nostr.Event) error {
func (b NullStore) ReplaceEvent(evt nostr.Event) error {
return nil
}
func (b NullStore) CountEvents(filter nostr.Filter) (uint32, error) {
return 0, nil
}

View File

@@ -69,8 +69,8 @@ func (b *SliceStore) QueryEvents(filter nostr.Filter) iter.Seq[nostr.Event] {
}
}
func (b *SliceStore) CountEvents(filter nostr.Filter) (int64, error) {
var val int64
func (b *SliceStore) CountEvents(filter nostr.Filter) (uint32, error) {
var val uint32
for _, event := range b.internal {
if filter.Matches(event) {
val++

View File

@@ -29,5 +29,5 @@ type Store interface {
ReplaceEvent(nostr.Event) error
// CountEvents counts all events that match a given filter
CountEvents(nostr.Filter) (int64, error)
CountEvents(nostr.Filter) (uint32, error)
}

View File

@@ -1,34 +0,0 @@
package count
import (
"context"
"fiatjaf.com/nostr/eventstore"
"fiatjaf.com/nostr"
)
type Wrapper struct {
eventstore.Store
}
var _ eventstore.Store = (*Wrapper)(nil)
func (w Wrapper) CountEvents(ctx context.Context, filter nostr.Filter) (int64, error) {
if counter, ok := w.Store.(eventstore.Counter); ok {
return counter.CountEvents(ctx, filter)
}
ch, err := w.Store.QueryEvents(ctx, filter)
if err != nil {
return 0, err
}
if ch == nil {
return 0, nil
}
var count int64
for range ch {
count++
}
return count, nil
}

View File

@@ -1,21 +0,0 @@
package disablesearch
import (
"context"
"fiatjaf.com/nostr/eventstore"
"fiatjaf.com/nostr"
)
type Wrapper struct {
eventstore.Store
}
var _ eventstore.Store = (*Wrapper)(nil)
func (w Wrapper) QueryEvents(ctx context.Context, filter nostr.Filter) (chan *nostr.Event, error) {
if filter.Search != "" {
return nil, nil
}
return w.Store.QueryEvents(ctx, filter)
}

View File

@@ -1,17 +1,20 @@
package eventstore
package wrappers
import (
"context"
"fmt"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/eventstore"
)
type RelayWrapper struct {
Store
var _ nostr.Publisher = StorePublisher{}
type StorePublisher struct {
eventstore.Store
}
func (w RelayWrapper) Publish(ctx context.Context, evt nostr.Event) error {
func (w StorePublisher) Publish(ctx context.Context, evt nostr.Event) error {
if nostr.IsEphemeralKind(evt.Kind) {
// do not store ephemeral events
return nil
@@ -22,7 +25,7 @@ func (w RelayWrapper) Publish(ctx context.Context, evt nostr.Event) error {
if nostr.IsRegularKind(evt.Kind) {
// regular events are just saved directly
if err := w.SaveEvent(evt); err != nil && err != ErrDupEvent {
if err := w.SaveEvent(evt); err != nil && err != eventstore.ErrDupEvent {
return fmt.Errorf("failed to save: %w", err)
}
return nil

View File

@@ -1,4 +1,4 @@
package test
package wrappers
import (
"context"
@@ -7,7 +7,6 @@ import (
"time"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/eventstore"
"fiatjaf.com/nostr/eventstore/slicestore"
"github.com/stretchr/testify/require"
)
@@ -21,7 +20,7 @@ func TestRelayWrapper(t *testing.T) {
s.Init()
defer s.Close()
w := eventstore.RelayWrapper{Store: s}
w := StorePublisher{Store: s}
evt1 := nostr.Event{
Kind: 3,

View File

@@ -0,0 +1,26 @@
package wrappers
import (
"context"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/eventstore"
)
var _ nostr.Querier = StoreQuerier{}
type StoreQuerier struct {
eventstore.Store
}
func (w StoreQuerier) QueryEvents(ctx context.Context, filter nostr.Filter) (chan nostr.Event, error) {
ch := make(chan nostr.Event)
go func() {
for evt := range w.Store.QueryEvents(filter) {
ch <- evt
}
}()
return ch, nil
}

View File

@@ -1,24 +0,0 @@
package skipevent
import (
"context"
"fiatjaf.com/nostr/eventstore"
"fiatjaf.com/nostr"
)
type Wrapper struct {
eventstore.Store
Skip func(ctx context.Context, evt *nostr.Event) bool
}
var _ eventstore.Store = (*Wrapper)(nil)
func (w Wrapper) SaveEvent(ctx context.Context, evt *nostr.Event) error {
if w.Skip(ctx, evt) {
return nil
}
return w.Store.SaveEvent(ctx, evt)
}