diff --git a/khatru/docs/cookbook/custom-live-events.md b/khatru/docs/cookbook/custom-live-events.md index 4cd4c3b..656d8be 100644 --- a/khatru/docs/cookbook/custom-live-events.md +++ b/khatru/docs/cookbook/custom-live-events.md @@ -46,9 +46,9 @@ func startPollingGame(relay *khatru.Relay) { relay.BroadcastEvent(evt) // just calling BroadcastEvent won't cause this event to be be stored, - // if for any reason you want to store these events you must call the store functions manually - for _, store := range relay.StoreEvent { - store(context.TODO(), evt) + // if for any reason you want to store these events you must call the store function manually + if relay.StoreEvent != nil { + relay.StoreEvent(context.TODO(), evt) } } if newStatus.TeamB > current.TeamB { diff --git a/khatru/docs/cookbook/custom-stores.md b/khatru/docs/cookbook/custom-stores.md index a8efb29..64fd4d9 100644 --- a/khatru/docs/cookbook/custom-stores.md +++ b/khatru/docs/cookbook/custom-stores.md @@ -69,12 +69,13 @@ func handleWeatherQuery(ctx context.Context, filter nostr.Filter) iter.Seq[nostr } } evt.Sign(global.RelaySecretKey) - ch <- evt + if !yield(evt) { + return + } } } } }() - return ch, nil } } ``` diff --git a/khatru/docs/cookbook/google-drive.md b/khatru/docs/cookbook/google-drive.md index 9e70ae7..582deea 100644 --- a/khatru/docs/cookbook/google-drive.md +++ b/khatru/docs/cookbook/google-drive.md @@ -16,7 +16,7 @@ func main () { // other stuff here } -func handleEvent(ctx context.Context, event *nostr.Event) error { +func handleEvent(ctx context.Context, event nostr.Event) error { // store each event as a file on google drive _, err := gdriveService.Files.Create(googledrive.CreateOptions{ Name: event.ID, // with the name set to their id @@ -25,12 +25,9 @@ func handleEvent(ctx context.Context, event *nostr.Event) error { return err } -func handleQuery(ctx context.Context, filter nostr.Filter) (ch chan *nostr.Event, err error) { - // QueryEvents functions are expected to return a channel - ch := make(chan *nostr.Event) - - // and they can do their query asynchronously, emitting events to the channel as they come - go func () { +func handleQuery(ctx context.Context, filter nostr.Filter) iter.Seq[nostr.Event] { + // QueryEvents functions return an iterator + return func(yield func(nostr.Event) bool) { if len(filter.IDs) > 0 { // if the query is for ids we can do a simpler name match for _, id := range filter.IDS { @@ -40,7 +37,9 @@ func handleQuery(ctx context.Context, filter nostr.Filter) (ch chan *nostr.Event if len(results) > 0 { var evt nostr.Event json.Unmarshal(results[0].Body, &evt) - ch <- evt + if !yield(evt) { + return + } } } } else { @@ -53,14 +52,14 @@ func handleQuery(ctx context.Context, filter nostr.Filter) (ch chan *nostr.Event var evt nostr.Event json.Unmarshal(results[0].Body, &evt) if filter.Match(evt) { - ch <- evt + if !yield(evt) { + return + } } } } } - }() - - return ch, nil + } } ``` diff --git a/khatru/docs/cookbook/search.md b/khatru/docs/cookbook/search.md index b819283..04881f3 100644 --- a/khatru/docs/cookbook/search.md +++ b/khatru/docs/cookbook/search.md @@ -25,9 +25,24 @@ func main () { panic(err) } - relay.StoreEvent = policies.SeqStore(normal.SaveEvent, search.SaveEvent) - relay.QueryStored = policies.SeqQuery(normal.QueryEvents, search.QueryEvents) - relay.DeleteEvent = policies.SeqDelete(normal.DeleteEvent, search.DeleteEvent) + relay.StoreEvent = func(ctx context.Context, evt nostr.Event) error { + if err := normal.SaveEvent(evt); err != nil { + return err + } + return search.SaveEvent(evt) + } + relay.QueryStored = func(ctx context.Context, filter nostr.Filter) iter.Seq[nostr.Event] { + if filter.Search != "" { + return search.QueryEvents(filter) + } + return normal.QueryEvents(filter) + } + relay.DeleteEvent = func(ctx context.Context, id nostr.ID) error { + if err := normal.DeleteEvent(id); err != nil { + return err + } + return search.DeleteEvent(id) + } // other stuff here } diff --git a/khatru/docs/core/auth.md b/khatru/docs/core/auth.md index bf96981..5361731 100644 --- a/khatru/docs/core/auth.md +++ b/khatru/docs/core/auth.md @@ -33,7 +33,7 @@ If on `OnRequest` or `OnEvent` you prefix the message with `auth-required: `, th relay.OnRequest = func(ctx context.Context, filter nostr.Filter) (bool, string) { return true, "auth-required: this query requires you to be authenticated" } -relay.OnEvent = func(ctx context.Context, event *nostr.Event) (bool, string) { +relay.OnEvent = func(ctx context.Context, event nostr.Event) (bool, string) { return true, "auth-required: publishing this event requires authentication" } ``` diff --git a/khatru/docs/core/embed.md b/khatru/docs/core/embed.md index 5cea700..cf7e070 100644 --- a/khatru/docs/core/embed.md +++ b/khatru/docs/core/embed.md @@ -63,7 +63,7 @@ func main() { } ``` -Every [`khatru.Relay`](https://pkg.go.dev/github.com/fiatjaf/khatru#Relay) instance comes with its own ['http.ServeMux`](https://pkg.go.dev/net/http#ServeMux) inside. It ensures all requests are handled normally, but intercepts the requests that are pertinent to the relay operation, specifically the WebSocket requests, and the [NIP-11](https://nips.nostr.com/11) and the [NIP-86](https://nips.nostr.com/86) HTTP requests. +Every [`khatru.Relay`](https://pkg.go.dev/fiatjaf.com/nostr/khatru#Relay) instance comes with its own ['http.ServeMux`](https://pkg.go.dev/net/http#ServeMux) inside. It ensures all requests are handled normally, but intercepts the requests that are pertinent to the relay operation, specifically the WebSocket requests, and the [NIP-11](https://nips.nostr.com/11) and the [NIP-86](https://nips.nostr.com/86) HTTP requests. ## Exposing multiple relays at the same path or at the root diff --git a/khatru/docs/core/eventstore.md b/khatru/docs/core/eventstore.md index de4e184..a682ada 100644 --- a/khatru/docs/core/eventstore.md +++ b/khatru/docs/core/eventstore.md @@ -62,7 +62,7 @@ You can do a kind of sharding, for example, by storing some events in one store For example, maybe you want kind 1 events in `db1` and kind 30023 events in `db30023`: ```go - relay.StoreEvent = func (ctx context.Context, evt *nostr.Event) error { + relay.StoreEvent = func (ctx context.Context, evt nostr.Event) error { switch evt.Kind { case nostr.Kind(1): return db1.SaveEvent(evt) diff --git a/khatru/docs/core/routing.md b/khatru/docs/core/routing.md index e79d044..4c406d7 100644 --- a/khatru/docs/core/routing.md +++ b/khatru/docs/core/routing.md @@ -6,8 +6,6 @@ outline: deep If you have one (or more) set of policies that have to be executed in sequence (for example, first you check for the presence of a tag, then later in the next policies you use that tag without checking) and they only apply to some class of events, but you still want your relay to deal with other classes of events that can lead to cumbersome sets of rules, always having to check if an event meets the requirements and so on. There is where routing can help you. -It also can be handy if you get a [`khatru.Relay`](https://pkg.go.dev/github.com/fiatjaf/khatru#Relay) from somewhere else, like a library such as [`relay29`](https://github.com/fiatjaf/relay29), and you want to combine it with other policies without some interfering with the others. As in the example below: - ```go sk := os.Getenv("RELAY_SECRET_KEY") diff --git a/khatru/docs/getting-started/index.md b/khatru/docs/getting-started/index.md index a6d5c6c..3c8b58a 100644 --- a/khatru/docs/getting-started/index.md +++ b/khatru/docs/getting-started/index.md @@ -47,7 +47,7 @@ These are lists of functions that will be called in order every time an `EVENT` The next step is adding some protection, because maybe we don't want to allow _anyone_ to write to our relay. Maybe we want to only allow people that have a pubkey starting with `"a"`, `"b"` or `"c"`: ```go -relay.OnEvent = func (ctx context.Context, event *nostr.Event) (reject bool, msg string) { +relay.OnEvent = func (ctx context.Context, event nostr.Event) (reject bool, msg string) { firstHexChar := event.PubKey.Hex()[0:1] if firstHexChar == "a" || firstHexChar == "b" || firstHexChar == "c" { return false, "" // allow diff --git a/khatru/docs/index.md b/khatru/docs/index.md index 8446fac..d1d4242 100644 --- a/khatru/docs/index.md +++ b/khatru/docs/index.md @@ -35,7 +35,7 @@ features: details: You just define your custom handlers for each RPC call and they will be exposed appropriately to management clients. - title: It's written in Go icon: 🛵 - link: https://pkg.go.dev/github.com/fiatjaf/khatru + link: https://pkg.go.dev/fiatjaf.com/nostr/khatru details: That means it is fast and lightweight, you can learn the language in 5 minutes and it builds your relay into a single binary that's easy to ship and deploy. ---