bridgev2/portal: include room id in cross-room replies
Some checks failed
Go / Lint (latest) (push) Has been cancelled
Go / Build (old, libolm) (push) Has been cancelled
Go / Build (latest, libolm) (push) Has been cancelled
Go / Build (old, goolm) (push) Has been cancelled
Go / Build (latest, goolm) (push) Has been cancelled

This commit is contained in:
Tulir Asokan 2025-06-08 00:12:53 +03:00
commit 07567f6f96
6 changed files with 44 additions and 6 deletions

View file

@ -72,6 +72,7 @@ type BridgeConfig struct {
OnlyBridgeTags []event.RoomTag `yaml:"only_bridge_tags"`
MuteOnlyOnCreate bool `yaml:"mute_only_on_create"`
DeduplicateMatrixMessages bool `yaml:"deduplicate_matrix_messages"`
CrossRoomReplies bool `yaml:"cross_room_replies"`
OutgoingMessageReID bool `yaml:"outgoing_message_re_id"`
CleanupOnLogout CleanupOnLogouts `yaml:"cleanup_on_logout"`
Relay RelayConfig `yaml:"relay"`

View file

@ -38,6 +38,7 @@ func doUpgrade(helper up.Helper) {
helper.Copy(up.List, "bridge", "only_bridge_tags")
helper.Copy(up.Bool, "bridge", "mute_only_on_create")
helper.Copy(up.Bool, "bridge", "deduplicate_matrix_messages")
helper.Copy(up.Bool, "bridge", "cross_room_replies")
helper.Copy(up.Bool, "bridge", "cleanup_on_logout", "enabled")
helper.Copy(up.Str, "bridge", "cleanup_on_logout", "manual", "private")
helper.Copy(up.Str, "bridge", "cleanup_on_logout", "manual", "relayed")

View file

@ -40,6 +40,9 @@ bridge:
mute_only_on_create: true
# Should the bridge check the db to ensure that incoming events haven't been handled before
deduplicate_matrix_messages: false
# Should cross-room reply metadata be bridged?
# Most Matrix clients don't support this and servers may reject such messages too.
cross_room_replies: false
# What should be done to portal rooms when a user logs out or is logged out?
# Permitted values:

View file

@ -1943,7 +1943,7 @@ func (portal *Portal) getRelationMeta(ctx context.Context, currentMsg networkid.
return
}
func (portal *Portal) applyRelationMeta(content *event.MessageEventContent, replyTo, threadRoot, prevThreadEvent *database.Message) {
func (portal *Portal) applyRelationMeta(ctx context.Context, content *event.MessageEventContent, replyTo, threadRoot, prevThreadEvent *database.Message) {
if content.Mentions == nil {
content.Mentions = &event.Mentions{}
}
@ -1951,7 +1951,24 @@ func (portal *Portal) applyRelationMeta(content *event.MessageEventContent, repl
content.GetRelatesTo().SetThread(threadRoot.MXID, prevThreadEvent.MXID)
}
if replyTo != nil {
content.GetRelatesTo().SetReplyTo(replyTo.MXID)
crossRoom := replyTo.Room != portal.PortalKey
if !crossRoom || portal.Bridge.Config.CrossRoomReplies {
content.GetRelatesTo().SetReplyTo(replyTo.MXID)
}
if crossRoom && portal.Bridge.Config.CrossRoomReplies {
targetPortal, err := portal.Bridge.GetExistingPortalByKey(ctx, replyTo.Room)
if err != nil {
zerolog.Ctx(ctx).Err(err).
Object("target_portal_key", replyTo.Room).
Msg("Failed to get cross-room reply portal")
} else if targetPortal == nil || targetPortal.MXID == "" {
zerolog.Ctx(ctx).Warn().
Object("target_portal_key", replyTo.Room).
Msg("Cross-room reply portal not found")
} else {
content.RelatesTo.InReplyTo.UnstableRoomID = targetPortal.MXID
}
}
content.Mentions.Add(replyTo.SenderMXID)
}
}
@ -1975,7 +1992,7 @@ func (portal *Portal) sendConvertedMessage(
replyTo, threadRoot, prevThreadEvent := portal.getRelationMeta(ctx, id, converted.ReplyTo, converted.ThreadRoot, false)
output := make([]*database.Message, 0, len(converted.Parts))
for i, part := range converted.Parts {
portal.applyRelationMeta(part.Content, replyTo, threadRoot, prevThreadEvent)
portal.applyRelationMeta(ctx, part.Content, replyTo, threadRoot, prevThreadEvent)
dbMessage := &database.Message{
ID: id,
PartID: part.ID,

View file

@ -333,7 +333,7 @@ func (portal *Portal) compileBatchMessage(ctx context.Context, source *UserLogin
var firstPart *database.Message
for i, part := range msg.Parts {
partIDs = append(partIDs, part.ID)
portal.applyRelationMeta(part.Content, replyTo, threadRoot, prevThreadEvent)
portal.applyRelationMeta(ctx, part.Content, replyTo, threadRoot, prevThreadEvent)
evtID := portal.Bridge.Matrix.GenerateDeterministicEventID(portal.MXID, portal.PortalKey, msg.ID, part.ID)
dbMessage := &database.Message{
ID: msg.ID,

View file

@ -89,10 +89,22 @@ func (portal *PortalInternals) CheckMessageContentCaps(ctx context.Context, caps
return (*Portal)(portal).checkMessageContentCaps(ctx, caps, content, evt)
}
func (portal *PortalInternals) ParseInputTransactionID(origSender *OrigSender, evt *event.Event) networkid.RawTransactionID {
return (*Portal)(portal).parseInputTransactionID(origSender, evt)
}
func (portal *PortalInternals) HandleMatrixMessage(ctx context.Context, sender *UserLogin, origSender *OrigSender, evt *event.Event) {
(*Portal)(portal).handleMatrixMessage(ctx, sender, origSender, evt)
}
func (portal *PortalInternals) PendingMessageTimeoutLoop(ctx context.Context, cfg *OutgoingTimeoutConfig) {
(*Portal)(portal).pendingMessageTimeoutLoop(ctx, cfg)
}
func (portal *PortalInternals) CheckPendingMessages(ctx context.Context, cfg *OutgoingTimeoutConfig) {
(*Portal)(portal).checkPendingMessages(ctx, cfg)
}
func (portal *PortalInternals) HandleMatrixEdit(ctx context.Context, sender *UserLogin, origSender *OrigSender, evt *event.Event, content *event.MessageEventContent, caps *event.RoomFeatures) {
(*Portal)(portal).handleMatrixEdit(ctx, sender, origSender, evt, content, caps)
}
@ -129,8 +141,8 @@ func (portal *PortalInternals) GetRelationMeta(ctx context.Context, currentMsg n
return (*Portal)(portal).getRelationMeta(ctx, currentMsg, replyToPtr, threadRootPtr, isBatchSend)
}
func (portal *PortalInternals) ApplyRelationMeta(content *event.MessageEventContent, replyTo, threadRoot, prevThreadEvent *database.Message) {
(*Portal)(portal).applyRelationMeta(content, replyTo, threadRoot, prevThreadEvent)
func (portal *PortalInternals) ApplyRelationMeta(ctx context.Context, content *event.MessageEventContent, replyTo, threadRoot, prevThreadEvent *database.Message) {
(*Portal)(portal).applyRelationMeta(ctx, content, replyTo, threadRoot, prevThreadEvent)
}
func (portal *PortalInternals) SendConvertedMessage(ctx context.Context, id networkid.MessageID, intent MatrixAPI, senderID networkid.UserID, converted *ConvertedMessage, ts time.Time, streamOrder int64, logContext func(*zerolog.Event) *zerolog.Event) []*database.Message {
@ -241,6 +253,10 @@ func (portal *PortalInternals) UpdateAvatar(ctx context.Context, avatar *Avatar,
return (*Portal)(portal).updateAvatar(ctx, avatar, sender, ts)
}
func (portal *PortalInternals) GetBridgeInfoStateKey() string {
return (*Portal)(portal).getBridgeInfoStateKey()
}
func (portal *PortalInternals) GetBridgeInfo() (string, event.BridgeEventContent) {
return (*Portal)(portal).getBridgeInfo()
}