Backfill reactions when using hungryserv

This commit is contained in:
Tulir Asokan 2022-09-28 15:07:09 +03:00
parent 93cbbb7f93
commit 7a6c4d53d3
2 changed files with 83 additions and 6 deletions

View file

@ -22,6 +22,8 @@ import (
"fmt"
"time"
"maunium.net/go/mautrix/util/variationselector"
waProto "go.mau.fi/whatsmeow/binary/proto"
"go.mau.fi/whatsmeow/types"
@ -43,6 +45,8 @@ type wrappedInfo struct {
Type database.MessageType
Error database.MessageErrorType
ReactionTarget types.MessageID
MediaKey []byte
ExpirationStart uint64
@ -570,7 +574,7 @@ func (portal *Portal) backfill(source *User, messages []*waProto.WebMessageInfo,
if converted.ReplyTo != nil {
portal.SetReply(converted.Content, converted.ReplyTo, true)
}
err = portal.appendBatchEvents(converted, &msgEvt.Info, webMsg.GetEphemeralStartTimestamp(), &req.Events, &infos)
err = portal.appendBatchEvents(source, converted, &msgEvt.Info, webMsg, &req.Events, &infos)
if err != nil {
portal.log.Errorfln("Error handling message %s during backfill: %v", msgEvt.Info.ID, err)
}
@ -638,7 +642,7 @@ func (portal *Portal) requestMediaRetries(source *User, eventIDs []id.EventID, i
}
}
func (portal *Portal) appendBatchEvents(converted *ConvertedMessage, info *types.MessageInfo, expirationStart uint64, eventsArray *[]*event.Event, infoArray *[]*wrappedInfo) error {
func (portal *Portal) appendBatchEvents(source *User, converted *ConvertedMessage, info *types.MessageInfo, raw *waProto.WebMessageInfo, eventsArray *[]*event.Event, infoArray *[]*wrappedInfo) error {
mainEvt, err := portal.wrapBatchEvent(info, converted.Intent, converted.Type, converted.Content, converted.Extra, "")
if err != nil {
return err
@ -646,16 +650,25 @@ func (portal *Portal) appendBatchEvents(converted *ConvertedMessage, info *types
if portal.bridge.Config.Bridge.CaptionInMessage {
converted.MergeCaption()
}
expirationStart := raw.GetEphemeralStartTimestamp()
mainInfo := &wrappedInfo{
MessageInfo: info,
Type: database.MsgNormal,
Error: converted.Error,
MediaKey: converted.MediaKey,
ExpirationStart: expirationStart,
ExpiresIn: converted.ExpiresIn,
}
if converted.Caption != nil {
captionEvt, err := portal.wrapBatchEvent(info, converted.Intent, converted.Type, converted.Caption, nil, "caption")
if err != nil {
return err
}
*eventsArray = append(*eventsArray, mainEvt, captionEvt)
*infoArray = append(*infoArray, &wrappedInfo{info, database.MsgNormal, converted.Error, converted.MediaKey, expirationStart, converted.ExpiresIn}, nil)
*infoArray = append(*infoArray, mainInfo, nil)
} else {
*eventsArray = append(*eventsArray, mainEvt)
*infoArray = append(*infoArray, &wrappedInfo{info, database.MsgNormal, converted.Error, converted.MediaKey, expirationStart, converted.ExpiresIn})
*infoArray = append(*infoArray, mainInfo)
}
if converted.MultiEvent != nil {
for i, subEvtContent := range converted.MultiEvent {
@ -667,9 +680,70 @@ func (portal *Portal) appendBatchEvents(converted *ConvertedMessage, info *types
*infoArray = append(*infoArray, nil)
}
}
// Sending reactions in the same batch requires deterministic event IDs, so only do it on hungryserv
if portal.bridge.Config.Homeserver.Software == bridgeconfig.SoftwareHungry {
for _, reaction := range raw.GetReactions() {
reactionEvent, reactionInfo := portal.wrapBatchReaction(source, reaction, mainEvt.ID, info.Timestamp)
if reactionEvent != nil {
*eventsArray = append(*eventsArray, reactionEvent)
*infoArray = append(*infoArray, &wrappedInfo{
MessageInfo: reactionInfo,
ReactionTarget: info.ID,
Type: database.MsgReaction,
})
}
}
}
return nil
}
func (portal *Portal) wrapBatchReaction(source *User, reaction *waProto.Reaction, mainEventID id.EventID, mainEventTS time.Time) (reactionEvent *event.Event, reactionInfo *types.MessageInfo) {
var senderJID types.JID
if reaction.GetKey().GetFromMe() {
senderJID = source.JID.ToNonAD()
} else if reaction.GetKey().GetParticipant() != "" {
senderJID, _ = types.ParseJID(reaction.GetKey().GetParticipant())
} else if portal.IsPrivateChat() {
senderJID = portal.Key.JID
}
if senderJID.IsEmpty() {
return
}
reactionInfo = &types.MessageInfo{
MessageSource: types.MessageSource{
Chat: portal.Key.JID,
Sender: senderJID,
IsFromMe: reaction.GetKey().GetFromMe(),
IsGroup: portal.IsGroupChat(),
},
ID: reaction.GetKey().GetId(),
Timestamp: mainEventTS,
}
puppet := portal.getMessagePuppet(source, reactionInfo)
if puppet == nil {
return
}
intent := puppet.IntentFor(portal)
content := event.ReactionEventContent{
RelatesTo: event.RelatesTo{
Type: event.RelAnnotation,
EventID: mainEventID,
Key: variationselector.Add(reaction.GetText()),
},
}
if rawTS := reaction.GetSenderTimestampMs(); rawTS >= mainEventTS.UnixMilli() && rawTS <= time.Now().UnixMilli() {
reactionInfo.Timestamp = time.UnixMilli(rawTS)
}
reactionEvent = &event.Event{
ID: portal.deterministicEventID(senderJID, reactionInfo.ID, ""),
Type: event.EventReaction,
Content: event.Content{Parsed: content},
Sender: intent.UserID,
Timestamp: reactionInfo.Timestamp.UnixMilli(),
}
return
}
func (portal *Portal) wrapBatchEvent(info *types.MessageInfo, intent *appservice.IntentAPI, eventType event.Type, content *event.MessageEventContent, extraContent map[string]interface{}, partName string) (*event.Event, error) {
wrappedContent := event.Content{
Parsed: content,
@ -704,6 +778,9 @@ func (portal *Portal) finishBatch(txn dbutil.Transaction, eventIDs []id.EventID,
eventID := eventIDs[i]
portal.markHandled(txn, nil, info.MessageInfo, eventID, true, false, info.Type, info.Error)
if info.Type == database.MsgReaction {
portal.upsertReaction(nil, info.ReactionTarget, info.Sender, eventID, info.ID)
}
if info.ExpiresIn > 0 {
if info.ExpirationStart > 0 {

View file

@ -828,7 +828,7 @@ func (portal *Portal) getMessagePuppet(user *User, info *types.MessageInfo) (pup
return portal.bridge.GetPuppetByJID(user.JID)
} else if portal.IsPrivateChat() {
puppet = portal.bridge.GetPuppetByJID(portal.Key.JID)
} else {
} else if !info.Sender.IsEmpty() {
puppet = portal.bridge.GetPuppetByJID(info.Sender)
}
if puppet == nil {
@ -3465,7 +3465,7 @@ func (portal *Portal) upsertReaction(intent *appservice.IntentAPI, targetJID typ
dbReaction.Chat = portal.Key
dbReaction.TargetJID = targetJID
dbReaction.Sender = senderJID
} else {
} else if intent != nil {
portal.log.Debugfln("Redacting old Matrix reaction %s after new one (%s) was sent", dbReaction.MXID, mxid)
var err error
if intent != nil {