sdk: FetchNutZapInfo() using the same flow as FetchProfileMetadata().
This commit is contained in:
@@ -27,13 +27,14 @@ const (
|
|||||||
kind_10006 replaceableIndex = 8
|
kind_10006 replaceableIndex = 8
|
||||||
kind_10007 replaceableIndex = 9
|
kind_10007 replaceableIndex = 9
|
||||||
kind_10015 replaceableIndex = 10
|
kind_10015 replaceableIndex = 10
|
||||||
kind_10030 replaceableIndex = 11
|
kind_10019 replaceableIndex = 11
|
||||||
|
kind_10030 replaceableIndex = 12
|
||||||
)
|
)
|
||||||
|
|
||||||
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], 13)
|
||||||
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)
|
||||||
@@ -45,6 +46,7 @@ func (sys *System) initializeReplaceableDataloaders() {
|
|||||||
sys.replaceableLoaders[kind_10006] = sys.createReplaceableDataloader(10006)
|
sys.replaceableLoaders[kind_10006] = sys.createReplaceableDataloader(10006)
|
||||||
sys.replaceableLoaders[kind_10007] = sys.createReplaceableDataloader(10007)
|
sys.replaceableLoaders[kind_10007] = sys.createReplaceableDataloader(10007)
|
||||||
sys.replaceableLoaders[kind_10015] = sys.createReplaceableDataloader(10015)
|
sys.replaceableLoaders[kind_10015] = sys.createReplaceableDataloader(10015)
|
||||||
|
sys.replaceableLoaders[kind_10019] = sys.createReplaceableDataloader(10019)
|
||||||
sys.replaceableLoaders[kind_10030] = sys.createReplaceableDataloader(10030)
|
sys.replaceableLoaders[kind_10030] = sys.createReplaceableDataloader(10030)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ type System struct {
|
|||||||
TopicSetsCache cache.Cache32[GenericSets[string, Topic]]
|
TopicSetsCache cache.Cache32[GenericSets[string, Topic]]
|
||||||
ZapProviderCache cache.Cache32[nostr.PubKey]
|
ZapProviderCache cache.Cache32[nostr.PubKey]
|
||||||
MintKeysCache cache.Cache32[map[uint64]*btcec.PublicKey]
|
MintKeysCache cache.Cache32[map[uint64]*btcec.PublicKey]
|
||||||
|
NutZapInfoCache cache.Cache32[NutZapInfo]
|
||||||
Hints hints.HintsDB
|
Hints hints.HintsDB
|
||||||
Pool *nostr.Pool
|
Pool *nostr.Pool
|
||||||
RelayListRelays *RelayStream
|
RelayListRelays *RelayStream
|
||||||
@@ -140,6 +141,9 @@ func NewSystem() *System {
|
|||||||
if sys.MintKeysCache == nil {
|
if sys.MintKeysCache == nil {
|
||||||
sys.MintKeysCache = cache_memory.New[map[uint64]*btcec.PublicKey](8000)
|
sys.MintKeysCache = cache_memory.New[map[uint64]*btcec.PublicKey](8000)
|
||||||
}
|
}
|
||||||
|
if sys.NutZapInfoCache == nil {
|
||||||
|
sys.NutZapInfoCache = cache_memory.New[NutZapInfo](8000)
|
||||||
|
}
|
||||||
|
|
||||||
if sys.Store == nil {
|
if sys.Store == nil {
|
||||||
sys.Store = &nullstore.NullStore{}
|
sys.Store = &nullstore.NullStore{}
|
||||||
|
|||||||
88
sdk/zap.go
88
sdk/zap.go
@@ -11,10 +11,20 @@ import (
|
|||||||
"fiatjaf.com/nostr"
|
"fiatjaf.com/nostr"
|
||||||
"fiatjaf.com/nostr/nip60"
|
"fiatjaf.com/nostr/nip60"
|
||||||
"fiatjaf.com/nostr/nip60/client"
|
"fiatjaf.com/nostr/nip60/client"
|
||||||
|
"fiatjaf.com/nostr/nip61"
|
||||||
"github.com/btcsuite/btcd/btcec/v2"
|
"github.com/btcsuite/btcd/btcec/v2"
|
||||||
"github.com/tidwall/gjson"
|
"github.com/tidwall/gjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NutZapInfo represents user nut zap information from kind 10019 events.
|
||||||
|
// contains both the raw event and parsed info fields.
|
||||||
|
type NutZapInfo struct {
|
||||||
|
PubKey nostr.PubKey `json:"-"` // must always be set otherwise things will break
|
||||||
|
Event *nostr.Event `json:"-"` // may be empty if a nut zap info event wasn't found
|
||||||
|
|
||||||
|
nip61.Info
|
||||||
|
}
|
||||||
|
|
||||||
// FetchZapProvider fetches the zap provider public key for a given user from their profile metadata.
|
// FetchZapProvider fetches the zap provider public key for a given user from their profile metadata.
|
||||||
// It uses a cache to avoid repeated fetches. If no zap provider is set in the profile, returns an empty PubKey.
|
// It uses a cache to avoid repeated fetches. If no zap provider is set in the profile, returns an empty PubKey.
|
||||||
func (sys *System) FetchZapProvider(ctx context.Context, pk nostr.PubKey) nostr.PubKey {
|
func (sys *System) FetchZapProvider(ctx context.Context, pk nostr.PubKey) nostr.PubKey {
|
||||||
@@ -52,6 +62,84 @@ func (sys *System) FetchZapProvider(ctx context.Context, pk nostr.PubKey) nostr.
|
|||||||
return nostr.ZeroPK
|
return nostr.ZeroPK
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FetchNutZapInfo fetches nut zap info for a given user from the local cache, or from the local store,
|
||||||
|
// or, failing these, from the target user's defined outbox relays -- then caches the result.
|
||||||
|
// always returns a NutZapInfo, even if no info was found (in which case only the PubKey field is set).
|
||||||
|
func (sys *System) FetchNutZapInfo(ctx context.Context, pubkey nostr.PubKey) NutZapInfo {
|
||||||
|
if v, ok := sys.NutZapInfoCache.Get(pubkey); ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
for evt := range sys.Store.QueryEvents(nostr.Filter{Kinds: []nostr.Kind{10019}, Authors: []nostr.PubKey{pubkey}}, 1) {
|
||||||
|
// ok, we found something locally
|
||||||
|
nzi, err := ParseNutZapInfo(evt)
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// but if we haven't tried fetching from the network recently we should do it
|
||||||
|
lastFetchKey := makeLastFetchKey(10019, pubkey)
|
||||||
|
lastFetchData, _ := sys.KVStore.Get(lastFetchKey)
|
||||||
|
if lastFetchData == nil || nostr.Now()-decodeTimestamp(lastFetchData) > 7*24*60*60 {
|
||||||
|
newNZI := sys.tryFetchNutZapInfoFromNetwork(ctx, pubkey)
|
||||||
|
if newNZI != nil && newNZI.Event.CreatedAt > nzi.Event.CreatedAt {
|
||||||
|
nzi = *newNZI
|
||||||
|
}
|
||||||
|
|
||||||
|
// even if we didn't find anything register this because we tried
|
||||||
|
// (and we still have the previous event in our local store)
|
||||||
|
sys.KVStore.Set(lastFetchKey, encodeTimestamp(nostr.Now()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// and finally save this to cache
|
||||||
|
sys.NutZapInfoCache.SetWithTTL(pubkey, nzi, time.Hour*6)
|
||||||
|
|
||||||
|
return nzi
|
||||||
|
}
|
||||||
|
|
||||||
|
var nzi NutZapInfo
|
||||||
|
nzi.PubKey = pubkey
|
||||||
|
if newNZI := sys.tryFetchNutZapInfoFromNetwork(ctx, pubkey); newNZI != nil {
|
||||||
|
nzi = *newNZI
|
||||||
|
|
||||||
|
// we'll only save this if we got something which means we found at least one event
|
||||||
|
lastFetchKey := makeLastFetchKey(10019, pubkey)
|
||||||
|
sys.KVStore.Set(lastFetchKey, encodeTimestamp(nostr.Now()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// save cache even if we didn't get anything
|
||||||
|
sys.NutZapInfoCache.SetWithTTL(pubkey, nzi, time.Hour*6)
|
||||||
|
|
||||||
|
return nzi
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sys *System) tryFetchNutZapInfoFromNetwork(ctx context.Context, pubkey nostr.PubKey) *NutZapInfo {
|
||||||
|
evt, err := sys.replaceableLoaders[kind_10019].Load(ctx, pubkey)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
nzi, err := ParseNutZapInfo(evt)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sys.Publisher.Publish(ctx, evt)
|
||||||
|
sys.NutZapInfoCache.SetWithTTL(pubkey, nzi, time.Hour*6)
|
||||||
|
return &nzi
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseNutZapInfo parses a kind 10019 event into a NutZapInfo struct.
|
||||||
|
// returns an error if the event is not kind 10019 or if parsing fails.
|
||||||
|
func ParseNutZapInfo(event nostr.Event) (nzi NutZapInfo, err error) {
|
||||||
|
err = nzi.Info.ParseEvent(event)
|
||||||
|
|
||||||
|
nzi.PubKey = event.PubKey
|
||||||
|
nzi.Event = &event
|
||||||
|
|
||||||
|
return nzi, err
|
||||||
|
}
|
||||||
|
|
||||||
// FetchMintKeys fetches the active keyset from the given mint URL and parses the keys.
|
// FetchMintKeys fetches the active keyset from the given mint URL and parses the keys.
|
||||||
// It uses a cache to avoid repeated fetches.
|
// It uses a cache to avoid repeated fetches.
|
||||||
func (sys *System) FetchMintKeys(ctx context.Context, mintURL string) (map[uint64]*btcec.PublicKey, error) {
|
func (sys *System) FetchMintKeys(ctx context.Context, mintURL string) (map[uint64]*btcec.PublicKey, error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user