mirror of
https://github.com/nbd-wtf/go-nostr.git
synced 2025-05-05 00:00:14 +02:00
153 lines
3.4 KiB
Go
153 lines
3.4 KiB
Go
package nip27
|
|
|
|
import (
|
|
"iter"
|
|
"net/url"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/nbd-wtf/go-nostr"
|
|
"github.com/nbd-wtf/go-nostr/nip19"
|
|
"github.com/nbd-wtf/go-nostr/nip73"
|
|
)
|
|
|
|
type Block struct {
|
|
Text string
|
|
Start int
|
|
Pointer nostr.Pointer
|
|
}
|
|
|
|
var (
|
|
noCharacter = regexp.MustCompile(`(?m)\W`)
|
|
noURLCharacter = regexp.MustCompile(`(?m)\W |\W$|$|,| `)
|
|
)
|
|
|
|
func Parse(content string) iter.Seq[Block] {
|
|
return func(yield func(Block) bool) {
|
|
max := len(content)
|
|
index := 0
|
|
prevIndex := 0
|
|
|
|
for index < max {
|
|
pu := strings.IndexRune(content[index:], ':')
|
|
if pu == -1 {
|
|
// reached end
|
|
break
|
|
}
|
|
u := pu + index
|
|
|
|
switch {
|
|
case u >= 5 && content[u-5:u] == "nostr" && u+60 < max:
|
|
m := noCharacter.FindStringIndex(content[u+60:])
|
|
end := max
|
|
if m != nil {
|
|
end = u + 60 + m[0]
|
|
}
|
|
|
|
prefix, data, err := nip19.Decode(content[u+1 : end])
|
|
if err != nil {
|
|
// ignore this, not a valid nostr uri
|
|
index = u + 1
|
|
continue
|
|
}
|
|
|
|
var pointer nostr.Pointer
|
|
switch prefix {
|
|
case "npub":
|
|
pointer = nostr.ProfilePointer{PublicKey: data.(string)}
|
|
case "nprofile", "nevent", "naddr":
|
|
pointer = data.(nostr.Pointer)
|
|
case "note", "nsec":
|
|
fallthrough // I'm so cool
|
|
default:
|
|
// ignore this, treat it as not a valid uri
|
|
index = end + 1
|
|
continue
|
|
}
|
|
|
|
if prevIndex != u-5 {
|
|
if !yield(Block{Text: content[prevIndex : u-5], Start: prevIndex}) {
|
|
return
|
|
}
|
|
}
|
|
|
|
if !yield(Block{Pointer: pointer, Text: content[u-5 : end], Start: u - 5}) {
|
|
return
|
|
}
|
|
|
|
index = end
|
|
prevIndex = index
|
|
continue
|
|
case ((u >= 5 && content[u-5:u] == "https") || (u >= 4 && content[u-4:u] == "http")) && u+4 < max:
|
|
m := noURLCharacter.FindStringIndex(content[u+4:])
|
|
end := max
|
|
if m != nil {
|
|
end = u + 4 + m[0]
|
|
}
|
|
prefixLen := 4
|
|
if content[u-1] == 's' {
|
|
prefixLen = 5
|
|
}
|
|
parsed, err := url.Parse(content[u-prefixLen : end])
|
|
if err != nil || !strings.Contains(parsed.Host, ".") {
|
|
// ignore this, not a valid url
|
|
index = end + 1
|
|
continue
|
|
}
|
|
|
|
if prevIndex != u-prefixLen {
|
|
if !yield(Block{Text: content[prevIndex : u-prefixLen], Start: prevIndex}) {
|
|
return
|
|
}
|
|
}
|
|
|
|
if !yield(Block{Pointer: nip73.ExternalPointer{Thing: content[u-prefixLen : end]}, Text: content[u-prefixLen : end], Start: u - prefixLen}) {
|
|
return
|
|
}
|
|
|
|
index = end
|
|
prevIndex = index
|
|
continue
|
|
case ((u >= 3 && content[u-3:u] == "wss") || (u >= 2 && content[u-2:u] == "ws")) && u+4 < max:
|
|
m := noURLCharacter.FindStringIndex(content[u+4:])
|
|
end := max
|
|
if m != nil {
|
|
end = u + 4 + m[0]
|
|
}
|
|
prefixLen := 2
|
|
if content[u-1] == 's' {
|
|
prefixLen = 3
|
|
}
|
|
parsed, err := url.Parse(content[u-prefixLen : end])
|
|
if err != nil || !strings.Contains(parsed.Host, ".") {
|
|
// ignore this, not a valid url
|
|
index = end + 1
|
|
continue
|
|
}
|
|
|
|
if prevIndex != u-prefixLen {
|
|
if !yield(Block{Text: content[prevIndex : u-prefixLen], Start: prevIndex}) {
|
|
return
|
|
}
|
|
}
|
|
|
|
if !yield(Block{Pointer: nip73.ExternalPointer{Thing: content[u-prefixLen : end]}, Text: content[u-prefixLen : end], Start: u - prefixLen}) {
|
|
return
|
|
}
|
|
|
|
index = end
|
|
prevIndex = index
|
|
continue
|
|
default:
|
|
// ignore this, it is nothing
|
|
index = u + 1
|
|
continue
|
|
}
|
|
}
|
|
|
|
if prevIndex != max {
|
|
yield(Block{Text: content[prevIndex:], Start: prevIndex})
|
|
}
|
|
}
|
|
}
|