Skip to content

Commit b823f51

Browse files
committed
Make replay a service in preparation for consolidating with search & scrollback (42wim#554)
Merge 42wim#554
2 parents 37d8c1a + 9d976c8 commit b823f51

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
"regexp"
@@ -10,6 +11,8 @@ import (
1011
"time"
1112
"unicode"
1213

14+
bolt "go.etcd.io/bbolt"
15+
1316
"github.com/42wim/matterircd/bridge"
1417
"github.com/mattermost/mattermost-server/v6/model"
1518
)
@@ -210,6 +213,174 @@ func login(u *User, toUser *User, args []string, service string) {
210213
u.MsgUser(toUser, "login OK")
211214
}
212215

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

mm-go-irckit/userbridge.go

Lines changed: 5 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -637,165 +637,19 @@ func (u *User) addUsersToChannels() {
637637
go u.handleEventChan()
638638
}
639639

640-
func (u *User) createSpoof(mmchannel *bridge.ChannelInfo) func(string, string, ...int) {
641-
if strings.Contains(mmchannel.Name, "__") {
642-
return func(nick string, msg string, maxlen ...int) {
643-
if usr, ok := u.Srv.HasUser(nick); ok {
644-
u.MsgSpoofUser(usr, u.Nick, msg)
645-
} else {
646-
logger.Errorf("%s not found for replay msg", nick)
647-
}
648-
}
649-
}
650-
651-
channelName := mmchannel.Name
652-
653-
if mmchannel.TeamID != u.br.GetMe().TeamID || u.v.GetBool(u.br.Protocol()+".prefixmainteam") {
654-
channelName = u.br.GetTeamName(mmchannel.TeamID) + "/" + mmchannel.Name
655-
}
656-
657-
u.syncChannel(mmchannel.ID, "#"+channelName)
658-
ch := u.Srv.Channel(mmchannel.ID)
659-
660-
return ch.SpoofMessage
661-
}
662-
663-
//nolint:funlen,gocognit,gocyclo,cyclop
664640
func (u *User) addUserToChannelWorker(channels <-chan *bridge.ChannelInfo, throttle *time.Ticker) {
665641
for brchannel := range channels {
666642
logger.Debug("addUserToChannelWorker", brchannel)
667643

668644
<-throttle.C
669-
// exclude direct messages
670-
spoof := u.createSpoof(brchannel)
671645

672-
since := u.br.GetLastViewedAt(brchannel.ID)
673-
// ignore invalid/deleted/old channels
674-
if since == 0 {
675-
continue
676-
}
677-
678-
logSince := "server"
679-
channame := brchannel.Name
680-
if !brchannel.DM {
681-
channame = fmt.Sprintf("#%s", brchannel.Name)
682-
}
646+
args := []string{brchannel.Name, brchannel.TeamID}
647+
replay(u, u, args, "")
683648

684-
// We used to stored last viewed at if present.
685-
var lastViewedAt int64
686-
key := brchannel.ID
687-
err := u.lastViewedAtDB.View(func(tx *bolt.Tx) error {
688-
b := tx.Bucket([]byte(u.User))
689-
if v := b.Get([]byte(key)); v != nil {
690-
lastViewedAt = int64(binary.LittleEndian.Uint64(v))
691-
}
692-
return nil
693-
})
694-
if err != nil {
695-
logger.Errorf("something wrong with u.lastViewedAtDB.View for %s for channel %s (%s)", u.Nick, channame, brchannel.ID)
696-
lastViewedAt = since
697-
}
698-
699-
// But only use the stored last viewed if it's later than what the server knows.
700-
if lastViewedAt > since {
701-
since = lastViewedAt + 1
702-
logSince = "stored"
703-
}
704-
705-
// post everything to the channel you haven't seen yet
706-
postlist := u.br.GetPostsSince(brchannel.ID, since)
707-
if postlist == nil {
708-
// if the channel is not from the primary team id, we can't get posts
709-
if brchannel.TeamID == u.br.GetMe().TeamID {
710-
logger.Errorf("something wrong with getPostsSince for %s for channel %s (%s)", u.Nick, channame, brchannel.ID)
711-
}
712-
continue
713-
}
714-
715-
showReplayHdr := true
716-
717-
mmPostList, _ := postlist.(*model.PostList)
718-
if mmPostList == nil {
719-
continue
720-
}
721-
// traverse the order in reverse
722-
for i := len(mmPostList.Order) - 1; i >= 0; i-- {
723-
p := mmPostList.Posts[mmPostList.Order[i]]
724-
if p.Type == model.PostTypeJoinLeave {
725-
continue
726-
}
727-
728-
if p.DeleteAt > p.CreateAt {
729-
continue
730-
}
731-
732-
// GetPostsSince will return older messages with reaction
733-
// changes since LastViewedAt. This will be confusing as
734-
// the user will think it's a duplicate, or a post out of
735-
// order. Plus, we don't show reaction changes when
736-
// relaying messages/logs so let's skip these.
737-
if p.CreateAt < since {
738-
continue
739-
}
740-
741-
ts := time.Unix(0, p.CreateAt*int64(time.Millisecond))
742-
743-
props := p.GetProps()
744-
botname, override := props["override_username"].(string)
745-
user := u.br.GetUser(p.UserId)
746-
nick := user.Nick
747-
if override {
748-
nick = botname
749-
}
750-
751-
if p.Type == model.PostTypeAddToTeam || p.Type == model.PostTypeRemoveFromTeam {
752-
nick = systemUser
753-
}
754-
755-
for _, post := range strings.Split(p.Message, "\n") {
756-
if showReplayHdr {
757-
date := ts.Format("2006-01-02 15:04:05")
758-
if brchannel.DM {
759-
spoof(nick, fmt.Sprintf("\x02Replaying msgs since %s\x0f", date))
760-
} else {
761-
spoof("matterircd", fmt.Sprintf("\x02Replaying msgs since %s\x0f", date))
762-
}
763-
logger.Infof("Replaying msgs for %s for %s (%s) since %s (%s)", u.Nick, channame, brchannel.ID, date, logSince)
764-
showReplayHdr = false
765-
}
766-
767-
if nick == systemUser {
768-
post = "\x1d" + post + "\x1d"
769-
}
770-
771-
replayMsg := fmt.Sprintf("[%s] %s", ts.Format("15:04"), post)
772-
if (u.v.GetBool(u.br.Protocol()+".prefixcontext") || u.v.GetBool(u.br.Protocol()+".suffixcontext")) && nick != systemUser {
773-
threadMsgID := u.prefixContext(brchannel.ID, p.Id, p.RootId, "replay")
774-
replayMsg = u.formatContextMessage(ts.Format("15:04"), threadMsgID, post)
775-
}
776-
spoof(nick, replayMsg)
777-
}
778-
779-
if len(p.FileIds) == 0 {
780-
continue
781-
}
782-
783-
for _, fname := range u.br.GetFileLinks(p.FileIds) {
784-
fileMsg := "\x1ddownload file - " + fname + "\x1d"
785-
if u.v.GetBool(u.br.Protocol()+".prefixcontext") || u.v.GetBool(u.br.Protocol()+".suffixcontext") {
786-
threadMsgID := u.prefixContext(brchannel.ID, p.Id, p.RootId, "replay_file")
787-
fileMsg = u.formatContextMessage(ts.Format("15:04"), threadMsgID, fileMsg)
788-
}
789-
spoof(nick, fileMsg)
790-
}
791-
}
792-
793-
if len(mmPostList.Order) > 0 {
794-
if !u.v.GetBool(u.br.Protocol() + ".disableautoview") {
795-
u.updateLastViewed(brchannel.ID)
796-
}
797-
u.saveLastViewedAt(brchannel.ID)
649+
if !u.v.GetBool(u.br.Protocol() + ".disableautoview") {
650+
u.updateLastViewed(brchannel.ID)
798651
}
652+
u.saveLastViewedAt(brchannel.ID)
799653
}
800654
}
801655

0 commit comments

Comments
 (0)