go-nostr/pointers.go
2025-02-16 11:53:26 -03:00

156 lines
3.7 KiB
Go

package nostr
import (
"fmt"
"strconv"
"strings"
)
type Pointer interface {
AsTagReference() string
AsTag() Tag
AsFilter() Filter
MatchesEvent(Event) bool
}
var (
_ Pointer = (*ProfilePointer)(nil)
_ Pointer = (*EventPointer)(nil)
_ Pointer = (*EntityPointer)(nil)
)
type ProfilePointer struct {
PublicKey string `json:"pubkey"`
Relays []string `json:"relays,omitempty"`
}
func ProfilePointerFromTag(refTag Tag) (ProfilePointer, error) {
pk := (refTag)[1]
if !IsValidPublicKey(pk) {
return ProfilePointer{}, fmt.Errorf("invalid pubkey '%s'", pk)
}
pointer := ProfilePointer{
PublicKey: pk,
}
if len(refTag) > 2 {
if relay := (refTag)[2]; IsValidRelayURL(relay) {
pointer.Relays = []string{relay}
}
}
return pointer, nil
}
func (ep ProfilePointer) MatchesEvent(_ Event) bool { return false }
func (ep ProfilePointer) AsTagReference() string { return ep.PublicKey }
func (ep ProfilePointer) AsFilter() Filter { return Filter{Authors: []string{ep.PublicKey}} }
func (ep ProfilePointer) AsTag() Tag {
if len(ep.Relays) > 0 {
return Tag{"p", ep.PublicKey, ep.Relays[0]}
}
return Tag{"p", ep.PublicKey}
}
type EventPointer struct {
ID string `json:"id"`
Relays []string `json:"relays,omitempty"`
Author string `json:"author,omitempty"`
Kind int `json:"kind,omitempty"`
}
func EventPointerFromTag(refTag Tag) (EventPointer, error) {
id := (refTag)[1]
if !IsValid32ByteHex(id) {
return EventPointer{}, fmt.Errorf("invalid id '%s'", id)
}
pointer := EventPointer{
ID: id,
}
if len(refTag) > 2 {
if relay := (refTag)[2]; IsValidRelayURL(relay) {
pointer.Relays = []string{relay}
}
if len(refTag) > 3 && IsValidPublicKey((refTag)[3]) {
pointer.Author = (refTag)[3]
}
}
return pointer, nil
}
func (ep EventPointer) MatchesEvent(evt Event) bool { return evt.ID == ep.ID }
func (ep EventPointer) AsTagReference() string { return ep.ID }
func (ep EventPointer) AsFilter() Filter { return Filter{IDs: []string{ep.ID}} }
func (ep EventPointer) AsTag() Tag {
if len(ep.Relays) > 0 {
if ep.Author != "" {
return Tag{"e", ep.ID, ep.Relays[0], ep.Author}
} else {
return Tag{"e", ep.ID, ep.Relays[0]}
}
}
return Tag{"e", ep.ID}
}
type EntityPointer struct {
PublicKey string `json:"pubkey"`
Kind int `json:"kind,omitempty"`
Identifier string `json:"identifier,omitempty"`
Relays []string `json:"relays,omitempty"`
}
func EntityPointerFromTag(refTag Tag) (EntityPointer, error) {
spl := strings.SplitN(refTag[1], ":", 3)
if len(spl) != 3 {
return EntityPointer{}, fmt.Errorf("invalid addr ref '%s'", refTag[1])
}
if !IsValidPublicKey(spl[1]) {
return EntityPointer{}, fmt.Errorf("invalid addr pubkey '%s'", spl[1])
}
kind, err := strconv.Atoi(spl[0])
if err != nil || kind > (1<<16) {
return EntityPointer{}, fmt.Errorf("invalid addr kind '%s'", spl[0])
}
pointer := EntityPointer{
Kind: kind,
PublicKey: spl[1],
Identifier: spl[2],
}
if len(refTag) > 2 {
if relay := (refTag)[2]; IsValidRelayURL(relay) {
pointer.Relays = []string{relay}
}
}
return pointer, nil
}
func (ep EntityPointer) MatchesEvent(evt Event) bool {
return ep.PublicKey == evt.PubKey &&
ep.Kind == evt.Kind &&
evt.Tags.GetD() == ep.Identifier
}
func (ep EntityPointer) AsTagReference() string {
return fmt.Sprintf("%d:%s:%s", ep.Kind, ep.PublicKey, ep.Identifier)
}
func (ep EntityPointer) AsFilter() Filter {
return Filter{
Kinds: []int{ep.Kind},
Authors: []string{ep.PublicKey},
Tags: TagMap{"d": []string{ep.Identifier}},
}
}
func (ep EntityPointer) AsTag() Tag {
if len(ep.Relays) > 0 {
return Tag{"a", ep.AsTagReference(), ep.Relays[0]}
}
return Tag{"a", ep.AsTagReference()}
}