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, id 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)) } }