diff --git a/pkg/connector/backfill.go b/pkg/connector/backfill.go index a0b8fc06..11bed9f6 100644 --- a/pkg/connector/backfill.go +++ b/pkg/connector/backfill.go @@ -40,74 +40,74 @@ var ( ) // getTakeoutID blocks until the takeout ID is available. -func (t *TelegramClient) getTakeoutID(ctx context.Context) (takeoutID int64, err error) { +func (tc *TelegramClient) getTakeoutID(ctx context.Context) (takeoutID int64, err error) { // Always stop the takeout timeout timer - if t.stopTakeoutTimer != nil { - t.stopTakeoutTimer.Stop() + if tc.stopTakeoutTimer != nil { + tc.stopTakeoutTimer.Stop() } log := zerolog.Ctx(ctx).With().Str("function", "getTakeoutID").Logger() - if t.metadata.TakeoutID != 0 { + if tc.metadata.TakeoutID != 0 { // Resume fetching dialogs using takeout and enqueueing them for // backfill. - go t.takeoutDialogsOnce.Do(func() { - if err = t.syncChats(ctx, takeoutID, false, false); err != nil { + go tc.takeoutDialogsOnce.Do(func() { + if err = tc.syncChats(ctx, takeoutID, false, false); err != nil { log.Err(err).Msg("Failed to takeout dialogs") } }) - return t.metadata.TakeoutID, nil + return tc.metadata.TakeoutID, nil } - t.stopTakeoutTimer = time.AfterFunc(max(time.Hour, time.Duration(t.main.Bridge.Config.Backfill.Queue.BatchDelay*2)), sync.OnceFunc(func() { t.stopTakeout(ctx) })) + tc.stopTakeoutTimer = time.AfterFunc(max(time.Hour, time.Duration(tc.main.Bridge.Config.Backfill.Queue.BatchDelay*2)), sync.OnceFunc(func() { tc.stopTakeout(ctx) })) for { - t.takeoutAccepted.Clear() + tc.takeoutAccepted.Clear() - accountTakeout, err := t.client.API().AccountInitTakeoutSession(ctx, &tg.AccountInitTakeoutSessionRequest{ + accountTakeout, err := tc.client.API().AccountInitTakeoutSession(ctx, &tg.AccountInitTakeoutSessionRequest{ MessageUsers: true, MessageChats: true, MessageMegagroups: true, MessageChannels: true, Files: true, - FileMaxSize: min(t.main.maxFileSize, 2000*1024*1024), + FileMaxSize: min(tc.main.maxFileSize, 2000*1024*1024), }) if rpcErr, ok := tgerr.As(err); ok && rpcErr.IsOneOf(tg.ErrTakeoutInitDelay) { log.Warn(). Err(err). Int("delay", rpcErr.Argument). Msg("Takeout requested, will wait for retry request or delay") - t.takeoutAccepted.WaitTimeout(time.Duration(rpcErr.Argument) * time.Second) + tc.takeoutAccepted.WaitTimeout(time.Duration(rpcErr.Argument) * time.Second) continue } else if err != nil { return 0, err } // Fetch all dialogs using takeout and enqueue them for backfill. - go t.takeoutDialogsOnce.Do(func() { - if err = t.syncChats(ctx, takeoutID, false, false); err != nil { + go tc.takeoutDialogsOnce.Do(func() { + if err = tc.syncChats(ctx, takeoutID, false, false); err != nil { log.Err(err).Msg("Failed to takeout dialogs") } }) - t.metadata.TakeoutID = accountTakeout.ID - return accountTakeout.ID, t.userLogin.Save(ctx) + tc.metadata.TakeoutID = accountTakeout.ID + return accountTakeout.ID, tc.userLogin.Save(ctx) } } -func (t *TelegramClient) stopTakeout(ctx context.Context) error { - t.takeoutLock.Lock() - defer t.takeoutLock.Unlock() +func (tc *TelegramClient) stopTakeout(ctx context.Context) error { + tc.takeoutLock.Lock() + defer tc.takeoutLock.Unlock() - _, err := t.client.API().AccountFinishTakeoutSession(ctx, &tg.AccountFinishTakeoutSessionRequest{Success: true}) + _, err := tc.client.API().AccountFinishTakeoutSession(ctx, &tg.AccountFinishTakeoutSessionRequest{Success: true}) if err != nil { return err } - t.metadata.TakeoutID = 0 - return t.userLogin.Save(ctx) + tc.metadata.TakeoutID = 0 + return tc.userLogin.Save(ctx) } -func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2.FetchMessagesParams) (*bridgev2.FetchMessagesResponse, error) { - if t.metadata.IsBot { +func (tc *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2.FetchMessagesParams) (*bridgev2.FetchMessagesResponse, error) { + if tc.metadata.IsBot { return nil, fmt.Errorf("bots cannot backfill messages") } log := zerolog.Ctx(ctx).With().Str("method", "FetchMessages").Logger() @@ -115,26 +115,26 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2 var takeoutID int64 var err error - if (t.main.Config.Takeout.ForwardBackfill && fetchParams.Forward) || (t.main.Config.Takeout.BackwardBackfill && !fetchParams.Forward) { - t.takeoutLock.Lock() - defer t.takeoutLock.Unlock() - takeoutID, err = t.getTakeoutID(ctx) + if (tc.main.Config.Takeout.ForwardBackfill && fetchParams.Forward) || (tc.main.Config.Takeout.BackwardBackfill && !fetchParams.Forward) { + tc.takeoutLock.Lock() + defer tc.takeoutLock.Unlock() + takeoutID, err = tc.getTakeoutID(ctx) if err != nil { return nil, err } if takeoutID != 0 { defer func() { - if t.stopTakeoutTimer == nil { - t.stopTakeoutTimer = time.AfterFunc(max(time.Hour, time.Duration(t.main.Bridge.Config.Backfill.Queue.BatchDelay*2)), sync.OnceFunc(func() { t.stopTakeout(ctx) })) + if tc.stopTakeoutTimer == nil { + tc.stopTakeoutTimer = time.AfterFunc(max(time.Hour, time.Duration(tc.main.Bridge.Config.Backfill.Queue.BatchDelay*2)), sync.OnceFunc(func() { tc.stopTakeout(ctx) })) } else { - t.stopTakeoutTimer.Reset(max(time.Hour, time.Duration(t.main.Bridge.Config.Backfill.Queue.BatchDelay*2))) + tc.stopTakeoutTimer.Reset(max(time.Hour, time.Duration(tc.main.Bridge.Config.Backfill.Queue.BatchDelay*2))) } }() } } - peer, topicID, err := t.inputPeerForPortalID(ctx, fetchParams.Portal.ID) + peer, topicID, err := tc.inputPeerForPortalID(ctx, fetchParams.Portal.ID) if err != nil { return nil, err } @@ -176,10 +176,10 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2 req = &tg.InvokeWithTakeoutRequest{TakeoutID: takeoutID, Query: req} } log.Info().Any("req", req).Msg("Fetching messages") - msgs, err := APICallWithUpdates(ctx, t, func() (tg.ModifiedMessagesMessages, error) { + msgs, err := APICallWithUpdates(ctx, tc, func() (tg.ModifiedMessagesMessages, error) { var box tg.MessagesMessagesBox // TODO a single request can only fetch 100 messages, use multiple requests if the requested count is higher - err = t.client.Invoke(ctx, req, &box) + err = tc.client.Invoke(ctx, req, &box) if err != nil { return nil, err } @@ -191,8 +191,8 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2 }) if err != nil { if tgerr.Is(err, tg.ErrTakeoutInvalid) { - t.metadata.TakeoutID = 0 - err := t.userLogin.Save(ctx) + tc.metadata.TakeoutID = 0 + err := tc.userLogin.Save(ctx) if err != nil { log.Err(err).Msg("Failed to save user login after clearing takeout ID") } else { @@ -248,12 +248,12 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2 continue } - sender := t.getEventSender(message, !portal.Metadata.(*PortalMetadata).IsSuperGroup) - intent, ok := portal.GetIntentFor(ctx, sender, t.userLogin, bridgev2.RemoteEventBackfill) + sender := tc.getEventSender(message, !portal.Metadata.(*PortalMetadata).IsSuperGroup) + intent, ok := portal.GetIntentFor(ctx, sender, tc.userLogin, bridgev2.RemoteEventBackfill) if !ok { continue } - converted, err := t.convertToMatrix(ctx, portal, intent, message) + converted, err := tc.convertToMatrix(ctx, portal, intent, message) if err != nil { return nil, err } @@ -267,7 +267,7 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2 } if reactions, ok := message.GetReactions(); ok { - reactionsList, _, customEmojis, err := t.computeReactionsList(ctx, message.PeerID, message.ID, reactions) + reactionsList, _, customEmojis, err := tc.computeReactionsList(ctx, message.PeerID, message.ID, reactions) if err != nil { return nil, err } @@ -285,7 +285,7 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2 backfillMessage.Reactions = append(backfillMessage.Reactions, &bridgev2.BackfillReaction{ Timestamp: time.Unix(int64(reaction.Date), 0), - Sender: t.senderForUserID(peer.UserID), + Sender: tc.senderForUserID(peer.UserID), EmojiID: emojiID, Emoji: emoji, }) @@ -307,7 +307,7 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2 }, nil } -func (c *TelegramClient) GetBackfillMaxBatchCount(ctx context.Context, portal *bridgev2.Portal, task *database.BackfillTask) int { +func (tc *TelegramClient) GetBackfillMaxBatchCount(ctx context.Context, portal *bridgev2.Portal, task *database.BackfillTask) int { log := zerolog.Ctx(ctx).With(). Str("method", "GetBackfillMaxBatchCount"). Logger() @@ -318,18 +318,18 @@ func (c *TelegramClient) GetBackfillMaxBatchCount(ctx context.Context, portal *b } switch peerType { case ids.PeerTypeUser: - return c.main.Bridge.Config.Backfill.Queue.GetOverride("user") + return tc.main.Bridge.Config.Backfill.Queue.GetOverride("user") case ids.PeerTypeChat: - return c.main.Bridge.Config.Backfill.Queue.GetOverride("normal_group") + return tc.main.Bridge.Config.Backfill.Queue.GetOverride("normal_group") case ids.PeerTypeChannel: if topicID == ids.TopicIDSpaceRoom { return 0 } else if topicID > 0 { - return c.main.Bridge.Config.Backfill.Queue.GetOverride("topic", "supergroup") + return tc.main.Bridge.Config.Backfill.Queue.GetOverride("topic", "supergroup") } else if portal.Metadata.(*PortalMetadata).IsSuperGroup { - return c.main.Bridge.Config.Backfill.Queue.GetOverride("supergroup") + return tc.main.Bridge.Config.Backfill.Queue.GetOverride("supergroup") } else { - return c.main.Bridge.Config.Backfill.Queue.GetOverride("channel") + return tc.main.Bridge.Config.Backfill.Queue.GetOverride("channel") } default: log.Error().Str("peer_type", string(peerType)).Msg("unknown peer type") diff --git a/pkg/connector/capabilities.go b/pkg/connector/capabilities.go index 52f623c4..b306f504 100644 --- a/pkg/connector/capabilities.go +++ b/pkg/connector/capabilities.go @@ -32,7 +32,7 @@ import ( "go.mau.fi/mautrix-telegram/pkg/connector/ids" ) -func (tg *TelegramConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities { +func (tc *TelegramConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities { return &bridgev2.NetworkGeneralCapabilities{ DisappearingMessages: true, Provisioning: bridgev2.ProvisioningCapabilities{ @@ -59,7 +59,7 @@ func (tg *TelegramConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilit } } -func (tg *TelegramConnector) GetBridgeInfoVersion() (info, capabilities int) { +func (tc *TelegramConnector) GetBridgeInfoVersion() (info, capabilities int) { return 1, 8 } @@ -210,7 +210,7 @@ func makeTimerList() []jsontime.Milliseconds { var telegramTimers = makeTimerList() -func (t *TelegramClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *event.RoomFeatures { +func (tc *TelegramClient) GetCapabilities(ctx context.Context, portal *bridgev2.Portal) *event.RoomFeatures { baseID := "fi.mau.telegram.capabilities.2025_11_24" feat := &event.RoomFeatures{ Formatting: formattingCaps, @@ -240,7 +240,7 @@ func (t *TelegramClient) GetCapabilities(ctx context.Context, portal *bridgev2.P reactions := portal.Metadata.(*PortalMetadata).AllowedReactions if reactions == nil { baseID += "+reactions_any" - feat.AllowedReactions, feat.CustomEmojiReactions = t.getAvailableReactionsForCapability(ctx) + feat.AllowedReactions, feat.CustomEmojiReactions = tc.getAvailableReactionsForCapability(ctx) if len(feat.AllowedReactions) > 0 { baseID += "+any_list_" + hashEmojiList(feat.AllowedReactions) } @@ -254,7 +254,7 @@ func (t *TelegramClient) GetCapabilities(ctx context.Context, portal *bridgev2.P for i, react := range feat.AllowedReactions { feat.AllowedReactions[i] = variationselector.Add(react) } - if t.isPremiumCache.Load() { + if tc.isPremiumCache.Load() { baseID += "+premium" feat.File = premiumFileCaps feat.ReactionCount = 3 diff --git a/pkg/connector/chatinfo.go b/pkg/connector/chatinfo.go index 1016e367..2c19526c 100644 --- a/pkg/connector/chatinfo.go +++ b/pkg/connector/chatinfo.go @@ -93,8 +93,8 @@ func adminRightsToPowerLevel(rights tg.ChatAdminRights) *int { return otherPowerLevel } -func (t *TelegramClient) getDMChatInfo(ctx context.Context, userID int64) (*bridgev2.ChatInfo, error) { - ghost, err := t.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(userID)) +func (tc *TelegramClient) getDMChatInfo(ctx context.Context, userID int64) (*bridgev2.ChatInfo, error) { + ghost, err := tc.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(userID)) if err != nil { return nil, err } @@ -104,19 +104,19 @@ func (t *TelegramClient) getDMChatInfo(ctx context.Context, userID int64) (*brid Members: &bridgev2.ChatMemberList{ IsFull: true, MemberMap: map[networkid.UserID]bridgev2.ChatMember{}, - PowerLevels: t.getDMPowerLevels(ghost), + PowerLevels: tc.getDMPowerLevels(ghost), }, - CanBackfill: !t.metadata.IsBot, + CanBackfill: !tc.metadata.IsBot, ExtraUpdates: updatePortalLastSyncAt, } - chatInfo.Members.MemberMap.Add(bridgev2.ChatMember{EventSender: t.mySender()}) - chatInfo.Members.MemberMap.Add(bridgev2.ChatMember{EventSender: t.senderForUserID(userID)}) - if userID == t.telegramUserID { + chatInfo.Members.MemberMap.Add(bridgev2.ChatMember{EventSender: tc.mySender()}) + chatInfo.Members.MemberMap.Add(bridgev2.ChatMember{EventSender: tc.senderForUserID(userID)}) + if userID == tc.telegramUserID { chatInfo.Avatar = &bridgev2.Avatar{ - ID: networkid.AvatarID(t.main.Config.SavedMessagesAvatar), - Remove: len(t.main.Config.SavedMessagesAvatar) == 0, - MXC: t.main.Config.SavedMessagesAvatar, - Hash: sha256.Sum256([]byte(t.main.Config.SavedMessagesAvatar)), + ID: networkid.AvatarID(tc.main.Config.SavedMessagesAvatar), + Remove: len(tc.main.Config.SavedMessagesAvatar) == 0, + MXC: tc.main.Config.SavedMessagesAvatar, + Hash: sha256.Sum256([]byte(tc.main.Config.SavedMessagesAvatar)), } chatInfo.Name = ptr.Ptr("Telegram Saved Messages") chatInfo.Topic = ptr.Ptr("Your Telegram cloud storage chat") @@ -140,10 +140,10 @@ type memberFetchMeta struct { IsForum bool } -func (t *TelegramClient) wrapChatInfo(portalID networkid.PortalID, rawChat tg.ChatClass) (*bridgev2.ChatInfo, *memberFetchMeta, error) { +func (tc *TelegramClient) wrapChatInfo(portalID networkid.PortalID, rawChat tg.ChatClass) (*bridgev2.ChatInfo, *memberFetchMeta, error) { info := bridgev2.ChatInfo{ Type: ptr.Ptr(database.RoomTypeDefault), - CanBackfill: !t.metadata.IsBot, + CanBackfill: !tc.metadata.IsBot, Members: &bridgev2.ChatMemberList{ ExcludeChangesFromTimeline: true, MemberMap: bridgev2.ChatMemberMap{}, @@ -158,8 +158,8 @@ func (t *TelegramClient) wrapChatInfo(portalID networkid.PortalID, rawChat tg.Ch case *tg.Chat: info.Name = &chat.Title info.Members.TotalMemberCount = chat.ParticipantsCount - info.Avatar, avatarErr = t.convertChatPhoto(chat.AsInputPeer(), chat.Photo) - info.Members.PowerLevels = t.getPowerLevelOverridesFromBannedRights(chat, chat.DefaultBannedRights) + info.Avatar, avatarErr = tc.convertChatPhoto(chat.AsInputPeer(), chat.Photo) + info.Members.PowerLevels = tc.getPowerLevelOverridesFromBannedRights(chat, chat.DefaultBannedRights) left = chat.Left if chat.Creator { ownPL = creatorPowerLevel @@ -174,8 +174,8 @@ func (t *TelegramClient) wrapChatInfo(portalID networkid.PortalID, rawChat tg.Ch info.Name = &chat.Title info.Members.TotalMemberCount = chat.ParticipantsCount isMegagroup = chat.Megagroup - info.Avatar, avatarErr = t.convertChatPhoto(chat.AsInputPeer(), chat.Photo) - info.Members.PowerLevels = t.getPowerLevelOverridesFromBannedRights(chat, chat.DefaultBannedRights) + info.Avatar, avatarErr = tc.convertChatPhoto(chat.AsInputPeer(), chat.Photo) + info.Members.PowerLevels = tc.getPowerLevelOverridesFromBannedRights(chat, chat.DefaultBannedRights) if chat.Creator { ownPL = creatorPowerLevel } else if rights, isAdmin := chat.GetAdminRights(); isAdmin { @@ -204,7 +204,7 @@ func (t *TelegramClient) wrapChatInfo(portalID networkid.PortalID, rawChat tg.Ch EventSender: bridgev2.EventSender{Sender: ids.MakeChannelUserID(chat.GetID())}, PowerLevel: superadminPowerLevel, }) - } else if chat.Megagroup && !t.main.Config.ShouldBridge(chat.ParticipantsCount) { + } else if chat.Megagroup && !tc.main.Config.ShouldBridge(chat.ParticipantsCount) { // TODO change this to a better error whenever that is implemented in mautrix-go return nil, nil, fmt.Errorf("too many participants (%d) in chat %d", chat.ParticipantsCount, chat.GetID()) } @@ -215,7 +215,7 @@ func (t *TelegramClient) wrapChatInfo(portalID networkid.PortalID, rawChat tg.Ch return nil, nil, fmt.Errorf("failed to wrap chat avatar: %w", avatarErr) } if !left { - info.Members.MemberMap.Add(bridgev2.ChatMember{EventSender: t.mySender(), PowerLevel: ownPL}) + info.Members.MemberMap.Add(bridgev2.ChatMember{EventSender: tc.mySender(), PowerLevel: ownPL}) } info.ExtraUpdates = func(ctx context.Context, portal *bridgev2.Portal) bool { meta := portal.Metadata.(*PortalMetadata) @@ -231,16 +231,16 @@ func (t *TelegramClient) wrapChatInfo(portalID networkid.PortalID, rawChat tg.Ch return &info, &mfm, nil } -func (t *TelegramClient) overrideChatInfoWithTopic(info *bridgev2.ChatInfo, topic *tg.ForumTopic) { +func (tc *TelegramClient) overrideChatInfoWithTopic(info *bridgev2.ChatInfo, topic *tg.ForumTopic) { info.Name = ptr.Ptr(topic.Title + " - " + *info.Name) if topic.Closed { info.Members.PowerLevels.EventsDefault = nobodyPowerLevel } } -func (t *TelegramClient) getChannelParticipants(ctx context.Context, req *tg.ChannelsGetParticipantsRequest) (*tg.ChannelsChannelParticipants, error) { - return APICallWithUpdates(ctx, t, func() (*tg.ChannelsChannelParticipants, error) { - p, err := t.client.API().ChannelsGetParticipants(ctx, req) +func (tc *TelegramClient) getChannelParticipants(ctx context.Context, req *tg.ChannelsGetParticipantsRequest) (*tg.ChannelsChannelParticipants, error) { + return APICallWithUpdates(ctx, tc, func() (*tg.ChannelsChannelParticipants, error) { + p, err := tc.client.API().ChannelsGetParticipants(ctx, req) if err != nil { return nil, err } @@ -249,14 +249,14 @@ func (t *TelegramClient) getChannelParticipants(ctx context.Context, req *tg.Cha }) } -func (t *TelegramClient) fillChannelMembers(ctx context.Context, mfm *memberFetchMeta, info *bridgev2.ChatMemberList) error { - if mfm.Input == nil || mfm.ParticipantsHidden || (mfm.IsBroadcast && !t.main.Config.MemberList.SyncBroadcastChannels) { +func (tc *TelegramClient) fillChannelMembers(ctx context.Context, mfm *memberFetchMeta, info *bridgev2.ChatMemberList) error { + if mfm.Input == nil || mfm.ParticipantsHidden || (mfm.IsBroadcast && !tc.main.Config.MemberList.SyncBroadcastChannels) { return nil } - memberSyncLimit := t.main.Config.MemberList.NormalizedMaxInitialSync() + memberSyncLimit := tc.main.Config.MemberList.NormalizedMaxInitialSync() if memberSyncLimit <= 200 { - participants, err := t.getChannelParticipants(ctx, &tg.ChannelsGetParticipantsRequest{ + participants, err := tc.getChannelParticipants(ctx, &tg.ChannelsGetParticipantsRequest{ Channel: mfm.Input, Filter: &tg.ChannelParticipantsRecent{}, Limit: memberSyncLimit, @@ -267,14 +267,14 @@ func (t *TelegramClient) fillChannelMembers(ctx context.Context, mfm *memberFetc info.IsFull = len(participants.Participants) < memberSyncLimit && len(participants.Participants) >= info.TotalMemberCount && info.TotalMemberCount > 0 - for participant := range t.filterChannelParticipants(participants.Participants, memberSyncLimit) { + for participant := range tc.filterChannelParticipants(participants.Participants, memberSyncLimit) { info.MemberMap.Set(participant) } } else { remaining := memberSyncLimit var offset int for remaining > 0 { - participants, err := t.getChannelParticipants(ctx, &tg.ChannelsGetParticipantsRequest{ + participants, err := tc.getChannelParticipants(ctx, &tg.ChannelsGetParticipantsRequest{ Channel: mfm.Input, Filter: &tg.ChannelParticipantsSearch{}, Limit: min(remaining, 200), @@ -289,7 +289,7 @@ func (t *TelegramClient) fillChannelMembers(ctx context.Context, mfm *memberFetc break } - for participant := range t.filterChannelParticipants(participants.Participants, remaining) { + for participant := range tc.filterChannelParticipants(participants.Participants, remaining) { info.MemberMap.Set(participant) } @@ -300,7 +300,7 @@ func (t *TelegramClient) fillChannelMembers(ctx context.Context, mfm *memberFetc return nil } -func (t *TelegramClient) fillUserLocalMeta(info *bridgev2.ChatInfo, dialog *tg.Dialog) { +func (tc *TelegramClient) fillUserLocalMeta(info *bridgev2.ChatInfo, dialog *tg.Dialog) { info.UserLocal = &bridgev2.UserLocalPortalInfo{} if mu, ok := dialog.NotifySettings.GetMuteUntil(); ok { info.UserLocal.MutedUntil = ptr.Ptr(time.Unix(int64(mu), 0)) @@ -312,7 +312,7 @@ func (t *TelegramClient) fillUserLocalMeta(info *bridgev2.ChatInfo, dialog *tg.D } } -func (t *TelegramClient) wrapFullChatInfo(portalID networkid.PortalID, fullChat *tg.MessagesChatFull) (*bridgev2.ChatInfo, *memberFetchMeta, error) { +func (tc *TelegramClient) wrapFullChatInfo(portalID networkid.PortalID, fullChat *tg.MessagesChatFull) (*bridgev2.ChatInfo, *memberFetchMeta, error) { var chat tg.ChatClass for _, c := range fullChat.GetChats() { if c.GetID() == fullChat.FullChat.GetID() { @@ -324,7 +324,7 @@ func (t *TelegramClient) wrapFullChatInfo(portalID networkid.PortalID, fullChat return nil, nil, fmt.Errorf("chat ID %d not found in full chat", fullChat.FullChat.GetID()) } - info, mfm, err := t.wrapChatInfo(portalID, chat) + info, mfm, err := tc.wrapChatInfo(portalID, chat) if err != nil { return nil, nil, err } @@ -365,7 +365,7 @@ func (t *TelegramClient) wrapFullChatInfo(portalID networkid.PortalID, fullChat switch typedFullChat := fullChat.FullChat.(type) { case *tg.ChatFull: participants, _ := typedFullChat.GetParticipants().(*tg.ChatParticipants) - memberSyncLimit := t.main.Config.MemberList.NormalizedMaxInitialSync() + memberSyncLimit := tc.main.Config.MemberList.NormalizedMaxInitialSync() info.Members.IsFull = true for i, user := range participants.GetParticipants() { var powerLevel *int @@ -379,7 +379,7 @@ func (t *TelegramClient) wrapFullChatInfo(portalID networkid.PortalID, fullChat } info.Members.MemberMap.Set(bridgev2.ChatMember{ - EventSender: t.senderForUserID(user.GetUserID()), + EventSender: tc.senderForUserID(user.GetUserID()), PowerLevel: powerLevel, }) @@ -422,7 +422,7 @@ func markFullSynced(ctx context.Context, portal *bridgev2.Portal) bool { return false } -func (t *TelegramClient) avatarFromPhoto(ctx context.Context, peerType ids.PeerType, peerID int64, photo tg.PhotoClass) *bridgev2.Avatar { +func (tc *TelegramClient) avatarFromPhoto(ctx context.Context, peerType ids.PeerType, peerID int64, photo tg.PhotoClass) *bridgev2.Avatar { if photo == nil { zerolog.Ctx(ctx).Trace().Msg("Chat photo is nil, returning no avatar") return nil @@ -430,7 +430,7 @@ func (t *TelegramClient) avatarFromPhoto(ctx context.Context, peerType ids.PeerT zerolog.Ctx(ctx).Debug().Str("type_name", photo.TypeName()).Msg("Chat photo type unknown, returning no avatar") return nil } - avatar, err := t.convertPhoto(ctx, peerType, peerID, photo) + avatar, err := tc.convertPhoto(ctx, peerType, peerID, photo) if err != nil { zerolog.Ctx(ctx).Err(err).Int64("id", photo.GetID()).Msg("Failed to convert avatar") return nil @@ -438,22 +438,22 @@ func (t *TelegramClient) avatarFromPhoto(ctx context.Context, peerType ids.PeerT return avatar } -func (t *TelegramClient) filterChannelParticipants(participants []tg.ChannelParticipantClass, limit int) iter.Seq[bridgev2.ChatMember] { +func (tc *TelegramClient) filterChannelParticipants(participants []tg.ChannelParticipantClass, limit int) iter.Seq[bridgev2.ChatMember] { return func(yield func(bridgev2.ChatMember) bool) { for i, u := range participants { var member bridgev2.ChatMember switch participant := u.(type) { case *tg.ChannelParticipant: - member.EventSender = t.senderForUserID(participant.GetUserID()) + member.EventSender = tc.senderForUserID(participant.GetUserID()) member.PowerLevel = anyonePowerLevel case *tg.ChannelParticipantSelf: - member.EventSender = t.senderForUserID(participant.GetUserID()) + member.EventSender = tc.senderForUserID(participant.GetUserID()) member.PowerLevel = anyonePowerLevel case *tg.ChannelParticipantCreator: - member.EventSender = t.senderForUserID(participant.GetUserID()) + member.EventSender = tc.senderForUserID(participant.GetUserID()) member.PowerLevel = creatorPowerLevel case *tg.ChannelParticipantAdmin: - member.EventSender = t.senderForUserID(participant.GetUserID()) + member.EventSender = tc.senderForUserID(participant.GetUserID()) member.PowerLevel = adminRightsToPowerLevel(participant.AdminRights) case *tg.ChannelParticipantBanned: if participant.BannedRights.ViewMessages { @@ -466,12 +466,12 @@ func (t *TelegramClient) filterChannelParticipants(participants []tg.ChannelPart } else { member.PowerLevel = anyonePowerLevel } - member.EventSender = t.getPeerSender(participant.GetPeer()) - member.MemberSender = t.senderForUserID(participant.GetKickedBy()) + member.EventSender = tc.getPeerSender(participant.GetPeer()) + member.MemberSender = tc.senderForUserID(participant.GetKickedBy()) case *tg.ChannelParticipantLeft: member.Membership = event.MembershipLeave member.PrevMembership = event.MembershipJoin - member.EventSender = t.getPeerSender(participant.GetPeer()) + member.EventSender = tc.getPeerSender(participant.GetPeer()) default: // TODO warning log? continue @@ -487,7 +487,7 @@ func (t *TelegramClient) filterChannelParticipants(participants []tg.ChannelPart } } -func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) { +func (tc *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) { peerType, id, topicID, err := ids.ParsePortalID(portal.ID) if err != nil { return nil, err @@ -495,24 +495,24 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta switch peerType { case ids.PeerTypeUser: - return t.getDMChatInfo(ctx, id) + return tc.getDMChatInfo(ctx, id) case ids.PeerTypeChat: - fullChat, err := APICallWithUpdates(ctx, t, func() (*tg.MessagesChatFull, error) { - return t.client.API().MessagesGetFullChat(ctx, id) + fullChat, err := APICallWithUpdates(ctx, tc, func() (*tg.MessagesChatFull, error) { + return tc.client.API().MessagesGetFullChat(ctx, id) }) if err != nil { return nil, err } - info, _, err := t.wrapFullChatInfo(portal.ID, fullChat) + info, _, err := tc.wrapFullChatInfo(portal.ID, fullChat) return info, err case ids.PeerTypeChannel: - accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id) + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id) if err != nil { return nil, fmt.Errorf("failed to get channel access hash: %w", err) } if topicID > 0 { - resp, err := APICallWithUpdates(ctx, t, func() (*tg.MessagesForumTopics, error) { - return t.client.API().MessagesGetForumTopicsByID(ctx, &tg.MessagesGetForumTopicsByIDRequest{ + resp, err := APICallWithUpdates(ctx, tc, func() (*tg.MessagesForumTopics, error) { + return tc.client.API().MessagesGetForumTopicsByID(ctx, &tg.MessagesGetForumTopicsByIDRequest{ Peer: &tg.InputPeerChannel{ChannelID: id, AccessHash: accessHash}, Topics: []int{topicID}, }) @@ -524,24 +524,24 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta if err != nil { return nil, err } - info, _, err := t.wrapChatInfo(portal.ID, channel) + info, _, err := tc.wrapChatInfo(portal.ID, channel) if err != nil { return nil, err } - t.overrideChatInfoWithTopic(info, topic) + tc.overrideChatInfoWithTopic(info, topic) return info, nil } - fullChat, err := APICallWithUpdates(ctx, t, func() (*tg.MessagesChatFull, error) { - return t.client.API().ChannelsGetFullChannel(ctx, &tg.InputChannel{ChannelID: id, AccessHash: accessHash}) + fullChat, err := APICallWithUpdates(ctx, tc, func() (*tg.MessagesChatFull, error) { + return tc.client.API().ChannelsGetFullChannel(ctx, &tg.InputChannel{ChannelID: id, AccessHash: accessHash}) }) if err != nil { return nil, err } - info, mfm, err := t.wrapFullChatInfo(portal.ID, fullChat) + info, mfm, err := tc.wrapFullChatInfo(portal.ID, fullChat) if err != nil { return nil, err } - err = t.fillChannelMembers(ctx, mfm, info.Members) + err = tc.fillChannelMembers(ctx, mfm, info.Members) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to get channel members") } @@ -580,7 +580,7 @@ func getTopicInfoFromResponse(resp *tg.MessagesForumTopics, channelID int64, top return } -func (t *TelegramClient) getDMPowerLevels(ghost *bridgev2.Ghost) *bridgev2.PowerLevelOverrides { +func (tc *TelegramClient) getDMPowerLevels(ghost *bridgev2.Ghost) *bridgev2.PowerLevelOverrides { var plo bridgev2.PowerLevelOverrides // TODO use per-login metadata for blocked status if /*ghost.Metadata.(*GhostMetadata).Blocked*/ false { @@ -599,7 +599,7 @@ func (t *TelegramClient) getDMPowerLevels(ghost *bridgev2.Ghost) *bridgev2.Power return &plo } -func (t *TelegramClient) getPowerLevelOverridesFromBannedRights(entity tg.ChatClass, dbr tg.ChatBannedRights) *bridgev2.PowerLevelOverrides { +func (tc *TelegramClient) getPowerLevelOverridesFromBannedRights(entity tg.ChatClass, dbr tg.ChatBannedRights) *bridgev2.PowerLevelOverrides { var plo bridgev2.PowerLevelOverrides plo.Ban = banUsersPowerLevel plo.Kick = banUsersPowerLevel diff --git a/pkg/connector/chatsync.go b/pkg/connector/chatsync.go index 3752f163..b74fdd39 100644 --- a/pkg/connector/chatsync.go +++ b/pkg/connector/chatsync.go @@ -33,8 +33,8 @@ import ( "go.mau.fi/mautrix-telegram/pkg/gotd/tgerr" ) -func (t *TelegramClient) syncChats(ctx context.Context, takeoutID int64, onLogin, restart bool) error { - if takeoutID != 0 && !t.main.Config.Takeout.DialogSync { +func (tc *TelegramClient) syncChats(ctx context.Context, takeoutID int64, onLogin, restart bool) error { + if takeoutID != 0 && !tc.main.Config.Takeout.DialogSync { return nil } logWith := zerolog.Ctx(ctx).With().Str("loop", "chat sync") @@ -46,36 +46,36 @@ func (t *TelegramClient) syncChats(ctx context.Context, takeoutID int64, onLogin } log := logWith.Logger() - if !t.syncChatsLock.TryLock() { + if !tc.syncChatsLock.TryLock() { log.Warn().Msg("Waiting for chat sync lock") - t.syncChatsLock.Lock() + tc.syncChatsLock.Lock() log.Debug().Msg("Acquired chat sync lock after waiting") } - defer t.syncChatsLock.Unlock() + defer tc.syncChatsLock.Unlock() if restart { - t.metadata.DialogSyncCount = 0 - t.metadata.DialogSyncComplete = false - t.metadata.DialogSyncCursor = "" - } else if t.metadata.DialogSyncComplete { + tc.metadata.DialogSyncCount = 0 + tc.metadata.DialogSyncComplete = false + tc.metadata.DialogSyncCursor = "" + } else if tc.metadata.DialogSyncComplete { log.Debug().Msg("Dialogs already synced") return nil } isFullSync := true - updateLimit := subtractLimit(t.main.Config.Sync.UpdateLimit, t.metadata.DialogSyncCount) - if onLogin && t.main.Config.Takeout.DialogSync { - updateLimit = t.main.Config.Sync.LoginLimit + updateLimit := subtractLimit(tc.main.Config.Sync.UpdateLimit, tc.metadata.DialogSyncCount) + if onLogin && tc.main.Config.Takeout.DialogSync { + updateLimit = tc.main.Config.Sync.LoginLimit isFullSync = false } - createLimit := subtractLimit(t.main.Config.Sync.CreateLimit, t.metadata.DialogSyncCount) + createLimit := subtractLimit(tc.main.Config.Sync.CreateLimit, tc.metadata.DialogSyncCount) var req tg.MessagesGetDialogsRequest isFirst := true - if t.metadata.DialogSyncCursor != "" { + if tc.metadata.DialogSyncCursor != "" { isFirst = false var err error - req.OffsetPeer, _, err = t.inputPeerForPortalID(ctx, t.metadata.DialogSyncCursor) + req.OffsetPeer, _, err = tc.inputPeerForPortalID(ctx, tc.metadata.DialogSyncCursor) if err != nil { return fmt.Errorf("failed to get input peer for pagination: %w", err) } @@ -99,12 +99,12 @@ func (t *TelegramClient) syncChats(ctx context.Context, takeoutID int64, onLogin Int("update_limit", updateLimit). Int("create_limit", createLimit). Msg("Fetching dialogs") - dialogs, err := APICallWithUpdates(ctx, t, func() (tg.ModifiedMessagesDialogs, error) { + dialogs, err := APICallWithUpdates(ctx, tc, func() (tg.ModifiedMessagesDialogs, error) { var dialogs tg.MessagesDialogsBox retry := true var err error for retry { - retry, err = tgerr.FloodWait(ctx, t.client.Invoke(ctx, wrappedReq, &dialogs)) + retry, err = tgerr.FloodWait(ctx, tc.client.Invoke(ctx, wrappedReq, &dialogs)) } if err != nil { return nil, err @@ -123,7 +123,7 @@ func (t *TelegramClient) syncChats(ctx context.Context, takeoutID int64, onLogin if isFirst { // This is the first fetch of dialogs, reset the pinned dialogs based on the list. - if err = t.resetPinnedDialogs(ctx, dialogs.GetDialogs()); err != nil { + if err = tc.resetPinnedDialogs(ctx, dialogs.GetDialogs()); err != nil { return fmt.Errorf("failed to save pinned dialogs: %w", err) } } @@ -133,34 +133,34 @@ func (t *TelegramClient) syncChats(ctx context.Context, takeoutID int64, onLogin if updateLimit > 0 && len(dialogList) > updateLimit { dialogList = dialogList[:updateLimit] } - err = t.handleDialogs(ctx, dialogList, dialogs, createLimit) + err = tc.handleDialogs(ctx, dialogList, dialogs, createLimit) if err != nil { return fmt.Errorf("failed to handle dialogs: %w", err) } updateLimit = subtractLimit(updateLimit, len(dialogList)) createLimit = subtractLimit(createLimit, len(dialogList)) - cursorPortalKey := t.makePortalKeyFromPeer(dialogList[len(dialogList)-1].GetPeer(), 0) - if t.metadata.DialogSyncCursor == cursorPortalKey.ID { + cursorPortalKey := tc.makePortalKeyFromPeer(dialogList[len(dialogList)-1].GetPeer(), 0) + if tc.metadata.DialogSyncCursor == cursorPortalKey.ID { log.Debug().Msg("No more dialogs found (last dialog is same as old cursor)") break } - t.metadata.DialogSyncCursor = cursorPortalKey.ID - t.metadata.DialogSyncCount += len(dialogList) - if err = t.userLogin.Save(ctx); err != nil { + tc.metadata.DialogSyncCursor = cursorPortalKey.ID + tc.metadata.DialogSyncCount += len(dialogList) + if err = tc.userLogin.Save(ctx); err != nil { return fmt.Errorf("failed to save user login to update cursor: %w", err) } - req.OffsetPeer, _, err = t.inputPeerForPortalID(ctx, cursorPortalKey.ID) + req.OffsetPeer, _, err = tc.inputPeerForPortalID(ctx, cursorPortalKey.ID) if err != nil { return fmt.Errorf("failed to get input peer for pagination: %w", err) } } if isFullSync { - t.metadata.DialogSyncComplete = true - t.metadata.DialogSyncCursor = "" - t.metadata.DialogSyncCount = 0 - if err := t.userLogin.Save(ctx); err != nil { + tc.metadata.DialogSyncComplete = true + tc.metadata.DialogSyncCursor = "" + tc.metadata.DialogSyncCount = 0 + if err := tc.userLogin.Save(ctx); err != nil { return fmt.Errorf("failed to save user login after successful sync: %w", err) } } @@ -179,18 +179,18 @@ func subtractLimit(limit, count int) int { return limit } -func (t *TelegramClient) resetPinnedDialogs(ctx context.Context, dialogs []tg.DialogClass) error { - t.metadata.PinnedDialogs = nil +func (tc *TelegramClient) resetPinnedDialogs(ctx context.Context, dialogs []tg.DialogClass) error { + tc.metadata.PinnedDialogs = nil for _, dialog := range dialogs { if dialog.GetPinned() { - portalKey := t.makePortalKeyFromPeer(dialog.GetPeer(), 0) - t.metadata.PinnedDialogs = append(t.metadata.PinnedDialogs, portalKey.ID) + portalKey := tc.makePortalKeyFromPeer(dialog.GetPeer(), 0) + tc.metadata.PinnedDialogs = append(tc.metadata.PinnedDialogs, portalKey.ID) } } - return t.userLogin.Save(ctx) + return tc.userLogin.Save(ctx) } -func (t *TelegramClient) handleDialogs(ctx context.Context, dialogList []tg.DialogClass, meta tg.ModifiedMessagesDialogs, createLimit int) error { +func (tc *TelegramClient) handleDialogs(ctx context.Context, dialogList []tg.DialogClass, meta tg.ModifiedMessagesDialogs, createLimit int) error { log := zerolog.Ctx(ctx) users := map[int64]tg.UserClass{} @@ -218,8 +218,8 @@ func (t *TelegramClient) handleDialogs(ctx context.Context, dialogList []tg.Dial Logger() log.Debug().Msg("Syncing dialog") - portalKey := t.makePortalKeyFromPeer(dialog.GetPeer(), 0) - portal, err := t.main.Bridge.GetPortalByKey(ctx, portalKey) + portalKey := tc.makePortalKeyFromPeer(dialog.GetPeer(), 0) + portal, err := tc.main.Bridge.GetPortalByKey(ctx, portalKey) if err != nil { return err } @@ -236,7 +236,7 @@ func (t *TelegramClient) handleDialogs(ctx context.Context, dialogList []tg.Dial log.Debug().Int64("user_id", peer.UserID).Msg("Not syncing portal because user is deleted") continue } - chatInfo, err = t.getDMChatInfo(ctx, peer.UserID) + chatInfo, err = tc.getDMChatInfo(ctx, peer.UserID) if err != nil { return fmt.Errorf("failed to get dm info for %d: %w", peer.UserID, err) } @@ -251,7 +251,7 @@ func (t *TelegramClient) handleDialogs(ctx context.Context, dialogList []tg.Dial switch chat := chats[peer.ChatID].(type) { case *tg.Chat: // Need to get full chat info to get the member list - chatInfo, err = t.GetChatInfo(ctx, portal) + chatInfo, err = tc.GetChatInfo(ctx, portal) if err != nil { return fmt.Errorf("failed to get chat info for %s: %w", portalKey, err) } @@ -271,11 +271,11 @@ func (t *TelegramClient) handleDialogs(ctx context.Context, dialogList []tg.Dial switch channel := chats[peer.ChannelID].(type) { case *tg.Channel: var mfm *memberFetchMeta - chatInfo, mfm, err = t.wrapChatInfo(portal.ID, channel) + chatInfo, mfm, err = tc.wrapChatInfo(portal.ID, channel) if err != nil { return fmt.Errorf("failed to get chat info for %s: %w", portalKey, err) } - err = t.fillChannelMembers(ctx, mfm, chatInfo.Members) + err = tc.fillChannelMembers(ctx, mfm, chatInfo.Members) if err != nil { log.Err(err).Msg("Failed to get channel members") } @@ -315,9 +315,9 @@ func (t *TelegramClient) handleDialogs(ctx context.Context, dialogList []tg.Dial } } - t.fillUserLocalMeta(chatInfo, dialog) + tc.fillUserLocalMeta(chatInfo, dialog) - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatResync{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatResync{ ChatInfo: chatInfo, EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventChatResync, @@ -343,11 +343,11 @@ func (t *TelegramClient) handleDialogs(ctx context.Context, dialogList []tg.Dial } // Generate a read receipt from the last known read message id - res = t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Receipt{ + res = tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Receipt{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventReadReceipt, PortalKey: portalKey, - Sender: t.mySender(), + Sender: tc.mySender(), }, LastTarget: ids.MakeMessageID(portalKey, dialog.ReadInboxMaxID), ReadUpToStreamOrder: int64(dialog.ReadInboxMaxID), diff --git a/pkg/connector/client.go b/pkg/connector/client.go index 8932781a..9a13df34 100644 --- a/pkg/connector/client.go +++ b/pkg/connector/client.go @@ -123,13 +123,13 @@ var _ bridgev2.NetworkAPI = (*TelegramClient)(nil) var messageLinkRegex = regexp.MustCompile(`^https?://t(?:elegram)?\.(?:me|dog)/([A-Za-z][A-Za-z0-9_]{3,31}[A-Za-z0-9]|[Cc]/[0-9]{1,20})/([0-9]{1,20})(?:/([0-9]{1,20}))?$`) -func (tg *TelegramConnector) deviceConfig() telegram.DeviceConfig { +func (tc *TelegramConnector) deviceConfig() telegram.DeviceConfig { return telegram.DeviceConfig{ - DeviceModel: tg.Config.DeviceInfo.DeviceModel, - SystemVersion: tg.Config.DeviceInfo.SystemVersion, - AppVersion: tg.Config.DeviceInfo.AppVersion, - SystemLangCode: tg.Config.DeviceInfo.SystemLangCode, - LangCode: tg.Config.DeviceInfo.LangCode, + DeviceModel: tc.Config.DeviceInfo.DeviceModel, + SystemVersion: tc.Config.DeviceInfo.SystemVersion, + AppVersion: tc.Config.DeviceInfo.AppVersion, + SystemLangCode: tc.Config.DeviceInfo.SystemLangCode, + LangCode: tc.Config.DeviceInfo.LangCode, } } @@ -365,34 +365,34 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge return &client, err } -func (t *TelegramClient) onDead() { - prevState := t.userLogin.BridgeState.GetPrev().StateEvent +func (tc *TelegramClient) onDead() { + prevState := tc.userLogin.BridgeState.GetPrev().StateEvent if slices.Contains([]status.BridgeStateEvent{ status.StateTransientDisconnect, status.StateBadCredentials, status.StateLoggedOut, status.StateUnknownError, }, prevState) { - t.userLogin.Log.Warn(). + tc.userLogin.Log.Warn(). Str("prev_state", string(prevState)). Msg("client is dead, not sending transient disconnect, because already in an error state") return } - t.userLogin.BridgeState.Send(status.BridgeState{ + tc.userLogin.BridgeState.Send(status.BridgeState{ StateEvent: status.StateTransientDisconnect, Message: "Telegram client disconnected", }) } -func (t *TelegramClient) sendBadCredentialsOrUnknownError(err error) { +func (tc *TelegramClient) sendBadCredentialsOrUnknownError(err error) { if auth.IsUnauthorized(err) || errors.Is(err, ErrNoAuthKey) { - t.userLogin.BridgeState.Send(status.BridgeState{ + tc.userLogin.BridgeState.Send(status.BridgeState{ StateEvent: status.StateBadCredentials, Error: "tg-no-auth", Message: humanise.Error(err), }) } else { - t.userLogin.BridgeState.Send(status.BridgeState{ + tc.userLogin.BridgeState.Send(status.BridgeState{ StateEvent: status.StateUnknownError, Error: "tg-unknown-error", Message: humanise.Error(err), @@ -403,38 +403,38 @@ func (t *TelegramClient) sendBadCredentialsOrUnknownError(err error) { } } -func (t *TelegramClient) onPing() { - prev := t.userLogin.BridgeState.GetPrev() +func (tc *TelegramClient) onPing() { + prev := tc.userLogin.BridgeState.GetPrev() if prev.StateEvent == status.StateConnected || prev.Error == updateHandlerStuck { return } - ctx := t.userLogin.Log.WithContext(t.main.Bridge.BackgroundCtx) - t.userLogin.Log.Debug().Msg("Got ping while not connected, checking auth") + ctx := tc.userLogin.Log.WithContext(tc.main.Bridge.BackgroundCtx) + tc.userLogin.Log.Debug().Msg("Got ping while not connected, checking auth") - me, err := t.client.Self(ctx) + me, err := tc.client.Self(ctx) if auth.IsUnauthorized(err) { - t.onAuthError(err) + tc.onAuthError(err) } else if errors.Is(err, syscall.EPIPE) { // This is a pipe error, try disconnecting which will force the // updatesManager to fail and cause the client to reconnect. - t.userLogin.BridgeState.Send(status.BridgeState{ + tc.userLogin.BridgeState.Send(status.BridgeState{ StateEvent: status.StateTransientDisconnect, Error: "pipe-error", Message: humanise.Error(err), }) } else if err != nil { - t.sendBadCredentialsOrUnknownError(err) + tc.sendBadCredentialsOrUnknownError(err) } else { - t.onConnected(me) + tc.onConnected(me) } } -func (t *TelegramConnector) userToRemoteProfile( +func (tc *TelegramConnector) userToRemoteProfile( self *tg.User, ghost *bridgev2.Ghost, prevState *status.RemoteProfile, ) (profile status.RemoteProfile, name string) { - profile.Name = t.Config.FormatDisplayname(self.FirstName, self.LastName, self.Username, self.Deleted, self.ID) + profile.Name = tc.Config.FormatDisplayname(self.FirstName, self.LastName, self.Username, self.Deleted, self.ID) if self.Phone != "" { profile.Phone = "+" + strings.TrimPrefix(self.Phone, "+") } else if prevState != nil { @@ -453,99 +453,99 @@ func (t *TelegramConnector) userToRemoteProfile( return } -func (t *TelegramClient) updateRemoteProfile(ctx context.Context, self *tg.User, ghost *bridgev2.Ghost) bool { - newProfile, newName := t.main.userToRemoteProfile(self, ghost, &t.userLogin.RemoteProfile) - if t.userLogin.RemoteProfile != newProfile || t.userLogin.RemoteName != newName { - t.userLogin.RemoteProfile = newProfile - t.userLogin.RemoteName = newName - err := t.userLogin.Save(ctx) +func (tc *TelegramClient) updateRemoteProfile(ctx context.Context, self *tg.User, ghost *bridgev2.Ghost) bool { + newProfile, newName := tc.main.userToRemoteProfile(self, ghost, &tc.userLogin.RemoteProfile) + if tc.userLogin.RemoteProfile != newProfile || tc.userLogin.RemoteName != newName { + tc.userLogin.RemoteProfile = newProfile + tc.userLogin.RemoteName = newName + err := tc.userLogin.Save(ctx) if err != nil { - t.userLogin.Log.Err(err).Msg("Failed to save user login after profile update") + tc.userLogin.Log.Err(err).Msg("Failed to save user login after profile update") } return true } return false } -func (t *TelegramClient) onConnected(self *tg.User) { - log := t.userLogin.Log - ctx := log.WithContext(t.main.Bridge.BackgroundCtx) - ghost, err := t.main.Bridge.GetGhostByID(ctx, t.userID) +func (tc *TelegramClient) onConnected(self *tg.User) { + log := tc.userLogin.Log + ctx := log.WithContext(tc.main.Bridge.BackgroundCtx) + ghost, err := tc.main.Bridge.GetGhostByID(ctx, tc.userID) if err != nil { log.Err(err).Msg("Failed to get own ghost") - } else if wrapped, err := t.wrapUserInfo(ctx, self, ghost); err != nil { + } else if wrapped, err := tc.wrapUserInfo(ctx, self, ghost); err != nil { log.Err(err).Msg("Failed to wrap own user info") } else { ghost.UpdateInfo(ctx, wrapped) } - t.updateRemoteProfile(ctx, self, ghost) - t.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) + tc.updateRemoteProfile(ctx, self, ghost) + tc.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) } -func (t *TelegramClient) onTransfer(ctx context.Context, _ *telegram.Client, fn func(context.Context) error) error { - t.userLogin.Log.Trace().Msg("Doing DC auth transfer") - t.dcTransferLock.Lock() - defer t.dcTransferLock.Unlock() +func (tc *TelegramClient) onTransfer(ctx context.Context, _ *telegram.Client, fn func(context.Context) error) error { + tc.userLogin.Log.Trace().Msg("Doing DC auth transfer") + tc.dcTransferLock.Lock() + defer tc.dcTransferLock.Unlock() return fn(ctx) } -func (t *TelegramClient) onSession() { - t.userLogin.Log.Debug().Msg("Got session created event") +func (tc *TelegramClient) onSession() { + tc.userLogin.Log.Debug().Msg("Got session created event") } -func (t *TelegramClient) onAuthError(err error) { - t.sendBadCredentialsOrUnknownError(err) - t.metadata.ResetOnLogout() +func (tc *TelegramClient) onAuthError(err error) { + tc.sendBadCredentialsOrUnknownError(err) + tc.metadata.ResetOnLogout() go func() { - t.Disconnect() - if err := t.userLogin.Save(context.Background()); err != nil { - t.main.Bridge.Log.Err(err).Msg("failed to save user login") + tc.Disconnect() + if err := tc.userLogin.Save(context.Background()); err != nil { + tc.main.Bridge.Log.Err(err).Msg("failed to save user login") } }() } -func (t *TelegramClient) Connect(ctx context.Context) { - t.mu.Lock() - defer t.mu.Unlock() +func (tc *TelegramClient) Connect(ctx context.Context) { + tc.mu.Lock() + defer tc.mu.Unlock() log := zerolog.Ctx(ctx) - if !t.metadata.Session.HasAuthKey() { + if !tc.metadata.Session.HasAuthKey() { log.Warn().Msg("user does not have an auth key, sending bad credentials state") - t.sendBadCredentialsOrUnknownError(ErrNoAuthKey) + tc.sendBadCredentialsOrUnknownError(ErrNoAuthKey) return } - t.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnecting}) + tc.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnecting}) log.Info().Msg("Connecting client") // Add a cancellation layer we can use for explicit Disconnect ctx, cancel := context.WithCancel(ctx) - t.clientCtx = ctx - t.clientCancel = cancel - t.clientDone.Clear() - t.clientInitialized.Clear() - go t.runInBackground(ctx) + tc.clientCtx = ctx + tc.clientCancel = cancel + tc.clientDone.Clear() + tc.clientInitialized.Clear() + go tc.runInBackground(ctx) } -func (t *TelegramClient) runInBackground(ctx context.Context) { +func (tc *TelegramClient) runInBackground(ctx context.Context) { log := zerolog.Ctx(ctx) - err := t.client.Run(ctx, func(ctx context.Context) error { - t.clientInitialized.Set() + err := tc.client.Run(ctx, func(ctx context.Context) error { + tc.clientInitialized.Set() // If takeout dialog sync is enabled, we assume it'll resume from a getTakeoutID call. // If not, resume dialog sync manually here. - if !t.isNewLogin && !t.main.Config.Takeout.DialogSync { + if !tc.isNewLogin && !tc.main.Config.Takeout.DialogSync { go func() { - if err := t.syncChats(log.WithContext(t.clientCtx), 0, false, false); err != nil { + if err := tc.syncChats(log.WithContext(tc.clientCtx), 0, false, false); err != nil { log.Err(err).Msg("Failed to resume chat sync") } }() } log.Info().Msg("Client running, starting updates") - err := t.updatesManager.Run(ctx, t.client.API(), t.telegramUserID, updates.AuthOptions{ - IsBot: t.metadata.IsBot, + err := tc.updatesManager.Run(ctx, tc.client.API(), tc.telegramUserID, updates.AuthOptions{ + IsBot: tc.metadata.IsBot, }) if err != nil && !errors.Is(err, ctx.Err()) { log.Warn().Err(err).AnErr("ctx_err", ctx.Err()).Msg("Update manager exited with error") @@ -554,77 +554,77 @@ func (t *TelegramClient) runInBackground(ctx context.Context) { } return err }) - t.clientDone.Set() - t.clientInitialized.Set() + tc.clientDone.Set() + tc.clientInitialized.Set() if err != nil { log.Err(err).AnErr("ctx_err", ctx.Err()).Msg("Client exited with error") - t.sendBadCredentialsOrUnknownError(err) + tc.sendBadCredentialsOrUnknownError(err) } else if ctx.Err() == nil { log.Warn().Msg("Client exited unexpectedly") - t.sendBadCredentialsOrUnknownError(fmt.Errorf("unexpectedly disconnected from Telegram")) + tc.sendBadCredentialsOrUnknownError(fmt.Errorf("unexpectedly disconnected from Telegram")) } else { log.Debug().AnErr("ctx_err", ctx.Err()).Msg("Client exited without error") } } -func (t *TelegramClient) Disconnect() { - t.mu.Lock() - defer t.mu.Unlock() +func (tc *TelegramClient) Disconnect() { + tc.mu.Lock() + defer tc.mu.Unlock() - t.userLogin.Log.Debug().Msg("Disconnecting client") + tc.userLogin.Log.Debug().Msg("Disconnecting client") - if t.clientCancel != nil { - t.clientCancel() - t.userLogin.Log.Debug().Msg("Waiting for client disconnection") - <-t.clientDone.GetChan() + if tc.clientCancel != nil { + tc.clientCancel() + tc.userLogin.Log.Debug().Msg("Waiting for client disconnection") + <-tc.clientDone.GetChan() } - t.userLogin.Log.Info().Msg("Disconnect complete") + tc.userLogin.Log.Info().Msg("Disconnect complete") } -func (t *TelegramClient) IsLoggedIn() bool { +func (tc *TelegramClient) IsLoggedIn() bool { // TODO use less hacky check than context cancellation - return t != nil && t.client != nil && - t.clientInitialized.IsSet() && !t.clientDone.IsSet() && - t.metadata.Session.HasAuthKey() + return tc != nil && tc.client != nil && + tc.clientInitialized.IsSet() && !tc.clientDone.IsSet() && + tc.metadata.Session.HasAuthKey() } -func (t *TelegramClient) LogoutRemote(ctx context.Context) { +func (tc *TelegramClient) LogoutRemote(ctx context.Context) { log := zerolog.Ctx(ctx).With(). Str("action", "logout_remote"). - Int64("user_id", t.telegramUserID). + Int64("user_id", tc.telegramUserID). Logger() log.Info().Msg("Logging out and disconnecting") - if t.metadata.Session.HasAuthKey() { + if tc.metadata.Session.HasAuthKey() { log.Info().Msg("User has an auth key, logging out") // logging out is best effort, we want to logout even if we can't call the endpoint ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() - _, err := t.client.API().AuthLogOut(ctx) + _, err := tc.client.API().AuthLogOut(ctx) if err != nil { log.Err(err).Msg("failed to logout on Telegram") } } - t.Disconnect() + tc.Disconnect() log.Info().Msg("Deleting user state") - err := t.ScopedStore.DeleteUserState(ctx) + err := tc.ScopedStore.DeleteUserState(ctx) if err != nil { log.Err(err).Msg("failed to delete user state") } - err = t.ScopedStore.DeleteChannelStateForUser(ctx) + err = tc.ScopedStore.DeleteChannelStateForUser(ctx) if err != nil { log.Err(err).Msg("failed to delete channel state for user") } - err = t.ScopedStore.DeleteAccessHashesForUser(ctx) + err = tc.ScopedStore.DeleteAccessHashesForUser(ctx) if err != nil { log.Err(err).Msg("failed to delete access hashes for user") } @@ -632,31 +632,31 @@ func (t *TelegramClient) LogoutRemote(ctx context.Context) { log.Info().Msg("Logged out and deleted user state") } -func (t *TelegramClient) IsThisUser(ctx context.Context, userID networkid.UserID) bool { - return userID == networkid.UserID(t.userLogin.ID) +func (tc *TelegramClient) IsThisUser(ctx context.Context, userID networkid.UserID) bool { + return userID == networkid.UserID(tc.userLogin.ID) } -func (t *TelegramClient) mySender() bridgev2.EventSender { +func (tc *TelegramClient) mySender() bridgev2.EventSender { return bridgev2.EventSender{ IsFromMe: true, - SenderLogin: t.loginID, - Sender: t.userID, + SenderLogin: tc.loginID, + Sender: tc.userID, } } -func (t *TelegramClient) senderForUserID(userID int64) bridgev2.EventSender { +func (tc *TelegramClient) senderForUserID(userID int64) bridgev2.EventSender { return bridgev2.EventSender{ - IsFromMe: userID == t.telegramUserID, + IsFromMe: userID == tc.telegramUserID, SenderLogin: ids.MakeUserLoginID(userID), Sender: ids.MakeUserID(userID), } } -func (t *TelegramClient) FillBridgeState(state status.BridgeState) status.BridgeState { +func (tc *TelegramClient) FillBridgeState(state status.BridgeState) status.BridgeState { if state.Info == nil { state.Info = make(map[string]any) } - state.Info["is_bot"] = t.metadata.IsBot - state.Info["login_method"] = t.metadata.LoginMethod + state.Info["is_bot"] = tc.metadata.IsBot + state.Info["login_method"] = tc.metadata.LoginMethod return state } diff --git a/pkg/connector/config.go b/pkg/connector/config.go index 569ce4e3..f290888e 100644 --- a/pkg/connector/config.go +++ b/pkg/connector/config.go @@ -179,8 +179,8 @@ func upgradeConfig(helper up.Helper) { helper.Copy(up.Str, "displayname_template") } -func (tg *TelegramConnector) GetConfig() (example string, data any, upgrader up.Upgrader) { - return ExampleConfig, &tg.Config, &up.StructUpgrader{ +func (tc *TelegramConnector) GetConfig() (example string, data any, upgrader up.Upgrader) { + return ExampleConfig, &tc.Config, &up.StructUpgrader{ SimpleUpgrader: up.SimpleUpgrader(upgradeConfig), Blocks: [][]string{ {"device_info"}, @@ -195,15 +195,15 @@ func (tg *TelegramConnector) GetConfig() (example string, data any, upgrader up. } } -func (tg *TelegramConnector) ValidateConfig() error { - if tg.Config.APIID == 0 { +func (tc *TelegramConnector) ValidateConfig() error { + if tc.Config.APIID == 0 { return fmt.Errorf("api_id is required") } - if tg.Config.APIHash == "" || tg.Config.APIHash == "tjyd5yge35lbodk1xwzw2jstp90k55qz" { + if tc.Config.APIHash == "" || tc.Config.APIHash == "tjyd5yge35lbodk1xwzw2jstp90k55qz" { return fmt.Errorf("api_hash is required") } - if !slices.Contains([]string{"disable", "gif", "png", "webp", "webm"}, tg.Config.AnimatedSticker.Target) { - return fmt.Errorf("unsupported animated sticker target: %s", tg.Config.AnimatedSticker.Target) + if !slices.Contains([]string{"disable", "gif", "png", "webp", "webm"}, tc.Config.AnimatedSticker.Target) { + return fmt.Errorf("unsupported animated sticker target: %s", tc.Config.AnimatedSticker.Target) } return nil } diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index e829dad1..81367a40 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -38,14 +38,14 @@ type TelegramConnector struct { var _ bridgev2.NetworkConnector = (*TelegramConnector)(nil) var _ bridgev2.MaxFileSizeingNetwork = (*TelegramConnector)(nil) -func (tg *TelegramConnector) Init(bridge *bridgev2.Bridge) { - tg.Store = store.NewStore(bridge.DB.Database, dbutil.ZeroLogger(bridge.Log.With().Str("db_section", "telegram").Logger())) - tg.Bridge = bridge - tg.Bridge.Commands.(*commands.Processor).AddHandlers(cmdSyncChats, cmdEmojiPack, cmdUpgrade, cmdJoin) +func (tc *TelegramConnector) Init(bridge *bridgev2.Bridge) { + tc.Store = store.NewStore(bridge.DB.Database, dbutil.ZeroLogger(bridge.Log.With().Str("db_section", "telegram").Logger())) + tc.Bridge = bridge + tc.Bridge.Commands.(*commands.Processor).AddHandlers(cmdSyncChats, cmdEmojiPack, cmdUpgrade, cmdJoin) } -func (tg *TelegramConnector) Start(ctx context.Context) error { - return tg.Store.Upgrade(ctx) +func (tc *TelegramConnector) Start(ctx context.Context) error { + return tc.Store.Upgrade(ctx) } func (tc *TelegramConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) (err error) { @@ -53,11 +53,11 @@ func (tc *TelegramConnector) LoadUserLogin(ctx context.Context, login *bridgev2. return } -func (tg *TelegramConnector) SetMaxFileSize(maxSize int64) { - tg.maxFileSize = maxSize +func (tc *TelegramConnector) SetMaxFileSize(maxSize int64) { + tc.maxFileSize = maxSize } -func (tg *TelegramConnector) GetName() bridgev2.BridgeName { +func (tc *TelegramConnector) GetName() bridgev2.BridgeName { return bridgev2.BridgeName{ DisplayName: "Telegram", NetworkURL: "https://telegram.org/", diff --git a/pkg/connector/directdownload.go b/pkg/connector/directdownload.go index 878ab6e0..9fc070d1 100644 --- a/pkg/connector/directdownload.go +++ b/pkg/connector/directdownload.go @@ -218,6 +218,6 @@ func (tc *TelegramConnector) Download(ctx context.Context, mediaID networkid.Med return readyTransferer.ToDirectMediaResponse(ctx) } -func (tg *TelegramConnector) SetUseDirectMedia() { - tg.useDirectMedia = true +func (tc *TelegramConnector) SetUseDirectMedia() { + tc.useDirectMedia = true } diff --git a/pkg/connector/handlematrix.go b/pkg/connector/handlematrix.go index de96a1d8..9cc4e014 100644 --- a/pkg/connector/handlematrix.go +++ b/pkg/connector/handlematrix.go @@ -97,7 +97,7 @@ func getMediaFilename(content *event.MessageEventContent) (filename string) { return filename } -func (t *TelegramClient) HandleMatrixViewingChat(ctx context.Context, msg *bridgev2.MatrixViewingChat) error { +func (tc *TelegramClient) HandleMatrixViewingChat(ctx context.Context, msg *bridgev2.MatrixViewingChat) error { if msg.Portal == nil { return nil } @@ -105,27 +105,27 @@ func (t *TelegramClient) HandleMatrixViewingChat(ctx context.Context, msg *bridg // TODO sync topic parent space meta := msg.Portal.Metadata.(*PortalMetadata) if (topicID == 0 && !meta.FullSynced) || meta.LastSync.Add(24*time.Hour).Before(time.Now()) { - t.userLogin.QueueRemoteEvent(&simplevent.ChatResync{ + tc.userLogin.QueueRemoteEvent(&simplevent.ChatResync{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventChatResync, PortalKey: msg.Portal.PortalKey, }, - GetChatInfoFunc: t.GetChatInfo, + GetChatInfoFunc: tc.GetChatInfo, }) } - err := t.maybePollForReactions(ctx, msg.Portal) + err := tc.maybePollForReactions(ctx, msg.Portal) if err != nil { return err } - err = t.pollSponsoredMessage(ctx, msg.Portal) + err = tc.pollSponsoredMessage(ctx, msg.Portal) if err != nil { return err } return nil } -func (t *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridgev2.Portal) error { - if t.metadata.IsBot { +func (tc *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridgev2.Portal) error { + if tc.metadata.IsBot { return nil } meta := portal.Metadata.(*PortalMetadata) @@ -140,18 +140,18 @@ func (t *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridg if time.Since(meta.SponsoredMessagePollTS.Time) < 5*time.Minute { return nil } - latestMessage, err := t.main.Bridge.DB.Message.GetLastNonFakePartAtOrBeforeTime(ctx, portal.PortalKey, time.Now()) + latestMessage, err := tc.main.Bridge.DB.Message.GetLastNonFakePartAtOrBeforeTime(ctx, portal.PortalKey, time.Now()) if err != nil { return fmt.Errorf("failed to get latest message for portal: %w", err) } else if latestMessage != nil && latestMessage.ID == meta.LastMessageOnSponsorFetch { meta.SponsoredMessagePollTS = jsontime.UnixNow() return nil } - accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id) + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id) if err != nil { return err } - resp, err := t.client.API().MessagesGetSponsoredMessages(ctx, &tg.MessagesGetSponsoredMessagesRequest{ + resp, err := tc.client.API().MessagesGetSponsoredMessages(ctx, &tg.MessagesGetSponsoredMessagesRequest{ Peer: &tg.InputPeerChannel{ChannelID: id, AccessHash: accessHash}, }) if err != nil { @@ -179,7 +179,7 @@ func (t *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridg msg = msgs.Messages[1] } meta.SponsoredMessageRandomID = msg.RandomID - content := t.parseBodyAndHTML(ctx, msg.Message, msg.Entities) + content := tc.parseBodyAndHTML(ctx, msg.Message, msg.Entities) content.MsgType = event.MsgNotice content.EnsureHasHTML() extra := map[string]any{ @@ -207,7 +207,7 @@ func (t *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridg `%s: %s
%s

