Thumbnail

rani/matterbridge.git

Clone URL: https://git.buni.party/rani/matterbridge.git

Viewing file on branch master

1package bzulip
2
3import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "strconv"
8 "strings"
9 "sync"
10 "time"
11
12 "github.com/matterbridge-org/matterbridge/bridge"
13 "github.com/matterbridge-org/matterbridge/bridge/config"
14 "github.com/matterbridge-org/matterbridge/bridge/helper"
15 "github.com/matterbridge-org/matterbridge/version"
16
17 // Seems not significantly different from upstream https://github.com/ifo/gozulipbot replace?
18 gzb "github.com/matterbridge/gozulipbot"
19)
20
21type Bzulip struct {
22 q *gzb.Queue
23 bot *gzb.Bot
24 streams map[int]string
25 *bridge.Config
26 sync.RWMutex
27}
28
29func New(cfg *bridge.Config) bridge.Bridger {
30 return &Bzulip{Config: cfg, streams: make(map[int]string)}
31}
32
33func (b *Bzulip) Connect() error {
34 bot := gzb.Bot{APIKey: b.GetString("token"), APIURL: b.GetString("server") + "/api/v1/", Email: b.GetString("login"), UserAgent: fmt.Sprintf("matterbridge/%s", version.Release)}
35 bot.Init()
36 q, err := bot.RegisterAll()
37 b.q = q
38 b.bot = &bot
39 if err != nil {
40 b.Log.Errorf("Connect() %#v", err)
41 return err
42 }
43 // init stream
44 b.getChannel(0)
45 b.Log.Info("Connection succeeded")
46 go b.handleQueue()
47 return nil
48}
49
50func (b *Bzulip) Disconnect() error {
51 return nil
52}
53
54func (b *Bzulip) JoinChannel(channel config.ChannelInfo) error {
55 return nil
56}
57
58func (b *Bzulip) Send(msg config.Message) (string, error) {
59 b.Log.Debugf("=> Receiving %#v", msg)
60
61 // Delete message
62 if msg.Event == config.EventMsgDelete {
63 if msg.ID == "" {
64 return "", nil
65 }
66 _, err := b.bot.UpdateMessage(msg.ID, "")
67 return "", err
68 }
69
70 // Upload a file if it exists
71 if msg.Extra != nil {
72 for _, rmsg := range helper.HandleExtra(&msg, b.General) {
73 b.sendMessage(rmsg)
74 }
75 if len(msg.Extra["file"]) > 0 {
76 return b.handleUploadFile(&msg)
77 }
78 }
79
80 // edit the message if we have a msg ID
81 if msg.ID != "" {
82 _, err := b.bot.UpdateMessage(msg.ID, msg.Username+msg.Text)
83 return "", err
84 }
85
86 // Post normal message
87 return b.sendMessage(msg)
88}
89
90func (b *Bzulip) getChannel(id int) string {
91 if name, ok := b.streams[id]; ok {
92 return name
93 }
94 streams, err := b.bot.GetRawStreams()
95 if err != nil {
96 b.Log.Errorf("getChannel: %#v", err)
97 return ""
98 }
99 for _, stream := range streams.Streams {
100 b.streams[stream.StreamID] = stream.Name
101 }
102 if name, ok := b.streams[id]; ok {
103 return name
104 }
105 return ""
106}
107
108func (b *Bzulip) handleQueue() error {
109 for {
110 messages, err := b.q.GetEvents()
111 if err != nil {
112 switch err {
113 case gzb.BackoffError:
114 time.Sleep(time.Second * 5)
115 case gzb.NoJSONError:
116 b.Log.Error("Response wasn't JSON, server down or restarting? sleeping 10 seconds")
117 time.Sleep(time.Second * 10)
118 case gzb.BadEventQueueError:
119 b.Log.Info("got a bad event queue id error, reconnecting")
120 b.bot.Queues = nil
121 for {
122 b.q, err = b.bot.RegisterAll()
123 if err != nil {
124 b.Log.Errorf("reconnecting failed: %s. Sleeping 10 seconds", err)
125 time.Sleep(time.Second * 10)
126 }
127 break
128 }
129 case gzb.HeartbeatError:
130 b.Log.Debug("heartbeat received.")
131 default:
132 b.Log.Debugf("receiving error: %#v", err)
133 time.Sleep(time.Second * 10)
134 }
135
136 continue
137 }
138 for _, m := range messages {
139 b.Log.Debugf("== Receiving %#v", m)
140 // ignore our own messages
141 if m.SenderEmail == b.GetString("login") {
142 continue
143 }
144
145 avatarURL := m.AvatarURL
146 if !strings.HasPrefix(avatarURL, "http") {
147 avatarURL = b.GetString("server") + avatarURL
148 }
149
150 rmsg := config.Message{
151 Username: m.SenderFullName,
152 Text: m.Content,
153 Channel: b.getChannel(m.StreamID) + "/topic:" + m.Subject,
154 Account: b.Account,
155 UserID: strconv.Itoa(m.SenderID),
156 Avatar: avatarURL,
157 }
158 b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account)
159 b.Log.Debugf("<= Message is %#v", rmsg)
160 b.Remote <- rmsg
161 }
162
163 time.Sleep(time.Second * 3)
164 }
165}
166
167func (b *Bzulip) sendMessage(msg config.Message) (string, error) {
168 topic := ""
169 if strings.Contains(msg.Channel, "/topic:") {
170 res := strings.Split(msg.Channel, "/topic:")
171 topic = res[1]
172 msg.Channel = res[0]
173 }
174 m := gzb.Message{
175 Stream: msg.Channel,
176 Topic: topic,
177 Content: msg.Username + msg.Text,
178 }
179 resp, err := b.bot.Message(m)
180 if err != nil {
181 return "", err
182 }
183 if resp != nil {
184 defer resp.Body.Close()
185
186 res, err := io.ReadAll(resp.Body)
187 if err != nil {
188 return "", err
189 }
190 var jr struct {
191 ID int `json:"id"`
192 }
193 err = json.Unmarshal(res, &jr)
194 if err != nil {
195 return "", err
196 }
197 return strconv.Itoa(jr.ID), nil
198 }
199 return "", nil
200}
201
202func (b *Bzulip) handleUploadFile(msg *config.Message) (string, error) {
203 for _, f := range msg.Extra["file"] {
204 fi := f.(config.FileInfo)
205 if fi.Comment != "" {
206 msg.Text += fi.Comment + ": "
207 }
208 if fi.URL != "" {
209 msg.Text = fi.URL
210 if fi.Comment != "" {
211 msg.Text = fi.Comment + ": " + fi.URL
212 }
213 }
214 _, err := b.sendMessage(*msg)
215 if err != nil {
216 return "", err
217 }
218 }
219 return "", nil
220}
221