Skip to content

Commit b9de1aa

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

File tree

2 files changed

+177
-151
lines changed

2 files changed

+177
-151
lines changed

mm-go-irckit/service.go

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