Skip to content

Commit fec77d7

Browse files
committed
Make replay a service in preparation for consolidating with search & scrollback
1 parent bbe3e54 commit fec77d7

File tree

2 files changed

+180
-151
lines changed

2 files changed

+180
-151
lines changed

mm-go-irckit/service.go

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package irckit
22

33
import (
4+
"encoding/binary"
45
"errors"
56
"fmt"
67
"sort"
@@ -9,6 +10,8 @@ import (
910
"time"
1011
"unicode"
1112

13+
bolt "go.etcd.io/bbolt"
14+
1215
"github.com/42wim/matterircd/bridge"
1316
"github.com/mattermost/mattermost-server/v6/model"
1417
)
@@ -209,6 +212,177 @@ func login(u *User, toUser *User, args []string, service string) {
209212
u.MsgUser(toUser, "login OK")
210213
}
211214

215+
func createSpoof(u *User, mmchannel *bridge.ChannelInfo) func(string, string, ...int) {
216+
if strings.Contains(mmchannel.Name, "__") {
217+
return func(nick string, msg string, maxlen ...int) {
218+
if usr, ok := u.Srv.HasUser(nick); ok {
219+
u.MsgSpoofUser(usr, u.Nick, msg)
220+
} else {
221+
logger.Errorf("%s not found for replay msg", nick)
222+
}
223+
}
224+
}
225+
226+
channelName := mmchannel.Name
227+
228+
if mmchannel.TeamID != u.br.GetMe().TeamID || u.v.GetBool(u.br.Protocol()+".prefixmainteam") {
229+
channelName = u.br.GetTeamName(mmchannel.TeamID) + "/" + mmchannel.Name
230+
}
231+
232+
u.syncChannel(mmchannel.ID, "#"+channelName)
233+
ch := u.Srv.Channel(mmchannel.ID)
234+
235+
return ch.SpoofMessage
236+
}
237+
238+
//nolint:funlen,gocognit,gocyclo,cyclop
239+
func replay(u *User, toUser *User, args []string, service string) {
240+
if len(args) == 0 || len(args) > 2 {
241+
u.MsgUser(toUser, "need REPLAY (#<channel>|<user>)")
242+
u.MsgUser(toUser, "e.g. REPLAY #bugs")
243+
return
244+
}
245+
246+
channelName := args[0]
247+
if strings.HasPrefix(channelName, "#") {
248+
channelName = channelName[1:]
249+
}
250+
channelTeamID := u.br.GetMe().TeamID
251+
if len(args) == 2 {
252+
channelTeamID = args[1]
253+
}
254+
channelID := u.br.GetChannelID(channelName, channelTeamID)
255+
brchannel, err := u.br.GetChannel(channelID)
256+
if err != nil {
257+
logger.Errorf("%s not found", channelName)
258+
return
259+
}
260+
261+
// exclude direct messages
262+
spoof := createSpoof(u, brchannel)
263+
264+
since := u.br.GetLastViewedAt(brchannel.ID)
265+
// ignore invalid/deleted/old channels
266+
if since == 0 {
267+
return
268+
}
269+
270+
logSince := "server"
271+
channame := brchannel.Name
272+
if !brchannel.DM {
273+
channame = fmt.Sprintf("#%s", brchannel.Name)
274+
}
275+
276+
// We used to stored last viewed at if present.
277+
var lastViewedAt int64
278+
key := brchannel.ID
279+
err = u.lastViewedAtDB.View(func(tx *bolt.Tx) error {
280+
b := tx.Bucket([]byte(u.User))
281+
if v := b.Get([]byte(key)); v != nil {
282+
lastViewedAt = int64(binary.LittleEndian.Uint64(v))
283+
}
284+
return nil
285+
})
286+
if err != nil {
287+
logger.Errorf("something wrong with u.lastViewedAtDB.View for %s for channel %s (%s)", u.Nick, channame, brchannel.ID)
288+
lastViewedAt = since
289+
}
290+
291+
// But only use the stored last viewed if it's later than what the server knows.
292+
if lastViewedAt > since {
293+
since = lastViewedAt + 1
294+
logSince = "stored"
295+
}
296+
297+
// post everything to the channel you haven't seen yet
298+
postlist := u.br.GetPostsSince(brchannel.ID, since)
299+
if postlist == nil {
300+
// if the channel is not from the primary team id, we can't get posts
301+
if brchannel.TeamID == u.br.GetMe().TeamID {
302+
logger.Errorf("something wrong with getPostsSince for %s for channel %s (%s)", u.Nick, channame, brchannel.ID)
303+
}
304+
return
305+
}
306+
307+
showReplayHdr := true
308+
309+
mmPostList, _ := postlist.(*model.PostList)
310+
if mmPostList == nil {
311+
return
312+
}
313+
// traverse the order in reverse
314+
for i := len(mmPostList.Order) - 1; i >= 0; i-- {
315+
p := mmPostList.Posts[mmPostList.Order[i]]
316+
if p.Type == model.PostTypeJoinLeave {
317+
continue
318+
}
319+
320+
if p.DeleteAt > p.CreateAt {
321+
continue
322+
}
323+
324+
// GetPostsSince will return older messages with reaction
325+
// changes since LastViewedAt. This will be confusing as
326+
// the user will think it's a duplicate, or a post out of
327+
// order. Plus, we don't show reaction changes when
328+
// relaying messages/logs so let's skip these.
329+
if p.CreateAt < since {
330+
continue
331+
}
332+
333+
ts := time.Unix(0, p.CreateAt*int64(time.Millisecond))
334+
335+
props := p.GetProps()
336+
botname, override := props["override_username"].(string)
337+
user := u.br.GetUser(p.UserId)
338+
nick := user.Nick
339+
if override {
340+
nick = botname
341+
}
342+
343+
if p.Type == model.PostTypeAddToTeam || p.Type == model.PostTypeRemoveFromTeam {
344+
nick = systemUser
345+
}
346+
347+
for _, post := range strings.Split(p.Message, "\n") {
348+
if showReplayHdr {
349+
date := ts.Format("2006-01-02 15:04:05")
350+
if brchannel.DM {
351+
spoof(nick, fmt.Sprintf("\x02Replaying msgs since %s\x0f (%s)", date, logSince))
352+
} else {
353+
spoof("matterircd", fmt.Sprintf("\x02Replaying msgs since %s\x0f (%s)", date, logSince))
354+
}
355+
logger.Infof("Replaying msgs for %s for %s (%s) since %s (%s)", u.Nick, channame, brchannel.ID, date, logSince)
356+
showReplayHdr = false
357+
}
358+
359+
if nick == systemUser {
360+
post = "\x1d" + post + "\x1d"
361+
}
362+
363+
replayMsg := fmt.Sprintf("[%s] %s", ts.Format("15:04"), post)
364+
if (u.v.GetBool(u.br.Protocol()+".prefixcontext") || u.v.GetBool(u.br.Protocol()+".suffixcontext")) && nick != systemUser {
365+
threadMsgID := u.prefixContext(brchannel.ID, p.Id, p.RootId, "replay")
366+
replayMsg = u.formatContextMessage(ts.Format("15:04"), threadMsgID, post)
367+
}
368+
spoof(nick, replayMsg)
369+
}
370+
371+
if len(p.FileIds) == 0 {
372+
continue
373+
}
374+
375+
for _, fname := range u.br.GetFileLinks(p.FileIds) {
376+
fileMsg := "\x1ddownload file - " + fname + "\x1d"
377+
if u.v.GetBool(u.br.Protocol()+".prefixcontext") || u.v.GetBool(u.br.Protocol()+".suffixcontext") {
378+
threadMsgID := u.prefixContext(brchannel.ID, p.Id, p.RootId, "replay_file")
379+
fileMsg = u.formatContextMessage(ts.Format("15:04"), threadMsgID, fileMsg)
380+
}
381+
spoof(nick, fileMsg)
382+
}
383+
}
384+
}
385+
212386
//nolint:cyclop
213387
func search(u *User, toUser *User, args []string, service string) {
214388
if service == "slack" {
@@ -472,6 +646,7 @@ var cmds = map[string]Command{
472646
"lastsent": {handler: lastsent, login: true, minParams: 0, maxParams: 0},
473647
"logout": {handler: logout, login: true, minParams: 0, maxParams: 0},
474648
"login": {handler: login, minParams: 2, maxParams: 5},
649+
"replay": {handler: replay, login: true, minParams: 1, maxParams: 2},
475650
"search": {handler: search, login: true, minParams: 1, maxParams: -1},
476651
"searchusers": {handler: searchUsers, login: true, minParams: 1, maxParams: -1},
477652
"scrollback": {handler: scrollback, login: true, minParams: 2, maxParams: 2},

mm-go-irckit/userbridge.go

Lines changed: 5 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -603,165 +603,19 @@ func (u *User) addUsersToChannels() {
603603
go u.handleEventChan()
604604
}
605605

606-
func (u *User) createSpoof(mmchannel *bridge.ChannelInfo) func(string, string, ...int) {
607-
if strings.Contains(mmchannel.Name, "__") {
608-
return func(nick string, msg string, maxlen ...int) {
609-
if usr, ok := u.Srv.HasUser(nick); ok {
610-
u.MsgSpoofUser(usr, u.Nick, msg)
611-
} else {
612-
logger.Errorf("%s not found for replay msg", nick)
613-
}
614-
}
615-
}
616-
617-
channelName := mmchannel.Name
618-
619-
if mmchannel.TeamID != u.br.GetMe().TeamID || u.v.GetBool(u.br.Protocol()+".prefixmainteam") {
620-
channelName = u.br.GetTeamName(mmchannel.TeamID) + "/" + mmchannel.Name
621-
}
622-
623-
u.syncChannel(mmchannel.ID, "#"+channelName)
624-
ch := u.Srv.Channel(mmchannel.ID)
625-
626-
return ch.SpoofMessage
627-
}
628-
629-
//nolint:funlen,gocognit,gocyclo,cyclop
630606
func (u *User) addUserToChannelWorker(channels <-chan *bridge.ChannelInfo, throttle *time.Ticker) {
631607
for brchannel := range channels {
632608
logger.Debug("addUserToChannelWorker", brchannel)
633609

634610
<-throttle.C
635-
// exclude direct messages
636-
spoof := u.createSpoof(brchannel)
637611

638-
since := u.br.GetLastViewedAt(brchannel.ID)
639-
// ignore invalid/deleted/old channels
640-
if since == 0 {
641-
continue
642-
}
643-
644-
logSince := "server"
645-
channame := brchannel.Name
646-
if !brchannel.DM {
647-
channame = fmt.Sprintf("#%s", brchannel.Name)
648-
}
612+
args := []string{brchannel.Name, brchannel.TeamID}
613+
replay(u, u, args, "")
649614

650-
// We used to stored last viewed at if present.
651-
var lastViewedAt int64
652-
key := brchannel.ID
653-
err := u.lastViewedAtDB.View(func(tx *bolt.Tx) error {
654-
b := tx.Bucket([]byte(u.User))
655-
if v := b.Get([]byte(key)); v != nil {
656-
lastViewedAt = int64(binary.LittleEndian.Uint64(v))
657-
}
658-
return nil
659-
})
660-
if err != nil {
661-
logger.Errorf("something wrong with u.lastViewedAtDB.View for %s for channel %s (%s)", u.Nick, channame, brchannel.ID)
662-
lastViewedAt = since
663-
}
664-
665-
// But only use the stored last viewed if it's later than what the server knows.
666-
if lastViewedAt > since {
667-
since = lastViewedAt + 1
668-
logSince = "stored"
669-
}
670-
671-
// post everything to the channel you haven't seen yet
672-
postlist := u.br.GetPostsSince(brchannel.ID, since)
673-
if postlist == nil {
674-
// if the channel is not from the primary team id, we can't get posts
675-
if brchannel.TeamID == u.br.GetMe().TeamID {
676-
logger.Errorf("something wrong with getPostsSince for %s for channel %s (%s)", u.Nick, channame, brchannel.ID)
677-
}
678-
continue
679-
}
680-
681-
showReplayHdr := true
682-
683-
mmPostList, _ := postlist.(*model.PostList)
684-
if mmPostList == nil {
685-
continue
686-
}
687-
// traverse the order in reverse
688-
for i := len(mmPostList.Order) - 1; i >= 0; i-- {
689-
p := mmPostList.Posts[mmPostList.Order[i]]
690-
if p.Type == model.PostTypeJoinLeave {
691-
continue
692-
}
693-
694-
if p.DeleteAt > p.CreateAt {
695-
continue
696-
}
697-
698-
// GetPostsSince will return older messages with reaction
699-
// changes since LastViewedAt. This will be confusing as
700-
// the user will think it's a duplicate, or a post out of
701-
// order. Plus, we don't show reaction changes when
702-
// relaying messages/logs so let's skip these.
703-
if p.CreateAt < since {
704-
continue
705-
}
706-
707-
ts := time.Unix(0, p.CreateAt*int64(time.Millisecond))
708-
709-
props := p.GetProps()
710-
botname, override := props["override_username"].(string)
711-
user := u.br.GetUser(p.UserId)
712-
nick := user.Nick
713-
if override {
714-
nick = botname
715-
}
716-
717-
if p.Type == model.PostTypeAddToTeam || p.Type == model.PostTypeRemoveFromTeam {
718-
nick = systemUser
719-
}
720-
721-
for _, post := range strings.Split(p.Message, "\n") {
722-
if showReplayHdr {
723-
date := ts.Format("2006-01-02 15:04:05")
724-
if brchannel.DM {
725-
spoof(nick, fmt.Sprintf("\x02Replaying msgs since %s\x0f", date))
726-
} else {
727-
spoof("matterircd", fmt.Sprintf("\x02Replaying msgs since %s\x0f", date))
728-
}
729-
logger.Infof("Replaying msgs for %s for %s (%s) since %s (%s)", u.Nick, channame, brchannel.ID, date, logSince)
730-
showReplayHdr = false
731-
}
732-
733-
if nick == systemUser {
734-
post = "\x1d" + post + "\x1d"
735-
}
736-
737-
replayMsg := fmt.Sprintf("[%s] %s", ts.Format("15:04"), post)
738-
if (u.v.GetBool(u.br.Protocol()+".prefixcontext") || u.v.GetBool(u.br.Protocol()+".suffixcontext")) && nick != systemUser {
739-
threadMsgID := u.prefixContext(brchannel.ID, p.Id, p.RootId, "replay")
740-
replayMsg = u.formatContextMessage(ts.Format("15:04"), threadMsgID, post)
741-
}
742-
spoof(nick, replayMsg)
743-
}
744-
745-
if len(p.FileIds) == 0 {
746-
continue
747-
}
748-
749-
for _, fname := range u.br.GetFileLinks(p.FileIds) {
750-
fileMsg := "\x1ddownload file - " + fname + "\x1d"
751-
if u.v.GetBool(u.br.Protocol()+".prefixcontext") || u.v.GetBool(u.br.Protocol()+".suffixcontext") {
752-
threadMsgID := u.prefixContext(brchannel.ID, p.Id, p.RootId, "replay_file")
753-
fileMsg = u.formatContextMessage(ts.Format("15:04"), threadMsgID, fileMsg)
754-
}
755-
spoof(nick, fileMsg)
756-
}
757-
}
758-
759-
if len(mmPostList.Order) > 0 {
760-
if !u.v.GetBool(u.br.Protocol() + ".disableautoview") {
761-
u.updateLastViewed(brchannel.ID)
762-
}
763-
u.saveLastViewedAt(brchannel.ID)
615+
if !u.v.GetBool(u.br.Protocol() + ".disableautoview") {
616+
u.updateLastViewed(brchannel.ID)
764617
}
618+
u.saveLastViewedAt(brchannel.ID)
765619
}
766620
}
767621

0 commit comments

Comments
 (0)