mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-03-17 13:22:56 +01:00
breaking pointer mess
- ExternalPointer (?) - nip27, nip22 and nip10 functions to return pointers - get rid of sdk/thread helpers that were just a thin layer over nip10 and nip22
This commit is contained in:
parent
f575f63f6c
commit
7e04bbb4b8
@ -36,11 +36,12 @@ func GetImmediateParent(tags nostr.Tags) *nostr.EventPointer {
|
|||||||
|
|
||||||
if len(tag) >= 4 {
|
if len(tag) >= 4 {
|
||||||
if tag[3] == "reply" {
|
if tag[3] == "reply" {
|
||||||
return &tag
|
parent = tag
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if tag[3] == "root" {
|
if tag[3] == "parent" {
|
||||||
// will be used as our first fallback
|
// will be used as our first fallback
|
||||||
root = &tag
|
parent = tag
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if tag[3] == "mention" {
|
if tag[3] == "mention" {
|
||||||
@ -49,15 +50,23 @@ func GetImmediateParent(tags nostr.Tags) *nostr.EventPointer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lastE = &tag // will be used as our second fallback (clients that don't add markers)
|
lastE = tag // will be used as our second fallback (clients that don't add markers)
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we reached this point we don't have a "reply", but if we have a "root"
|
// if we reached this point we don't have a "reply", but if we have a "parent"
|
||||||
// that means this event is a direct reply to the root
|
// that means this event is a direct reply to the parent
|
||||||
if root != nil {
|
if parent != nil {
|
||||||
return root
|
p, _ := nostr.EventPointerFromTag(parent)
|
||||||
|
return &p
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we reached this point and we have at least one "e" we'll use that (the last)
|
if lastE != nil {
|
||||||
return lastE
|
// if we reached this point and we have at least one "e" we'll use that (the last)
|
||||||
|
// (we don't bother looking for relay or author hints because these clients don't add these anyway)
|
||||||
|
return &nostr.EventPointer{
|
||||||
|
ID: lastE[1],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -9,8 +9,13 @@ import (
|
|||||||
func EncodePointer(pointer nostr.Pointer) string {
|
func EncodePointer(pointer nostr.Pointer) string {
|
||||||
switch v := pointer.(type) {
|
switch v := pointer.(type) {
|
||||||
case nostr.ProfilePointer:
|
case nostr.ProfilePointer:
|
||||||
res, _ := EncodeProfile(v.PublicKey, v.Relays)
|
if v.Relays == nil {
|
||||||
return res
|
res, _ := EncodePublicKey(v.PublicKey)
|
||||||
|
return res
|
||||||
|
} else {
|
||||||
|
res, _ := EncodeProfile(v.PublicKey, v.Relays)
|
||||||
|
return res
|
||||||
|
}
|
||||||
case nostr.EventPointer:
|
case nostr.EventPointer:
|
||||||
res, _ := EncodeEvent(v.ID, v.Relays, v.Author)
|
res, _ := EncodeEvent(v.ID, v.Relays, v.Author)
|
||||||
return res
|
return res
|
||||||
|
@ -2,25 +2,41 @@ package nip22
|
|||||||
|
|
||||||
import "github.com/nbd-wtf/go-nostr"
|
import "github.com/nbd-wtf/go-nostr"
|
||||||
|
|
||||||
func GetThreadRoot(tags nostr.Tags) *nostr.Tag {
|
func GetThreadRoot(tags nostr.Tags) nostr.Pointer {
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
if len(tag) < 2 {
|
if len(tag) < 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if tag[0] == "E" || tag[0] == "A" || tag[0] == "I" {
|
switch tag[0] {
|
||||||
return &tag
|
case "E":
|
||||||
|
ep, _ := nostr.EventPointerFromTag(tag)
|
||||||
|
return ep
|
||||||
|
case "A":
|
||||||
|
ep, _ := nostr.EntityPointerFromTag(tag)
|
||||||
|
return ep
|
||||||
|
case "I":
|
||||||
|
ep, _ := nostr.ExternalPointerFromTag(tag)
|
||||||
|
return ep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetImmediateReply(tags nostr.Tags) *nostr.Tag {
|
func GetImmediateParent(tags nostr.Tags) nostr.Pointer {
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
if len(tag) < 2 {
|
if len(tag) < 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if tag[0] == "e" || tag[0] == "a" || tag[0] == "i" {
|
switch tag[0] {
|
||||||
return &tag
|
case "e":
|
||||||
|
ep, _ := nostr.EventPointerFromTag(tag)
|
||||||
|
return ep
|
||||||
|
case "a":
|
||||||
|
ep, _ := nostr.EntityPointerFromTag(tag)
|
||||||
|
return ep
|
||||||
|
case "i":
|
||||||
|
ep, _ := nostr.ExternalPointerFromTag(tag)
|
||||||
|
return ep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -12,9 +12,7 @@ type Reference struct {
|
|||||||
Text string
|
Text string
|
||||||
Start int
|
Start int
|
||||||
End int
|
End int
|
||||||
Profile *nostr.ProfilePointer
|
Pointer nostr.Pointer
|
||||||
Event *nostr.EventPointer
|
|
||||||
Entity *nostr.EntityPointer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var mentionRegex = regexp.MustCompile(`\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b`)
|
var mentionRegex = regexp.MustCompile(`\bnostr:((note|npub|naddr|nevent|nprofile)1\w+)\b`)
|
||||||
@ -33,40 +31,45 @@ func ParseReferences(evt nostr.Event) iter.Seq[Reference] {
|
|||||||
if prefix, data, err := nip19.Decode(nip19code); err == nil {
|
if prefix, data, err := nip19.Decode(nip19code); err == nil {
|
||||||
switch prefix {
|
switch prefix {
|
||||||
case "npub":
|
case "npub":
|
||||||
reference.Profile = &nostr.ProfilePointer{
|
pointer := &nostr.ProfilePointer{
|
||||||
PublicKey: data.(string), Relays: []string{},
|
PublicKey: data.(string), Relays: []string{},
|
||||||
}
|
}
|
||||||
tag := evt.Tags.GetFirst([]string{"p", reference.Profile.PublicKey})
|
tag := evt.Tags.FindWithValue("p", pointer.PublicKey)
|
||||||
if tag != nil && len(*tag) >= 3 {
|
if tag != nil && len(tag) >= 3 {
|
||||||
reference.Profile.Relays = []string{(*tag)[2]}
|
pointer.Relays = []string{tag[2]}
|
||||||
|
}
|
||||||
|
if nostr.IsValidPublicKey(pointer.PublicKey) {
|
||||||
|
reference.Pointer = pointer
|
||||||
}
|
}
|
||||||
case "nprofile":
|
case "nprofile":
|
||||||
pp := data.(nostr.ProfilePointer)
|
pointer := data.(nostr.ProfilePointer)
|
||||||
reference.Profile = &pp
|
tag := evt.Tags.FindWithValue("p", pointer.PublicKey)
|
||||||
tag := evt.Tags.GetFirst([]string{"p", reference.Profile.PublicKey})
|
if tag != nil && len(tag) >= 3 {
|
||||||
if tag != nil && len(*tag) >= 3 {
|
pointer.Relays = append(pointer.Relays, tag[2])
|
||||||
reference.Profile.Relays = append(reference.Profile.Relays, (*tag)[2])
|
}
|
||||||
|
if nostr.IsValidPublicKey(pointer.PublicKey) {
|
||||||
|
reference.Pointer = pointer
|
||||||
}
|
}
|
||||||
case "note":
|
case "note":
|
||||||
// we don't even bother here because people using note1 codes aren't including relay hints anyway
|
// we don't even bother here because people using note1 codes aren't including relay hints anyway
|
||||||
reference.Event = &nostr.EventPointer{ID: data.(string), Relays: []string{}}
|
reference.Pointer = &nostr.EventPointer{ID: data.(string), Relays: nil}
|
||||||
case "nevent":
|
case "nevent":
|
||||||
evp := data.(nostr.EventPointer)
|
pointer := data.(nostr.EventPointer)
|
||||||
reference.Event = &evp
|
tag := evt.Tags.FindWithValue("e", pointer.ID)
|
||||||
tag := evt.Tags.GetFirst([]string{"e", reference.Event.ID})
|
if tag != nil && len(tag) >= 3 {
|
||||||
if tag != nil && len(*tag) >= 3 {
|
pointer.Relays = append(pointer.Relays, tag[2])
|
||||||
reference.Event.Relays = append(reference.Event.Relays, (*tag)[2])
|
if pointer.Author == "" && len(tag) >= 5 && nostr.IsValidPublicKey(tag[4]) {
|
||||||
if reference.Event.Author == "" && len(*tag) >= 5 {
|
pointer.Author = tag[4]
|
||||||
reference.Event.Author = (*tag)[4]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
reference.Pointer = pointer
|
||||||
case "naddr":
|
case "naddr":
|
||||||
addr := data.(nostr.EntityPointer)
|
pointer := data.(nostr.EntityPointer)
|
||||||
reference.Entity = &addr
|
tag := evt.Tags.FindWithValue("a", pointer.AsTagReference())
|
||||||
tag := evt.Tags.GetFirst([]string{"a", reference.Entity.AsTagReference()})
|
if tag != nil && len(tag) >= 3 {
|
||||||
if tag != nil && len(*tag) >= 3 {
|
pointer.Relays = append(pointer.Relays, tag[2])
|
||||||
reference.Entity.Relays = append(reference.Entity.Relays, (*tag)[2])
|
|
||||||
}
|
}
|
||||||
|
reference.Pointer = pointer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ func TestParseReferences(t *testing.T) {
|
|||||||
Text: "nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg",
|
Text: "nostr:nprofile1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8yc5usxdg",
|
||||||
Start: 7,
|
Start: 7,
|
||||||
End: 83,
|
End: 83,
|
||||||
Profile: &nostr.ProfilePointer{
|
Pointer: nostr.ProfilePointer{
|
||||||
PublicKey: "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393",
|
PublicKey: "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393",
|
||||||
Relays: []string{"wss://xawr.com"},
|
Relays: []string{"wss://xawr.com"},
|
||||||
},
|
},
|
||||||
@ -32,7 +32,7 @@ func TestParseReferences(t *testing.T) {
|
|||||||
Text: "nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4",
|
Text: "nostr:nevent1qqsvc6ulagpn7kwrcwdqgp797xl7usumqa6s3kgcelwq6m75x8fe8ychxp5v4",
|
||||||
Start: 90,
|
Start: 90,
|
||||||
End: 164,
|
End: 164,
|
||||||
Event: &nostr.EventPointer{
|
Pointer: nostr.EventPointer{
|
||||||
ID: "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393",
|
ID: "cc6b9fea033f59c3c39a0407c5f1bfee439b077508d918cfdc0d6fd431d39393",
|
||||||
Relays: []string{"wss://nasdj.com"},
|
Relays: []string{"wss://nasdj.com"},
|
||||||
Author: "",
|
Author: "",
|
||||||
|
27
pointers.go
27
pointers.go
@ -26,6 +26,7 @@ var (
|
|||||||
_ Pointer = (*ProfilePointer)(nil)
|
_ Pointer = (*ProfilePointer)(nil)
|
||||||
_ Pointer = (*EventPointer)(nil)
|
_ Pointer = (*EventPointer)(nil)
|
||||||
_ Pointer = (*EntityPointer)(nil)
|
_ Pointer = (*EntityPointer)(nil)
|
||||||
|
_ Pointer = (*ExternalPointer)(nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProfilePointer represents a pointer to a Nostr profile.
|
// ProfilePointer represents a pointer to a Nostr profile.
|
||||||
@ -36,7 +37,7 @@ type ProfilePointer struct {
|
|||||||
|
|
||||||
// ProfilePointerFromTag creates a ProfilePointer from a "p" tag (but it doesn't have to be necessarily a "p" tag, could be something else).
|
// ProfilePointerFromTag creates a ProfilePointer from a "p" tag (but it doesn't have to be necessarily a "p" tag, could be something else).
|
||||||
func ProfilePointerFromTag(refTag Tag) (ProfilePointer, error) {
|
func ProfilePointerFromTag(refTag Tag) (ProfilePointer, error) {
|
||||||
pk := (refTag)[1]
|
pk := refTag[1]
|
||||||
if !IsValidPublicKey(pk) {
|
if !IsValidPublicKey(pk) {
|
||||||
return ProfilePointer{}, fmt.Errorf("invalid pubkey '%s'", pk)
|
return ProfilePointer{}, fmt.Errorf("invalid pubkey '%s'", pk)
|
||||||
}
|
}
|
||||||
@ -74,7 +75,7 @@ type EventPointer struct {
|
|||||||
|
|
||||||
// EventPointerFromTag creates an EventPointer from an "e" tag (but it could be other tag name, it isn't checked).
|
// EventPointerFromTag creates an EventPointer from an "e" tag (but it could be other tag name, it isn't checked).
|
||||||
func EventPointerFromTag(refTag Tag) (EventPointer, error) {
|
func EventPointerFromTag(refTag Tag) (EventPointer, error) {
|
||||||
id := (refTag)[1]
|
id := refTag[1]
|
||||||
if !IsValid32ByteHex(id) {
|
if !IsValid32ByteHex(id) {
|
||||||
return EventPointer{}, fmt.Errorf("invalid id '%s'", id)
|
return EventPointer{}, fmt.Errorf("invalid id '%s'", id)
|
||||||
}
|
}
|
||||||
@ -86,8 +87,10 @@ func EventPointerFromTag(refTag Tag) (EventPointer, error) {
|
|||||||
if relay := (refTag)[2]; IsValidRelayURL(relay) {
|
if relay := (refTag)[2]; IsValidRelayURL(relay) {
|
||||||
pointer.Relays = []string{relay}
|
pointer.Relays = []string{relay}
|
||||||
}
|
}
|
||||||
if len(refTag) > 3 && IsValidPublicKey((refTag)[3]) {
|
if len(refTag) > 3 && IsValidPublicKey(refTag[3]) {
|
||||||
pointer.Author = (refTag)[3]
|
pointer.Author = (refTag)[3]
|
||||||
|
} else if len(refTag) > 4 && IsValidPublicKey(refTag[4]) {
|
||||||
|
pointer.Author = (refTag)[4]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return pointer, nil
|
return pointer, nil
|
||||||
@ -171,3 +174,21 @@ func (ep EntityPointer) AsTag() Tag {
|
|||||||
}
|
}
|
||||||
return Tag{"a", ep.AsTagReference()}
|
return Tag{"a", ep.AsTagReference()}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExternalPointer represents a pointer to a Nostr profile.
|
||||||
|
type ExternalPointer struct {
|
||||||
|
Thing string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExternalPointerFromTag creates a ExternalPointer from an "i" tag
|
||||||
|
func ExternalPointerFromTag(refTag Tag) (ExternalPointer, error) {
|
||||||
|
return ExternalPointer{refTag[1]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ep ExternalPointer) MatchesEvent(_ Event) bool { return false }
|
||||||
|
func (ep ExternalPointer) AsTagReference() string { return ep.Thing }
|
||||||
|
func (ep ExternalPointer) AsFilter() Filter { return Filter{} }
|
||||||
|
|
||||||
|
func (ep ExternalPointer) AsTag() Tag {
|
||||||
|
return Tag{"i", ep.Thing}
|
||||||
|
}
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
package sdk
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nbd-wtf/go-nostr"
|
|
||||||
"github.com/nbd-wtf/go-nostr/nip10"
|
|
||||||
"github.com/nbd-wtf/go-nostr/nip22"
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetThreadRoot(evt *nostr.Event) *nostr.Tag {
|
|
||||||
if evt.Kind == nostr.KindComment {
|
|
||||||
return nip22.GetThreadRoot(evt.Tags)
|
|
||||||
} else {
|
|
||||||
return nip10.GetThreadRoot(evt.Tags)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetImmediateReply(evt *nostr.Event) *nostr.Tag {
|
|
||||||
if evt.Kind == nostr.KindComment {
|
|
||||||
return nip22.GetImmediateReply(evt.Tags)
|
|
||||||
} else {
|
|
||||||
return nip10.GetImmediateReply(evt.Tags)
|
|
||||||
}
|
|
||||||
}
|
|
@ -106,27 +106,36 @@ func (sys *System) trackEventHints(ie nostr.RelayEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for ref := range nip27.ParseReferences(*ie.Event) {
|
for ref := range nip27.ParseReferences(*ie.Event) {
|
||||||
if ref.Profile != nil {
|
switch pointer := ref.Pointer.(type) {
|
||||||
for _, relay := range ref.Profile.Relays {
|
case nostr.ProfilePointer:
|
||||||
|
for _, relay := range pointer.Relays {
|
||||||
if IsVirtualRelay(relay) {
|
if IsVirtualRelay(relay) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if p, err := url.Parse(relay); err != nil || (p.Scheme != "wss" && p.Scheme != "ws") {
|
if p, err := url.Parse(relay); err != nil || (p.Scheme != "wss" && p.Scheme != "ws") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if nostr.IsValidPublicKey(ref.Profile.PublicKey) {
|
sys.Hints.Save(pointer.PublicKey, nostr.NormalizeURL(relay), hints.LastInHint, ie.CreatedAt)
|
||||||
sys.Hints.Save(ref.Profile.PublicKey, nostr.NormalizeURL(relay), hints.LastInHint, ie.CreatedAt)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if ref.Event != nil && nostr.IsValidPublicKey(ref.Event.Author) {
|
case nostr.EventPointer:
|
||||||
for _, relay := range ref.Event.Relays {
|
for _, relay := range pointer.Relays {
|
||||||
if IsVirtualRelay(relay) {
|
if IsVirtualRelay(relay) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if p, err := url.Parse(relay); err != nil || (p.Scheme != "wss" && p.Scheme != "ws") {
|
if p, err := url.Parse(relay); err != nil || (p.Scheme != "wss" && p.Scheme != "ws") {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
sys.Hints.Save(ref.Event.Author, nostr.NormalizeURL(relay), hints.LastInHint, ie.CreatedAt)
|
sys.Hints.Save(pointer.Author, nostr.NormalizeURL(relay), hints.LastInHint, ie.CreatedAt)
|
||||||
|
}
|
||||||
|
case nostr.EntityPointer:
|
||||||
|
for _, relay := range pointer.Relays {
|
||||||
|
if IsVirtualRelay(relay) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if p, err := url.Parse(relay); err != nil || (p.Scheme != "wss" && p.Scheme != "ws") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
sys.Hints.Save(pointer.PublicKey, nostr.NormalizeURL(relay), hints.LastInHint, ie.CreatedAt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user