mirror of
https://github.com/fiatjaf/khatru.git
synced 2025-03-17 21:32:55 +01:00
Adds NIP-33 support for replaceable events.
This commit is contained in:
parent
7ea3cd5431
commit
a82e5edb0d
@ -308,7 +308,7 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, r *http.Request) {
|
||||
func (s *Server) handleNIP11(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
supportedNIPs := []int{9, 11, 12, 15, 16, 20}
|
||||
supportedNIPs := []int{9, 11, 12, 15, 16, 20, 33}
|
||||
if _, ok := s.relay.(Auther); ok {
|
||||
supportedNIPs = append(supportedNIPs, 42)
|
||||
}
|
||||
|
@ -97,7 +97,12 @@ func (ess *ElasticsearchStorage) Init() error {
|
||||
}
|
||||
|
||||
func (ess *ElasticsearchStorage) DeleteEvent(id string, pubkey string) error {
|
||||
// todo: is pubkey match required?
|
||||
// first do get by ID and check that pubkeys match
|
||||
// this is cheaper than doing delete by query, which also doesn't work with bulk indexer.
|
||||
found, _ := ess.getByID(&nostr.Filter{IDs: []string{id}})
|
||||
if len(found) == 0 || found[0].PubKey != pubkey {
|
||||
return nil
|
||||
}
|
||||
|
||||
done := make(chan error)
|
||||
err := ess.bi.Add(
|
||||
@ -132,9 +137,9 @@ func (ess *ElasticsearchStorage) DeleteEvent(id string, pubkey string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (ess *ElasticsearchStorage) SaveEvent(event *nostr.Event) error {
|
||||
func (ess *ElasticsearchStorage) SaveEvent(evt *nostr.Event) error {
|
||||
ie := &IndexedEvent{
|
||||
Event: *event,
|
||||
Event: *evt,
|
||||
}
|
||||
|
||||
// post processing: index for FTS
|
||||
@ -144,8 +149,8 @@ func (ess *ElasticsearchStorage) SaveEvent(event *nostr.Event) error {
|
||||
// - if it's valid JSON just index the "values" and not the keys
|
||||
// - more content introspection: language detection
|
||||
// - denormalization... attach profile + ranking signals to events
|
||||
if event.Kind != 4 {
|
||||
ie.ContentSearch = event.Content
|
||||
if evt.Kind != 4 {
|
||||
ie.ContentSearch = evt.Content
|
||||
}
|
||||
|
||||
data, err := json.Marshal(ie)
|
||||
@ -155,13 +160,57 @@ func (ess *ElasticsearchStorage) SaveEvent(event *nostr.Event) error {
|
||||
|
||||
done := make(chan error)
|
||||
|
||||
// delete replaceable events
|
||||
deleteIDs := []string{}
|
||||
queryForDelete := func(filter *nostr.Filter) {
|
||||
toDelete, _ := ess.QueryEvents(filter)
|
||||
for _, e := range toDelete {
|
||||
// KindRecommendServer: we can't query ES for exact content match
|
||||
// so query by kind and loop over results to compare content
|
||||
if evt.Kind == nostr.KindRecommendServer {
|
||||
if e.Content == evt.Content {
|
||||
deleteIDs = append(deleteIDs, e.ID)
|
||||
}
|
||||
} else {
|
||||
deleteIDs = append(deleteIDs, e.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
if evt.Kind == nostr.KindSetMetadata || evt.Kind == nostr.KindContactList || evt.Kind == nostr.KindRecommendServer || (10000 <= evt.Kind && evt.Kind < 20000) {
|
||||
// delete past events from this user
|
||||
queryForDelete(&nostr.Filter{
|
||||
Authors: []string{evt.PubKey},
|
||||
Kinds: []int{evt.Kind},
|
||||
})
|
||||
} else if evt.Kind >= 30000 && evt.Kind < 40000 {
|
||||
// NIP-33
|
||||
d := evt.Tags.GetFirst([]string{"d"})
|
||||
if d != nil {
|
||||
queryForDelete(&nostr.Filter{
|
||||
Authors: []string{evt.PubKey},
|
||||
Kinds: []int{evt.Kind},
|
||||
Tags: nostr.TagMap{
|
||||
"d": []string{d.Value()},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, id := range deleteIDs {
|
||||
ess.bi.Add(
|
||||
context.Background(),
|
||||
esutil.BulkIndexerItem{
|
||||
Action: "delete",
|
||||
DocumentID: id,
|
||||
})
|
||||
}
|
||||
|
||||
// adapted from:
|
||||
// https://github.com/elastic/go-elasticsearch/blob/main/_examples/bulk/indexer.go#L196
|
||||
err = ess.bi.Add(
|
||||
context.Background(),
|
||||
esutil.BulkIndexerItem{
|
||||
Action: "index",
|
||||
DocumentID: event.ID,
|
||||
DocumentID: evt.ID,
|
||||
Body: bytes.NewReader(data),
|
||||
OnSuccess: func(ctx context.Context, item esutil.BulkIndexerItem, res esutil.BulkIndexerResponseItem) {
|
||||
close(done)
|
||||
|
@ -172,6 +172,7 @@ func isGetByID(filter *nostr.Filter) bool {
|
||||
len(filter.Authors) == 0 &&
|
||||
len(filter.Kinds) == 0 &&
|
||||
len(filter.Tags) == 0 &&
|
||||
len(filter.Search) == 0 &&
|
||||
filter.Since == nil &&
|
||||
filter.Until == nil
|
||||
|
||||
|
@ -16,6 +16,13 @@ func (b *PostgresBackend) SaveEvent(evt *nostr.Event) error {
|
||||
// delete past recommend_server events equal to this one
|
||||
b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3`,
|
||||
evt.PubKey, evt.Kind, evt.Content)
|
||||
} else if evt.Kind >= 30000 && evt.Kind < 40000 {
|
||||
// NIP-33
|
||||
d := evt.Tags.GetFirst([]string{"d"})
|
||||
if d != nil {
|
||||
b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND tagvalues && ARRAY[$3]`,
|
||||
evt.PubKey, evt.Kind, d.Value())
|
||||
}
|
||||
}
|
||||
|
||||
// insert
|
||||
|
@ -2,6 +2,7 @@ package sqlite3
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/fiatjaf/relayer/storage"
|
||||
"github.com/nbd-wtf/go-nostr"
|
||||
@ -16,6 +17,13 @@ func (b *SQLite3Backend) SaveEvent(evt *nostr.Event) error {
|
||||
// delete past recommend_server events equal to this one
|
||||
b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3`,
|
||||
evt.PubKey, evt.Kind, evt.Content)
|
||||
} else if evt.Kind >= 30000 && evt.Kind < 40000 {
|
||||
// NIP-33
|
||||
d := evt.Tags.GetFirst([]string{"d"})
|
||||
if d != nil {
|
||||
tagsLike := fmt.Sprintf(`%%"d","%s"%%`, d.Value())
|
||||
b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND tags LIKE $3`, evt.PubKey, evt.Kind, tagsLike)
|
||||
}
|
||||
}
|
||||
|
||||
// insert
|
||||
|
Loading…
x
Reference in New Issue
Block a user