From a52165fb7d4c1b5530b6de7cef33ae8fa695e570 Mon Sep 17 00:00:00 2001 From: fiatjaf Date: Mon, 10 Mar 2025 02:33:29 -0300 Subject: [PATCH] deprecate all useless tag methods, implement Find() and friends. --- event.go | 18 +++++++- nip10/nip10.go | 25 ++++++----- nip13/nip13.go | 4 +- nip45/hll_event.go | 4 +- tag_test.go | 12 +----- tags.go | 102 ++++++++++++++++++++++++--------------------- 6 files changed, 90 insertions(+), 75 deletions(-) diff --git a/event.go b/event.go index 7303bf6..6d3ebb4 100644 --- a/event.go +++ b/event.go @@ -69,8 +69,22 @@ func (evt *Event) Serialize() []byte { dst = append(dst, ',') // tags - dst = evt.Tags.marshalTo(dst) - dst = append(dst, ',') + dst = append(dst, '[') + for i, tag := range evt.Tags { + if i > 0 { + dst = append(dst, ',') + } + // tag item + dst = append(dst, '[') + for i, s := range tag { + if i > 0 { + dst = append(dst, ',') + } + dst = escapeString(dst, s) + } + dst = append(dst, ']') + } + dst = append(dst, "],"...) // content needs to be escaped in general as it is user generated. dst = escapeString(dst, evt.Content) diff --git a/nip10/nip10.go b/nip10/nip10.go index 174e7bb..d27ef02 100644 --- a/nip10/nip10.go +++ b/nip10/nip10.go @@ -2,24 +2,27 @@ package nip10 import "github.com/nbd-wtf/go-nostr" -func GetThreadRoot(tags nostr.Tags) *nostr.Tag { +func GetThreadRoot(tags nostr.Tags) *nostr.EventPointer { for _, tag := range tags { if len(tag) >= 4 && tag[0] == "e" && tag[3] == "root" { - return &tag + p, _ := nostr.EventPointerFromTag(tag) + return &p } } - return tags.GetFirst([]string{"e", ""}) + firstE := tags.Find("e") + if firstE != nil { + return &nostr.EventPointer{ + ID: firstE[1], + } + } + + return nil } -// Deprecated: this was misnamed, use GetImmediateParent instead. -func GetImmediateReply(tags nostr.Tags) *nostr.Tag { - return GetImmediateParent(tags) -} - -func GetImmediateParent(tags nostr.Tags) *nostr.Tag { - var root *nostr.Tag - var lastE *nostr.Tag +func GetImmediateParent(tags nostr.Tags) *nostr.EventPointer { + var parent nostr.Tag + var lastE nostr.Tag for i := 0; i <= len(tags)-1; i++ { tag := tags[i] diff --git a/nip13/nip13.go b/nip13/nip13.go index 6cd68b3..71fd5a3 100644 --- a/nip13/nip13.go +++ b/nip13/nip13.go @@ -24,9 +24,9 @@ var ( // if the target is bigger than the actual difficulty then it returns 0. func CommittedDifficulty(event *nostr.Event) int { work := 0 - if nonceTag := event.Tags.GetFirst([]string{"nonce", ""}); nonceTag != nil && len(*nonceTag) >= 3 { + if nonceTag := event.Tags.Find("nonce"); nonceTag != nil && len(nonceTag) >= 3 { work = Difficulty(event.ID) - target, _ := strconv.Atoi((*nonceTag)[2]) + target, _ := strconv.Atoi(nonceTag[2]) if target <= work { work = target } else { diff --git a/nip45/hll_event.go b/nip45/hll_event.go index dc4d01f..ad76565 100644 --- a/nip45/hll_event.go +++ b/nip45/hll_event.go @@ -26,9 +26,9 @@ func HyperLogLogEventPubkeyOffsetsAndReferencesForEvent(evt *nostr.Event) iter.S // // reaction counts: // (only the last "e" tag counts) - lastE := evt.Tags.GetLast([]string{"e", ""}) + lastE := evt.Tags.FindLast("e") if lastE != nil { - v := (*lastE)[1] + v := lastE[1] if nostr.IsValid32ByteHex(v) { // 32th nibble of "e" tag p, _ := strconv.ParseInt(v[32:33], 16, 64) diff --git a/tag_test.go b/tag_test.go index 8edff85..846e58f 100644 --- a/tag_test.go +++ b/tag_test.go @@ -19,20 +19,10 @@ func TestTagHelpers(t *testing.T) { assert.Nil(t, tags.GetFirst([]string{"x", ""}), "got with wrong prefix") assert.NotNil(t, tags.GetFirst([]string{"p", "abcdef", "wss://"}), "failed to get with existing prefix") assert.NotNil(t, tags.GetFirst([]string{"p", "abcdef", ""}), "failed to get with existing prefix (blank last string)") - assert.Equal(t, "ffffff", (*(tags.GetLast([]string{"e"})))[1], "failed to get last") + assert.Equal(t, "ffffff", tags.FindLast("e")[1], "failed to get last") assert.Equal(t, 2, len(tags.GetAll([]string{"e", ""})), "failed to get all") c := make(Tags, 0, 2) for _, tag := range tags.All([]string{"e", ""}) { c = append(c, tag) } - assert.Equal(t, tags.GetAll([]string{"e", ""}), c) - assert.Equal(t, 5, len(tags.AppendUnique(Tag{"e", "ffffff"})), "append unique changed the array size when existed") - assert.Equal(t, 6, len(tags.AppendUnique(Tag{"e", "bbbbbb"})), "append unique failed to append when didn't exist") - assert.Equal(t, "ffffff", tags.AppendUnique(Tag{"e", "eeeeee"})[4][1], "append unique changed the order") - assert.Equal(t, "eeeeee", tags.AppendUnique(Tag{"e", "eeeeee"})[3][1], "append unique changed the order") - - filtered := tags.FilterOut([]string{"e"}) - tags.FilterOutInPlace([]string{"e"}) - assert.ElementsMatch(t, filtered, tags) - assert.Len(t, filtered, 3) } diff --git a/tags.go b/tags.go index 507ce82..0ca0fa5 100644 --- a/tags.go +++ b/tags.go @@ -9,18 +9,8 @@ import ( type Tag []string -// StartsWith checks if a tag contains a prefix. -// for example, -// -// ["p", "abcdef...", "wss://relay.com"] -// -// would match against -// -// ["p", "abcdef..."] -// -// or even -// -// ["p", "abcdef...", "wss://"] +// Deprecated: this is too cumbersome for no reason when what we actually want is +// the simpler logic present in Find and FindWithValue. func (tag Tag) StartsWith(prefix []string) bool { prefixLen := len(prefix) @@ -37,6 +27,7 @@ func (tag Tag) StartsWith(prefix []string) bool { return strings.HasPrefix(tag[prefixLen-1], prefix[prefixLen-1]) } +// Deprecated: write these inline instead func (tag Tag) Key() string { if len(tag) > 0 { return tag[0] @@ -44,6 +35,7 @@ func (tag Tag) Key() string { return "" } +// Deprecated: write these inline instead func (tag Tag) Value() string { if len(tag) > 1 { return tag[1] @@ -51,6 +43,7 @@ func (tag Tag) Value() string { return "" } +// Deprecated: write these inline instead func (tag Tag) Relay() string { if len(tag) > 2 && (tag[0] == "e" || tag[0] == "p") { return NormalizeURL(tag[2]) @@ -70,7 +63,7 @@ func (tags Tags) GetD() string { return "" } -// GetFirst gets the first tag in tags that matches the prefix, see [Tag.StartsWith] +// Deprecated: use Find or FindWithValue instead func (tags Tags) GetFirst(tagPrefix []string) *Tag { for _, v := range tags { if v.StartsWith(tagPrefix) { @@ -80,7 +73,7 @@ func (tags Tags) GetFirst(tagPrefix []string) *Tag { return nil } -// GetLast gets the last tag in tags that matches the prefix, see [Tag.StartsWith] +// Deprecated: use FindLast or FindLastWithValue instead func (tags Tags) GetLast(tagPrefix []string) *Tag { for i := len(tags) - 1; i >= 0; i-- { v := tags[i] @@ -91,7 +84,7 @@ func (tags Tags) GetLast(tagPrefix []string) *Tag { return nil } -// GetAll gets all the tags that match the prefix, see [Tag.StartsWith] +// Deprecated: use FindAll instead func (tags Tags) GetAll(tagPrefix []string) Tags { result := make(Tags, 0, len(tags)) for _, v := range tags { @@ -102,7 +95,7 @@ func (tags Tags) GetAll(tagPrefix []string) Tags { return result } -// All returns an iterator for all the tags that match the prefix, see [Tag.StartsWith] +// Deprecated: use FindAll instead func (tags Tags) All(tagPrefix []string) iter.Seq2[int, Tag] { return func(yield func(int, Tag) bool) { for i, v := range tags { @@ -115,7 +108,7 @@ func (tags Tags) All(tagPrefix []string) iter.Seq2[int, Tag] { } } -// FilterOut returns a new slice with only the elements that match the prefix, see [Tag.StartsWith] +// Deprecated: this is useless, write your own func (tags Tags) FilterOut(tagPrefix []string) Tags { filtered := make(Tags, 0, len(tags)) for _, v := range tags { @@ -126,7 +119,7 @@ func (tags Tags) FilterOut(tagPrefix []string) Tags { return filtered } -// FilterOutInPlace removes all tags that match the prefix, but potentially reorders the tags in unpredictable ways, see [Tag.StartsWith] +// Deprecated: this is useless, write your own func (tags *Tags) FilterOutInPlace(tagPrefix []string) { for i := 0; i < len(*tags); i++ { tag := (*tags)[i] @@ -140,8 +133,7 @@ func (tags *Tags) FilterOutInPlace(tagPrefix []string) { } } -// AppendUnique appends a tag if it doesn't exist yet, otherwise does nothing. -// the uniqueness comparison is done based only on the first 2 elements of the tag. +// Deprecated: write your own instead with Find() and append() func (tags Tags) AppendUnique(tag Tag) Tags { n := len(tag) if n > 2 { @@ -154,6 +146,49 @@ func (tags Tags) AppendUnique(tag Tag) Tags { return tags } +// Find returns the first tag with the given key/tagName that also has one value (i.e. at least 2 items) +func (tags Tags) Find(key string) Tag { + for _, v := range tags { + if len(v) >= 2 && v[0] == key { + return v + } + } + return nil +} + +// FindWithValue is like Find, but also checks if the value (the second item) matches +func (tags Tags) FindWithValue(key, value string) Tag { + for _, v := range tags { + if len(v) >= 2 && v[1] == value && v[0] == key { + return v + } + } + return nil +} + +// FindLast is like Find, but starts at the end +func (tags Tags) FindLast(key string) Tag { + for i := len(tags) - 1; i >= 0; i-- { + v := tags[i] + if len(v) >= 2 && v[0] == key { + return v + } + } + return nil +} + +// FindLastWithValue is like FindLast, but starts at the end +func (tags Tags) FindLastWithValue(key, value string) Tag { + for i := len(tags) - 1; i >= 0; i-- { + v := tags[i] + if len(v) >= 2 && v[1] == value && v[0] == key { + return v + } + } + return nil +} + +// this exists to satisfy Postgres and stuff and should probably be removed in the future since it's too specific func (t *Tags) Scan(src any) error { var jtags []byte @@ -187,30 +222,3 @@ func (tags Tags) ContainsAny(tagName string, values []string) bool { return false } - -// Marshal Tag. Used for Serialization so string escaping should be as in RFC8259. -func (tag Tag) marshalTo(dst []byte) []byte { - dst = append(dst, '[') - for i, s := range tag { - if i > 0 { - dst = append(dst, ',') - } - dst = escapeString(dst, s) - } - dst = append(dst, ']') - return dst -} - -// MarshalTo appends the JSON encoded byte of Tags as [][]string to dst. -// String escaping is as described in RFC8259. -func (tags Tags) marshalTo(dst []byte) []byte { - dst = append(dst, '[') - for i, tag := range tags { - if i > 0 { - dst = append(dst, ',') - } - dst = tag.marshalTo(dst) - } - dst = append(dst, ']') - return dst -}