mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-03-17 21:32:56 +01:00
more list fetchers.
This commit is contained in:
parent
159e5d21e6
commit
c2c08ab6bc
@ -30,7 +30,8 @@ func fetchGenericList[I TagItemWithValue](
|
||||
sys *System,
|
||||
ctx context.Context,
|
||||
pubkey string,
|
||||
kind int,
|
||||
actualKind int,
|
||||
replaceableIndex replaceableIndex,
|
||||
parseTag func(nostr.Tag) (I, bool),
|
||||
cache cache.Cache32[GenericList[I]],
|
||||
skipFetch bool,
|
||||
@ -38,7 +39,7 @@ func fetchGenericList[I TagItemWithValue](
|
||||
// we have 24 mutexes, so we can load up to 24 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
|
||||
lockIdx := (int(pubkey[13]) + kind) % 24
|
||||
lockIdx := (int(pubkey[13]) + int(replaceableIndex)) % 24
|
||||
genericListMutexes[lockIdx].Lock()
|
||||
|
||||
if valueWasJustCached[lockIdx] {
|
||||
@ -56,7 +57,7 @@ func fetchGenericList[I TagItemWithValue](
|
||||
|
||||
v := GenericList[I]{PubKey: pubkey}
|
||||
|
||||
events, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{Kinds: []int{kind}, Authors: []string{pubkey}})
|
||||
events, _ := sys.StoreRelay.QuerySync(ctx, nostr.Filter{Kinds: []int{actualKind}, Authors: []string{pubkey}})
|
||||
if len(events) != 0 {
|
||||
items := parseItemsFromEventTags(events[0], parseTag)
|
||||
v.Event = events[0]
|
||||
@ -67,7 +68,7 @@ func fetchGenericList[I TagItemWithValue](
|
||||
}
|
||||
|
||||
if !skipFetch {
|
||||
thunk := sys.replaceableLoaders[kind].Load(ctx, pubkey)
|
||||
thunk := sys.replaceableLoaders[replaceableIndex].Load(ctx, pubkey)
|
||||
evt, err := thunk()
|
||||
if err == nil {
|
||||
items := parseItemsFromEventTags(evt, parseTag)
|
||||
|
67
sdk/lists_event.go
Normal file
67
sdk/lists_event.go
Normal file
@ -0,0 +1,67 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
)
|
||||
|
||||
type EventRef struct{ nostr.Pointer }
|
||||
|
||||
func (e EventRef) Value() string { return e.Pointer.AsTagReference() }
|
||||
|
||||
func (sys *System) FetchBookmarkList(ctx context.Context, pubkey string) GenericList[EventRef] {
|
||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10003, kind_10003, parseEventRef, sys.BookmarkListCache, false)
|
||||
return ml
|
||||
}
|
||||
|
||||
func (sys *System) FetchPinList(ctx context.Context, pubkey string) GenericList[EventRef] {
|
||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10001, kind_10001, parseEventRef, sys.PinListCache, false)
|
||||
return ml
|
||||
}
|
||||
|
||||
func parseEventRef(tag nostr.Tag) (evr EventRef, ok bool) {
|
||||
if len(tag) < 2 {
|
||||
return evr, false
|
||||
}
|
||||
switch tag[0] {
|
||||
case "e":
|
||||
if !nostr.IsValid32ByteHex(tag[1]) {
|
||||
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]) {
|
||||
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
|
||||
}
|
||||
|
||||
return evr, false
|
||||
}
|
@ -8,22 +8,25 @@ import (
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
)
|
||||
|
||||
type FollowList = GenericList[Follow]
|
||||
|
||||
type Follow struct {
|
||||
type ProfileRef struct {
|
||||
Pubkey string
|
||||
Relay string
|
||||
Petname string
|
||||
}
|
||||
|
||||
func (f Follow) Value() string { return f.Pubkey }
|
||||
func (f ProfileRef) Value() string { return f.Pubkey }
|
||||
|
||||
func (sys *System) FetchFollowList(ctx context.Context, pubkey string) FollowList {
|
||||
fl, _ := fetchGenericList(sys, ctx, pubkey, 3, parseFollow, sys.FollowListCache, false)
|
||||
func (sys *System) FetchFollowList(ctx context.Context, pubkey string) GenericList[ProfileRef] {
|
||||
fl, _ := fetchGenericList(sys, ctx, pubkey, 3, kind_3, parseProfileRef, sys.FollowListCache, false)
|
||||
return fl
|
||||
}
|
||||
|
||||
func parseFollow(tag nostr.Tag) (fw Follow, ok bool) {
|
||||
func (sys *System) FetchMuteList(ctx context.Context, pubkey string) GenericList[ProfileRef] {
|
||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10000, kind_10000, parseProfileRef, sys.MuteListCache, false)
|
||||
return ml
|
||||
}
|
||||
|
||||
func parseProfileRef(tag nostr.Tag) (fw ProfileRef, ok bool) {
|
||||
if len(tag) < 2 {
|
||||
return fw, false
|
||||
}
|
72
sdk/lists_relay.go
Normal file
72
sdk/lists_relay.go
Normal file
@ -0,0 +1,72 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
)
|
||||
|
||||
type Relay struct {
|
||||
URL string
|
||||
Inbox bool
|
||||
Outbox bool
|
||||
}
|
||||
|
||||
func (r Relay) Value() string { return r.URL }
|
||||
|
||||
type RelayURL string
|
||||
|
||||
func (r RelayURL) Value() string { return string(r) }
|
||||
|
||||
func (sys *System) FetchRelayList(ctx context.Context, pubkey string) GenericList[Relay] {
|
||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10002, kind_10002, parseRelayFromKind10002, sys.RelayListCache, false)
|
||||
return ml
|
||||
}
|
||||
|
||||
func (sys *System) FetchBlockedRelayList(ctx context.Context, pubkey string) GenericList[RelayURL] {
|
||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10006, kind_10006, parseRelayURL, sys.BlockedRelayListCache, false)
|
||||
return ml
|
||||
}
|
||||
|
||||
func (sys *System) FetchSearchRelayList(ctx context.Context, pubkey string) GenericList[RelayURL] {
|
||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10007, kind_10007, parseRelayURL, sys.SearchRelayListCache, false)
|
||||
return ml
|
||||
}
|
||||
|
||||
func parseRelayFromKind10002(tag nostr.Tag) (rl Relay, ok bool) {
|
||||
if u := tag.Value(); u != "" && tag[0] == "r" {
|
||||
if !nostr.IsValidRelayURL(u) {
|
||||
return rl, false
|
||||
}
|
||||
u := nostr.NormalizeURL(u)
|
||||
|
||||
relay := Relay{
|
||||
URL: u,
|
||||
}
|
||||
|
||||
if len(tag) == 2 {
|
||||
relay.Inbox = true
|
||||
relay.Outbox = true
|
||||
} else if tag[2] == "write" {
|
||||
relay.Outbox = true
|
||||
} else if tag[2] == "read" {
|
||||
relay.Inbox = true
|
||||
}
|
||||
|
||||
return relay, true
|
||||
}
|
||||
|
||||
return rl, false
|
||||
}
|
||||
|
||||
func parseRelayURL(tag nostr.Tag) (rl RelayURL, ok bool) {
|
||||
if u := tag.Value(); u != "" && tag[0] == "relay" {
|
||||
if !nostr.IsValidRelayURL(u) {
|
||||
return rl, false
|
||||
}
|
||||
u := nostr.NormalizeURL(u)
|
||||
return RelayURL(u), true
|
||||
}
|
||||
|
||||
return rl, false
|
||||
}
|
@ -117,7 +117,7 @@ func (sys *System) FetchProfileMetadata(ctx context.Context, pubkey string) (pm
|
||||
|
||||
pm.PubKey = pubkey
|
||||
|
||||
thunk0 := sys.replaceableLoaders[0].Load(ctx, pubkey)
|
||||
thunk0 := sys.replaceableLoaders[kind_0].Load(ctx, pubkey)
|
||||
evt, err := thunk0()
|
||||
if err == nil {
|
||||
pm, _ = ParseMetadata(evt)
|
||||
|
10
sdk/mutes.go
10
sdk/mutes.go
@ -1,10 +0,0 @@
|
||||
package sdk
|
||||
|
||||
import "context"
|
||||
|
||||
type MuteList = GenericList[Follow]
|
||||
|
||||
func (sys *System) FetchMuteList(ctx context.Context, pubkey string) MuteList {
|
||||
ml, _ := fetchGenericList(sys, ctx, pubkey, 10000, parseFollow, sys.MuteListCache, false)
|
||||
return ml
|
||||
}
|
@ -18,7 +18,7 @@ func (sys *System) FetchOutboxRelays(ctx context.Context, pubkey string, n int)
|
||||
}
|
||||
|
||||
// if we have it cached that means we have at least tried to fetch recently and it won't be tried again
|
||||
fetchGenericList(sys, ctx, pubkey, 10002, parseRelayFromKind10002, sys.RelayListCache, false)
|
||||
fetchGenericList(sys, ctx, pubkey, 10002, kind_10002, parseRelayFromKind10002, sys.RelayListCache, false)
|
||||
|
||||
relays := sys.Hints.TopN(pubkey, 6)
|
||||
if len(relays) == 0 {
|
||||
|
@ -1,41 +0,0 @@
|
||||
package sdk
|
||||
|
||||
import (
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
)
|
||||
|
||||
type RelayList = GenericList[Relay]
|
||||
|
||||
type Relay struct {
|
||||
URL string
|
||||
Inbox bool
|
||||
Outbox bool
|
||||
}
|
||||
|
||||
func (r Relay) Value() string { return r.URL }
|
||||
|
||||
func parseRelayFromKind10002(tag nostr.Tag) (rl Relay, ok bool) {
|
||||
if u := tag.Value(); u != "" && tag[0] == "r" {
|
||||
if !nostr.IsValidRelayURL(u) {
|
||||
return rl, false
|
||||
}
|
||||
u := nostr.NormalizeURL(u)
|
||||
|
||||
relay := Relay{
|
||||
URL: u,
|
||||
}
|
||||
|
||||
if len(tag) == 2 {
|
||||
relay.Inbox = true
|
||||
relay.Outbox = true
|
||||
} else if tag[2] == "write" {
|
||||
relay.Outbox = true
|
||||
} else if tag[2] == "read" {
|
||||
relay.Inbox = true
|
||||
}
|
||||
|
||||
return relay, true
|
||||
}
|
||||
|
||||
return rl, false
|
||||
}
|
@ -12,13 +12,38 @@ import (
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
)
|
||||
|
||||
type replaceableIndex int
|
||||
|
||||
const (
|
||||
kind_0 replaceableIndex = 0
|
||||
kind_3 replaceableIndex = 1
|
||||
kind_10000 replaceableIndex = 2
|
||||
kind_10001 replaceableIndex = 3
|
||||
kind_10002 replaceableIndex = 4
|
||||
kind_10003 replaceableIndex = 5
|
||||
kind_10004 replaceableIndex = 6
|
||||
kind_10005 replaceableIndex = 7
|
||||
kind_10006 replaceableIndex = 8
|
||||
kind_10007 replaceableIndex = 9
|
||||
kind_10015 replaceableIndex = 10
|
||||
kind_10030 replaceableIndex = 11
|
||||
)
|
||||
|
||||
type EventResult dataloader.Result[*nostr.Event]
|
||||
|
||||
func (sys *System) initializeDataloaders() {
|
||||
sys.replaceableLoaders = make(map[int]*dataloader.Loader[string, *nostr.Event])
|
||||
for _, kind := range []int{0, 3, 10000, 10001, 10002, 10003, 10004, 10005, 10006, 10007, 10015, 10030} {
|
||||
sys.replaceableLoaders[kind] = sys.createReplaceableDataloader(kind)
|
||||
}
|
||||
sys.replaceableLoaders[kind_0] = sys.createReplaceableDataloader(0)
|
||||
sys.replaceableLoaders[kind_3] = sys.createReplaceableDataloader(3)
|
||||
sys.replaceableLoaders[kind_10000] = sys.createReplaceableDataloader(10000)
|
||||
sys.replaceableLoaders[kind_10001] = sys.createReplaceableDataloader(10001)
|
||||
sys.replaceableLoaders[kind_10002] = sys.createReplaceableDataloader(10002)
|
||||
sys.replaceableLoaders[kind_10003] = sys.createReplaceableDataloader(10003)
|
||||
sys.replaceableLoaders[kind_10004] = sys.createReplaceableDataloader(10004)
|
||||
sys.replaceableLoaders[kind_10005] = sys.createReplaceableDataloader(10005)
|
||||
sys.replaceableLoaders[kind_10006] = sys.createReplaceableDataloader(10006)
|
||||
sys.replaceableLoaders[kind_10007] = sys.createReplaceableDataloader(10007)
|
||||
sys.replaceableLoaders[kind_10015] = sys.createReplaceableDataloader(10015)
|
||||
sys.replaceableLoaders[kind_10030] = sys.createReplaceableDataloader(10030)
|
||||
}
|
||||
|
||||
func (sys *System) createReplaceableDataloader(kind int) *dataloader.Loader[string, *nostr.Event] {
|
||||
|
@ -15,24 +15,28 @@ import (
|
||||
)
|
||||
|
||||
type System struct {
|
||||
RelayListCache cache.Cache32[RelayList]
|
||||
FollowListCache cache.Cache32[FollowList]
|
||||
MuteListCache cache.Cache32[FollowList]
|
||||
MetadataCache cache.Cache32[ProfileMetadata]
|
||||
Hints hints.HintsDB
|
||||
Pool *nostr.SimplePool
|
||||
RelayListRelays *RelayStream
|
||||
FollowListRelays *RelayStream
|
||||
MetadataRelays *RelayStream
|
||||
FallbackRelays *RelayStream
|
||||
JustIDRelays *RelayStream
|
||||
UserSearchRelays *RelayStream
|
||||
NoteSearchRelays *RelayStream
|
||||
Store eventstore.Store
|
||||
MetadataCache cache.Cache32[ProfileMetadata]
|
||||
RelayListCache cache.Cache32[GenericList[Relay]]
|
||||
FollowListCache cache.Cache32[GenericList[ProfileRef]]
|
||||
MuteListCache cache.Cache32[GenericList[ProfileRef]]
|
||||
BookmarkListCache cache.Cache32[GenericList[EventRef]]
|
||||
PinListCache cache.Cache32[GenericList[EventRef]]
|
||||
BlockedRelayListCache cache.Cache32[GenericList[RelayURL]]
|
||||
SearchRelayListCache cache.Cache32[GenericList[RelayURL]]
|
||||
Hints hints.HintsDB
|
||||
Pool *nostr.SimplePool
|
||||
RelayListRelays *RelayStream
|
||||
FollowListRelays *RelayStream
|
||||
MetadataRelays *RelayStream
|
||||
FallbackRelays *RelayStream
|
||||
JustIDRelays *RelayStream
|
||||
UserSearchRelays *RelayStream
|
||||
NoteSearchRelays *RelayStream
|
||||
Store eventstore.Store
|
||||
|
||||
StoreRelay nostr.RelayStore
|
||||
|
||||
replaceableLoaders map[int]*dataloader.Loader[string, *nostr.Event]
|
||||
replaceableLoaders []*dataloader.Loader[string, *nostr.Event]
|
||||
outboxShortTermCache cache.Cache32[[]string]
|
||||
}
|
||||
|
||||
@ -54,13 +58,17 @@ func (rs *RelayStream) Next() string {
|
||||
|
||||
func NewSystem(mods ...SystemModifier) *System {
|
||||
sys := &System{
|
||||
RelayListCache: cache_memory.New32[RelayList](1000),
|
||||
FollowListCache: cache_memory.New32[FollowList](1000),
|
||||
MuteListCache: cache_memory.New32[FollowList](1000),
|
||||
MetadataCache: cache_memory.New32[ProfileMetadata](1000),
|
||||
RelayListRelays: NewRelayStream("wss://purplepag.es", "wss://user.kindpag.es", "wss://relay.nos.social"),
|
||||
FollowListRelays: NewRelayStream("wss://purplepag.es", "wss://user.kindpag.es", "wss://relay.nos.social"),
|
||||
MetadataRelays: NewRelayStream("wss://purplepag.es", "wss://user.kindpag.es", "wss://relay.nos.social"),
|
||||
MetadataCache: cache_memory.New32[ProfileMetadata](8000),
|
||||
RelayListCache: cache_memory.New32[GenericList[Relay]](8000),
|
||||
FollowListCache: cache_memory.New32[GenericList[ProfileRef]](1000),
|
||||
MuteListCache: cache_memory.New32[GenericList[ProfileRef]](1000),
|
||||
BookmarkListCache: cache_memory.New32[GenericList[EventRef]](1000),
|
||||
PinListCache: cache_memory.New32[GenericList[EventRef]](1000),
|
||||
BlockedRelayListCache: cache_memory.New32[GenericList[RelayURL]](1000),
|
||||
SearchRelayListCache: cache_memory.New32[GenericList[RelayURL]](1000),
|
||||
RelayListRelays: NewRelayStream("wss://purplepag.es", "wss://user.kindpag.es", "wss://relay.nos.social"),
|
||||
FollowListRelays: NewRelayStream("wss://purplepag.es", "wss://user.kindpag.es", "wss://relay.nos.social"),
|
||||
MetadataRelays: NewRelayStream("wss://purplepag.es", "wss://user.kindpag.es", "wss://relay.nos.social"),
|
||||
FallbackRelays: NewRelayStream(
|
||||
"wss://relay.damus.io",
|
||||
"wss://nostr.mom",
|
||||
@ -165,24 +173,18 @@ func WithStore(store eventstore.Store) SystemModifier {
|
||||
}
|
||||
}
|
||||
|
||||
func WithRelayListCache(cache cache.Cache32[RelayList]) SystemModifier {
|
||||
func WithRelayListCache(cache cache.Cache32[GenericList[Relay]]) SystemModifier {
|
||||
return func(sys *System) {
|
||||
sys.RelayListCache = cache
|
||||
}
|
||||
}
|
||||
|
||||
func WithFollowListCache(cache cache.Cache32[FollowList]) SystemModifier {
|
||||
func WithFollowListCache(cache cache.Cache32[GenericList[ProfileRef]]) SystemModifier {
|
||||
return func(sys *System) {
|
||||
sys.FollowListCache = cache
|
||||
}
|
||||
}
|
||||
|
||||
func WithMuteListCache(cache cache.Cache32[FollowList]) SystemModifier {
|
||||
return func(sys *System) {
|
||||
sys.MuteListCache = cache
|
||||
}
|
||||
}
|
||||
|
||||
func WithMetadataCache(cache cache.Cache32[ProfileMetadata]) SystemModifier {
|
||||
return func(sys *System) {
|
||||
sys.MetadataCache = cache
|
||||
|
@ -81,7 +81,7 @@ func (sys *System) TrackEventHints(ie nostr.RelayEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
for _, ref := range ParseReferences(ie.Event) {
|
||||
for ref := range ParseReferences(*ie.Event) {
|
||||
if ref.Profile != nil {
|
||||
for _, relay := range ref.Profile.Relays {
|
||||
if IsVirtualRelay(relay) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user