underbbs/adapter/nostr.go

116 lines
2.4 KiB
Go

package adapter
import (
"context"
"encoding/json"
"errors"
"fmt"
. "forge.lightcrystal.systems/lightcrystal/underbbs/models"
nostr "github.com/nbd-wtf/go-nostr"
"strings"
)
type NostrAdapter struct {
data chan SocketData
nickname string
privkey string
relays []*nostr.Relay
}
func (self *NostrAdapter) Name() string {
return self.nickname
}
func (self *NostrAdapter) Init(settings Settings, data chan SocketData) error {
self.nickname = settings.Nickname
self.privkey = *settings.PrivKey
self.data = data
ctx := context.Background()
for _, r := range settings.Relays {
pr, _ := nostr.RelayConnect(ctx, strings.Trim(r, " "))
if pr == nil {
return errors.New("Relay connection could not be completed")
}
self.relays = append(self.relays, pr)
}
return nil
}
func (self *NostrAdapter) Subscribe(filter string) []error {
var filters nostr.Filters
err := json.Unmarshal([]byte(filter), &filters)
if err != nil {
return []error{err}
}
errs := make([]error, 0)
fmt.Print("unmarshalled filter from json; iterating through relays to subscribe..")
for _, r := range self.relays {
fmt.Print(".")
sub, err := r.Subscribe(context.Background(), filters)
if err != nil {
errs = append(errs, err)
} else {
go func() {
for ev := range sub.Events {
fmt.Print("!")
// try sequentially to encode into an underbbs object
// and send it to the appropriate channel
m, err := self.nostrEventToMsg(ev)
if err == nil {
self.data <- m
}
}
}()
}
fmt.Println()
}
if len(errs) > 0 {
fmt.Println("subscription operation completed with errors")
return errs
}
fmt.Println("subscription operation completed without errors")
return nil
}
func (self *NostrAdapter) Fetch(etype string, ids []string) error {
return nil
}
func (self *NostrAdapter) Do(action string) error {
return nil
}
func (self *NostrAdapter) DefaultSubscriptionFilter() string {
return "[{\"kinds\":[1]}]"
}
func (self *NostrAdapter) nostrEventToMsg(evt *nostr.Event) (Message, error) {
m := Message{
Datagram: Datagram{
Protocol: "nostr",
Adapter: self.nickname,
Type: "message",
},
}
if evt == nil {
return m, errors.New("no event")
}
switch evt.Kind {
case nostr.KindTextNote:
m.Id = evt.ID
m.Author = evt.PubKey
m.Created = evt.CreatedAt.Time().UnixMilli()
m.Content = evt.Content
return m, nil
default:
return m, errors.New(fmt.Sprintf("unsupported event kind: %d", evt.Kind))
}
}