a bunch of [32]byte conversions. still more needed.

This commit is contained in:
fiatjaf
2025-04-14 17:31:23 -03:00
parent 40535e6b19
commit b4268d649c
132 changed files with 857 additions and 879 deletions

View File

@@ -5,8 +5,8 @@ import (
"sync"
"time"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/sdk/dataloader"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/sdk/dataloader"
)
// this is similar to replaceable_loader and reuses logic from that.
@@ -21,16 +21,16 @@ const (
)
func (sys *System) initializeAddressableDataloaders() {
sys.addressableLoaders = make([]*dataloader.Loader[string, []*nostr.Event], 4)
sys.addressableLoaders = make([]*dataloader.Loader[nostr.PubKey, []*nostr.Event], 4)
sys.addressableLoaders[kind_30000] = sys.createAddressableDataloader(30000)
sys.addressableLoaders[kind_30002] = sys.createAddressableDataloader(30002)
sys.addressableLoaders[kind_30015] = sys.createAddressableDataloader(30015)
sys.addressableLoaders[kind_30030] = sys.createAddressableDataloader(30030)
}
func (sys *System) createAddressableDataloader(kind int) *dataloader.Loader[string, []*nostr.Event] {
func (sys *System) createAddressableDataloader(kind uint16) *dataloader.Loader[nostr.PubKey, []*nostr.Event] {
return dataloader.NewBatchedLoader(
func(ctxs []context.Context, pubkeys []string) map[string]dataloader.Result[[]*nostr.Event] {
func(ctxs []context.Context, pubkeys []nostr.PubKey) map[nostr.PubKey]dataloader.Result[[]*nostr.Event] {
return sys.batchLoadAddressableEvents(ctxs, kind, pubkeys)
},
dataloader.Options{
@@ -42,11 +42,11 @@ func (sys *System) createAddressableDataloader(kind int) *dataloader.Loader[stri
func (sys *System) batchLoadAddressableEvents(
ctxs []context.Context,
kind int,
pubkeys []string,
) map[string]dataloader.Result[[]*nostr.Event] {
kind uint16,
pubkeys []nostr.PubKey,
) map[nostr.PubKey]dataloader.Result[[]*nostr.Event] {
batchSize := len(pubkeys)
results := make(map[string]dataloader.Result[[]*nostr.Event], batchSize)
results := make(map[nostr.PubKey]dataloader.Result[[]*nostr.Event], batchSize)
relayFilter := make([]nostr.DirectedFilter, 0, max(3, batchSize*2))
relayFilterIndex := make(map[string]int, max(3, batchSize*2))
@@ -62,7 +62,7 @@ func (sys *System) batchLoadAddressableEvents(
defer cancel()
// build batched queries for the external relays
go func(i int, pubkey string) {
go func(i int, pubkey nostr.PubKey) {
// gather relays we'll use for this pubkey
relays := sys.determineRelaysToQuery(ctx, pubkey, kind)
@@ -77,8 +77,8 @@ func (sys *System) batchLoadAddressableEvents(
dfilter = nostr.DirectedFilter{
Relay: relay,
Filter: nostr.Filter{
Kinds: []int{kind},
Authors: make([]string, 0, batchSize-i /* this and all pubkeys after this can be added */),
Kinds: []uint16{kind},
Authors: make([]nostr.PubKey, 0, batchSize-i /* this and all pubkeys after this can be added */),
},
}
idx = len(relayFilter)

View File

@@ -3,8 +3,8 @@ package cache
import "time"
type Cache32[V any] interface {
Get(k string) (v V, ok bool)
Delete(k string)
Set(k string, v V) bool
SetWithTTL(k string, v V, d time.Duration) bool
Get(k [32]byte) (v V, ok bool)
Delete(k [32]byte)
Set(k [32]byte, v V) bool
SetWithTTL(k [32]byte, v V, d time.Duration) bool
}

View File

@@ -2,47 +2,33 @@ package cache_memory
import (
"encoding/binary"
"encoding/hex"
"time"
"github.com/dgraph-io/ristretto"
)
type RistrettoCache[V any] struct {
Cache *ristretto.Cache[string, V]
Cache *ristretto.Cache[uint64, V]
}
func New32[V any](max int64) *RistrettoCache[V] {
cache, _ := ristretto.NewCache(&ristretto.Config[string, V]{
func New[V any](max int64) *RistrettoCache[V] {
cache, _ := ristretto.NewCache(&ristretto.Config[uint64, V]{
NumCounters: max * 10,
MaxCost: max,
BufferItems: 64,
KeyToHash: func(key string) (uint64, uint64) { return h32(key), 0 },
KeyToHash: func(key uint64) (uint64, uint64) { return key, 0 },
})
return &RistrettoCache[V]{Cache: cache}
}
func (s RistrettoCache[V]) Get(k string) (v V, ok bool) { return s.Cache.Get(k) }
func (s RistrettoCache[V]) Delete(k string) { s.Cache.Del(k) }
func (s RistrettoCache[V]) Set(k string, v V) bool { return s.Cache.Set(k, v, 1) }
func (s RistrettoCache[V]) SetWithTTL(k string, v V, d time.Duration) bool {
return s.Cache.SetWithTTL(k, v, 1, d)
func (s RistrettoCache[V]) Get(k [32]byte) (v V, ok bool) {
return s.Cache.Get(binary.BigEndian.Uint64(k[32-8:]))
}
func (s RistrettoCache[V]) Delete(k [32]byte) { s.Cache.Del(binary.BigEndian.Uint64(k[32-8:])) }
func (s RistrettoCache[V]) Set(k [32]byte, v V) bool {
return s.Cache.Set(binary.BigEndian.Uint64(k[32-8:]), v, 1)
}
func h32(key string) uint64 {
// we get an event id or pubkey as hex,
// so just extract the last 8 bytes from it and turn them into a uint64
return shortUint64(key)
}
func shortUint64(idOrPubkey string) uint64 {
length := len(idOrPubkey)
if length < 8 {
return 0
}
b, err := hex.DecodeString(idOrPubkey[length-8:])
if err != nil {
return 0
}
return uint64(binary.BigEndian.Uint32(b))
func (s RistrettoCache[V]) SetWithTTL(k [32]byte, v V, d time.Duration) bool {
return s.Cache.SetWithTTL(binary.BigEndian.Uint64(k[32-8:]), v, 1, d)
}

View File

@@ -1,22 +1,21 @@
package sdk
import (
"encoding/hex"
"fmt"
"slices"
"github.com/nbd-wtf/go-nostr/sdk/kvstore"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/sdk/kvstore"
)
const eventRelayPrefix = byte('r')
// makeEventRelayKey creates a key for storing event relay information.
// It uses the first 8 bytes of the event ID to create a compact key.
func makeEventRelayKey(eventID []byte) []byte {
func makeEventRelayKey(id nostr.ID) []byte {
// format: 'r' + first 8 bytes of event ID
key := make([]byte, 9)
key[0] = eventRelayPrefix
copy(key[1:], eventID[:8])
copy(key[1:], id[:8])
return key
}
@@ -75,15 +74,9 @@ func decodeRelayList(data []byte) []string {
// trackEventRelay records that an event was seen on a particular relay.
// If onlyIfItExists is true, it will only update existing records and not create new ones.
func (sys *System) trackEventRelay(eventID string, relay string, onlyIfItExists bool) {
// decode the event ID hex into bytes
idBytes, err := hex.DecodeString(eventID)
if err != nil || len(idBytes) < 8 {
return
}
func (sys *System) trackEventRelay(id nostr.ID, relay string, onlyIfItExists bool) {
// get the key for this event
key := makeEventRelayKey(idBytes)
key := makeEventRelayKey(id)
// update the relay list atomically
sys.KVStore.Update(key, func(data []byte) ([]byte, error) {
@@ -111,15 +104,9 @@ func (sys *System) trackEventRelay(eventID string, relay string, onlyIfItExists
// GetEventRelays returns all known relay URLs an event is known to be available on.
// It is based on information kept on KVStore.
func (sys *System) GetEventRelays(eventID string) ([]string, error) {
// decode the event ID hex into bytes
idBytes, err := hex.DecodeString(eventID)
if err != nil || len(idBytes) < 8 {
return nil, fmt.Errorf("invalid event id")
}
func (sys *System) GetEventRelays(id nostr.ID) ([]string, error) {
// get the key for this event
key := makeEventRelayKey(idBytes)
key := makeEventRelayKey(id)
// get stored relay list
data, err := sys.KVStore.Get(key)

View File

@@ -8,7 +8,7 @@ import (
"sync"
"sync/atomic"
"github.com/nbd-wtf/go-nostr"
"fiatjaf.com/nostr"
)
const (
@@ -29,7 +29,7 @@ func makePubkeyStreamKey(prefix byte, pubkey string) []byte {
// each pubkey (stored in KVStore) onwards.
func (sys *System) StreamLiveFeed(
ctx context.Context,
pubkeys []string,
pubkeys []nostr.PubKey,
kinds []int,
) (<-chan *nostr.Event, error) {
events := make(chan *nostr.Event)

View File

@@ -5,9 +5,9 @@ import (
"testing"
"time"
"fiatjaf.com/nostr"
"github.com/fiatjaf/eventstore/slicestore"
"github.com/fiatjaf/khatru"
"github.com/nbd-wtf/go-nostr"
"github.com/stretchr/testify/require"
)
@@ -56,9 +56,9 @@ func TestStreamLiveFeed(t *testing.T) {
// generate two random keypairs for testing
sk1 := nostr.GeneratePrivateKey()
pk1, _ := nostr.GetPublicKey(sk1)
pk1 := nostr.GetPublicKey(sk1)
sk2 := nostr.GeneratePrivateKey()
pk2, _ := nostr.GetPublicKey(sk2)
pk2 := nostr.GetPublicKey(sk2)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
@@ -131,7 +131,7 @@ func TestStreamLiveFeed(t *testing.T) {
go sys.Pool.PublishMany(ctx, []string{"ws://localhost:48482", "ws://localhost:48483"}, evt2)
// start streaming events for both pubkeys
events, err := sys.StreamLiveFeed(ctx, []string{pk1, pk2}, []int{1})
events, err := sys.StreamLiveFeed(ctx, []nostr.PubKey{pk1, pk2}, []int{1})
if err != nil {
t.Fatalf("failed to start streaming: %v", err)
}

View File

@@ -1,14 +1,13 @@
package badgerh
import (
"encoding/hex"
"fmt"
"math"
"slices"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/sdk/hints"
"github.com/dgraph-io/badger/v4"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/sdk/hints"
)
var _ hints.HintsDB = (*BadgerHints)(nil)
@@ -30,7 +29,7 @@ func (bh *BadgerHints) Close() {
bh.db.Close()
}
func (bh *BadgerHints) Save(pubkey string, relay string, hintkey hints.HintKey, ts nostr.Timestamp) {
func (bh *BadgerHints) Save(pubkey nostr.PubKey, relay string, hintkey hints.HintKey, ts nostr.Timestamp) {
if now := nostr.Now(); ts > now {
ts = now
}
@@ -64,7 +63,7 @@ func (bh *BadgerHints) Save(pubkey string, relay string, hintkey hints.HintKey,
}
}
func (bh *BadgerHints) TopN(pubkey string, n int) []string {
func (bh *BadgerHints) TopN(pubkey nostr.PubKey, n int) []string {
type relayScore struct {
relay string
score int64
@@ -73,7 +72,7 @@ func (bh *BadgerHints) TopN(pubkey string, n int) []string {
scores := make([]relayScore, 0, n)
err := bh.db.View(func(txn *badger.Txn) error {
opts := badger.DefaultIteratorOptions
opts.Prefix, _ = hex.DecodeString(pubkey)
opts.Prefix = pubkey[:]
it := txn.NewIterator(opts)
defer it.Close()
@@ -112,7 +111,7 @@ func (bh *BadgerHints) TopN(pubkey string, n int) []string {
return result
}
func (bh *BadgerHints) GetDetailedScores(pubkey string, n int) []hints.RelayScores {
func (bh *BadgerHints) GetDetailedScores(pubkey nostr.PubKey, n int) []hints.RelayScores {
type relayScore struct {
relay string
tss timestamps
@@ -121,11 +120,10 @@ func (bh *BadgerHints) GetDetailedScores(pubkey string, n int) []hints.RelayScor
scores := make([]relayScore, 0, n)
err := bh.db.View(func(txn *badger.Txn) error {
prefix, _ := hex.DecodeString(pubkey)
it := txn.NewIterator(badger.DefaultIteratorOptions)
defer it.Close()
for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() {
for it.Seek(pubkey[:]); it.ValidForPrefix(pubkey[:]); it.Next() {
item := it.Item()
k := item.Key()
relay := string(k[32:])
@@ -172,7 +170,7 @@ func (bh *BadgerHints) PrintScores() {
it := txn.NewIterator(badger.DefaultIteratorOptions)
defer it.Close()
var lastPubkey string
var lastPubkey nostr.PubKey
i := 0
for it.Seek(nil); it.Valid(); it.Next() {

View File

@@ -2,20 +2,19 @@ package badgerh
import (
"encoding/binary"
"encoding/hex"
"github.com/nbd-wtf/go-nostr"
"fiatjaf.com/nostr"
)
func encodeKey(pubhintkey, relay string) []byte {
func encodeKey(pubhintkey nostr.PubKey, relay string) []byte {
k := make([]byte, 32+len(relay))
hex.Decode(k[0:32], []byte(pubhintkey))
copy(k[0:32], pubhintkey[:])
copy(k[32:], relay)
return k
}
func parseKey(k []byte) (pubkey string, relay string) {
pubkey = hex.EncodeToString(k[0:32])
func parseKey(k []byte) (pubkey nostr.PubKey, relay string) {
pubkey = [32]byte(k[0:32])
relay = string(k[32:])
return
}

View File

@@ -1,6 +1,8 @@
package hints
import "github.com/nbd-wtf/go-nostr"
import (
"fiatjaf.com/nostr"
)
type RelayScores struct {
Relay string
@@ -9,8 +11,8 @@ type RelayScores struct {
}
type HintsDB interface {
TopN(pubkey string, n int) []string
Save(pubkey string, relay string, key HintKey, score nostr.Timestamp)
TopN(pubkey nostr.PubKey, n int) []string
Save(pubkey nostr.PubKey, relay string, key HintKey, score nostr.Timestamp)
PrintScores()
GetDetailedScores(pubkey string, n int) []RelayScores
GetDetailedScores(pubkey nostr.PubKey, n int) []RelayScores
}

View File

@@ -1,6 +1,6 @@
package hints
import "github.com/nbd-wtf/go-nostr"
import "fiatjaf.com/nostrlib"
const END_OF_WORLD nostr.Timestamp = 2208999600 // 2040-01-01

View File

@@ -6,8 +6,8 @@ import (
"slices"
"sync"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/sdk/hints"
"fiatjaf.com/nostrlib"
"fiatjaf.com/nostrlib/sdk/hints"
)
var _ hints.HintsDB = (*HintDB)(nil)

View File

@@ -7,8 +7,8 @@ import (
"strings"
"github.com/jmoiron/sqlx"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/sdk/hints"
"fiatjaf.com/nostrlib"
"fiatjaf.com/nostrlib/sdk/hints"
)
type SQLHints struct {

View File

@@ -7,7 +7,7 @@ import (
"os"
"testing"
"github.com/nbd-wtf/go-nostr/sdk/hints/sqlh"
"fiatjaf.com/nostrlib/sdk/hints/sqlh"
"github.com/stretchr/testify/require"
_ "github.com/tursodatabase/go-libsql"
)

View File

@@ -8,7 +8,7 @@ import (
"testing"
_ "github.com/mattn/go-sqlite3"
"github.com/nbd-wtf/go-nostr/sdk/hints/sqlh"
"fiatjaf.com/nostrlib/sdk/hints/sqlh"
"github.com/stretchr/testify/require"
)

View File

@@ -3,7 +3,7 @@ package test
import (
"testing"
"github.com/nbd-wtf/go-nostr/sdk/hints/memoryh"
"fiatjaf.com/nostrlib/sdk/hints/memoryh"
)
func TestMemoryHints(t *testing.T) {

View File

@@ -7,7 +7,7 @@ import (
"os"
"testing"
"github.com/nbd-wtf/go-nostr/sdk/hints/sqlh"
"fiatjaf.com/nostrlib/sdk/hints/sqlh"
"github.com/stretchr/testify/require"
_ "modernc.org/sqlite"
)

View File

@@ -4,8 +4,8 @@ import (
"testing"
"time"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/sdk/hints"
"fiatjaf.com/nostrlib"
"fiatjaf.com/nostrlib/sdk/hints"
"github.com/stretchr/testify/require"
)

View File

@@ -7,7 +7,7 @@ import (
"os"
"testing"
"github.com/nbd-wtf/go-nostr/sdk/hints/sqlh"
"fiatjaf.com/nostrlib/sdk/hints/sqlh"
_ "github.com/ncruces/go-sqlite3/driver"
_ "github.com/ncruces/go-sqlite3/embed"
"github.com/stretchr/testify/require"

View File

@@ -4,9 +4,9 @@ import (
"context"
"encoding/hex"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip05"
"github.com/nbd-wtf/go-nostr/nip19"
"fiatjaf.com/nostrlib"
"fiatjaf.com/nostrlib/nip05"
"fiatjaf.com/nostrlib/nip19"
)
// InputToProfile turns any npub/nprofile/hex/nip05 input into a ProfilePointer (or nil).

View File

@@ -2,7 +2,7 @@ package badger
import (
"github.com/dgraph-io/badger/v4"
"github.com/nbd-wtf/go-nostr/sdk/kvstore"
"fiatjaf.com/nostrlib/sdk/kvstore"
)
var _ kvstore.KVStore = (*Store)(nil)

View File

@@ -4,7 +4,7 @@ import (
"os"
"github.com/PowerDNS/lmdb-go/lmdb"
"github.com/nbd-wtf/go-nostr/sdk/kvstore"
"fiatjaf.com/nostrlib/sdk/kvstore"
)
var _ kvstore.KVStore = (*Store)(nil)

View File

@@ -3,7 +3,7 @@ package memory
import (
"sync"
"github.com/nbd-wtf/go-nostr/sdk/kvstore"
"fiatjaf.com/nostrlib/sdk/kvstore"
)
var _ kvstore.KVStore = (*Store)(nil)

View File

@@ -3,23 +3,22 @@ package sdk
import (
"context"
"slices"
"strconv"
"sync"
"time"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/sdk/cache"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/sdk/cache"
)
type GenericList[I TagItemWithValue] struct {
PubKey string `json:"-"` // must always be set otherwise things will break
PubKey nostr.PubKey `json:"-"` // must always be set otherwise things will break
Event *nostr.Event `json:"-"` // may be empty if a contact list event wasn't found
Items []I
}
type TagItemWithValue interface {
Value() string
Value() any
}
var (
@@ -30,8 +29,8 @@ var (
func fetchGenericList[I TagItemWithValue](
sys *System,
ctx context.Context,
pubkey string,
actualKind int,
pubkey nostr.PubKey,
actualKind uint16,
replaceableIndex replaceableIndex,
parseTag func(nostr.Tag) (I, bool),
cache cache.Cache32[GenericList[I]],
@@ -39,8 +38,8 @@ func fetchGenericList[I TagItemWithValue](
// we have 60 mutexes, so we can load up to 60 lists at the same time, but if we do the same exact
// call that will do it only once, the subsequent ones will wait for a result to be cached
// and then return it from cache -- 13 is an arbitrary index for the pubkey
n, _ := strconv.ParseUint(pubkey[14:16], 16, 8)
lockIdx := (n + uint64(actualKind)) % 60
n := pubkey[7]
lockIdx := (uint16(n) + actualKind) % 60
genericListMutexes[lockIdx].Lock()
if valueWasJustCached[lockIdx] {
@@ -58,7 +57,7 @@ func fetchGenericList[I TagItemWithValue](
v := GenericList[I]{PubKey: pubkey}
events, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{Kinds: []int{actualKind}, Authors: []string{pubkey}})
events, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{Kinds: []uint16{actualKind}, Authors: []nostr.PubKey{pubkey}})
if len(events) != 0 {
// ok, we found something locally
items := parseItemsFromEventTags(events[0], parseTag)
@@ -104,7 +103,7 @@ func fetchGenericList[I TagItemWithValue](
func tryFetchListFromNetwork[I TagItemWithValue](
ctx context.Context,
sys *System,
pubkey string,
pubkey nostr.PubKey,
replaceableIndex replaceableIndex,
parseTag func(nostr.Tag) (I, bool),
) *GenericList[I] {
@@ -140,7 +139,7 @@ func parseItemsFromEventTags[I TagItemWithValue](
return result
}
func getLocalStoreRefreshDaysForKind(kind int) nostr.Timestamp {
func getLocalStoreRefreshDaysForKind(kind uint16) nostr.Timestamp {
switch kind {
case 0:
return 7

View File

@@ -2,11 +2,9 @@ package sdk
import (
"context"
"strconv"
"strings"
"github.com/nbd-wtf/go-nostr"
cache_memory "github.com/nbd-wtf/go-nostr/sdk/cache/memory"
"fiatjaf.com/nostr"
cache_memory "fiatjaf.com/nostr/sdk/cache/memory"
)
type EventRef struct{ nostr.Pointer }
@@ -15,7 +13,7 @@ func (e EventRef) Value() string { return e.Pointer.AsTagReference() }
func (sys *System) FetchBookmarkList(ctx context.Context, pubkey string) GenericList[EventRef] {
if sys.BookmarkListCache == nil {
sys.BookmarkListCache = cache_memory.New32[GenericList[EventRef]](1000)
sys.BookmarkListCache = cache_memory.New[GenericList[EventRef]](1000)
}
ml, _ := fetchGenericList(sys, ctx, pubkey, 10003, kind_10003, parseEventRef, sys.BookmarkListCache)
@@ -24,7 +22,7 @@ func (sys *System) FetchBookmarkList(ctx context.Context, pubkey string) Generic
func (sys *System) FetchPinList(ctx context.Context, pubkey string) GenericList[EventRef] {
if sys.PinListCache == nil {
sys.PinListCache = cache_memory.New32[GenericList[EventRef]](1000)
sys.PinListCache = cache_memory.New[GenericList[EventRef]](1000)
}
ml, _ := fetchGenericList(sys, ctx, pubkey, 10001, kind_10001, parseEventRef, sys.PinListCache)
@@ -37,36 +35,16 @@ func parseEventRef(tag nostr.Tag) (evr EventRef, ok bool) {
}
switch tag[0] {
case "e":
if !nostr.IsValid32ByteHex(tag[1]) {
pointer, err := nostr.EventPointerFromTag(tag)
if err != nil {
return evr, false
}
pointer := nostr.EventPointer{
ID: tag[1],
}
if len(tag) >= 3 {
pointer.Relays = []string{nostr.NormalizeURL(tag[2])}
if len(tag) >= 4 {
pointer.Author = tag[3]
}
}
evr.Pointer = pointer
case "a":
spl := strings.SplitN(tag[1], ":", 3)
if len(spl) != 3 || !nostr.IsValidPublicKey(spl[1]) {
pointer, err := nostr.EntityPointerFromTag(tag)
if err != nil {
return evr, false
}
pointer := nostr.EntityPointer{
PublicKey: spl[1],
Identifier: spl[2],
}
if kind, err := strconv.Atoi(spl[0]); err != nil {
return evr, false
} else {
pointer.Kind = kind
}
if len(tag) >= 3 {
pointer.Relays = []string{nostr.NormalizeURL(tag[2])}
}
evr.Pointer = pointer
default:
return evr, false

View File

@@ -5,39 +5,39 @@ import (
"net/url"
"strings"
"github.com/nbd-wtf/go-nostr"
cache_memory "github.com/nbd-wtf/go-nostr/sdk/cache/memory"
"fiatjaf.com/nostr"
cache_memory "fiatjaf.com/nostr/sdk/cache/memory"
)
type ProfileRef struct {
Pubkey string
Pubkey nostr.PubKey
Relay string
Petname string
}
func (f ProfileRef) Value() string { return f.Pubkey }
func (f ProfileRef) Value() nostr.PubKey { return f.Pubkey }
func (sys *System) FetchFollowList(ctx context.Context, pubkey string) GenericList[ProfileRef] {
func (sys *System) FetchFollowList(ctx context.Context, pubkey nostr.PubKey) GenericList[ProfileRef] {
if sys.FollowListCache == nil {
sys.FollowListCache = cache_memory.New32[GenericList[ProfileRef]](1000)
sys.FollowListCache = cache_memory.New[GenericList[ProfileRef]](1000)
}
fl, _ := fetchGenericList(sys, ctx, pubkey, 3, kind_3, parseProfileRef, sys.FollowListCache)
return fl
}
func (sys *System) FetchMuteList(ctx context.Context, pubkey string) GenericList[ProfileRef] {
func (sys *System) FetchMuteList(ctx context.Context, pubkey nostr.PubKey) GenericList[ProfileRef] {
if sys.MuteListCache == nil {
sys.MuteListCache = cache_memory.New32[GenericList[ProfileRef]](1000)
sys.MuteListCache = cache_memory.New[GenericList[ProfileRef]](1000)
}
ml, _ := fetchGenericList(sys, ctx, pubkey, 10000, kind_10000, parseProfileRef, sys.MuteListCache)
return ml
}
func (sys *System) FetchFollowSets(ctx context.Context, pubkey string) GenericSets[ProfileRef] {
func (sys *System) FetchFollowSets(ctx context.Context, pubkey nostr.PubKey) GenericSets[ProfileRef] {
if sys.FollowSetsCache == nil {
sys.FollowSetsCache = cache_memory.New32[GenericSets[ProfileRef]](1000)
sys.FollowSetsCache = cache_memory.New[GenericSets[ProfileRef]](1000)
}
ml, _ := fetchGenericSets(sys, ctx, pubkey, 30000, kind_30000, parseProfileRef, sys.FollowSetsCache)
@@ -52,11 +52,13 @@ func parseProfileRef(tag nostr.Tag) (fw ProfileRef, ok bool) {
return fw, false
}
fw.Pubkey = tag[1]
if !nostr.IsValidPublicKey(fw.Pubkey) {
pubkey, err := nostr.PubKeyFromHex(fw.Pubkey)
if err != nil {
return fw, false
}
fw.Pubkey = pubkey
if len(tag) > 2 {
if _, err := url.Parse(tag[2]); err == nil {
fw.Relay = nostr.NormalizeURL(tag[2])

View File

@@ -3,8 +3,8 @@ package sdk
import (
"context"
"github.com/nbd-wtf/go-nostr"
cache_memory "github.com/nbd-wtf/go-nostr/sdk/cache/memory"
"fiatjaf.com/nostr"
cache_memory "fiatjaf.com/nostr/sdk/cache/memory"
)
type Relay struct {
@@ -19,32 +19,32 @@ type RelayURL string
func (r RelayURL) Value() string { return string(r) }
func (sys *System) FetchRelayList(ctx context.Context, pubkey string) GenericList[Relay] {
func (sys *System) FetchRelayList(ctx context.Context, pubkey nostr.PubKey) GenericList[Relay] {
ml, _ := fetchGenericList(sys, ctx, pubkey, 10002, kind_10002, parseRelayFromKind10002, sys.RelayListCache)
return ml
}
func (sys *System) FetchBlockedRelayList(ctx context.Context, pubkey string) GenericList[RelayURL] {
func (sys *System) FetchBlockedRelayList(ctx context.Context, pubkey nostr.PubKey) GenericList[RelayURL] {
if sys.BlockedRelayListCache == nil {
sys.BlockedRelayListCache = cache_memory.New32[GenericList[RelayURL]](1000)
sys.BlockedRelayListCache = cache_memory.New[GenericList[RelayURL]](1000)
}
ml, _ := fetchGenericList(sys, ctx, pubkey, 10006, kind_10006, parseRelayURL, sys.BlockedRelayListCache)
return ml
}
func (sys *System) FetchSearchRelayList(ctx context.Context, pubkey string) GenericList[RelayURL] {
func (sys *System) FetchSearchRelayList(ctx context.Context, pubkey nostr.PubKey) GenericList[RelayURL] {
if sys.SearchRelayListCache == nil {
sys.SearchRelayListCache = cache_memory.New32[GenericList[RelayURL]](1000)
sys.SearchRelayListCache = cache_memory.New[GenericList[RelayURL]](1000)
}
ml, _ := fetchGenericList(sys, ctx, pubkey, 10007, kind_10007, parseRelayURL, sys.SearchRelayListCache)
return ml
}
func (sys *System) FetchRelaySets(ctx context.Context, pubkey string) GenericSets[RelayURL] {
func (sys *System) FetchRelaySets(ctx context.Context, pubkey nostr.PubKey) GenericSets[RelayURL] {
if sys.RelaySetsCache == nil {
sys.RelaySetsCache = cache_memory.New32[GenericSets[RelayURL]](1000)
sys.RelaySetsCache = cache_memory.New[GenericSets[RelayURL]](1000)
}
ml, _ := fetchGenericSets(sys, ctx, pubkey, 30002, kind_30002, parseRelayURL, sys.RelaySetsCache)
@@ -52,7 +52,11 @@ func (sys *System) FetchRelaySets(ctx context.Context, pubkey string) GenericSet
}
func parseRelayFromKind10002(tag nostr.Tag) (rl Relay, ok bool) {
if u := tag.Value(); u != "" && tag[0] == "r" {
if len(tag) < 2 {
return rl, false
}
if u := tag[1]; u != "" && tag[0] == "r" {
if !nostr.IsValidRelayURL(u) {
return rl, false
}
@@ -78,7 +82,11 @@ func parseRelayFromKind10002(tag nostr.Tag) (rl Relay, ok bool) {
}
func parseRelayURL(tag nostr.Tag) (rl RelayURL, ok bool) {
if u := tag.Value(); u != "" && tag[0] == "relay" {
if len(tag) < 2 {
return rl, false
}
if u := tag[1]; u != "" && tag[0] == "relay" {
if !nostr.IsValidRelayURL(u) {
return rl, false
}

View File

@@ -3,26 +3,26 @@ package sdk
import (
"context"
"github.com/nbd-wtf/go-nostr"
cache_memory "github.com/nbd-wtf/go-nostr/sdk/cache/memory"
"fiatjaf.com/nostr"
cache_memory "fiatjaf.com/nostr/sdk/cache/memory"
)
type Topic string
func (r Topic) Value() string { return string(r) }
func (sys *System) FetchTopicList(ctx context.Context, pubkey string) GenericList[Topic] {
func (sys *System) FetchTopicList(ctx context.Context, pubkey nostr.PubKey) GenericList[Topic] {
if sys.TopicListCache == nil {
sys.TopicListCache = cache_memory.New32[GenericList[Topic]](1000)
sys.TopicListCache = cache_memory.New[GenericList[Topic]](1000)
}
ml, _ := fetchGenericList(sys, ctx, pubkey, 10015, kind_10015, parseTopicString, sys.TopicListCache)
return ml
}
func (sys *System) FetchTopicSets(ctx context.Context, pubkey string) GenericSets[Topic] {
func (sys *System) FetchTopicSets(ctx context.Context, pubkey nostr.PubKey) GenericSets[Topic] {
if sys.TopicSetsCache == nil {
sys.TopicSetsCache = cache_memory.New32[GenericSets[Topic]](1000)
sys.TopicSetsCache = cache_memory.New[GenericSets[Topic]](1000)
}
ml, _ := fetchGenericSets(sys, ctx, pubkey, 30015, kind_30015, parseTopicString, sys.TopicSetsCache)
@@ -30,8 +30,12 @@ func (sys *System) FetchTopicSets(ctx context.Context, pubkey string) GenericSet
}
func parseTopicString(tag nostr.Tag) (t Topic, ok bool) {
if t := tag.Value(); t != "" && tag[0] == "t" {
if len(tag) < 2 {
return t, false
}
if t := tag[1]; t != "" && tag[0] == "t" {
return Topic(t), true
}
return t, false
}

View File

@@ -2,18 +2,17 @@ package sdk
import (
"encoding/binary"
"encoding/hex"
"github.com/nbd-wtf/go-nostr"
"fiatjaf.com/nostr"
)
var kvStoreLastFetchPrefix = byte('f')
func makeLastFetchKey(kind int, pubkey string) []byte {
func makeLastFetchKey(kind uint16, pubkey nostr.PubKey) []byte {
buf := make([]byte, 1+5+32)
buf[0] = kvStoreLastFetchPrefix
binary.LittleEndian.PutUint32(buf[1:], uint32(kind))
hex.Decode(buf[5:], []byte(pubkey))
copy(buf[5:], pubkey[:])
return buf
}

View File

@@ -5,10 +5,10 @@ import (
"fmt"
"time"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip05"
"github.com/nbd-wtf/go-nostr/nip19"
"github.com/nbd-wtf/go-nostr/sdk/hints"
"fiatjaf.com/nostrlib"
"fiatjaf.com/nostrlib/nip05"
"fiatjaf.com/nostrlib/nip19"
"fiatjaf.com/nostrlib/sdk/hints"
)
// ProfileMetadata represents user profile information from kind 0 events.

View File

@@ -2,14 +2,15 @@ package sdk
import (
"context"
"strconv"
"time"
"fiatjaf.com/nostr"
)
var outboxShortTermCache = [256]ostcEntry{}
type ostcEntry struct {
pubkey string
pubkey nostr.PubKey
relays []string
when time.Time
}
@@ -18,8 +19,8 @@ type ostcEntry struct {
// NIP-05, past attempts at fetching data from a user from a given relay, including successes and failures, and
// the "write" relays of kind:10002, in order to determine the best possible list of relays where a user might be
// currently publishing their events to.
func (sys *System) FetchOutboxRelays(ctx context.Context, pubkey string, n int) []string {
ostcIndex, _ := strconv.ParseUint(pubkey[12:14], 16, 8)
func (sys *System) FetchOutboxRelays(ctx context.Context, pubkey nostr.PubKey, n int) []string {
ostcIndex := pubkey[7]
now := time.Now()
if entry := outboxShortTermCache[ostcIndex]; entry.pubkey == pubkey && entry.when.Add(time.Minute*2).After(now) {
return entry.relays

View File

@@ -9,8 +9,8 @@ import (
"sync/atomic"
"time"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/sdk/dataloader"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/sdk/dataloader"
)
type replaceableIndex int
@@ -33,7 +33,7 @@ const (
type EventResult dataloader.Result[*nostr.Event]
func (sys *System) initializeReplaceableDataloaders() {
sys.replaceableLoaders = make([]*dataloader.Loader[string, *nostr.Event], 12)
sys.replaceableLoaders = make([]*dataloader.Loader[nostr.PubKey, *nostr.Event], 12)
sys.replaceableLoaders[kind_0] = sys.createReplaceableDataloader(0)
sys.replaceableLoaders[kind_3] = sys.createReplaceableDataloader(3)
sys.replaceableLoaders[kind_10000] = sys.createReplaceableDataloader(10000)
@@ -48,9 +48,9 @@ func (sys *System) initializeReplaceableDataloaders() {
sys.replaceableLoaders[kind_10030] = sys.createReplaceableDataloader(10030)
}
func (sys *System) createReplaceableDataloader(kind int) *dataloader.Loader[string, *nostr.Event] {
func (sys *System) createReplaceableDataloader(kind uint16) *dataloader.Loader[nostr.PubKey, *nostr.Event] {
return dataloader.NewBatchedLoader(
func(ctxs []context.Context, pubkeys []string) map[string]dataloader.Result[*nostr.Event] {
func(ctxs []context.Context, pubkeys []nostr.PubKey) map[nostr.PubKey]dataloader.Result[*nostr.Event] {
return sys.batchLoadReplaceableEvents(ctxs, kind, pubkeys)
},
dataloader.Options{
@@ -62,11 +62,11 @@ func (sys *System) createReplaceableDataloader(kind int) *dataloader.Loader[stri
func (sys *System) batchLoadReplaceableEvents(
ctxs []context.Context,
kind int,
pubkeys []string,
) map[string]dataloader.Result[*nostr.Event] {
kind uint16,
pubkeys []nostr.PubKey,
) map[nostr.PubKey]dataloader.Result[*nostr.Event] {
batchSize := len(pubkeys)
results := make(map[string]dataloader.Result[*nostr.Event], batchSize)
results := make(map[nostr.PubKey]dataloader.Result[*nostr.Event], batchSize)
relayFilter := make([]nostr.DirectedFilter, 0, max(3, batchSize*2))
relayFilterIndex := make(map[string]int, max(3, batchSize*2))
@@ -83,7 +83,7 @@ func (sys *System) batchLoadReplaceableEvents(
defer cancel()
// build batched queries for the external relays
go func(i int, pubkey string) {
go func(i int, pubkey nostr.PubKey) {
// gather relays we'll use for this pubkey
relays := sys.determineRelaysToQuery(ctx, pubkey, kind)
@@ -98,8 +98,8 @@ func (sys *System) batchLoadReplaceableEvents(
dfilter = nostr.DirectedFilter{
Relay: relay,
Filter: nostr.Filter{
Kinds: []int{kind},
Authors: make([]string, 0, batchSize-i /* this and all pubkeys after this can be added */),
Kinds: []uint16{kind},
Authors: make([]nostr.PubKey, 0, batchSize-i /* this and all pubkeys after this can be added */),
},
}
idx = len(relayFilter)
@@ -122,7 +122,7 @@ func (sys *System) batchLoadReplaceableEvents(
// query all relays with the prepared filters
wg.Wait()
multiSubs := sys.Pool.BatchedSubManyEose(aggregatedContext, relayFilter,
nostr.WithLabel("repl~"+strconv.Itoa(kind)),
nostr.WithLabel("repl~"+strconv.Itoa(int(kind))),
)
for {
select {
@@ -141,7 +141,7 @@ func (sys *System) batchLoadReplaceableEvents(
}
}
func (sys *System) determineRelaysToQuery(ctx context.Context, pubkey string, kind int) []string {
func (sys *System) determineRelaysToQuery(ctx context.Context, pubkey nostr.PubKey, kind uint16) []string {
var relays []string
// search in specific relays for user

View File

@@ -7,7 +7,7 @@ import (
"sync"
"testing"
"github.com/nbd-wtf/go-nostr"
"fiatjaf.com/nostrlib"
"github.com/stretchr/testify/require"
)

View File

@@ -3,7 +3,7 @@ package sdk
import (
"context"
"github.com/nbd-wtf/go-nostr"
"fiatjaf.com/nostrlib"
)
func (sys *System) SearchUsers(ctx context.Context, query string) []ProfileMetadata {

View File

@@ -3,17 +3,16 @@ package sdk
import (
"context"
"slices"
"strconv"
"time"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/sdk/cache"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/sdk/cache"
)
// this is similar to list.go and inherits code from that.
type GenericSets[I TagItemWithValue] struct {
PubKey string `json:"-"`
PubKey nostr.PubKey `json:"-"`
Events []*nostr.Event `json:"-"`
Sets map[string][]I
@@ -22,14 +21,14 @@ type GenericSets[I TagItemWithValue] struct {
func fetchGenericSets[I TagItemWithValue](
sys *System,
ctx context.Context,
pubkey string,
actualKind int,
pubkey nostr.PubKey,
actualKind uint16,
addressableIndex addressableIndex,
parseTag func(nostr.Tag) (I, bool),
cache cache.Cache32[GenericSets[I]],
) (fl GenericSets[I], fromInternal bool) {
n, _ := strconv.ParseUint(pubkey[14:16], 16, 8)
lockIdx := (n + uint64(actualKind)) % 60
n := pubkey[7]
lockIdx := (uint16(n) + actualKind) % 60
genericListMutexes[lockIdx].Lock()
if valueWasJustCached[lockIdx] {
@@ -47,7 +46,7 @@ func fetchGenericSets[I TagItemWithValue](
v := GenericSets[I]{PubKey: pubkey}
events, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{Kinds: []int{actualKind}, Authors: []string{pubkey}})
events, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{Kinds: []uint16{actualKind}, Authors: []nostr.PubKey{pubkey}})
if len(events) != 0 {
// ok, we found something locally
sets := parseSetsFromEvents(events, parseTag)
@@ -93,7 +92,7 @@ func fetchGenericSets[I TagItemWithValue](
func tryFetchSetsFromNetwork[I TagItemWithValue](
ctx context.Context,
sys *System,
pubkey string,
pubkey nostr.PubKey,
addressableIndex addressableIndex,
parseTag func(nostr.Tag) (I, bool),
) *GenericSets[I] {

View File

@@ -6,9 +6,9 @@ import (
"slices"
"sync"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/nip19"
"github.com/nbd-wtf/go-nostr/sdk/hints"
"fiatjaf.com/nostrlib"
"fiatjaf.com/nostrlib/nip19"
"fiatjaf.com/nostrlib/sdk/hints"
)
// FetchSpecificEventParameters contains options for fetching specific events.

View File

@@ -4,16 +4,16 @@ import (
"context"
"math/rand/v2"
"fiatjaf.com/nostr"
"fiatjaf.com/nostr/sdk/cache"
cache_memory "fiatjaf.com/nostr/sdk/cache/memory"
"fiatjaf.com/nostr/sdk/dataloader"
"fiatjaf.com/nostr/sdk/hints"
"fiatjaf.com/nostr/sdk/hints/memoryh"
"fiatjaf.com/nostr/sdk/kvstore"
kvstore_memory "fiatjaf.com/nostr/sdk/kvstore/memory"
"github.com/fiatjaf/eventstore"
"github.com/fiatjaf/eventstore/nullstore"
"github.com/nbd-wtf/go-nostr"
"github.com/nbd-wtf/go-nostr/sdk/cache"
cache_memory "github.com/nbd-wtf/go-nostr/sdk/cache/memory"
"github.com/nbd-wtf/go-nostr/sdk/dataloader"
"github.com/nbd-wtf/go-nostr/sdk/hints"
"github.com/nbd-wtf/go-nostr/sdk/hints/memoryh"
"github.com/nbd-wtf/go-nostr/sdk/kvstore"
kvstore_memory "github.com/nbd-wtf/go-nostr/sdk/kvstore/memory"
)
// System represents the core functionality of the SDK, providing access to
@@ -53,8 +53,8 @@ type System struct {
StoreRelay nostr.RelayStore
replaceableLoaders []*dataloader.Loader[string, *nostr.Event]
addressableLoaders []*dataloader.Loader[string, []*nostr.Event]
replaceableLoaders []*dataloader.Loader[nostr.PubKey, *nostr.Event]
addressableLoaders []*dataloader.Loader[nostr.PubKey, []*nostr.Event]
}
// SystemModifier is a function that modifies a System instance.
@@ -130,10 +130,10 @@ func NewSystem(mods ...SystemModifier) *System {
}
if sys.MetadataCache == nil {
sys.MetadataCache = cache_memory.New32[ProfileMetadata](8000)
sys.MetadataCache = cache_memory.New[ProfileMetadata](8000)
}
if sys.RelayListCache == nil {
sys.RelayListCache = cache_memory.New32[GenericList[Relay]](8000)
sys.RelayListCache = cache_memory.New[GenericList[Relay]](8000)
}
if sys.Store == nil {

View File

@@ -3,12 +3,12 @@ package sdk
import (
"net/url"
"github.com/nbd-wtf/go-nostr"
"fiatjaf.com/nostr"
"fiatjaf.com/nostrlib/sdk/hints"
"github.com/nbd-wtf/go-nostr/nip27"
"github.com/nbd-wtf/go-nostr/sdk/hints"
)
func (sys *System) TrackQueryAttempts(relay string, author string, kind int) {
func (sys *System) TrackQueryAttempts(relay string, author nostr.PubKey, kind uint16) {
if IsVirtualRelay(relay) {
return
}
@@ -83,8 +83,10 @@ func (sys *System) trackEventHints(ie nostr.RelayEvent) {
if p, err := url.Parse(tag[2]); err != nil || (p.Scheme != "wss" && p.Scheme != "ws") {
continue
}
if tag[0] == "p" && nostr.IsValidPublicKey(tag[1]) {
sys.Hints.Save(tag[1], nostr.NormalizeURL(tag[2]), hints.LastInHint, ie.CreatedAt)
if tag[0] == "p" {
if pk, err := nostr.PubKeyFromHex(tag[1]); err == nil {
sys.Hints.Save(pk, nostr.NormalizeURL(tag[2]), hints.LastInHint, ie.CreatedAt)
}
}
}
default:
@@ -101,8 +103,10 @@ func (sys *System) trackEventHints(ie nostr.RelayEvent) {
if p, err := url.Parse(tag[2]); err != nil || (p.Scheme != "wss" && p.Scheme != "ws") {
continue
}
if tag[0] == "p" && nostr.IsValidPublicKey(tag[1]) {
sys.Hints.Save(tag[1], nostr.NormalizeURL(tag[2]), hints.LastInHint, ie.CreatedAt)
if tag[0] == "p" {
if pk, err := nostr.PubKeyFromHex(tag[1]); err == nil {
sys.Hints.Save(pk, nostr.NormalizeURL(tag[2]), hints.LastInHint, ie.CreatedAt)
}
}
}
@@ -144,7 +148,7 @@ func (sys *System) trackEventHints(ie nostr.RelayEvent) {
}
// TrackEventRelaysD is a companion to TrackEventRelays meant to be used with WithDuplicateMiddleware()
func (sys *System) TrackEventRelaysD(relay, id string) {
func (sys *System) TrackEventRelaysD(relay string, id nostr.ID) {
if IsVirtualRelay(relay) {
return
}