it never ends.
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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++
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
})
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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++
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
@@ -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,
|
||||
26
eventstore/wrappers/querier.go
Normal file
26
eventstore/wrappers/querier.go
Normal 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
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user