go-nostr/sdk/system.go

252 lines
7.8 KiB
Go
Raw Permalink Normal View History

package sdk
import (
"context"
"math/rand/v2"
"github.com/fiatjaf/eventstore"
"github.com/fiatjaf/eventstore/nullstore"
"github.com/graph-gophers/dataloader/v7"
"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/hints"
"github.com/nbd-wtf/go-nostr/sdk/hints/memoryh"
2025-01-14 23:11:37 -03:00
"github.com/nbd-wtf/go-nostr/sdk/kvstore"
kvstore_memory "github.com/nbd-wtf/go-nostr/sdk/kvstore/memory"
)
2025-03-04 11:08:31 -03:00
// System represents the core functionality of the SDK, providing access to
// various caches, relays, and dataloaders for efficient Nostr operations.
//
// Usually an application should have a single global instance of this and use
// its internal Pool for all its operations.
//
// Store, KVStore and Hints are databases that should generally be persisted
// for any application that is intended to be executed more than once. By
// default they're set to in-memory stores, but ideally persisteable
// implementations should be given (some alternatives are provided in subpackages).
type System struct {
2025-01-14 23:11:37 -03:00
KVStore kvstore.KVStore
2025-01-01 18:16:36 -03:00
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]]
2025-01-02 12:12:49 -03:00
TopicListCache cache.Cache32[GenericList[Topic]]
RelaySetsCache cache.Cache32[GenericSets[RelayURL]]
FollowSetsCache cache.Cache32[GenericSets[ProfileRef]]
TopicSetsCache cache.Cache32[GenericSets[Topic]]
2025-01-01 18:16:36 -03:00
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 []*dataloader.Loader[string, *nostr.Event]
addressableLoaders []*dataloader.Loader[string, []*nostr.Event]
}
2025-03-04 11:08:31 -03:00
// SystemModifier is a function that modifies a System instance.
// It's used with NewSystem to configure the system during creation.
type SystemModifier func(sys *System)
2025-03-04 11:08:31 -03:00
// RelayStream provides a rotating list of relay URLs.
// It's used to distribute requests across multiple relays.
2024-10-06 15:53:33 -03:00
type RelayStream struct {
URLs []string
serial int
}
2025-03-04 11:08:31 -03:00
// NewRelayStream creates a new RelayStream with the provided URLs.
2024-10-06 15:53:33 -03:00
func NewRelayStream(urls ...string) *RelayStream {
return &RelayStream{URLs: urls, serial: rand.Int()}
2024-10-06 15:53:33 -03:00
}
2025-03-04 11:08:31 -03:00
// Next returns the next URL in the rotation.
2024-10-06 15:53:33 -03:00
func (rs *RelayStream) Next() string {
rs.serial++
return rs.URLs[rs.serial%len(rs.URLs)]
}
2025-03-04 11:08:31 -03:00
// NewSystem creates a new System with default configuration,
// which can be customized using the provided modifiers.
//
// The list of provided With* modifiers isn't exhaustive and
// most internal fields of System can be modified after the System
// creation -- and in many cases one or another of these will have
// to be modified, so don't be afraid of doing that.
func NewSystem(mods ...SystemModifier) *System {
sys := &System{
KVStore: kvstore_memory.NewStore(),
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"),
2024-10-06 15:53:33 -03:00
FallbackRelays: NewRelayStream(
"wss://relay.damus.io",
"wss://nostr.mom",
"wss://nos.lol",
"wss://mostr.pub",
"wss://relay.nostr.band",
2024-10-06 15:53:33 -03:00
),
JustIDRelays: NewRelayStream(
"wss://cache2.primal.net/v1",
"wss://relay.nostr.band",
),
UserSearchRelays: NewRelayStream(
"wss://search.nos.today",
"wss://nostr.wine",
"wss://relay.nostr.band",
2024-10-06 15:53:33 -03:00
),
NoteSearchRelays: NewRelayStream(
"wss://nostr.wine",
"wss://relay.nostr.band",
2024-10-06 15:53:33 -03:00
"wss://search.nos.today",
),
Hints: memoryh.NewHintDB(),
}
sys.Pool = nostr.NewSimplePool(context.Background(),
nostr.WithAuthorKindQueryMiddleware(sys.TrackQueryAttempts),
nostr.WithEventMiddleware(sys.TrackEventHintsAndRelays),
2025-01-15 00:30:24 -03:00
nostr.WithDuplicateMiddleware(sys.TrackEventRelaysD),
nostr.WithPenaltyBox(),
)
for _, mod := range mods {
mod(sys)
}
if sys.MetadataCache == nil {
sys.MetadataCache = cache_memory.New32[ProfileMetadata](8000)
}
if sys.RelayListCache == nil {
sys.RelayListCache = cache_memory.New32[GenericList[Relay]](8000)
}
if sys.Store == nil {
sys.Store = &nullstore.NullStore{}
sys.Store.Init()
}
sys.StoreRelay = eventstore.RelayWrapper{Store: sys.Store}
2025-01-02 12:12:49 -03:00
sys.initializeReplaceableDataloaders()
sys.initializeAddressableDataloaders()
return sys
}
2025-03-04 11:08:31 -03:00
// Close releases resources held by the System.
2025-01-14 23:11:37 -03:00
func (sys *System) Close() {
if sys.KVStore != nil {
sys.KVStore.Close()
}
2025-03-04 11:08:31 -03:00
if sys.Pool != nil {
sys.Pool.Close("sdk.System closed")
}
2025-01-14 23:11:37 -03:00
}
2025-03-04 11:08:31 -03:00
// WithHintsDB returns a SystemModifier that sets the HintsDB.
func WithHintsDB(hdb hints.HintsDB) SystemModifier {
return func(sys *System) {
sys.Hints = hdb
}
}
2025-03-04 11:08:31 -03:00
// WithRelayListRelays returns a SystemModifier that sets the RelayListRelays.
func WithRelayListRelays(list []string) SystemModifier {
return func(sys *System) {
2024-10-06 15:53:33 -03:00
sys.RelayListRelays.URLs = list
}
}
2025-03-04 11:08:31 -03:00
// WithMetadataRelays returns a SystemModifier that sets the MetadataRelays.
func WithMetadataRelays(list []string) SystemModifier {
return func(sys *System) {
2024-10-06 15:53:33 -03:00
sys.MetadataRelays.URLs = list
}
}
2025-03-04 11:08:31 -03:00
// WithFollowListRelays returns a SystemModifier that sets the FollowListRelays.
func WithFollowListRelays(list []string) SystemModifier {
return func(sys *System) {
2024-10-06 15:53:33 -03:00
sys.FollowListRelays.URLs = list
}
}
2025-03-04 11:08:31 -03:00
// WithFallbackRelays returns a SystemModifier that sets the FallbackRelays.
func WithFallbackRelays(list []string) SystemModifier {
return func(sys *System) {
2024-10-06 15:53:33 -03:00
sys.FallbackRelays.URLs = list
}
}
2025-03-04 11:08:31 -03:00
// WithJustIDRelays returns a SystemModifier that sets the JustIDRelays.
2024-10-06 15:53:33 -03:00
func WithJustIDRelays(list []string) SystemModifier {
return func(sys *System) {
sys.JustIDRelays.URLs = list
}
}
2025-03-04 11:08:31 -03:00
// WithUserSearchRelays returns a SystemModifier that sets the UserSearchRelays.
func WithUserSearchRelays(list []string) SystemModifier {
return func(sys *System) {
2024-10-06 15:53:33 -03:00
sys.UserSearchRelays.URLs = list
}
}
2025-03-04 11:08:31 -03:00
// WithNoteSearchRelays returns a SystemModifier that sets the NoteSearchRelays.
func WithNoteSearchRelays(list []string) SystemModifier {
return func(sys *System) {
2024-10-06 15:53:33 -03:00
sys.NoteSearchRelays.URLs = list
}
}
2025-03-04 11:08:31 -03:00
// WithStore returns a SystemModifier that sets the Store.
func WithStore(store eventstore.Store) SystemModifier {
return func(sys *System) {
sys.Store = store
}
}
2025-03-04 11:08:31 -03:00
// WithRelayListCache returns a SystemModifier that sets the RelayListCache.
2025-01-01 18:16:36 -03:00
func WithRelayListCache(cache cache.Cache32[GenericList[Relay]]) SystemModifier {
return func(sys *System) {
sys.RelayListCache = cache
}
}
2025-03-04 11:08:31 -03:00
// WithFollowListCache returns a SystemModifier that sets the FollowListCache.
2025-01-01 18:16:36 -03:00
func WithFollowListCache(cache cache.Cache32[GenericList[ProfileRef]]) SystemModifier {
return func(sys *System) {
sys.FollowListCache = cache
}
}
2025-03-04 11:08:31 -03:00
// WithMetadataCache returns a SystemModifier that sets the MetadataCache.
func WithMetadataCache(cache cache.Cache32[ProfileMetadata]) SystemModifier {
return func(sys *System) {
sys.MetadataCache = cache
}
}
2025-01-14 23:11:37 -03:00
2025-03-04 11:08:31 -03:00
// WithKVStore returns a SystemModifier that sets the KVStore.
2025-01-14 23:11:37 -03:00
func WithKVStore(store kvstore.KVStore) SystemModifier {
return func(sys *System) {
if sys.KVStore != nil {
sys.KVStore.Close()
}
sys.KVStore = store
}
}