mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-06-27 17:23:07 +02:00
WithCheckDuplicateReplaceable() and helper functions for efficient replaceable event matching.
This commit is contained in:
parent
d2ceac48f6
commit
441f94563f
46
helpers.go
46
helpers.go
@ -154,3 +154,49 @@ func extractEventID(jsonStr string) string {
|
||||
// get 64 characters of the id
|
||||
return jsonStr[start : start+64]
|
||||
}
|
||||
|
||||
func extractDTag(jsonStr string) string {
|
||||
// look for ["d", pattern
|
||||
start := strings.Index(jsonStr, `["d"`)
|
||||
if start == -1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// move to the next quote
|
||||
offset := strings.IndexRune(jsonStr[start+4:], '"')
|
||||
start += 4 + offset + 1
|
||||
|
||||
// find the ending quote
|
||||
end := strings.IndexRune(jsonStr[start:], '"')
|
||||
if end == -1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
// get the contents
|
||||
return jsonStr[start : start+end]
|
||||
}
|
||||
|
||||
func extractTimestamp(jsonStr string) Timestamp {
|
||||
// look for "created_at": pattern
|
||||
start := strings.Index(jsonStr, `"created_at"`)
|
||||
if start == -1 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// move to the next number
|
||||
offset := strings.IndexAny(jsonStr[start+12:], "9876543210")
|
||||
if offset == -1 {
|
||||
return 0
|
||||
}
|
||||
start += 12 + offset
|
||||
|
||||
// find the end
|
||||
end := strings.IndexAny(jsonStr[start:], ",} ")
|
||||
if end == -1 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// get the contents
|
||||
ts, _ := strconv.ParseInt(jsonStr[start:start+end], 10, 64)
|
||||
return Timestamp(ts)
|
||||
}
|
||||
|
@ -43,4 +43,26 @@ func TestSubIdExtract(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestDTagExtract(t *testing.T) {
|
||||
{
|
||||
data := `["EVENT", "xxz" ,{"kind":30023,"id":"6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16","pubkey":"67ada8e344532cbf82f0e702472e24c7896e0e1c96235eacbaaa4b8616052171","created_at":1736909072,"tags":[["d", "balalaika"]["e","cfdf18b78527455097515545be4ccbe17e9b88f64539a566c632e405e2c0d08a","","root"],["e","f1ec9c301383be082f1860f7e24e49164d855bfab67f8e5c3ed17f6f3f867cca","","reply"],["p","1afe0c74e3d7784eba93a5e3fa554a6eeb01928d12739ae8ba4832786808e36d"],["p","8aa642e26e65072139e10db59646a89aa7538a59965aab3ed89191d71967d6c3"],["p","f4d89779148ccd245c8d50914a284fd62d97cb0fb68b797a70f24a172b522db9"],["p","18905d0a5d623ab81a98ba98c582bd5f57f2506c6b808905fc599d5a0b229b08"],["p","9a0e2043afaa056a12b8bbe77ac4c3185c0e2bc46b12aac158689144323c0e3c"],["p","45f195cffcb8c9724efc248f0507a2fb65b579dfabe7cd35398598163cab7627"]],"content":"🫡","sig":"d21aaf43963b07a3cb5f85ac8809c2b2e4dd3269195f4d810e1b7650895178fe01cf685ab3ee93f193cdde1f8d17419ff05332c6e3fc7429bbbe3d70016b8638"}]`
|
||||
require.Equal(t, "balalaika", extractDTag(data))
|
||||
}
|
||||
{
|
||||
data := `{"kind":1,"pubkey":"67ada8e344532cbf82f0e702472e24c7896e0e1c96235eacbaaa4b8616052171","created_at":1736909072,"tags":[["e","cfdf18b78527455097515545be4ccbe17e9b88f64539a566c632e405e2c0d08a","","root"],["e","f1ec9c301383be082f1860f7e24e49164d855bfab67f8e5c3ed17f6f3f867cca","","reply"],["p","1afe0c74e3d7784eba93a5e3fa554a6eeb01928d12739ae8ba4832786808e36d"],["p","8aa642e26e65072139e10db59646a89aa7538a59965aab3ed89191d71967d6c3"],["p","f4d89779148ccd245c8d50914a284fd62d97cb0fb68b797a70f24a172b522db9"],["p","18905d0a5d623ab81a98ba98c582bd5f57f2506c6b808905fc599d5a0b229b08"],["p","9a0e2043afaa056a12b8bbe77ac4c3185c0e2bc46b12aac158689144323c0e3c"],["p","45f195cffcb8c9724efc248f0507a2fb65b579dfabe7cd35398598163cab7627"]],"content":"🫡","sig":"d21aaf43963b07a3cb5f85ac8809c2b2e4dd3269195f4d810e1b7650895178fe01cf685ab3ee93f193cdde1f8d17419ff05332c6e3fc7429bbbe3d70016b8638","id": "6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16" }`
|
||||
require.Equal(t, "", extractDTag(data))
|
||||
}
|
||||
}
|
||||
|
||||
func TestTimestampExtract(t *testing.T) {
|
||||
{
|
||||
data := `["EVENT", "xxz" ,{"kind":30023,"id":"6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16","pubkey":"67ada8e344532cbf82f0e702472e24c7896e0e1c96235eacbaaa4b8616052171","created_at": 1736909072 ,"tags":[["d", "balalaika"]["e","cfdf18b78527455097515545be4ccbe17e9b88f64539a566c632e405e2c0d08a","","root"],["e","f1ec9c301383be082f1860f7e24e49164d855bfab67f8e5c3ed17f6f3f867cca","","reply"],["p","1afe0c74e3d7784eba93a5e3fa554a6eeb01928d12739ae8ba4832786808e36d"],["p","8aa642e26e65072139e10db59646a89aa7538a59965aab3ed89191d71967d6c3"],["p","f4d89779148ccd245c8d50914a284fd62d97cb0fb68b797a70f24a172b522db9"],["p","18905d0a5d623ab81a98ba98c582bd5f57f2506c6b808905fc599d5a0b229b08"],["p","9a0e2043afaa056a12b8bbe77ac4c3185c0e2bc46b12aac158689144323c0e3c"],["p","45f195cffcb8c9724efc248f0507a2fb65b579dfabe7cd35398598163cab7627"]],"content":"🫡","sig":"d21aaf43963b07a3cb5f85ac8809c2b2e4dd3269195f4d810e1b7650895178fe01cf685ab3ee93f193cdde1f8d17419ff05332c6e3fc7429bbbe3d70016b8638"}]`
|
||||
require.Equal(t, Timestamp(1736909072), extractTimestamp(data))
|
||||
}
|
||||
{
|
||||
data := `{"kind":1,"pubkey":"67ada8e344532cbf82f0e702472e24c7896e0e1c96235eacbaaa4b8616052171","tags":[["e","cfdf18b78527455097515545be4ccbe17e9b88f64539a566c632e405e2c0d08a","","root"],["e","f1ec9c301383be082f1860f7e24e49164d855bfab67f8e5c3ed17f6f3f867cca","","reply"],["p","1afe0c74e3d7784eba93a5e3fa554a6eeb01928d12739ae8ba4832786808e36d"],["p","8aa642e26e65072139e10db59646a89aa7538a59965aab3ed89191d71967d6c3"],["p","f4d89779148ccd245c8d50914a284fd62d97cb0fb68b797a70f24a172b522db9"],["p","18905d0a5d623ab81a98ba98c582bd5f57f2506c6b808905fc599d5a0b229b08"],["p","9a0e2043afaa056a12b8bbe77ac4c3185c0e2bc46b12aac158689144323c0e3c"],["p","45f195cffcb8c9724efc248f0507a2fb65b579dfabe7cd35398598163cab7627"]],"content":"🫡","sig":"d21aaf43963b07a3cb5f85ac8809c2b2e4dd3269195f4d810e1b7650895178fe01cf685ab3ee93f193cdde1f8d17419ff05332c6e3fc7429bbbe3d70016b8638","id": "6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16" ,"created_at":01736909054}`
|
||||
require.Equal(t, Timestamp(1736909054), extractTimestamp(data))
|
||||
}
|
||||
}
|
||||
|
||||
func ptr[S any](s S) *S { return &s }
|
||||
|
12
relay.go
12
relay.go
@ -231,9 +231,13 @@ func (r *Relay) ConnectWithTLS(ctx context.Context, tlsConfig *tls.Config) error
|
||||
// if this is an "EVENT" we will have this preparser logic that should speed things up a little
|
||||
// as we skip handling duplicate events
|
||||
subid := extractSubID(message)
|
||||
subscription, ok := r.Subscriptions.Load(subIdToSerial(subid))
|
||||
if ok && subscription.checkDuplicate != nil {
|
||||
if subscription.checkDuplicate(extractEventID(message[10+len(subid):]), r.URL) {
|
||||
sub, ok := r.Subscriptions.Load(subIdToSerial(subid))
|
||||
if ok && sub.checkDuplicate != nil {
|
||||
if sub.checkDuplicate(extractEventID(message[10+len(subid):]), r.URL) {
|
||||
continue
|
||||
}
|
||||
} else if sub.checkDuplicateReplaceable != nil {
|
||||
if sub.checkDuplicateReplaceable(extractDTag(message), extractTimestamp(message)) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -437,6 +441,8 @@ func (r *Relay) PrepareSubscription(ctx context.Context, filters Filters, opts .
|
||||
label = string(o)
|
||||
case WithCheckDuplicate:
|
||||
sub.checkDuplicate = o
|
||||
case WithCheckDuplicateReplaceable:
|
||||
sub.checkDuplicateReplaceable = o
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,10 +33,14 @@ type Subscription struct {
|
||||
// Context will be .Done() when the subscription ends
|
||||
Context context.Context
|
||||
|
||||
// if it is not nil, CheckDuplicate will be called for every event received
|
||||
// if it is not nil, checkDuplicate will be called for every event received
|
||||
// if it returns true that event will not be processed further.
|
||||
checkDuplicate func(id string, relay string) bool
|
||||
|
||||
// if it is not nil, checkDuplicateReplaceable will be called for every event received
|
||||
// if it returns true that event will not be processed further.
|
||||
checkDuplicateReplaceable func(d string, ts Timestamp) bool
|
||||
|
||||
match func(*Event) bool // this will be either Filters.Match or Filters.MatchIgnoringTimestampConstraints
|
||||
live atomic.Bool
|
||||
eosed atomic.Bool
|
||||
@ -63,9 +67,15 @@ type WithCheckDuplicate func(id, relay string) bool
|
||||
|
||||
func (_ WithCheckDuplicate) IsSubscriptionOption() {}
|
||||
|
||||
// WithCheckDuplicateReplaceable sets checkDuplicateReplaceable on the subscription
|
||||
type WithCheckDuplicateReplaceable func(d string, ts Timestamp) bool
|
||||
|
||||
func (_ WithCheckDuplicateReplaceable) IsSubscriptionOption() {}
|
||||
|
||||
var (
|
||||
_ SubscriptionOption = (WithLabel)("")
|
||||
_ SubscriptionOption = (WithCheckDuplicate)(nil)
|
||||
_ SubscriptionOption = (WithCheckDuplicateReplaceable)(nil)
|
||||
)
|
||||
|
||||
func (sub *Subscription) start() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user