diff --git a/bridgev2/matrixinterface.go b/bridgev2/matrixinterface.go index 4ccba353..ae1b99d7 100644 --- a/bridgev2/matrixinterface.go +++ b/bridgev2/matrixinterface.go @@ -171,6 +171,10 @@ type MatrixAPI interface { MuteRoom(ctx context.Context, roomID id.RoomID, until time.Time) error } +type StreamOrderReadingMatrixAPI interface { + MarkStreamOrderRead(ctx context.Context, roomID id.RoomID, streamOrder int64, ts time.Time) error +} + type MarkAsDMMatrixAPI interface { MarkAsDM(ctx context.Context, roomID id.RoomID, otherUser id.UserID) error } diff --git a/bridgev2/networkinterface.go b/bridgev2/networkinterface.go index 14e3a681..14db58d6 100644 --- a/bridgev2/networkinterface.go +++ b/bridgev2/networkinterface.go @@ -1117,6 +1117,11 @@ type RemoteReadReceipt interface { GetReadUpTo() time.Time } +type RemoteReadReceiptWithStreamOrder interface { + RemoteReadReceipt + GetReadUpToStreamOrder() int64 +} + type RemoteDeliveryReceipt interface { RemoteEvent GetReceiptTargets() []networkid.MessageID diff --git a/bridgev2/portal.go b/bridgev2/portal.go index 63081f57..d5d82f03 100644 --- a/bridgev2/portal.go +++ b/bridgev2/portal.go @@ -2693,17 +2693,31 @@ func (portal *Portal) handleRemoteReadReceipt(ctx context.Context, source *UserL log.Err(err).Time("read_up_to", readUpTo).Msg("Failed to get target message for read receipt") } } - if lastTarget == nil { - log.Warn().Msg("No target message found for read receipt") - return - } sender := evt.GetSender() intent := portal.GetIntentFor(ctx, sender, source, RemoteEventReadReceipt) - err = intent.MarkRead(ctx, portal.MXID, lastTarget.MXID, getEventTS(evt)) + var addTargetLog func(evt *zerolog.Event) *zerolog.Event + if lastTarget == nil { + sevt, evtOK := evt.(RemoteReadReceiptWithStreamOrder) + soIntent, soIntentOK := intent.(StreamOrderReadingMatrixAPI) + if !evtOK || !soIntentOK || sevt.GetReadUpToStreamOrder() == 0 { + log.Warn().Msg("No target message found for read receipt") + return + } + targetStreamOrder := sevt.GetReadUpToStreamOrder() + addTargetLog = func(evt *zerolog.Event) *zerolog.Event { + return evt.Int64("target_stream_order", targetStreamOrder) + } + err = soIntent.MarkStreamOrderRead(ctx, portal.MXID, targetStreamOrder, getEventTS(evt)) + } else { + addTargetLog = func(evt *zerolog.Event) *zerolog.Event { + return evt.Stringer("target_mxid", lastTarget.MXID) + } + err = intent.MarkRead(ctx, portal.MXID, lastTarget.MXID, getEventTS(evt)) + } if err != nil { - log.Err(err).Stringer("target_mxid", lastTarget.MXID).Msg("Failed to bridge read receipt") + addTargetLog(log.Err(err)).Msg("Failed to bridge read receipt") } else { - log.Debug().Stringer("target_mxid", lastTarget.MXID).Msg("Bridged read receipt") + addTargetLog(log.Debug()).Msg("Bridged read receipt") } if sender.IsFromMe { portal.Bridge.DisappearLoop.StartAll(ctx, portal.MXID) diff --git a/bridgev2/simplevent/receipt.go b/bridgev2/simplevent/receipt.go index 3565986b..41614e40 100644 --- a/bridgev2/simplevent/receipt.go +++ b/bridgev2/simplevent/receipt.go @@ -19,6 +19,8 @@ type Receipt struct { LastTarget networkid.MessageID Targets []networkid.MessageID ReadUpTo time.Time + + ReadUpToStreamOrder int64 } var ( @@ -38,6 +40,10 @@ func (evt *Receipt) GetReadUpTo() time.Time { return evt.ReadUpTo } +func (evt *Receipt) GetReadUpToStreamOrder() int64 { + return evt.ReadUpToStreamOrder +} + type MarkUnread struct { EventMeta Unread bool