From b37b509c67a218c0626e263ba048d555f88f9b0c Mon Sep 17 00:00:00 2001 From: Nick Mills-Barrett Date: Mon, 5 Jan 2026 14:37:38 +0000 Subject: [PATCH] connector: update DM user or group info on chat view --- pkg/connector/chatinfo.go | 9 +++++- pkg/connector/handlematrix.go | 54 +++++++++++++++++++++++++++++------ pkg/connector/userinfo.go | 2 ++ pkg/metaid/dbmeta.go | 7 ++++- 4 files changed, 62 insertions(+), 10 deletions(-) diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 317b8e2d..e47b85b5 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -7,6 +7,7 @@ import ( "github.com/rs/zerolog" "github.com/rs/zerolog/log" + "go.mau.fi/util/jsontime" "go.mau.fi/util/ptr" "go.mau.fi/whatsmeow/types" "maunium.net/go/mautrix/bridgev2" @@ -107,7 +108,7 @@ func (m *MetaClient) wrapWAGroupInfo(chatInfo *types.GroupInfo) *bridgev2.ChatIn Type: ptr.Ptr(database.RoomTypeDefault), Disappear: &disappear, CanBackfill: false, - ExtraUpdates: updateServerAndThreadType(chatInfo.JID, table.ENCRYPTED_OVER_WA_GROUP), + ExtraUpdates: bridgev2.MergeExtraUpdaters(updateServerAndThreadType(chatInfo.JID, table.ENCRYPTED_OVER_WA_GROUP), updatePortalSyncMeta), } } @@ -126,6 +127,12 @@ func updateServerAndThreadType(jid types.JID, threadType table.ThreadType) func( } } +func updatePortalSyncMeta(ctx context.Context, portal *bridgev2.Portal) bool { + meta := portal.Metadata.(*metaid.PortalMetadata) + meta.LastSync = jsontime.UnixNow() + return true +} + func (m *MetaClient) makeMinimalChatInfo(threadID int64, threadType table.ThreadType) *bridgev2.ChatInfo { selfEvtSender := m.selfEventSender() members := &bridgev2.ChatMemberList{ diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index b723314d..30f6aa09 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -17,6 +17,7 @@ import ( "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/database" "maunium.net/go/mautrix/bridgev2/networkid" + "maunium.net/go/mautrix/bridgev2/simplevent" "maunium.net/go/mautrix/event" "maunium.net/go/mautrix/id" @@ -564,11 +565,51 @@ func (m *MetaClient) HandleMatrixReadReceipt(ctx context.Context, receipt *bridg return nil } -// Note: the handling of typing notifications for facebook E2EE is -// very similar to the handling of typing notifications in the -// whatsapp bridge, because they both use the same API. +// When to trigger user/group refresh on chat view +var ViewChatUserInfoRefreshInterval = 5 * time.Minute +var ViewChatGroupInfoRefreshInterval = 24 * time.Hour func (m *MetaClient) HandleMatrixViewingChat(ctx context.Context, msg *bridgev2.MatrixViewingChat) error { + if msg.Portal == nil { + return nil + } + + // Sync the other users ghost in DMs + if msg.Portal.OtherUserID != "" { + ghost, err := m.Main.Bridge.GetExistingGhostByID(ctx, msg.Portal.OtherUserID) + if err != nil { + return fmt.Errorf("failed to get ghost for sync: %w", err) + } else if ghost == nil { + zerolog.Ctx(ctx).Warn(). + Str("other_user_id", string(msg.Portal.OtherUserID)). + Msg("No ghost found for other user in portal") + } else { + meta := ghost.Metadata.(*metaid.GhostMetadata) + if meta.ProfileFetchedAt.Time.Add(ViewChatUserInfoRefreshInterval).Before(time.Now()) { + info, err := m.GetUserInfo(ctx, ghost) + if err != nil { + return fmt.Errorf("failed to get user info: %w", err) + } + ghost.UpdateInfo(ctx, info) + } + } + } + + // always resync the portal if its stale + portalMeta := msg.Portal.Metadata.(*metaid.PortalMetadata) + if portalMeta.LastSync.Add(ViewChatGroupInfoRefreshInterval).Before(time.Now()) { + m.UserLogin.QueueRemoteEvent(&simplevent.ChatResync{ + EventMeta: simplevent.EventMeta{ + Type: bridgev2.RemoteEventChatResync, + PortalKey: msg.Portal.PortalKey, + }, + GetChatInfoFunc: m.GetChatInfo, + }) + } + + // Note: the handling of typing notifications for facebook E2EE is + // very similar to the handling of typing notifications in the + // whatsapp bridge, because they both use the same API. if m.E2EEClient == nil { return nil } @@ -578,11 +619,8 @@ func (m *MetaClient) HandleMatrixViewingChat(ctx context.Context, msg *bridgev2. // therefore we need to set online status for typing // notifications to work properly. presence := waTypes.PresenceUnavailable - if msg.Portal != nil { - portalMeta := msg.Portal.Metadata.(*metaid.PortalMetadata) - if portalMeta.ThreadType.IsWhatsApp() { - presence = waTypes.PresenceAvailable - } + if portalMeta.ThreadType.IsWhatsApp() { + presence = waTypes.PresenceAvailable } if m.waLastPresence != presence { diff --git a/pkg/connector/userinfo.go b/pkg/connector/userinfo.go index add4161e..fc737525 100644 --- a/pkg/connector/userinfo.go +++ b/pkg/connector/userinfo.go @@ -5,6 +5,7 @@ import ( "fmt" "net/url" "path" + "time" "github.com/rs/zerolog" "go.mau.fi/util/ptr" @@ -118,6 +119,7 @@ func (m *MetaClient) wrapUserInfo(info types.UserInfo) *bridgev2.UserInfo { IsBot: ptr.Ptr(info.GetFBID() == MetaAIInstagramID || info.GetFBID() == MetaAIMessengerID), // TODO do this in a less hardcoded way? ExtraUpdates: func(ctx context.Context, ghost *bridgev2.Ghost) (changed bool) { meta := ghost.Metadata.(*metaid.GhostMetadata) + meta.ProfileFetchedAt.Time = time.Now() if m.LoginMeta.Platform == types.Instagram && meta.Username != info.GetUsername() { meta.Username = info.GetUsername() changed = true diff --git a/pkg/metaid/dbmeta.go b/pkg/metaid/dbmeta.go index 14996531..e44ffe2c 100644 --- a/pkg/metaid/dbmeta.go +++ b/pkg/metaid/dbmeta.go @@ -7,6 +7,7 @@ import ( "sync/atomic" "go.mau.fi/util/exerrors" + "go.mau.fi/util/jsontime" "go.mau.fi/util/random" waTypes "go.mau.fi/whatsmeow/types" "maunium.net/go/mautrix/bridgev2/networkid" @@ -22,7 +23,8 @@ type MessageMetadata struct { } type GhostMetadata struct { - Username string `json:"username,omitempty"` + Username string `json:"username,omitempty"` + ProfileFetchedAt jsontime.UnixMilli `json:"profile_fetched_at"` } type UserLoginMetadata struct { @@ -55,6 +57,9 @@ type PortalMetadata struct { EphemeralSettingTimestamp int64 `json:"ephemeral_setting_timestamp,omitempty"` FetchAttempted atomic.Bool `json:"-"` + + // Lazy resync tracking + LastSync jsontime.Unix `json:"last_sync,omitempty"` } func (meta *PortalMetadata) JID(id networkid.PortalID) waTypes.JID {