Skip to content

Routing

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 from somewhere else, like a library such as 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")

// a relay for NIP-29 groups
groupsStore := badger.BadgerBackend{}
groupsStore.Init()
groupsRelay, _ := khatru29.Init(relay29.Options{Domain: "example.com", DB: groupsStore, SecretKey: sk})
// ...

// a relay for everything else
publicStore := slicestore.SliceStore{}
publicStore.Init()
publicRelay := khatru.NewRelay()
publicRelay.StoreEvent = append(publicRelay.StoreEvent, publicStore.SaveEvent)
publicRelay.QueryEvents = append(publicRelay.QueryEvents, publicStore.QueryEvents)
publicRelay.CountEvents = append(publicRelay.CountEvents, publicStore.CountEvents)
publicRelay.DeleteEvent = append(publicRelay.DeleteEvent, publicStore.DeleteEvent)
// ...

// a higher-level relay that just routes between the two above
router := khatru.NewRouter()

// route requests and events to the groups relay
router.Route().
	Req(func (filter nostr.Filter) bool {
		_, hasHTag := filter.Tags["h"]
		if hasHTag {
			return true
		}
		return slices.Contains(filter.Kinds, func (k int) bool { return k == 39000 || k == 39001 || k == 39002 })
	}).
	Event(func (event *nostr.Event) bool {
		switch {
		case event.Kind <= 9021 && event.Kind >= 9000:
			return true
		case event.Kind <= 39010 && event.Kind >= 39000:
			return true
		case event.Kind <= 12 && event.Kind >= 9:
			return true
		case event.Tags.GetFirst([]string{"h", ""}) != nil:
			return true
		default:
			return false
		}
	}).
	Relay(groupsRelay)

// route requests and events to the other
router.Route().
	Req(func (filter nostr.Filter) bool { return true }).
	Event(func (event *nostr.Event) bool { return true }).
	Relay(publicRelay)
~