sdk finally compiles.
This commit is contained in:
@@ -21,16 +21,16 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (sys *System) initializeAddressableDataloaders() {
|
func (sys *System) initializeAddressableDataloaders() {
|
||||||
sys.addressableLoaders = make([]*dataloader.Loader[nostr.PubKey, []*nostr.Event], 4)
|
sys.addressableLoaders = make([]*dataloader.Loader[nostr.PubKey, []nostr.Event], 4)
|
||||||
sys.addressableLoaders[kind_30000] = sys.createAddressableDataloader(30000)
|
sys.addressableLoaders[kind_30000] = sys.createAddressableDataloader(30000)
|
||||||
sys.addressableLoaders[kind_30002] = sys.createAddressableDataloader(30002)
|
sys.addressableLoaders[kind_30002] = sys.createAddressableDataloader(30002)
|
||||||
sys.addressableLoaders[kind_30015] = sys.createAddressableDataloader(30015)
|
sys.addressableLoaders[kind_30015] = sys.createAddressableDataloader(30015)
|
||||||
sys.addressableLoaders[kind_30030] = sys.createAddressableDataloader(30030)
|
sys.addressableLoaders[kind_30030] = sys.createAddressableDataloader(30030)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *System) createAddressableDataloader(kind uint16) *dataloader.Loader[nostr.PubKey, []*nostr.Event] {
|
func (sys *System) createAddressableDataloader(kind uint16) *dataloader.Loader[nostr.PubKey, []nostr.Event] {
|
||||||
return dataloader.NewBatchedLoader(
|
return dataloader.NewBatchedLoader(
|
||||||
func(ctxs []context.Context, pubkeys []nostr.PubKey) map[nostr.PubKey]dataloader.Result[[]*nostr.Event] {
|
func(ctxs []context.Context, pubkeys []nostr.PubKey) map[nostr.PubKey]dataloader.Result[[]nostr.Event] {
|
||||||
return sys.batchLoadAddressableEvents(ctxs, kind, pubkeys)
|
return sys.batchLoadAddressableEvents(ctxs, kind, pubkeys)
|
||||||
},
|
},
|
||||||
dataloader.Options{
|
dataloader.Options{
|
||||||
@@ -44,9 +44,9 @@ func (sys *System) batchLoadAddressableEvents(
|
|||||||
ctxs []context.Context,
|
ctxs []context.Context,
|
||||||
kind uint16,
|
kind uint16,
|
||||||
pubkeys []nostr.PubKey,
|
pubkeys []nostr.PubKey,
|
||||||
) map[nostr.PubKey]dataloader.Result[[]*nostr.Event] {
|
) map[nostr.PubKey]dataloader.Result[[]nostr.Event] {
|
||||||
batchSize := len(pubkeys)
|
batchSize := len(pubkeys)
|
||||||
results := make(map[nostr.PubKey]dataloader.Result[[]*nostr.Event], batchSize)
|
results := make(map[nostr.PubKey]dataloader.Result[[]nostr.Event], batchSize)
|
||||||
relayFilter := make([]nostr.DirectedFilter, 0, max(3, batchSize*2))
|
relayFilter := make([]nostr.DirectedFilter, 0, max(3, batchSize*2))
|
||||||
relayFilterIndex := make(map[string]int, max(3, batchSize*2))
|
relayFilterIndex := make(map[string]int, max(3, batchSize*2))
|
||||||
|
|
||||||
@@ -103,7 +103,9 @@ func (sys *System) batchLoadAddressableEvents(
|
|||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|
||||||
// query all relays with the prepared filters
|
// query all relays with the prepared filters
|
||||||
multiSubs := sys.Pool.BatchedSubManyEose(aggregatedContext, relayFilter)
|
multiSubs := sys.Pool.BatchedSubManyEose(aggregatedContext, relayFilter, nostr.SubscriptionOptions{
|
||||||
|
Label: "loadaddrs",
|
||||||
|
})
|
||||||
nextEvent:
|
nextEvent:
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -115,7 +117,7 @@ nextEvent:
|
|||||||
events := results[ie.PubKey].Data
|
events := results[ie.PubKey].Data
|
||||||
if events == nil {
|
if events == nil {
|
||||||
// no events found, so just add this and end
|
// no events found, so just add this and end
|
||||||
results[ie.PubKey] = dataloader.Result[[]*nostr.Event]{Data: []*nostr.Event{ie.Event}}
|
results[ie.PubKey] = dataloader.Result[[]nostr.Event]{Data: []nostr.Event{ie.Event}}
|
||||||
continue nextEvent
|
continue nextEvent
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +138,7 @@ nextEvent:
|
|||||||
}
|
}
|
||||||
|
|
||||||
events = append(events, ie.Event)
|
events = append(events, ie.Event)
|
||||||
results[ie.PubKey] = dataloader.Result[[]*nostr.Event]{Data: events}
|
results[ie.PubKey] = dataloader.Result[[]nostr.Event]{Data: events}
|
||||||
case <-aggregatedContext.Done():
|
case <-aggregatedContext.Done():
|
||||||
return results
|
return results
|
||||||
}
|
}
|
||||||
|
|||||||
12
sdk/feeds.go
12
sdk/feeds.go
@@ -105,9 +105,9 @@ func (sys *System) FetchFeedPage(
|
|||||||
kinds []uint16,
|
kinds []uint16,
|
||||||
until nostr.Timestamp,
|
until nostr.Timestamp,
|
||||||
totalLimit int,
|
totalLimit int,
|
||||||
) ([]*nostr.Event, error) {
|
) ([]nostr.Event, error) {
|
||||||
limitPerKey := PerQueryLimitInBatch(totalLimit, len(pubkeys))
|
limitPerKey := PerQueryLimitInBatch(totalLimit, len(pubkeys))
|
||||||
events := make([]*nostr.Event, 0, len(pubkeys)*limitPerKey)
|
events := make([]nostr.Event, 0, len(pubkeys)*limitPerKey)
|
||||||
|
|
||||||
wg := sync.WaitGroup{}
|
wg := sync.WaitGroup{}
|
||||||
wg.Add(len(pubkeys))
|
wg.Add(len(pubkeys))
|
||||||
@@ -153,8 +153,10 @@ func (sys *System) FetchFeedPage(
|
|||||||
fUntil := oldestTimestamp + 1
|
fUntil := oldestTimestamp + 1
|
||||||
filter.Until = &fUntil
|
filter.Until = &fUntil
|
||||||
filter.Since = nil
|
filter.Since = nil
|
||||||
for ie := range sys.Pool.FetchMany(ctx, relays, filter, nostr.WithLabel("feedpage")) {
|
for ie := range sys.Pool.FetchMany(ctx, relays, filter, nostr.SubscriptionOptions{
|
||||||
sys.StoreRelay.Publish(ctx, *ie.Event)
|
Label: "feedpage",
|
||||||
|
}) {
|
||||||
|
sys.Publisher.Publish(ctx, ie.Event)
|
||||||
|
|
||||||
// we shouldn't need this check here, but against rogue relays we'll do it
|
// we shouldn't need this check here, but against rogue relays we'll do it
|
||||||
if ie.Event.CreatedAt < oldestTimestamp {
|
if ie.Event.CreatedAt < oldestTimestamp {
|
||||||
@@ -173,7 +175,7 @@ func (sys *System) FetchFeedPage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
slices.SortFunc(events, nostr.CompareEventPtrReverse)
|
slices.SortFunc(events, nostr.CompareEventReverse)
|
||||||
|
|
||||||
return events, nil
|
return events, nil
|
||||||
}
|
}
|
||||||
|
|||||||
20
sdk/input.go
20
sdk/input.go
@@ -2,7 +2,6 @@ package sdk
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/hex"
|
|
||||||
|
|
||||||
"fiatjaf.com/nostr"
|
"fiatjaf.com/nostr"
|
||||||
"fiatjaf.com/nostr/nip05"
|
"fiatjaf.com/nostr/nip05"
|
||||||
@@ -12,18 +11,15 @@ import (
|
|||||||
// InputToProfile turns any npub/nprofile/hex/nip05 input into a ProfilePointer (or nil).
|
// InputToProfile turns any npub/nprofile/hex/nip05 input into a ProfilePointer (or nil).
|
||||||
func InputToProfile(ctx context.Context, input string) *nostr.ProfilePointer {
|
func InputToProfile(ctx context.Context, input string) *nostr.ProfilePointer {
|
||||||
// handle if it is a hex string
|
// handle if it is a hex string
|
||||||
if len(input) == 64 {
|
if pk, err := nostr.PubKeyFromHex(input); err == nil {
|
||||||
if _, err := hex.DecodeString(input); err == nil {
|
return &nostr.ProfilePointer{PublicKey: pk}
|
||||||
return &nostr.ProfilePointer{PublicKey: input}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle nip19 codes, if that's the case
|
// handle nip19 codes, if that's the case
|
||||||
prefix, data, _ := nip19.Decode(input)
|
prefix, data, _ := nip19.Decode(input)
|
||||||
switch prefix {
|
switch prefix {
|
||||||
case "npub":
|
case "npub":
|
||||||
input = data.(string)
|
return &nostr.ProfilePointer{PublicKey: data.(nostr.PubKey)}
|
||||||
return &nostr.ProfilePointer{PublicKey: input}
|
|
||||||
case "nprofile":
|
case "nprofile":
|
||||||
pp := data.(nostr.ProfilePointer)
|
pp := data.(nostr.ProfilePointer)
|
||||||
return &pp
|
return &pp
|
||||||
@@ -41,19 +37,15 @@ func InputToProfile(ctx context.Context, input string) *nostr.ProfilePointer {
|
|||||||
// InputToEventPointer turns any note/nevent/hex input into a EventPointer (or nil).
|
// InputToEventPointer turns any note/nevent/hex input into a EventPointer (or nil).
|
||||||
func InputToEventPointer(input string) *nostr.EventPointer {
|
func InputToEventPointer(input string) *nostr.EventPointer {
|
||||||
// handle if it is a hex string
|
// handle if it is a hex string
|
||||||
if len(input) == 64 {
|
if id, err := nostr.IDFromHex(input); err == nil {
|
||||||
if _, err := hex.DecodeString(input); err == nil {
|
return &nostr.EventPointer{ID: id}
|
||||||
return &nostr.EventPointer{ID: input}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle nip19 codes, if that's the case
|
// handle nip19 codes, if that's the case
|
||||||
prefix, data, _ := nip19.Decode(input)
|
prefix, data, _ := nip19.Decode(input)
|
||||||
switch prefix {
|
switch prefix {
|
||||||
case "note":
|
case "note":
|
||||||
if input, ok := data.(string); ok {
|
return &nostr.EventPointer{ID: data.([32]byte)}
|
||||||
return &nostr.EventPointer{ID: input}
|
|
||||||
}
|
|
||||||
case "nevent":
|
case "nevent":
|
||||||
if ep, ok := data.(nostr.EventPointer); ok {
|
if ep, ok := data.(nostr.EventPointer); ok {
|
||||||
return &ep
|
return &ep
|
||||||
|
|||||||
35
sdk/list.go
35
sdk/list.go
@@ -10,15 +10,15 @@ import (
|
|||||||
"fiatjaf.com/nostr/sdk/cache"
|
"fiatjaf.com/nostr/sdk/cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GenericList[I TagItemWithValue] struct {
|
type GenericList[V comparable, I TagItemWithValue[V]] struct {
|
||||||
PubKey nostr.PubKey `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
|
Event *nostr.Event `json:"-"` // may be empty if a contact list event wasn't found
|
||||||
|
|
||||||
Items []I
|
Items []I
|
||||||
}
|
}
|
||||||
|
|
||||||
type TagItemWithValue interface {
|
type TagItemWithValue[V comparable] interface {
|
||||||
Value() any
|
Value() V
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -26,15 +26,15 @@ var (
|
|||||||
valueWasJustCached = [60]bool{}
|
valueWasJustCached = [60]bool{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func fetchGenericList[I TagItemWithValue](
|
func fetchGenericList[V comparable, I TagItemWithValue[V]](
|
||||||
sys *System,
|
sys *System,
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
pubkey nostr.PubKey,
|
pubkey nostr.PubKey,
|
||||||
actualKind uint16,
|
actualKind uint16,
|
||||||
replaceableIndex replaceableIndex,
|
replaceableIndex replaceableIndex,
|
||||||
parseTag func(nostr.Tag) (I, bool),
|
parseTag func(nostr.Tag) (I, bool),
|
||||||
cache cache.Cache32[GenericList[I]],
|
cache cache.Cache32[GenericList[V, I]],
|
||||||
) (fl GenericList[I], fromInternal bool) {
|
) (fl GenericList[V, I], fromInternal bool) {
|
||||||
// we have 60 mutexes, so we can load up to 60 lists at the same time, but if we do the same exact
|
// 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
|
// 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
|
// and then return it from cache -- 13 is an arbitrary index for the pubkey
|
||||||
@@ -55,13 +55,12 @@ func fetchGenericList[I TagItemWithValue](
|
|||||||
return v, true
|
return v, true
|
||||||
}
|
}
|
||||||
|
|
||||||
v := GenericList[I]{PubKey: pubkey}
|
v := GenericList[V, I]{PubKey: pubkey}
|
||||||
|
|
||||||
events, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{Kinds: []uint16{actualKind}, Authors: []nostr.PubKey{pubkey}})
|
for evt := range sys.Store.QueryEvents(nostr.Filter{Kinds: []uint16{actualKind}, Authors: []nostr.PubKey{pubkey}}) {
|
||||||
if len(events) != 0 {
|
|
||||||
// ok, we found something locally
|
// ok, we found something locally
|
||||||
items := parseItemsFromEventTags(events[0], parseTag)
|
items := parseItemsFromEventTags(evt, parseTag)
|
||||||
v.Event = events[0]
|
v.Event = &evt
|
||||||
v.Items = items
|
v.Items = items
|
||||||
|
|
||||||
// but if we haven't tried fetching from the network recently we should do it
|
// but if we haven't tried fetching from the network recently we should do it
|
||||||
@@ -100,30 +99,30 @@ func fetchGenericList[I TagItemWithValue](
|
|||||||
return v, false
|
return v, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryFetchListFromNetwork[I TagItemWithValue](
|
func tryFetchListFromNetwork[V comparable, I TagItemWithValue[V]](
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
sys *System,
|
sys *System,
|
||||||
pubkey nostr.PubKey,
|
pubkey nostr.PubKey,
|
||||||
replaceableIndex replaceableIndex,
|
replaceableIndex replaceableIndex,
|
||||||
parseTag func(nostr.Tag) (I, bool),
|
parseTag func(nostr.Tag) (I, bool),
|
||||||
) *GenericList[I] {
|
) *GenericList[V, I] {
|
||||||
evt, err := sys.replaceableLoaders[replaceableIndex].Load(ctx, pubkey)
|
evt, err := sys.replaceableLoaders[replaceableIndex].Load(ctx, pubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
v := &GenericList[I]{
|
v := &GenericList[V, I]{
|
||||||
PubKey: pubkey,
|
PubKey: pubkey,
|
||||||
Event: evt,
|
Event: &evt,
|
||||||
Items: parseItemsFromEventTags(evt, parseTag),
|
Items: parseItemsFromEventTags(evt, parseTag),
|
||||||
}
|
}
|
||||||
sys.StoreRelay.Publish(ctx, *evt)
|
sys.Publisher.Publish(ctx, evt)
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseItemsFromEventTags[I TagItemWithValue](
|
func parseItemsFromEventTags[V comparable, I TagItemWithValue[V]](
|
||||||
evt *nostr.Event,
|
evt nostr.Event,
|
||||||
parseTag func(nostr.Tag) (I, bool),
|
parseTag func(nostr.Tag) (I, bool),
|
||||||
) []I {
|
) []I {
|
||||||
result := make([]I, 0, len(evt.Tags))
|
result := make([]I, 0, len(evt.Tags))
|
||||||
|
|||||||
@@ -11,18 +11,18 @@ type EventRef struct{ nostr.Pointer }
|
|||||||
|
|
||||||
func (e EventRef) Value() string { return e.Pointer.AsTagReference() }
|
func (e EventRef) Value() string { return e.Pointer.AsTagReference() }
|
||||||
|
|
||||||
func (sys *System) FetchBookmarkList(ctx context.Context, pubkey string) GenericList[EventRef] {
|
func (sys *System) FetchBookmarkList(ctx context.Context, pubkey nostr.PubKey) GenericList[string, EventRef] {
|
||||||
if sys.BookmarkListCache == nil {
|
if sys.BookmarkListCache == nil {
|
||||||
sys.BookmarkListCache = cache_memory.New[GenericList[EventRef]](1000)
|
sys.BookmarkListCache = cache_memory.New[GenericList[string, EventRef]](1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10003, kind_10003, parseEventRef, sys.BookmarkListCache)
|
ml, _ := fetchGenericList(sys, ctx, pubkey, 10003, kind_10003, parseEventRef, sys.BookmarkListCache)
|
||||||
return ml
|
return ml
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *System) FetchPinList(ctx context.Context, pubkey string) GenericList[EventRef] {
|
func (sys *System) FetchPinList(ctx context.Context, pubkey nostr.PubKey) GenericList[string, EventRef] {
|
||||||
if sys.PinListCache == nil {
|
if sys.PinListCache == nil {
|
||||||
sys.PinListCache = cache_memory.New[GenericList[EventRef]](1000)
|
sys.PinListCache = cache_memory.New[GenericList[string, EventRef]](1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10001, kind_10001, parseEventRef, sys.PinListCache)
|
ml, _ := fetchGenericList(sys, ctx, pubkey, 10001, kind_10001, parseEventRef, sys.PinListCache)
|
||||||
|
|||||||
@@ -17,27 +17,27 @@ type ProfileRef struct {
|
|||||||
|
|
||||||
func (f ProfileRef) Value() nostr.PubKey { return f.Pubkey }
|
func (f ProfileRef) Value() nostr.PubKey { return f.Pubkey }
|
||||||
|
|
||||||
func (sys *System) FetchFollowList(ctx context.Context, pubkey nostr.PubKey) GenericList[ProfileRef] {
|
func (sys *System) FetchFollowList(ctx context.Context, pubkey nostr.PubKey) GenericList[nostr.PubKey, ProfileRef] {
|
||||||
if sys.FollowListCache == nil {
|
if sys.FollowListCache == nil {
|
||||||
sys.FollowListCache = cache_memory.New[GenericList[ProfileRef]](1000)
|
sys.FollowListCache = cache_memory.New[GenericList[nostr.PubKey, ProfileRef]](1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
fl, _ := fetchGenericList(sys, ctx, pubkey, 3, kind_3, parseProfileRef, sys.FollowListCache)
|
fl, _ := fetchGenericList(sys, ctx, pubkey, 3, kind_3, parseProfileRef, sys.FollowListCache)
|
||||||
return fl
|
return fl
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *System) FetchMuteList(ctx context.Context, pubkey nostr.PubKey) GenericList[ProfileRef] {
|
func (sys *System) FetchMuteList(ctx context.Context, pubkey nostr.PubKey) GenericList[nostr.PubKey, ProfileRef] {
|
||||||
if sys.MuteListCache == nil {
|
if sys.MuteListCache == nil {
|
||||||
sys.MuteListCache = cache_memory.New[GenericList[ProfileRef]](1000)
|
sys.MuteListCache = cache_memory.New[GenericList[nostr.PubKey, ProfileRef]](1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10000, kind_10000, parseProfileRef, sys.MuteListCache)
|
ml, _ := fetchGenericList(sys, ctx, pubkey, 10000, kind_10000, parseProfileRef, sys.MuteListCache)
|
||||||
return ml
|
return ml
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *System) FetchFollowSets(ctx context.Context, pubkey nostr.PubKey) GenericSets[ProfileRef] {
|
func (sys *System) FetchFollowSets(ctx context.Context, pubkey nostr.PubKey) GenericSets[nostr.PubKey, ProfileRef] {
|
||||||
if sys.FollowSetsCache == nil {
|
if sys.FollowSetsCache == nil {
|
||||||
sys.FollowSetsCache = cache_memory.New[GenericSets[ProfileRef]](1000)
|
sys.FollowSetsCache = cache_memory.New[GenericSets[nostr.PubKey, ProfileRef]](1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
ml, _ := fetchGenericSets(sys, ctx, pubkey, 30000, kind_30000, parseProfileRef, sys.FollowSetsCache)
|
ml, _ := fetchGenericSets(sys, ctx, pubkey, 30000, kind_30000, parseProfileRef, sys.FollowSetsCache)
|
||||||
@@ -52,11 +52,10 @@ func parseProfileRef(tag nostr.Tag) (fw ProfileRef, ok bool) {
|
|||||||
return fw, false
|
return fw, false
|
||||||
}
|
}
|
||||||
|
|
||||||
pubkey, err := nostr.PubKeyFromHex(fw.Pubkey)
|
pubkey, err := nostr.PubKeyFromHex(tag[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fw, false
|
return fw, false
|
||||||
}
|
}
|
||||||
|
|
||||||
fw.Pubkey = pubkey
|
fw.Pubkey = pubkey
|
||||||
|
|
||||||
if len(tag) > 2 {
|
if len(tag) > 2 {
|
||||||
|
|||||||
@@ -19,32 +19,32 @@ type RelayURL string
|
|||||||
|
|
||||||
func (r RelayURL) Value() string { return string(r) }
|
func (r RelayURL) Value() string { return string(r) }
|
||||||
|
|
||||||
func (sys *System) FetchRelayList(ctx context.Context, pubkey nostr.PubKey) GenericList[Relay] {
|
func (sys *System) FetchRelayList(ctx context.Context, pubkey nostr.PubKey) GenericList[string, Relay] {
|
||||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10002, kind_10002, parseRelayFromKind10002, sys.RelayListCache)
|
ml, _ := fetchGenericList(sys, ctx, pubkey, 10002, kind_10002, parseRelayFromKind10002, sys.RelayListCache)
|
||||||
return ml
|
return ml
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *System) FetchBlockedRelayList(ctx context.Context, pubkey nostr.PubKey) GenericList[RelayURL] {
|
func (sys *System) FetchBlockedRelayList(ctx context.Context, pubkey nostr.PubKey) GenericList[string, RelayURL] {
|
||||||
if sys.BlockedRelayListCache == nil {
|
if sys.BlockedRelayListCache == nil {
|
||||||
sys.BlockedRelayListCache = cache_memory.New[GenericList[RelayURL]](1000)
|
sys.BlockedRelayListCache = cache_memory.New[GenericList[string, RelayURL]](1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10006, kind_10006, parseRelayURL, sys.BlockedRelayListCache)
|
ml, _ := fetchGenericList(sys, ctx, pubkey, 10006, kind_10006, parseRelayURL, sys.BlockedRelayListCache)
|
||||||
return ml
|
return ml
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *System) FetchSearchRelayList(ctx context.Context, pubkey nostr.PubKey) GenericList[RelayURL] {
|
func (sys *System) FetchSearchRelayList(ctx context.Context, pubkey nostr.PubKey) GenericList[string, RelayURL] {
|
||||||
if sys.SearchRelayListCache == nil {
|
if sys.SearchRelayListCache == nil {
|
||||||
sys.SearchRelayListCache = cache_memory.New[GenericList[RelayURL]](1000)
|
sys.SearchRelayListCache = cache_memory.New[GenericList[string, RelayURL]](1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10007, kind_10007, parseRelayURL, sys.SearchRelayListCache)
|
ml, _ := fetchGenericList(sys, ctx, pubkey, 10007, kind_10007, parseRelayURL, sys.SearchRelayListCache)
|
||||||
return ml
|
return ml
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *System) FetchRelaySets(ctx context.Context, pubkey nostr.PubKey) GenericSets[RelayURL] {
|
func (sys *System) FetchRelaySets(ctx context.Context, pubkey nostr.PubKey) GenericSets[string, RelayURL] {
|
||||||
if sys.RelaySetsCache == nil {
|
if sys.RelaySetsCache == nil {
|
||||||
sys.RelaySetsCache = cache_memory.New[GenericSets[RelayURL]](1000)
|
sys.RelaySetsCache = cache_memory.New[GenericSets[string, RelayURL]](1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
ml, _ := fetchGenericSets(sys, ctx, pubkey, 30002, kind_30002, parseRelayURL, sys.RelaySetsCache)
|
ml, _ := fetchGenericSets(sys, ctx, pubkey, 30002, kind_30002, parseRelayURL, sys.RelaySetsCache)
|
||||||
|
|||||||
@@ -11,18 +11,18 @@ type Topic string
|
|||||||
|
|
||||||
func (r Topic) Value() string { return string(r) }
|
func (r Topic) Value() string { return string(r) }
|
||||||
|
|
||||||
func (sys *System) FetchTopicList(ctx context.Context, pubkey nostr.PubKey) GenericList[Topic] {
|
func (sys *System) FetchTopicList(ctx context.Context, pubkey nostr.PubKey) GenericList[string, Topic] {
|
||||||
if sys.TopicListCache == nil {
|
if sys.TopicListCache == nil {
|
||||||
sys.TopicListCache = cache_memory.New[GenericList[Topic]](1000)
|
sys.TopicListCache = cache_memory.New[GenericList[string, Topic]](1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10015, kind_10015, parseTopicString, sys.TopicListCache)
|
ml, _ := fetchGenericList(sys, ctx, pubkey, 10015, kind_10015, parseTopicString, sys.TopicListCache)
|
||||||
return ml
|
return ml
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *System) FetchTopicSets(ctx context.Context, pubkey nostr.PubKey) GenericSets[Topic] {
|
func (sys *System) FetchTopicSets(ctx context.Context, pubkey nostr.PubKey) GenericSets[string, Topic] {
|
||||||
if sys.TopicSetsCache == nil {
|
if sys.TopicSetsCache == nil {
|
||||||
sys.TopicSetsCache = cache_memory.New[GenericSets[Topic]](1000)
|
sys.TopicSetsCache = cache_memory.New[GenericSets[string, Topic]](1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
ml, _ := fetchGenericSets(sys, ctx, pubkey, 30015, kind_30015, parseTopicString, sys.TopicSetsCache)
|
ml, _ := fetchGenericSets(sys, ctx, pubkey, 30015, kind_30015, parseTopicString, sys.TopicSetsCache)
|
||||||
|
|||||||
@@ -110,12 +110,11 @@ func (sys *System) FetchProfileMetadata(ctx context.Context, pubkey nostr.PubKey
|
|||||||
|
|
||||||
pm.PubKey = pubkey
|
pm.PubKey = pubkey
|
||||||
|
|
||||||
res, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{Kinds: []int{0}, Authors: []string{pubkey}})
|
for evt := range sys.Store.QueryEvents(nostr.Filter{Kinds: []uint16{0}, Authors: []nostr.PubKey{pubkey}}) {
|
||||||
if len(res) != 0 {
|
|
||||||
// ok, we found something locally
|
// ok, we found something locally
|
||||||
pm, _ = ParseMetadata(res[0])
|
pm, _ = ParseMetadata(evt)
|
||||||
pm.PubKey = pubkey
|
pm.PubKey = pubkey
|
||||||
pm.Event = res[0]
|
pm.Event = &evt
|
||||||
|
|
||||||
// but if we haven't tried fetching from the network recently we should do it
|
// but if we haven't tried fetching from the network recently we should do it
|
||||||
lastFetchKey := makeLastFetchKey(0, pubkey)
|
lastFetchKey := makeLastFetchKey(0, pubkey)
|
||||||
@@ -151,7 +150,7 @@ func (sys *System) FetchProfileMetadata(ctx context.Context, pubkey nostr.PubKey
|
|||||||
return pm
|
return pm
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *System) tryFetchMetadataFromNetwork(ctx context.Context, pubkey string) *ProfileMetadata {
|
func (sys *System) tryFetchMetadataFromNetwork(ctx context.Context, pubkey nostr.PubKey) *ProfileMetadata {
|
||||||
evt, err := sys.replaceableLoaders[kind_0].Load(ctx, pubkey)
|
evt, err := sys.replaceableLoaders[kind_0].Load(ctx, pubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -163,15 +162,15 @@ func (sys *System) tryFetchMetadataFromNetwork(ctx context.Context, pubkey strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
pm.PubKey = pubkey
|
pm.PubKey = pubkey
|
||||||
pm.Event = evt
|
pm.Event = &evt
|
||||||
sys.StoreRelay.Publish(ctx, *evt)
|
sys.Publisher.Publish(ctx, evt)
|
||||||
sys.MetadataCache.SetWithTTL(pubkey, pm, time.Hour*6)
|
sys.MetadataCache.SetWithTTL(pubkey, pm, time.Hour*6)
|
||||||
return &pm
|
return &pm
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseMetadata parses a kind 0 event into a ProfileMetadata struct.
|
// ParseMetadata parses a kind 0 event into a ProfileMetadata struct.
|
||||||
// Returns an error if the event is not kind 0 or if the content is not valid JSON.
|
// Returns an error if the event is not kind 0 or if the content is not valid JSON.
|
||||||
func ParseMetadata(event *nostr.Event) (meta ProfileMetadata, err error) {
|
func ParseMetadata(event nostr.Event) (meta ProfileMetadata, err error) {
|
||||||
if event.Kind != 0 {
|
if event.Kind != 0 {
|
||||||
err = fmt.Errorf("event %s is kind %d, not 0", event.ID, event.Kind)
|
err = fmt.Errorf("event %s is kind %d, not 0", event.ID, event.Kind)
|
||||||
} else if er := json.Unmarshal([]byte(event.Content), &meta); er != nil {
|
} else if er := json.Unmarshal([]byte(event.Content), &meta); er != nil {
|
||||||
@@ -183,6 +182,6 @@ func ParseMetadata(event *nostr.Event) (meta ProfileMetadata, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
meta.PubKey = event.PubKey
|
meta.PubKey = event.PubKey
|
||||||
meta.Event = event
|
meta.Event = &event
|
||||||
return meta, err
|
return meta, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func (sys *System) FetchOutboxRelays(ctx context.Context, pubkey nostr.PubKey, n
|
|||||||
|
|
||||||
// FetchWriteRelays just reads relays from a kind:10002, that's the only canonical place where a user reveals
|
// FetchWriteRelays just reads relays from a kind:10002, that's the only canonical place where a user reveals
|
||||||
// the relays they intend to receive notifications from.
|
// the relays they intend to receive notifications from.
|
||||||
func (sys *System) FetchInboxRelays(ctx context.Context, pubkey string, n int) []string {
|
func (sys *System) FetchInboxRelays(ctx context.Context, pubkey nostr.PubKey, n int) []string {
|
||||||
rl := sys.FetchRelayList(ctx, pubkey)
|
rl := sys.FetchRelayList(ctx, pubkey)
|
||||||
if len(rl.Items) == 0 || len(rl.Items) > 10 {
|
if len(rl.Items) == 0 || len(rl.Items) > 10 {
|
||||||
return []string{"wss://relay.damus.io", "wss://nos.lol"}
|
return []string{"wss://relay.damus.io", "wss://nos.lol"}
|
||||||
@@ -70,7 +70,7 @@ func (sys *System) FetchInboxRelays(ctx context.Context, pubkey string, n int) [
|
|||||||
//
|
//
|
||||||
// Use FetchWriteRelays when deciding where to publish on behalf of a user, but FetchOutboxRelays when deciding
|
// Use FetchWriteRelays when deciding where to publish on behalf of a user, but FetchOutboxRelays when deciding
|
||||||
// from where to read notes authored by other users.
|
// from where to read notes authored by other users.
|
||||||
func (sys *System) FetchWriteRelays(ctx context.Context, pubkey string) []string {
|
func (sys *System) FetchWriteRelays(ctx context.Context, pubkey nostr.PubKey) []string {
|
||||||
rl := sys.FetchRelayList(ctx, pubkey)
|
rl := sys.FetchRelayList(ctx, pubkey)
|
||||||
|
|
||||||
relays := make([]string, 0, 7)
|
relays := make([]string, 0, 7)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const (
|
|||||||
type EventResult dataloader.Result[*nostr.Event]
|
type EventResult dataloader.Result[*nostr.Event]
|
||||||
|
|
||||||
func (sys *System) initializeReplaceableDataloaders() {
|
func (sys *System) initializeReplaceableDataloaders() {
|
||||||
sys.replaceableLoaders = make([]*dataloader.Loader[nostr.PubKey, *nostr.Event], 12)
|
sys.replaceableLoaders = make([]*dataloader.Loader[nostr.PubKey, nostr.Event], 12)
|
||||||
sys.replaceableLoaders[kind_0] = sys.createReplaceableDataloader(0)
|
sys.replaceableLoaders[kind_0] = sys.createReplaceableDataloader(0)
|
||||||
sys.replaceableLoaders[kind_3] = sys.createReplaceableDataloader(3)
|
sys.replaceableLoaders[kind_3] = sys.createReplaceableDataloader(3)
|
||||||
sys.replaceableLoaders[kind_10000] = sys.createReplaceableDataloader(10000)
|
sys.replaceableLoaders[kind_10000] = sys.createReplaceableDataloader(10000)
|
||||||
@@ -48,9 +48,9 @@ func (sys *System) initializeReplaceableDataloaders() {
|
|||||||
sys.replaceableLoaders[kind_10030] = sys.createReplaceableDataloader(10030)
|
sys.replaceableLoaders[kind_10030] = sys.createReplaceableDataloader(10030)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sys *System) createReplaceableDataloader(kind uint16) *dataloader.Loader[nostr.PubKey, *nostr.Event] {
|
func (sys *System) createReplaceableDataloader(kind uint16) *dataloader.Loader[nostr.PubKey, nostr.Event] {
|
||||||
return dataloader.NewBatchedLoader(
|
return dataloader.NewBatchedLoader(
|
||||||
func(ctxs []context.Context, pubkeys []nostr.PubKey) map[nostr.PubKey]dataloader.Result[*nostr.Event] {
|
func(ctxs []context.Context, pubkeys []nostr.PubKey) map[nostr.PubKey]dataloader.Result[nostr.Event] {
|
||||||
return sys.batchLoadReplaceableEvents(ctxs, kind, pubkeys)
|
return sys.batchLoadReplaceableEvents(ctxs, kind, pubkeys)
|
||||||
},
|
},
|
||||||
dataloader.Options{
|
dataloader.Options{
|
||||||
@@ -64,9 +64,9 @@ func (sys *System) batchLoadReplaceableEvents(
|
|||||||
ctxs []context.Context,
|
ctxs []context.Context,
|
||||||
kind uint16,
|
kind uint16,
|
||||||
pubkeys []nostr.PubKey,
|
pubkeys []nostr.PubKey,
|
||||||
) map[nostr.PubKey]dataloader.Result[*nostr.Event] {
|
) map[nostr.PubKey]dataloader.Result[nostr.Event] {
|
||||||
batchSize := len(pubkeys)
|
batchSize := len(pubkeys)
|
||||||
results := make(map[nostr.PubKey]dataloader.Result[*nostr.Event], batchSize)
|
results := make(map[nostr.PubKey]dataloader.Result[nostr.Event], batchSize)
|
||||||
relayFilter := make([]nostr.DirectedFilter, 0, max(3, batchSize*2))
|
relayFilter := make([]nostr.DirectedFilter, 0, max(3, batchSize*2))
|
||||||
relayFilterIndex := make(map[string]int, max(3, batchSize*2))
|
relayFilterIndex := make(map[string]int, max(3, batchSize*2))
|
||||||
|
|
||||||
@@ -121,9 +121,9 @@ func (sys *System) batchLoadReplaceableEvents(
|
|||||||
|
|
||||||
// query all relays with the prepared filters
|
// query all relays with the prepared filters
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
multiSubs := sys.Pool.BatchedSubManyEose(aggregatedContext, relayFilter,
|
multiSubs := sys.Pool.BatchedSubManyEose(aggregatedContext, relayFilter, nostr.SubscriptionOptions{
|
||||||
nostr.WithLabel("repl~"+strconv.Itoa(int(kind))),
|
Label: "repl~" + strconv.Itoa(int(kind)),
|
||||||
)
|
})
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case ie, more := <-multiSubs:
|
case ie, more := <-multiSubs:
|
||||||
@@ -132,8 +132,8 @@ func (sys *System) batchLoadReplaceableEvents(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// insert this event at the desired position
|
// insert this event at the desired position
|
||||||
if val, ok := results[ie.PubKey]; !ok || val.Data == nil || val.Data.CreatedAt < ie.CreatedAt {
|
if val, ok := results[ie.PubKey]; !ok || val.Data.ID == nostr.ZeroID || val.Data.CreatedAt < ie.CreatedAt {
|
||||||
results[ie.PubKey] = dataloader.Result[*nostr.Event]{Data: ie.Event}
|
results[ie.PubKey] = dataloader.Result[nostr.Event]{Data: ie.Event}
|
||||||
}
|
}
|
||||||
case <-aggregatedContext.Done():
|
case <-aggregatedContext.Done():
|
||||||
return results
|
return results
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ func (sys *System) SearchUsers(ctx context.Context, query string) []ProfileMetad
|
|||||||
for ie := range sys.Pool.FetchMany(ctx, sys.UserSearchRelays.URLs, nostr.Filter{
|
for ie := range sys.Pool.FetchMany(ctx, sys.UserSearchRelays.URLs, nostr.Filter{
|
||||||
Search: query,
|
Search: query,
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
}, nostr.WithLabel("search")) {
|
}, nostr.SubscriptionOptions{
|
||||||
|
Label: "search",
|
||||||
|
}) {
|
||||||
m, _ := ParseMetadata(ie.Event)
|
m, _ := ParseMetadata(ie.Event)
|
||||||
profiles = append(profiles, m)
|
profiles = append(profiles, m)
|
||||||
}
|
}
|
||||||
|
|||||||
30
sdk/set.go
30
sdk/set.go
@@ -11,22 +11,22 @@ import (
|
|||||||
|
|
||||||
// this is similar to list.go and inherits code from that.
|
// this is similar to list.go and inherits code from that.
|
||||||
|
|
||||||
type GenericSets[I TagItemWithValue] struct {
|
type GenericSets[V comparable, I TagItemWithValue[V]] struct {
|
||||||
PubKey nostr.PubKey `json:"-"`
|
PubKey nostr.PubKey `json:"-"`
|
||||||
Events []*nostr.Event `json:"-"`
|
Events []nostr.Event `json:"-"`
|
||||||
|
|
||||||
Sets map[string][]I
|
Sets map[string][]I
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchGenericSets[I TagItemWithValue](
|
func fetchGenericSets[V comparable, I TagItemWithValue[V]](
|
||||||
sys *System,
|
sys *System,
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
pubkey nostr.PubKey,
|
pubkey nostr.PubKey,
|
||||||
actualKind uint16,
|
actualKind uint16,
|
||||||
addressableIndex addressableIndex,
|
addressableIndex addressableIndex,
|
||||||
parseTag func(nostr.Tag) (I, bool),
|
parseTag func(nostr.Tag) (I, bool),
|
||||||
cache cache.Cache32[GenericSets[I]],
|
cache cache.Cache32[GenericSets[V, I]],
|
||||||
) (fl GenericSets[I], fromInternal bool) {
|
) (fl GenericSets[V, I], fromInternal bool) {
|
||||||
n := pubkey[7]
|
n := pubkey[7]
|
||||||
lockIdx := (uint16(n) + actualKind) % 60
|
lockIdx := (uint16(n) + actualKind) % 60
|
||||||
genericListMutexes[lockIdx].Lock()
|
genericListMutexes[lockIdx].Lock()
|
||||||
@@ -44,9 +44,11 @@ func fetchGenericSets[I TagItemWithValue](
|
|||||||
return v, true
|
return v, true
|
||||||
}
|
}
|
||||||
|
|
||||||
v := GenericSets[I]{PubKey: pubkey}
|
v := GenericSets[V, I]{PubKey: pubkey}
|
||||||
|
|
||||||
events, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{Kinds: []uint16{actualKind}, Authors: []nostr.PubKey{pubkey}})
|
events := slices.Collect(
|
||||||
|
sys.Store.QueryEvents(nostr.Filter{Kinds: []uint16{actualKind}, Authors: []nostr.PubKey{pubkey}}),
|
||||||
|
)
|
||||||
if len(events) != 0 {
|
if len(events) != 0 {
|
||||||
// ok, we found something locally
|
// ok, we found something locally
|
||||||
sets := parseSetsFromEvents(events, parseTag)
|
sets := parseSetsFromEvents(events, parseTag)
|
||||||
@@ -89,31 +91,31 @@ func fetchGenericSets[I TagItemWithValue](
|
|||||||
return v, false
|
return v, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func tryFetchSetsFromNetwork[I TagItemWithValue](
|
func tryFetchSetsFromNetwork[V comparable, I TagItemWithValue[V]](
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
sys *System,
|
sys *System,
|
||||||
pubkey nostr.PubKey,
|
pubkey nostr.PubKey,
|
||||||
addressableIndex addressableIndex,
|
addressableIndex addressableIndex,
|
||||||
parseTag func(nostr.Tag) (I, bool),
|
parseTag func(nostr.Tag) (I, bool),
|
||||||
) *GenericSets[I] {
|
) *GenericSets[V, I] {
|
||||||
events, err := sys.addressableLoaders[addressableIndex].Load(ctx, pubkey)
|
events, err := sys.addressableLoaders[addressableIndex].Load(ctx, pubkey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
v := &GenericSets[I]{
|
v := &GenericSets[V, I]{
|
||||||
PubKey: pubkey,
|
PubKey: pubkey,
|
||||||
Events: events,
|
Events: events,
|
||||||
Sets: parseSetsFromEvents(events, parseTag),
|
Sets: parseSetsFromEvents(events, parseTag),
|
||||||
}
|
}
|
||||||
for _, evt := range events {
|
for _, evt := range events {
|
||||||
sys.StoreRelay.Publish(ctx, *evt)
|
sys.Publisher.Publish(ctx, evt)
|
||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSetsFromEvents[I TagItemWithValue](
|
func parseSetsFromEvents[V comparable, I TagItemWithValue[V]](
|
||||||
events []*nostr.Event,
|
events []nostr.Event,
|
||||||
parseTag func(nostr.Tag) (I, bool),
|
parseTag func(nostr.Tag) (I, bool),
|
||||||
) map[string][]I {
|
) map[string][]I {
|
||||||
sets := make(map[string][]I, len(events))
|
sets := make(map[string][]I, len(events))
|
||||||
|
|||||||
@@ -39,13 +39,13 @@ func (sys *System) FetchSpecificEventFromInput(
|
|||||||
case "naddr":
|
case "naddr":
|
||||||
pointer = data.(nostr.EntityPointer)
|
pointer = data.(nostr.EntityPointer)
|
||||||
case "note":
|
case "note":
|
||||||
pointer = nostr.EventPointer{ID: data.(string)}
|
pointer = nostr.EventPointer{ID: data.([32]byte)}
|
||||||
default:
|
default:
|
||||||
return nil, nil, fmt.Errorf("invalid code '%s'", input)
|
return nil, nil, fmt.Errorf("invalid code '%s'", input)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if nostr.IsValid32ByteHex(input) {
|
if id, err := nostr.IDFromHex(input); err == nil {
|
||||||
pointer = nostr.EventPointer{ID: input}
|
pointer = nostr.EventPointer{ID: id}
|
||||||
} else {
|
} else {
|
||||||
return nil, nil, fmt.Errorf("failed to decode '%s': %w", input, err)
|
return nil, nil, fmt.Errorf("failed to decode '%s': %w", input, err)
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ func (sys *System) FetchSpecificEvent(
|
|||||||
priorityRelays := make([]string, 0, 8)
|
priorityRelays := make([]string, 0, 8)
|
||||||
|
|
||||||
var filter nostr.Filter
|
var filter nostr.Filter
|
||||||
author := ""
|
var author nostr.PubKey
|
||||||
relays := make([]string, 0, 10)
|
relays := make([]string, 0, 10)
|
||||||
fallback := make([]string, 0, 10)
|
fallback := make([]string, 0, 10)
|
||||||
successRelays = make([]string, 0, 10)
|
successRelays = make([]string, 0, 10)
|
||||||
@@ -74,7 +74,7 @@ func (sys *System) FetchSpecificEvent(
|
|||||||
switch v := pointer.(type) {
|
switch v := pointer.(type) {
|
||||||
case nostr.EventPointer:
|
case nostr.EventPointer:
|
||||||
author = v.Author
|
author = v.Author
|
||||||
filter.IDs = []string{v.ID}
|
filter.IDs = []nostr.ID{v.ID}
|
||||||
relays = append(relays, v.Relays...)
|
relays = append(relays, v.Relays...)
|
||||||
relays = appendUnique(relays, sys.FallbackRelays.Next())
|
relays = appendUnique(relays, sys.FallbackRelays.Next())
|
||||||
fallback = append(fallback, sys.JustIDRelays.URLs...)
|
fallback = append(fallback, sys.JustIDRelays.URLs...)
|
||||||
@@ -82,9 +82,9 @@ func (sys *System) FetchSpecificEvent(
|
|||||||
priorityRelays = append(priorityRelays, v.Relays...)
|
priorityRelays = append(priorityRelays, v.Relays...)
|
||||||
case nostr.EntityPointer:
|
case nostr.EntityPointer:
|
||||||
author = v.PublicKey
|
author = v.PublicKey
|
||||||
filter.Authors = []string{v.PublicKey}
|
filter.Authors = []nostr.PubKey{v.PublicKey}
|
||||||
filter.Tags = nostr.TagMap{"d": []string{v.Identifier}}
|
filter.Tags = nostr.TagMap{"d": []string{v.Identifier}}
|
||||||
filter.Kinds = []int{v.Kind}
|
filter.Kinds = []uint16{v.Kind}
|
||||||
relays = append(relays, v.Relays...)
|
relays = append(relays, v.Relays...)
|
||||||
relays = appendUnique(relays, sys.FallbackRelays.Next())
|
relays = appendUnique(relays, sys.FallbackRelays.Next())
|
||||||
fallback = append(fallback, sys.FallbackRelays.Next(), sys.FallbackRelays.Next())
|
fallback = append(fallback, sys.FallbackRelays.Next(), sys.FallbackRelays.Next())
|
||||||
@@ -93,13 +93,12 @@ func (sys *System) FetchSpecificEvent(
|
|||||||
|
|
||||||
// try to fetch in our internal eventstore first
|
// try to fetch in our internal eventstore first
|
||||||
if !params.SkipLocalStore {
|
if !params.SkipLocalStore {
|
||||||
if res, _ := sys.StoreRelay.QuerySync(ctx, filter); len(res) != 0 {
|
for evt := range sys.Store.QueryEvents(filter) {
|
||||||
evt := res[0]
|
return &evt, nil, nil
|
||||||
return evt, nil, nil
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if author != "" {
|
if author != nostr.ZeroPK {
|
||||||
// fetch relays for author
|
// fetch relays for author
|
||||||
authorRelays := sys.FetchOutboxRelays(ctx, author, 3)
|
authorRelays := sys.FetchOutboxRelays(ctx, author, 3)
|
||||||
|
|
||||||
@@ -141,19 +140,16 @@ attempts:
|
|||||||
countdown := 6.0
|
countdown := 6.0
|
||||||
subManyCtx := ctx
|
subManyCtx := ctx
|
||||||
|
|
||||||
for ie := range sys.Pool.FetchMany(
|
for ie := range sys.Pool.FetchMany(subManyCtx, attempt.relays, filter, nostr.SubscriptionOptions{
|
||||||
subManyCtx,
|
Label: attempt.label,
|
||||||
attempt.relays,
|
}) {
|
||||||
filter,
|
|
||||||
nostr.WithLabel(attempt.label),
|
|
||||||
) {
|
|
||||||
fetchProfileOnce.Do(func() {
|
fetchProfileOnce.Do(func() {
|
||||||
go sys.FetchProfileMetadata(ctx, ie.PubKey)
|
go sys.FetchProfileMetadata(ctx, ie.PubKey)
|
||||||
})
|
})
|
||||||
|
|
||||||
successRelays = append(successRelays, ie.Relay.URL)
|
successRelays = append(successRelays, ie.Relay.URL)
|
||||||
if result == nil || ie.CreatedAt > result.CreatedAt {
|
if result == nil || ie.CreatedAt > result.CreatedAt {
|
||||||
result = ie.Event
|
result = &ie.Event
|
||||||
}
|
}
|
||||||
|
|
||||||
if !attempt.slowWithRelays {
|
if !attempt.slowWithRelays {
|
||||||
@@ -170,7 +166,7 @@ attempts:
|
|||||||
|
|
||||||
// save stuff in cache and in internal store
|
// save stuff in cache and in internal store
|
||||||
if !params.SkipLocalStore {
|
if !params.SkipLocalStore {
|
||||||
sys.StoreRelay.Publish(ctx, *result)
|
sys.Publisher.Publish(ctx, *result)
|
||||||
}
|
}
|
||||||
|
|
||||||
// put priority relays first so they get used in nevent and nprofile
|
// put priority relays first so they get used in nevent and nprofile
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
package sdk
|
package sdk
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"math/rand/v2"
|
"math/rand/v2"
|
||||||
|
|
||||||
"fiatjaf.com/nostr"
|
"fiatjaf.com/nostr"
|
||||||
|
"fiatjaf.com/nostr/eventstore"
|
||||||
|
"fiatjaf.com/nostr/eventstore/nullstore"
|
||||||
"fiatjaf.com/nostr/eventstore/wrappers"
|
"fiatjaf.com/nostr/eventstore/wrappers"
|
||||||
"fiatjaf.com/nostr/sdk/cache"
|
"fiatjaf.com/nostr/sdk/cache"
|
||||||
cache_memory "fiatjaf.com/nostr/sdk/cache/memory"
|
cache_memory "fiatjaf.com/nostr/sdk/cache/memory"
|
||||||
@@ -13,8 +14,6 @@ import (
|
|||||||
"fiatjaf.com/nostr/sdk/hints/memoryh"
|
"fiatjaf.com/nostr/sdk/hints/memoryh"
|
||||||
"fiatjaf.com/nostr/sdk/kvstore"
|
"fiatjaf.com/nostr/sdk/kvstore"
|
||||||
kvstore_memory "fiatjaf.com/nostr/sdk/kvstore/memory"
|
kvstore_memory "fiatjaf.com/nostr/sdk/kvstore/memory"
|
||||||
"fiatjaf.com/nostr/eventstore"
|
|
||||||
"fiatjaf.com/nostr/eventstore/nullstore"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// System represents the core functionality of the SDK, providing access to
|
// System represents the core functionality of the SDK, providing access to
|
||||||
@@ -30,17 +29,17 @@ import (
|
|||||||
type System struct {
|
type System struct {
|
||||||
KVStore kvstore.KVStore
|
KVStore kvstore.KVStore
|
||||||
MetadataCache cache.Cache32[ProfileMetadata]
|
MetadataCache cache.Cache32[ProfileMetadata]
|
||||||
RelayListCache cache.Cache32[GenericList[Relay]]
|
RelayListCache cache.Cache32[GenericList[string, Relay]]
|
||||||
FollowListCache cache.Cache32[GenericList[ProfileRef]]
|
FollowListCache cache.Cache32[GenericList[nostr.PubKey, ProfileRef]]
|
||||||
MuteListCache cache.Cache32[GenericList[ProfileRef]]
|
MuteListCache cache.Cache32[GenericList[nostr.PubKey, ProfileRef]]
|
||||||
BookmarkListCache cache.Cache32[GenericList[EventRef]]
|
BookmarkListCache cache.Cache32[GenericList[string, EventRef]]
|
||||||
PinListCache cache.Cache32[GenericList[EventRef]]
|
PinListCache cache.Cache32[GenericList[string, EventRef]]
|
||||||
BlockedRelayListCache cache.Cache32[GenericList[RelayURL]]
|
BlockedRelayListCache cache.Cache32[GenericList[string, RelayURL]]
|
||||||
SearchRelayListCache cache.Cache32[GenericList[RelayURL]]
|
SearchRelayListCache cache.Cache32[GenericList[string, RelayURL]]
|
||||||
TopicListCache cache.Cache32[GenericList[Topic]]
|
TopicListCache cache.Cache32[GenericList[string, Topic]]
|
||||||
RelaySetsCache cache.Cache32[GenericSets[RelayURL]]
|
RelaySetsCache cache.Cache32[GenericSets[string, RelayURL]]
|
||||||
FollowSetsCache cache.Cache32[GenericSets[ProfileRef]]
|
FollowSetsCache cache.Cache32[GenericSets[nostr.PubKey, ProfileRef]]
|
||||||
TopicSetsCache cache.Cache32[GenericSets[Topic]]
|
TopicSetsCache cache.Cache32[GenericSets[string, Topic]]
|
||||||
Hints hints.HintsDB
|
Hints hints.HintsDB
|
||||||
Pool *nostr.Pool
|
Pool *nostr.Pool
|
||||||
RelayListRelays *RelayStream
|
RelayListRelays *RelayStream
|
||||||
@@ -54,8 +53,8 @@ type System struct {
|
|||||||
|
|
||||||
Publisher wrappers.StorePublisher
|
Publisher wrappers.StorePublisher
|
||||||
|
|
||||||
replaceableLoaders []*dataloader.Loader[nostr.PubKey, *nostr.Event]
|
replaceableLoaders []*dataloader.Loader[nostr.PubKey, nostr.Event]
|
||||||
addressableLoaders []*dataloader.Loader[nostr.PubKey, []*nostr.Event]
|
addressableLoaders []*dataloader.Loader[nostr.PubKey, []nostr.Event]
|
||||||
}
|
}
|
||||||
|
|
||||||
// SystemModifier is a function that modifies a System instance.
|
// SystemModifier is a function that modifies a System instance.
|
||||||
@@ -119,12 +118,12 @@ func NewSystem(mods ...SystemModifier) *System {
|
|||||||
Hints: memoryh.NewHintDB(),
|
Hints: memoryh.NewHintDB(),
|
||||||
}
|
}
|
||||||
|
|
||||||
sys.Pool = nostr.NewPool(context.Background(),
|
sys.Pool = nostr.NewPool(nostr.PoolOptions{
|
||||||
nostr.WithAuthorKindQueryMiddleware(sys.TrackQueryAttempts),
|
AuthorKindQueryMiddleware: sys.TrackQueryAttempts,
|
||||||
nostr.WithEventMiddleware(sys.TrackEventHintsAndRelays),
|
EventMiddleware: sys.TrackEventHintsAndRelays,
|
||||||
nostr.WithDuplicateMiddleware(sys.TrackEventRelaysD),
|
DuplicateMiddleware: sys.TrackEventRelaysD,
|
||||||
nostr.WithPenaltyBox(),
|
PenaltyBox: true,
|
||||||
)
|
})
|
||||||
|
|
||||||
for _, mod := range mods {
|
for _, mod := range mods {
|
||||||
mod(sys)
|
mod(sys)
|
||||||
@@ -134,14 +133,14 @@ func NewSystem(mods ...SystemModifier) *System {
|
|||||||
sys.MetadataCache = cache_memory.New[ProfileMetadata](8000)
|
sys.MetadataCache = cache_memory.New[ProfileMetadata](8000)
|
||||||
}
|
}
|
||||||
if sys.RelayListCache == nil {
|
if sys.RelayListCache == nil {
|
||||||
sys.RelayListCache = cache_memory.New[GenericList[Relay]](8000)
|
sys.RelayListCache = cache_memory.New[GenericList[string, Relay]](8000)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sys.Store == nil {
|
if sys.Store == nil {
|
||||||
sys.Store = &nullstore.NullStore{}
|
sys.Store = &nullstore.NullStore{}
|
||||||
sys.Store.Init()
|
sys.Store.Init()
|
||||||
}
|
}
|
||||||
sys.StoreRelay = eventstore.RelayWrapper{Store: sys.Store}
|
sys.Publisher = wrappers.StorePublisher{Store: sys.Store}
|
||||||
|
|
||||||
sys.initializeReplaceableDataloaders()
|
sys.initializeReplaceableDataloaders()
|
||||||
sys.initializeAddressableDataloaders()
|
sys.initializeAddressableDataloaders()
|
||||||
@@ -223,14 +222,14 @@ func WithStore(store eventstore.Store) SystemModifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WithRelayListCache returns a SystemModifier that sets the RelayListCache.
|
// WithRelayListCache returns a SystemModifier that sets the RelayListCache.
|
||||||
func WithRelayListCache(cache cache.Cache32[GenericList[Relay]]) SystemModifier {
|
func WithRelayListCache(cache cache.Cache32[GenericList[string, Relay]]) SystemModifier {
|
||||||
return func(sys *System) {
|
return func(sys *System) {
|
||||||
sys.RelayListCache = cache
|
sys.RelayListCache = cache
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithFollowListCache returns a SystemModifier that sets the FollowListCache.
|
// WithFollowListCache returns a SystemModifier that sets the FollowListCache.
|
||||||
func WithFollowListCache(cache cache.Cache32[GenericList[ProfileRef]]) SystemModifier {
|
func WithFollowListCache(cache cache.Cache32[GenericList[nostr.PubKey, ProfileRef]]) SystemModifier {
|
||||||
return func(sys *System) {
|
return func(sys *System) {
|
||||||
sys.FollowListCache = cache
|
sys.FollowListCache = cache
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user