all repos — underbbs @ 44bdad2e509c30962c79155a16e6d499bbaf3791

decentralized social media client

adapter/mastodon.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 (
	"fmt"
	. "forge.lightcrystal.systems/lightcrystal/underbbs/models"
	madon "github.com/McKael/madon"
)

type MastoAdapter struct {
	data     chan SocketData
	nickname string
	server   string
	apiKey   string

	masto *madon.Client

	events chan madon.StreamEvent
	stop   chan bool
	done   chan bool
}

var scopes = []string{"read", "write", "follow"}

func (self *MastoAdapter) Name() string {
  return self.nickname
}


func (self *MastoAdapter) Init(settings Settings, data chan SocketData) error {
	self.nickname = settings.Nickname
	self.server = *settings.Server
	self.apiKey = *settings.ApiKey
	self.data = data

	masto, err := madon.NewApp("underbbs", "https://lightcrystal.systems", scopes, madon.NoRedirect, self.server)
	if err != nil {
		return err
	}
	self.masto = masto
	err = self.masto.SetUserToken(self.apiKey, "", "", []string{})
	return err
}

func (self *MastoAdapter) Subscribe(filter string) []error {
	// TODO: decode separate timelines and hashtags
	// for now, the filter is just the timeline

	if self.events != nil {
		close(self.events)
	}
	self.events = make(chan madon.StreamEvent)

	if self.stop != nil {
		close(self.stop)
	}
	self.stop = make(chan bool)

	self.done = make(chan bool)

	err := self.masto.StreamListener(filter, "", self.events, self.stop, self.done)
	if err != nil {
		return []error{err}
	}
	go func() {
		for e := range self.events {
			fmt.Println("event: %s !!!", e.Event)
			switch e.Event {
			case "error":
			case "update":
				var msg *Message
				switch v := e.Data.(type) {
				case int64:
					s, _ := self.masto.GetStatus(v)
					if s != nil {
						msg = self.mastoUpdateToMessage(*s)
					}
				case madon.Status:
					msg = self.mastoUpdateToMessage(v)
				}
				if msg != nil {
					self.data <- msg
				}
			case "notification":
			case "delete":
			}
		}
	}()
	// in the background, read and translate events from the stream
	// and check for doneCh closing
	// the stopCh will be closed by a subsequent call to subscribe
	return nil
}

func (self *MastoAdapter) Fetch(etype string, id string) error {
	return nil
}

func (self *MastoAdapter) Do(action string) error {
	return nil
}

func (self *MastoAdapter) DefaultSubscriptionFilter() string {
	return "user"
}

func (self *MastoAdapter) mastoUpdateToMessage(status madon.Status) *Message {
	msg := Message{
		Datagram: Datagram{
			Protocol: "mastodon",
			Adapter:  self.nickname,
			Id:       fmt.Sprintf("%d", status.ID),
			Uri:      status.URI,
			Type:     "message",
		},
		Content:    status.Content,
		Author:     status.Account.Acct,
		Created:    status.CreatedAt,
		Visibility: status.Visibility,
	}
	if status.InReplyToID != nil {
		idStr := fmt.Sprintf("%d", *status.InReplyToID)
		msg.ReplyTo = &idStr
	}
	// TODO: mentions and replies

	return &msg
}