Sponsored message%s - %s

`, prefix, html.EscapeString(msg.Title), content.FormattedBody, fromStr, msg.URL, msg.ButtonText, ) - sendResp, err := t.main.Bridge.Bot.SendMessage(ctx, portal.MXID, event.EventMessage, &event.Content{ + sendResp, err := tc.main.Bridge.Bot.SendMessage(ctx, portal.MXID, event.EventMessage, &event.Content{ Raw: extra, Parsed: content, }, &bridgev2.MatrixSendExtra{Timestamp: time.Now()}) @@ -226,11 +226,11 @@ func (t *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridg return nil } -func (t *TelegramClient) transferMediaToTelegram(ctx context.Context, content *event.MessageEventContent, sticker bool) (tg.InputMediaClass, error) { +func (tc *TelegramClient) transferMediaToTelegram(ctx context.Context, content *event.MessageEventContent, sticker bool) (tg.InputMediaClass, error) { var upload tg.InputFileClass var forceDocument bool filename := getMediaFilename(content) - err := t.main.Bridge.Bot.DownloadMediaToFile(ctx, content.URL, content.File, false, func(f *os.File) (err error) { + err := tc.main.Bridge.Bot.DownloadMediaToFile(ctx, content.URL, content.File, false, func(f *os.File) (err error) { uploadFilename := f.Name() if sticker && content.Info != nil && (content.Info.MimeType == "image/png" || content.Info.MimeType == "image/jpeg") { tempFile, err := os.CreateTemp("", "telegram-sticker-*.webp") @@ -270,7 +270,7 @@ func (t *TelegramClient) transferMediaToTelegram(ctx context.Context, content *e // We also have the image_as_file_pixels configuration threshold to // prevent Telegram from compressing the file. aspectRatio := float64(max(cfg.Height, cfg.Width)) / float64(min(cfg.Height, cfg.Width)) - forceDocument = cfg.Height*cfg.Width > t.main.Config.ImageAsFilePixels || + forceDocument = cfg.Height*cfg.Width > tc.main.Config.ImageAsFilePixels || info.Size() > int64(10*1024*1024) || aspectRatio > 20 || cfg.Height+cfg.Width > 10000 @@ -298,7 +298,7 @@ func (t *TelegramClient) transferMediaToTelegram(ctx context.Context, content *e content.Info.MimeType = "image/jpeg" } - upload, err = uploader.NewUploader(t.client.API()).FromPath(ctx, uploadFilename, filename) + upload, err = uploader.NewUploader(tc.client.API()).FromPath(ctx, uploadFilename, filename) return }) if err != nil { @@ -349,7 +349,7 @@ func (t *TelegramClient) transferMediaToTelegram(ctx context.Context, content *e }, nil } -func (t *TelegramClient) humaniseSendError(err error) bridgev2.MessageStatus { +func (tc *TelegramClient) humaniseSendError(err error) bridgev2.MessageStatus { status := bridgev2.WrapErrorInStatus(err). WithErrorReason(event.MessageStatusNetworkError). WithMessage(humanise.Error(err)) @@ -381,7 +381,7 @@ func (t *TelegramClient) humaniseSendError(err error) bridgev2.MessageStatus { WithStatus(event.MessageStatusFail) } -func (tg *TelegramConnector) GenerateTransactionID(userID id.UserID, roomID id.RoomID, eventType event.Type) networkid.RawTransactionID { +func (tc *TelegramConnector) GenerateTransactionID(userID id.UserID, roomID id.RoomID, eventType event.Type) networkid.RawTransactionID { return networkid.RawTransactionID(strconv.FormatInt(rand.Int64(), 10)) } @@ -394,17 +394,17 @@ func parseRandomID(txnID networkid.RawTransactionID) int64 { return rand.Int64() } -func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (resp *bridgev2.MatrixMessageResponse, err error) { +func (tc *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.MatrixMessage) (resp *bridgev2.MatrixMessageResponse, err error) { if msg.Portal.RoomType == database.RoomTypeSpace { return nil, fmt.Errorf("can't send messages to space portals") } // Handle Matrix events only after initial connection has been established to avoid deadlocking gotd - err = t.clientInitialized.Wait(ctx) + err = tc.clientInitialized.Wait(ctx) if err != nil { return nil, err } - peer, topicID, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) + peer, topicID, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID) if err != nil { return nil, err } @@ -418,7 +418,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. noWebpage := msg.Content.BeeperLinkPreviews != nil && len(msg.Content.BeeperLinkPreviews) == 0 - message, entities := matrixfmt.Parse(ctx, t.matrixParser, msg.Content, msg.Portal) + message, entities := matrixfmt.Parse(ctx, tc.matrixParser, msg.Content, msg.Portal) var replyTo tg.InputReplyToClass if msg.ReplyTo != nil { @@ -442,11 +442,11 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. var updates tg.UpdatesClass if msg.Event.Type == event.EventSticker { var media tg.InputMediaClass - media, err = t.transferMediaToTelegram(ctx, msg.Content, true) + media, err = tc.transferMediaToTelegram(ctx, msg.Content, true) if err != nil { return nil, err } - updates, err = t.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{ + updates, err = tc.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{ Peer: peer, Message: message, Entities: entities, @@ -457,7 +457,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. } else { switch msg.Content.MsgType { case event.MsgText, event.MsgNotice, event.MsgEmote: - updates, err = t.client.API().MessagesSendMessage(ctx, &tg.MessagesSendMessageRequest{ + updates, err = tc.client.API().MessagesSendMessage(ctx, &tg.MessagesSendMessageRequest{ Peer: peer, NoWebpage: noWebpage, Message: message, @@ -467,11 +467,11 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. }) case event.MsgImage, event.MsgFile, event.MsgAudio, event.MsgVideo: var media tg.InputMediaClass - media, err = t.transferMediaToTelegram(ctx, msg.Content, false) + media, err = tc.transferMediaToTelegram(ctx, msg.Content, false) if err != nil { return nil, err } - updates, err = t.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{ + updates, err = tc.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{ Peer: peer, Message: message, Entities: entities, @@ -491,7 +491,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. message = desc } } - updates, err = t.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{ + updates, err = tc.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{ Peer: peer, Message: message, Media: &tg.InputMediaGeoPoint{ @@ -506,7 +506,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. } if err != nil { log.Err(err).Msg("failed to send message to Telegram") - return nil, t.humaniseSendError(err) + return nil, tc.humaniseSendError(err) } hasher := sha256.New() @@ -581,7 +581,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. resp = &bridgev2.MatrixMessageResponse{ DB: &database.Message{ ID: messageID, - SenderID: t.userID, + SenderID: tc.userID, Timestamp: timestamp, Metadata: &MessageMetadata{ ContentHash: hash, @@ -593,7 +593,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2. return } -func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error { +func (tc *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.MatrixEdit) error { if msg.Portal.RoomType == database.RoomTypeSpace { return fmt.Errorf("can't send messages to space portals") } @@ -602,7 +602,7 @@ func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Mat Str("handler", "matrix_edit"). Logger() - peer, _, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) + peer, _, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID) if err != nil { return err } @@ -612,7 +612,7 @@ func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Mat return err } - message, entities := matrixfmt.Parse(ctx, t.matrixParser, msg.Content, msg.Portal) + message, entities := matrixfmt.Parse(ctx, tc.matrixParser, msg.Content, msg.Portal) var newContentURI id.ContentURIString req := tg.MessagesEditMessageRequest{ @@ -631,7 +631,7 @@ func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Mat log.Info().Msg("media URI unchanged, skipping re-upload, just editing text") } else { log.Info().Msg("media URI changed, re-uploading media") - req.Media, err = t.transferMediaToTelegram(ctx, msg.Content, false) + req.Media, err = tc.transferMediaToTelegram(ctx, msg.Content, false) if err != nil { return err } @@ -639,9 +639,9 @@ func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Mat } else if !msg.Content.MsgType.IsText() { return fmt.Errorf("editing message type %s is unsupported", msg.Content.MsgType) } - updates, err := t.client.API().MessagesEditMessage(ctx, &req) + updates, err := tc.client.API().MessagesEditMessage(ctx, &req) if err != nil { - return t.humaniseSendError(err) + return tc.humaniseSendError(err) } hasher := sha256.New() @@ -690,17 +690,17 @@ func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Mat return nil } -func (t *TelegramClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridgev2.MatrixMessageRemove) error { +func (tc *TelegramClient) HandleMatrixMessageRemove(ctx context.Context, msg *bridgev2.MatrixMessageRemove) error { if msg.Portal.RoomType == database.RoomTypeSpace { return fmt.Errorf("can't send messages to space portals") - } else if dbMsg, err := t.main.Bridge.DB.Message.GetPartByMXID(ctx, msg.TargetMessage.MXID); err != nil { + } else if dbMsg, err := tc.main.Bridge.DB.Message.GetPartByMXID(ctx, msg.TargetMessage.MXID); err != nil { return err } else if _, messageID, err := ids.ParseMessageID(dbMsg.ID); err != nil { return err - } else if peer, _, err := t.inputPeerForPortalID(ctx, msg.Portal.ID); err != nil { + } else if peer, _, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID); err != nil { return err } else { - _, err := message.NewSender(t.client.API()). + _, err := message.NewSender(tc.client.API()). To(peer). Revoke(). Messages(ctx, messageID) @@ -708,7 +708,7 @@ func (t *TelegramClient) HandleMatrixMessageRemove(ctx context.Context, msg *bri } } -func (t *TelegramClient) PreHandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) { +func (tc *TelegramClient) PreHandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) { if msg.Portal.RoomType == database.RoomTypeSpace { return bridgev2.MatrixReactionPreResponse{}, fmt.Errorf("can't send messages to space portals") } @@ -720,7 +720,7 @@ func (t *TelegramClient) PreHandleMatrixReaction(ctx context.Context, msg *bridg var resp bridgev2.MatrixReactionPreResponse var maxReactions int - maxReactions, err := t.getReactionLimit(ctx, t.userID) + maxReactions, err := tc.getReactionLimit(ctx, tc.userID) if err != nil { return resp, err } @@ -728,7 +728,7 @@ func (t *TelegramClient) PreHandleMatrixReaction(ctx context.Context, msg *bridg keyNoVariation := variationselector.Remove(msg.Content.RelatesTo.Key) emojiID := ids.MakeEmojiIDFromEmoticon(msg.Content.RelatesTo.Key) if strings.HasPrefix(msg.Content.RelatesTo.Key, "mxc://") { - if file, err := t.main.Store.TelegramFile.GetByMXC(ctx, id.ContentURIString(msg.Content.RelatesTo.Key)); err != nil { + if file, err := tc.main.Store.TelegramFile.GetByMXC(ctx, id.ContentURIString(msg.Content.RelatesTo.Key)); err != nil { return resp, err } else if file == nil { return resp, fmt.Errorf("reaction MXC URI %s does not correspond with any known Telegram files", msg.Content.RelatesTo.Key) @@ -737,17 +737,17 @@ func (t *TelegramClient) PreHandleMatrixReaction(ctx context.Context, msg *bridg } else { emojiID = ids.MakeEmojiIDFromDocumentID(documentID) } - } else if t.main.Config.AlwaysCustomEmojiReaction { + } else if tc.main.Config.AlwaysCustomEmojiReaction { // Always use the unicodemoji reaction if available if documentID, ok := emojis.GetEmojiDocumentID(keyNoVariation); ok { log.Debug().Msg("Using custom emoji reaction") emojiID = ids.MakeEmojiIDFromDocumentID(documentID) } - } else if availableReactions, err := t.getAvailableReactions(ctx); err != nil { + } else if availableReactions, err := tc.getAvailableReactions(ctx); err != nil { return resp, fmt.Errorf("failed to get available reactions: %w", err) } else if _, ok := availableReactions[keyNoVariation]; ok { log.Debug().Msg("Not using custom emoji reaction since the emoji is available") - } else if documentID, ok := emojis.GetEmojiDocumentID(keyNoVariation); ok && !t.metadata.IsBot { + } else if documentID, ok := emojis.GetEmojiDocumentID(keyNoVariation); ok && !tc.metadata.IsBot { log.Debug().Msg("Using custom emoji reaction") emojiID = ids.MakeEmojiIDFromDocumentID(documentID) } @@ -755,14 +755,14 @@ func (t *TelegramClient) PreHandleMatrixReaction(ctx context.Context, msg *bridg log.Debug().Str("emoji_id", string(emojiID)).Msg("Pre-handled reaction") return bridgev2.MatrixReactionPreResponse{ - SenderID: t.userID, + SenderID: tc.userID, EmojiID: emojiID, Emoji: variationselector.FullyQualify(msg.Content.RelatesTo.Key), MaxReactions: maxReactions, }, nil } -func (t *TelegramClient) appendEmojiID(reactionList []tg.ReactionClass, emojiID networkid.EmojiID) ([]tg.ReactionClass, error) { +func (tc *TelegramClient) appendEmojiID(reactionList []tg.ReactionClass, emojiID networkid.EmojiID) ([]tg.ReactionClass, error) { if documentID, emoticon, err := ids.ParseEmojiID(emojiID); err != nil { return nil, err } else if documentID > 0 { @@ -772,8 +772,8 @@ func (t *TelegramClient) appendEmojiID(reactionList []tg.ReactionClass, emojiID } } -func (t *TelegramClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (reaction *database.Reaction, err error) { - peer, _, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) +func (tc *TelegramClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (reaction *database.Reaction, err error) { + peer, _, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID) if err != nil { return nil, err } @@ -784,17 +784,17 @@ func (t *TelegramClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2 var newReactions []tg.ReactionClass for _, existing := range msg.ExistingReactionsToKeep { - newReactions, err = t.appendEmojiID(newReactions, existing.EmojiID) + newReactions, err = tc.appendEmojiID(newReactions, existing.EmojiID) if err != nil { return nil, err } } - newReactions, err = t.appendEmojiID(newReactions, msg.PreHandleResp.EmojiID) + newReactions, err = tc.appendEmojiID(newReactions, msg.PreHandleResp.EmojiID) if err != nil { return nil, err } - _, err = t.client.API().MessagesSendReaction(ctx, &tg.MessagesSendReactionRequest{ + _, err = tc.client.API().MessagesSendReaction(ctx, &tg.MessagesSendReactionRequest{ Peer: peer, AddToRecent: true, MsgID: targetMessageID, @@ -809,27 +809,27 @@ func (t *TelegramClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2 return &database.Reaction{}, err } -func (t *TelegramClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error { +func (tc *TelegramClient) HandleMatrixReactionRemove(ctx context.Context, msg *bridgev2.MatrixReactionRemove) error { if msg.Portal.RoomType == database.RoomTypeSpace { return fmt.Errorf("can't send messages to space portals") } - peer, _, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) + peer, _, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID) if err != nil { return err } var newReactions []tg.ReactionClass - if maxReactions, err := t.getReactionLimit(ctx, t.userID); err != nil { + if maxReactions, err := tc.getReactionLimit(ctx, tc.userID); err != nil { return err } else if maxReactions > 1 { - existing, err := t.main.Bridge.DB.Reaction.GetAllToMessageBySender(ctx, msg.Portal.Receiver, msg.TargetReaction.MessageID, msg.TargetReaction.SenderID) + existing, err := tc.main.Bridge.DB.Reaction.GetAllToMessageBySender(ctx, msg.Portal.Receiver, msg.TargetReaction.MessageID, msg.TargetReaction.SenderID) if err != nil { return err } for _, existing := range existing { if msg.TargetReaction.EmojiID != existing.EmojiID { - newReactions, err = t.appendEmojiID(newReactions, existing.EmojiID) + newReactions, err = tc.appendEmojiID(newReactions, existing.EmojiID) if err != nil { return err } @@ -841,7 +841,7 @@ func (t *TelegramClient) HandleMatrixReactionRemove(ctx context.Context, msg *br if err != nil { return err } - _, err = t.client.API().MessagesSendReaction(ctx, &tg.MessagesSendReactionRequest{ + _, err = tc.client.API().MessagesSendReaction(ctx, &tg.MessagesSendReactionRequest{ Peer: peer, AddToRecent: true, MsgID: messageID, @@ -850,7 +850,7 @@ func (t *TelegramClient) HandleMatrixReactionRemove(ctx context.Context, msg *br return err } -func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridgev2.MatrixReadReceipt) error { +func (tc *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridgev2.MatrixReadReceipt) error { if msg.Portal.RoomType == database.RoomTypeSpace { return nil } @@ -866,7 +866,7 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg if msg.Portal.Metadata.(*PortalMetadata).IsForumGeneral { topicID = 1 } - inputPeer, _, parseErr := t.inputPeerForPortalID(ctx, msg.Portal.ID) + inputPeer, _, parseErr := tc.inputPeerForPortalID(ctx, msg.Portal.ID) if parseErr != nil { return parseErr } @@ -874,7 +874,7 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg var readMentionsErr, readReactionsErr, readMessagesErr error var wg sync.WaitGroup - isBot := t.metadata.IsBot + isBot := tc.metadata.IsBot // Read mentions wg.Add(1) @@ -883,7 +883,7 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg if isBot { return } - _, readMentionsErr = t.client.API().MessagesReadMentions(ctx, &tg.MessagesReadMentionsRequest{ + _, readMentionsErr = tc.client.API().MessagesReadMentions(ctx, &tg.MessagesReadMentionsRequest{ Peer: inputPeer, TopMsgID: topicID, }) @@ -896,7 +896,7 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg if isBot { return } - _, readMentionsErr = t.client.API().MessagesReadReactions(ctx, &tg.MessagesReadReactionsRequest{ + _, readMentionsErr = tc.client.API().MessagesReadReactions(ctx, &tg.MessagesReadReactionsRequest{ Peer: inputPeer, TopMsgID: topicID, }) @@ -913,7 +913,7 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg message := msg.ExactMessage if message == nil { - message, readMessagesErr = t.main.Bridge.DB.Message.GetLastPartAtOrBeforeTime(ctx, msg.Portal.PortalKey, time.Now()) + message, readMessagesErr = tc.main.Bridge.DB.Message.GetLastPartAtOrBeforeTime(ctx, msg.Portal.PortalKey, time.Now()) if readMessagesErr != nil { return } else if message == nil { @@ -929,29 +929,29 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg switch peerType { case ids.PeerTypeUser, ids.PeerTypeChat: - _, readMessagesErr = t.client.API().MessagesReadHistory(ctx, &tg.MessagesReadHistoryRequest{ + _, readMessagesErr = tc.client.API().MessagesReadHistory(ctx, &tg.MessagesReadHistoryRequest{ Peer: inputPeer, MaxID: maxID, }) case ids.PeerTypeChannel: var accessHash int64 - accessHash, readMessagesErr = t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, portalID) + accessHash, readMessagesErr = tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, portalID) if readMessagesErr != nil { return } - _, readMessagesErr = t.client.API().ChannelsReadHistory(ctx, &tg.ChannelsReadHistoryRequest{ + _, readMessagesErr = tc.client.API().ChannelsReadHistory(ctx, &tg.ChannelsReadHistoryRequest{ Channel: &tg.InputChannel{ChannelID: portalID, AccessHash: accessHash}, MaxID: maxID, }) meta := msg.Portal.Metadata.(*PortalMetadata) randomID := meta.SponsoredMessageRandomID - if !t.metadata.IsBot && + if !tc.metadata.IsBot && randomID != nil && time.Since(meta.SponsoredMessagePollTS.Time) < 15*time.Minute && (meta.SponsoredMessageEventID == msg.EventID || msg.Receipt.Timestamp.After(meta.SponsoredMessagePollTS.Time)) && - meta.sponsoredMessageSeen.Add(t.telegramUserID) { - _, viewSponsoredErr := t.client.API().MessagesViewSponsoredMessage(ctx, randomID) + meta.sponsoredMessageSeen.Add(tc.telegramUserID) { + _, viewSponsoredErr := tc.client.API().MessagesViewSponsoredMessage(ctx, randomID) if viewSponsoredErr != nil { log.Err(viewSponsoredErr).Msg("Failed to mark sponsored message as viewed after read receipt") } else { @@ -967,11 +967,11 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg // Poll for reactions (non-blocking to avoid deadlock when portal event buffer is disabled) go func() { - err := t.maybePollForReactions(ctx, msg.Portal) + err := tc.maybePollForReactions(ctx, msg.Portal) if err != nil { log.Err(err).Msg("failed to poll for reactions after read receipt") } - err = t.pollSponsoredMessage(ctx, msg.Portal) + err = tc.pollSponsoredMessage(ctx, msg.Portal) if err != nil { log.Err(err).Msg("failed to poll for sponsored message after read receipt") } @@ -979,12 +979,12 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg if peerType == ids.PeerTypeChannel && !msg.Portal.Metadata.(*PortalMetadata).FullSynced { log.Debug().Msg("Scheduling chat resync on read receipt because channel has never got a full sync") - go t.userLogin.QueueRemoteEvent(&simplevent.ChatResync{ + go tc.userLogin.QueueRemoteEvent(&simplevent.ChatResync{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventChatResync, PortalKey: msg.Portal.PortalKey, }, - GetChatInfoFunc: t.GetChatInfo, + GetChatInfoFunc: tc.GetChatInfo, }) } @@ -992,11 +992,11 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg return errors.Join(readMentionsErr, readReactionsErr, readMessagesErr) } -func (t *TelegramClient) HandleMatrixTyping(ctx context.Context, msg *bridgev2.MatrixTyping) error { +func (tc *TelegramClient) HandleMatrixTyping(ctx context.Context, msg *bridgev2.MatrixTyping) error { if msg.Portal.RoomType == database.RoomTypeSpace { return nil } - inputPeer, topicID, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) + inputPeer, topicID, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID) if err != nil { return err } @@ -1016,7 +1016,7 @@ func (t *TelegramClient) HandleMatrixTyping(ctx context.Context, msg *bridgev2.M if !msg.IsTyping { action = &tg.SendMessageCancelAction{} } - _, err = t.client.API().MessagesSetTyping(ctx, &tg.MessagesSetTypingRequest{ + _, err = tc.client.API().MessagesSetTyping(ctx, &tg.MessagesSetTypingRequest{ Peer: inputPeer, TopMsgID: topicID, Action: action, @@ -1024,14 +1024,14 @@ func (t *TelegramClient) HandleMatrixTyping(ctx context.Context, msg *bridgev2.M return err } -func (t *TelegramClient) HandleMatrixDisappearingTimer(ctx context.Context, msg *bridgev2.MatrixDisappearingTimer) (bool, error) { - inputPeer, topicID, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) +func (tc *TelegramClient) HandleMatrixDisappearingTimer(ctx context.Context, msg *bridgev2.MatrixDisappearingTimer) (bool, error) { + inputPeer, topicID, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID) if err != nil { return false, err } else if topicID > 0 { return false, fmt.Errorf("topics can't have their own disappearing timer") } - _, err = t.client.API().MessagesSetHistoryTTL(ctx, &tg.MessagesSetHistoryTTLRequest{ + _, err = tc.client.API().MessagesSetHistoryTTL(ctx, &tg.MessagesSetHistoryTTLRequest{ Peer: inputPeer, Period: int(msg.Content.Timer.Seconds()), }) @@ -1044,8 +1044,8 @@ func (t *TelegramClient) HandleMatrixDisappearingTimer(ctx context.Context, msg return err == nil, err } -func (t *TelegramClient) HandleMute(ctx context.Context, msg *bridgev2.MatrixMute) error { - inputPeer, topicID, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) +func (tc *TelegramClient) HandleMute(ctx context.Context, msg *bridgev2.MatrixMute) error { + inputPeer, topicID, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID) if err != nil { return err } @@ -1061,40 +1061,40 @@ func (t *TelegramClient) HandleMute(ctx context.Context, msg *bridgev2.MatrixMut peer = &tg.InputNotifyPeer{Peer: inputPeer} } - _, err = t.client.API().AccountUpdateNotifySettings(ctx, &tg.AccountUpdateNotifySettingsRequest{ + _, err = tc.client.API().AccountUpdateNotifySettings(ctx, &tg.AccountUpdateNotifySettingsRequest{ Peer: peer, Settings: settings, }) return err } -func (t *TelegramClient) HandleRoomTag(ctx context.Context, msg *bridgev2.MatrixRoomTag) error { - inputPeer, topicID, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) +func (tc *TelegramClient) HandleRoomTag(ctx context.Context, msg *bridgev2.MatrixRoomTag) error { + inputPeer, topicID, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID) if err != nil { return err } else if topicID > 0 { return fmt.Errorf("topics can't be pinned for yourself") } - _, err = t.client.API().MessagesToggleDialogPin(ctx, &tg.MessagesToggleDialogPinRequest{ + _, err = tc.client.API().MessagesToggleDialogPin(ctx, &tg.MessagesToggleDialogPinRequest{ Pinned: slices.Contains(maps.Keys(msg.Content.Tags), event.RoomTagFavourite), Peer: &tg.InputDialogPeer{Peer: inputPeer}, }) return err } -func (t *TelegramClient) HandleMatrixDeleteChat(ctx context.Context, chat *bridgev2.MatrixDeleteChat) error { +func (tc *TelegramClient) HandleMatrixDeleteChat(ctx context.Context, chat *bridgev2.MatrixDeleteChat) error { peerType, id, topicID, err := ids.ParsePortalID(chat.Portal.ID) if err != nil { return err } switch peerType { case ids.PeerTypeUser: - accessHash, err := t.ScopedStore.GetAccessHash(ctx, peerType, id) + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, peerType, id) if err != nil { return err } - _, err = t.client.API().MessagesDeleteHistory(ctx, &tg.MessagesDeleteHistoryRequest{ + _, err = tc.client.API().MessagesDeleteHistory(ctx, &tg.MessagesDeleteHistoryRequest{ Peer: &tg.InputPeerUser{UserID: id, AccessHash: accessHash}, JustClear: !chat.Content.DeleteForEveryone, Revoke: chat.Content.DeleteForEveryone, @@ -1107,7 +1107,7 @@ func (t *TelegramClient) HandleMatrixDeleteChat(ctx context.Context, chat *bridg if !chat.Content.DeleteForEveryone { return fmt.Errorf("chats can only be deleted for everyone or left") } - result, err := t.client.API().MessagesDeleteChat(ctx, id) + result, err := tc.client.API().MessagesDeleteChat(ctx, id) if err != nil { return err } @@ -1119,12 +1119,12 @@ func (t *TelegramClient) HandleMatrixDeleteChat(ctx context.Context, chat *bridg if !chat.Content.DeleteForEveryone { return fmt.Errorf("channels can only be deleted for everyone or left") } - accessHash, err := t.ScopedStore.GetAccessHash(ctx, peerType, id) + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, peerType, id) if err != nil { return err } if topicID > 0 { - _, err = t.client.API().MessagesDeleteTopicHistory(ctx, &tg.MessagesDeleteTopicHistoryRequest{ + _, err = tc.client.API().MessagesDeleteTopicHistory(ctx, &tg.MessagesDeleteTopicHistoryRequest{ Peer: &tg.InputPeerChannel{ ChannelID: id, AccessHash: accessHash, @@ -1132,7 +1132,7 @@ func (t *TelegramClient) HandleMatrixDeleteChat(ctx context.Context, chat *bridg TopMsgID: topicID, }) } else { - _, err = t.client.API().ChannelsDeleteChannel(ctx, &tg.InputChannel{ + _, err = tc.client.API().ChannelsDeleteChannel(ctx, &tg.InputChannel{ ChannelID: id, AccessHash: accessHash, }) @@ -1147,7 +1147,7 @@ func (t *TelegramClient) HandleMatrixDeleteChat(ctx context.Context, chat *bridg return nil } -func (t *TelegramClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2.MatrixRoomName) (bool, error) { +func (tc *TelegramClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2.MatrixRoomName) (bool, error) { peerType, id, topicID, err := ids.ParsePortalID(msg.Portal.ID) if err != nil { return false, err @@ -1155,7 +1155,7 @@ func (t *TelegramClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2 switch peerType { case ids.PeerTypeChat: - _, err = t.client.API().MessagesEditChatTitle(ctx, &tg.MessagesEditChatTitleRequest{ + _, err = tc.client.API().MessagesEditChatTitle(ctx, &tg.MessagesEditChatTitleRequest{ ChatID: id, Title: msg.Content.Name, }) @@ -1164,12 +1164,12 @@ func (t *TelegramClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2 } return true, nil case ids.PeerTypeChannel: - accessHash, err := t.ScopedStore.GetAccessHash(ctx, peerType, id) + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, peerType, id) if err != nil { return false, err } if topicID > 0 { - _, err = t.client.API().MessagesEditForumTopic(ctx, &tg.MessagesEditForumTopicRequest{ + _, err = tc.client.API().MessagesEditForumTopic(ctx, &tg.MessagesEditForumTopicRequest{ Peer: &tg.InputPeerChannel{ ChannelID: id, AccessHash: accessHash, @@ -1178,7 +1178,7 @@ func (t *TelegramClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2 Title: msg.Content.Name, }) } else { - _, err = t.client.API().ChannelsEditTitle(ctx, &tg.ChannelsEditTitleRequest{ + _, err = tc.client.API().ChannelsEditTitle(ctx, &tg.ChannelsEditTitleRequest{ Channel: &tg.InputChannel{ ChannelID: id, AccessHash: accessHash, @@ -1195,7 +1195,7 @@ func (t *TelegramClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2 } } -func (t *TelegramClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridgev2.MatrixRoomAvatar) (bool, error) { +func (tc *TelegramClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridgev2.MatrixRoomAvatar) (bool, error) { peerType, id, topicID, err := ids.ParsePortalID(msg.Portal.ID) if err != nil { return false, err @@ -1211,11 +1211,11 @@ func (t *TelegramClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridge if msg.Content.URL == "" { photo = &tg.InputChatPhotoEmpty{} } else { - data, err := t.main.Bridge.Bot.DownloadMedia(ctx, msg.Content.URL, nil) + data, err := tc.main.Bridge.Bot.DownloadMedia(ctx, msg.Content.URL, nil) if err != nil { return false, fmt.Errorf("failed to download avatar: %w", err) } - upload, err := uploader.NewUploader(t.client.API()).FromBytes(ctx, "avatar.jpg", data) + upload, err := uploader.NewUploader(tc.client.API()).FromBytes(ctx, "avatar.jpg", data) if err != nil { return false, fmt.Errorf("failed to upload avatar: %w", err) } @@ -1224,7 +1224,7 @@ func (t *TelegramClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridge switch peerType { case ids.PeerTypeChat: - _, err = t.client.API().MessagesEditChatPhoto(ctx, &tg.MessagesEditChatPhotoRequest{ + _, err = tc.client.API().MessagesEditChatPhoto(ctx, &tg.MessagesEditChatPhotoRequest{ ChatID: id, Photo: photo, }) @@ -1234,11 +1234,11 @@ func (t *TelegramClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridge // TODO update portal metadata return true, nil case ids.PeerTypeChannel: - accessHash, err := t.ScopedStore.GetAccessHash(ctx, peerType, id) + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, peerType, id) if err != nil { return false, err } - _, err = t.client.API().ChannelsEditPhoto(ctx, &tg.ChannelsEditPhotoRequest{ + _, err = tc.client.API().ChannelsEditPhoto(ctx, &tg.ChannelsEditPhotoRequest{ Channel: &tg.InputChannel{ ChannelID: id, AccessHash: accessHash, diff --git a/pkg/connector/handletelegram.go b/pkg/connector/handletelegram.go index 95800b60..62e71f2b 100644 --- a/pkg/connector/handletelegram.go +++ b/pkg/connector/handletelegram.go @@ -54,23 +54,23 @@ type IGetMessages interface { GetMessages() []int } -func (t *TelegramClient) selfLeaveChat(ctx context.Context, portalKey networkid.PortalKey, reason error) error { +func (tc *TelegramClient) selfLeaveChat(ctx context.Context, portalKey networkid.PortalKey, reason error) error { peerType, id, _, err := ids.ParsePortalID(portalKey.ID) if err != nil { return err } if peerType == ids.PeerTypeChannel { - t.updatesManager.RemoveChannel(id, reason) - topics, err := t.main.Store.Topic.GetAll(ctx, id) + tc.updatesManager.RemoveChannel(id, reason) + topics, err := tc.main.Store.Topic.GetAll(ctx, id) if err != nil { return err } for _, topicID := range topics { - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatDelete{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatDelete{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventChatDelete, - PortalKey: t.makePortalKeyFromID(peerType, id, topicID), - Sender: t.mySender(), + PortalKey: tc.makePortalKeyFromID(peerType, id, topicID), + Sender: tc.mySender(), LogContext: func(c zerolog.Context) zerolog.Context { return c.AnErr("self_leave_reason", reason) }, @@ -82,11 +82,11 @@ func (t *TelegramClient) selfLeaveChat(ctx context.Context, portalKey networkid. } } } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatDelete{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatDelete{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventChatDelete, PortalKey: portalKey, - Sender: t.mySender(), + Sender: tc.mySender(), LogContext: func(c zerolog.Context) zerolog.Context { return c.AnErr("self_leave_reason", reason) }, @@ -98,11 +98,11 @@ func (t *TelegramClient) selfLeaveChat(ctx context.Context, portalKey networkid. } if peerType == ids.PeerTypeChannel { // This is a no-op if there's no space portal - res = t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatDelete{ + res = tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatDelete{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventChatDelete, - PortalKey: t.makePortalKeyFromID(peerType, id, ids.TopicIDSpaceRoom), - Sender: t.mySender(), + PortalKey: tc.makePortalKeyFromID(peerType, id, ids.TopicIDSpaceRoom), + Sender: tc.mySender(), LogContext: func(c zerolog.Context) zerolog.Context { return c.AnErr("self_leave_reason", reason) }, @@ -116,35 +116,35 @@ func (t *TelegramClient) selfLeaveChat(ctx context.Context, portalKey networkid. return nil } -func (t *TelegramClient) onNotChannelMember(ctx context.Context, channelID int64) error { - return t.selfLeaveChat(ctx, t.makePortalKeyFromID(ids.PeerTypeChannel, channelID, 0), fmt.Errorf("startup channel member check failed")) +func (tc *TelegramClient) onNotChannelMember(ctx context.Context, channelID int64) error { + return tc.selfLeaveChat(ctx, tc.makePortalKeyFromID(ids.PeerTypeChannel, channelID, 0), fmt.Errorf("startup channel member check failed")) } -func (t *TelegramClient) onUpdateChannel(ctx context.Context, e tg.Entities, update *tg.UpdateChannel) error { +func (tc *TelegramClient) onUpdateChannel(ctx context.Context, e tg.Entities, update *tg.UpdateChannel) error { log := zerolog.Ctx(ctx).With(). Str("handler", "on_update_channel"). Int64("channel_id", update.ChannelID). Logger() // TODO resync topic portals? - portalKey := t.makePortalKeyFromID(ids.PeerTypeChannel, update.ChannelID, 0) + portalKey := tc.makePortalKeyFromID(ids.PeerTypeChannel, update.ChannelID, 0) // TODO is using the info in entities safe? channel, ok := e.Channels[update.ChannelID] if !ok { log.Debug().Msg("Fetching channel due to UpdateChannel event") - chats, err := APICallWithOnlyChatUpdates(ctx, t, func() (tg.MessagesChatsClass, error) { - if accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, update.ChannelID); err != nil { + chats, err := APICallWithOnlyChatUpdates(ctx, tc, func() (tg.MessagesChatsClass, error) { + if accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, update.ChannelID); err != nil { return nil, err } else { - return t.client.API().ChannelsGetChannels(ctx, []tg.InputChannelClass{ + return tc.client.API().ChannelsGetChannels(ctx, []tg.InputChannelClass{ &tg.InputChannel{ChannelID: update.ChannelID, AccessHash: accessHash}, }) } }) if err != nil { if tgerr.Is(err, tg.ErrChannelInvalid, tg.ErrChannelPrivate) { - return t.selfLeaveChat(ctx, portalKey, fmt.Errorf("error fetching after UpdateChannel: %w", err)) + return tc.selfLeaveChat(ctx, portalKey, fmt.Errorf("error fetching after UpdateChannel: %w", err)) } log.Err(err).Msg("Failed to get channel info after UpdateChannel event") return nil @@ -153,14 +153,14 @@ func (t *TelegramClient) onUpdateChannel(ctx context.Context, e tg.Entities, upd return nil } else if channel, ok = chats.GetChats()[0].(*tg.Channel); !ok { log.Error().Type("chat_type", chats.GetChats()[0]).Msg("Expected channel, got something else. Leaving the channel.") - return t.selfLeaveChat(ctx, portalKey, fmt.Errorf("channel not returned in getChannels after UpdateChannel")) + return tc.selfLeaveChat(ctx, portalKey, fmt.Errorf("channel not returned in getChannels after UpdateChannel")) } } if channel.Left { log.Debug().Msg("Update was for a left channel. Leaving the channel.") - return t.selfLeaveChat(ctx, portalKey, fmt.Errorf("channel has left=true after UpdateChannel")) + return tc.selfLeaveChat(ctx, portalKey, fmt.Errorf("channel has left=true after UpdateChannel")) } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatResync{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatResync{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventChatResync, PortalKey: portalKey, @@ -170,12 +170,12 @@ func (t *TelegramClient) onUpdateChannel(ctx context.Context, e tg.Entities, upd }, }, GetChatInfoFunc: func(ctx context.Context, portal *bridgev2.Portal) (*bridgev2.ChatInfo, error) { - chatInfo, mfm, err := t.wrapChatInfo(portal.ID, channel) + chatInfo, mfm, err := tc.wrapChatInfo(portal.ID, channel) if err != nil { return nil, err } if portal.MXID == "" { - err = t.fillChannelMembers(ctx, mfm, chatInfo.Members) + err = tc.fillChannelMembers(ctx, mfm, chatInfo.Members) if err != nil { return nil, err } @@ -186,7 +186,7 @@ func (t *TelegramClient) onUpdateChannel(ctx context.Context, e tg.Entities, upd return resultToError(res) } -func (t *TelegramClient) onUpdateNewMessage(ctx context.Context, entities tg.Entities, update IGetMessage) error { +func (tc *TelegramClient) onUpdateNewMessage(ctx context.Context, entities tg.Entities, update IGetMessage) error { log := *zerolog.Ctx(ctx) switch msg := update.GetMessage().(type) { case *tg.Message: @@ -208,7 +208,7 @@ func (t *TelegramClient) onUpdateNewMessage(ctx context.Context, entities tg.Ent } } - sender := t.getEventSender(msg, isBroadcastChannel) + sender := tc.getEventSender(msg, isBroadcastChannel) if media, ok := msg.GetMedia(); ok && media.TypeID() == tg.MessageMediaContactTypeID { contact := media.(*tg.MessageMediaContact) @@ -216,8 +216,8 @@ func (t *TelegramClient) onUpdateNewMessage(ctx context.Context, entities tg.Ent log.Info().Int64("user_id", contact.UserID).Msg("received contact") } - topicID := t.getTopicID(ctx, msg.PeerID, msg.ReplyTo) - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Message[*tg.Message]{ + topicID := tc.getTopicID(ctx, msg.PeerID, msg.ReplyTo) + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Message[*tg.Message]{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventMessage, LogContext: func(c zerolog.Context) zerolog.Context { @@ -229,23 +229,23 @@ func (t *TelegramClient) onUpdateNewMessage(ctx context.Context, entities tg.Ent Stringer("peer_id", msg.PeerID) }, Sender: sender, - PortalKey: t.makePortalKeyFromPeer(msg.PeerID, topicID), + PortalKey: tc.makePortalKeyFromPeer(msg.PeerID, topicID), CreatePortal: true, Timestamp: time.Unix(int64(msg.Date), 0), StreamOrder: int64(msg.GetID()), }, ID: ids.GetMessageIDFromMessage(msg), Data: msg, - ConvertMessageFunc: t.convertToMatrix, + ConvertMessageFunc: tc.convertToMatrix, }) if err := resultToError(res); err != nil { return err } - return t.handleTelegramReactions(ctx, msg.PeerID, topicID, msg.ID, msg.Reactions) + return tc.handleTelegramReactions(ctx, msg.PeerID, topicID, msg.ID, msg.Reactions) case *tg.MessageService: - return t.handleServiceMessage(ctx, msg) + return tc.handleServiceMessage(ctx, msg) default: log.Warn(). @@ -255,11 +255,11 @@ func (t *TelegramClient) onUpdateNewMessage(ctx context.Context, entities tg.Ent } } -func (t *TelegramClient) getTopicID(ctx context.Context, peerID tg.PeerClass, rawReplyTo tg.MessageReplyHeaderClass) int { +func (tc *TelegramClient) getTopicID(ctx context.Context, peerID tg.PeerClass, rawReplyTo tg.MessageReplyHeaderClass) int { topicID := rawGetTopicID(rawReplyTo) if topicID != 0 { channelPeer, _ := peerID.(*tg.PeerChannel) - err := t.main.Store.Topic.Add(ctx, channelPeer.GetChannelID(), topicID) + err := tc.main.Store.Topic.Add(ctx, channelPeer.GetChannelID(), topicID) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to save topic ID") } @@ -280,12 +280,12 @@ func rawGetTopicID(rawReplyTo tg.MessageReplyHeaderClass) int { return 0 } -func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.MessageService) error { +func (tc *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.MessageService) error { log := zerolog.Ctx(ctx) - sender := t.getEventSender(msg, false) + sender := tc.getEventSender(msg, false) eventMeta := simplevent.EventMeta{ - PortalKey: t.makePortalKeyFromPeer(msg.PeerID, t.getTopicID(ctx, msg.PeerID, msg.ReplyTo)), + PortalKey: tc.makePortalKeyFromPeer(msg.PeerID, tc.getTopicID(ctx, msg.PeerID, msg.ReplyTo)), Sender: sender, Timestamp: time.Unix(int64(msg.Date), 0), LogContext: func(c zerolog.Context) zerolog.Context { @@ -301,7 +301,7 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa } switch action := msg.Action.(type) { case *tg.MessageActionChatEditTitle: - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventChatInfoChange), ChatInfoChange: &bridgev2.ChatInfoChange{ChatInfo: &bridgev2.ChatInfo{Name: &action.Title}}, }) @@ -309,18 +309,18 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa case *tg.MessageActionChatEditPhoto: switch peer := msg.PeerID.(type) { case *tg.PeerChat: - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventChatInfoChange), ChatInfoChange: &bridgev2.ChatInfoChange{ChatInfo: &bridgev2.ChatInfo{ - Avatar: t.avatarFromPhoto(ctx, ids.PeerTypeChat, peer.ChatID, action.Photo), + Avatar: tc.avatarFromPhoto(ctx, ids.PeerTypeChat, peer.ChatID, action.Photo), }}, }) return resultToError(res) case *tg.PeerChannel: - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventChatInfoChange), ChatInfoChange: &bridgev2.ChatInfoChange{ChatInfo: &bridgev2.ChatInfo{ - Avatar: t.avatarFromPhoto(ctx, ids.PeerTypeChannel, peer.ChannelID, action.Photo), + Avatar: tc.avatarFromPhoto(ctx, ids.PeerTypeChannel, peer.ChannelID, action.Photo), }}, }) return resultToError(res) @@ -329,7 +329,7 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa } case *tg.MessageActionChatDeletePhoto: - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventChatInfoChange), ChatInfoChange: &bridgev2.ChatInfoChange{ChatInfo: &bridgev2.ChatInfo{Avatar: &bridgev2.Avatar{Remove: true}}}, }) @@ -340,17 +340,17 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa } for _, userID := range action.Users { memberChanges.MemberMap.Set(bridgev2.ChatMember{ - EventSender: t.senderForUserID(userID), + EventSender: tc.senderForUserID(userID), Membership: event.MembershipJoin, }) } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventChatInfoChange), ChatInfoChange: &bridgev2.ChatInfoChange{MemberChanges: memberChanges}, }) return resultToError(res) case *tg.MessageActionChatJoinedByLink: - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventChatInfoChange), ChatInfoChange: &bridgev2.ChatInfoChange{ MemberChanges: &bridgev2.ChatMemberList{ @@ -363,15 +363,15 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa }) return resultToError(res) case *tg.MessageActionChatDeleteUser: - if action.UserID == t.telegramUserID { - return t.selfLeaveChat(ctx, eventMeta.PortalKey, fmt.Errorf("delete user event for chat")) + if action.UserID == tc.telegramUserID { + return tc.selfLeaveChat(ctx, eventMeta.PortalKey, fmt.Errorf("delete user event for chat")) } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventChatInfoChange), ChatInfoChange: &bridgev2.ChatInfoChange{ MemberChanges: &bridgev2.ChatMemberList{ MemberMap: bridgev2.ChatMemberMap{}.Set(bridgev2.ChatMember{ - EventSender: t.senderForUserID(action.UserID), + EventSender: tc.senderForUserID(action.UserID), Membership: event.MembershipLeave, }), }, @@ -379,7 +379,7 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa }) return resultToError(res) case *tg.MessageActionChatCreate: - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Message[any]{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Message[any]{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventMessage).WithCreatePortal(true), ID: ids.GetMessageIDFromMessage(msg), ConvertMessageFunc: func(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data any) (*bridgev2.ConvertedMessage, error) { @@ -397,16 +397,16 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa return resultToError(res) case *tg.MessageActionChannelCreate: - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatResync{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatResync{ EventMeta: eventMeta. WithType(bridgev2.RemoteEventChatResync). WithCreatePortal(true), - GetChatInfoFunc: t.GetChatInfo, + GetChatInfoFunc: tc.GetChatInfo, }) if err := resultToError(res); err != nil { return err } - res = t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Message[any]{ + res = tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Message[any]{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventMessage), ID: ids.GetMessageIDFromMessage(msg), ConvertMessageFunc: func(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data any) (*bridgev2.ConvertedMessage, error) { @@ -426,7 +426,7 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa Type: event.DisappearingTypeAfterSend, Timer: time.Duration(action.Period) * time.Second, }.Normalize() - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventChatInfoChange), ChatInfoChange: &bridgev2.ChatInfoChange{ ChatInfo: &bridgev2.ChatInfo{ @@ -462,7 +462,7 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa body.WriteString(")") } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Message[any]{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Message[any]{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventMessage), ID: ids.GetMessageIDFromMessage(msg), ConvertMessageFunc: func(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data any) (*bridgev2.ConvertedMessage, error) { @@ -485,7 +485,7 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa body = fmt.Sprintf("Ended the video chat (%s)", exfmt.Duration(time.Duration(action.Duration)*time.Second)) } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Message[any]{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Message[any]{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventMessage), ID: ids.GetMessageIDFromMessage(msg), ConvertMessageFunc: func(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data any) (*bridgev2.ConvertedMessage, error) { @@ -515,11 +515,11 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa body.WriteString(", ") } - if ghost, err := t.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(userID)); err != nil { + if ghost, err := tc.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(userID)); err != nil { return err } else { var name string - if username, err := t.main.Store.Username.Get(ctx, ids.PeerTypeUser, userID); err != nil { + if username, err := tc.main.Store.Username.Get(ctx, ids.PeerTypeUser, userID); err != nil { name = "@" + username } else { name = ghost.Name @@ -532,7 +532,7 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa } body.WriteString(" to the video chat") html.WriteString(" to the video chat") - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Message[any]{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Message[any]{ EventMeta: eventMeta.WithType(bridgev2.RemoteEventMessage), ID: ids.GetMessageIDFromMessage(msg), ConvertMessageFunc: func(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, data any) (*bridgev2.ConvertedMessage, error) { @@ -553,7 +553,7 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa return resultToError(res) case *tg.MessageActionGroupCallScheduled: start := time.Unix(int64(action.ScheduleDate), 0) - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Message[any]{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Message[any]{ EventMeta: eventMeta. WithType(bridgev2.RemoteEventMessage). WithSender(bridgev2.EventSender{}), // Telegram shows it as not coming from a specific user @@ -577,12 +577,12 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa Str("old_portal_id", string(eventMeta.PortalKey.ID)). Int64("channel_id", action.ChannelID). Msg("MessageActionChatMigrateTo") - newPortalKey := t.makePortalKeyFromID(ids.PeerTypeChannel, action.ChannelID, 0) - if err := t.migrateChat(ctx, eventMeta.PortalKey, newPortalKey); err != nil { + newPortalKey := tc.makePortalKeyFromID(ids.PeerTypeChannel, action.ChannelID, 0) + if err := tc.migrateChat(ctx, eventMeta.PortalKey, newPortalKey); err != nil { log.Err(err).Msg("Failed to migrate chat to channel") return err } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Message[any]{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Message[any]{ EventMeta: eventMeta. WithPortalKey(newPortalKey). WithStreamOrder(0). @@ -604,26 +604,26 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa case *tg.MessageActionTopicCreate: channelPeer, _ := msg.PeerID.(*tg.PeerChannel) - err := t.main.Store.Topic.Add(ctx, channelPeer.GetChannelID(), msg.ID) + err := tc.main.Store.Topic.Add(ctx, channelPeer.GetChannelID(), msg.ID) if err != nil { return fmt.Errorf("failed to store new topic: %w", err) } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatResync{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatResync{ EventMeta: eventMeta. - WithPortalKey(t.makePortalKeyFromPeer(msg.PeerID, msg.ID)). + WithPortalKey(tc.makePortalKeyFromPeer(msg.PeerID, msg.ID)). WithType(bridgev2.RemoteEventChatResync). WithCreatePortal(true), - GetChatInfoFunc: t.GetChatInfo, + GetChatInfoFunc: tc.GetChatInfo, }) return resultToError(res) case *tg.MessageActionTopicEdit: // TODO specific changes? - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatResync{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatResync{ EventMeta: eventMeta. - WithPortalKey(t.makePortalKeyFromPeer(msg.PeerID, msg.ID)). + WithPortalKey(tc.makePortalKeyFromPeer(msg.PeerID, msg.ID)). WithType(bridgev2.RemoteEventChatResync). WithCreatePortal(true), - GetChatInfoFunc: t.GetChatInfo, + GetChatInfoFunc: tc.GetChatInfo, }) return resultToError(res) @@ -635,29 +635,29 @@ func (t *TelegramClient) handleServiceMessage(ctx context.Context, msg *tg.Messa } } -func (t *TelegramClient) migrateChat(ctx context.Context, oldPortalKey, newPortalKey networkid.PortalKey) error { - if t.main.Config.AlwaysTombstoneOnSupergroupMigration { - newPortal, err := t.main.Bridge.GetPortalByKey(ctx, newPortalKey) +func (tc *TelegramClient) migrateChat(ctx context.Context, oldPortalKey, newPortalKey networkid.PortalKey) error { + if tc.main.Config.AlwaysTombstoneOnSupergroupMigration { + newPortal, err := tc.main.Bridge.GetPortalByKey(ctx, newPortalKey) if err != nil { return fmt.Errorf("failed to get new portal for chat migration: %w", err) } - info, err := t.GetChatInfo(ctx, newPortal) + info, err := tc.GetChatInfo(ctx, newPortal) if err != nil { return fmt.Errorf("failed to get chat info for new portal: %w", err) } - err = newPortal.CreateMatrixRoom(ctx, t.userLogin, info) + err = newPortal.CreateMatrixRoom(ctx, tc.userLogin, info) if err != nil { return fmt.Errorf("failed to create Matrix room for new portal: %w", err) } } - result, portal, err := t.main.Bridge.ReIDPortal(ctx, oldPortalKey, newPortalKey) + result, portal, err := tc.main.Bridge.ReIDPortal(ctx, oldPortalKey, newPortalKey) if err != nil { return fmt.Errorf("failed to re-ID portal: %w", err) } else if result == bridgev2.ReIDResultSourceReIDd || result == bridgev2.ReIDResultTargetDeletedAndSourceReIDd { // If the source portal is re-ID'd, we need to sync metadata and participants. // If the source is deleted, then it doesn't matter, any existing target will already be correct - info, err := t.GetChatInfo(ctx, portal) + info, err := tc.GetChatInfo(ctx, portal) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to get chat info after re-ID") if tgerr.Is(err, tg.ErrChannelPrivate) { @@ -668,22 +668,22 @@ func (t *TelegramClient) migrateChat(ctx context.Context, oldPortalKey, newPorta return } zerolog.Ctx(ctx).Debug().Msg("Retrying GetChatInfo after re-ID") - info, err := t.GetChatInfo(ctx, portal) + info, err := tc.GetChatInfo(ctx, portal) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to get chat info after re-ID retry") } else { - portal.UpdateInfo(ctx, info, t.userLogin, nil, time.Time{}) + portal.UpdateInfo(ctx, info, tc.userLogin, nil, time.Time{}) } }() } } else { - portal.UpdateInfo(ctx, info, t.userLogin, nil, time.Time{}) + portal.UpdateInfo(ctx, info, tc.userLogin, nil, time.Time{}) } } return nil } -func (t *TelegramClient) getEventSender(msg interface { +func (tc *TelegramClient) getEventSender(msg interface { GetOut() bool GetFromID() (tg.PeerClass, bool) GetPeerID() tg.PeerClass @@ -691,24 +691,24 @@ func (t *TelegramClient) getEventSender(msg interface { if isBroadcastChannel && msg.GetPeerID().TypeID() == tg.PeerChannelTypeID { // Always send as the channel in broadcast channels. We set a // per-message profile to indicate the actual user it was from. - return t.getPeerSender(msg.GetPeerID()) + return tc.getPeerSender(msg.GetPeerID()) } if msg.GetOut() { - return t.mySender() + return tc.mySender() } peer, ok := msg.GetFromID() if !ok { peer = msg.GetPeerID() } - return t.getPeerSender(peer) + return tc.getPeerSender(peer) } -func (t *TelegramClient) getPeerSender(peer tg.PeerClass) bridgev2.EventSender { +func (tc *TelegramClient) getPeerSender(peer tg.PeerClass) bridgev2.EventSender { switch from := peer.(type) { case *tg.PeerUser: - return t.senderForUserID(from.UserID) + return tc.senderForUserID(from.UserID) case *tg.PeerChannel: return bridgev2.EventSender{ Sender: ids.MakeChannelUserID(from.ChannelID), @@ -718,8 +718,8 @@ func (t *TelegramClient) getPeerSender(peer tg.PeerClass) bridgev2.EventSender { } } -func (t *TelegramClient) onUserName(ctx context.Context, e tg.Entities, update *tg.UpdateUserName) error { - ghost, err := t.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(update.UserID)) +func (tc *TelegramClient) onUserName(ctx context.Context, e tg.Entities, update *tg.UpdateUserName) error { + ghost, err := tc.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(update.UserID)) if err != nil { return err } @@ -746,20 +746,20 @@ func (t *TelegramClient) onUserName(ctx context.Context, e tg.Entities, update * userInfo.Identifiers = slices.Compact(userInfo.Identifiers) } - name := t.main.Config.FormatDisplayname(update.FirstName, update.LastName, firstUsername, false, update.UserID) + name := tc.main.Config.FormatDisplayname(update.FirstName, update.LastName, firstUsername, false, update.UserID) userInfo.Name = &name - if meta.ContactSource != 0 && meta.ContactSource != t.telegramUserID && !t.main.Config.ContactNames { + if meta.ContactSource != 0 && meta.ContactSource != tc.telegramUserID && !tc.main.Config.ContactNames { // TODO fetch full info to accurately detect if the user is a contact or not userInfo.Name = nil } ghost.UpdateInfo(ctx, &userInfo) - if ghost.ID == t.userID { + if ghost.ID == tc.userID { var firstUsername string if len(update.Usernames) > 0 { firstUsername = update.Usernames[0].Username } - t.updateRemoteProfile(ctx, &tg.User{ + tc.updateRemoteProfile(ctx, &tg.User{ Self: true, ID: update.UserID, FirstName: update.FirstName, @@ -772,27 +772,27 @@ func (t *TelegramClient) onUserName(ctx context.Context, e tg.Entities, update * return nil } -func (t *TelegramClient) onDeleteMessages(ctx context.Context, channelID int64, update IGetMessages) error { +func (tc *TelegramClient) onDeleteMessages(ctx context.Context, channelID int64, update IGetMessages) error { for _, messageID := range update.GetMessages() { wrappedMessageID := ids.MakeMessageID(channelID, messageID) var portalKey networkid.PortalKey var ok bool - if portalKey, ok = t.recentMessageRooms.Get(wrappedMessageID); ok { + if portalKey, ok = tc.recentMessageRooms.Get(wrappedMessageID); ok { // key found in cache - } else if parts, err := t.main.Bridge.DB.Message.GetAllPartsByID(ctx, t.loginID, wrappedMessageID); err != nil { + } else if parts, err := tc.main.Bridge.DB.Message.GetAllPartsByID(ctx, tc.loginID, wrappedMessageID); err != nil { return err } else if len(parts) > 0 { portalKey = parts[0].Room } else if channelID != 0 { // This won't work for topics, but should work for any other channels - portalKey = t.makePortalKeyFromPeer(&tg.PeerChannel{ChannelID: channelID}, 0) + portalKey = tc.makePortalKeyFromPeer(&tg.PeerChannel{ChannelID: channelID}, 0) } else { zerolog.Ctx(ctx).Debug(). Int("message_id", messageID). Msg("Ignoring delete of unknown message") continue } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.MessageRemove{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.MessageRemove{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventMessageRemove, PortalKey: portalKey, @@ -806,31 +806,31 @@ func (t *TelegramClient) onDeleteMessages(ctx context.Context, channelID int64, return nil } -func (t *TelegramClient) updateGhost(ctx context.Context, userID int64, user *tg.User) (*bridgev2.UserInfo, error) { - ghost, err := t.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(userID)) +func (tc *TelegramClient) updateGhost(ctx context.Context, userID int64, user *tg.User) (*bridgev2.UserInfo, error) { + ghost, err := tc.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(userID)) if err != nil { return nil, err } - userInfo, err := t.wrapUserInfo(ctx, user, ghost) + userInfo, err := tc.wrapUserInfo(ctx, user, ghost) if err != nil { return nil, err } ghost.UpdateInfo(ctx, userInfo) - if !user.Min && ghost.ID == t.userID && t.updateRemoteProfile(ctx, user, ghost) { - t.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) + if !user.Min && ghost.ID == tc.userID && tc.updateRemoteProfile(ctx, user, ghost) { + tc.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) } return userInfo, nil } -func (t *TelegramClient) updateChannel(ctx context.Context, channel *tg.Channel) (*bridgev2.UserInfo, error) { +func (tc *TelegramClient) updateChannel(ctx context.Context, channel *tg.Channel) (*bridgev2.UserInfo, error) { // TODO resync portal metadata? - userInfo, err := t.wrapChannelGhostInfo(ctx, channel) + userInfo, err := tc.wrapChannelGhostInfo(ctx, channel) if err != nil { return nil, err } - ghost, err := t.main.Bridge.GetGhostByID(ctx, ids.MakeChannelUserID(channel.ID)) + ghost, err := tc.main.Bridge.GetGhostByID(ctx, ids.MakeChannelUserID(channel.ID)) if err != nil { return nil, err } @@ -840,10 +840,10 @@ func (t *TelegramClient) updateChannel(ctx context.Context, channel *tg.Channel) const updateHandlerStuck status.BridgeStateErrorCode = "tg-update-handler-stuck" -func (t *TelegramClient) onUpdateWrapper(ctx context.Context, e tg.Entities, upd tg.UpdateClass) error { +func (tc *TelegramClient) onUpdateWrapper(ctx context.Context, e tg.Entities, upd tg.UpdateClass) error { doneChan := make(chan error, 1) go func() { - doneChan <- t.onUpdate(ctx, e, upd) + doneChan <- tc.onUpdate(ctx, e, upd) }() ticker := time.NewTicker(10 * time.Second) defer ticker.Stop() @@ -857,15 +857,15 @@ func (t *TelegramClient) onUpdateWrapper(ctx context.Context, e tg.Entities, upd Msg("Telegram update handling is taking long") if time.Since(startedAt) > 3*time.Minute && !bridgeStateUpdated { bridgeStateUpdated = true - t.userLogin.BridgeState.Send(status.BridgeState{ + tc.userLogin.BridgeState.Send(status.BridgeState{ StateEvent: status.StateUnknownError, Error: updateHandlerStuck, Message: "Processing messages from Telegram is stuck", }) } case err := <-doneChan: - if bridgeStateUpdated && t.userLogin.BridgeState.GetPrevUnsent().Error == updateHandlerStuck { - t.userLogin.BridgeState.Send(status.BridgeState{ + if bridgeStateUpdated && tc.userLogin.BridgeState.GetPrevUnsent().Error == updateHandlerStuck { + tc.userLogin.BridgeState.Send(status.BridgeState{ StateEvent: status.StateConnected, Info: map[string]any{ "update_reason": "finished processing slow update", @@ -877,11 +877,11 @@ func (t *TelegramClient) onUpdateWrapper(ctx context.Context, e tg.Entities, upd } } -func (t *TelegramClient) onUpdate(ctx context.Context, e tg.Entities, upd tg.UpdateClass) error { +func (tc *TelegramClient) onUpdate(ctx context.Context, e tg.Entities, upd tg.UpdateClass) error { zerolog.Ctx(ctx).Trace().Stringer("update", upd).Msg("Raw update") for userID, user := range e.Users { zerolog.Ctx(ctx).Trace().Stringer("user", user).Msg("Raw user info in update") - if _, err := t.updateGhost(ctx, userID, user); err != nil { + if _, err := tc.updateGhost(ctx, userID, user); err != nil { return err } } @@ -889,65 +889,65 @@ func (t *TelegramClient) onUpdate(ctx context.Context, e tg.Entities, upd tg.Upd zerolog.Ctx(ctx).Trace().Stringer("chat", chat).Msg("Raw chat info in update") if chat.GetLeft() { // TODO don't ignore errors - t.selfLeaveChat(ctx, t.makePortalKeyFromID(ids.PeerTypeChat, chatID, 0), fmt.Errorf("left flag in entity update")) + tc.selfLeaveChat(ctx, tc.makePortalKeyFromID(ids.PeerTypeChat, chatID, 0), fmt.Errorf("left flag in entity update")) } } for _, channel := range e.Channels { zerolog.Ctx(ctx).Trace().Stringer("channel", channel).Msg("Raw channel info in update") if channel.GetLeft() { - t.selfLeaveChat(ctx, t.makePortalKeyFromID(ids.PeerTypeChannel, channel.ID, 0), fmt.Errorf("left flag in entity update")) + tc.selfLeaveChat(ctx, tc.makePortalKeyFromID(ids.PeerTypeChannel, channel.ID, 0), fmt.Errorf("left flag in entity update")) } - if _, err := t.updateChannel(ctx, channel); err != nil { + if _, err := tc.updateChannel(ctx, channel); err != nil { return err } } switch update := upd.(type) { case *tg.UpdateNewMessage: - return t.onUpdateNewMessage(ctx, e, update) + return tc.onUpdateNewMessage(ctx, e, update) case *tg.UpdateNewChannelMessage: - return t.onUpdateNewMessage(ctx, e, update) + return tc.onUpdateNewMessage(ctx, e, update) case *tg.UpdateChannel: - return t.onUpdateChannel(ctx, e, update) + return tc.onUpdateChannel(ctx, e, update) case *tg.UpdateUserName: - return t.onUserName(ctx, e, update) + return tc.onUserName(ctx, e, update) case *tg.UpdateDeleteMessages: - return t.onDeleteMessages(ctx, 0, update) + return tc.onDeleteMessages(ctx, 0, update) case *tg.UpdateDeleteChannelMessages: - return t.onDeleteMessages(ctx, update.ChannelID, update) + return tc.onDeleteMessages(ctx, update.ChannelID, update) case *tg.UpdateEditMessage: - return t.onMessageEdit(ctx, update) + return tc.onMessageEdit(ctx, update) case *tg.UpdateEditChannelMessage: - return t.onMessageEdit(ctx, update) + return tc.onMessageEdit(ctx, update) case *tg.UpdateMessageReactions: - return t.onMessageReactions(ctx, update) + return tc.onMessageReactions(ctx, update) case *tg.UpdateUserTyping: - return t.handleTyping(t.makePortalKeyFromID(ids.PeerTypeUser, update.UserID, 0), t.senderForUserID(update.UserID), update.Action) + return tc.handleTyping(tc.makePortalKeyFromID(ids.PeerTypeUser, update.UserID, 0), tc.senderForUserID(update.UserID), update.Action) case *tg.UpdateChatUserTyping: if update.FromID.TypeID() != tg.PeerUserTypeID { zerolog.Ctx(ctx).Warn().Str("from_id_type", update.FromID.TypeName()).Msg("unsupported from_id type") return nil } - return t.handleTyping(t.makePortalKeyFromID(ids.PeerTypeChat, update.ChatID, 0), t.getPeerSender(update.FromID), update.Action) + return tc.handleTyping(tc.makePortalKeyFromID(ids.PeerTypeChat, update.ChatID, 0), tc.getPeerSender(update.FromID), update.Action) case *tg.UpdateChannelUserTyping: - return t.handleTyping(t.makePortalKeyFromID(ids.PeerTypeChannel, update.ChannelID, update.TopMsgID), t.getPeerSender(update.FromID), update.Action) + return tc.handleTyping(tc.makePortalKeyFromID(ids.PeerTypeChannel, update.ChannelID, update.TopMsgID), tc.getPeerSender(update.FromID), update.Action) case *tg.UpdateReadHistoryOutbox: - return t.updateReadReceipt(ctx, e, update) + return tc.updateReadReceipt(ctx, e, update) case *tg.UpdateReadHistoryInbox: - return t.onOwnReadReceipt(t.makePortalKeyFromPeer(update.Peer, update.TopMsgID), update.MaxID) + return tc.onOwnReadReceipt(tc.makePortalKeyFromPeer(update.Peer, update.TopMsgID), update.MaxID) case *tg.UpdateReadChannelInbox: - return t.onOwnReadReceipt(t.makePortalKeyFromID(ids.PeerTypeChannel, update.ChannelID, 0), update.MaxID) + return tc.onOwnReadReceipt(tc.makePortalKeyFromID(ids.PeerTypeChannel, update.ChannelID, 0), update.MaxID) case *tg.UpdateNotifySettings: - return t.onNotifySettings(ctx, e, update) + return tc.onNotifySettings(ctx, e, update) case *tg.UpdatePinnedDialogs: - return t.onPinnedDialogs(ctx, e, update) + return tc.onPinnedDialogs(ctx, e, update) case *tg.UpdateChatDefaultBannedRights: - return t.onChatDefaultBannedRights(ctx, e, update) + return tc.onChatDefaultBannedRights(ctx, e, update) case *tg.UpdatePeerBlocked: - return t.onPeerBlocked(ctx, e, update) + return tc.onPeerBlocked(ctx, e, update) case *tg.UpdateChat: - return t.onChat(ctx, e, update) + return tc.onChat(ctx, e, update) case *tg.UpdatePhoneCall: - return t.onPhoneCall(ctx, e, update) + return tc.onPhoneCall(ctx, e, update) case *tg.UpdateUserStatus: // ignored return nil @@ -957,11 +957,11 @@ func (t *TelegramClient) onUpdate(ctx context.Context, e tg.Entities, upd tg.Upd } } -func (t *TelegramClient) onMessageReactions(ctx context.Context, update *tg.UpdateMessageReactions) error { - return t.handleTelegramReactions(ctx, update.Peer, update.TopMsgID, update.MsgID, update.Reactions) +func (tc *TelegramClient) onMessageReactions(ctx context.Context, update *tg.UpdateMessageReactions) error { + return tc.handleTelegramReactions(ctx, update.Peer, update.TopMsgID, update.MsgID, update.Reactions) } -func (t *TelegramClient) onMessageEdit(ctx context.Context, update IGetMessage) error { +func (tc *TelegramClient) onMessageEdit(ctx context.Context, update IGetMessage) error { msg, ok := update.GetMessage().(*tg.Message) if !ok { zerolog.Ctx(ctx).Warn(). @@ -970,23 +970,23 @@ func (t *TelegramClient) onMessageEdit(ctx context.Context, update IGetMessage) return nil } - topicID := t.getTopicID(ctx, msg.PeerID, msg.ReplyTo) + topicID := tc.getTopicID(ctx, msg.PeerID, msg.ReplyTo) // Channels don't use edits to signal reactions, and when sending the first reaction they send a no-op edit // with an empty reactions list, which would confuse the handle method. Therefore, just don't sync reactions // on channel message edits. if _, isChannel := msg.PeerID.(*tg.PeerChannel); !isChannel { - err := t.handleTelegramReactions(ctx, msg.PeerID, topicID, msg.ID, msg.Reactions) + err := tc.handleTelegramReactions(ctx, msg.PeerID, topicID, msg.ID, msg.Reactions) if err != nil { zerolog.Ctx(ctx).Err(err).Msg("Failed to handle reactions on edited message") } } - portalKey := t.makePortalKeyFromPeer(msg.PeerID, topicID) - portal, err := t.main.Bridge.GetPortalByKey(ctx, portalKey) + portalKey := tc.makePortalKeyFromPeer(msg.PeerID, topicID) + portal, err := tc.main.Bridge.GetPortalByKey(ctx, portalKey) if err != nil { return err } - sender := t.getEventSender(msg, !portal.Metadata.(*PortalMetadata).IsSuperGroup) + sender := tc.getEventSender(msg, !portal.Metadata.(*PortalMetadata).IsSuperGroup) // Check if this edit was a data export request acceptance message if sender.Sender == networkid.UserID("777000") { @@ -994,12 +994,12 @@ func (t *TelegramClient) onMessageEdit(ctx context.Context, update IGetMessage) zerolog.Ctx(ctx).Info(). Int("message_id", msg.ID). Msg("Received an edit to message that looks like the data export was accepted, marking takeout as retriable") - t.takeoutAccepted.Set() + tc.takeoutAccepted.Set() } // TODO detect takeout being rejected too } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Message[*tg.Message]{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Message[*tg.Message]{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventEdit, LogContext: func(c zerolog.Context) zerolog.Context { @@ -1017,7 +1017,7 @@ func (t *TelegramClient) onMessageEdit(ctx context.Context, update IGetMessage) Data: msg, ConvertEditFunc: func(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, existing []*database.Message, data *tg.Message) (*bridgev2.ConvertedEdit, error) { log := zerolog.Ctx(ctx) - converted, err := t.convertToMatrix(ctx, portal, intent, msg) + converted, err := tc.convertToMatrix(ctx, portal, intent, msg) if err != nil { return nil, err } @@ -1052,8 +1052,8 @@ func (t *TelegramClient) onMessageEdit(ctx context.Context, update IGetMessage) return resultToError(res) } -func (t *TelegramClient) handleTyping(portal networkid.PortalKey, sender bridgev2.EventSender, action tg.SendMessageActionClass) error { - if sender.IsFromMe || (sender.Sender == t.userID && sender.SenderLogin == t.userLogin.ID) { +func (tc *TelegramClient) handleTyping(portal networkid.PortalKey, sender bridgev2.EventSender, action tg.SendMessageActionClass) error { + if sender.IsFromMe || (sender.Sender == tc.userID && sender.SenderLogin == tc.userLogin.ID) { return nil } timeout := time.Duration(6) * time.Second @@ -1070,7 +1070,7 @@ func (t *TelegramClient) handleTyping(portal networkid.PortalKey, sender bridgev default: timeout = 0 } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Typing{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Typing{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventTyping, PortalKey: portal, @@ -1085,17 +1085,17 @@ func (t *TelegramClient) handleTyping(portal networkid.PortalKey, sender bridgev return resultToError(res) } -func (t *TelegramClient) updateReadReceipt(ctx context.Context, e tg.Entities, update *tg.UpdateReadHistoryOutbox) error { +func (tc *TelegramClient) updateReadReceipt(ctx context.Context, e tg.Entities, update *tg.UpdateReadHistoryOutbox) error { user, ok := update.Peer.(*tg.PeerUser) if !ok { // Read receipts from other users are meaningless in chats/channels // (they only say "someone read the message" and not who) return nil } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Receipt{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Receipt{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventReadReceipt, - PortalKey: t.makePortalKeyFromPeer(update.Peer, 0), + PortalKey: tc.makePortalKeyFromPeer(update.Peer, 0), Sender: bridgev2.EventSender{ SenderLogin: ids.MakeUserLoginID(user.UserID), Sender: ids.MakeUserID(user.UserID), @@ -1110,12 +1110,12 @@ func (t *TelegramClient) updateReadReceipt(ctx context.Context, e tg.Entities, u return resultToError(res) } -func (t *TelegramClient) onOwnReadReceipt(portalKey networkid.PortalKey, maxID int) error { - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Receipt{ +func (tc *TelegramClient) onOwnReadReceipt(portalKey networkid.PortalKey, maxID int) error { + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Receipt{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventReadReceipt, PortalKey: portalKey, - Sender: t.mySender(), + Sender: tc.mySender(), LogContext: func(c zerolog.Context) zerolog.Context { return c.Str("tg_event", "updateRead*Inbox") }, @@ -1126,14 +1126,14 @@ func (t *TelegramClient) onOwnReadReceipt(portalKey networkid.PortalKey, maxID i return resultToError(res) } -func (t *TelegramClient) inputPeerForPortalID(ctx context.Context, portalID networkid.PortalID) (tg.InputPeerClass, int, error) { +func (tc *TelegramClient) inputPeerForPortalID(ctx context.Context, portalID networkid.PortalID) (tg.InputPeerClass, int, error) { peerType, id, topicID, err := ids.ParsePortalID(portalID) if err != nil { return nil, 0, err } switch peerType { case ids.PeerTypeUser: - if accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, id); err != nil { + if accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, id); err != nil { return nil, 0, fmt.Errorf("failed to get user access hash for %d: %w", id, err) } else { return &tg.InputPeerUser{UserID: id, AccessHash: accessHash}, 0, nil @@ -1141,7 +1141,7 @@ func (t *TelegramClient) inputPeerForPortalID(ctx context.Context, portalID netw case ids.PeerTypeChat: return &tg.InputPeerChat{ChatID: id}, 0, nil case ids.PeerTypeChannel: - if accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id); err != nil { + if accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id); err != nil { return nil, 0, err } else { return &tg.InputPeerChannel{ChannelID: id, AccessHash: accessHash}, topicID, nil @@ -1151,14 +1151,14 @@ func (t *TelegramClient) inputPeerForPortalID(ctx context.Context, portalID netw } } -func (t *TelegramClient) getAppConfigCached(ctx context.Context) (map[string]any, error) { - if t.metadata.IsBot { +func (tc *TelegramClient) getAppConfigCached(ctx context.Context) (map[string]any, error) { + if tc.metadata.IsBot { return nil, nil } - t.appConfigLock.Lock() - defer t.appConfigLock.Unlock() - if t.appConfig == nil { - cfg, err := t.client.API().HelpGetAppConfig(ctx, t.appConfigHash) + tc.appConfigLock.Lock() + defer tc.appConfigLock.Unlock() + if tc.appConfig == nil { + cfg, err := tc.client.API().HelpGetAppConfig(ctx, tc.appConfigHash) if err != nil { return nil, err } @@ -1170,39 +1170,39 @@ func (t *TelegramClient) getAppConfigCached(ctx context.Context) (map[string]any if err != nil { return nil, err } - t.appConfig, ok = parsedConfig.(map[string]any) + tc.appConfig, ok = parsedConfig.(map[string]any) if !ok { - return nil, fmt.Errorf("failed to parse app config: unexpected type %T", t.appConfig) + return nil, fmt.Errorf("failed to parse app config: unexpected type %T", tc.appConfig) } - t.appConfigHash = appConfig.Hash + tc.appConfigHash = appConfig.Hash } - return t.appConfig, nil + return tc.appConfig, nil } -func (t *TelegramClient) getAvailableReactionsForCapability(ctx context.Context) ([]string, bool) { - _, err := t.getAvailableReactions(ctx) +func (tc *TelegramClient) getAvailableReactionsForCapability(ctx context.Context) ([]string, bool) { + _, err := tc.getAvailableReactions(ctx) if err != nil { zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to get available reactions for capability listing") } - return t.availableReactionsList, t.isPremiumCache.Load() + return tc.availableReactionsList, tc.isPremiumCache.Load() } -func (t *TelegramClient) getAvailableReactions(ctx context.Context) (map[string]struct{}, error) { - if t.metadata.IsBot { +func (tc *TelegramClient) getAvailableReactions(ctx context.Context) (map[string]struct{}, error) { + if tc.metadata.IsBot { return nil, nil - } else if !t.IsLoggedIn() { + } else if !tc.IsLoggedIn() { return nil, errors.New("you must be logged in to get available reactions") } log := zerolog.Ctx(ctx).With().Str("handler", "get_available_reactions").Logger() - t.availableReactionsLock.Lock() - defer t.availableReactionsLock.Unlock() - if t.availableReactions == nil || time.Since(t.availableReactionsFetched) > 12*time.Hour { - cfg, err := t.client.API().MessagesGetAvailableReactions(ctx, t.availableReactionsHash) + tc.availableReactionsLock.Lock() + defer tc.availableReactionsLock.Unlock() + if tc.availableReactions == nil || time.Since(tc.availableReactionsFetched) > 12*time.Hour { + cfg, err := tc.client.API().MessagesGetAvailableReactions(ctx, tc.availableReactionsHash) if err != nil { return nil, err } - t.availableReactionsFetched = time.Now() + tc.availableReactionsFetched = time.Now() switch v := cfg.(type) { case *tg.MessagesAvailableReactions: availableReactions, ok := cfg.(*tg.MessagesAvailableReactions) @@ -1212,26 +1212,26 @@ func (t *TelegramClient) getAvailableReactions(ctx context.Context) (map[string] log.Debug().Msg("Fetched new available reactions") - myGhost, err := t.main.Bridge.GetGhostByID(ctx, t.userID) + myGhost, err := tc.main.Bridge.GetGhostByID(ctx, tc.userID) if err != nil { log.Err(err).Msg("failed to get own ghost") } - t.availableReactions = make(map[string]struct{}, len(availableReactions.Reactions)) + tc.availableReactions = make(map[string]struct{}, len(availableReactions.Reactions)) for _, reaction := range availableReactions.Reactions { if !reaction.Inactive && (myGhost.Metadata.(*GhostMetadata).IsPremium || !reaction.Premium) { - t.availableReactions[reaction.Reaction] = struct{}{} + tc.availableReactions[reaction.Reaction] = struct{}{} } } - t.availableReactionsHash = availableReactions.Hash + tc.availableReactionsHash = availableReactions.Hash if myGhost.Metadata.(*GhostMetadata).IsPremium { // All reactions are allowed via the unicodemojipack feature - t.availableReactionsList = nil - t.isPremiumCache.Store(true) + tc.availableReactionsList = nil + tc.isPremiumCache.Store(true) } else { - t.availableReactionsList = maps.Keys(t.availableReactions) - t.isPremiumCache.Store(false) - slices.Sort(t.availableReactionsList) + tc.availableReactionsList = maps.Keys(tc.availableReactions) + tc.isPremiumCache.Store(false) + slices.Sort(tc.availableReactionsList) } case *tg.MessagesAvailableReactionsNotModified: log.Debug().Msg("Available reactions not modified") @@ -1239,27 +1239,27 @@ func (t *TelegramClient) getAvailableReactions(ctx context.Context) (map[string] log.Error().Type("reaction_type", v).Msg("failed to get available reactions: unexpected type") } } - return t.availableReactions, nil + return tc.availableReactions, nil } -func (t *TelegramClient) transferEmojisToMatrix(ctx context.Context, customEmojiIDs []int64) (result map[networkid.EmojiID]emojis.EmojiInfo, err error) { +func (tc *TelegramClient) transferEmojisToMatrix(ctx context.Context, customEmojiIDs []int64) (result map[networkid.EmojiID]emojis.EmojiInfo, err error) { result, customEmojiIDs = emojis.ConvertKnownEmojis(customEmojiIDs) if len(customEmojiIDs) == 0 { return } - if t.main.useDirectMedia { + if tc.main.useDirectMedia { for _, emojiID := range customEmojiIDs { mediaID, err := ids.DirectMediaInfo{ PeerType: ids.FakePeerTypeEmoji, - UserID: t.telegramUserID, + UserID: tc.telegramUserID, ID: emojiID, }.AsMediaID() if err != nil { return nil, err } - if mxcURI, err := t.main.Bridge.Matrix.GenerateContentURI(ctx, mediaID); err != nil { + if mxcURI, err := tc.main.Bridge.Matrix.GenerateContentURI(ctx, mediaID); err != nil { return nil, err } else { result[ids.MakeEmojiIDFromDocumentID(emojiID)] = emojis.EmojiInfo{EmojiURI: mxcURI, DocumentID: emojiID} @@ -1271,7 +1271,7 @@ func (t *TelegramClient) transferEmojisToMatrix(ctx context.Context, customEmoji missingCustomEmojiIDs := customEmojiIDs[:0] for _, emojiID := range customEmojiIDs { - file, err := t.main.Store.TelegramFile.GetByLocationID(ctx, store.TelegramFileLocationID(strconv.FormatInt(emojiID, 10))) + file, err := tc.main.Store.TelegramFile.GetByLocationID(ctx, store.TelegramFileLocationID(strconv.FormatInt(emojiID, 10))) if err != nil { return nil, fmt.Errorf("failed to get file for custom emoji %d: %w", emojiID, err) } else if file != nil { @@ -1284,17 +1284,17 @@ func (t *TelegramClient) transferEmojisToMatrix(ctx context.Context, customEmoji return } - customEmojiDocuments, err := t.client.API().MessagesGetCustomEmojiDocuments(ctx, missingCustomEmojiIDs) + customEmojiDocuments, err := tc.client.API().MessagesGetCustomEmojiDocuments(ctx, missingCustomEmojiIDs) if err != nil { return nil, err } for _, customEmojiDocument := range customEmojiDocuments { - mxcURI, _, _, err := media.NewTransferer(t.client.API()). - WithStickerConfig(t.main.Config.AnimatedSticker). + mxcURI, _, _, err := media.NewTransferer(tc.client.API()). + WithStickerConfig(tc.main.Config.AnimatedSticker). WithForceWebmStickerConvert(true). WithDocument(customEmojiDocument, false). - Transfer(ctx, t.main.Store, t.main.Bridge.Bot) + Transfer(ctx, tc.main.Store, tc.main.Bridge.Bot) if err != nil { return nil, err } @@ -1303,13 +1303,13 @@ func (t *TelegramClient) transferEmojisToMatrix(ctx context.Context, customEmoji return } -func (t *TelegramClient) onNotifySettings(ctx context.Context, e tg.Entities, update *tg.UpdateNotifySettings) error { +func (tc *TelegramClient) onNotifySettings(ctx context.Context, e tg.Entities, update *tg.UpdateNotifySettings) error { var portalKey networkid.PortalKey switch typedPeer := update.Peer.(type) { case *tg.NotifyPeer: - portalKey = t.makePortalKeyFromPeer(typedPeer.Peer, 0) + portalKey = tc.makePortalKeyFromPeer(typedPeer.Peer, 0) case *tg.NotifyForumTopic: - portalKey = t.makePortalKeyFromPeer(typedPeer.Peer, typedPeer.TopMsgID) + portalKey = tc.makePortalKeyFromPeer(typedPeer.Peer, typedPeer.TopMsgID) default: zerolog.Ctx(ctx).Debug(). Type("peer_type", update.Peer). @@ -1325,7 +1325,7 @@ func (t *TelegramClient) onNotifySettings(ctx context.Context, e tg.Entities, up mutedUntil = &bridgev2.Unmuted } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ ChatInfoChange: &bridgev2.ChatInfoChange{ ChatInfo: &bridgev2.ChatInfo{ UserLocal: &bridgev2.UserLocalPortalInfo{ @@ -1346,27 +1346,27 @@ func (t *TelegramClient) onNotifySettings(ctx context.Context, e tg.Entities, up return resultToError(res) } -func (t *TelegramClient) onPinnedDialogs(ctx context.Context, e tg.Entities, msg *tg.UpdatePinnedDialogs) error { +func (tc *TelegramClient) onPinnedDialogs(ctx context.Context, e tg.Entities, msg *tg.UpdatePinnedDialogs) error { needsUnpinning := map[networkid.PortalKey]struct{}{} - for _, portalID := range t.metadata.PinnedDialogs { + for _, portalID := range tc.metadata.PinnedDialogs { pt, id, _, err := ids.ParsePortalID(portalID) if err != nil { return err } - needsUnpinning[t.makePortalKeyFromID(pt, id, 0)] = struct{}{} + needsUnpinning[tc.makePortalKeyFromID(pt, id, 0)] = struct{}{} } - t.metadata.PinnedDialogs = nil + tc.metadata.PinnedDialogs = nil for _, d := range msg.Order { dialog, ok := d.(*tg.DialogPeer) if !ok { continue } - portalKey := t.makePortalKeyFromPeer(dialog.Peer, 0) + portalKey := tc.makePortalKeyFromPeer(dialog.Peer, 0) delete(needsUnpinning, portalKey) - t.metadata.PinnedDialogs = append(t.metadata.PinnedDialogs, portalKey.ID) + tc.metadata.PinnedDialogs = append(tc.metadata.PinnedDialogs, portalKey.ID) - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ ChatInfoChange: &bridgev2.ChatInfoChange{ ChatInfo: &bridgev2.ChatInfo{ UserLocal: &bridgev2.UserLocalPortalInfo{ @@ -1391,7 +1391,7 @@ func (t *TelegramClient) onPinnedDialogs(ctx context.Context, e tg.Entities, msg var empty event.RoomTag for portalKey := range needsUnpinning { - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ ChatInfoChange: &bridgev2.ChatInfoChange{ ChatInfo: &bridgev2.ChatInfo{ UserLocal: &bridgev2.UserLocalPortalInfo{ @@ -1414,22 +1414,22 @@ func (t *TelegramClient) onPinnedDialogs(ctx context.Context, e tg.Entities, msg } } - return t.userLogin.Save(ctx) + return tc.userLogin.Save(ctx) } -func (t *TelegramClient) onChatDefaultBannedRights(ctx context.Context, entities tg.Entities, update *tg.UpdateChatDefaultBannedRights) error { +func (tc *TelegramClient) onChatDefaultBannedRights(ctx context.Context, entities tg.Entities, update *tg.UpdateChatDefaultBannedRights) error { // TODO update all topic portals - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatInfoChange{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatInfoChange{ ChatInfoChange: &bridgev2.ChatInfoChange{ ChatInfo: &bridgev2.ChatInfo{ Members: &bridgev2.ChatMemberList{ - PowerLevels: t.getPowerLevelOverridesFromBannedRights(entities.Chats[0], update.DefaultBannedRights), + PowerLevels: tc.getPowerLevelOverridesFromBannedRights(entities.Chats[0], update.DefaultBannedRights), }, }, }, EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventChatInfoChange, - PortalKey: t.makePortalKeyFromPeer(update.Peer, 0), + PortalKey: tc.makePortalKeyFromPeer(update.Peer, 0), LogContext: func(c zerolog.Context) zerolog.Context { return c.Str("tg_event", "updateChatDefaultBannedRights") }, @@ -1438,7 +1438,7 @@ func (t *TelegramClient) onChatDefaultBannedRights(ctx context.Context, entities return resultToError(res) } -func (t *TelegramClient) onPeerBlocked(ctx context.Context, e tg.Entities, update *tg.UpdatePeerBlocked) error { +func (tc *TelegramClient) onPeerBlocked(ctx context.Context, e tg.Entities, update *tg.UpdatePeerBlocked) error { // TODO fix this after adding storage for block status (getDMPowerLevels also needs updating) if true { return nil @@ -1452,22 +1452,22 @@ func (t *TelegramClient) onPeerBlocked(ctx context.Context, e tg.Entities, updat } // Update the ghost - ghost, err := t.main.Bridge.GetGhostByID(ctx, userID) + ghost, err := tc.main.Bridge.GetGhostByID(ctx, userID) if err != nil { return err } // Find portals that are DMs with the user - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ChatResync{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ChatResync{ ChatInfo: &bridgev2.ChatInfo{ Members: &bridgev2.ChatMemberList{ - PowerLevels: t.getDMPowerLevels(ghost), + PowerLevels: tc.getDMPowerLevels(ghost), }, CanBackfill: true, }, EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventChatResync, - PortalKey: t.makePortalKeyFromPeer(update.PeerID, 0), + PortalKey: tc.makePortalKeyFromPeer(update.PeerID, 0), LogContext: func(c zerolog.Context) zerolog.Context { return c.Str("tg_event", "updatePeerBlocked") }, @@ -1476,17 +1476,17 @@ func (t *TelegramClient) onPeerBlocked(ctx context.Context, e tg.Entities, updat return resultToError(res) } -func (t *TelegramClient) onChat(ctx context.Context, e tg.Entities, update *tg.UpdateChat) error { +func (tc *TelegramClient) onChat(ctx context.Context, e tg.Entities, update *tg.UpdateChat) error { return nil } -func (t *TelegramClient) onPhoneCall(ctx context.Context, e tg.Entities, update *tg.UpdatePhoneCall) error { +func (tc *TelegramClient) onPhoneCall(ctx context.Context, e tg.Entities, update *tg.UpdatePhoneCall) error { log := zerolog.Ctx(ctx).With().Str("action", "on_phone_call").Logger() call, ok := update.PhoneCall.(*tg.PhoneCallRequested) if !ok { log.Info().Type("type", update.PhoneCall).Msg("Unhandled phone call update class") return nil - } else if call.ParticipantID != t.telegramUserID { + } else if call.ParticipantID != tc.telegramUserID { log.Warn().Msg("Received phone call for user that is not us") return nil } @@ -1501,12 +1501,12 @@ func (t *TelegramClient) onPhoneCall(ctx context.Context, e tg.Entities, update callType = event.BeeperActionMessageCallTypeVoice body.WriteString("call") } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.Message[any]{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.Message[any]{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventMessage, - PortalKey: t.makePortalKeyFromID(ids.PeerTypeUser, call.AdminID, 0), + PortalKey: tc.makePortalKeyFromID(ids.PeerTypeUser, call.AdminID, 0), CreatePortal: true, - Sender: t.senderForUserID(call.AdminID), + Sender: tc.senderForUserID(call.AdminID), LogContext: func(c zerolog.Context) zerolog.Context { return c.Str("tg_event", "updatePhoneCall") }, diff --git a/pkg/connector/ids.go b/pkg/connector/ids.go index 150bcaa5..b414c68c 100644 --- a/pkg/connector/ids.go +++ b/pkg/connector/ids.go @@ -23,18 +23,18 @@ import ( "go.mau.fi/mautrix-telegram/pkg/gotd/tg" ) -func (t *TelegramClient) makePortalKeyFromPeer(peer tg.PeerClass, topicID int) networkid.PortalKey { - key := ids.InternalPeerToPortalKey(peer, topicID, t.loginID) - if t.main.Bridge.Config.SplitPortals { - key.Receiver = t.userLogin.ID +func (tc *TelegramClient) makePortalKeyFromPeer(peer tg.PeerClass, topicID int) networkid.PortalKey { + key := ids.InternalPeerToPortalKey(peer, topicID, tc.loginID) + if tc.main.Bridge.Config.SplitPortals { + key.Receiver = tc.userLogin.ID } return key } -func (t *TelegramClient) makePortalKeyFromID(peerType ids.PeerType, chatID int64, topicID int) networkid.PortalKey { - key := ids.InternalMakePortalKey(peerType, chatID, topicID, t.loginID) - if t.main.Bridge.Config.SplitPortals { - key.Receiver = t.userLogin.ID +func (tc *TelegramClient) makePortalKeyFromID(peerType ids.PeerType, chatID int64, topicID int) networkid.PortalKey { + key := ids.InternalMakePortalKey(peerType, chatID, topicID, tc.loginID) + if tc.main.Bridge.Config.SplitPortals { + key.Receiver = tc.userLogin.ID } return key } diff --git a/pkg/connector/imagepack.go b/pkg/connector/imagepack.go index 95b70cc2..8640576e 100644 --- a/pkg/connector/imagepack.go +++ b/pkg/connector/imagepack.go @@ -49,8 +49,8 @@ import ( "go.mau.fi/mautrix-telegram/pkg/gotd/tgerr" ) -func (t *TelegramClient) fnListEmojiPacks(ce *commands.Event) { - resp, err := t.client.API().MessagesGetAllStickers(ce.Ctx, 0) +func (tc *TelegramClient) fnListEmojiPacks(ce *commands.Event) { + resp, err := tc.client.API().MessagesGetAllStickers(ce.Ctx, 0) if err != nil { ce.Reply("Failed to list image packs: %v", err) return @@ -76,7 +76,7 @@ func (t *TelegramClient) fnListEmojiPacks(ce *commands.Event) { ce.Reply("Your packs:\n\n%s", strings.Join(lines, "\n")) } -func (t *TelegramClient) fnUploadEmojiPack(ce *commands.Event) { +func (tc *TelegramClient) fnUploadEmojiPack(ce *commands.Event) { if len(ce.Args) < 3 || !strings.HasPrefix(ce.Args[1], "!") { ce.Reply("Usage: `$cmdprefix emoji-pack upload `") return @@ -94,7 +94,7 @@ func (t *TelegramClient) fnUploadEmojiPack(ce *commands.Event) { tgPackShortcode := ce.Args[0] roomID := id.RoomID(ce.Args[1]) packStateKey := strings.Join(ce.Args[2:], " ") - err := t.main.Bridge.Bot.EnsureJoined(ce.Ctx, roomID) + err := tc.main.Bridge.Bot.EnsureJoined(ce.Ctx, roomID) if err != nil { ce.Reply("Failed to join room: %v", err) return @@ -111,7 +111,7 @@ func (t *TelegramClient) fnUploadEmojiPack(ce *commands.Event) { } evtID := ce.React("\u23f3\ufe0f") defer redactReaction(ce, evtID) - link, err := t.synchronizeEmojiPack(ce.Ctx, ce, pack, tgPackShortcode) + link, err := tc.synchronizeEmojiPack(ce.Ctx, ce, pack, tgPackShortcode) if err != nil { ce.Reply("Failed to synchronize emoji pack: %v", err) return @@ -216,10 +216,10 @@ func normalizeImage(ctx context.Context, data []byte, info *event.FileInfo, emoj } } -func (t *TelegramClient) synchronizeEmoji( +func (tc *TelegramClient) synchronizeEmoji( ctx context.Context, shortcode string, img *event.ImagePackImage, emoji bool, ) (*tg.InputStickerSetItem, func(int64) error, error) { - data, err := t.main.Bridge.Bot.DownloadMedia(ctx, img.URL, nil) + data, err := tc.main.Bridge.Bot.DownloadMedia(ctx, img.URL, nil) if err != nil { return nil, nil, fmt.Errorf("failed to download %s (%s): %w", shortcode, img.URL, err) } @@ -243,11 +243,11 @@ func (t *TelegramClient) synchronizeEmoji( if err != nil { return nil, nil, fmt.Errorf("failed to normalize image for %s: %w", shortcode, err) } - up, err := uploader.NewUploader(t.client.API()).FromBytes(ctx, "", data) + up, err := uploader.NewUploader(tc.client.API()).FromBytes(ctx, "", data) if err != nil { return nil, nil, fmt.Errorf("failed to reupload %s: %w", shortcode, err) } - uploaded, err := t.client.API().MessagesUploadMedia(ctx, &tg.MessagesUploadMediaRequest{ + uploaded, err := tc.client.API().MessagesUploadMedia(ctx, &tg.MessagesUploadMediaRequest{ Media: &tg.InputMediaUploadedDocument{ File: up, ForceFile: true, @@ -270,7 +270,7 @@ func (t *TelegramClient) synchronizeEmoji( if realDocID == 0 { return fmt.Errorf("failed to get real document ID for %s/%d", shortcode, fakeDoc.ID) } - err = t.main.Store.TelegramFile.Insert(ctx, &store.TelegramFile{ + err = tc.main.Store.TelegramFile.Insert(ctx, &store.TelegramFile{ LocationID: store.TelegramFileLocationID(strconv.FormatInt(realDocID, 10)), MXC: img.URL, MIMEType: img.Info.MimeType, @@ -315,8 +315,8 @@ func extractNewDocID(oldSet tg.MessagesStickerSetClass, newSetBox tg.MessagesSti return found } -func (t *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands.Event, pack *event.ImagePackEventContent, packShortcode string) (string, error) { - resp, err := t.client.API().StickersCheckShortName(ctx, packShortcode) +func (tc *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands.Event, pack *event.ImagePackEventContent, packShortcode string) (string, error) { + resp, err := tc.client.API().StickersCheckShortName(ctx, packShortcode) if err != nil && !tgerr.Is(err, tg.ErrShortNameOccupied) { return "", fmt.Errorf("failed to check if shortcode is available: %w", err) } @@ -331,11 +331,11 @@ func (t *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands. if img == nil { return "", fmt.Errorf("pack must contain at least one image") } - item, saveCache, err := t.synchronizeEmoji(ctx, shortcode, img, isEmojiPack) + item, saveCache, err := tc.synchronizeEmoji(ctx, shortcode, img, isEmojiPack) if err != nil { return "", fmt.Errorf("failed to synchronize emoji %s: %w", shortcode, err) } - rawSet, err = t.client.API().StickersCreateStickerSet(ctx, &tg.StickersCreateStickerSetRequest{ + rawSet, err = tc.client.API().StickersCreateStickerSet(ctx, &tg.StickersCreateStickerSetRequest{ Emojis: isEmojiPack, UserID: &tg.InputUserSelf{}, Title: cmp.Or(pack.Metadata.DisplayName, packShortcode), @@ -350,7 +350,7 @@ func (t *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands. return "", fmt.Errorf("failed to cache document ID for new pack: %w", err) } } else { - rawSet, err = t.client.API().MessagesGetStickerSet(ctx, &tg.MessagesGetStickerSetRequest{ + rawSet, err = tc.client.API().MessagesGetStickerSet(ctx, &tg.MessagesGetStickerSetRequest{ Stickerset: &tg.InputStickerSetShortName{ShortName: packShortcode}, }) if err != nil { @@ -372,7 +372,7 @@ func (t *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands. deletedMXCs := make(map[id.ContentURIString]*tg.InputDocument, len(set.Documents)) existingMXCs := make(exmaps.Set[id.ContentURIString], len(set.Documents)) for _, doc := range set.Documents { - file, err := t.main.Store.TelegramFile.GetByLocationID(ctx, store.TelegramFileLocationID(strconv.FormatInt(doc.GetID(), 10))) + file, err := tc.main.Store.TelegramFile.GetByLocationID(ctx, store.TelegramFileLocationID(strconv.FormatInt(doc.GetID(), 10))) if err != nil { return "", fmt.Errorf("failed to get cached file for doc %d: %w", doc.GetID(), err) } else if file != nil { @@ -386,12 +386,12 @@ func (t *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands. continue } existingMXCs.Add(img.URL) - item, saveCache, err := t.synchronizeEmoji(ctx, shortcode, img, isEmojiPack) + item, saveCache, err := tc.synchronizeEmoji(ctx, shortcode, img, isEmojiPack) if err != nil { ce.Reply("Failed to reupload %s: %v", shortcode, err) continue } - rawNewSet, err := t.client.API().StickersAddStickerToSet(ctx, &tg.StickersAddStickerToSetRequest{ + rawNewSet, err := tc.client.API().StickersAddStickerToSet(ctx, &tg.StickersAddStickerToSetRequest{ Stickerset: inputSet, Sticker: *item, }) @@ -409,7 +409,7 @@ func (t *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands. rawSet = rawNewSet } for mxc, inputDoc := range deletedMXCs { - _, err = t.client.API().StickersRemoveStickerFromSet(ctx, inputDoc) + _, err = tc.client.API().StickersRemoveStickerFromSet(ctx, inputDoc) if err != nil { return "", fmt.Errorf("failed to remove %s/%d from set: %w", mxc, inputDoc.ID, err) } @@ -435,12 +435,12 @@ func redactReaction(ce *commands.Event, evtID id.EventID) { }, nil) } -func (t *TelegramClient) fnDownloadEmojiPack(ce *commands.Event) { +func (tc *TelegramClient) fnDownloadEmojiPack(ce *commands.Event) { if len(ce.Args) == 0 { ce.Reply("Usage: `$cmdprefix emoji-pack download `") return } - spaceRoom, err := t.userLogin.GetSpaceRoom(ce.Ctx) + spaceRoom, err := tc.userLogin.GetSpaceRoom(ce.Ctx) if err != nil { ce.Reply("Failed to get space room: %v", err) return @@ -457,7 +457,7 @@ func (t *TelegramClient) fnDownloadEmojiPack(ce *commands.Event) { ce.Reply("Invalid pack shortcode or link.") return } - rawSet, err := t.client.API().MessagesGetStickerSet(ce.Ctx, &tg.MessagesGetStickerSetRequest{Stickerset: input}) + rawSet, err := tc.client.API().MessagesGetStickerSet(ce.Ctx, &tg.MessagesGetStickerSetRequest{Stickerset: input}) if err != nil { ce.Reply("Failed to get sticker set: %v", err) return @@ -496,11 +496,11 @@ func (t *TelegramClient) fnDownloadEmojiPack(ce *commands.Event) { evtID := ce.React("\u23f3\ufe0f") defer redactReaction(ce, evtID) for i, rawDoc := range set.Documents { - mxc, _, info, err := media.NewTransferer(t.client.API()). - WithStickerConfig(t.main.Config.AnimatedSticker). + mxc, _, info, err := media.NewTransferer(tc.client.API()). + WithStickerConfig(tc.main.Config.AnimatedSticker). WithForceWebmStickerConvert(set.Set.Emojis). WithDocument(rawDoc, false). - Transfer(ce.Ctx, t.main.Store, t.main.Bridge.Bot) + Transfer(ce.Ctx, tc.main.Store, tc.main.Bridge.Bot) if err != nil { ce.Log.Err(err).Msg("Failed to transfer image in pack") ce.Reply("Failed to transfer document `%d`: %v", rawDoc.GetID(), err) @@ -530,13 +530,13 @@ func (t *TelegramClient) fnDownloadEmojiPack(ce *commands.Event) { Info: info, } } - _, err = t.main.Bridge.Bot.SendState(ce.Ctx, spaceRoom, event.StateUnstableImagePack, set.Set.ShortName, &event.Content{Parsed: pack}, time.Now()) + _, err = tc.main.Bridge.Bot.SendState(ce.Ctx, spaceRoom, event.StateUnstableImagePack, set.Set.ShortName, &event.Content{Parsed: pack}, time.Now()) if err != nil { ce.Reply("Failed to send image pack to space: %v", err) } else { ce.Reply( "Successfully bridged image pack to %s", format.MarkdownLink("your personal filtering space", - spaceRoom.URI(t.main.Bridge.Matrix.ServerName()).MatrixToURL())) + spaceRoom.URI(tc.main.Bridge.Matrix.ServerName()).MatrixToURL())) } } diff --git a/pkg/connector/login.go b/pkg/connector/login.go index ca564d6f..2b6bc267 100644 --- a/pkg/connector/login.go +++ b/pkg/connector/login.go @@ -64,7 +64,7 @@ var ( } ) -func (tg *TelegramConnector) GetLoginFlows() []bridgev2.LoginFlow { +func (tc *TelegramConnector) GetLoginFlows() []bridgev2.LoginFlow { return []bridgev2.LoginFlow{ { Name: "Phone Number", @@ -84,10 +84,10 @@ func (tg *TelegramConnector) GetLoginFlows() []bridgev2.LoginFlow { } } -func (tg *TelegramConnector) CreateLogin(ctx context.Context, user *bridgev2.User, flowID string) (bridgev2.LoginProcess, error) { +func (tc *TelegramConnector) CreateLogin(ctx context.Context, user *bridgev2.User, flowID string) (bridgev2.LoginProcess, error) { bl := &baseLogin{ user: user, - main: tg, + main: tc, flowID: flowID, } switch flowID { diff --git a/pkg/connector/metadata.go b/pkg/connector/metadata.go index c7aeef7e..dd1b258d 100644 --- a/pkg/connector/metadata.go +++ b/pkg/connector/metadata.go @@ -31,7 +31,7 @@ import ( "go.mau.fi/mautrix-telegram/pkg/gotd/session" ) -func (tg *TelegramConnector) GetDBMetaTypes() database.MetaTypes { +func (tc *TelegramConnector) GetDBMetaTypes() database.MetaTypes { return database.MetaTypes{ Ghost: func() any { return &GhostMetadata{} }, Portal: func() any { return &PortalMetadata{} }, diff --git a/pkg/connector/push.go b/pkg/connector/push.go index c9277c38..49cee849 100644 --- a/pkg/connector/push.go +++ b/pkg/connector/push.go @@ -256,13 +256,13 @@ var PushMessageFormats = map[string]string{ var FullSyncOnConnectBackground = false -func (t *TelegramClient) ConnectBackground(ctx context.Context, params *bridgev2.ConnectBackgroundParams) error { +func (tc *TelegramClient) ConnectBackground(ctx context.Context, params *bridgev2.ConnectBackgroundParams) error { data, _ := params.ExtraData.(*PushNotificationData) var relatedPortal *bridgev2.Portal var sender *bridgev2.Ghost var messageID networkid.MessageID var messageText, notificationText, notificationTitle string - if notifs, ok := t.main.Bridge.Matrix.(bridgev2.MatrixConnectorWithNotifications); ok && data != nil { + if notifs, ok := tc.main.Bridge.Matrix.(bridgev2.MatrixConnectorWithNotifications); ok && data != nil { if data.Aps != nil { notificationTitle = data.Aps.Alert.Title notificationText = data.Aps.Alert.Body @@ -282,23 +282,23 @@ func (t *TelegramClient) ConnectBackground(ctx context.Context, params *bridgev2 } var err error if data.Custom.ChannelID != 0 { - relatedPortal, err = t.main.Bridge.GetPortalByKey(ctx, t.makePortalKeyFromID(ids.PeerTypeChannel, data.Custom.ChannelID, data.Custom.TopicID)) + relatedPortal, err = tc.main.Bridge.GetPortalByKey(ctx, tc.makePortalKeyFromID(ids.PeerTypeChannel, data.Custom.ChannelID, data.Custom.TopicID)) } else if data.Custom.ChatID != 0 { - relatedPortal, err = t.main.Bridge.GetPortalByKey(ctx, t.makePortalKeyFromID(ids.PeerTypeChat, data.Custom.ChatID, 0)) + relatedPortal, err = tc.main.Bridge.GetPortalByKey(ctx, tc.makePortalKeyFromID(ids.PeerTypeChat, data.Custom.ChatID, 0)) } else if data.Custom.FromID != 0 { - relatedPortal, err = t.main.Bridge.GetPortalByKey(ctx, t.makePortalKeyFromID(ids.PeerTypeUser, data.Custom.FromID, 0)) + relatedPortal, err = tc.main.Bridge.GetPortalByKey(ctx, tc.makePortalKeyFromID(ids.PeerTypeUser, data.Custom.FromID, 0)) } if err != nil { return fmt.Errorf("failed to get related portal: %w", err) } if data.Custom.ChatFromBroadcastID != 0 { - sender, err = t.main.Bridge.GetGhostByID(ctx, ids.MakeChannelUserID(data.Custom.FromID)) + sender, err = tc.main.Bridge.GetGhostByID(ctx, ids.MakeChannelUserID(data.Custom.FromID)) } else if data.Custom.ChatFromGroupID != 0 { - sender, err = t.main.Bridge.GetGhostByID(ctx, ids.MakeChannelUserID(data.Custom.ChatFromGroupID)) + sender, err = tc.main.Bridge.GetGhostByID(ctx, ids.MakeChannelUserID(data.Custom.ChatFromGroupID)) } else if data.Custom.ChatFromID != 0 { - sender, err = t.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(data.Custom.ChatFromID)) + sender, err = tc.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(data.Custom.ChatFromID)) } else if data.Custom.FromID != 0 { - sender, err = t.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(data.Custom.FromID)) + sender, err = tc.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(data.Custom.FromID)) } if err != nil { return fmt.Errorf("failed to get sender: %w", err) @@ -317,8 +317,8 @@ func (t *TelegramClient) ConnectBackground(ctx context.Context, params *bridgev2 }) } if FullSyncOnConnectBackground { - t.Connect(ctx) - defer t.Disconnect() + tc.Connect(ctx) + defer tc.Disconnect() // TODO is it possible to safely only sync one chat? select { case <-time.After(20 * time.Second): @@ -328,7 +328,7 @@ func (t *TelegramClient) ConnectBackground(ctx context.Context, params *bridgev2 return nil } -func (tg *TelegramConnector) ParsePushNotification(ctx context.Context, data json.RawMessage) (networkid.UserLoginID, any, error) { +func (tc *TelegramConnector) ParsePushNotification(ctx context.Context, data json.RawMessage) (networkid.UserLoginID, any, error) { val := gjson.GetBytes(data, "p") if val.Type != gjson.String { return "", nil, fmt.Errorf("missing or invalid p field") @@ -342,7 +342,7 @@ func (tg *TelegramConnector) ParsePushNotification(ctx context.Context, data jso if err != nil { return "", nil, fmt.Errorf("failed to decode auth key and message ID: %w", err) } - userIDs, err := tg.Bridge.DB.UserLogin.GetAllUserIDsWithLogins(ctx) + userIDs, err := tc.Bridge.DB.UserLogin.GetAllUserIDsWithLogins(ctx) if err != nil { return "", nil, fmt.Errorf("failed to get users with logins: %w", err) } @@ -350,7 +350,7 @@ func (tg *TelegramConnector) ParsePushNotification(ctx context.Context, data jso var userLoginID networkid.UserLoginID UserLoop: for _, userID := range userIDs { - user, err := tg.Bridge.GetExistingUserByMXID(ctx, userID) + user, err := tc.Bridge.GetExistingUserByMXID(ctx, userID) if err != nil { return "", nil, fmt.Errorf("failed to get user %s: %w", userID, err) } @@ -398,11 +398,11 @@ UserLoop: return userLoginID, &pmd, nil } -func (t *TelegramClient) RegisterPushNotifications(ctx context.Context, pushType bridgev2.PushType, token string) error { - meta := t.metadata +func (tc *TelegramClient) RegisterPushNotifications(ctx context.Context, pushType bridgev2.PushType, token string) error { + meta := tc.metadata if meta.PushEncryptionKey == nil { meta.PushEncryptionKey = random.Bytes(256) - err := t.userLogin.Save(ctx) + err := tc.userLogin.Save(ctx) if err != nil { return fmt.Errorf("failed to save push encryption key: %w", err) } @@ -418,7 +418,7 @@ func (t *TelegramClient) RegisterPushNotifications(ctx context.Context, pushType default: return fmt.Errorf("unsupported push type %s", pushType) } - _, err := t.client.API().AccountRegisterDevice(ctx, &tg.AccountRegisterDeviceRequest{ + _, err := tc.client.API().AccountRegisterDevice(ctx, &tg.AccountRegisterDeviceRequest{ NoMuted: true, TokenType: tokenType, Token: token, @@ -429,6 +429,6 @@ func (t *TelegramClient) RegisterPushNotifications(ctx context.Context, pushType return err } -func (t *TelegramClient) GetPushConfigs() *bridgev2.PushConfig { +func (tc *TelegramClient) GetPushConfigs() *bridgev2.PushConfig { return &bridgev2.PushConfig{Native: true} } diff --git a/pkg/connector/reactions.go b/pkg/connector/reactions.go index d0ca41e0..45b9977e 100644 --- a/pkg/connector/reactions.go +++ b/pkg/connector/reactions.go @@ -32,7 +32,7 @@ import ( "go.mau.fi/mautrix-telegram/pkg/gotd/tg" ) -func (t *TelegramClient) computeReactionsList(ctx context.Context, peer tg.PeerClass, msgID int, msgReactions tg.MessageReactions) (reactions []tg.MessagePeerReaction, isFull bool, customEmojis map[networkid.EmojiID]emojis.EmojiInfo, err error) { +func (tc *TelegramClient) computeReactionsList(ctx context.Context, peer tg.PeerClass, msgID int, msgReactions tg.MessageReactions) (reactions []tg.MessagePeerReaction, isFull bool, customEmojis map[networkid.EmojiID]emojis.EmojiInfo, err error) { log := zerolog.Ctx(ctx).With().Str("fn", "computeReactionsList").Logger() var totalCount int for _, r := range msgReactions.Results { @@ -54,18 +54,18 @@ func (t *TelegramClient) computeReactionsList(ctx context.Context, peer tg.PeerC if len(reactionsList) < totalCount { if user, ok := peer.(*tg.PeerUser); ok { - reactionsList = splitDMReactionCounts(msgReactions.Results, user.UserID, t.telegramUserID) - } else if t.metadata.IsBot { + reactionsList = splitDMReactionCounts(msgReactions.Results, user.UserID, tc.telegramUserID) + } else if tc.metadata.IsBot { // Can't fetch exact reaction senders as a bot return // TODO remove redundant peer roundtrip, just add a peer -> input peer helper - } else if peer, _, err := t.inputPeerForPortalID(ctx, t.makePortalKeyFromPeer(peer, 0).ID); err != nil { + } else if peer, _, err := tc.inputPeerForPortalID(ctx, tc.makePortalKeyFromPeer(peer, 0).ID); err != nil { return nil, false, nil, fmt.Errorf("failed to get input peer: %w", err) } else { // TODO should calls to this be limited? - reactions, err := APICallWithUpdates(ctx, t, func() (*tg.MessagesMessageReactionsList, error) { - return t.client.API().MessagesGetMessageReactionsList(ctx, &tg.MessagesGetMessageReactionsListRequest{ + reactions, err := APICallWithUpdates(ctx, tc, func() (*tg.MessagesMessageReactionsList, error) { + return tc.client.API().MessagesGetMessageReactionsList(ctx, &tg.MessagesGetMessageReactionsListRequest{ Peer: peer, ID: msgID, Limit: 100, }) }) @@ -85,7 +85,7 @@ func (t *TelegramClient) computeReactionsList(ctx context.Context, peer tg.PeerC } } - customEmojis, err = t.transferEmojisToMatrix(ctx, customEmojiIDs) + customEmojis, err = tc.transferEmojisToMatrix(ctx, customEmojiIDs) return reactionsList, len(reactionsList) == totalCount, customEmojis, err } @@ -105,8 +105,8 @@ func computeEmojiAndID(reaction tg.ReactionClass, customEmojis map[networkid.Emo return } -func (t *TelegramClient) prepareReactionSync(ctx context.Context, peer tg.PeerClass, msgID int, reactions tg.MessageReactions) (*bridgev2.ReactionSyncData, error) { - reactionsList, isFull, customEmojis, err := t.computeReactionsList(ctx, peer, msgID, reactions) +func (tc *TelegramClient) prepareReactionSync(ctx context.Context, peer tg.PeerClass, msgID int, reactions tg.MessageReactions) (*bridgev2.ReactionSyncData, error) { + reactionsList, isFull, customEmojis, err := tc.computeReactionsList(ctx, peer, msgID, reactions) if err != nil { return nil, fmt.Errorf("failed to compute reactions: %w", err) } @@ -119,18 +119,18 @@ func (t *TelegramClient) prepareReactionSync(ctx context.Context, peer tg.PeerCl switch senderPeer := reaction.PeerID.(type) { case *tg.PeerUser: userID = ids.MakeUserID(senderPeer.UserID) - eventSender = t.senderForUserID(senderPeer.UserID) + eventSender = tc.senderForUserID(senderPeer.UserID) case *tg.PeerChannel: userID = ids.MakeChannelUserID(senderPeer.ChannelID) eventSender = bridgev2.EventSender{ Sender: userID, - IsFromMe: reaction.My && t.main.Bridge.Config.SplitPortals, + IsFromMe: reaction.My && tc.main.Bridge.Config.SplitPortals, } default: log.Debug().Type("peer_type", reaction.PeerID).Msg("Ignoring reaction from non-user peer") continue } - reactionLimit, err := t.getReactionLimit(ctx, userID) + reactionLimit, err := tc.getReactionLimit(ctx, userID) if err != nil { reactionLimit = 1 log.Err(err).Str("id", string(userID)).Msg("failed to get reaction limit") @@ -155,24 +155,24 @@ func (t *TelegramClient) prepareReactionSync(ctx context.Context, peer tg.PeerCl return &bridgev2.ReactionSyncData{Users: users, HasAllUsers: isFull}, nil } -func (t *TelegramClient) handleTelegramReactions(ctx context.Context, peer tg.PeerClass, topicID, msgID int, reactions tg.MessageReactions) error { +func (tc *TelegramClient) handleTelegramReactions(ctx context.Context, peer tg.PeerClass, topicID, msgID int, reactions tg.MessageReactions) error { ctx = zerolog.Ctx(ctx).With(). Str("handler", "handle_telegram_reactions"). Int("message_id", msgID). Logger().WithContext(ctx) - data, err := t.prepareReactionSync(ctx, peer, msgID, reactions) + data, err := tc.prepareReactionSync(ctx, peer, msgID, reactions) if err != nil { return err } - return resultToError(t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ReactionSync{ + return resultToError(tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ReactionSync{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventReactionSync, LogContext: func(c zerolog.Context) zerolog.Context { return c.Int("message_id", msgID) }, - PortalKey: t.makePortalKeyFromPeer(peer, topicID), + PortalKey: tc.makePortalKeyFromPeer(peer, topicID), }, TargetMessage: ids.MakeMessageID(peer, msgID), Reactions: data, @@ -198,13 +198,13 @@ func splitDMReactionCounts(res []tg.ReactionCount, theirUserID, myUserID int64) return } -func (t *TelegramClient) getReactionLimit(ctx context.Context, sender networkid.UserID) (limit int, err error) { - config, err := t.getAppConfigCached(ctx) +func (tc *TelegramClient) getReactionLimit(ctx context.Context, sender networkid.UserID) (limit int, err error) { + config, err := tc.getAppConfigCached(ctx) if err != nil { return 0, err } - ghost, err := t.main.Bridge.GetGhostByID(ctx, sender) + ghost, err := tc.main.Bridge.GetGhostByID(ctx, sender) if err != nil { return 0, err } @@ -223,27 +223,27 @@ func (t *TelegramClient) getReactionLimit(ctx context.Context, sender networkid. } } -func (t *TelegramClient) maybePollForReactions(ctx context.Context, portal *bridgev2.Portal) error { +func (tc *TelegramClient) maybePollForReactions(ctx context.Context, portal *bridgev2.Portal) error { // Only poll for reactions in supergroups - if t.metadata.IsBot || portal == nil || !portal.Metadata.(*PortalMetadata).IsSuperGroup || portal.RoomType == database.RoomTypeSpace { + if tc.metadata.IsBot || portal == nil || !portal.Metadata.(*PortalMetadata).IsSuperGroup || portal.RoomType == database.RoomTypeSpace { return nil } - t.prevReactionPollLock.Lock() - prev, ok := t.prevReactionPoll[portal.PortalKey] + tc.prevReactionPollLock.Lock() + prev, ok := tc.prevReactionPoll[portal.PortalKey] if ok && time.Since(prev) > 20*time.Second { ok = false - t.prevReactionPoll[portal.PortalKey] = time.Now() + tc.prevReactionPoll[portal.PortalKey] = time.Now() } - t.prevReactionPollLock.Unlock() + tc.prevReactionPollLock.Unlock() if ok { return nil } - return t.pollForReactions(ctx, portal.PortalKey) + return tc.pollForReactions(ctx, portal.PortalKey) } -func (t *TelegramClient) pollForReactions(ctx context.Context, portalKey networkid.PortalKey) error { - inputPeer, _, parseErr := t.inputPeerForPortalID(ctx, portalKey.ID) +func (tc *TelegramClient) pollForReactions(ctx context.Context, portalKey networkid.PortalKey) error { + inputPeer, _, parseErr := tc.inputPeerForPortalID(ctx, portalKey.ID) if parseErr != nil { return parseErr } @@ -254,7 +254,7 @@ func (t *TelegramClient) pollForReactions(ctx context.Context, portalKey network log.Debug().Msg("Polling reactions for recent messages") - messages, err := t.main.Bridge.DB.Message.GetLastNInPortal(ctx, portalKey, 20) + messages, err := tc.main.Bridge.DB.Message.GetLastNInPortal(ctx, portalKey, 20) if err != nil { return err } @@ -267,8 +267,8 @@ func (t *TelegramClient) pollForReactions(ctx context.Context, portalKey network } } - updates, err := APICallWithUpdates(ctx, t, func() (*tg.Updates, error) { - u, err := t.client.API().MessagesGetMessagesReactions(ctx, &tg.MessagesGetMessagesReactionsRequest{ + updates, err := APICallWithUpdates(ctx, tc, func() (*tg.Updates, error) { + u, err := tc.client.API().MessagesGetMessagesReactions(ctx, &tg.MessagesGetMessagesReactionsRequest{ Peer: inputPeer, ID: messageIDs, }) @@ -291,19 +291,19 @@ func (t *TelegramClient) pollForReactions(ctx context.Context, portalKey network log.Warn().Type("update_type", update).Msg("Unexpected update type in get reactions response") continue } - dbMsg, err := t.main.Bridge.DB.Message.GetFirstPartByID(ctx, t.loginID, ids.MakeMessageID(portalKey, reaction.MsgID)) + dbMsg, err := tc.main.Bridge.DB.Message.GetFirstPartByID(ctx, tc.loginID, ids.MakeMessageID(portalKey, reaction.MsgID)) if err != nil { return fmt.Errorf("failed to get message from database: %w", err) } else if dbMsg == nil { return fmt.Errorf("message not found in database: %w", err) } - data, err := t.prepareReactionSync(ctx, reaction.Peer, reaction.MsgID, reaction.Reactions) + data, err := tc.prepareReactionSync(ctx, reaction.Peer, reaction.MsgID, reaction.Reactions) if err != nil { return err } - res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ReactionSync{ + res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ReactionSync{ EventMeta: simplevent.EventMeta{ Type: bridgev2.RemoteEventReactionSync, LogContext: func(c zerolog.Context) zerolog.Context { diff --git a/pkg/connector/startchat.go b/pkg/connector/startchat.go index a40017d3..58e322c3 100644 --- a/pkg/connector/startchat.go +++ b/pkg/connector/startchat.go @@ -42,32 +42,32 @@ var ( _ bridgev2.GroupCreatingNetworkAPI = (*TelegramClient)(nil) ) -func (t *TelegramClient) resolveUser(ctx context.Context, user tg.UserClass) (*bridgev2.ResolveIdentifierResponse, error) { +func (tc *TelegramClient) resolveUser(ctx context.Context, user tg.UserClass) (*bridgev2.ResolveIdentifierResponse, error) { networkUserID := ids.MakeUserID(user.GetID()) - if ghost, err := t.main.Bridge.GetGhostByID(ctx, networkUserID); err != nil { + if ghost, err := tc.main.Bridge.GetGhostByID(ctx, networkUserID); err != nil { return nil, fmt.Errorf("failed to get ghost: %w", err) - } else if userInfo, err := t.wrapUserInfo(ctx, user, ghost); err != nil { + } else if userInfo, err := tc.wrapUserInfo(ctx, user, ghost); err != nil { return nil, fmt.Errorf("failed to get user info: %w", err) } else { - return t.makeResolveIdentifierResponse(ghost, user, userInfo), nil + return tc.makeResolveIdentifierResponse(ghost, user, userInfo), nil } } -func (t *TelegramClient) makeResolveIdentifierResponse(ghost *bridgev2.Ghost, user tg.UserClass, info *bridgev2.UserInfo) *bridgev2.ResolveIdentifierResponse { +func (tc *TelegramClient) makeResolveIdentifierResponse(ghost *bridgev2.Ghost, user tg.UserClass, info *bridgev2.UserInfo) *bridgev2.ResolveIdentifierResponse { return &bridgev2.ResolveIdentifierResponse{ Ghost: ghost, UserID: ids.MakeUserID(user.GetID()), UserInfo: info, Chat: &bridgev2.CreateChatResponse{ - PortalKey: t.makePortalKeyFromID(ids.PeerTypeUser, user.GetID(), 0), + PortalKey: tc.makePortalKeyFromID(ids.PeerTypeUser, user.GetID(), 0), }, } } -func (t *TelegramClient) resolveUserID(ctx context.Context, userID int64) (resp *bridgev2.ResolveIdentifierResponse, err error) { - _, err = t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, userID) +func (tc *TelegramClient) resolveUserID(ctx context.Context, userID int64) (resp *bridgev2.ResolveIdentifierResponse, err error) { + _, err = tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, userID) if errors.Is(err, store.ErrNoAccessHash) { - username, usernameErr := t.main.Store.Username.Get(ctx, ids.PeerTypeUser, userID) + username, usernameErr := tc.main.Store.Username.Get(ctx, ids.PeerTypeUser, userID) if usernameErr != nil { return nil, fmt.Errorf("failed to get username after missing access hash: %w", usernameErr) } else if username != "" { @@ -75,7 +75,7 @@ func (t *TelegramClient) resolveUserID(ctx context.Context, userID int64) (resp Str("target_username", username). Int64("target_user_id", userID). Msg("Access hash not found for user ID, trying to look up username") - return t.resolveUsername(ctx, username, userID) + return tc.resolveUsername(ctx, username, userID) } return nil, fmt.Errorf("%w: %w", bridgev2.ErrResolveIdentifierTryNext, err) } else if err != nil { @@ -85,39 +85,39 @@ func (t *TelegramClient) resolveUserID(ctx context.Context, userID int64) (resp resp = &bridgev2.ResolveIdentifierResponse{ UserID: networkUserID, Chat: &bridgev2.CreateChatResponse{ - PortalKey: t.makePortalKeyFromID(ids.PeerTypeUser, userID, 0), + PortalKey: tc.makePortalKeyFromID(ids.PeerTypeUser, userID, 0), }, } - resp.Ghost, err = t.main.Bridge.GetExistingGhostByID(ctx, networkUserID) + resp.Ghost, err = tc.main.Bridge.GetExistingGhostByID(ctx, networkUserID) if err != nil { return nil, fmt.Errorf("failed to get ghost: %w", err) } else if resp.Ghost == nil || resp.Ghost.Name == "" { // Try to fetch the user from Telegram - if user, err := t.getSingleUser(ctx, userID); err != nil { + if user, err := tc.getSingleUser(ctx, userID); err != nil { return nil, fmt.Errorf("failed to get user with ID %d: %w", userID, err) } else if user.TypeID() != tg.UserTypeID { return nil, fmt.Errorf("unexpected user type: %T", user) - } else if userInfo, err := t.updateGhost(ctx, userID, user.(*tg.User)); err != nil { + } else if userInfo, err := tc.updateGhost(ctx, userID, user.(*tg.User)); err != nil { return nil, fmt.Errorf("failed to update ghost: %w", err) } else { if resp.Ghost == nil { - resp.Ghost, _ = t.main.Bridge.GetExistingGhostByID(ctx, networkUserID) + resp.Ghost, _ = tc.main.Bridge.GetExistingGhostByID(ctx, networkUserID) } - return t.makeResolveIdentifierResponse(resp.Ghost, user, userInfo), nil + return tc.makeResolveIdentifierResponse(resp.Ghost, user, userInfo), nil } } return } -func (t *TelegramClient) resolveUsername(ctx context.Context, username string, expectedID int64) (*bridgev2.ResolveIdentifierResponse, error) { - resolved, err := APICallWithUpdates(ctx, t, func() (*tg.ContactsResolvedPeer, error) { - return t.client.API().ContactsResolveUsername(ctx, &tg.ContactsResolveUsernameRequest{ +func (tc *TelegramClient) resolveUsername(ctx context.Context, username string, expectedID int64) (*bridgev2.ResolveIdentifierResponse, error) { + resolved, err := APICallWithUpdates(ctx, tc, func() (*tg.ContactsResolvedPeer, error) { + return tc.client.API().ContactsResolveUsername(ctx, &tg.ContactsResolveUsernameRequest{ Username: username, }) }) if tg.IsUsernameNotOccupied(err) { if expectedID != 0 { - err = t.main.Store.Username.Delete(ctx, username) + err = tc.main.Store.Username.Delete(ctx, username) if err != nil { zerolog.Ctx(ctx).Warn().Err(err).Str("username", username). Msg("Failed to delete stale username mapping") @@ -137,7 +137,7 @@ func (t *TelegramClient) resolveUsername(ctx context.Context, username string, e } for _, user := range resolved.GetUsers() { if user.GetID() == peer.GetUserID() { - return t.resolveUser(ctx, user) + return tc.resolveUser(ctx, user) } } return nil, fmt.Errorf("peer user not found in contact resolved response") @@ -154,7 +154,7 @@ func (t *TelegramClient) resolveUsername(ctx context.Context, username string, e // (some bots like @pic and @gif have 3 characters, fragment might allow 4 characters) var usernameRe = regexp.MustCompile(`^(?:(?:https?://)?t(?:elegram)?\.(?:me|dog)/|tg:/{0,2}resolve\?domain=|@)?([a-zA-Z]\w{3,30}[a-zA-Z\d])$`) -func (t *TelegramClient) ResolveIdentifier(ctx context.Context, identifier string, createChat bool) (*bridgev2.ResolveIdentifierResponse, error) { +func (tc *TelegramClient) ResolveIdentifier(ctx context.Context, identifier string, createChat bool) (*bridgev2.ResolveIdentifierResponse, error) { log := zerolog.Ctx(ctx).With().Str("identifier", identifier).Logger() log.Debug().Msg("Resolving identifier") @@ -164,35 +164,35 @@ func (t *TelegramClient) ResolveIdentifier(ctx context.Context, identifier strin if identifier[0] == '+' { normalized := strings.TrimPrefix(identifier, "+") - if userID, err := t.main.Store.PhoneNumber.GetUserID(ctx, normalized); err != nil { + if userID, err := tc.main.Store.PhoneNumber.GetUserID(ctx, normalized); err != nil { return nil, fmt.Errorf("failed to get user ID by phone number: %w", err) } else if userID == 0 { log.Info().Msg("Phone number not found in database") return nil, nil } else { - return t.resolveUserID(ctx, userID) + return tc.resolveUserID(ctx, userID) } } else if userID, err := strconv.ParseInt(identifier, 10, 64); err == nil && userID > 0 { // This is an integer, try and parse it as a Telegram User ID - return t.resolveUserID(ctx, userID) + return tc.resolveUserID(ctx, userID) } else if match := usernameRe.FindStringSubmatch(identifier); match != nil && !strings.Contains(identifier, "__") { // This is a username - entityType, userID, err := t.main.Store.Username.GetEntityID(ctx, match[1]) + entityType, userID, err := tc.main.Store.Username.GetEntityID(ctx, match[1]) if entityType == ids.PeerTypeUser && (err == nil || userID != 0) { // We know this username. - resp, err := t.resolveUserID(ctx, userID) + resp, err := tc.resolveUserID(ctx, userID) if err == nil || !errors.Is(err, store.ErrNoAccessHash) { return resp, err } } - return t.resolveUsername(ctx, match[1], 0) + return tc.resolveUsername(ctx, match[1], 0) } return nil, fmt.Errorf("invalid identifier: %q (must be a phone number, username, or Telegram user ID)", identifier) } -func (t *TelegramClient) SearchUsers(ctx context.Context, query string) (resp []*bridgev2.ResolveIdentifierResponse, err error) { - contactsFound, err := APICallWithUpdates(ctx, t, func() (*tg.ContactsFound, error) { - return t.client.API().ContactsSearch(ctx, &tg.ContactsSearchRequest{Q: query}) +func (tc *TelegramClient) SearchUsers(ctx context.Context, query string) (resp []*bridgev2.ResolveIdentifierResponse, err error) { + contactsFound, err := APICallWithUpdates(ctx, tc, func() (*tg.ContactsFound, error) { + return tc.client.API().ContactsSearch(ctx, &tg.ContactsSearchRequest{Q: query}) }) if err != nil { return nil, err @@ -206,7 +206,7 @@ func (t *TelegramClient) SearchUsers(ctx context.Context, query string) (resp [] if peer, ok := p.(*tg.PeerUser); !ok { return nil } else if user, ok := users[peer.GetUserID()]; ok { - if r, err := t.resolveUser(ctx, user); err != nil { + if r, err := tc.resolveUser(ctx, user); err != nil { return err } else { resp = append(resp, r) @@ -230,37 +230,37 @@ func (t *TelegramClient) SearchUsers(ctx context.Context, query string) (resp [] return resp, nil } -func (t *TelegramClient) GetContactList(ctx context.Context) (resp []*bridgev2.ResolveIdentifierResponse, err error) { - t.contactsLock.Lock() - defer t.contactsLock.Unlock() +func (tc *TelegramClient) GetContactList(ctx context.Context) (resp []*bridgev2.ResolveIdentifierResponse, err error) { + tc.contactsLock.Lock() + defer tc.contactsLock.Unlock() var contacts *tg.ContactsContacts - if time.Since(t.lastContactReq) > 10*time.Minute { - contacts, err = APICallWithOnlyUserUpdates(ctx, t, func() (*tg.ContactsContacts, error) { - c, err := t.client.API().ContactsGetContacts(ctx, t.cachedContactsHash) + if time.Since(tc.lastContactReq) > 10*time.Minute { + contacts, err = APICallWithOnlyUserUpdates(ctx, tc, func() (*tg.ContactsContacts, error) { + c, err := tc.client.API().ContactsGetContacts(ctx, tc.cachedContactsHash) if err != nil { return nil, err } switch typedResp := c.(type) { case *tg.ContactsContacts: - t.cachedContacts = typedResp + tc.cachedContacts = typedResp var h hasher.Hasher - for _, contact := range t.cachedContacts.Contacts { + for _, contact := range tc.cachedContacts.Contacts { h.Update(uint32(contact.UserID)) } - t.cachedContactsHash = h.Sum() + tc.cachedContactsHash = h.Sum() case *tg.ContactsContactsNotModified: // No changes default: return nil, fmt.Errorf("unexpected contacts type: %T", c) } - return t.cachedContacts, nil + return tc.cachedContacts, nil }) if err != nil { return nil, err } - t.lastContactReq = time.Now() + tc.lastContactReq = time.Now() } else { - contacts = t.cachedContacts + contacts = tc.cachedContacts } users := map[int64]tg.UserClass{} for _, user := range contacts.GetUsers() { @@ -269,7 +269,7 @@ func (t *TelegramClient) GetContactList(ctx context.Context) (resp []*bridgev2.R for _, contact := range contacts.Contacts { if user, ok := users[contact.UserID]; ok { - if r, err := t.resolveUser(ctx, user); err != nil { + if r, err := tc.resolveUser(ctx, user); err != nil { return nil, err } else { resp = append(resp, r) @@ -282,7 +282,7 @@ func (t *TelegramClient) GetContactList(ctx context.Context) (resp []*bridgev2.R } // TODO support channels -func (t *TelegramClient) CreateGroup(ctx context.Context, params *bridgev2.GroupCreateParams) (*bridgev2.CreateChatResponse, error) { +func (tc *TelegramClient) CreateGroup(ctx context.Context, params *bridgev2.GroupCreateParams) (*bridgev2.CreateChatResponse, error) { req := tg.MessagesCreateChatRequest{ Title: ptr.Val(params.Name).Name, } @@ -291,13 +291,13 @@ func (t *TelegramClient) CreateGroup(ctx context.Context, params *bridgev2.Group return nil, fmt.Errorf("failed to parse user ID: %w", err) } else if peerType != ids.PeerTypeUser { return nil, fmt.Errorf("unexpected peer type: %s", peerType) - } else if inputUser, err := t.getInputUser(ctx, userID); err != nil { + } else if inputUser, err := tc.getInputUser(ctx, userID); err != nil { return nil, fmt.Errorf("failed to get input user: %w", err) } else { req.Users = append(req.Users, inputUser) } } - invitedUsers, err := t.client.API().MessagesCreateChat(ctx, &req) + invitedUsers, err := tc.client.API().MessagesCreateChat(ctx, &req) if err != nil { return nil, fmt.Errorf("failed to create chat: %w", err) } @@ -315,9 +315,9 @@ func (t *TelegramClient) CreateGroup(ctx context.Context, params *bridgev2.Group } else if chat, ok := chats[0].(*tg.Chat); !ok { return nil, fmt.Errorf("unexpected chat type: %T", chats[0]) } else { - portalKey := t.makePortalKeyFromID(ids.PeerTypeChat, chat.ID, 0) + portalKey := tc.makePortalKeyFromID(ids.PeerTypeChat, chat.ID, 0) if params.RoomID != "" { - portal, err := t.main.Bridge.GetPortalByKey(ctx, portalKey) + portal, err := tc.main.Bridge.GetPortalByKey(ctx, portalKey) if err != nil { return nil, err } @@ -329,7 +329,7 @@ func (t *TelegramClient) CreateGroup(ctx context.Context, params *bridgev2.Group OverwriteOldPortal: true, TombstoneOldRoom: true, DeleteOldRoom: true, - ChatInfoSource: t.userLogin, + ChatInfoSource: tc.userLogin, }) if err != nil { return nil, err diff --git a/pkg/connector/tomatrix.go b/pkg/connector/tomatrix.go index c9633328..1e252d52 100644 --- a/pkg/connector/tomatrix.go +++ b/pkg/connector/tomatrix.go @@ -79,7 +79,7 @@ func mediaHashID(ctx context.Context, m tg.MessageMediaClass) []byte { return nil } -func (c *TelegramClient) mediaToMatrix( +func (tc *TelegramClient) mediaToMatrix( ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, @@ -106,10 +106,10 @@ func (c *TelegramClient) mediaToMatrix( }, }, nil, nil case tg.MessageMediaPhotoTypeID, tg.MessageMediaDocumentTypeID: - converted, disappearingSetting := c.convertMediaRequiringUpload(ctx, portal, intent, msg.ID, media, true) + converted, disappearingSetting := tc.convertMediaRequiringUpload(ctx, portal, intent, msg.ID, media, true) return converted, disappearingSetting, mediaHashID(ctx, media) case tg.MessageMediaContactTypeID: - return c.convertContact(media), nil, nil + return tc.convertContact(media), nil, nil case tg.MessageMediaGeoTypeID, tg.MessageMediaGeoLiveTypeID, tg.MessageMediaVenueTypeID: return convertLocation(media), nil, nil case tg.MessageMediaPollTypeID: @@ -134,7 +134,7 @@ func (c *TelegramClient) mediaToMatrix( } } -func (c *TelegramClient) convertToMatrix( +func (tc *TelegramClient) convertToMatrix( ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, @@ -143,7 +143,7 @@ func (c *TelegramClient) convertToMatrix( log := zerolog.Ctx(ctx).With().Str("conversion_direction", "to_matrix").Logger() ctx = log.WithContext(ctx) - if c.client == nil { + if tc.client == nil { return nil, fmt.Errorf("telegram client is nil, we are likely logged out") } @@ -153,9 +153,9 @@ func (c *TelegramClient) convertToMatrix( } else if peerType == ids.PeerTypeChannel && !portal.Metadata.(*PortalMetadata).IsSuperGroup { var sender *networkid.UserID if msg.Out { - sender = &c.userID + sender = &tc.userID } else if fromID, ok := msg.GetFromID(); ok { - sender = ptr.Ptr(c.getPeerSender(fromID).Sender) + sender = ptr.Ptr(tc.getPeerSender(fromID).Sender) } if sender != nil { profile, err := portal.PerMessageProfileForSender(ctx, *sender) @@ -171,11 +171,11 @@ func (c *TelegramClient) convertToMatrix( if len(msg.Message) > 0 { hasher.Write([]byte(msg.Message)) - content := c.parseBodyAndHTML(ctx, msg.Message, msg.Entities) + content := tc.parseBodyAndHTML(ctx, msg.Message, msg.Entities) if media, ok := msg.GetMedia(); ok && media.TypeID() == tg.MessageMediaWebPageTypeID { webpageCtx, webpageCtxCancel := context.WithTimeout(ctx, time.Second*5) defer webpageCtxCancel() - preview, err := c.webpageToBeeperLinkPreview(webpageCtx, portal, intent, msg, media) + preview, err := tc.webpageToBeeperLinkPreview(webpageCtx, portal, intent, msg, media) if err != nil { log.Err(err).Msg("Failed to convert webpage to link preview") } else if preview != nil { @@ -191,7 +191,7 @@ func (c *TelegramClient) convertToMatrix( } var contentURI id.ContentURIString - mediaPart, disappearingSetting, mediaHashID := c.mediaToMatrix(ctx, portal, intent, msg) + mediaPart, disappearingSetting, mediaHashID := tc.mediaToMatrix(ctx, portal, intent, msg) if mediaPart != nil { hasher.Write(mediaHashID) cm.Parts = append(cm.Parts, mediaPart) @@ -213,7 +213,7 @@ func (c *TelegramClient) convertToMatrix( } if fwd, isForwarded := msg.GetFwdFrom(); isForwarded { - err = c.addForwardHeader(ctx, cm.Parts[0], fwd) + err = tc.addForwardHeader(ctx, cm.Parts[0], fwd) if err != nil { return nil, fmt.Errorf("failed to add forward header: %w", err) } @@ -231,7 +231,7 @@ func (c *TelegramClient) convertToMatrix( } } if replyTo.Quote { - parsedQuote := c.parseBodyAndHTML(ctx, replyTo.QuoteText, replyTo.QuoteEntities) + parsedQuote := tc.parseBodyAndHTML(ctx, replyTo.QuoteText, replyTo.QuoteEntities) parsedQuote.EnsureHasHTML() existingPart := cm.Parts[0] existingPart.Content.EnsureHasHTML() @@ -256,20 +256,20 @@ func (c *TelegramClient) convertToMatrix( return } -func (t *TelegramClient) addForwardHeader(ctx context.Context, part *bridgev2.ConvertedMessagePart, fwd tg.MessageFwdHeader) error { +func (tc *TelegramClient) addForwardHeader(ctx context.Context, part *bridgev2.ConvertedMessagePart, fwd tg.MessageFwdHeader) error { var fwdFromText, fwdFromHTML string switch from := fwd.FromID.(type) { case *tg.PeerUser: - user := t.main.Bridge.GetCachedUserLoginByID(ids.MakeUserLoginID(from.UserID)) + user := tc.main.Bridge.GetCachedUserLoginByID(ids.MakeUserLoginID(from.UserID)) var mxid id.UserID if user != nil { mxid = user.UserMXID fwdFromText = cmp.Or(user.RemoteName, user.UserMXID.String()) - } else if ghost, err := t.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(from.UserID)); err != nil { + } else if ghost, err := tc.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(from.UserID)); err != nil { return err } else { if ghost.Name == "" { - info, err := t.GetUserInfo(ctx, ghost) + info, err := tc.GetUserInfo(ctx, ghost) if err != nil { zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to get user info to add forward header") } else if info != nil { @@ -291,7 +291,7 @@ func (t *TelegramClient) addForwardHeader(ctx context.Context, part *bridgev2.Co unknownType = "unknown channel" channelID = ch.ChannelID } - portal, err := t.main.Bridge.GetExistingPortalByKey(ctx, t.makePortalKeyFromPeer(from, 0)) + portal, err := tc.main.Bridge.GetExistingPortalByKey(ctx, tc.makePortalKeyFromPeer(from, 0)) if err != nil { return err } else if portal != nil && portal.MXID != "" { @@ -309,7 +309,7 @@ func (t *TelegramClient) addForwardHeader(ctx context.Context, part *bridgev2.Co fwdFromHTML = unknownType } if channelID != 0 && fwdFromText == unknownType { - ghost, err := t.main.Bridge.GetExistingGhostByID(ctx, ids.MakeChannelUserID(channelID)) + ghost, err := tc.main.Bridge.GetExistingGhostByID(ctx, ids.MakeChannelUserID(channelID)) if err != nil { return err } else if ghost != nil && ghost.Name != "" { @@ -364,7 +364,7 @@ func (t *TelegramClient) addForwardHeader(ctx context.Context, part *bridgev2.Co return nil } -func (t *TelegramClient) parseBodyAndHTML(ctx context.Context, message string, entities []tg.MessageEntityClass) *event.MessageEventContent { +func (tc *TelegramClient) parseBodyAndHTML(ctx context.Context, message string, entities []tg.MessageEntityClass) *event.MessageEventContent { if len(entities) == 0 { return &event.MessageEventContent{MsgType: event.MsgText, Body: message} } @@ -376,16 +376,16 @@ func (t *TelegramClient) parseBodyAndHTML(ctx context.Context, message string, e customEmojiIDs = append(customEmojiIDs, entity.DocumentID) } } - customEmojis, err := t.transferEmojisToMatrix(ctx, customEmojiIDs) + customEmojis, err := tc.transferEmojisToMatrix(ctx, customEmojiIDs) if err != nil { zerolog.Ctx(ctx).Err(err). Ints64("emoji_ids", customEmojiIDs). Msg("Failed to transfer custom emojis to Matrix") } - return telegramfmt.Parse(ctx, message, entities, t.telegramFmtParams.WithCustomEmojis(customEmojis)) + return telegramfmt.Parse(ctx, message, entities, tc.telegramFmtParams.WithCustomEmojis(customEmojis)) } -func (c *TelegramClient) webpageToBeeperLinkPreview(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, msg *tg.Message, msgMedia tg.MessageMediaClass) (preview *event.BeeperLinkPreview, err error) { +func (tc *TelegramClient) webpageToBeeperLinkPreview(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, msg *tg.Message, msgMedia tg.MessageMediaClass) (preview *event.BeeperLinkPreview, err error) { webpage, ok := msgMedia.(*tg.MessageMediaWebPage).Webpage.(*tg.WebPage) if !ok { return nil, nil @@ -401,11 +401,11 @@ func (c *TelegramClient) webpageToBeeperLinkPreview(ctx context.Context, portal if photo, ok := webpage.Photo.(*tg.Photo); ok { var fileInfo *event.FileInfo - transferer := media.NewTransferer(c.client.API()).WithPhoto(photo) - if c.main.useDirectMedia { - preview.ImageURL, fileInfo, err = transferer.DirectDownloadURL(ctx, c.telegramUserID, portal, msg.ID, true, 0) + transferer := media.NewTransferer(tc.client.API()).WithPhoto(photo) + if tc.main.useDirectMedia { + preview.ImageURL, fileInfo, err = transferer.DirectDownloadURL(ctx, tc.telegramUserID, portal, msg.ID, true, 0) } else { - preview.ImageURL, preview.ImageEncryption, fileInfo, err = transferer.Transfer(ctx, c.main.Store, intent) + preview.ImageURL, preview.ImageEncryption, fileInfo, err = transferer.Transfer(ctx, tc.main.Store, intent) } if err != nil { return nil, err @@ -422,7 +422,7 @@ func (c *TelegramClient) webpageToBeeperLinkPreview(ctx context.Context, portal return preview, nil } -func (c *TelegramClient) convertMediaRequiringUpload( +func (tc *TelegramClient) convertMediaRequiringUpload( ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, @@ -443,7 +443,7 @@ func (c *TelegramClient) convertMediaRequiringUpload( // FIXME don't use raw map for fields in the FileInfo struct extraInfo := map[string]any{} - transferer := media.NewTransferer(c.client.API()).WithRoomID(portal.MXID) + transferer := media.NewTransferer(tc.client.API()).WithRoomID(portal.MXID) var mediaTransferer *media.ReadyTransferer if t, ok := msgMedia.(ttlable); ok { @@ -457,7 +457,7 @@ func (c *TelegramClient) convertMediaRequiringUpload( // This is a view-once message, set a low TTL. ttl = 15 - if c.main.Config.DisableViewOnce { + if tc.main.Config.DisableViewOnce { converted = &bridgev2.ConvertedMessagePart{ Type: event.EventMessage, Content: &event.MessageEventContent{ @@ -509,17 +509,17 @@ func (c *TelegramClient) convertMediaRequiringUpload( var thumbnailInfo *event.FileInfo var err error - thumbnailTransferer := media.NewTransferer(c.client.API()). + thumbnailTransferer := media.NewTransferer(tc.client.API()). WithRoomID(portal.MXID). WithPhoto(photo) - if c.main.useDirectMedia { - thumbnailURL, thumbnailInfo, err = thumbnailTransferer.DirectDownloadURL(ctx, c.telegramUserID, portal, msgID, false, photo.ID) + if tc.main.useDirectMedia { + thumbnailURL, thumbnailInfo, err = thumbnailTransferer.DirectDownloadURL(ctx, tc.telegramUserID, portal, msgID, false, photo.ID) if err != nil { log.Err(err).Msg("Failed to create direct download URL for thumbnail") } } if thumbnailURL == "" { - thumbnailURL, thumbnailFile, thumbnailInfo, err = thumbnailTransferer.Transfer(ctx, c.main.Store, intent) + thumbnailURL, thumbnailFile, thumbnailInfo, err = thumbnailTransferer.Transfer(ctx, tc.main.Store, intent) if err != nil { log.Err(err).Msg("Failed to transfer thumbnail") } @@ -603,7 +603,7 @@ func (c *TelegramClient) convertMediaRequiringUpload( } } extraInfo["fi.mau.telegram.sticker"] = stickerInfo - transferer = transferer.WithStickerConfig(c.main.Config.AnimatedSticker) + transferer = transferer.WithStickerConfig(tc.main.Config.AnimatedSticker) case *tg.DocumentAttributeAnimated: isVideoGif = true extraInfo["fi.mau.telegram.gif"] = true @@ -622,7 +622,7 @@ func (c *TelegramClient) convertMediaRequiringUpload( // Strip filename so that we never render the caption content.FileName = "" - if c.main.Config.AnimatedSticker.Target == "webm" || (isVideo && !c.main.Config.AnimatedSticker.ConvertFromWebm) { + if tc.main.Config.AnimatedSticker.Target == "webm" || (isVideo && !tc.main.Config.AnimatedSticker.ConvertFromWebm) { isVideoGif = true extraInfo["fi.mau.telegram.animated_sticker"] = true transferer.WithMIMEType("video/webm") @@ -646,17 +646,17 @@ func (c *TelegramClient) convertMediaRequiringUpload( var thumbnailInfo *event.FileInfo var err error - thumbnailTransferer := media.NewTransferer(c.client.API()). + thumbnailTransferer := media.NewTransferer(tc.client.API()). WithRoomID(portal.MXID). WithDocument(document, true) - if c.main.useDirectMedia { - thumbnailURL, thumbnailInfo, err = thumbnailTransferer.DirectDownloadURL(ctx, c.telegramUserID, portal, msgID, true, document.ID) + if tc.main.useDirectMedia { + thumbnailURL, thumbnailInfo, err = thumbnailTransferer.DirectDownloadURL(ctx, tc.telegramUserID, portal, msgID, true, document.ID) if err != nil { log.Err(err).Msg("Failed to create direct download URL for thumbnail") } } if thumbnailURL == "" { - thumbnailURL, thumbnailFile, thumbnailInfo, err = thumbnailTransferer.Transfer(ctx, c.main.Store, intent) + thumbnailURL, thumbnailFile, thumbnailInfo, err = thumbnailTransferer.Transfer(ctx, tc.main.Store, intent) if err != nil { log.Err(err).Msg("Failed to transfer thumbnail") } @@ -681,24 +681,24 @@ func (c *TelegramClient) convertMediaRequiringUpload( } var err error - if c.main.useDirectMedia && (!isSticker || c.main.Config.AnimatedSticker.Target == "disable") { - content.URL, content.Info, err = mediaTransferer.DirectDownloadURL(ctx, c.telegramUserID, portal, msgID, false, telegramMediaID) + if tc.main.useDirectMedia && (!isSticker || tc.main.Config.AnimatedSticker.Target == "disable") { + content.URL, content.Info, err = mediaTransferer.DirectDownloadURL(ctx, tc.telegramUserID, portal, msgID, false, telegramMediaID) if err != nil { log.Err(err).Msg("Failed to create direct download URL for media") } } if content.URL == "" { - content.URL, content.File, content.Info, err = mediaTransferer.Transfer(ctx, c.main.Store, intent) + content.URL, content.File, content.Info, err = mediaTransferer.Transfer(ctx, tc.main.Store, intent) if err != nil { if tgerr.Is(err, tg.ErrFileReferenceExpired) && allowRefetch { log.Warn().Err(err).Msg("Failed to transfer media, trying to refetch from message") peerType, peerID, _, err := ids.ParsePortalID(portal.ID) if err != nil { log.Err(err).Msg("Failed to parse portal ID to refetch media") - } else if msgMedia, err = c.refetchMedia(ctx, peerType, peerID, msgID); err != nil { + } else if msgMedia, err = tc.refetchMedia(ctx, peerType, peerID, msgID); err != nil { log.Err(err).Msg("Failed to refetch media after file reference expired error") } else { - return c.convertMediaRequiringUpload(ctx, portal, intent, msgID, msgMedia, false) + return tc.convertMediaRequiringUpload(ctx, portal, intent, msgID, msgMedia, false) } } else { log.Err(err).Msg("Failed to transfer media") @@ -738,9 +738,9 @@ func (c *TelegramClient) convertMediaRequiringUpload( return } -func (c *TelegramClient) convertContact(media tg.MessageMediaClass) *bridgev2.ConvertedMessagePart { +func (tc *TelegramClient) convertContact(media tg.MessageMediaClass) *bridgev2.ConvertedMessagePart { contact := media.(*tg.MessageMediaContact) - name := c.main.Config.FormatDisplayname(contact.FirstName, contact.LastName, "", false, contact.UserID) + name := tc.main.Config.FormatDisplayname(contact.FirstName, contact.LastName, "", false, contact.UserID) formattedPhone := fmt.Sprintf("+%s", strings.TrimPrefix(contact.PhoneNumber, "+")) content := event.MessageEventContent{ @@ -751,7 +751,7 @@ func (c *TelegramClient) convertContact(media tg.MessageMediaClass) *bridgev2.Co content.Format = event.FormatHTML content.FormattedBody = fmt.Sprintf( `Shared contact info for %s: %s`, - c.main.Bridge.Matrix.GhostIntent(ids.MakeUserID(contact.UserID)).GetMXID().URI().MatrixToURL(), + tc.main.Bridge.Matrix.GhostIntent(ids.MakeUserID(contact.UserID)).GetMXID().URI().MatrixToURL(), html.EscapeString(name), html.EscapeString(formattedPhone), ) @@ -940,50 +940,50 @@ func convertGame(media tg.MessageMediaClass) *bridgev2.ConvertedMessagePart { } } -func (c *TelegramClient) convertUserProfilePhoto(ctx context.Context, user *tg.User, photo *tg.UserProfilePhoto) (*bridgev2.Avatar, error) { +func (tc *TelegramClient) convertUserProfilePhoto(ctx context.Context, user *tg.User, photo *tg.UserProfilePhoto) (*bridgev2.Avatar, error) { avatar := &bridgev2.Avatar{ ID: ids.MakeAvatarID(photo.PhotoID), } - if c.main.useDirectMedia { + if tc.main.useDirectMedia { mediaID, err := ids.DirectMediaInfo{ PeerType: ids.PeerTypeUser, PeerID: user.ID, - UserID: c.telegramUserID, + UserID: tc.telegramUserID, ID: photo.PhotoID, }.AsMediaID() if err != nil { return nil, err } - if avatar.MXC, err = c.main.Bridge.Matrix.GenerateContentURI(ctx, mediaID); err != nil { + if avatar.MXC, err = tc.main.Bridge.Matrix.GenerateContentURI(ctx, mediaID); err != nil { return nil, err } avatar.Hash = ids.HashMediaID(mediaID) } else { avatar.Get = func(ctx context.Context) (data []byte, err error) { // TODO determine if it's safe to unconditionally use the access hash from the user object here - peer, err := c.getInputPeerUser(ctx, user.ID) + peer, err := tc.getInputPeerUser(ctx, user.ID) if errors.Is(err, store.ErrNoAccessHash) { peer = &tg.InputPeerUser{ UserID: user.ID, AccessHash: user.AccessHash, } - if user.Min && c.metadata.IsBot { + if user.Min && tc.metadata.IsBot { // Bots should use a zero access hash when only a min hash is available peer.AccessHash = 0 } } else if err != nil { return nil, fmt.Errorf("failed to get peer: %w", err) } - return media.NewTransferer(c.client.API()).WithPeerPhoto(peer, photo.PhotoID).DownloadBytes(ctx) + return media.NewTransferer(tc.client.API()).WithPeerPhoto(peer, photo.PhotoID).DownloadBytes(ctx) } } return avatar, nil } -func (c *TelegramClient) convertChatPhoto(chat tg.InputPeerClass, rawChatPhoto tg.ChatPhotoClass) (*bridgev2.Avatar, error) { +func (tc *TelegramClient) convertChatPhoto(chat tg.InputPeerClass, rawChatPhoto tg.ChatPhotoClass) (*bridgev2.Avatar, error) { var chatPhoto *tg.ChatPhoto switch typedChatPhoto := rawChatPhoto.(type) { case *tg.ChatPhotoEmpty: @@ -997,7 +997,7 @@ func (c *TelegramClient) convertChatPhoto(chat tg.InputPeerClass, rawChatPhoto t ID: ids.MakeAvatarID(chatPhoto.PhotoID), } - if c.main.useDirectMedia { + if tc.main.useDirectMedia { var peerID int64 var peerType ids.PeerType switch typedChat := chat.(type) { @@ -1016,28 +1016,28 @@ func (c *TelegramClient) convertChatPhoto(chat tg.InputPeerClass, rawChatPhoto t mediaID, err := ids.DirectMediaInfo{ PeerType: peerType, PeerID: peerID, - UserID: c.telegramUserID, + UserID: tc.telegramUserID, ID: chatPhoto.PhotoID, }.AsMediaID() if err != nil { return nil, err } - todoRemove := c.main.Bridge.BackgroundCtx // TODO remove context parameter from GenerateContentURI - if avatar.MXC, err = c.main.Bridge.Matrix.GenerateContentURI(todoRemove, mediaID); err != nil { + todoRemove := tc.main.Bridge.BackgroundCtx // TODO remove context parameter from GenerateContentURI + if avatar.MXC, err = tc.main.Bridge.Matrix.GenerateContentURI(todoRemove, mediaID); err != nil { return nil, err } avatar.Hash = ids.HashMediaID(mediaID) } else { avatar.Get = func(ctx context.Context) (data []byte, err error) { - return media.NewTransferer(c.client.API()).WithPeerPhoto(chat, chatPhoto.PhotoID).DownloadBytes(ctx) + return media.NewTransferer(tc.client.API()).WithPeerPhoto(chat, chatPhoto.PhotoID).DownloadBytes(ctx) } } return avatar, nil } -func (c *TelegramClient) convertPhoto(ctx context.Context, peerType ids.PeerType, peerID int64, photoClass tg.PhotoClass) (*bridgev2.Avatar, error) { +func (tc *TelegramClient) convertPhoto(ctx context.Context, peerType ids.PeerType, peerID int64, photoClass tg.PhotoClass) (*bridgev2.Avatar, error) { photo, ok := photoClass.(*tg.Photo) if !ok { return nil, fmt.Errorf("not a photo: %T", photoClass) @@ -1047,25 +1047,25 @@ func (c *TelegramClient) convertPhoto(ctx context.Context, peerType ids.PeerType ID: ids.MakeAvatarID(photo.GetID()), } - if c.main.useDirectMedia { + if tc.main.useDirectMedia { mediaID, err := ids.DirectMediaInfo{ PeerType: peerType, PeerID: peerID, - UserID: c.telegramUserID, + UserID: tc.telegramUserID, ID: photo.GetID(), }.AsMediaID() if err != nil { return nil, err } - if avatar.MXC, err = c.main.Bridge.Matrix.GenerateContentURI(ctx, mediaID); err != nil { + if avatar.MXC, err = tc.main.Bridge.Matrix.GenerateContentURI(ctx, mediaID); err != nil { return nil, err } avatar.Hash = ids.HashMediaID(mediaID) } else { avatar.Get = func(ctx context.Context) (data []byte, err error) { - return media.NewTransferer(c.client.API()).WithPhoto(photo).DownloadBytes(ctx) + return media.NewTransferer(tc.client.API()).WithPhoto(photo).DownloadBytes(ctx) } } diff --git a/pkg/connector/userinfo.go b/pkg/connector/userinfo.go index f1b22f96..35d3dd54 100644 --- a/pkg/connector/userinfo.go +++ b/pkg/connector/userinfo.go @@ -16,37 +16,37 @@ import ( "go.mau.fi/mautrix-telegram/pkg/gotd/tg" ) -func (t *TelegramClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) { +func (tc *TelegramClient) GetUserInfo(ctx context.Context, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) { peerType, id, err := ids.ParseUserID(ghost.ID) if err != nil { return nil, err } switch peerType { case ids.PeerTypeUser: - if user, err := t.getSingleUser(ctx, id); err != nil { + if user, err := tc.getSingleUser(ctx, id); err != nil { return nil, fmt.Errorf("failed to get user %d: %w", id, err) } else { - return t.wrapUserInfo(ctx, user, ghost) + return tc.wrapUserInfo(ctx, user, ghost) } case ids.PeerTypeChannel: - if channel, err := t.getSingleChannel(ctx, id); err != nil { + if channel, err := tc.getSingleChannel(ctx, id); err != nil { return nil, fmt.Errorf("failed to get channel %d: %w", id, err) } else { - return t.wrapChannelGhostInfo(ctx, channel) + return tc.wrapChannelGhostInfo(ctx, channel) } default: return nil, fmt.Errorf("unexpected peer type: %s", peerType) } } -func (t *TelegramClient) getChatPeerForInputFromMessage(ctx context.Context, id int64, peerID tg.PeerClass) (tg.InputPeerClass, error) { +func (tc *TelegramClient) getChatPeerForInputFromMessage(ctx context.Context, id int64, peerID tg.PeerClass) (tg.InputPeerClass, error) { switch typedChat := peerID.(type) { case *tg.PeerUser: if id == typedChat.UserID { // We don't have the user's access hash return nil, nil } - accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, typedChat.UserID) + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, typedChat.UserID) if err != nil { return nil, err } @@ -58,7 +58,7 @@ func (t *TelegramClient) getChatPeerForInputFromMessage(ctx context.Context, id // We don't have the channel's access hash return nil, nil } - accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, typedChat.ChannelID) + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, typedChat.ChannelID) if err != nil { return nil, err } @@ -68,12 +68,12 @@ func (t *TelegramClient) getChatPeerForInputFromMessage(ctx context.Context, id } } -func (t *TelegramClient) getInputUserFromContext(ctx context.Context, id int64) (*tg.InputUserFromMessage, error) { +func (tc *TelegramClient) getInputUserFromContext(ctx context.Context, id int64) (*tg.InputUserFromMessage, error) { msg, ok := bridgev2.GetRemoteEventFromContext(ctx).(*simplevent.Message[*tg.Message]) if !ok { return nil, nil } - inputPeer, err := t.getChatPeerForInputFromMessage(ctx, id, msg.Data.PeerID) + inputPeer, err := tc.getChatPeerForInputFromMessage(ctx, id, msg.Data.PeerID) if err != nil || inputPeer == nil { return nil, err } @@ -84,12 +84,12 @@ func (t *TelegramClient) getInputUserFromContext(ctx context.Context, id int64) }, nil } -func (t *TelegramClient) getInputChannelFromContext(ctx context.Context, id int64) (*tg.InputChannelFromMessage, error) { +func (tc *TelegramClient) getInputChannelFromContext(ctx context.Context, id int64) (*tg.InputChannelFromMessage, error) { msg, ok := bridgev2.GetRemoteEventFromContext(ctx).(*simplevent.Message[*tg.Message]) if !ok { return nil, nil } - inputPeer, err := t.getChatPeerForInputFromMessage(ctx, id, msg.Data.PeerID) + inputPeer, err := tc.getChatPeerForInputFromMessage(ctx, id, msg.Data.PeerID) if err != nil || inputPeer == nil { return nil, err } @@ -100,10 +100,10 @@ func (t *TelegramClient) getInputChannelFromContext(ctx context.Context, id int6 }, nil } -func (t *TelegramClient) getInputUser(ctx context.Context, id int64) (tg.InputUserClass, error) { - accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, id) +func (tc *TelegramClient) getInputUser(ctx context.Context, id int64) (tg.InputUserClass, error) { + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, id) if errors.Is(err, store.ErrNoAccessHash) { - fromMsg, fromMsgErr := t.getInputUserFromContext(ctx, id) + fromMsg, fromMsgErr := tc.getInputUserFromContext(ctx, id) if fromMsgErr != nil { return nil, fmt.Errorf("%w, also failed to get from message: %w", err, fromMsgErr) } else if fromMsg == nil { @@ -119,8 +119,8 @@ func (t *TelegramClient) getInputUser(ctx context.Context, id int64) (tg.InputUs return &tg.InputUser{UserID: id, AccessHash: accessHash}, nil } -func (t *TelegramClient) getInputPeerUser(ctx context.Context, id int64) (*tg.InputPeerUser, error) { - accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, id) +func (tc *TelegramClient) getInputPeerUser(ctx context.Context, id int64) (*tg.InputPeerUser, error) { + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, id) if errors.Is(err, store.ErrNoAccessHash) { return nil, err } else if err != nil { @@ -129,10 +129,10 @@ func (t *TelegramClient) getInputPeerUser(ctx context.Context, id int64) (*tg.In return &tg.InputPeerUser{UserID: id, AccessHash: accessHash}, nil } -func (t *TelegramClient) getSingleUser(ctx context.Context, id int64) (tg.UserClass, error) { - if inputUser, err := t.getInputUser(ctx, id); err != nil { +func (tc *TelegramClient) getSingleUser(ctx context.Context, id int64) (tg.UserClass, error) { + if inputUser, err := tc.getInputUser(ctx, id); err != nil { return nil, err - } else if users, err := t.client.API().UsersGetUsers(ctx, []tg.InputUserClass{inputUser}); err != nil { + } else if users, err := tc.client.API().UsersGetUsers(ctx, []tg.InputUserClass{inputUser}); err != nil { return nil, err } else if len(users) == 0 { // TODO does this mean the user is deleted? Need to handle this a bit better @@ -142,10 +142,10 @@ func (t *TelegramClient) getSingleUser(ctx context.Context, id int64) (tg.UserCl } } -func (t *TelegramClient) getInputChannel(ctx context.Context, id int64) (tg.InputChannelClass, error) { - accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id) +func (tc *TelegramClient) getInputChannel(ctx context.Context, id int64) (tg.InputChannelClass, error) { + accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id) if err != nil { - fromMsg, fromMsgErr := t.getInputChannelFromContext(ctx, id) + fromMsg, fromMsgErr := tc.getInputChannelFromContext(ctx, id) if fromMsgErr != nil { return nil, fmt.Errorf("%w, also failed to get from message: %w", err, fromMsgErr) } else if fromMsg == nil { @@ -159,13 +159,13 @@ func (t *TelegramClient) getInputChannel(ctx context.Context, id int64) (tg.Inpu return &tg.InputChannel{ChannelID: id, AccessHash: accessHash}, nil } -func (t *TelegramClient) getSingleChannel(ctx context.Context, id int64) (*tg.Channel, error) { - inputChannel, err := t.getInputChannel(ctx, id) +func (tc *TelegramClient) getSingleChannel(ctx context.Context, id int64) (*tg.Channel, error) { + inputChannel, err := tc.getInputChannel(ctx, id) if err != nil { return nil, err } - chats, err := APICallWithOnlyChatUpdates(ctx, t, func() (tg.MessagesChatsClass, error) { - return t.client.API().ChannelsGetChannels(ctx, []tg.InputChannelClass{inputChannel}) + chats, err := APICallWithOnlyChatUpdates(ctx, tc, func() (tg.MessagesChatsClass, error) { + return tc.client.API().ChannelsGetChannels(ctx, []tg.InputChannelClass{inputChannel}) }) if err != nil { return nil, err @@ -178,23 +178,23 @@ func (t *TelegramClient) getSingleChannel(ctx context.Context, id int64) (*tg.Ch } } -func (t *TelegramClient) wrapChannelGhostInfo(ctx context.Context, channel *tg.Channel) (*bridgev2.UserInfo, error) { +func (tc *TelegramClient) wrapChannelGhostInfo(ctx context.Context, channel *tg.Channel) (*bridgev2.UserInfo, error) { var err error if accessHash, ok := channel.GetAccessHash(); ok && !channel.Min { - if err = t.ScopedStore.SetAccessHash(ctx, ids.PeerTypeChannel, channel.ID, accessHash); err != nil { + if err = tc.ScopedStore.SetAccessHash(ctx, ids.PeerTypeChannel, channel.ID, accessHash); err != nil { return nil, err } } var avatar *bridgev2.Avatar - avatar, err = t.convertChatPhoto(channel.AsInputPeer(), channel.GetPhoto()) + avatar, err = tc.convertChatPhoto(channel.AsInputPeer(), channel.GetPhoto()) if err != nil { return nil, err } var identifiers []string if username, set := channel.GetUsername(); set { - err = t.main.Store.Username.Set(ctx, ids.PeerTypeChannel, channel.ID, username) + err = tc.main.Store.Username.Set(ctx, ids.PeerTypeChannel, channel.ID, username) if err != nil { return nil, err } @@ -208,7 +208,7 @@ func (t *TelegramClient) wrapChannelGhostInfo(ctx context.Context, channel *tg.C }, nil } -func (t *TelegramClient) wrapUserInfo(ctx context.Context, u tg.UserClass, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) { +func (tc *TelegramClient) wrapUserInfo(ctx context.Context, u tg.UserClass, ghost *bridgev2.Ghost) (*bridgev2.UserInfo, error) { oldMeta := ghost.Metadata.(*GhostMetadata) user, ok := u.(*tg.User) if !ok { @@ -217,12 +217,12 @@ func (t *TelegramClient) wrapUserInfo(ctx context.Context, u tg.UserClass, ghost var identifiers []string if !user.Min { if accessHash, ok := user.GetAccessHash(); ok { - if err := t.ScopedStore.SetAccessHash(ctx, ids.PeerTypeUser, user.ID, accessHash); err != nil { + if err := tc.ScopedStore.SetAccessHash(ctx, ids.PeerTypeUser, user.ID, accessHash); err != nil { return nil, err } } - if err := t.main.Store.Username.Set(ctx, ids.PeerTypeUser, user.ID, user.Username); err != nil { + if err := tc.main.Store.Username.Set(ctx, ids.PeerTypeUser, user.ID, user.Username); err != nil { return nil, err } @@ -235,7 +235,7 @@ func (t *TelegramClient) wrapUserInfo(ctx context.Context, u tg.UserClass, ghost if phone, ok := user.GetPhone(); ok { normalized := strings.TrimPrefix(phone, "+") identifiers = append(identifiers, fmt.Sprintf("tel:+%s", normalized)) - if err := t.main.Store.PhoneNumber.Set(ctx, user.ID, normalized); err != nil { + if err := tc.main.Store.PhoneNumber.Set(ctx, user.ID, normalized); err != nil { return nil, err } } @@ -249,17 +249,17 @@ func (t *TelegramClient) wrapUserInfo(ctx context.Context, u tg.UserClass, ghost (!user.Min || user.ApplyMinPhoto || oldMeta.IsMin()) && // Hack: check ApplyMinPhoto in addition to Personal, because some personalized avatars // only have the ApplyMinPhoto flag and not Personal. - ((!photo.Personal && user.ApplyMinPhoto) || t.main.Config.ContactAvatars) { + ((!photo.Personal && user.ApplyMinPhoto) || tc.main.Config.ContactAvatars) { var err error - avatar, err = t.convertUserProfilePhoto(ctx, user, photo) + avatar, err = tc.convertUserProfilePhoto(ctx, user, photo) if err != nil { return nil, err } } - name := t.main.Config.FormatDisplayname(user.FirstName, user.LastName, user.Username, user.Deleted, user.ID) + name := tc.main.Config.FormatDisplayname(user.FirstName, user.LastName, user.Username, user.Deleted, user.ID) namePtr := &name - if user.Contact && ghost.Name != "" && oldMeta.ContactSource != t.telegramUserID && oldMeta.ContactSource != 0 && !t.main.Config.ContactNames { + if user.Contact && ghost.Name != "" && oldMeta.ContactSource != tc.telegramUserID && oldMeta.ContactSource != 0 && !tc.main.Config.ContactNames { namePtr = nil } if user.Min && !oldMeta.IsMin() && ghost.Name != "" { @@ -277,9 +277,9 @@ func (t *TelegramClient) wrapUserInfo(ctx context.Context, u tg.UserClass, ghost meta.IsPremium = user.Premium meta.Deleted = user.Deleted meta.NotMin = true - if meta.ContactSource == 0 || meta.ContactSource == t.telegramUserID || (!user.Contact && meta.SourceIsContact) { - changed = changed || meta.ContactSource != t.telegramUserID || meta.SourceIsContact != user.Contact - meta.ContactSource = t.telegramUserID + if meta.ContactSource == 0 || meta.ContactSource == tc.telegramUserID || (!user.Contact && meta.SourceIsContact) { + changed = changed || meta.ContactSource != tc.telegramUserID || meta.SourceIsContact != user.Contact + meta.ContactSource = tc.telegramUserID meta.SourceIsContact = user.Contact } }