diff --git a/backfill.go b/backfill.go index f25df2d..962de1d 100644 --- a/backfill.go +++ b/backfill.go @@ -43,7 +43,7 @@ func (portal *Portal) initialForwardBackfill(user *User, markRead bool) { portal.forwardBackfill(ctx, user, time.Time{}, 50, markRead) } -func (portal *Portal) missedForwardBackfill(user *User, lastMessageTS time.Time, lastMessageID string, markRead bool) { +func (portal *Portal) missedForwardBackfill(user *User, lastMessageTS time.Time, lastMessageID string, markRead bool) bool { portal.forwardBackfillLock.Lock() defer portal.forwardBackfillLock.Unlock() log := portal.zlog.With(). @@ -55,7 +55,7 @@ func (portal *Portal) missedForwardBackfill(user *User, lastMessageTS time.Time, lastMsg, err := portal.bridge.DB.Message.GetLastInChat(ctx, portal.Key) if err != nil { log.Err(err).Msg("Failed to get last message in chat") - return + return false } else if lastMsg == nil { log.Debug().Msg("No messages in chat") } else { @@ -68,7 +68,7 @@ func (portal *Portal) missedForwardBackfill(user *User, lastMessageTS time.Time, Str("latest_message_id", lastMessageID). Time("last_bridged_ts", portal.lastMessageTS). Msg("Nothing to backfill") - return + return false } } log.Info(). @@ -76,7 +76,7 @@ func (portal *Portal) missedForwardBackfill(user *User, lastMessageTS time.Time, Str("latest_message_id", lastMessageID). Time("last_bridged_ts", portal.lastMessageTS). Msg("Backfilling missed messages") - portal.forwardBackfill(ctx, user, portal.lastMessageTS, 100, markRead) + return portal.forwardBackfill(ctx, user, portal.lastMessageTS, 100, markRead) } func (portal *Portal) deterministicEventID(messageID string, part int) id.EventID { @@ -85,12 +85,12 @@ func (portal *Portal) deterministicEventID(messageID string, part int) id.EventI return id.EventID(fmt.Sprintf("$%s:messages.google.com", base64.RawURLEncoding.EncodeToString(sum[:]))) } -func (portal *Portal) forwardBackfill(ctx context.Context, user *User, after time.Time, limit int64, markRead bool) { +func (portal *Portal) forwardBackfill(ctx context.Context, user *User, after time.Time, limit int64, markRead bool) bool { log := zerolog.Ctx(ctx) resp, err := user.Client.FetchMessages(portal.ID, limit, nil) if err != nil { portal.zlog.Error().Err(err).Msg("Failed to fetch messages") - return + return false } log.Debug(). Int64("total_messages", resp.TotalMessages). @@ -119,7 +119,7 @@ func (portal *Portal) forwardBackfill(ctx context.Context, user *User, after tim } if len(converted) == 0 { log.Debug().Msg("Didn't get any converted messages") - return + return false } log.Debug(). Int("converted_count", len(converted)). @@ -141,6 +141,7 @@ func (portal *Portal) forwardBackfill(ctx context.Context, user *User, after tim } } portal.lastMessageTS = maxTS + return true } func (portal *Portal) backfillSendBatch(ctx context.Context, converted []*ConvertedMessage, markReadBy id.UserID) { diff --git a/user.go b/user.go index 4fdb477..7df9545 100644 --- a/user.go +++ b/user.go @@ -718,8 +718,12 @@ func (user *User) syncConversation(v *gmproto.Conversation) { portal.Cleanup(false) default: portal.UpdateMetadata(user, v) - portal.missedForwardBackfill(user, time.UnixMicro(v.LastMessageTimestamp), v.LatestMessageID, !v.GetUnread()) - // TODO sync read status if there was nothing backfilled + didBackfill := portal.missedForwardBackfill(user, time.UnixMicro(v.LastMessageTimestamp), v.LatestMessageID, !v.GetUnread()) + user.syncChatDoublePuppetDetails(portal, v, false) + if !didBackfill && !v.GetUnread() && v.LatestMessageID != "" && user.DoublePuppetIntent != nil { + // TODO this would spam a lot of read receipts on startup + //user.markSelfReadFull(portal, v.LatestMessageID) + } } } else if updateType == gmproto.ConvUpdateTypes_UNARCHIVED || updateType == gmproto.ConvUpdateTypes_ARCHIVED { err := portal.CreateMatrixRoom(user, v) @@ -797,14 +801,46 @@ type CustomReadMarkers struct { FullyReadExtra CustomReadReceipt `json:"com.beeper.fully_read.extra"` } +func (user *User) markSelfReadFull(portal *Portal, lastMessageID string) { + ctx := context.TODO() + lastMessage, err := user.bridge.DB.Message.GetByID(ctx, portal.Key, lastMessageID) + if err == nil && lastMessage == nil { + lastMessage, err = user.bridge.DB.Message.GetLastInChat(ctx, portal.Key) + } + if err != nil { + user.zlog.Warn().Err(err).Msg("Failed to get last message in chat to mark it as read") + return + } else if lastMessage == nil { + return + } + log := user.zlog.With(). + Str("conversation_id", portal.ID). + Str("message_id", lastMessage.ID). + Str("room_id", portal.ID). + Str("event_id", lastMessage.MXID.String()). + Logger() + err = user.DoublePuppetIntent.SetReadMarkers(portal.MXID, &CustomReadMarkers{ + ReqSetReadMarkers: mautrix.ReqSetReadMarkers{ + Read: lastMessage.MXID, + FullyRead: lastMessage.MXID, + }, + ReadExtra: CustomReadReceipt{DoublePuppetSource: user.bridge.Name}, + FullyReadExtra: CustomReadReceipt{DoublePuppetSource: user.bridge.Name}, + }) + if err != nil { + log.Warn().Err(err).Msg("Failed to mark last message in chat as read") + } else { + log.Debug().Msg("Marked last message in chat as read") + } +} + func (user *User) syncChatDoublePuppetDetails(portal *Portal, conv *gmproto.Conversation, justCreated bool) { if user.DoublePuppetIntent == nil || len(portal.MXID) == 0 { return } if justCreated || !user.bridge.Config.Bridge.TagOnlyOnCreate { - //user.updateChatMute(portal, chat.MutedUntil) - //user.updateChatTag(portal, user.bridge.Config.Bridge.ArchiveTag, conv.Status == 2) - //user.updateChatTag(portal, user.bridge.Config.Bridge.PinnedTag, chat.Pinned) + user.updateChatTag(portal, user.bridge.Config.Bridge.ArchiveTag, conv.Status == gmproto.ConvUpdateTypes_ARCHIVED) + user.updateChatTag(portal, user.bridge.Config.Bridge.PinnedTag, conv.Pinned) } }