all repos — underbbs @ 89df01f089e2e00fa6fbcc5fa147074cce4e81a2

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
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
}

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

func (self *NostrAdapter) Init(settings Settings, msgChan chan SocketData) error {
	self.nickname = settings.Nickname
	self.privkey = *settings.PrivKey
	self.msgChan = msgChan

	ctx := context.Background()

	relays := strings.Split(*settings.Relays, ",")

	for _, r := range 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, 1)

	for _, r := range self.relays {

		sub, err := r.Subscribe(context.Background(), filters)
		if err != nil {
			errs = append(errs, err)
		} else {
			go func() {
				for ev := range sub.Events {
					// try sequentially to encode into an underbbs object
					// and send it to the appropriate channel
					m, err := nostrEventToMsg(ev)
					if err == nil {
						self.msgChan <- m
					}

				}
			}()
		}
	}

	if len(errs) > 0 {
		return errs
	}
	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 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))
	}
}