2024-09-17 01:01:42 +00:00
|
|
|
package khatru
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/fiatjaf/eventstore"
|
|
|
|
"github.com/nbd-wtf/go-nostr"
|
|
|
|
)
|
|
|
|
|
|
|
|
// AddEvent sends an event through then normal add pipeline, as if it was received from a websocket.
|
|
|
|
func (rl *Relay) AddEvent(ctx context.Context, evt *nostr.Event) (skipBroadcast bool, writeError error) {
|
2024-09-25 02:29:00 +00:00
|
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
|
|
defer cancel()
|
|
|
|
|
2024-09-17 01:01:42 +00:00
|
|
|
if evt == nil {
|
|
|
|
return false, errors.New("error: event is nil")
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, reject := range rl.RejectEvent {
|
|
|
|
if reject, msg := reject(ctx, evt); reject {
|
|
|
|
if msg == "" {
|
|
|
|
return false, errors.New("blocked: no reason")
|
|
|
|
} else {
|
|
|
|
return false, errors.New(nostr.NormalizeOKMessage(msg, "blocked"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if 20000 <= evt.Kind && evt.Kind < 30000 {
|
|
|
|
// do not store ephemeral events
|
|
|
|
for _, oee := range rl.OnEphemeralEvent {
|
|
|
|
oee(ctx, evt)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// will store
|
2024-11-29 19:44:33 +00:00
|
|
|
// regular kinds are just saved directly
|
|
|
|
if nostr.IsRegularKind(evt.Kind) {
|
|
|
|
for _, store := range rl.StoreEvent {
|
|
|
|
if err := store(ctx, evt); err != nil {
|
|
|
|
switch err {
|
|
|
|
case eventstore.ErrDupEvent:
|
|
|
|
return true, nil
|
|
|
|
default:
|
|
|
|
return false, fmt.Errorf(nostr.NormalizeOKMessage(err.Error(), "error"))
|
|
|
|
}
|
2024-09-17 01:01:42 +00:00
|
|
|
}
|
2024-11-29 19:44:33 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// otherwise it's a replaceable -- so we'll use the replacer functions if we have any
|
|
|
|
if len(rl.ReplaceEvent) > 0 {
|
|
|
|
for _, repl := range rl.ReplaceEvent {
|
|
|
|
if err := repl(ctx, evt); err != nil {
|
|
|
|
switch err {
|
|
|
|
case eventstore.ErrDupEvent:
|
|
|
|
return true, nil
|
|
|
|
default:
|
|
|
|
return false, fmt.Errorf(nostr.NormalizeOKMessage(err.Error(), "error"))
|
2024-09-17 01:01:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-11-29 19:44:33 +00:00
|
|
|
} else {
|
|
|
|
// otherwise do it the manual way
|
|
|
|
filter := nostr.Filter{Limit: 1, Kinds: []int{evt.Kind}, Authors: []string{evt.PubKey}}
|
|
|
|
if nostr.IsAddressableKind(evt.Kind) {
|
|
|
|
// when addressable, add the "d" tag to the filter
|
|
|
|
filter.Tags = nostr.TagMap{"d": []string{evt.Tags.GetD()}}
|
2024-09-17 01:01:42 +00:00
|
|
|
}
|
2024-11-29 19:44:33 +00:00
|
|
|
|
|
|
|
// now we fetch old events and delete them
|
|
|
|
shouldStore := true
|
|
|
|
for _, query := range rl.QueryEvents {
|
|
|
|
ch, err := query(ctx, filter)
|
|
|
|
if err != nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
for previous := range ch {
|
|
|
|
if isOlder(previous, evt) {
|
|
|
|
for _, del := range rl.DeleteEvent {
|
|
|
|
del(ctx, previous)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// we found a more recent event, so we won't delete it and also will not store this new one
|
|
|
|
shouldStore = false
|
2024-09-17 01:01:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-29 19:44:33 +00:00
|
|
|
// store
|
|
|
|
if shouldStore {
|
|
|
|
for _, store := range rl.StoreEvent {
|
|
|
|
if saveErr := store(ctx, evt); saveErr != nil {
|
|
|
|
switch saveErr {
|
|
|
|
case eventstore.ErrDupEvent:
|
|
|
|
return true, nil
|
|
|
|
default:
|
|
|
|
return false, fmt.Errorf(nostr.NormalizeOKMessage(saveErr.Error(), "error"))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-09-17 01:01:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, ons := range rl.OnEventSaved {
|
|
|
|
ons(ctx, evt)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false, nil
|
|
|
|
}
|