mirror of
https://github.com/fiatjaf/khatru.git
synced 2026-06-05 18:21:31 +02:00
Adds NIP-33 support for replaceable events.
This commit is contained in:
@@ -308,7 +308,7 @@ func (s *Server) handleWebsocket(w http.ResponseWriter, r *http.Request) {
|
|||||||
func (s *Server) handleNIP11(w http.ResponseWriter, r *http.Request) {
|
func (s *Server) handleNIP11(w http.ResponseWriter, r *http.Request) {
|
||||||
w.Header().Set("Content-Type", "application/json")
|
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 {
|
if _, ok := s.relay.(Auther); ok {
|
||||||
supportedNIPs = append(supportedNIPs, 42)
|
supportedNIPs = append(supportedNIPs, 42)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,12 @@ func (ess *ElasticsearchStorage) Init() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ess *ElasticsearchStorage) DeleteEvent(id string, pubkey string) 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)
|
done := make(chan error)
|
||||||
err := ess.bi.Add(
|
err := ess.bi.Add(
|
||||||
@@ -132,9 +137,9 @@ func (ess *ElasticsearchStorage) DeleteEvent(id string, pubkey string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ess *ElasticsearchStorage) SaveEvent(event *nostr.Event) error {
|
func (ess *ElasticsearchStorage) SaveEvent(evt *nostr.Event) error {
|
||||||
ie := &IndexedEvent{
|
ie := &IndexedEvent{
|
||||||
Event: *event,
|
Event: *evt,
|
||||||
}
|
}
|
||||||
|
|
||||||
// post processing: index for FTS
|
// 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
|
// - if it's valid JSON just index the "values" and not the keys
|
||||||
// - more content introspection: language detection
|
// - more content introspection: language detection
|
||||||
// - denormalization... attach profile + ranking signals to events
|
// - denormalization... attach profile + ranking signals to events
|
||||||
if event.Kind != 4 {
|
if evt.Kind != 4 {
|
||||||
ie.ContentSearch = event.Content
|
ie.ContentSearch = evt.Content
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.Marshal(ie)
|
data, err := json.Marshal(ie)
|
||||||
@@ -155,13 +160,57 @@ func (ess *ElasticsearchStorage) SaveEvent(event *nostr.Event) error {
|
|||||||
|
|
||||||
done := make(chan 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:
|
// adapted from:
|
||||||
// https://github.com/elastic/go-elasticsearch/blob/main/_examples/bulk/indexer.go#L196
|
// https://github.com/elastic/go-elasticsearch/blob/main/_examples/bulk/indexer.go#L196
|
||||||
err = ess.bi.Add(
|
err = ess.bi.Add(
|
||||||
context.Background(),
|
context.Background(),
|
||||||
esutil.BulkIndexerItem{
|
esutil.BulkIndexerItem{
|
||||||
Action: "index",
|
Action: "index",
|
||||||
DocumentID: event.ID,
|
DocumentID: evt.ID,
|
||||||
Body: bytes.NewReader(data),
|
Body: bytes.NewReader(data),
|
||||||
OnSuccess: func(ctx context.Context, item esutil.BulkIndexerItem, res esutil.BulkIndexerResponseItem) {
|
OnSuccess: func(ctx context.Context, item esutil.BulkIndexerItem, res esutil.BulkIndexerResponseItem) {
|
||||||
close(done)
|
close(done)
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ func isGetByID(filter *nostr.Filter) bool {
|
|||||||
len(filter.Authors) == 0 &&
|
len(filter.Authors) == 0 &&
|
||||||
len(filter.Kinds) == 0 &&
|
len(filter.Kinds) == 0 &&
|
||||||
len(filter.Tags) == 0 &&
|
len(filter.Tags) == 0 &&
|
||||||
|
len(filter.Search) == 0 &&
|
||||||
filter.Since == nil &&
|
filter.Since == nil &&
|
||||||
filter.Until == 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
|
// delete past recommend_server events equal to this one
|
||||||
b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3`,
|
b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3`,
|
||||||
evt.PubKey, evt.Kind, evt.Content)
|
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
|
// insert
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package sqlite3
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/fiatjaf/relayer/storage"
|
"github.com/fiatjaf/relayer/storage"
|
||||||
"github.com/nbd-wtf/go-nostr"
|
"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
|
// delete past recommend_server events equal to this one
|
||||||
b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3`,
|
b.DB.Exec(`DELETE FROM event WHERE pubkey = $1 AND kind = $2 AND content = $3`,
|
||||||
evt.PubKey, evt.Kind, evt.Content)
|
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
|
// insert
|
||||||
|
|||||||
Reference in New Issue
Block a user