all repos — underbbs @ 27c9e9bc59eb4423d7a19e9157b2c288ccbe8568

decentralized social media client

adapter/adapter.go (raw)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package adapter

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	. "forge.lightcrystal.systems/lightcrystal/underbbs/models"
	nostr "github.com/nbd-wtf/go-nostr"
	"strings"
)

type Adapter interface {
	Init(Settings, chan SocketData) error
	Subscribe(string) []error
	SendMessage(Message) error
	Follow(Author) error
	Unfollow(Author) error
	GetFollowers() error
	UpdateMetadata(interface{}) error
	DefaultSubscriptionFilter() string
}

type NostrAdapter struct {
	data     chan SocketData
	nickname string
	privkey  string
	relays   []*nostr.Relay
}

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 := 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) SendMessage(msg Message) error {
	return nil
}
func (self *NostrAdapter) Follow(author Author) error {
	return nil
}
func (self *NostrAdapter) Unfollow(author Author) error {
	return nil
}
func (self *NostrAdapter) GetFollowers() error {
	return nil
}
func (self *NostrAdapter) UpdateMetadata(data interface{}) error {
	return nil
}

func (self *NostrAdapter) DefaultSubscriptionFilter() string {
	return "[{\"kinds\":[1]}]"
}

func nostrEventToMsg(evt *nostr.Event) (Message, error) {
	m := Message{
		Protocol: "nostr",
	}
	if evt == nil {
		return m, errors.New("no event")
	}
	switch evt.Kind {
	case nostr.KindTextNote:
		m.Uri = evt.ID
		m.Author = Author{
			Id: evt.PubKey,
		}
		m.Created = evt.CreatedAt.Time()
		m.Content = evt.Content
		return m, nil
	default:
		return m, errors.New(fmt.Sprintf("unsupported event kind: %d", evt.Kind))
	}
}