forked from mirror/mautrix-discord
Backfill threads when found and from server thread list sync
This commit is contained in:
parent
b77eea4586
commit
11b91dc299
6 changed files with 97 additions and 24 deletions
10
backfill.go
10
backfill.go
|
@ -29,6 +29,7 @@ func (portal *Portal) forwardBackfillInitial(source *User, thread *Thread) {
|
||||||
limit = portal.bridge.Config.Bridge.Backfill.Limits.Initial.DM
|
limit = portal.bridge.Config.Bridge.Backfill.Limits.Initial.DM
|
||||||
if thread != nil {
|
if thread != nil {
|
||||||
limit = portal.bridge.Config.Bridge.Backfill.Limits.Initial.Thread
|
limit = portal.bridge.Config.Bridge.Backfill.Limits.Initial.Thread
|
||||||
|
thread.initialBackfillAttempted = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if limit == 0 {
|
if limit == 0 {
|
||||||
|
@ -225,16 +226,9 @@ func (portal *Portal) forwardBatchSend(log zerolog.Logger, source *User, message
|
||||||
for i, evtID := range resp.EventIDs {
|
for i, evtID := range resp.EventIDs {
|
||||||
dbMessages[i].MXID = evtID
|
dbMessages[i].MXID = evtID
|
||||||
if metas[i] != nil && metas[i].Flags == discordgo.MessageFlagsHasThread {
|
if metas[i] != nil && metas[i].Flags == discordgo.MessageFlagsHasThread {
|
||||||
thread = portal.bridge.GetThreadByID(metas[i].ID, &dbMessages[i])
|
|
||||||
log.Debug().
|
|
||||||
Str("message_id", metas[i].ID).
|
|
||||||
Str("event_id", evtID.String()).
|
|
||||||
Msg("Marked backfilled message as thread root")
|
|
||||||
if thread.CreationNoticeMXID == "" {
|
|
||||||
// TODO proper context
|
// TODO proper context
|
||||||
ctx := log.WithContext(context.Background())
|
ctx := log.WithContext(context.Background())
|
||||||
portal.sendThreadCreationNotice(ctx, thread)
|
portal.bridge.threadFound(ctx, source, &dbMessages[i], metas[i].ID, metas[i].Thread)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
portal.bridge.DB.Message.MassInsert(portal.Key, dbMessages)
|
portal.bridge.DB.Message.MassInsert(portal.Key, dbMessages)
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -38,4 +38,4 @@ require (
|
||||||
maunium.net/go/mauflag v1.0.0 // indirect
|
maunium.net/go/mauflag v1.0.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace github.com/bwmarrin/discordgo => github.com/beeper/discordgo v0.0.0-20230512133900-5b12693331c0
|
replace github.com/bwmarrin/discordgo => github.com/beeper/discordgo v0.0.0-20230618183737-3c7afd8d8596
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -1,6 +1,6 @@
|
||||||
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60=
|
||||||
github.com/beeper/discordgo v0.0.0-20230512133900-5b12693331c0 h1:ECBEbC4ruaXzcVJJ4UurkGpT/Xlm9ZnwsHiHn9gjPZw=
|
github.com/beeper/discordgo v0.0.0-20230618183737-3c7afd8d8596 h1:PxtbetWbVi2OlACDNtx6YJahhXt/rhiEsGqtOOLSx4o=
|
||||||
github.com/beeper/discordgo v0.0.0-20230512133900-5b12693331c0/go.mod h1:59+AOzzjmL6onAh62nuLXmn7dJCaC/owDLWbGtjTcFA=
|
github.com/beeper/discordgo v0.0.0-20230618183737-3c7afd8d8596/go.mod h1:59+AOzzjmL6onAh62nuLXmn7dJCaC/owDLWbGtjTcFA=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
|
13
portal.go
13
portal.go
|
@ -683,11 +683,7 @@ func (portal *Portal) handleDiscordMessageCreate(user *User, msg *discordgo.Mess
|
||||||
} else {
|
} else {
|
||||||
firstDBMessage := portal.markMessageHandled(msg.ID, msg.Author.ID, ts, discordThreadID, intent.UserID, dbParts)
|
firstDBMessage := portal.markMessageHandled(msg.ID, msg.Author.ID, ts, discordThreadID, intent.UserID, dbParts)
|
||||||
if msg.Flags == discordgo.MessageFlagsHasThread {
|
if msg.Flags == discordgo.MessageFlagsHasThread {
|
||||||
thread = portal.bridge.GetThreadByID(msg.ID, firstDBMessage)
|
portal.bridge.threadFound(ctx, user, firstDBMessage, msg.ID, msg.Thread)
|
||||||
log.Debug().Msg("Marked message as thread root")
|
|
||||||
if thread.CreationNoticeMXID == "" {
|
|
||||||
portal.sendThreadCreationNotice(ctx, thread)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -817,11 +813,7 @@ func (portal *Portal) handleDiscordMessageUpdate(user *User, msg *discordgo.Mess
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.Flags == discordgo.MessageFlagsHasThread {
|
if msg.Flags == discordgo.MessageFlagsHasThread {
|
||||||
thread := portal.bridge.GetThreadByID(msg.ID, existing[0])
|
portal.bridge.threadFound(ctx, user, existing[0], msg.ID, msg.Thread)
|
||||||
log.Debug().Msg("Marked message as thread root")
|
|
||||||
if thread.CreationNoticeMXID == "" {
|
|
||||||
portal.sendThreadCreationNotice(ctx, thread)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if msg.Author == nil {
|
if msg.Author == nil {
|
||||||
|
@ -1476,6 +1468,7 @@ func (portal *Portal) handleMatrixMessage(sender *User, evt *event.Event) {
|
||||||
existingThread := portal.bridge.GetThreadByRootMXID(threadRoot)
|
existingThread := portal.bridge.GetThreadByRootMXID(threadRoot)
|
||||||
if existingThread != nil {
|
if existingThread != nil {
|
||||||
threadID = existingThread.ID
|
threadID = existingThread.ID
|
||||||
|
existingThread.initialBackfillAttempted = true
|
||||||
} else {
|
} else {
|
||||||
if isWebhookSend {
|
if isWebhookSend {
|
||||||
// TODO start thread with bot?
|
// TODO start thread with bot?
|
||||||
|
|
59
thread.go
59
thread.go
|
@ -1,10 +1,13 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"golang.org/x/exp/slices"
|
||||||
"maunium.net/go/mautrix/id"
|
"maunium.net/go/mautrix/id"
|
||||||
|
|
||||||
"go.mau.fi/mautrix-discord/database"
|
"go.mau.fi/mautrix-discord/database"
|
||||||
|
@ -15,6 +18,7 @@ type Thread struct {
|
||||||
Parent *Portal
|
Parent *Portal
|
||||||
|
|
||||||
creationNoticeLock sync.Mutex
|
creationNoticeLock sync.Mutex
|
||||||
|
initialBackfillAttempted bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (br *DiscordBridge) GetThreadByID(id string, root *database.Message) *Thread {
|
func (br *DiscordBridge) GetThreadByID(id string, root *database.Message) *Thread {
|
||||||
|
@ -74,12 +78,63 @@ func (br *DiscordBridge) loadThread(dbThread *database.Thread, id string, root *
|
||||||
return thread
|
return thread
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (br *DiscordBridge) threadFound(ctx context.Context, source *User, rootMessage *database.Message, id string, metadata *discordgo.Channel) {
|
||||||
|
thread := br.GetThreadByID(id, rootMessage)
|
||||||
|
log := zerolog.Ctx(ctx)
|
||||||
|
log.Debug().Msg("Marked message as thread root")
|
||||||
|
if thread.CreationNoticeMXID == "" {
|
||||||
|
thread.Parent.sendThreadCreationNotice(ctx, thread)
|
||||||
|
}
|
||||||
|
// TODO member_ids_preview is probably not guaranteed to contain the source user
|
||||||
|
if source != nil && metadata != nil && slices.Contains(metadata.MemberIDsPreview, source.DiscordID) && !source.IsInPortal(thread.ID) {
|
||||||
|
source.MarkInPortal(database.UserPortal{
|
||||||
|
DiscordID: thread.ID,
|
||||||
|
Type: database.UserPortalTypeThread,
|
||||||
|
Timestamp: time.Now(),
|
||||||
|
})
|
||||||
|
if metadata.MessageCount > 0 {
|
||||||
|
go thread.maybeInitialBackfill(source)
|
||||||
|
} else {
|
||||||
|
thread.initialBackfillAttempted = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (thread *Thread) maybeInitialBackfill(source *User) {
|
||||||
|
if thread.initialBackfillAttempted || thread.Parent.bridge.Config.Bridge.Backfill.Limits.Initial.Thread == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
thread.Parent.forwardBackfillLock.Lock()
|
||||||
|
if thread.Parent.bridge.DB.Message.GetLastInThread(thread.Parent.Key, thread.ID) != nil {
|
||||||
|
thread.Parent.forwardBackfillLock.Unlock()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
thread.Parent.forwardBackfillInitial(source, thread)
|
||||||
|
}
|
||||||
|
|
||||||
func (thread *Thread) Join(user *User) {
|
func (thread *Thread) Join(user *User) {
|
||||||
if user.IsInPortal(thread.ID) {
|
if user.IsInPortal(thread.ID) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log := user.log.With().Str("thread_id", thread.ID).Str("channel_id", thread.ParentID).Logger()
|
log := user.log.With().Str("thread_id", thread.ID).Str("channel_id", thread.ParentID).Logger()
|
||||||
log.Debug().Msg("Joining thread")
|
log.Debug().Msg("Joining thread")
|
||||||
|
|
||||||
|
var doBackfill, backfillStarted bool
|
||||||
|
if !thread.initialBackfillAttempted && thread.Parent.bridge.Config.Bridge.Backfill.Limits.Initial.Thread > 0 {
|
||||||
|
thread.Parent.forwardBackfillLock.Lock()
|
||||||
|
lastMessage := thread.Parent.bridge.DB.Message.GetLastInThread(thread.Parent.Key, thread.ID)
|
||||||
|
if lastMessage != nil {
|
||||||
|
thread.Parent.forwardBackfillLock.Unlock()
|
||||||
|
} else {
|
||||||
|
doBackfill = true
|
||||||
|
defer func() {
|
||||||
|
if !backfillStarted {
|
||||||
|
thread.Parent.forwardBackfillLock.Unlock()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if user.Session.IsUser {
|
if user.Session.IsUser {
|
||||||
err = user.Session.ThreadJoinWithLocation(thread.ID, discordgo.ThreadJoinLocationContextMenu)
|
err = user.Session.ThreadJoinWithLocation(thread.ID, discordgo.ThreadJoinLocationContextMenu)
|
||||||
|
@ -94,5 +149,9 @@ func (thread *Thread) Join(user *User) {
|
||||||
Type: database.UserPortalTypeThread,
|
Type: database.UserPortalTypeThread,
|
||||||
Timestamp: time.Now(),
|
Timestamp: time.Now(),
|
||||||
})
|
})
|
||||||
|
if doBackfill {
|
||||||
|
go thread.Parent.forwardBackfillInitial(user, thread)
|
||||||
|
backfillStarted = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
27
user.go
27
user.go
|
@ -1,6 +1,7 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
@ -650,6 +651,8 @@ func (user *User) eventHandler(rawEvt any) {
|
||||||
user.typingStartHandler(evt)
|
user.typingStartHandler(evt)
|
||||||
case *discordgo.InteractionSuccess:
|
case *discordgo.InteractionSuccess:
|
||||||
user.interactionSuccessHandler(evt)
|
user.interactionSuccessHandler(evt)
|
||||||
|
case *discordgo.ThreadListSync:
|
||||||
|
user.threadListSyncHandler(evt)
|
||||||
case *discordgo.Event:
|
case *discordgo.Event:
|
||||||
// Ignore
|
// Ignore
|
||||||
default:
|
default:
|
||||||
|
@ -1038,6 +1041,30 @@ func (user *User) guildUpdateHandler(g *discordgo.GuildUpdate) {
|
||||||
user.handleGuild(g.Guild, time.Now(), user.IsInSpace(g.ID))
|
user.handleGuild(g.Guild, time.Now(), user.IsInSpace(g.ID))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (user *User) threadListSyncHandler(t *discordgo.ThreadListSync) {
|
||||||
|
for _, meta := range t.Threads {
|
||||||
|
log := user.log.With().
|
||||||
|
Str("action", "thread list sync").
|
||||||
|
Str("guild_id", t.GuildID).
|
||||||
|
Str("parent_id", meta.ParentID).
|
||||||
|
Str("thread_id", meta.ID).
|
||||||
|
Logger()
|
||||||
|
ctx := log.WithContext(context.Background())
|
||||||
|
thread := user.bridge.GetThreadByID(meta.ID, nil)
|
||||||
|
if thread == nil {
|
||||||
|
msg := user.bridge.DB.Message.GetByDiscordID(database.NewPortalKey(meta.ParentID, ""), meta.ID)
|
||||||
|
if len(msg) == 0 {
|
||||||
|
log.Debug().Msg("Found unknown thread in thread list sync and don't have message")
|
||||||
|
} else {
|
||||||
|
log.Debug().Msg("Found unknown thread in thread list sync for existing message, creating thread")
|
||||||
|
user.bridge.threadFound(ctx, user, msg[0], meta.ID, meta)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
thread.Parent.ForwardBackfillMissed(user, meta.LastMessageID, thread)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (user *User) channelCreateHandler(c *discordgo.ChannelCreate) {
|
func (user *User) channelCreateHandler(c *discordgo.ChannelCreate) {
|
||||||
if user.getGuildBridgingMode(c.GuildID) < database.GuildBridgeEverything {
|
if user.getGuildBridgingMode(c.GuildID) < database.GuildBridgeEverything {
|
||||||
user.log.Debug().
|
user.log.Debug().
|
||||||
|
|
Loading…
Reference in a new issue