all: fix inconsistent method receiver names

This commit is contained in:
Tulir Asokan
2026-04-05 21:22:14 +03:00
parent f13af2ef54
commit 92fdf7b8e9
19 changed files with 862 additions and 862 deletions
+47 -47
View File
@@ -40,74 +40,74 @@ var (
) )
// getTakeoutID blocks until the takeout ID is available. // 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 // Always stop the takeout timeout timer
if t.stopTakeoutTimer != nil { if tc.stopTakeoutTimer != nil {
t.stopTakeoutTimer.Stop() tc.stopTakeoutTimer.Stop()
} }
log := zerolog.Ctx(ctx).With().Str("function", "getTakeoutID").Logger() 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 // Resume fetching dialogs using takeout and enqueueing them for
// backfill. // backfill.
go t.takeoutDialogsOnce.Do(func() { go tc.takeoutDialogsOnce.Do(func() {
if err = t.syncChats(ctx, takeoutID, false, false); err != nil { if err = tc.syncChats(ctx, takeoutID, false, false); err != nil {
log.Err(err).Msg("Failed to takeout dialogs") 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 { 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, MessageUsers: true,
MessageChats: true, MessageChats: true,
MessageMegagroups: true, MessageMegagroups: true,
MessageChannels: true, MessageChannels: true,
Files: 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) { if rpcErr, ok := tgerr.As(err); ok && rpcErr.IsOneOf(tg.ErrTakeoutInitDelay) {
log.Warn(). log.Warn().
Err(err). Err(err).
Int("delay", rpcErr.Argument). Int("delay", rpcErr.Argument).
Msg("Takeout requested, will wait for retry request or delay") 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 continue
} else if err != nil { } else if err != nil {
return 0, err return 0, err
} }
// Fetch all dialogs using takeout and enqueue them for backfill. // Fetch all dialogs using takeout and enqueue them for backfill.
go t.takeoutDialogsOnce.Do(func() { go tc.takeoutDialogsOnce.Do(func() {
if err = t.syncChats(ctx, takeoutID, false, false); err != nil { if err = tc.syncChats(ctx, takeoutID, false, false); err != nil {
log.Err(err).Msg("Failed to takeout dialogs") log.Err(err).Msg("Failed to takeout dialogs")
} }
}) })
t.metadata.TakeoutID = accountTakeout.ID tc.metadata.TakeoutID = accountTakeout.ID
return accountTakeout.ID, t.userLogin.Save(ctx) return accountTakeout.ID, tc.userLogin.Save(ctx)
} }
} }
func (t *TelegramClient) stopTakeout(ctx context.Context) error { func (tc *TelegramClient) stopTakeout(ctx context.Context) error {
t.takeoutLock.Lock() tc.takeoutLock.Lock()
defer t.takeoutLock.Unlock() 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 { if err != nil {
return err return err
} }
t.metadata.TakeoutID = 0 tc.metadata.TakeoutID = 0
return t.userLogin.Save(ctx) return tc.userLogin.Save(ctx)
} }
func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2.FetchMessagesParams) (*bridgev2.FetchMessagesResponse, error) { func (tc *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2.FetchMessagesParams) (*bridgev2.FetchMessagesResponse, error) {
if t.metadata.IsBot { if tc.metadata.IsBot {
return nil, fmt.Errorf("bots cannot backfill messages") return nil, fmt.Errorf("bots cannot backfill messages")
} }
log := zerolog.Ctx(ctx).With().Str("method", "FetchMessages").Logger() 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 takeoutID int64
var err error var err error
if (t.main.Config.Takeout.ForwardBackfill && fetchParams.Forward) || (t.main.Config.Takeout.BackwardBackfill && !fetchParams.Forward) { if (tc.main.Config.Takeout.ForwardBackfill && fetchParams.Forward) || (tc.main.Config.Takeout.BackwardBackfill && !fetchParams.Forward) {
t.takeoutLock.Lock() tc.takeoutLock.Lock()
defer t.takeoutLock.Unlock() defer tc.takeoutLock.Unlock()
takeoutID, err = t.getTakeoutID(ctx) takeoutID, err = tc.getTakeoutID(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if takeoutID != 0 { if takeoutID != 0 {
defer func() { defer func() {
if t.stopTakeoutTimer == nil { if tc.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) })) tc.stopTakeoutTimer = time.AfterFunc(max(time.Hour, time.Duration(tc.main.Bridge.Config.Backfill.Queue.BatchDelay*2)), sync.OnceFunc(func() { tc.stopTakeout(ctx) }))
} else { } 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 { if err != nil {
return nil, err return nil, err
} }
@@ -176,10 +176,10 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2
req = &tg.InvokeWithTakeoutRequest{TakeoutID: takeoutID, Query: req} req = &tg.InvokeWithTakeoutRequest{TakeoutID: takeoutID, Query: req}
} }
log.Info().Any("req", req).Msg("Fetching messages") 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 var box tg.MessagesMessagesBox
// TODO a single request can only fetch 100 messages, use multiple requests if the requested count is higher // 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 { if err != nil {
return nil, err return nil, err
} }
@@ -191,8 +191,8 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2
}) })
if err != nil { if err != nil {
if tgerr.Is(err, tg.ErrTakeoutInvalid) { if tgerr.Is(err, tg.ErrTakeoutInvalid) {
t.metadata.TakeoutID = 0 tc.metadata.TakeoutID = 0
err := t.userLogin.Save(ctx) err := tc.userLogin.Save(ctx)
if err != nil { if err != nil {
log.Err(err).Msg("Failed to save user login after clearing takeout ID") log.Err(err).Msg("Failed to save user login after clearing takeout ID")
} else { } else {
@@ -248,12 +248,12 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2
continue continue
} }
sender := t.getEventSender(message, !portal.Metadata.(*PortalMetadata).IsSuperGroup) sender := tc.getEventSender(message, !portal.Metadata.(*PortalMetadata).IsSuperGroup)
intent, ok := portal.GetIntentFor(ctx, sender, t.userLogin, bridgev2.RemoteEventBackfill) intent, ok := portal.GetIntentFor(ctx, sender, tc.userLogin, bridgev2.RemoteEventBackfill)
if !ok { if !ok {
continue continue
} }
converted, err := t.convertToMatrix(ctx, portal, intent, message) converted, err := tc.convertToMatrix(ctx, portal, intent, message)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -267,7 +267,7 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2
} }
if reactions, ok := message.GetReactions(); ok { 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 { if err != nil {
return nil, err return nil, err
} }
@@ -285,7 +285,7 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2
backfillMessage.Reactions = append(backfillMessage.Reactions, &bridgev2.BackfillReaction{ backfillMessage.Reactions = append(backfillMessage.Reactions, &bridgev2.BackfillReaction{
Timestamp: time.Unix(int64(reaction.Date), 0), Timestamp: time.Unix(int64(reaction.Date), 0),
Sender: t.senderForUserID(peer.UserID), Sender: tc.senderForUserID(peer.UserID),
EmojiID: emojiID, EmojiID: emojiID,
Emoji: emoji, Emoji: emoji,
}) })
@@ -307,7 +307,7 @@ func (t *TelegramClient) FetchMessages(ctx context.Context, fetchParams bridgev2
}, nil }, 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(). log := zerolog.Ctx(ctx).With().
Str("method", "GetBackfillMaxBatchCount"). Str("method", "GetBackfillMaxBatchCount").
Logger() Logger()
@@ -318,18 +318,18 @@ func (c *TelegramClient) GetBackfillMaxBatchCount(ctx context.Context, portal *b
} }
switch peerType { switch peerType {
case ids.PeerTypeUser: case ids.PeerTypeUser:
return c.main.Bridge.Config.Backfill.Queue.GetOverride("user") return tc.main.Bridge.Config.Backfill.Queue.GetOverride("user")
case ids.PeerTypeChat: 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: case ids.PeerTypeChannel:
if topicID == ids.TopicIDSpaceRoom { if topicID == ids.TopicIDSpaceRoom {
return 0 return 0
} else if topicID > 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 { } 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 { } else {
return c.main.Bridge.Config.Backfill.Queue.GetOverride("channel") return tc.main.Bridge.Config.Backfill.Queue.GetOverride("channel")
} }
default: default:
log.Error().Str("peer_type", string(peerType)).Msg("unknown peer type") log.Error().Str("peer_type", string(peerType)).Msg("unknown peer type")
+5 -5
View File
@@ -32,7 +32,7 @@ import (
"go.mau.fi/mautrix-telegram/pkg/connector/ids" "go.mau.fi/mautrix-telegram/pkg/connector/ids"
) )
func (tg *TelegramConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities { func (tc *TelegramConnector) GetCapabilities() *bridgev2.NetworkGeneralCapabilities {
return &bridgev2.NetworkGeneralCapabilities{ return &bridgev2.NetworkGeneralCapabilities{
DisappearingMessages: true, DisappearingMessages: true,
Provisioning: bridgev2.ProvisioningCapabilities{ 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 return 1, 8
} }
@@ -210,7 +210,7 @@ func makeTimerList() []jsontime.Milliseconds {
var telegramTimers = makeTimerList() 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" baseID := "fi.mau.telegram.capabilities.2025_11_24"
feat := &event.RoomFeatures{ feat := &event.RoomFeatures{
Formatting: formattingCaps, Formatting: formattingCaps,
@@ -240,7 +240,7 @@ func (t *TelegramClient) GetCapabilities(ctx context.Context, portal *bridgev2.P
reactions := portal.Metadata.(*PortalMetadata).AllowedReactions reactions := portal.Metadata.(*PortalMetadata).AllowedReactions
if reactions == nil { if reactions == nil {
baseID += "+reactions_any" baseID += "+reactions_any"
feat.AllowedReactions, feat.CustomEmojiReactions = t.getAvailableReactionsForCapability(ctx) feat.AllowedReactions, feat.CustomEmojiReactions = tc.getAvailableReactionsForCapability(ctx)
if len(feat.AllowedReactions) > 0 { if len(feat.AllowedReactions) > 0 {
baseID += "+any_list_" + hashEmojiList(feat.AllowedReactions) 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 { for i, react := range feat.AllowedReactions {
feat.AllowedReactions[i] = variationselector.Add(react) feat.AllowedReactions[i] = variationselector.Add(react)
} }
if t.isPremiumCache.Load() { if tc.isPremiumCache.Load() {
baseID += "+premium" baseID += "+premium"
feat.File = premiumFileCaps feat.File = premiumFileCaps
feat.ReactionCount = 3 feat.ReactionCount = 3
+61 -61
View File
@@ -93,8 +93,8 @@ func adminRightsToPowerLevel(rights tg.ChatAdminRights) *int {
return otherPowerLevel return otherPowerLevel
} }
func (t *TelegramClient) getDMChatInfo(ctx context.Context, userID int64) (*bridgev2.ChatInfo, error) { func (tc *TelegramClient) getDMChatInfo(ctx context.Context, userID int64) (*bridgev2.ChatInfo, error) {
ghost, err := t.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(userID)) ghost, err := tc.main.Bridge.GetGhostByID(ctx, ids.MakeUserID(userID))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -104,19 +104,19 @@ func (t *TelegramClient) getDMChatInfo(ctx context.Context, userID int64) (*brid
Members: &bridgev2.ChatMemberList{ Members: &bridgev2.ChatMemberList{
IsFull: true, IsFull: true,
MemberMap: map[networkid.UserID]bridgev2.ChatMember{}, MemberMap: map[networkid.UserID]bridgev2.ChatMember{},
PowerLevels: t.getDMPowerLevels(ghost), PowerLevels: tc.getDMPowerLevels(ghost),
}, },
CanBackfill: !t.metadata.IsBot, CanBackfill: !tc.metadata.IsBot,
ExtraUpdates: updatePortalLastSyncAt, ExtraUpdates: updatePortalLastSyncAt,
} }
chatInfo.Members.MemberMap.Add(bridgev2.ChatMember{EventSender: t.mySender()}) chatInfo.Members.MemberMap.Add(bridgev2.ChatMember{EventSender: tc.mySender()})
chatInfo.Members.MemberMap.Add(bridgev2.ChatMember{EventSender: t.senderForUserID(userID)}) chatInfo.Members.MemberMap.Add(bridgev2.ChatMember{EventSender: tc.senderForUserID(userID)})
if userID == t.telegramUserID { if userID == tc.telegramUserID {
chatInfo.Avatar = &bridgev2.Avatar{ chatInfo.Avatar = &bridgev2.Avatar{
ID: networkid.AvatarID(t.main.Config.SavedMessagesAvatar), ID: networkid.AvatarID(tc.main.Config.SavedMessagesAvatar),
Remove: len(t.main.Config.SavedMessagesAvatar) == 0, Remove: len(tc.main.Config.SavedMessagesAvatar) == 0,
MXC: t.main.Config.SavedMessagesAvatar, MXC: tc.main.Config.SavedMessagesAvatar,
Hash: sha256.Sum256([]byte(t.main.Config.SavedMessagesAvatar)), Hash: sha256.Sum256([]byte(tc.main.Config.SavedMessagesAvatar)),
} }
chatInfo.Name = ptr.Ptr("Telegram Saved Messages") chatInfo.Name = ptr.Ptr("Telegram Saved Messages")
chatInfo.Topic = ptr.Ptr("Your Telegram cloud storage chat") chatInfo.Topic = ptr.Ptr("Your Telegram cloud storage chat")
@@ -140,10 +140,10 @@ type memberFetchMeta struct {
IsForum bool 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{ info := bridgev2.ChatInfo{
Type: ptr.Ptr(database.RoomTypeDefault), Type: ptr.Ptr(database.RoomTypeDefault),
CanBackfill: !t.metadata.IsBot, CanBackfill: !tc.metadata.IsBot,
Members: &bridgev2.ChatMemberList{ Members: &bridgev2.ChatMemberList{
ExcludeChangesFromTimeline: true, ExcludeChangesFromTimeline: true,
MemberMap: bridgev2.ChatMemberMap{}, MemberMap: bridgev2.ChatMemberMap{},
@@ -158,8 +158,8 @@ func (t *TelegramClient) wrapChatInfo(portalID networkid.PortalID, rawChat tg.Ch
case *tg.Chat: case *tg.Chat:
info.Name = &chat.Title info.Name = &chat.Title
info.Members.TotalMemberCount = chat.ParticipantsCount info.Members.TotalMemberCount = chat.ParticipantsCount
info.Avatar, avatarErr = t.convertChatPhoto(chat.AsInputPeer(), chat.Photo) info.Avatar, avatarErr = tc.convertChatPhoto(chat.AsInputPeer(), chat.Photo)
info.Members.PowerLevels = t.getPowerLevelOverridesFromBannedRights(chat, chat.DefaultBannedRights) info.Members.PowerLevels = tc.getPowerLevelOverridesFromBannedRights(chat, chat.DefaultBannedRights)
left = chat.Left left = chat.Left
if chat.Creator { if chat.Creator {
ownPL = creatorPowerLevel ownPL = creatorPowerLevel
@@ -174,8 +174,8 @@ func (t *TelegramClient) wrapChatInfo(portalID networkid.PortalID, rawChat tg.Ch
info.Name = &chat.Title info.Name = &chat.Title
info.Members.TotalMemberCount = chat.ParticipantsCount info.Members.TotalMemberCount = chat.ParticipantsCount
isMegagroup = chat.Megagroup isMegagroup = chat.Megagroup
info.Avatar, avatarErr = t.convertChatPhoto(chat.AsInputPeer(), chat.Photo) info.Avatar, avatarErr = tc.convertChatPhoto(chat.AsInputPeer(), chat.Photo)
info.Members.PowerLevels = t.getPowerLevelOverridesFromBannedRights(chat, chat.DefaultBannedRights) info.Members.PowerLevels = tc.getPowerLevelOverridesFromBannedRights(chat, chat.DefaultBannedRights)
if chat.Creator { if chat.Creator {
ownPL = creatorPowerLevel ownPL = creatorPowerLevel
} else if rights, isAdmin := chat.GetAdminRights(); isAdmin { } 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())}, EventSender: bridgev2.EventSender{Sender: ids.MakeChannelUserID(chat.GetID())},
PowerLevel: superadminPowerLevel, 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 // 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()) 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) return nil, nil, fmt.Errorf("failed to wrap chat avatar: %w", avatarErr)
} }
if !left { 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 { info.ExtraUpdates = func(ctx context.Context, portal *bridgev2.Portal) bool {
meta := portal.Metadata.(*PortalMetadata) meta := portal.Metadata.(*PortalMetadata)
@@ -231,16 +231,16 @@ func (t *TelegramClient) wrapChatInfo(portalID networkid.PortalID, rawChat tg.Ch
return &info, &mfm, nil 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) info.Name = ptr.Ptr(topic.Title + " - " + *info.Name)
if topic.Closed { if topic.Closed {
info.Members.PowerLevels.EventsDefault = nobodyPowerLevel info.Members.PowerLevels.EventsDefault = nobodyPowerLevel
} }
} }
func (t *TelegramClient) getChannelParticipants(ctx context.Context, req *tg.ChannelsGetParticipantsRequest) (*tg.ChannelsChannelParticipants, error) { func (tc *TelegramClient) getChannelParticipants(ctx context.Context, req *tg.ChannelsGetParticipantsRequest) (*tg.ChannelsChannelParticipants, error) {
return APICallWithUpdates(ctx, t, func() (*tg.ChannelsChannelParticipants, error) { return APICallWithUpdates(ctx, tc, func() (*tg.ChannelsChannelParticipants, error) {
p, err := t.client.API().ChannelsGetParticipants(ctx, req) p, err := tc.client.API().ChannelsGetParticipants(ctx, req)
if err != nil { if err != nil {
return nil, err 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 { func (tc *TelegramClient) fillChannelMembers(ctx context.Context, mfm *memberFetchMeta, info *bridgev2.ChatMemberList) error {
if mfm.Input == nil || mfm.ParticipantsHidden || (mfm.IsBroadcast && !t.main.Config.MemberList.SyncBroadcastChannels) { if mfm.Input == nil || mfm.ParticipantsHidden || (mfm.IsBroadcast && !tc.main.Config.MemberList.SyncBroadcastChannels) {
return nil return nil
} }
memberSyncLimit := t.main.Config.MemberList.NormalizedMaxInitialSync() memberSyncLimit := tc.main.Config.MemberList.NormalizedMaxInitialSync()
if memberSyncLimit <= 200 { if memberSyncLimit <= 200 {
participants, err := t.getChannelParticipants(ctx, &tg.ChannelsGetParticipantsRequest{ participants, err := tc.getChannelParticipants(ctx, &tg.ChannelsGetParticipantsRequest{
Channel: mfm.Input, Channel: mfm.Input,
Filter: &tg.ChannelParticipantsRecent{}, Filter: &tg.ChannelParticipantsRecent{},
Limit: memberSyncLimit, Limit: memberSyncLimit,
@@ -267,14 +267,14 @@ func (t *TelegramClient) fillChannelMembers(ctx context.Context, mfm *memberFetc
info.IsFull = len(participants.Participants) < memberSyncLimit && info.IsFull = len(participants.Participants) < memberSyncLimit &&
len(participants.Participants) >= info.TotalMemberCount && len(participants.Participants) >= info.TotalMemberCount &&
info.TotalMemberCount > 0 info.TotalMemberCount > 0
for participant := range t.filterChannelParticipants(participants.Participants, memberSyncLimit) { for participant := range tc.filterChannelParticipants(participants.Participants, memberSyncLimit) {
info.MemberMap.Set(participant) info.MemberMap.Set(participant)
} }
} else { } else {
remaining := memberSyncLimit remaining := memberSyncLimit
var offset int var offset int
for remaining > 0 { for remaining > 0 {
participants, err := t.getChannelParticipants(ctx, &tg.ChannelsGetParticipantsRequest{ participants, err := tc.getChannelParticipants(ctx, &tg.ChannelsGetParticipantsRequest{
Channel: mfm.Input, Channel: mfm.Input,
Filter: &tg.ChannelParticipantsSearch{}, Filter: &tg.ChannelParticipantsSearch{},
Limit: min(remaining, 200), Limit: min(remaining, 200),
@@ -289,7 +289,7 @@ func (t *TelegramClient) fillChannelMembers(ctx context.Context, mfm *memberFetc
break break
} }
for participant := range t.filterChannelParticipants(participants.Participants, remaining) { for participant := range tc.filterChannelParticipants(participants.Participants, remaining) {
info.MemberMap.Set(participant) info.MemberMap.Set(participant)
} }
@@ -300,7 +300,7 @@ func (t *TelegramClient) fillChannelMembers(ctx context.Context, mfm *memberFetc
return nil 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{} info.UserLocal = &bridgev2.UserLocalPortalInfo{}
if mu, ok := dialog.NotifySettings.GetMuteUntil(); ok { if mu, ok := dialog.NotifySettings.GetMuteUntil(); ok {
info.UserLocal.MutedUntil = ptr.Ptr(time.Unix(int64(mu), 0)) 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 var chat tg.ChatClass
for _, c := range fullChat.GetChats() { for _, c := range fullChat.GetChats() {
if c.GetID() == fullChat.FullChat.GetID() { 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()) 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 { if err != nil {
return nil, nil, err return nil, nil, err
} }
@@ -365,7 +365,7 @@ func (t *TelegramClient) wrapFullChatInfo(portalID networkid.PortalID, fullChat
switch typedFullChat := fullChat.FullChat.(type) { switch typedFullChat := fullChat.FullChat.(type) {
case *tg.ChatFull: case *tg.ChatFull:
participants, _ := typedFullChat.GetParticipants().(*tg.ChatParticipants) participants, _ := typedFullChat.GetParticipants().(*tg.ChatParticipants)
memberSyncLimit := t.main.Config.MemberList.NormalizedMaxInitialSync() memberSyncLimit := tc.main.Config.MemberList.NormalizedMaxInitialSync()
info.Members.IsFull = true info.Members.IsFull = true
for i, user := range participants.GetParticipants() { for i, user := range participants.GetParticipants() {
var powerLevel *int var powerLevel *int
@@ -379,7 +379,7 @@ func (t *TelegramClient) wrapFullChatInfo(portalID networkid.PortalID, fullChat
} }
info.Members.MemberMap.Set(bridgev2.ChatMember{ info.Members.MemberMap.Set(bridgev2.ChatMember{
EventSender: t.senderForUserID(user.GetUserID()), EventSender: tc.senderForUserID(user.GetUserID()),
PowerLevel: powerLevel, PowerLevel: powerLevel,
}) })
@@ -422,7 +422,7 @@ func markFullSynced(ctx context.Context, portal *bridgev2.Portal) bool {
return false 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 { if photo == nil {
zerolog.Ctx(ctx).Trace().Msg("Chat photo is nil, returning no avatar") zerolog.Ctx(ctx).Trace().Msg("Chat photo is nil, returning no avatar")
return nil 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") zerolog.Ctx(ctx).Debug().Str("type_name", photo.TypeName()).Msg("Chat photo type unknown, returning no avatar")
return nil return nil
} }
avatar, err := t.convertPhoto(ctx, peerType, peerID, photo) avatar, err := tc.convertPhoto(ctx, peerType, peerID, photo)
if err != nil { if err != nil {
zerolog.Ctx(ctx).Err(err).Int64("id", photo.GetID()).Msg("Failed to convert avatar") zerolog.Ctx(ctx).Err(err).Int64("id", photo.GetID()).Msg("Failed to convert avatar")
return nil return nil
@@ -438,22 +438,22 @@ func (t *TelegramClient) avatarFromPhoto(ctx context.Context, peerType ids.PeerT
return avatar 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) { return func(yield func(bridgev2.ChatMember) bool) {
for i, u := range participants { for i, u := range participants {
var member bridgev2.ChatMember var member bridgev2.ChatMember
switch participant := u.(type) { switch participant := u.(type) {
case *tg.ChannelParticipant: case *tg.ChannelParticipant:
member.EventSender = t.senderForUserID(participant.GetUserID()) member.EventSender = tc.senderForUserID(participant.GetUserID())
member.PowerLevel = anyonePowerLevel member.PowerLevel = anyonePowerLevel
case *tg.ChannelParticipantSelf: case *tg.ChannelParticipantSelf:
member.EventSender = t.senderForUserID(participant.GetUserID()) member.EventSender = tc.senderForUserID(participant.GetUserID())
member.PowerLevel = anyonePowerLevel member.PowerLevel = anyonePowerLevel
case *tg.ChannelParticipantCreator: case *tg.ChannelParticipantCreator:
member.EventSender = t.senderForUserID(participant.GetUserID()) member.EventSender = tc.senderForUserID(participant.GetUserID())
member.PowerLevel = creatorPowerLevel member.PowerLevel = creatorPowerLevel
case *tg.ChannelParticipantAdmin: case *tg.ChannelParticipantAdmin:
member.EventSender = t.senderForUserID(participant.GetUserID()) member.EventSender = tc.senderForUserID(participant.GetUserID())
member.PowerLevel = adminRightsToPowerLevel(participant.AdminRights) member.PowerLevel = adminRightsToPowerLevel(participant.AdminRights)
case *tg.ChannelParticipantBanned: case *tg.ChannelParticipantBanned:
if participant.BannedRights.ViewMessages { if participant.BannedRights.ViewMessages {
@@ -466,12 +466,12 @@ func (t *TelegramClient) filterChannelParticipants(participants []tg.ChannelPart
} else { } else {
member.PowerLevel = anyonePowerLevel member.PowerLevel = anyonePowerLevel
} }
member.EventSender = t.getPeerSender(participant.GetPeer()) member.EventSender = tc.getPeerSender(participant.GetPeer())
member.MemberSender = t.senderForUserID(participant.GetKickedBy()) member.MemberSender = tc.senderForUserID(participant.GetKickedBy())
case *tg.ChannelParticipantLeft: case *tg.ChannelParticipantLeft:
member.Membership = event.MembershipLeave member.Membership = event.MembershipLeave
member.PrevMembership = event.MembershipJoin member.PrevMembership = event.MembershipJoin
member.EventSender = t.getPeerSender(participant.GetPeer()) member.EventSender = tc.getPeerSender(participant.GetPeer())
default: default:
// TODO warning log? // TODO warning log?
continue 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) peerType, id, topicID, err := ids.ParsePortalID(portal.ID)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -495,24 +495,24 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta
switch peerType { switch peerType {
case ids.PeerTypeUser: case ids.PeerTypeUser:
return t.getDMChatInfo(ctx, id) return tc.getDMChatInfo(ctx, id)
case ids.PeerTypeChat: case ids.PeerTypeChat:
fullChat, err := APICallWithUpdates(ctx, t, func() (*tg.MessagesChatFull, error) { fullChat, err := APICallWithUpdates(ctx, tc, func() (*tg.MessagesChatFull, error) {
return t.client.API().MessagesGetFullChat(ctx, id) return tc.client.API().MessagesGetFullChat(ctx, id)
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
info, _, err := t.wrapFullChatInfo(portal.ID, fullChat) info, _, err := tc.wrapFullChatInfo(portal.ID, fullChat)
return info, err return info, err
case ids.PeerTypeChannel: case ids.PeerTypeChannel:
accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id) accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to get channel access hash: %w", err) return nil, fmt.Errorf("failed to get channel access hash: %w", err)
} }
if topicID > 0 { if topicID > 0 {
resp, err := APICallWithUpdates(ctx, t, func() (*tg.MessagesForumTopics, error) { resp, err := APICallWithUpdates(ctx, tc, func() (*tg.MessagesForumTopics, error) {
return t.client.API().MessagesGetForumTopicsByID(ctx, &tg.MessagesGetForumTopicsByIDRequest{ return tc.client.API().MessagesGetForumTopicsByID(ctx, &tg.MessagesGetForumTopicsByIDRequest{
Peer: &tg.InputPeerChannel{ChannelID: id, AccessHash: accessHash}, Peer: &tg.InputPeerChannel{ChannelID: id, AccessHash: accessHash},
Topics: []int{topicID}, Topics: []int{topicID},
}) })
@@ -524,24 +524,24 @@ func (t *TelegramClient) GetChatInfo(ctx context.Context, portal *bridgev2.Porta
if err != nil { if err != nil {
return nil, err return nil, err
} }
info, _, err := t.wrapChatInfo(portal.ID, channel) info, _, err := tc.wrapChatInfo(portal.ID, channel)
if err != nil { if err != nil {
return nil, err return nil, err
} }
t.overrideChatInfoWithTopic(info, topic) tc.overrideChatInfoWithTopic(info, topic)
return info, nil return info, nil
} }
fullChat, err := APICallWithUpdates(ctx, t, func() (*tg.MessagesChatFull, error) { fullChat, err := APICallWithUpdates(ctx, tc, func() (*tg.MessagesChatFull, error) {
return t.client.API().ChannelsGetFullChannel(ctx, &tg.InputChannel{ChannelID: id, AccessHash: accessHash}) return tc.client.API().ChannelsGetFullChannel(ctx, &tg.InputChannel{ChannelID: id, AccessHash: accessHash})
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
info, mfm, err := t.wrapFullChatInfo(portal.ID, fullChat) info, mfm, err := tc.wrapFullChatInfo(portal.ID, fullChat)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = t.fillChannelMembers(ctx, mfm, info.Members) err = tc.fillChannelMembers(ctx, mfm, info.Members)
if err != nil { if err != nil {
zerolog.Ctx(ctx).Err(err).Msg("Failed to get channel members") zerolog.Ctx(ctx).Err(err).Msg("Failed to get channel members")
} }
@@ -580,7 +580,7 @@ func getTopicInfoFromResponse(resp *tg.MessagesForumTopics, channelID int64, top
return return
} }
func (t *TelegramClient) getDMPowerLevels(ghost *bridgev2.Ghost) *bridgev2.PowerLevelOverrides { func (tc *TelegramClient) getDMPowerLevels(ghost *bridgev2.Ghost) *bridgev2.PowerLevelOverrides {
var plo bridgev2.PowerLevelOverrides var plo bridgev2.PowerLevelOverrides
// TODO use per-login metadata for blocked status // TODO use per-login metadata for blocked status
if /*ghost.Metadata.(*GhostMetadata).Blocked*/ false { if /*ghost.Metadata.(*GhostMetadata).Blocked*/ false {
@@ -599,7 +599,7 @@ func (t *TelegramClient) getDMPowerLevels(ghost *bridgev2.Ghost) *bridgev2.Power
return &plo 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 var plo bridgev2.PowerLevelOverrides
plo.Ban = banUsersPowerLevel plo.Ban = banUsersPowerLevel
plo.Kick = banUsersPowerLevel plo.Kick = banUsersPowerLevel
+45 -45
View File
@@ -33,8 +33,8 @@ import (
"go.mau.fi/mautrix-telegram/pkg/gotd/tgerr" "go.mau.fi/mautrix-telegram/pkg/gotd/tgerr"
) )
func (t *TelegramClient) syncChats(ctx context.Context, takeoutID int64, onLogin, restart bool) error { func (tc *TelegramClient) syncChats(ctx context.Context, takeoutID int64, onLogin, restart bool) error {
if takeoutID != 0 && !t.main.Config.Takeout.DialogSync { if takeoutID != 0 && !tc.main.Config.Takeout.DialogSync {
return nil return nil
} }
logWith := zerolog.Ctx(ctx).With().Str("loop", "chat sync") 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() log := logWith.Logger()
if !t.syncChatsLock.TryLock() { if !tc.syncChatsLock.TryLock() {
log.Warn().Msg("Waiting for chat sync lock") log.Warn().Msg("Waiting for chat sync lock")
t.syncChatsLock.Lock() tc.syncChatsLock.Lock()
log.Debug().Msg("Acquired chat sync lock after waiting") log.Debug().Msg("Acquired chat sync lock after waiting")
} }
defer t.syncChatsLock.Unlock() defer tc.syncChatsLock.Unlock()
if restart { if restart {
t.metadata.DialogSyncCount = 0 tc.metadata.DialogSyncCount = 0
t.metadata.DialogSyncComplete = false tc.metadata.DialogSyncComplete = false
t.metadata.DialogSyncCursor = "" tc.metadata.DialogSyncCursor = ""
} else if t.metadata.DialogSyncComplete { } else if tc.metadata.DialogSyncComplete {
log.Debug().Msg("Dialogs already synced") log.Debug().Msg("Dialogs already synced")
return nil return nil
} }
isFullSync := true isFullSync := true
updateLimit := subtractLimit(t.main.Config.Sync.UpdateLimit, t.metadata.DialogSyncCount) updateLimit := subtractLimit(tc.main.Config.Sync.UpdateLimit, tc.metadata.DialogSyncCount)
if onLogin && t.main.Config.Takeout.DialogSync { if onLogin && tc.main.Config.Takeout.DialogSync {
updateLimit = t.main.Config.Sync.LoginLimit updateLimit = tc.main.Config.Sync.LoginLimit
isFullSync = false 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 var req tg.MessagesGetDialogsRequest
isFirst := true isFirst := true
if t.metadata.DialogSyncCursor != "" { if tc.metadata.DialogSyncCursor != "" {
isFirst = false isFirst = false
var err error var err error
req.OffsetPeer, _, err = t.inputPeerForPortalID(ctx, t.metadata.DialogSyncCursor) req.OffsetPeer, _, err = tc.inputPeerForPortalID(ctx, tc.metadata.DialogSyncCursor)
if err != nil { if err != nil {
return fmt.Errorf("failed to get input peer for pagination: %w", err) 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("update_limit", updateLimit).
Int("create_limit", createLimit). Int("create_limit", createLimit).
Msg("Fetching dialogs") 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 var dialogs tg.MessagesDialogsBox
retry := true retry := true
var err error var err error
for retry { 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 { if err != nil {
return nil, err return nil, err
@@ -123,7 +123,7 @@ func (t *TelegramClient) syncChats(ctx context.Context, takeoutID int64, onLogin
if isFirst { if isFirst {
// This is the first fetch of dialogs, reset the pinned dialogs based on the list. // 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) 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 { if updateLimit > 0 && len(dialogList) > updateLimit {
dialogList = dialogList[:updateLimit] dialogList = dialogList[:updateLimit]
} }
err = t.handleDialogs(ctx, dialogList, dialogs, createLimit) err = tc.handleDialogs(ctx, dialogList, dialogs, createLimit)
if err != nil { if err != nil {
return fmt.Errorf("failed to handle dialogs: %w", err) return fmt.Errorf("failed to handle dialogs: %w", err)
} }
updateLimit = subtractLimit(updateLimit, len(dialogList)) updateLimit = subtractLimit(updateLimit, len(dialogList))
createLimit = subtractLimit(createLimit, len(dialogList)) createLimit = subtractLimit(createLimit, len(dialogList))
cursorPortalKey := t.makePortalKeyFromPeer(dialogList[len(dialogList)-1].GetPeer(), 0) cursorPortalKey := tc.makePortalKeyFromPeer(dialogList[len(dialogList)-1].GetPeer(), 0)
if t.metadata.DialogSyncCursor == cursorPortalKey.ID { if tc.metadata.DialogSyncCursor == cursorPortalKey.ID {
log.Debug().Msg("No more dialogs found (last dialog is same as old cursor)") log.Debug().Msg("No more dialogs found (last dialog is same as old cursor)")
break break
} }
t.metadata.DialogSyncCursor = cursorPortalKey.ID tc.metadata.DialogSyncCursor = cursorPortalKey.ID
t.metadata.DialogSyncCount += len(dialogList) tc.metadata.DialogSyncCount += len(dialogList)
if err = t.userLogin.Save(ctx); err != nil { if err = tc.userLogin.Save(ctx); err != nil {
return fmt.Errorf("failed to save user login to update cursor: %w", err) 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 { if err != nil {
return fmt.Errorf("failed to get input peer for pagination: %w", err) return fmt.Errorf("failed to get input peer for pagination: %w", err)
} }
} }
if isFullSync { if isFullSync {
t.metadata.DialogSyncComplete = true tc.metadata.DialogSyncComplete = true
t.metadata.DialogSyncCursor = "" tc.metadata.DialogSyncCursor = ""
t.metadata.DialogSyncCount = 0 tc.metadata.DialogSyncCount = 0
if err := t.userLogin.Save(ctx); err != nil { if err := tc.userLogin.Save(ctx); err != nil {
return fmt.Errorf("failed to save user login after successful sync: %w", err) 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 return limit
} }
func (t *TelegramClient) resetPinnedDialogs(ctx context.Context, dialogs []tg.DialogClass) error { func (tc *TelegramClient) resetPinnedDialogs(ctx context.Context, dialogs []tg.DialogClass) error {
t.metadata.PinnedDialogs = nil tc.metadata.PinnedDialogs = nil
for _, dialog := range dialogs { for _, dialog := range dialogs {
if dialog.GetPinned() { if dialog.GetPinned() {
portalKey := t.makePortalKeyFromPeer(dialog.GetPeer(), 0) portalKey := tc.makePortalKeyFromPeer(dialog.GetPeer(), 0)
t.metadata.PinnedDialogs = append(t.metadata.PinnedDialogs, portalKey.ID) 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) log := zerolog.Ctx(ctx)
users := map[int64]tg.UserClass{} users := map[int64]tg.UserClass{}
@@ -218,8 +218,8 @@ func (t *TelegramClient) handleDialogs(ctx context.Context, dialogList []tg.Dial
Logger() Logger()
log.Debug().Msg("Syncing dialog") log.Debug().Msg("Syncing dialog")
portalKey := t.makePortalKeyFromPeer(dialog.GetPeer(), 0) portalKey := tc.makePortalKeyFromPeer(dialog.GetPeer(), 0)
portal, err := t.main.Bridge.GetPortalByKey(ctx, portalKey) portal, err := tc.main.Bridge.GetPortalByKey(ctx, portalKey)
if err != nil { if err != nil {
return err 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") log.Debug().Int64("user_id", peer.UserID).Msg("Not syncing portal because user is deleted")
continue continue
} }
chatInfo, err = t.getDMChatInfo(ctx, peer.UserID) chatInfo, err = tc.getDMChatInfo(ctx, peer.UserID)
if err != nil { if err != nil {
return fmt.Errorf("failed to get dm info for %d: %w", peer.UserID, err) 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) { switch chat := chats[peer.ChatID].(type) {
case *tg.Chat: case *tg.Chat:
// Need to get full chat info to get the member list // 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 { if err != nil {
return fmt.Errorf("failed to get chat info for %s: %w", portalKey, err) 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) { switch channel := chats[peer.ChannelID].(type) {
case *tg.Channel: case *tg.Channel:
var mfm *memberFetchMeta var mfm *memberFetchMeta
chatInfo, mfm, err = t.wrapChatInfo(portal.ID, channel) chatInfo, mfm, err = tc.wrapChatInfo(portal.ID, channel)
if err != nil { if err != nil {
return fmt.Errorf("failed to get chat info for %s: %w", portalKey, err) 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 { if err != nil {
log.Err(err).Msg("Failed to get channel members") 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, ChatInfo: chatInfo,
EventMeta: simplevent.EventMeta{ EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventChatResync, 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 // 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{ EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventReadReceipt, Type: bridgev2.RemoteEventReadReceipt,
PortalKey: portalKey, PortalKey: portalKey,
Sender: t.mySender(), Sender: tc.mySender(),
}, },
LastTarget: ids.MakeMessageID(portalKey, dialog.ReadInboxMaxID), LastTarget: ids.MakeMessageID(portalKey, dialog.ReadInboxMaxID),
ReadUpToStreamOrder: int64(dialog.ReadInboxMaxID), ReadUpToStreamOrder: int64(dialog.ReadInboxMaxID),
+103 -103
View File
@@ -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}))?$`) 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{ return telegram.DeviceConfig{
DeviceModel: tg.Config.DeviceInfo.DeviceModel, DeviceModel: tc.Config.DeviceInfo.DeviceModel,
SystemVersion: tg.Config.DeviceInfo.SystemVersion, SystemVersion: tc.Config.DeviceInfo.SystemVersion,
AppVersion: tg.Config.DeviceInfo.AppVersion, AppVersion: tc.Config.DeviceInfo.AppVersion,
SystemLangCode: tg.Config.DeviceInfo.SystemLangCode, SystemLangCode: tc.Config.DeviceInfo.SystemLangCode,
LangCode: tg.Config.DeviceInfo.LangCode, LangCode: tc.Config.DeviceInfo.LangCode,
} }
} }
@@ -365,34 +365,34 @@ func NewTelegramClient(ctx context.Context, tc *TelegramConnector, login *bridge
return &client, err return &client, err
} }
func (t *TelegramClient) onDead() { func (tc *TelegramClient) onDead() {
prevState := t.userLogin.BridgeState.GetPrev().StateEvent prevState := tc.userLogin.BridgeState.GetPrev().StateEvent
if slices.Contains([]status.BridgeStateEvent{ if slices.Contains([]status.BridgeStateEvent{
status.StateTransientDisconnect, status.StateTransientDisconnect,
status.StateBadCredentials, status.StateBadCredentials,
status.StateLoggedOut, status.StateLoggedOut,
status.StateUnknownError, status.StateUnknownError,
}, prevState) { }, prevState) {
t.userLogin.Log.Warn(). tc.userLogin.Log.Warn().
Str("prev_state", string(prevState)). Str("prev_state", string(prevState)).
Msg("client is dead, not sending transient disconnect, because already in an error state") Msg("client is dead, not sending transient disconnect, because already in an error state")
return return
} }
t.userLogin.BridgeState.Send(status.BridgeState{ tc.userLogin.BridgeState.Send(status.BridgeState{
StateEvent: status.StateTransientDisconnect, StateEvent: status.StateTransientDisconnect,
Message: "Telegram client disconnected", Message: "Telegram client disconnected",
}) })
} }
func (t *TelegramClient) sendBadCredentialsOrUnknownError(err error) { func (tc *TelegramClient) sendBadCredentialsOrUnknownError(err error) {
if auth.IsUnauthorized(err) || errors.Is(err, ErrNoAuthKey) { if auth.IsUnauthorized(err) || errors.Is(err, ErrNoAuthKey) {
t.userLogin.BridgeState.Send(status.BridgeState{ tc.userLogin.BridgeState.Send(status.BridgeState{
StateEvent: status.StateBadCredentials, StateEvent: status.StateBadCredentials,
Error: "tg-no-auth", Error: "tg-no-auth",
Message: humanise.Error(err), Message: humanise.Error(err),
}) })
} else { } else {
t.userLogin.BridgeState.Send(status.BridgeState{ tc.userLogin.BridgeState.Send(status.BridgeState{
StateEvent: status.StateUnknownError, StateEvent: status.StateUnknownError,
Error: "tg-unknown-error", Error: "tg-unknown-error",
Message: humanise.Error(err), Message: humanise.Error(err),
@@ -403,38 +403,38 @@ func (t *TelegramClient) sendBadCredentialsOrUnknownError(err error) {
} }
} }
func (t *TelegramClient) onPing() { func (tc *TelegramClient) onPing() {
prev := t.userLogin.BridgeState.GetPrev() prev := tc.userLogin.BridgeState.GetPrev()
if prev.StateEvent == status.StateConnected || prev.Error == updateHandlerStuck { if prev.StateEvent == status.StateConnected || prev.Error == updateHandlerStuck {
return return
} }
ctx := t.userLogin.Log.WithContext(t.main.Bridge.BackgroundCtx) ctx := tc.userLogin.Log.WithContext(tc.main.Bridge.BackgroundCtx)
t.userLogin.Log.Debug().Msg("Got ping while not connected, checking auth") 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) { if auth.IsUnauthorized(err) {
t.onAuthError(err) tc.onAuthError(err)
} else if errors.Is(err, syscall.EPIPE) { } else if errors.Is(err, syscall.EPIPE) {
// This is a pipe error, try disconnecting which will force the // This is a pipe error, try disconnecting which will force the
// updatesManager to fail and cause the client to reconnect. // updatesManager to fail and cause the client to reconnect.
t.userLogin.BridgeState.Send(status.BridgeState{ tc.userLogin.BridgeState.Send(status.BridgeState{
StateEvent: status.StateTransientDisconnect, StateEvent: status.StateTransientDisconnect,
Error: "pipe-error", Error: "pipe-error",
Message: humanise.Error(err), Message: humanise.Error(err),
}) })
} else if err != nil { } else if err != nil {
t.sendBadCredentialsOrUnknownError(err) tc.sendBadCredentialsOrUnknownError(err)
} else { } else {
t.onConnected(me) tc.onConnected(me)
} }
} }
func (t *TelegramConnector) userToRemoteProfile( func (tc *TelegramConnector) userToRemoteProfile(
self *tg.User, self *tg.User,
ghost *bridgev2.Ghost, ghost *bridgev2.Ghost,
prevState *status.RemoteProfile, prevState *status.RemoteProfile,
) (profile status.RemoteProfile, name string) { ) (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 != "" { if self.Phone != "" {
profile.Phone = "+" + strings.TrimPrefix(self.Phone, "+") profile.Phone = "+" + strings.TrimPrefix(self.Phone, "+")
} else if prevState != nil { } else if prevState != nil {
@@ -453,99 +453,99 @@ func (t *TelegramConnector) userToRemoteProfile(
return return
} }
func (t *TelegramClient) updateRemoteProfile(ctx context.Context, self *tg.User, ghost *bridgev2.Ghost) bool { func (tc *TelegramClient) updateRemoteProfile(ctx context.Context, self *tg.User, ghost *bridgev2.Ghost) bool {
newProfile, newName := t.main.userToRemoteProfile(self, ghost, &t.userLogin.RemoteProfile) newProfile, newName := tc.main.userToRemoteProfile(self, ghost, &tc.userLogin.RemoteProfile)
if t.userLogin.RemoteProfile != newProfile || t.userLogin.RemoteName != newName { if tc.userLogin.RemoteProfile != newProfile || tc.userLogin.RemoteName != newName {
t.userLogin.RemoteProfile = newProfile tc.userLogin.RemoteProfile = newProfile
t.userLogin.RemoteName = newName tc.userLogin.RemoteName = newName
err := t.userLogin.Save(ctx) err := tc.userLogin.Save(ctx)
if err != nil { 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 true
} }
return false return false
} }
func (t *TelegramClient) onConnected(self *tg.User) { func (tc *TelegramClient) onConnected(self *tg.User) {
log := t.userLogin.Log log := tc.userLogin.Log
ctx := log.WithContext(t.main.Bridge.BackgroundCtx) ctx := log.WithContext(tc.main.Bridge.BackgroundCtx)
ghost, err := t.main.Bridge.GetGhostByID(ctx, t.userID) ghost, err := tc.main.Bridge.GetGhostByID(ctx, tc.userID)
if err != nil { if err != nil {
log.Err(err).Msg("Failed to get own ghost") 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") log.Err(err).Msg("Failed to wrap own user info")
} else { } else {
ghost.UpdateInfo(ctx, wrapped) ghost.UpdateInfo(ctx, wrapped)
} }
t.updateRemoteProfile(ctx, self, ghost) tc.updateRemoteProfile(ctx, self, ghost)
t.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected}) tc.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnected})
} }
func (t *TelegramClient) onTransfer(ctx context.Context, _ *telegram.Client, fn func(context.Context) error) error { func (tc *TelegramClient) onTransfer(ctx context.Context, _ *telegram.Client, fn func(context.Context) error) error {
t.userLogin.Log.Trace().Msg("Doing DC auth transfer") tc.userLogin.Log.Trace().Msg("Doing DC auth transfer")
t.dcTransferLock.Lock() tc.dcTransferLock.Lock()
defer t.dcTransferLock.Unlock() defer tc.dcTransferLock.Unlock()
return fn(ctx) return fn(ctx)
} }
func (t *TelegramClient) onSession() { func (tc *TelegramClient) onSession() {
t.userLogin.Log.Debug().Msg("Got session created event") tc.userLogin.Log.Debug().Msg("Got session created event")
} }
func (t *TelegramClient) onAuthError(err error) { func (tc *TelegramClient) onAuthError(err error) {
t.sendBadCredentialsOrUnknownError(err) tc.sendBadCredentialsOrUnknownError(err)
t.metadata.ResetOnLogout() tc.metadata.ResetOnLogout()
go func() { go func() {
t.Disconnect() tc.Disconnect()
if err := t.userLogin.Save(context.Background()); err != nil { if err := tc.userLogin.Save(context.Background()); err != nil {
t.main.Bridge.Log.Err(err).Msg("failed to save user login") tc.main.Bridge.Log.Err(err).Msg("failed to save user login")
} }
}() }()
} }
func (t *TelegramClient) Connect(ctx context.Context) { func (tc *TelegramClient) Connect(ctx context.Context) {
t.mu.Lock() tc.mu.Lock()
defer t.mu.Unlock() defer tc.mu.Unlock()
log := zerolog.Ctx(ctx) 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") log.Warn().Msg("user does not have an auth key, sending bad credentials state")
t.sendBadCredentialsOrUnknownError(ErrNoAuthKey) tc.sendBadCredentialsOrUnknownError(ErrNoAuthKey)
return return
} }
t.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnecting}) tc.userLogin.BridgeState.Send(status.BridgeState{StateEvent: status.StateConnecting})
log.Info().Msg("Connecting client") log.Info().Msg("Connecting client")
// Add a cancellation layer we can use for explicit Disconnect // Add a cancellation layer we can use for explicit Disconnect
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
t.clientCtx = ctx tc.clientCtx = ctx
t.clientCancel = cancel tc.clientCancel = cancel
t.clientDone.Clear() tc.clientDone.Clear()
t.clientInitialized.Clear() tc.clientInitialized.Clear()
go t.runInBackground(ctx) go tc.runInBackground(ctx)
} }
func (t *TelegramClient) runInBackground(ctx context.Context) { func (tc *TelegramClient) runInBackground(ctx context.Context) {
log := zerolog.Ctx(ctx) log := zerolog.Ctx(ctx)
err := t.client.Run(ctx, func(ctx context.Context) error { err := tc.client.Run(ctx, func(ctx context.Context) error {
t.clientInitialized.Set() tc.clientInitialized.Set()
// If takeout dialog sync is enabled, we assume it'll resume from a getTakeoutID call. // If takeout dialog sync is enabled, we assume it'll resume from a getTakeoutID call.
// If not, resume dialog sync manually here. // 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() { 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.Err(err).Msg("Failed to resume chat sync")
} }
}() }()
} }
log.Info().Msg("Client running, starting updates") log.Info().Msg("Client running, starting updates")
err := t.updatesManager.Run(ctx, t.client.API(), t.telegramUserID, updates.AuthOptions{ err := tc.updatesManager.Run(ctx, tc.client.API(), tc.telegramUserID, updates.AuthOptions{
IsBot: t.metadata.IsBot, IsBot: tc.metadata.IsBot,
}) })
if err != nil && !errors.Is(err, ctx.Err()) { if err != nil && !errors.Is(err, ctx.Err()) {
log.Warn().Err(err).AnErr("ctx_err", ctx.Err()).Msg("Update manager exited with error") 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 return err
}) })
t.clientDone.Set() tc.clientDone.Set()
t.clientInitialized.Set() tc.clientInitialized.Set()
if err != nil { if err != nil {
log.Err(err).AnErr("ctx_err", ctx.Err()).Msg("Client exited with error") log.Err(err).AnErr("ctx_err", ctx.Err()).Msg("Client exited with error")
t.sendBadCredentialsOrUnknownError(err) tc.sendBadCredentialsOrUnknownError(err)
} else if ctx.Err() == nil { } else if ctx.Err() == nil {
log.Warn().Msg("Client exited unexpectedly") log.Warn().Msg("Client exited unexpectedly")
t.sendBadCredentialsOrUnknownError(fmt.Errorf("unexpectedly disconnected from Telegram")) tc.sendBadCredentialsOrUnknownError(fmt.Errorf("unexpectedly disconnected from Telegram"))
} else { } else {
log.Debug().AnErr("ctx_err", ctx.Err()).Msg("Client exited without error") log.Debug().AnErr("ctx_err", ctx.Err()).Msg("Client exited without error")
} }
} }
func (t *TelegramClient) Disconnect() { func (tc *TelegramClient) Disconnect() {
t.mu.Lock() tc.mu.Lock()
defer t.mu.Unlock() defer tc.mu.Unlock()
t.userLogin.Log.Debug().Msg("Disconnecting client") tc.userLogin.Log.Debug().Msg("Disconnecting client")
if t.clientCancel != nil { if tc.clientCancel != nil {
t.clientCancel() tc.clientCancel()
t.userLogin.Log.Debug().Msg("Waiting for client disconnection") tc.userLogin.Log.Debug().Msg("Waiting for client disconnection")
<-t.clientDone.GetChan() <-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 // TODO use less hacky check than context cancellation
return t != nil && t.client != nil && return tc != nil && tc.client != nil &&
t.clientInitialized.IsSet() && !t.clientDone.IsSet() && tc.clientInitialized.IsSet() && !tc.clientDone.IsSet() &&
t.metadata.Session.HasAuthKey() tc.metadata.Session.HasAuthKey()
} }
func (t *TelegramClient) LogoutRemote(ctx context.Context) { func (tc *TelegramClient) LogoutRemote(ctx context.Context) {
log := zerolog.Ctx(ctx).With(). log := zerolog.Ctx(ctx).With().
Str("action", "logout_remote"). Str("action", "logout_remote").
Int64("user_id", t.telegramUserID). Int64("user_id", tc.telegramUserID).
Logger() Logger()
log.Info().Msg("Logging out and disconnecting") 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") 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 // 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) ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel() defer cancel()
_, err := t.client.API().AuthLogOut(ctx) _, err := tc.client.API().AuthLogOut(ctx)
if err != nil { if err != nil {
log.Err(err).Msg("failed to logout on Telegram") log.Err(err).Msg("failed to logout on Telegram")
} }
} }
t.Disconnect() tc.Disconnect()
log.Info().Msg("Deleting user state") log.Info().Msg("Deleting user state")
err := t.ScopedStore.DeleteUserState(ctx) err := tc.ScopedStore.DeleteUserState(ctx)
if err != nil { if err != nil {
log.Err(err).Msg("failed to delete user state") log.Err(err).Msg("failed to delete user state")
} }
err = t.ScopedStore.DeleteChannelStateForUser(ctx) err = tc.ScopedStore.DeleteChannelStateForUser(ctx)
if err != nil { if err != nil {
log.Err(err).Msg("failed to delete channel state for user") log.Err(err).Msg("failed to delete channel state for user")
} }
err = t.ScopedStore.DeleteAccessHashesForUser(ctx) err = tc.ScopedStore.DeleteAccessHashesForUser(ctx)
if err != nil { if err != nil {
log.Err(err).Msg("failed to delete access hashes for user") 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") log.Info().Msg("Logged out and deleted user state")
} }
func (t *TelegramClient) IsThisUser(ctx context.Context, userID networkid.UserID) bool { func (tc *TelegramClient) IsThisUser(ctx context.Context, userID networkid.UserID) bool {
return userID == networkid.UserID(t.userLogin.ID) return userID == networkid.UserID(tc.userLogin.ID)
} }
func (t *TelegramClient) mySender() bridgev2.EventSender { func (tc *TelegramClient) mySender() bridgev2.EventSender {
return bridgev2.EventSender{ return bridgev2.EventSender{
IsFromMe: true, IsFromMe: true,
SenderLogin: t.loginID, SenderLogin: tc.loginID,
Sender: t.userID, Sender: tc.userID,
} }
} }
func (t *TelegramClient) senderForUserID(userID int64) bridgev2.EventSender { func (tc *TelegramClient) senderForUserID(userID int64) bridgev2.EventSender {
return bridgev2.EventSender{ return bridgev2.EventSender{
IsFromMe: userID == t.telegramUserID, IsFromMe: userID == tc.telegramUserID,
SenderLogin: ids.MakeUserLoginID(userID), SenderLogin: ids.MakeUserLoginID(userID),
Sender: ids.MakeUserID(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 { if state.Info == nil {
state.Info = make(map[string]any) state.Info = make(map[string]any)
} }
state.Info["is_bot"] = t.metadata.IsBot state.Info["is_bot"] = tc.metadata.IsBot
state.Info["login_method"] = t.metadata.LoginMethod state.Info["login_method"] = tc.metadata.LoginMethod
return state return state
} }
+7 -7
View File
@@ -179,8 +179,8 @@ func upgradeConfig(helper up.Helper) {
helper.Copy(up.Str, "displayname_template") helper.Copy(up.Str, "displayname_template")
} }
func (tg *TelegramConnector) GetConfig() (example string, data any, upgrader up.Upgrader) { func (tc *TelegramConnector) GetConfig() (example string, data any, upgrader up.Upgrader) {
return ExampleConfig, &tg.Config, &up.StructUpgrader{ return ExampleConfig, &tc.Config, &up.StructUpgrader{
SimpleUpgrader: up.SimpleUpgrader(upgradeConfig), SimpleUpgrader: up.SimpleUpgrader(upgradeConfig),
Blocks: [][]string{ Blocks: [][]string{
{"device_info"}, {"device_info"},
@@ -195,15 +195,15 @@ func (tg *TelegramConnector) GetConfig() (example string, data any, upgrader up.
} }
} }
func (tg *TelegramConnector) ValidateConfig() error { func (tc *TelegramConnector) ValidateConfig() error {
if tg.Config.APIID == 0 { if tc.Config.APIID == 0 {
return fmt.Errorf("api_id is required") 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") return fmt.Errorf("api_hash is required")
} }
if !slices.Contains([]string{"disable", "gif", "png", "webp", "webm"}, 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", tg.Config.AnimatedSticker.Target) return fmt.Errorf("unsupported animated sticker target: %s", tc.Config.AnimatedSticker.Target)
} }
return nil return nil
} }
+9 -9
View File
@@ -38,14 +38,14 @@ type TelegramConnector struct {
var _ bridgev2.NetworkConnector = (*TelegramConnector)(nil) var _ bridgev2.NetworkConnector = (*TelegramConnector)(nil)
var _ bridgev2.MaxFileSizeingNetwork = (*TelegramConnector)(nil) var _ bridgev2.MaxFileSizeingNetwork = (*TelegramConnector)(nil)
func (tg *TelegramConnector) Init(bridge *bridgev2.Bridge) { func (tc *TelegramConnector) Init(bridge *bridgev2.Bridge) {
tg.Store = store.NewStore(bridge.DB.Database, dbutil.ZeroLogger(bridge.Log.With().Str("db_section", "telegram").Logger())) tc.Store = store.NewStore(bridge.DB.Database, dbutil.ZeroLogger(bridge.Log.With().Str("db_section", "telegram").Logger()))
tg.Bridge = bridge tc.Bridge = bridge
tg.Bridge.Commands.(*commands.Processor).AddHandlers(cmdSyncChats, cmdEmojiPack, cmdUpgrade, cmdJoin) tc.Bridge.Commands.(*commands.Processor).AddHandlers(cmdSyncChats, cmdEmojiPack, cmdUpgrade, cmdJoin)
} }
func (tg *TelegramConnector) Start(ctx context.Context) error { func (tc *TelegramConnector) Start(ctx context.Context) error {
return tg.Store.Upgrade(ctx) return tc.Store.Upgrade(ctx)
} }
func (tc *TelegramConnector) LoadUserLogin(ctx context.Context, login *bridgev2.UserLogin) (err error) { 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 return
} }
func (tg *TelegramConnector) SetMaxFileSize(maxSize int64) { func (tc *TelegramConnector) SetMaxFileSize(maxSize int64) {
tg.maxFileSize = maxSize tc.maxFileSize = maxSize
} }
func (tg *TelegramConnector) GetName() bridgev2.BridgeName { func (tc *TelegramConnector) GetName() bridgev2.BridgeName {
return bridgev2.BridgeName{ return bridgev2.BridgeName{
DisplayName: "Telegram", DisplayName: "Telegram",
NetworkURL: "https://telegram.org/", NetworkURL: "https://telegram.org/",
+2 -2
View File
@@ -218,6 +218,6 @@ func (tc *TelegramConnector) Download(ctx context.Context, mediaID networkid.Med
return readyTransferer.ToDirectMediaResponse(ctx) return readyTransferer.ToDirectMediaResponse(ctx)
} }
func (tg *TelegramConnector) SetUseDirectMedia() { func (tc *TelegramConnector) SetUseDirectMedia() {
tg.useDirectMedia = true tc.useDirectMedia = true
} }
+105 -105
View File
@@ -97,7 +97,7 @@ func getMediaFilename(content *event.MessageEventContent) (filename string) {
return filename 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 { if msg.Portal == nil {
return nil return nil
} }
@@ -105,27 +105,27 @@ func (t *TelegramClient) HandleMatrixViewingChat(ctx context.Context, msg *bridg
// TODO sync topic parent space // TODO sync topic parent space
meta := msg.Portal.Metadata.(*PortalMetadata) meta := msg.Portal.Metadata.(*PortalMetadata)
if (topicID == 0 && !meta.FullSynced) || meta.LastSync.Add(24*time.Hour).Before(time.Now()) { 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{ EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventChatResync, Type: bridgev2.RemoteEventChatResync,
PortalKey: msg.Portal.PortalKey, 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 { if err != nil {
return err return err
} }
err = t.pollSponsoredMessage(ctx, msg.Portal) err = tc.pollSponsoredMessage(ctx, msg.Portal)
if err != nil { if err != nil {
return err return err
} }
return nil return nil
} }
func (t *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridgev2.Portal) error { func (tc *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridgev2.Portal) error {
if t.metadata.IsBot { if tc.metadata.IsBot {
return nil return nil
} }
meta := portal.Metadata.(*PortalMetadata) 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 { if time.Since(meta.SponsoredMessagePollTS.Time) < 5*time.Minute {
return nil 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 { if err != nil {
return fmt.Errorf("failed to get latest message for portal: %w", err) return fmt.Errorf("failed to get latest message for portal: %w", err)
} else if latestMessage != nil && latestMessage.ID == meta.LastMessageOnSponsorFetch { } else if latestMessage != nil && latestMessage.ID == meta.LastMessageOnSponsorFetch {
meta.SponsoredMessagePollTS = jsontime.UnixNow() meta.SponsoredMessagePollTS = jsontime.UnixNow()
return nil return nil
} }
accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id) accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id)
if err != nil { if err != nil {
return err 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}, Peer: &tg.InputPeerChannel{ChannelID: id, AccessHash: accessHash},
}) })
if err != nil { if err != nil {
@@ -179,7 +179,7 @@ func (t *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridg
msg = msgs.Messages[1] msg = msgs.Messages[1]
} }
meta.SponsoredMessageRandomID = msg.RandomID 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.MsgType = event.MsgNotice
content.EnsureHasHTML() content.EnsureHasHTML()
extra := map[string]any{ extra := map[string]any{
@@ -207,7 +207,7 @@ func (t *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridg
`<strong>%s: %s</strong><blockquote>%s</blockquote><p>Sponsored message%s - <a href="%s">%s</a></p>`, `<strong>%s: %s</strong><blockquote>%s</blockquote><p>Sponsored message%s - <a href="%s">%s</a></p>`,
prefix, html.EscapeString(msg.Title), content.FormattedBody, fromStr, msg.URL, msg.ButtonText, 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, Raw: extra,
Parsed: content, Parsed: content,
}, &bridgev2.MatrixSendExtra{Timestamp: time.Now()}) }, &bridgev2.MatrixSendExtra{Timestamp: time.Now()})
@@ -226,11 +226,11 @@ func (t *TelegramClient) pollSponsoredMessage(ctx context.Context, portal *bridg
return nil 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 upload tg.InputFileClass
var forceDocument bool var forceDocument bool
filename := getMediaFilename(content) 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() uploadFilename := f.Name()
if sticker && content.Info != nil && (content.Info.MimeType == "image/png" || content.Info.MimeType == "image/jpeg") { if sticker && content.Info != nil && (content.Info.MimeType == "image/png" || content.Info.MimeType == "image/jpeg") {
tempFile, err := os.CreateTemp("", "telegram-sticker-*.webp") 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 // We also have the image_as_file_pixels configuration threshold to
// prevent Telegram from compressing the file. // prevent Telegram from compressing the file.
aspectRatio := float64(max(cfg.Height, cfg.Width)) / float64(min(cfg.Height, cfg.Width)) 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) || info.Size() > int64(10*1024*1024) ||
aspectRatio > 20 || aspectRatio > 20 ||
cfg.Height+cfg.Width > 10000 cfg.Height+cfg.Width > 10000
@@ -298,7 +298,7 @@ func (t *TelegramClient) transferMediaToTelegram(ctx context.Context, content *e
content.Info.MimeType = "image/jpeg" 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 return
}) })
if err != nil { if err != nil {
@@ -349,7 +349,7 @@ func (t *TelegramClient) transferMediaToTelegram(ctx context.Context, content *e
}, nil }, nil
} }
func (t *TelegramClient) humaniseSendError(err error) bridgev2.MessageStatus { func (tc *TelegramClient) humaniseSendError(err error) bridgev2.MessageStatus {
status := bridgev2.WrapErrorInStatus(err). status := bridgev2.WrapErrorInStatus(err).
WithErrorReason(event.MessageStatusNetworkError). WithErrorReason(event.MessageStatusNetworkError).
WithMessage(humanise.Error(err)) WithMessage(humanise.Error(err))
@@ -381,7 +381,7 @@ func (t *TelegramClient) humaniseSendError(err error) bridgev2.MessageStatus {
WithStatus(event.MessageStatusFail) 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)) return networkid.RawTransactionID(strconv.FormatInt(rand.Int64(), 10))
} }
@@ -394,17 +394,17 @@ func parseRandomID(txnID networkid.RawTransactionID) int64 {
return rand.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 { if msg.Portal.RoomType == database.RoomTypeSpace {
return nil, fmt.Errorf("can't send messages to space portals") 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 // 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 { if err != nil {
return nil, err return nil, err
} }
peer, topicID, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) peer, topicID, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID)
if err != nil { if err != nil {
return nil, err 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 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 var replyTo tg.InputReplyToClass
if msg.ReplyTo != nil { if msg.ReplyTo != nil {
@@ -442,11 +442,11 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
var updates tg.UpdatesClass var updates tg.UpdatesClass
if msg.Event.Type == event.EventSticker { if msg.Event.Type == event.EventSticker {
var media tg.InputMediaClass var media tg.InputMediaClass
media, err = t.transferMediaToTelegram(ctx, msg.Content, true) media, err = tc.transferMediaToTelegram(ctx, msg.Content, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
updates, err = t.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{ updates, err = tc.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{
Peer: peer, Peer: peer,
Message: message, Message: message,
Entities: entities, Entities: entities,
@@ -457,7 +457,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
} else { } else {
switch msg.Content.MsgType { switch msg.Content.MsgType {
case event.MsgText, event.MsgNotice, event.MsgEmote: 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, Peer: peer,
NoWebpage: noWebpage, NoWebpage: noWebpage,
Message: message, Message: message,
@@ -467,11 +467,11 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
}) })
case event.MsgImage, event.MsgFile, event.MsgAudio, event.MsgVideo: case event.MsgImage, event.MsgFile, event.MsgAudio, event.MsgVideo:
var media tg.InputMediaClass var media tg.InputMediaClass
media, err = t.transferMediaToTelegram(ctx, msg.Content, false) media, err = tc.transferMediaToTelegram(ctx, msg.Content, false)
if err != nil { if err != nil {
return nil, err return nil, err
} }
updates, err = t.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{ updates, err = tc.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{
Peer: peer, Peer: peer,
Message: message, Message: message,
Entities: entities, Entities: entities,
@@ -491,7 +491,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
message = desc message = desc
} }
} }
updates, err = t.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{ updates, err = tc.client.API().MessagesSendMedia(ctx, &tg.MessagesSendMediaRequest{
Peer: peer, Peer: peer,
Message: message, Message: message,
Media: &tg.InputMediaGeoPoint{ Media: &tg.InputMediaGeoPoint{
@@ -506,7 +506,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
} }
if err != nil { if err != nil {
log.Err(err).Msg("failed to send message to Telegram") log.Err(err).Msg("failed to send message to Telegram")
return nil, t.humaniseSendError(err) return nil, tc.humaniseSendError(err)
} }
hasher := sha256.New() hasher := sha256.New()
@@ -581,7 +581,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
resp = &bridgev2.MatrixMessageResponse{ resp = &bridgev2.MatrixMessageResponse{
DB: &database.Message{ DB: &database.Message{
ID: messageID, ID: messageID,
SenderID: t.userID, SenderID: tc.userID,
Timestamp: timestamp, Timestamp: timestamp,
Metadata: &MessageMetadata{ Metadata: &MessageMetadata{
ContentHash: hash, ContentHash: hash,
@@ -593,7 +593,7 @@ func (t *TelegramClient) HandleMatrixMessage(ctx context.Context, msg *bridgev2.
return 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 { if msg.Portal.RoomType == database.RoomTypeSpace {
return fmt.Errorf("can't send messages to space portals") 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"). Str("handler", "matrix_edit").
Logger() Logger()
peer, _, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) peer, _, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -612,7 +612,7 @@ func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Mat
return err 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 var newContentURI id.ContentURIString
req := tg.MessagesEditMessageRequest{ 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") log.Info().Msg("media URI unchanged, skipping re-upload, just editing text")
} else { } else {
log.Info().Msg("media URI changed, re-uploading media") 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 { if err != nil {
return err return err
} }
@@ -639,9 +639,9 @@ func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Mat
} else if !msg.Content.MsgType.IsText() { } else if !msg.Content.MsgType.IsText() {
return fmt.Errorf("editing message type %s is unsupported", msg.Content.MsgType) 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 { if err != nil {
return t.humaniseSendError(err) return tc.humaniseSendError(err)
} }
hasher := sha256.New() hasher := sha256.New()
@@ -690,17 +690,17 @@ func (t *TelegramClient) HandleMatrixEdit(ctx context.Context, msg *bridgev2.Mat
return nil 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 { if msg.Portal.RoomType == database.RoomTypeSpace {
return fmt.Errorf("can't send messages to space portals") 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 return err
} else if _, messageID, err := ids.ParseMessageID(dbMsg.ID); err != nil { } else if _, messageID, err := ids.ParseMessageID(dbMsg.ID); err != nil {
return err 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 return err
} else { } else {
_, err := message.NewSender(t.client.API()). _, err := message.NewSender(tc.client.API()).
To(peer). To(peer).
Revoke(). Revoke().
Messages(ctx, messageID) 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 { if msg.Portal.RoomType == database.RoomTypeSpace {
return bridgev2.MatrixReactionPreResponse{}, fmt.Errorf("can't send messages to space portals") 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 resp bridgev2.MatrixReactionPreResponse
var maxReactions int var maxReactions int
maxReactions, err := t.getReactionLimit(ctx, t.userID) maxReactions, err := tc.getReactionLimit(ctx, tc.userID)
if err != nil { if err != nil {
return resp, err return resp, err
} }
@@ -728,7 +728,7 @@ func (t *TelegramClient) PreHandleMatrixReaction(ctx context.Context, msg *bridg
keyNoVariation := variationselector.Remove(msg.Content.RelatesTo.Key) keyNoVariation := variationselector.Remove(msg.Content.RelatesTo.Key)
emojiID := ids.MakeEmojiIDFromEmoticon(msg.Content.RelatesTo.Key) emojiID := ids.MakeEmojiIDFromEmoticon(msg.Content.RelatesTo.Key)
if strings.HasPrefix(msg.Content.RelatesTo.Key, "mxc://") { 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 return resp, err
} else if file == nil { } else if file == nil {
return resp, fmt.Errorf("reaction MXC URI %s does not correspond with any known Telegram files", msg.Content.RelatesTo.Key) 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 { } else {
emojiID = ids.MakeEmojiIDFromDocumentID(documentID) emojiID = ids.MakeEmojiIDFromDocumentID(documentID)
} }
} else if t.main.Config.AlwaysCustomEmojiReaction { } else if tc.main.Config.AlwaysCustomEmojiReaction {
// Always use the unicodemoji reaction if available // Always use the unicodemoji reaction if available
if documentID, ok := emojis.GetEmojiDocumentID(keyNoVariation); ok { if documentID, ok := emojis.GetEmojiDocumentID(keyNoVariation); ok {
log.Debug().Msg("Using custom emoji reaction") log.Debug().Msg("Using custom emoji reaction")
emojiID = ids.MakeEmojiIDFromDocumentID(documentID) 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) return resp, fmt.Errorf("failed to get available reactions: %w", err)
} else if _, ok := availableReactions[keyNoVariation]; ok { } else if _, ok := availableReactions[keyNoVariation]; ok {
log.Debug().Msg("Not using custom emoji reaction since the emoji is available") 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") log.Debug().Msg("Using custom emoji reaction")
emojiID = ids.MakeEmojiIDFromDocumentID(documentID) 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") log.Debug().Str("emoji_id", string(emojiID)).Msg("Pre-handled reaction")
return bridgev2.MatrixReactionPreResponse{ return bridgev2.MatrixReactionPreResponse{
SenderID: t.userID, SenderID: tc.userID,
EmojiID: emojiID, EmojiID: emojiID,
Emoji: variationselector.FullyQualify(msg.Content.RelatesTo.Key), Emoji: variationselector.FullyQualify(msg.Content.RelatesTo.Key),
MaxReactions: maxReactions, MaxReactions: maxReactions,
}, nil }, 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 { if documentID, emoticon, err := ids.ParseEmojiID(emojiID); err != nil {
return nil, err return nil, err
} else if documentID > 0 { } 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) { func (tc *TelegramClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (reaction *database.Reaction, err error) {
peer, _, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) peer, _, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -784,17 +784,17 @@ func (t *TelegramClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2
var newReactions []tg.ReactionClass var newReactions []tg.ReactionClass
for _, existing := range msg.ExistingReactionsToKeep { for _, existing := range msg.ExistingReactionsToKeep {
newReactions, err = t.appendEmojiID(newReactions, existing.EmojiID) newReactions, err = tc.appendEmojiID(newReactions, existing.EmojiID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
newReactions, err = t.appendEmojiID(newReactions, msg.PreHandleResp.EmojiID) newReactions, err = tc.appendEmojiID(newReactions, msg.PreHandleResp.EmojiID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
_, err = t.client.API().MessagesSendReaction(ctx, &tg.MessagesSendReactionRequest{ _, err = tc.client.API().MessagesSendReaction(ctx, &tg.MessagesSendReactionRequest{
Peer: peer, Peer: peer,
AddToRecent: true, AddToRecent: true,
MsgID: targetMessageID, MsgID: targetMessageID,
@@ -809,27 +809,27 @@ func (t *TelegramClient) HandleMatrixReaction(ctx context.Context, msg *bridgev2
return &database.Reaction{}, err 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 { if msg.Portal.RoomType == database.RoomTypeSpace {
return fmt.Errorf("can't send messages to space portals") 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 { if err != nil {
return err return err
} }
var newReactions []tg.ReactionClass 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 return err
} else if maxReactions > 1 { } 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 { if err != nil {
return err return err
} }
for _, existing := range existing { for _, existing := range existing {
if msg.TargetReaction.EmojiID != existing.EmojiID { if msg.TargetReaction.EmojiID != existing.EmojiID {
newReactions, err = t.appendEmojiID(newReactions, existing.EmojiID) newReactions, err = tc.appendEmojiID(newReactions, existing.EmojiID)
if err != nil { if err != nil {
return err return err
} }
@@ -841,7 +841,7 @@ func (t *TelegramClient) HandleMatrixReactionRemove(ctx context.Context, msg *br
if err != nil { if err != nil {
return err return err
} }
_, err = t.client.API().MessagesSendReaction(ctx, &tg.MessagesSendReactionRequest{ _, err = tc.client.API().MessagesSendReaction(ctx, &tg.MessagesSendReactionRequest{
Peer: peer, Peer: peer,
AddToRecent: true, AddToRecent: true,
MsgID: messageID, MsgID: messageID,
@@ -850,7 +850,7 @@ func (t *TelegramClient) HandleMatrixReactionRemove(ctx context.Context, msg *br
return err 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 { if msg.Portal.RoomType == database.RoomTypeSpace {
return nil return nil
} }
@@ -866,7 +866,7 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg
if msg.Portal.Metadata.(*PortalMetadata).IsForumGeneral { if msg.Portal.Metadata.(*PortalMetadata).IsForumGeneral {
topicID = 1 topicID = 1
} }
inputPeer, _, parseErr := t.inputPeerForPortalID(ctx, msg.Portal.ID) inputPeer, _, parseErr := tc.inputPeerForPortalID(ctx, msg.Portal.ID)
if parseErr != nil { if parseErr != nil {
return parseErr return parseErr
} }
@@ -874,7 +874,7 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg
var readMentionsErr, readReactionsErr, readMessagesErr error var readMentionsErr, readReactionsErr, readMessagesErr error
var wg sync.WaitGroup var wg sync.WaitGroup
isBot := t.metadata.IsBot isBot := tc.metadata.IsBot
// Read mentions // Read mentions
wg.Add(1) wg.Add(1)
@@ -883,7 +883,7 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg
if isBot { if isBot {
return return
} }
_, readMentionsErr = t.client.API().MessagesReadMentions(ctx, &tg.MessagesReadMentionsRequest{ _, readMentionsErr = tc.client.API().MessagesReadMentions(ctx, &tg.MessagesReadMentionsRequest{
Peer: inputPeer, Peer: inputPeer,
TopMsgID: topicID, TopMsgID: topicID,
}) })
@@ -896,7 +896,7 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg
if isBot { if isBot {
return return
} }
_, readMentionsErr = t.client.API().MessagesReadReactions(ctx, &tg.MessagesReadReactionsRequest{ _, readMentionsErr = tc.client.API().MessagesReadReactions(ctx, &tg.MessagesReadReactionsRequest{
Peer: inputPeer, Peer: inputPeer,
TopMsgID: topicID, TopMsgID: topicID,
}) })
@@ -913,7 +913,7 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg
message := msg.ExactMessage message := msg.ExactMessage
if message == nil { 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 { if readMessagesErr != nil {
return return
} else if message == nil { } else if message == nil {
@@ -929,29 +929,29 @@ func (t *TelegramClient) HandleMatrixReadReceipt(ctx context.Context, msg *bridg
switch peerType { switch peerType {
case ids.PeerTypeUser, ids.PeerTypeChat: case ids.PeerTypeUser, ids.PeerTypeChat:
_, readMessagesErr = t.client.API().MessagesReadHistory(ctx, &tg.MessagesReadHistoryRequest{ _, readMessagesErr = tc.client.API().MessagesReadHistory(ctx, &tg.MessagesReadHistoryRequest{
Peer: inputPeer, Peer: inputPeer,
MaxID: maxID, MaxID: maxID,
}) })
case ids.PeerTypeChannel: case ids.PeerTypeChannel:
var accessHash int64 var accessHash int64
accessHash, readMessagesErr = t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, portalID) accessHash, readMessagesErr = tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, portalID)
if readMessagesErr != nil { if readMessagesErr != nil {
return return
} }
_, readMessagesErr = t.client.API().ChannelsReadHistory(ctx, &tg.ChannelsReadHistoryRequest{ _, readMessagesErr = tc.client.API().ChannelsReadHistory(ctx, &tg.ChannelsReadHistoryRequest{
Channel: &tg.InputChannel{ChannelID: portalID, AccessHash: accessHash}, Channel: &tg.InputChannel{ChannelID: portalID, AccessHash: accessHash},
MaxID: maxID, MaxID: maxID,
}) })
meta := msg.Portal.Metadata.(*PortalMetadata) meta := msg.Portal.Metadata.(*PortalMetadata)
randomID := meta.SponsoredMessageRandomID randomID := meta.SponsoredMessageRandomID
if !t.metadata.IsBot && if !tc.metadata.IsBot &&
randomID != nil && randomID != nil &&
time.Since(meta.SponsoredMessagePollTS.Time) < 15*time.Minute && time.Since(meta.SponsoredMessagePollTS.Time) < 15*time.Minute &&
(meta.SponsoredMessageEventID == msg.EventID || msg.Receipt.Timestamp.After(meta.SponsoredMessagePollTS.Time)) && (meta.SponsoredMessageEventID == msg.EventID || msg.Receipt.Timestamp.After(meta.SponsoredMessagePollTS.Time)) &&
meta.sponsoredMessageSeen.Add(t.telegramUserID) { meta.sponsoredMessageSeen.Add(tc.telegramUserID) {
_, viewSponsoredErr := t.client.API().MessagesViewSponsoredMessage(ctx, randomID) _, viewSponsoredErr := tc.client.API().MessagesViewSponsoredMessage(ctx, randomID)
if viewSponsoredErr != nil { if viewSponsoredErr != nil {
log.Err(viewSponsoredErr).Msg("Failed to mark sponsored message as viewed after read receipt") log.Err(viewSponsoredErr).Msg("Failed to mark sponsored message as viewed after read receipt")
} else { } 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) // Poll for reactions (non-blocking to avoid deadlock when portal event buffer is disabled)
go func() { go func() {
err := t.maybePollForReactions(ctx, msg.Portal) err := tc.maybePollForReactions(ctx, msg.Portal)
if err != nil { if err != nil {
log.Err(err).Msg("failed to poll for reactions after read receipt") 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 { if err != nil {
log.Err(err).Msg("failed to poll for sponsored message after read receipt") 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 { 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") 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{ EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventChatResync, Type: bridgev2.RemoteEventChatResync,
PortalKey: msg.Portal.PortalKey, 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) 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 { if msg.Portal.RoomType == database.RoomTypeSpace {
return nil return nil
} }
inputPeer, topicID, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) inputPeer, topicID, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -1016,7 +1016,7 @@ func (t *TelegramClient) HandleMatrixTyping(ctx context.Context, msg *bridgev2.M
if !msg.IsTyping { if !msg.IsTyping {
action = &tg.SendMessageCancelAction{} action = &tg.SendMessageCancelAction{}
} }
_, err = t.client.API().MessagesSetTyping(ctx, &tg.MessagesSetTypingRequest{ _, err = tc.client.API().MessagesSetTyping(ctx, &tg.MessagesSetTypingRequest{
Peer: inputPeer, Peer: inputPeer,
TopMsgID: topicID, TopMsgID: topicID,
Action: action, Action: action,
@@ -1024,14 +1024,14 @@ func (t *TelegramClient) HandleMatrixTyping(ctx context.Context, msg *bridgev2.M
return err return err
} }
func (t *TelegramClient) HandleMatrixDisappearingTimer(ctx context.Context, msg *bridgev2.MatrixDisappearingTimer) (bool, error) { func (tc *TelegramClient) HandleMatrixDisappearingTimer(ctx context.Context, msg *bridgev2.MatrixDisappearingTimer) (bool, error) {
inputPeer, topicID, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) inputPeer, topicID, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID)
if err != nil { if err != nil {
return false, err return false, err
} else if topicID > 0 { } else if topicID > 0 {
return false, fmt.Errorf("topics can't have their own disappearing timer") 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, Peer: inputPeer,
Period: int(msg.Content.Timer.Seconds()), Period: int(msg.Content.Timer.Seconds()),
}) })
@@ -1044,8 +1044,8 @@ func (t *TelegramClient) HandleMatrixDisappearingTimer(ctx context.Context, msg
return err == nil, err return err == nil, err
} }
func (t *TelegramClient) HandleMute(ctx context.Context, msg *bridgev2.MatrixMute) error { func (tc *TelegramClient) HandleMute(ctx context.Context, msg *bridgev2.MatrixMute) error {
inputPeer, topicID, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) inputPeer, topicID, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID)
if err != nil { if err != nil {
return err return err
} }
@@ -1061,40 +1061,40 @@ func (t *TelegramClient) HandleMute(ctx context.Context, msg *bridgev2.MatrixMut
peer = &tg.InputNotifyPeer{Peer: inputPeer} peer = &tg.InputNotifyPeer{Peer: inputPeer}
} }
_, err = t.client.API().AccountUpdateNotifySettings(ctx, &tg.AccountUpdateNotifySettingsRequest{ _, err = tc.client.API().AccountUpdateNotifySettings(ctx, &tg.AccountUpdateNotifySettingsRequest{
Peer: peer, Peer: peer,
Settings: settings, Settings: settings,
}) })
return err return err
} }
func (t *TelegramClient) HandleRoomTag(ctx context.Context, msg *bridgev2.MatrixRoomTag) error { func (tc *TelegramClient) HandleRoomTag(ctx context.Context, msg *bridgev2.MatrixRoomTag) error {
inputPeer, topicID, err := t.inputPeerForPortalID(ctx, msg.Portal.ID) inputPeer, topicID, err := tc.inputPeerForPortalID(ctx, msg.Portal.ID)
if err != nil { if err != nil {
return err return err
} else if topicID > 0 { } else if topicID > 0 {
return fmt.Errorf("topics can't be pinned for yourself") 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), Pinned: slices.Contains(maps.Keys(msg.Content.Tags), event.RoomTagFavourite),
Peer: &tg.InputDialogPeer{Peer: inputPeer}, Peer: &tg.InputDialogPeer{Peer: inputPeer},
}) })
return err 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) peerType, id, topicID, err := ids.ParsePortalID(chat.Portal.ID)
if err != nil { if err != nil {
return err return err
} }
switch peerType { switch peerType {
case ids.PeerTypeUser: case ids.PeerTypeUser:
accessHash, err := t.ScopedStore.GetAccessHash(ctx, peerType, id) accessHash, err := tc.ScopedStore.GetAccessHash(ctx, peerType, id)
if err != nil { if err != nil {
return err 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}, Peer: &tg.InputPeerUser{UserID: id, AccessHash: accessHash},
JustClear: !chat.Content.DeleteForEveryone, JustClear: !chat.Content.DeleteForEveryone,
Revoke: chat.Content.DeleteForEveryone, Revoke: chat.Content.DeleteForEveryone,
@@ -1107,7 +1107,7 @@ func (t *TelegramClient) HandleMatrixDeleteChat(ctx context.Context, chat *bridg
if !chat.Content.DeleteForEveryone { if !chat.Content.DeleteForEveryone {
return fmt.Errorf("chats can only be deleted for everyone or left") 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 { if err != nil {
return err return err
} }
@@ -1119,12 +1119,12 @@ func (t *TelegramClient) HandleMatrixDeleteChat(ctx context.Context, chat *bridg
if !chat.Content.DeleteForEveryone { if !chat.Content.DeleteForEveryone {
return fmt.Errorf("channels can only be deleted for everyone or left") 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 { if err != nil {
return err return err
} }
if topicID > 0 { if topicID > 0 {
_, err = t.client.API().MessagesDeleteTopicHistory(ctx, &tg.MessagesDeleteTopicHistoryRequest{ _, err = tc.client.API().MessagesDeleteTopicHistory(ctx, &tg.MessagesDeleteTopicHistoryRequest{
Peer: &tg.InputPeerChannel{ Peer: &tg.InputPeerChannel{
ChannelID: id, ChannelID: id,
AccessHash: accessHash, AccessHash: accessHash,
@@ -1132,7 +1132,7 @@ func (t *TelegramClient) HandleMatrixDeleteChat(ctx context.Context, chat *bridg
TopMsgID: topicID, TopMsgID: topicID,
}) })
} else { } else {
_, err = t.client.API().ChannelsDeleteChannel(ctx, &tg.InputChannel{ _, err = tc.client.API().ChannelsDeleteChannel(ctx, &tg.InputChannel{
ChannelID: id, ChannelID: id,
AccessHash: accessHash, AccessHash: accessHash,
}) })
@@ -1147,7 +1147,7 @@ func (t *TelegramClient) HandleMatrixDeleteChat(ctx context.Context, chat *bridg
return nil 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) peerType, id, topicID, err := ids.ParsePortalID(msg.Portal.ID)
if err != nil { if err != nil {
return false, err return false, err
@@ -1155,7 +1155,7 @@ func (t *TelegramClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2
switch peerType { switch peerType {
case ids.PeerTypeChat: case ids.PeerTypeChat:
_, err = t.client.API().MessagesEditChatTitle(ctx, &tg.MessagesEditChatTitleRequest{ _, err = tc.client.API().MessagesEditChatTitle(ctx, &tg.MessagesEditChatTitleRequest{
ChatID: id, ChatID: id,
Title: msg.Content.Name, Title: msg.Content.Name,
}) })
@@ -1164,12 +1164,12 @@ func (t *TelegramClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2
} }
return true, nil return true, nil
case ids.PeerTypeChannel: case ids.PeerTypeChannel:
accessHash, err := t.ScopedStore.GetAccessHash(ctx, peerType, id) accessHash, err := tc.ScopedStore.GetAccessHash(ctx, peerType, id)
if err != nil { if err != nil {
return false, err return false, err
} }
if topicID > 0 { if topicID > 0 {
_, err = t.client.API().MessagesEditForumTopic(ctx, &tg.MessagesEditForumTopicRequest{ _, err = tc.client.API().MessagesEditForumTopic(ctx, &tg.MessagesEditForumTopicRequest{
Peer: &tg.InputPeerChannel{ Peer: &tg.InputPeerChannel{
ChannelID: id, ChannelID: id,
AccessHash: accessHash, AccessHash: accessHash,
@@ -1178,7 +1178,7 @@ func (t *TelegramClient) HandleMatrixRoomName(ctx context.Context, msg *bridgev2
Title: msg.Content.Name, Title: msg.Content.Name,
}) })
} else { } else {
_, err = t.client.API().ChannelsEditTitle(ctx, &tg.ChannelsEditTitleRequest{ _, err = tc.client.API().ChannelsEditTitle(ctx, &tg.ChannelsEditTitleRequest{
Channel: &tg.InputChannel{ Channel: &tg.InputChannel{
ChannelID: id, ChannelID: id,
AccessHash: accessHash, 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) peerType, id, topicID, err := ids.ParsePortalID(msg.Portal.ID)
if err != nil { if err != nil {
return false, err return false, err
@@ -1211,11 +1211,11 @@ func (t *TelegramClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridge
if msg.Content.URL == "" { if msg.Content.URL == "" {
photo = &tg.InputChatPhotoEmpty{} photo = &tg.InputChatPhotoEmpty{}
} else { } 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 { if err != nil {
return false, fmt.Errorf("failed to download avatar: %w", err) 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 { if err != nil {
return false, fmt.Errorf("failed to upload avatar: %w", err) 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 { switch peerType {
case ids.PeerTypeChat: case ids.PeerTypeChat:
_, err = t.client.API().MessagesEditChatPhoto(ctx, &tg.MessagesEditChatPhotoRequest{ _, err = tc.client.API().MessagesEditChatPhoto(ctx, &tg.MessagesEditChatPhotoRequest{
ChatID: id, ChatID: id,
Photo: photo, Photo: photo,
}) })
@@ -1234,11 +1234,11 @@ func (t *TelegramClient) HandleMatrixRoomAvatar(ctx context.Context, msg *bridge
// TODO update portal metadata // TODO update portal metadata
return true, nil return true, nil
case ids.PeerTypeChannel: case ids.PeerTypeChannel:
accessHash, err := t.ScopedStore.GetAccessHash(ctx, peerType, id) accessHash, err := tc.ScopedStore.GetAccessHash(ctx, peerType, id)
if err != nil { if err != nil {
return false, err return false, err
} }
_, err = t.client.API().ChannelsEditPhoto(ctx, &tg.ChannelsEditPhotoRequest{ _, err = tc.client.API().ChannelsEditPhoto(ctx, &tg.ChannelsEditPhotoRequest{
Channel: &tg.InputChannel{ Channel: &tg.InputChannel{
ChannelID: id, ChannelID: id,
AccessHash: accessHash, AccessHash: accessHash,
File diff suppressed because it is too large Load Diff
+8 -8
View File
@@ -23,18 +23,18 @@ import (
"go.mau.fi/mautrix-telegram/pkg/gotd/tg" "go.mau.fi/mautrix-telegram/pkg/gotd/tg"
) )
func (t *TelegramClient) makePortalKeyFromPeer(peer tg.PeerClass, topicID int) networkid.PortalKey { func (tc *TelegramClient) makePortalKeyFromPeer(peer tg.PeerClass, topicID int) networkid.PortalKey {
key := ids.InternalPeerToPortalKey(peer, topicID, t.loginID) key := ids.InternalPeerToPortalKey(peer, topicID, tc.loginID)
if t.main.Bridge.Config.SplitPortals { if tc.main.Bridge.Config.SplitPortals {
key.Receiver = t.userLogin.ID key.Receiver = tc.userLogin.ID
} }
return key return key
} }
func (t *TelegramClient) makePortalKeyFromID(peerType ids.PeerType, chatID int64, topicID int) networkid.PortalKey { func (tc *TelegramClient) makePortalKeyFromID(peerType ids.PeerType, chatID int64, topicID int) networkid.PortalKey {
key := ids.InternalMakePortalKey(peerType, chatID, topicID, t.loginID) key := ids.InternalMakePortalKey(peerType, chatID, topicID, tc.loginID)
if t.main.Bridge.Config.SplitPortals { if tc.main.Bridge.Config.SplitPortals {
key.Receiver = t.userLogin.ID key.Receiver = tc.userLogin.ID
} }
return key return key
} }
+27 -27
View File
@@ -49,8 +49,8 @@ import (
"go.mau.fi/mautrix-telegram/pkg/gotd/tgerr" "go.mau.fi/mautrix-telegram/pkg/gotd/tgerr"
) )
func (t *TelegramClient) fnListEmojiPacks(ce *commands.Event) { func (tc *TelegramClient) fnListEmojiPacks(ce *commands.Event) {
resp, err := t.client.API().MessagesGetAllStickers(ce.Ctx, 0) resp, err := tc.client.API().MessagesGetAllStickers(ce.Ctx, 0)
if err != nil { if err != nil {
ce.Reply("Failed to list image packs: %v", err) ce.Reply("Failed to list image packs: %v", err)
return return
@@ -76,7 +76,7 @@ func (t *TelegramClient) fnListEmojiPacks(ce *commands.Event) {
ce.Reply("Your packs:\n\n%s", strings.Join(lines, "\n")) 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], "!") { if len(ce.Args) < 3 || !strings.HasPrefix(ce.Args[1], "!") {
ce.Reply("Usage: `$cmdprefix emoji-pack upload <telegram shortcode> <room ID> <state key>`") ce.Reply("Usage: `$cmdprefix emoji-pack upload <telegram shortcode> <room ID> <state key>`")
return return
@@ -94,7 +94,7 @@ func (t *TelegramClient) fnUploadEmojiPack(ce *commands.Event) {
tgPackShortcode := ce.Args[0] tgPackShortcode := ce.Args[0]
roomID := id.RoomID(ce.Args[1]) roomID := id.RoomID(ce.Args[1])
packStateKey := strings.Join(ce.Args[2:], " ") 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 { if err != nil {
ce.Reply("Failed to join room: %v", err) ce.Reply("Failed to join room: %v", err)
return return
@@ -111,7 +111,7 @@ func (t *TelegramClient) fnUploadEmojiPack(ce *commands.Event) {
} }
evtID := ce.React("\u23f3\ufe0f") evtID := ce.React("\u23f3\ufe0f")
defer redactReaction(ce, evtID) 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 { if err != nil {
ce.Reply("Failed to synchronize emoji pack: %v", err) ce.Reply("Failed to synchronize emoji pack: %v", err)
return 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, ctx context.Context, shortcode string, img *event.ImagePackImage, emoji bool,
) (*tg.InputStickerSetItem, func(int64) error, error) { ) (*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 { if err != nil {
return nil, nil, fmt.Errorf("failed to download %s (%s): %w", shortcode, img.URL, err) 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 { if err != nil {
return nil, nil, fmt.Errorf("failed to normalize image for %s: %w", shortcode, err) 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 { if err != nil {
return nil, nil, fmt.Errorf("failed to reupload %s: %w", shortcode, err) 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{ Media: &tg.InputMediaUploadedDocument{
File: up, File: up,
ForceFile: true, ForceFile: true,
@@ -270,7 +270,7 @@ func (t *TelegramClient) synchronizeEmoji(
if realDocID == 0 { if realDocID == 0 {
return fmt.Errorf("failed to get real document ID for %s/%d", shortcode, fakeDoc.ID) 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)), LocationID: store.TelegramFileLocationID(strconv.FormatInt(realDocID, 10)),
MXC: img.URL, MXC: img.URL,
MIMEType: img.Info.MimeType, MIMEType: img.Info.MimeType,
@@ -315,8 +315,8 @@ func extractNewDocID(oldSet tg.MessagesStickerSetClass, newSetBox tg.MessagesSti
return found return found
} }
func (t *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands.Event, pack *event.ImagePackEventContent, packShortcode string) (string, error) { func (tc *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands.Event, pack *event.ImagePackEventContent, packShortcode string) (string, error) {
resp, err := t.client.API().StickersCheckShortName(ctx, packShortcode) resp, err := tc.client.API().StickersCheckShortName(ctx, packShortcode)
if err != nil && !tgerr.Is(err, tg.ErrShortNameOccupied) { if err != nil && !tgerr.Is(err, tg.ErrShortNameOccupied) {
return "", fmt.Errorf("failed to check if shortcode is available: %w", err) 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 { if img == nil {
return "", fmt.Errorf("pack must contain at least one image") 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 { if err != nil {
return "", fmt.Errorf("failed to synchronize emoji %s: %w", shortcode, err) 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, Emojis: isEmojiPack,
UserID: &tg.InputUserSelf{}, UserID: &tg.InputUserSelf{},
Title: cmp.Or(pack.Metadata.DisplayName, packShortcode), 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) return "", fmt.Errorf("failed to cache document ID for new pack: %w", err)
} }
} else { } else {
rawSet, err = t.client.API().MessagesGetStickerSet(ctx, &tg.MessagesGetStickerSetRequest{ rawSet, err = tc.client.API().MessagesGetStickerSet(ctx, &tg.MessagesGetStickerSetRequest{
Stickerset: &tg.InputStickerSetShortName{ShortName: packShortcode}, Stickerset: &tg.InputStickerSetShortName{ShortName: packShortcode},
}) })
if err != nil { 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)) deletedMXCs := make(map[id.ContentURIString]*tg.InputDocument, len(set.Documents))
existingMXCs := make(exmaps.Set[id.ContentURIString], len(set.Documents)) existingMXCs := make(exmaps.Set[id.ContentURIString], len(set.Documents))
for _, doc := range 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 { if err != nil {
return "", fmt.Errorf("failed to get cached file for doc %d: %w", doc.GetID(), err) return "", fmt.Errorf("failed to get cached file for doc %d: %w", doc.GetID(), err)
} else if file != nil { } else if file != nil {
@@ -386,12 +386,12 @@ func (t *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands.
continue continue
} }
existingMXCs.Add(img.URL) 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 { if err != nil {
ce.Reply("Failed to reupload %s: %v", shortcode, err) ce.Reply("Failed to reupload %s: %v", shortcode, err)
continue continue
} }
rawNewSet, err := t.client.API().StickersAddStickerToSet(ctx, &tg.StickersAddStickerToSetRequest{ rawNewSet, err := tc.client.API().StickersAddStickerToSet(ctx, &tg.StickersAddStickerToSetRequest{
Stickerset: inputSet, Stickerset: inputSet,
Sticker: *item, Sticker: *item,
}) })
@@ -409,7 +409,7 @@ func (t *TelegramClient) synchronizeEmojiPack(ctx context.Context, ce *commands.
rawSet = rawNewSet rawSet = rawNewSet
} }
for mxc, inputDoc := range deletedMXCs { for mxc, inputDoc := range deletedMXCs {
_, err = t.client.API().StickersRemoveStickerFromSet(ctx, inputDoc) _, err = tc.client.API().StickersRemoveStickerFromSet(ctx, inputDoc)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to remove %s/%d from set: %w", mxc, inputDoc.ID, err) 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) }, nil)
} }
func (t *TelegramClient) fnDownloadEmojiPack(ce *commands.Event) { func (tc *TelegramClient) fnDownloadEmojiPack(ce *commands.Event) {
if len(ce.Args) == 0 { if len(ce.Args) == 0 {
ce.Reply("Usage: `$cmdprefix emoji-pack download <pack shortcode or link>`") ce.Reply("Usage: `$cmdprefix emoji-pack download <pack shortcode or link>`")
return return
} }
spaceRoom, err := t.userLogin.GetSpaceRoom(ce.Ctx) spaceRoom, err := tc.userLogin.GetSpaceRoom(ce.Ctx)
if err != nil { if err != nil {
ce.Reply("Failed to get space room: %v", err) ce.Reply("Failed to get space room: %v", err)
return return
@@ -457,7 +457,7 @@ func (t *TelegramClient) fnDownloadEmojiPack(ce *commands.Event) {
ce.Reply("Invalid pack shortcode or link.") ce.Reply("Invalid pack shortcode or link.")
return 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 { if err != nil {
ce.Reply("Failed to get sticker set: %v", err) ce.Reply("Failed to get sticker set: %v", err)
return return
@@ -496,11 +496,11 @@ func (t *TelegramClient) fnDownloadEmojiPack(ce *commands.Event) {
evtID := ce.React("\u23f3\ufe0f") evtID := ce.React("\u23f3\ufe0f")
defer redactReaction(ce, evtID) defer redactReaction(ce, evtID)
for i, rawDoc := range set.Documents { for i, rawDoc := range set.Documents {
mxc, _, info, err := media.NewTransferer(t.client.API()). mxc, _, info, err := media.NewTransferer(tc.client.API()).
WithStickerConfig(t.main.Config.AnimatedSticker). WithStickerConfig(tc.main.Config.AnimatedSticker).
WithForceWebmStickerConvert(set.Set.Emojis). WithForceWebmStickerConvert(set.Set.Emojis).
WithDocument(rawDoc, false). 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 { if err != nil {
ce.Log.Err(err).Msg("Failed to transfer image in pack") ce.Log.Err(err).Msg("Failed to transfer image in pack")
ce.Reply("Failed to transfer document `%d`: %v", rawDoc.GetID(), err) ce.Reply("Failed to transfer document `%d`: %v", rawDoc.GetID(), err)
@@ -530,13 +530,13 @@ func (t *TelegramClient) fnDownloadEmojiPack(ce *commands.Event) {
Info: info, 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 { if err != nil {
ce.Reply("Failed to send image pack to space: %v", err) ce.Reply("Failed to send image pack to space: %v", err)
} else { } else {
ce.Reply( ce.Reply(
"Successfully bridged image pack to %s", "Successfully bridged image pack to %s",
format.MarkdownLink("your personal filtering space", format.MarkdownLink("your personal filtering space",
spaceRoom.URI(t.main.Bridge.Matrix.ServerName()).MatrixToURL())) spaceRoom.URI(tc.main.Bridge.Matrix.ServerName()).MatrixToURL()))
} }
} }
+3 -3
View File
@@ -64,7 +64,7 @@ var (
} }
) )
func (tg *TelegramConnector) GetLoginFlows() []bridgev2.LoginFlow { func (tc *TelegramConnector) GetLoginFlows() []bridgev2.LoginFlow {
return []bridgev2.LoginFlow{ return []bridgev2.LoginFlow{
{ {
Name: "Phone Number", 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{ bl := &baseLogin{
user: user, user: user,
main: tg, main: tc,
flowID: flowID, flowID: flowID,
} }
switch flowID { switch flowID {
+1 -1
View File
@@ -31,7 +31,7 @@ import (
"go.mau.fi/mautrix-telegram/pkg/gotd/session" "go.mau.fi/mautrix-telegram/pkg/gotd/session"
) )
func (tg *TelegramConnector) GetDBMetaTypes() database.MetaTypes { func (tc *TelegramConnector) GetDBMetaTypes() database.MetaTypes {
return database.MetaTypes{ return database.MetaTypes{
Ghost: func() any { return &GhostMetadata{} }, Ghost: func() any { return &GhostMetadata{} },
Portal: func() any { return &PortalMetadata{} }, Portal: func() any { return &PortalMetadata{} },
+19 -19
View File
@@ -256,13 +256,13 @@ var PushMessageFormats = map[string]string{
var FullSyncOnConnectBackground = false 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) data, _ := params.ExtraData.(*PushNotificationData)
var relatedPortal *bridgev2.Portal var relatedPortal *bridgev2.Portal
var sender *bridgev2.Ghost var sender *bridgev2.Ghost
var messageID networkid.MessageID var messageID networkid.MessageID
var messageText, notificationText, notificationTitle string 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 { if data.Aps != nil {
notificationTitle = data.Aps.Alert.Title notificationTitle = data.Aps.Alert.Title
notificationText = data.Aps.Alert.Body notificationText = data.Aps.Alert.Body
@@ -282,23 +282,23 @@ func (t *TelegramClient) ConnectBackground(ctx context.Context, params *bridgev2
} }
var err error var err error
if data.Custom.ChannelID != 0 { 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 { } 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 { } 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 { if err != nil {
return fmt.Errorf("failed to get related portal: %w", err) return fmt.Errorf("failed to get related portal: %w", err)
} }
if data.Custom.ChatFromBroadcastID != 0 { 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 { } 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 { } 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 { } 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 { if err != nil {
return fmt.Errorf("failed to get sender: %w", err) return fmt.Errorf("failed to get sender: %w", err)
@@ -317,8 +317,8 @@ func (t *TelegramClient) ConnectBackground(ctx context.Context, params *bridgev2
}) })
} }
if FullSyncOnConnectBackground { if FullSyncOnConnectBackground {
t.Connect(ctx) tc.Connect(ctx)
defer t.Disconnect() defer tc.Disconnect()
// TODO is it possible to safely only sync one chat? // TODO is it possible to safely only sync one chat?
select { select {
case <-time.After(20 * time.Second): case <-time.After(20 * time.Second):
@@ -328,7 +328,7 @@ func (t *TelegramClient) ConnectBackground(ctx context.Context, params *bridgev2
return nil 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") val := gjson.GetBytes(data, "p")
if val.Type != gjson.String { if val.Type != gjson.String {
return "", nil, fmt.Errorf("missing or invalid p field") 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 { if err != nil {
return "", nil, fmt.Errorf("failed to decode auth key and message ID: %w", err) 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 { if err != nil {
return "", nil, fmt.Errorf("failed to get users with logins: %w", err) 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 var userLoginID networkid.UserLoginID
UserLoop: UserLoop:
for _, userID := range userIDs { for _, userID := range userIDs {
user, err := tg.Bridge.GetExistingUserByMXID(ctx, userID) user, err := tc.Bridge.GetExistingUserByMXID(ctx, userID)
if err != nil { if err != nil {
return "", nil, fmt.Errorf("failed to get user %s: %w", userID, err) return "", nil, fmt.Errorf("failed to get user %s: %w", userID, err)
} }
@@ -398,11 +398,11 @@ UserLoop:
return userLoginID, &pmd, nil return userLoginID, &pmd, nil
} }
func (t *TelegramClient) RegisterPushNotifications(ctx context.Context, pushType bridgev2.PushType, token string) error { func (tc *TelegramClient) RegisterPushNotifications(ctx context.Context, pushType bridgev2.PushType, token string) error {
meta := t.metadata meta := tc.metadata
if meta.PushEncryptionKey == nil { if meta.PushEncryptionKey == nil {
meta.PushEncryptionKey = random.Bytes(256) meta.PushEncryptionKey = random.Bytes(256)
err := t.userLogin.Save(ctx) err := tc.userLogin.Save(ctx)
if err != nil { if err != nil {
return fmt.Errorf("failed to save push encryption key: %w", err) return fmt.Errorf("failed to save push encryption key: %w", err)
} }
@@ -418,7 +418,7 @@ func (t *TelegramClient) RegisterPushNotifications(ctx context.Context, pushType
default: default:
return fmt.Errorf("unsupported push type %s", pushType) 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, NoMuted: true,
TokenType: tokenType, TokenType: tokenType,
Token: token, Token: token,
@@ -429,6 +429,6 @@ func (t *TelegramClient) RegisterPushNotifications(ctx context.Context, pushType
return err return err
} }
func (t *TelegramClient) GetPushConfigs() *bridgev2.PushConfig { func (tc *TelegramClient) GetPushConfigs() *bridgev2.PushConfig {
return &bridgev2.PushConfig{Native: true} return &bridgev2.PushConfig{Native: true}
} }
+34 -34
View File
@@ -32,7 +32,7 @@ import (
"go.mau.fi/mautrix-telegram/pkg/gotd/tg" "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() log := zerolog.Ctx(ctx).With().Str("fn", "computeReactionsList").Logger()
var totalCount int var totalCount int
for _, r := range msgReactions.Results { for _, r := range msgReactions.Results {
@@ -54,18 +54,18 @@ func (t *TelegramClient) computeReactionsList(ctx context.Context, peer tg.PeerC
if len(reactionsList) < totalCount { if len(reactionsList) < totalCount {
if user, ok := peer.(*tg.PeerUser); ok { if user, ok := peer.(*tg.PeerUser); ok {
reactionsList = splitDMReactionCounts(msgReactions.Results, user.UserID, t.telegramUserID) reactionsList = splitDMReactionCounts(msgReactions.Results, user.UserID, tc.telegramUserID)
} else if t.metadata.IsBot { } else if tc.metadata.IsBot {
// Can't fetch exact reaction senders as a bot // Can't fetch exact reaction senders as a bot
return return
// TODO remove redundant peer roundtrip, just add a peer -> input peer helper // 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) return nil, false, nil, fmt.Errorf("failed to get input peer: %w", err)
} else { } else {
// TODO should calls to this be limited? // TODO should calls to this be limited?
reactions, err := APICallWithUpdates(ctx, t, func() (*tg.MessagesMessageReactionsList, error) { reactions, err := APICallWithUpdates(ctx, tc, func() (*tg.MessagesMessageReactionsList, error) {
return t.client.API().MessagesGetMessageReactionsList(ctx, &tg.MessagesGetMessageReactionsListRequest{ return tc.client.API().MessagesGetMessageReactionsList(ctx, &tg.MessagesGetMessageReactionsListRequest{
Peer: peer, ID: msgID, Limit: 100, 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 return reactionsList, len(reactionsList) == totalCount, customEmojis, err
} }
@@ -105,8 +105,8 @@ func computeEmojiAndID(reaction tg.ReactionClass, customEmojis map[networkid.Emo
return return
} }
func (t *TelegramClient) prepareReactionSync(ctx context.Context, peer tg.PeerClass, msgID int, reactions tg.MessageReactions) (*bridgev2.ReactionSyncData, error) { func (tc *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) reactionsList, isFull, customEmojis, err := tc.computeReactionsList(ctx, peer, msgID, reactions)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to compute reactions: %w", err) 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) { switch senderPeer := reaction.PeerID.(type) {
case *tg.PeerUser: case *tg.PeerUser:
userID = ids.MakeUserID(senderPeer.UserID) userID = ids.MakeUserID(senderPeer.UserID)
eventSender = t.senderForUserID(senderPeer.UserID) eventSender = tc.senderForUserID(senderPeer.UserID)
case *tg.PeerChannel: case *tg.PeerChannel:
userID = ids.MakeChannelUserID(senderPeer.ChannelID) userID = ids.MakeChannelUserID(senderPeer.ChannelID)
eventSender = bridgev2.EventSender{ eventSender = bridgev2.EventSender{
Sender: userID, Sender: userID,
IsFromMe: reaction.My && t.main.Bridge.Config.SplitPortals, IsFromMe: reaction.My && tc.main.Bridge.Config.SplitPortals,
} }
default: default:
log.Debug().Type("peer_type", reaction.PeerID).Msg("Ignoring reaction from non-user peer") log.Debug().Type("peer_type", reaction.PeerID).Msg("Ignoring reaction from non-user peer")
continue continue
} }
reactionLimit, err := t.getReactionLimit(ctx, userID) reactionLimit, err := tc.getReactionLimit(ctx, userID)
if err != nil { if err != nil {
reactionLimit = 1 reactionLimit = 1
log.Err(err).Str("id", string(userID)).Msg("failed to get reaction limit") 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 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(). ctx = zerolog.Ctx(ctx).With().
Str("handler", "handle_telegram_reactions"). Str("handler", "handle_telegram_reactions").
Int("message_id", msgID). Int("message_id", msgID).
Logger().WithContext(ctx) Logger().WithContext(ctx)
data, err := t.prepareReactionSync(ctx, peer, msgID, reactions) data, err := tc.prepareReactionSync(ctx, peer, msgID, reactions)
if err != nil { if err != nil {
return err 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{ EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventReactionSync, Type: bridgev2.RemoteEventReactionSync,
LogContext: func(c zerolog.Context) zerolog.Context { LogContext: func(c zerolog.Context) zerolog.Context {
return c.Int("message_id", msgID) return c.Int("message_id", msgID)
}, },
PortalKey: t.makePortalKeyFromPeer(peer, topicID), PortalKey: tc.makePortalKeyFromPeer(peer, topicID),
}, },
TargetMessage: ids.MakeMessageID(peer, msgID), TargetMessage: ids.MakeMessageID(peer, msgID),
Reactions: data, Reactions: data,
@@ -198,13 +198,13 @@ func splitDMReactionCounts(res []tg.ReactionCount, theirUserID, myUserID int64)
return return
} }
func (t *TelegramClient) getReactionLimit(ctx context.Context, sender networkid.UserID) (limit int, err error) { func (tc *TelegramClient) getReactionLimit(ctx context.Context, sender networkid.UserID) (limit int, err error) {
config, err := t.getAppConfigCached(ctx) config, err := tc.getAppConfigCached(ctx)
if err != nil { if err != nil {
return 0, err return 0, err
} }
ghost, err := t.main.Bridge.GetGhostByID(ctx, sender) ghost, err := tc.main.Bridge.GetGhostByID(ctx, sender)
if err != nil { if err != nil {
return 0, err 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 // 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 return nil
} }
t.prevReactionPollLock.Lock() tc.prevReactionPollLock.Lock()
prev, ok := t.prevReactionPoll[portal.PortalKey] prev, ok := tc.prevReactionPoll[portal.PortalKey]
if ok && time.Since(prev) > 20*time.Second { if ok && time.Since(prev) > 20*time.Second {
ok = false ok = false
t.prevReactionPoll[portal.PortalKey] = time.Now() tc.prevReactionPoll[portal.PortalKey] = time.Now()
} }
t.prevReactionPollLock.Unlock() tc.prevReactionPollLock.Unlock()
if ok { if ok {
return nil 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 { func (tc *TelegramClient) pollForReactions(ctx context.Context, portalKey networkid.PortalKey) error {
inputPeer, _, parseErr := t.inputPeerForPortalID(ctx, portalKey.ID) inputPeer, _, parseErr := tc.inputPeerForPortalID(ctx, portalKey.ID)
if parseErr != nil { if parseErr != nil {
return parseErr return parseErr
} }
@@ -254,7 +254,7 @@ func (t *TelegramClient) pollForReactions(ctx context.Context, portalKey network
log.Debug().Msg("Polling reactions for recent messages") 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 { if err != nil {
return err return err
} }
@@ -267,8 +267,8 @@ func (t *TelegramClient) pollForReactions(ctx context.Context, portalKey network
} }
} }
updates, err := APICallWithUpdates(ctx, t, func() (*tg.Updates, error) { updates, err := APICallWithUpdates(ctx, tc, func() (*tg.Updates, error) {
u, err := t.client.API().MessagesGetMessagesReactions(ctx, &tg.MessagesGetMessagesReactionsRequest{ u, err := tc.client.API().MessagesGetMessagesReactions(ctx, &tg.MessagesGetMessagesReactionsRequest{
Peer: inputPeer, Peer: inputPeer,
ID: messageIDs, 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") log.Warn().Type("update_type", update).Msg("Unexpected update type in get reactions response")
continue 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 { if err != nil {
return fmt.Errorf("failed to get message from database: %w", err) return fmt.Errorf("failed to get message from database: %w", err)
} else if dbMsg == nil { } else if dbMsg == nil {
return fmt.Errorf("message not found in database: %w", err) 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 { if err != nil {
return err return err
} }
res := t.main.Bridge.QueueRemoteEvent(t.userLogin, &simplevent.ReactionSync{ res := tc.main.Bridge.QueueRemoteEvent(tc.userLogin, &simplevent.ReactionSync{
EventMeta: simplevent.EventMeta{ EventMeta: simplevent.EventMeta{
Type: bridgev2.RemoteEventReactionSync, Type: bridgev2.RemoteEventReactionSync,
LogContext: func(c zerolog.Context) zerolog.Context { LogContext: func(c zerolog.Context) zerolog.Context {
+51 -51
View File
@@ -42,32 +42,32 @@ var (
_ bridgev2.GroupCreatingNetworkAPI = (*TelegramClient)(nil) _ 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()) 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) 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) return nil, fmt.Errorf("failed to get user info: %w", err)
} else { } 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{ return &bridgev2.ResolveIdentifierResponse{
Ghost: ghost, Ghost: ghost,
UserID: ids.MakeUserID(user.GetID()), UserID: ids.MakeUserID(user.GetID()),
UserInfo: info, UserInfo: info,
Chat: &bridgev2.CreateChatResponse{ 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) { func (tc *TelegramClient) resolveUserID(ctx context.Context, userID int64) (resp *bridgev2.ResolveIdentifierResponse, err error) {
_, err = t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, userID) _, err = tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, userID)
if errors.Is(err, store.ErrNoAccessHash) { 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 { if usernameErr != nil {
return nil, fmt.Errorf("failed to get username after missing access hash: %w", usernameErr) return nil, fmt.Errorf("failed to get username after missing access hash: %w", usernameErr)
} else if username != "" { } else if username != "" {
@@ -75,7 +75,7 @@ func (t *TelegramClient) resolveUserID(ctx context.Context, userID int64) (resp
Str("target_username", username). Str("target_username", username).
Int64("target_user_id", userID). Int64("target_user_id", userID).
Msg("Access hash not found for user ID, trying to look up username") 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) return nil, fmt.Errorf("%w: %w", bridgev2.ErrResolveIdentifierTryNext, err)
} else if err != nil { } else if err != nil {
@@ -85,39 +85,39 @@ func (t *TelegramClient) resolveUserID(ctx context.Context, userID int64) (resp
resp = &bridgev2.ResolveIdentifierResponse{ resp = &bridgev2.ResolveIdentifierResponse{
UserID: networkUserID, UserID: networkUserID,
Chat: &bridgev2.CreateChatResponse{ 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 { if err != nil {
return nil, fmt.Errorf("failed to get ghost: %w", err) return nil, fmt.Errorf("failed to get ghost: %w", err)
} else if resp.Ghost == nil || resp.Ghost.Name == "" { } else if resp.Ghost == nil || resp.Ghost.Name == "" {
// Try to fetch the user from Telegram // 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) return nil, fmt.Errorf("failed to get user with ID %d: %w", userID, err)
} else if user.TypeID() != tg.UserTypeID { } else if user.TypeID() != tg.UserTypeID {
return nil, fmt.Errorf("unexpected user type: %T", user) 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) return nil, fmt.Errorf("failed to update ghost: %w", err)
} else { } else {
if resp.Ghost == nil { 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 return
} }
func (t *TelegramClient) resolveUsername(ctx context.Context, username string, expectedID int64) (*bridgev2.ResolveIdentifierResponse, error) { func (tc *TelegramClient) resolveUsername(ctx context.Context, username string, expectedID int64) (*bridgev2.ResolveIdentifierResponse, error) {
resolved, err := APICallWithUpdates(ctx, t, func() (*tg.ContactsResolvedPeer, error) { resolved, err := APICallWithUpdates(ctx, tc, func() (*tg.ContactsResolvedPeer, error) {
return t.client.API().ContactsResolveUsername(ctx, &tg.ContactsResolveUsernameRequest{ return tc.client.API().ContactsResolveUsername(ctx, &tg.ContactsResolveUsernameRequest{
Username: username, Username: username,
}) })
}) })
if tg.IsUsernameNotOccupied(err) { if tg.IsUsernameNotOccupied(err) {
if expectedID != 0 { if expectedID != 0 {
err = t.main.Store.Username.Delete(ctx, username) err = tc.main.Store.Username.Delete(ctx, username)
if err != nil { if err != nil {
zerolog.Ctx(ctx).Warn().Err(err).Str("username", username). zerolog.Ctx(ctx).Warn().Err(err).Str("username", username).
Msg("Failed to delete stale username mapping") 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() { for _, user := range resolved.GetUsers() {
if user.GetID() == peer.GetUserID() { 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") 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) // (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])$`) 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 := zerolog.Ctx(ctx).With().Str("identifier", identifier).Logger()
log.Debug().Msg("Resolving identifier") log.Debug().Msg("Resolving identifier")
@@ -164,35 +164,35 @@ func (t *TelegramClient) ResolveIdentifier(ctx context.Context, identifier strin
if identifier[0] == '+' { if identifier[0] == '+' {
normalized := strings.TrimPrefix(identifier, "+") 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) return nil, fmt.Errorf("failed to get user ID by phone number: %w", err)
} else if userID == 0 { } else if userID == 0 {
log.Info().Msg("Phone number not found in database") log.Info().Msg("Phone number not found in database")
return nil, nil return nil, nil
} else { } else {
return t.resolveUserID(ctx, userID) return tc.resolveUserID(ctx, userID)
} }
} else if userID, err := strconv.ParseInt(identifier, 10, 64); err == nil && userID > 0 { } 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 // 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, "__") { } else if match := usernameRe.FindStringSubmatch(identifier); match != nil && !strings.Contains(identifier, "__") {
// This is a username // 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) { if entityType == ids.PeerTypeUser && (err == nil || userID != 0) {
// We know this username. // We know this username.
resp, err := t.resolveUserID(ctx, userID) resp, err := tc.resolveUserID(ctx, userID)
if err == nil || !errors.Is(err, store.ErrNoAccessHash) { if err == nil || !errors.Is(err, store.ErrNoAccessHash) {
return resp, err 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) 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) { func (tc *TelegramClient) SearchUsers(ctx context.Context, query string) (resp []*bridgev2.ResolveIdentifierResponse, err error) {
contactsFound, err := APICallWithUpdates(ctx, t, func() (*tg.ContactsFound, error) { contactsFound, err := APICallWithUpdates(ctx, tc, func() (*tg.ContactsFound, error) {
return t.client.API().ContactsSearch(ctx, &tg.ContactsSearchRequest{Q: query}) return tc.client.API().ContactsSearch(ctx, &tg.ContactsSearchRequest{Q: query})
}) })
if err != nil { if err != nil {
return nil, err return nil, err
@@ -206,7 +206,7 @@ func (t *TelegramClient) SearchUsers(ctx context.Context, query string) (resp []
if peer, ok := p.(*tg.PeerUser); !ok { if peer, ok := p.(*tg.PeerUser); !ok {
return nil return nil
} else if user, ok := users[peer.GetUserID()]; ok { } 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 return err
} else { } else {
resp = append(resp, r) resp = append(resp, r)
@@ -230,37 +230,37 @@ func (t *TelegramClient) SearchUsers(ctx context.Context, query string) (resp []
return resp, nil return resp, nil
} }
func (t *TelegramClient) GetContactList(ctx context.Context) (resp []*bridgev2.ResolveIdentifierResponse, err error) { func (tc *TelegramClient) GetContactList(ctx context.Context) (resp []*bridgev2.ResolveIdentifierResponse, err error) {
t.contactsLock.Lock() tc.contactsLock.Lock()
defer t.contactsLock.Unlock() defer tc.contactsLock.Unlock()
var contacts *tg.ContactsContacts var contacts *tg.ContactsContacts
if time.Since(t.lastContactReq) > 10*time.Minute { if time.Since(tc.lastContactReq) > 10*time.Minute {
contacts, err = APICallWithOnlyUserUpdates(ctx, t, func() (*tg.ContactsContacts, error) { contacts, err = APICallWithOnlyUserUpdates(ctx, tc, func() (*tg.ContactsContacts, error) {
c, err := t.client.API().ContactsGetContacts(ctx, t.cachedContactsHash) c, err := tc.client.API().ContactsGetContacts(ctx, tc.cachedContactsHash)
if err != nil { if err != nil {
return nil, err return nil, err
} }
switch typedResp := c.(type) { switch typedResp := c.(type) {
case *tg.ContactsContacts: case *tg.ContactsContacts:
t.cachedContacts = typedResp tc.cachedContacts = typedResp
var h hasher.Hasher var h hasher.Hasher
for _, contact := range t.cachedContacts.Contacts { for _, contact := range tc.cachedContacts.Contacts {
h.Update(uint32(contact.UserID)) h.Update(uint32(contact.UserID))
} }
t.cachedContactsHash = h.Sum() tc.cachedContactsHash = h.Sum()
case *tg.ContactsContactsNotModified: case *tg.ContactsContactsNotModified:
// No changes // No changes
default: default:
return nil, fmt.Errorf("unexpected contacts type: %T", c) return nil, fmt.Errorf("unexpected contacts type: %T", c)
} }
return t.cachedContacts, nil return tc.cachedContacts, nil
}) })
if err != nil { if err != nil {
return nil, err return nil, err
} }
t.lastContactReq = time.Now() tc.lastContactReq = time.Now()
} else { } else {
contacts = t.cachedContacts contacts = tc.cachedContacts
} }
users := map[int64]tg.UserClass{} users := map[int64]tg.UserClass{}
for _, user := range contacts.GetUsers() { for _, user := range contacts.GetUsers() {
@@ -269,7 +269,7 @@ func (t *TelegramClient) GetContactList(ctx context.Context) (resp []*bridgev2.R
for _, contact := range contacts.Contacts { for _, contact := range contacts.Contacts {
if user, ok := users[contact.UserID]; ok { 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 return nil, err
} else { } else {
resp = append(resp, r) resp = append(resp, r)
@@ -282,7 +282,7 @@ func (t *TelegramClient) GetContactList(ctx context.Context) (resp []*bridgev2.R
} }
// TODO support channels // 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{ req := tg.MessagesCreateChatRequest{
Title: ptr.Val(params.Name).Name, 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) return nil, fmt.Errorf("failed to parse user ID: %w", err)
} else if peerType != ids.PeerTypeUser { } else if peerType != ids.PeerTypeUser {
return nil, fmt.Errorf("unexpected peer type: %s", peerType) 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) return nil, fmt.Errorf("failed to get input user: %w", err)
} else { } else {
req.Users = append(req.Users, inputUser) 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 { if err != nil {
return nil, fmt.Errorf("failed to create chat: %w", err) 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 { } else if chat, ok := chats[0].(*tg.Chat); !ok {
return nil, fmt.Errorf("unexpected chat type: %T", chats[0]) return nil, fmt.Errorf("unexpected chat type: %T", chats[0])
} else { } else {
portalKey := t.makePortalKeyFromID(ids.PeerTypeChat, chat.ID, 0) portalKey := tc.makePortalKeyFromID(ids.PeerTypeChat, chat.ID, 0)
if params.RoomID != "" { if params.RoomID != "" {
portal, err := t.main.Bridge.GetPortalByKey(ctx, portalKey) portal, err := tc.main.Bridge.GetPortalByKey(ctx, portalKey)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -329,7 +329,7 @@ func (t *TelegramClient) CreateGroup(ctx context.Context, params *bridgev2.Group
OverwriteOldPortal: true, OverwriteOldPortal: true,
TombstoneOldRoom: true, TombstoneOldRoom: true,
DeleteOldRoom: true, DeleteOldRoom: true,
ChatInfoSource: t.userLogin, ChatInfoSource: tc.userLogin,
}) })
if err != nil { if err != nil {
return nil, err return nil, err
+65 -65
View File
@@ -79,7 +79,7 @@ func mediaHashID(ctx context.Context, m tg.MessageMediaClass) []byte {
return nil return nil
} }
func (c *TelegramClient) mediaToMatrix( func (tc *TelegramClient) mediaToMatrix(
ctx context.Context, ctx context.Context,
portal *bridgev2.Portal, portal *bridgev2.Portal,
intent bridgev2.MatrixAPI, intent bridgev2.MatrixAPI,
@@ -106,10 +106,10 @@ func (c *TelegramClient) mediaToMatrix(
}, },
}, nil, nil }, nil, nil
case tg.MessageMediaPhotoTypeID, tg.MessageMediaDocumentTypeID: 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) return converted, disappearingSetting, mediaHashID(ctx, media)
case tg.MessageMediaContactTypeID: case tg.MessageMediaContactTypeID:
return c.convertContact(media), nil, nil return tc.convertContact(media), nil, nil
case tg.MessageMediaGeoTypeID, tg.MessageMediaGeoLiveTypeID, tg.MessageMediaVenueTypeID: case tg.MessageMediaGeoTypeID, tg.MessageMediaGeoLiveTypeID, tg.MessageMediaVenueTypeID:
return convertLocation(media), nil, nil return convertLocation(media), nil, nil
case tg.MessageMediaPollTypeID: case tg.MessageMediaPollTypeID:
@@ -134,7 +134,7 @@ func (c *TelegramClient) mediaToMatrix(
} }
} }
func (c *TelegramClient) convertToMatrix( func (tc *TelegramClient) convertToMatrix(
ctx context.Context, ctx context.Context,
portal *bridgev2.Portal, portal *bridgev2.Portal,
intent bridgev2.MatrixAPI, intent bridgev2.MatrixAPI,
@@ -143,7 +143,7 @@ func (c *TelegramClient) convertToMatrix(
log := zerolog.Ctx(ctx).With().Str("conversion_direction", "to_matrix").Logger() log := zerolog.Ctx(ctx).With().Str("conversion_direction", "to_matrix").Logger()
ctx = log.WithContext(ctx) 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") 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 { } else if peerType == ids.PeerTypeChannel && !portal.Metadata.(*PortalMetadata).IsSuperGroup {
var sender *networkid.UserID var sender *networkid.UserID
if msg.Out { if msg.Out {
sender = &c.userID sender = &tc.userID
} else if fromID, ok := msg.GetFromID(); ok { } else if fromID, ok := msg.GetFromID(); ok {
sender = ptr.Ptr(c.getPeerSender(fromID).Sender) sender = ptr.Ptr(tc.getPeerSender(fromID).Sender)
} }
if sender != nil { if sender != nil {
profile, err := portal.PerMessageProfileForSender(ctx, *sender) profile, err := portal.PerMessageProfileForSender(ctx, *sender)
@@ -171,11 +171,11 @@ func (c *TelegramClient) convertToMatrix(
if len(msg.Message) > 0 { if len(msg.Message) > 0 {
hasher.Write([]byte(msg.Message)) 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 { if media, ok := msg.GetMedia(); ok && media.TypeID() == tg.MessageMediaWebPageTypeID {
webpageCtx, webpageCtxCancel := context.WithTimeout(ctx, time.Second*5) webpageCtx, webpageCtxCancel := context.WithTimeout(ctx, time.Second*5)
defer webpageCtxCancel() defer webpageCtxCancel()
preview, err := c.webpageToBeeperLinkPreview(webpageCtx, portal, intent, msg, media) preview, err := tc.webpageToBeeperLinkPreview(webpageCtx, portal, intent, msg, media)
if err != nil { if err != nil {
log.Err(err).Msg("Failed to convert webpage to link preview") log.Err(err).Msg("Failed to convert webpage to link preview")
} else if preview != nil { } else if preview != nil {
@@ -191,7 +191,7 @@ func (c *TelegramClient) convertToMatrix(
} }
var contentURI id.ContentURIString 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 { if mediaPart != nil {
hasher.Write(mediaHashID) hasher.Write(mediaHashID)
cm.Parts = append(cm.Parts, mediaPart) cm.Parts = append(cm.Parts, mediaPart)
@@ -213,7 +213,7 @@ func (c *TelegramClient) convertToMatrix(
} }
if fwd, isForwarded := msg.GetFwdFrom(); isForwarded { 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 { if err != nil {
return nil, fmt.Errorf("failed to add forward header: %w", err) return nil, fmt.Errorf("failed to add forward header: %w", err)
} }
@@ -231,7 +231,7 @@ func (c *TelegramClient) convertToMatrix(
} }
} }
if replyTo.Quote { if replyTo.Quote {
parsedQuote := c.parseBodyAndHTML(ctx, replyTo.QuoteText, replyTo.QuoteEntities) parsedQuote := tc.parseBodyAndHTML(ctx, replyTo.QuoteText, replyTo.QuoteEntities)
parsedQuote.EnsureHasHTML() parsedQuote.EnsureHasHTML()
existingPart := cm.Parts[0] existingPart := cm.Parts[0]
existingPart.Content.EnsureHasHTML() existingPart.Content.EnsureHasHTML()
@@ -256,20 +256,20 @@ func (c *TelegramClient) convertToMatrix(
return 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 var fwdFromText, fwdFromHTML string
switch from := fwd.FromID.(type) { switch from := fwd.FromID.(type) {
case *tg.PeerUser: 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 var mxid id.UserID
if user != nil { if user != nil {
mxid = user.UserMXID mxid = user.UserMXID
fwdFromText = cmp.Or(user.RemoteName, user.UserMXID.String()) 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 return err
} else { } else {
if ghost.Name == "" { if ghost.Name == "" {
info, err := t.GetUserInfo(ctx, ghost) info, err := tc.GetUserInfo(ctx, ghost)
if err != nil { if err != nil {
zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to get user info to add forward header") zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to get user info to add forward header")
} else if info != nil { } else if info != nil {
@@ -291,7 +291,7 @@ func (t *TelegramClient) addForwardHeader(ctx context.Context, part *bridgev2.Co
unknownType = "unknown channel" unknownType = "unknown channel"
channelID = ch.ChannelID 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 { if err != nil {
return err return err
} else if portal != nil && portal.MXID != "" { } else if portal != nil && portal.MXID != "" {
@@ -309,7 +309,7 @@ func (t *TelegramClient) addForwardHeader(ctx context.Context, part *bridgev2.Co
fwdFromHTML = unknownType fwdFromHTML = unknownType
} }
if channelID != 0 && fwdFromText == 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 { if err != nil {
return err return err
} else if ghost != nil && ghost.Name != "" { } else if ghost != nil && ghost.Name != "" {
@@ -364,7 +364,7 @@ func (t *TelegramClient) addForwardHeader(ctx context.Context, part *bridgev2.Co
return nil 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 { if len(entities) == 0 {
return &event.MessageEventContent{MsgType: event.MsgText, Body: message} 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) customEmojiIDs = append(customEmojiIDs, entity.DocumentID)
} }
} }
customEmojis, err := t.transferEmojisToMatrix(ctx, customEmojiIDs) customEmojis, err := tc.transferEmojisToMatrix(ctx, customEmojiIDs)
if err != nil { if err != nil {
zerolog.Ctx(ctx).Err(err). zerolog.Ctx(ctx).Err(err).
Ints64("emoji_ids", customEmojiIDs). Ints64("emoji_ids", customEmojiIDs).
Msg("Failed to transfer custom emojis to Matrix") 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) webpage, ok := msgMedia.(*tg.MessageMediaWebPage).Webpage.(*tg.WebPage)
if !ok { if !ok {
return nil, nil return nil, nil
@@ -401,11 +401,11 @@ func (c *TelegramClient) webpageToBeeperLinkPreview(ctx context.Context, portal
if photo, ok := webpage.Photo.(*tg.Photo); ok { if photo, ok := webpage.Photo.(*tg.Photo); ok {
var fileInfo *event.FileInfo var fileInfo *event.FileInfo
transferer := media.NewTransferer(c.client.API()).WithPhoto(photo) transferer := media.NewTransferer(tc.client.API()).WithPhoto(photo)
if c.main.useDirectMedia { if tc.main.useDirectMedia {
preview.ImageURL, fileInfo, err = transferer.DirectDownloadURL(ctx, c.telegramUserID, portal, msg.ID, true, 0) preview.ImageURL, fileInfo, err = transferer.DirectDownloadURL(ctx, tc.telegramUserID, portal, msg.ID, true, 0)
} else { } 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 { if err != nil {
return nil, err return nil, err
@@ -422,7 +422,7 @@ func (c *TelegramClient) webpageToBeeperLinkPreview(ctx context.Context, portal
return preview, nil return preview, nil
} }
func (c *TelegramClient) convertMediaRequiringUpload( func (tc *TelegramClient) convertMediaRequiringUpload(
ctx context.Context, ctx context.Context,
portal *bridgev2.Portal, portal *bridgev2.Portal,
intent bridgev2.MatrixAPI, intent bridgev2.MatrixAPI,
@@ -443,7 +443,7 @@ func (c *TelegramClient) convertMediaRequiringUpload(
// FIXME don't use raw map for fields in the FileInfo struct // FIXME don't use raw map for fields in the FileInfo struct
extraInfo := map[string]any{} 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 var mediaTransferer *media.ReadyTransferer
if t, ok := msgMedia.(ttlable); ok { if t, ok := msgMedia.(ttlable); ok {
@@ -457,7 +457,7 @@ func (c *TelegramClient) convertMediaRequiringUpload(
// This is a view-once message, set a low TTL. // This is a view-once message, set a low TTL.
ttl = 15 ttl = 15
if c.main.Config.DisableViewOnce { if tc.main.Config.DisableViewOnce {
converted = &bridgev2.ConvertedMessagePart{ converted = &bridgev2.ConvertedMessagePart{
Type: event.EventMessage, Type: event.EventMessage,
Content: &event.MessageEventContent{ Content: &event.MessageEventContent{
@@ -509,17 +509,17 @@ func (c *TelegramClient) convertMediaRequiringUpload(
var thumbnailInfo *event.FileInfo var thumbnailInfo *event.FileInfo
var err error var err error
thumbnailTransferer := media.NewTransferer(c.client.API()). thumbnailTransferer := media.NewTransferer(tc.client.API()).
WithRoomID(portal.MXID). WithRoomID(portal.MXID).
WithPhoto(photo) WithPhoto(photo)
if c.main.useDirectMedia { if tc.main.useDirectMedia {
thumbnailURL, thumbnailInfo, err = thumbnailTransferer.DirectDownloadURL(ctx, c.telegramUserID, portal, msgID, false, photo.ID) thumbnailURL, thumbnailInfo, err = thumbnailTransferer.DirectDownloadURL(ctx, tc.telegramUserID, portal, msgID, false, photo.ID)
if err != nil { if err != nil {
log.Err(err).Msg("Failed to create direct download URL for thumbnail") log.Err(err).Msg("Failed to create direct download URL for thumbnail")
} }
} }
if thumbnailURL == "" { 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 { if err != nil {
log.Err(err).Msg("Failed to transfer thumbnail") log.Err(err).Msg("Failed to transfer thumbnail")
} }
@@ -603,7 +603,7 @@ func (c *TelegramClient) convertMediaRequiringUpload(
} }
} }
extraInfo["fi.mau.telegram.sticker"] = stickerInfo extraInfo["fi.mau.telegram.sticker"] = stickerInfo
transferer = transferer.WithStickerConfig(c.main.Config.AnimatedSticker) transferer = transferer.WithStickerConfig(tc.main.Config.AnimatedSticker)
case *tg.DocumentAttributeAnimated: case *tg.DocumentAttributeAnimated:
isVideoGif = true isVideoGif = true
extraInfo["fi.mau.telegram.gif"] = true extraInfo["fi.mau.telegram.gif"] = true
@@ -622,7 +622,7 @@ func (c *TelegramClient) convertMediaRequiringUpload(
// Strip filename so that we never render the caption // Strip filename so that we never render the caption
content.FileName = "" 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 isVideoGif = true
extraInfo["fi.mau.telegram.animated_sticker"] = true extraInfo["fi.mau.telegram.animated_sticker"] = true
transferer.WithMIMEType("video/webm") transferer.WithMIMEType("video/webm")
@@ -646,17 +646,17 @@ func (c *TelegramClient) convertMediaRequiringUpload(
var thumbnailInfo *event.FileInfo var thumbnailInfo *event.FileInfo
var err error var err error
thumbnailTransferer := media.NewTransferer(c.client.API()). thumbnailTransferer := media.NewTransferer(tc.client.API()).
WithRoomID(portal.MXID). WithRoomID(portal.MXID).
WithDocument(document, true) WithDocument(document, true)
if c.main.useDirectMedia { if tc.main.useDirectMedia {
thumbnailURL, thumbnailInfo, err = thumbnailTransferer.DirectDownloadURL(ctx, c.telegramUserID, portal, msgID, true, document.ID) thumbnailURL, thumbnailInfo, err = thumbnailTransferer.DirectDownloadURL(ctx, tc.telegramUserID, portal, msgID, true, document.ID)
if err != nil { if err != nil {
log.Err(err).Msg("Failed to create direct download URL for thumbnail") log.Err(err).Msg("Failed to create direct download URL for thumbnail")
} }
} }
if thumbnailURL == "" { 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 { if err != nil {
log.Err(err).Msg("Failed to transfer thumbnail") log.Err(err).Msg("Failed to transfer thumbnail")
} }
@@ -681,24 +681,24 @@ func (c *TelegramClient) convertMediaRequiringUpload(
} }
var err error var err error
if c.main.useDirectMedia && (!isSticker || c.main.Config.AnimatedSticker.Target == "disable") { if tc.main.useDirectMedia && (!isSticker || tc.main.Config.AnimatedSticker.Target == "disable") {
content.URL, content.Info, err = mediaTransferer.DirectDownloadURL(ctx, c.telegramUserID, portal, msgID, false, telegramMediaID) content.URL, content.Info, err = mediaTransferer.DirectDownloadURL(ctx, tc.telegramUserID, portal, msgID, false, telegramMediaID)
if err != nil { if err != nil {
log.Err(err).Msg("Failed to create direct download URL for media") log.Err(err).Msg("Failed to create direct download URL for media")
} }
} }
if content.URL == "" { 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 err != nil {
if tgerr.Is(err, tg.ErrFileReferenceExpired) && allowRefetch { if tgerr.Is(err, tg.ErrFileReferenceExpired) && allowRefetch {
log.Warn().Err(err).Msg("Failed to transfer media, trying to refetch from message") log.Warn().Err(err).Msg("Failed to transfer media, trying to refetch from message")
peerType, peerID, _, err := ids.ParsePortalID(portal.ID) peerType, peerID, _, err := ids.ParsePortalID(portal.ID)
if err != nil { if err != nil {
log.Err(err).Msg("Failed to parse portal ID to refetch media") 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") log.Err(err).Msg("Failed to refetch media after file reference expired error")
} else { } else {
return c.convertMediaRequiringUpload(ctx, portal, intent, msgID, msgMedia, false) return tc.convertMediaRequiringUpload(ctx, portal, intent, msgID, msgMedia, false)
} }
} else { } else {
log.Err(err).Msg("Failed to transfer media") log.Err(err).Msg("Failed to transfer media")
@@ -738,9 +738,9 @@ func (c *TelegramClient) convertMediaRequiringUpload(
return return
} }
func (c *TelegramClient) convertContact(media tg.MessageMediaClass) *bridgev2.ConvertedMessagePart { func (tc *TelegramClient) convertContact(media tg.MessageMediaClass) *bridgev2.ConvertedMessagePart {
contact := media.(*tg.MessageMediaContact) 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, "+")) formattedPhone := fmt.Sprintf("+%s", strings.TrimPrefix(contact.PhoneNumber, "+"))
content := event.MessageEventContent{ content := event.MessageEventContent{
@@ -751,7 +751,7 @@ func (c *TelegramClient) convertContact(media tg.MessageMediaClass) *bridgev2.Co
content.Format = event.FormatHTML content.Format = event.FormatHTML
content.FormattedBody = fmt.Sprintf( content.FormattedBody = fmt.Sprintf(
`Shared contact info for <a href="%s">%s</a>: %s`, `Shared contact info for <a href="%s">%s</a>: %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(name),
html.EscapeString(formattedPhone), 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{ avatar := &bridgev2.Avatar{
ID: ids.MakeAvatarID(photo.PhotoID), ID: ids.MakeAvatarID(photo.PhotoID),
} }
if c.main.useDirectMedia { if tc.main.useDirectMedia {
mediaID, err := ids.DirectMediaInfo{ mediaID, err := ids.DirectMediaInfo{
PeerType: ids.PeerTypeUser, PeerType: ids.PeerTypeUser,
PeerID: user.ID, PeerID: user.ID,
UserID: c.telegramUserID, UserID: tc.telegramUserID,
ID: photo.PhotoID, ID: photo.PhotoID,
}.AsMediaID() }.AsMediaID()
if err != nil { if err != nil {
return nil, err 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 return nil, err
} }
avatar.Hash = ids.HashMediaID(mediaID) avatar.Hash = ids.HashMediaID(mediaID)
} else { } else {
avatar.Get = func(ctx context.Context) (data []byte, err error) { 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 // 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) { if errors.Is(err, store.ErrNoAccessHash) {
peer = &tg.InputPeerUser{ peer = &tg.InputPeerUser{
UserID: user.ID, UserID: user.ID,
AccessHash: user.AccessHash, 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 // Bots should use a zero access hash when only a min hash is available
peer.AccessHash = 0 peer.AccessHash = 0
} }
} else if err != nil { } else if err != nil {
return nil, fmt.Errorf("failed to get peer: %w", err) 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 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 var chatPhoto *tg.ChatPhoto
switch typedChatPhoto := rawChatPhoto.(type) { switch typedChatPhoto := rawChatPhoto.(type) {
case *tg.ChatPhotoEmpty: case *tg.ChatPhotoEmpty:
@@ -997,7 +997,7 @@ func (c *TelegramClient) convertChatPhoto(chat tg.InputPeerClass, rawChatPhoto t
ID: ids.MakeAvatarID(chatPhoto.PhotoID), ID: ids.MakeAvatarID(chatPhoto.PhotoID),
} }
if c.main.useDirectMedia { if tc.main.useDirectMedia {
var peerID int64 var peerID int64
var peerType ids.PeerType var peerType ids.PeerType
switch typedChat := chat.(type) { switch typedChat := chat.(type) {
@@ -1016,28 +1016,28 @@ func (c *TelegramClient) convertChatPhoto(chat tg.InputPeerClass, rawChatPhoto t
mediaID, err := ids.DirectMediaInfo{ mediaID, err := ids.DirectMediaInfo{
PeerType: peerType, PeerType: peerType,
PeerID: peerID, PeerID: peerID,
UserID: c.telegramUserID, UserID: tc.telegramUserID,
ID: chatPhoto.PhotoID, ID: chatPhoto.PhotoID,
}.AsMediaID() }.AsMediaID()
if err != nil { if err != nil {
return nil, err return nil, err
} }
todoRemove := c.main.Bridge.BackgroundCtx // TODO remove context parameter from GenerateContentURI todoRemove := tc.main.Bridge.BackgroundCtx // TODO remove context parameter from GenerateContentURI
if avatar.MXC, err = c.main.Bridge.Matrix.GenerateContentURI(todoRemove, mediaID); err != nil { if avatar.MXC, err = tc.main.Bridge.Matrix.GenerateContentURI(todoRemove, mediaID); err != nil {
return nil, err return nil, err
} }
avatar.Hash = ids.HashMediaID(mediaID) avatar.Hash = ids.HashMediaID(mediaID)
} else { } else {
avatar.Get = func(ctx context.Context) (data []byte, err error) { 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 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) photo, ok := photoClass.(*tg.Photo)
if !ok { if !ok {
return nil, fmt.Errorf("not a photo: %T", photoClass) 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()), ID: ids.MakeAvatarID(photo.GetID()),
} }
if c.main.useDirectMedia { if tc.main.useDirectMedia {
mediaID, err := ids.DirectMediaInfo{ mediaID, err := ids.DirectMediaInfo{
PeerType: peerType, PeerType: peerType,
PeerID: peerID, PeerID: peerID,
UserID: c.telegramUserID, UserID: tc.telegramUserID,
ID: photo.GetID(), ID: photo.GetID(),
}.AsMediaID() }.AsMediaID()
if err != nil { if err != nil {
return nil, err 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 return nil, err
} }
avatar.Hash = ids.HashMediaID(mediaID) avatar.Hash = ids.HashMediaID(mediaID)
} else { } else {
avatar.Get = func(ctx context.Context) (data []byte, err error) { 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)
} }
} }
+42 -42
View File
@@ -16,37 +16,37 @@ import (
"go.mau.fi/mautrix-telegram/pkg/gotd/tg" "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) peerType, id, err := ids.ParseUserID(ghost.ID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
switch peerType { switch peerType {
case ids.PeerTypeUser: 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) return nil, fmt.Errorf("failed to get user %d: %w", id, err)
} else { } else {
return t.wrapUserInfo(ctx, user, ghost) return tc.wrapUserInfo(ctx, user, ghost)
} }
case ids.PeerTypeChannel: 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) return nil, fmt.Errorf("failed to get channel %d: %w", id, err)
} else { } else {
return t.wrapChannelGhostInfo(ctx, channel) return tc.wrapChannelGhostInfo(ctx, channel)
} }
default: default:
return nil, fmt.Errorf("unexpected peer type: %s", peerType) 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) { switch typedChat := peerID.(type) {
case *tg.PeerUser: case *tg.PeerUser:
if id == typedChat.UserID { if id == typedChat.UserID {
// We don't have the user's access hash // We don't have the user's access hash
return nil, nil 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 { if err != nil {
return nil, err return nil, err
} }
@@ -58,7 +58,7 @@ func (t *TelegramClient) getChatPeerForInputFromMessage(ctx context.Context, id
// We don't have the channel's access hash // We don't have the channel's access hash
return nil, nil 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 { if err != nil {
return nil, err 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]) msg, ok := bridgev2.GetRemoteEventFromContext(ctx).(*simplevent.Message[*tg.Message])
if !ok { if !ok {
return nil, nil 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 { if err != nil || inputPeer == nil {
return nil, err return nil, err
} }
@@ -84,12 +84,12 @@ func (t *TelegramClient) getInputUserFromContext(ctx context.Context, id int64)
}, nil }, 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]) msg, ok := bridgev2.GetRemoteEventFromContext(ctx).(*simplevent.Message[*tg.Message])
if !ok { if !ok {
return nil, nil 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 { if err != nil || inputPeer == nil {
return nil, err return nil, err
} }
@@ -100,10 +100,10 @@ func (t *TelegramClient) getInputChannelFromContext(ctx context.Context, id int6
}, nil }, nil
} }
func (t *TelegramClient) getInputUser(ctx context.Context, id int64) (tg.InputUserClass, error) { func (tc *TelegramClient) getInputUser(ctx context.Context, id int64) (tg.InputUserClass, error) {
accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, id) accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, id)
if errors.Is(err, store.ErrNoAccessHash) { if errors.Is(err, store.ErrNoAccessHash) {
fromMsg, fromMsgErr := t.getInputUserFromContext(ctx, id) fromMsg, fromMsgErr := tc.getInputUserFromContext(ctx, id)
if fromMsgErr != nil { if fromMsgErr != nil {
return nil, fmt.Errorf("%w, also failed to get from message: %w", err, fromMsgErr) return nil, fmt.Errorf("%w, also failed to get from message: %w", err, fromMsgErr)
} else if fromMsg == nil { } 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 return &tg.InputUser{UserID: id, AccessHash: accessHash}, nil
} }
func (t *TelegramClient) getInputPeerUser(ctx context.Context, id int64) (*tg.InputPeerUser, error) { func (tc *TelegramClient) getInputPeerUser(ctx context.Context, id int64) (*tg.InputPeerUser, error) {
accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, id) accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeUser, id)
if errors.Is(err, store.ErrNoAccessHash) { if errors.Is(err, store.ErrNoAccessHash) {
return nil, err return nil, err
} else if err != nil { } 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 return &tg.InputPeerUser{UserID: id, AccessHash: accessHash}, nil
} }
func (t *TelegramClient) getSingleUser(ctx context.Context, id int64) (tg.UserClass, error) { func (tc *TelegramClient) getSingleUser(ctx context.Context, id int64) (tg.UserClass, error) {
if inputUser, err := t.getInputUser(ctx, id); err != nil { if inputUser, err := tc.getInputUser(ctx, id); err != nil {
return nil, err 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 return nil, err
} else if len(users) == 0 { } else if len(users) == 0 {
// TODO does this mean the user is deleted? Need to handle this a bit better // 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) { func (tc *TelegramClient) getInputChannel(ctx context.Context, id int64) (tg.InputChannelClass, error) {
accessHash, err := t.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id) accessHash, err := tc.ScopedStore.GetAccessHash(ctx, ids.PeerTypeChannel, id)
if err != nil { if err != nil {
fromMsg, fromMsgErr := t.getInputChannelFromContext(ctx, id) fromMsg, fromMsgErr := tc.getInputChannelFromContext(ctx, id)
if fromMsgErr != nil { if fromMsgErr != nil {
return nil, fmt.Errorf("%w, also failed to get from message: %w", err, fromMsgErr) return nil, fmt.Errorf("%w, also failed to get from message: %w", err, fromMsgErr)
} else if fromMsg == nil { } 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 return &tg.InputChannel{ChannelID: id, AccessHash: accessHash}, nil
} }
func (t *TelegramClient) getSingleChannel(ctx context.Context, id int64) (*tg.Channel, error) { func (tc *TelegramClient) getSingleChannel(ctx context.Context, id int64) (*tg.Channel, error) {
inputChannel, err := t.getInputChannel(ctx, id) inputChannel, err := tc.getInputChannel(ctx, id)
if err != nil { if err != nil {
return nil, err return nil, err
} }
chats, err := APICallWithOnlyChatUpdates(ctx, t, func() (tg.MessagesChatsClass, error) { chats, err := APICallWithOnlyChatUpdates(ctx, tc, func() (tg.MessagesChatsClass, error) {
return t.client.API().ChannelsGetChannels(ctx, []tg.InputChannelClass{inputChannel}) return tc.client.API().ChannelsGetChannels(ctx, []tg.InputChannelClass{inputChannel})
}) })
if err != nil { if err != nil {
return nil, err 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 var err error
if accessHash, ok := channel.GetAccessHash(); ok && !channel.Min { 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 return nil, err
} }
} }
var avatar *bridgev2.Avatar var avatar *bridgev2.Avatar
avatar, err = t.convertChatPhoto(channel.AsInputPeer(), channel.GetPhoto()) avatar, err = tc.convertChatPhoto(channel.AsInputPeer(), channel.GetPhoto())
if err != nil { if err != nil {
return nil, err return nil, err
} }
var identifiers []string var identifiers []string
if username, set := channel.GetUsername(); set { 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 { if err != nil {
return nil, err return nil, err
} }
@@ -208,7 +208,7 @@ func (t *TelegramClient) wrapChannelGhostInfo(ctx context.Context, channel *tg.C
}, nil }, 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) oldMeta := ghost.Metadata.(*GhostMetadata)
user, ok := u.(*tg.User) user, ok := u.(*tg.User)
if !ok { if !ok {
@@ -217,12 +217,12 @@ func (t *TelegramClient) wrapUserInfo(ctx context.Context, u tg.UserClass, ghost
var identifiers []string var identifiers []string
if !user.Min { if !user.Min {
if accessHash, ok := user.GetAccessHash(); ok { 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 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 return nil, err
} }
@@ -235,7 +235,7 @@ func (t *TelegramClient) wrapUserInfo(ctx context.Context, u tg.UserClass, ghost
if phone, ok := user.GetPhone(); ok { if phone, ok := user.GetPhone(); ok {
normalized := strings.TrimPrefix(phone, "+") normalized := strings.TrimPrefix(phone, "+")
identifiers = append(identifiers, fmt.Sprintf("tel:+%s", normalized)) 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 return nil, err
} }
} }
@@ -249,17 +249,17 @@ func (t *TelegramClient) wrapUserInfo(ctx context.Context, u tg.UserClass, ghost
(!user.Min || user.ApplyMinPhoto || oldMeta.IsMin()) && (!user.Min || user.ApplyMinPhoto || oldMeta.IsMin()) &&
// Hack: check ApplyMinPhoto in addition to Personal, because some personalized avatars // Hack: check ApplyMinPhoto in addition to Personal, because some personalized avatars
// only have the ApplyMinPhoto flag and not Personal. // 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 var err error
avatar, err = t.convertUserProfilePhoto(ctx, user, photo) avatar, err = tc.convertUserProfilePhoto(ctx, user, photo)
if err != nil { if err != nil {
return nil, err 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 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 namePtr = nil
} }
if user.Min && !oldMeta.IsMin() && ghost.Name != "" { 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.IsPremium = user.Premium
meta.Deleted = user.Deleted meta.Deleted = user.Deleted
meta.NotMin = true meta.NotMin = true
if meta.ContactSource == 0 || meta.ContactSource == t.telegramUserID || (!user.Contact && meta.SourceIsContact) { if meta.ContactSource == 0 || meta.ContactSource == tc.telegramUserID || (!user.Contact && meta.SourceIsContact) {
changed = changed || meta.ContactSource != t.telegramUserID || meta.SourceIsContact != user.Contact changed = changed || meta.ContactSource != tc.telegramUserID || meta.SourceIsContact != user.Contact
meta.ContactSource = t.telegramUserID meta.ContactSource = tc.telegramUserID
meta.SourceIsContact = user.Contact meta.SourceIsContact = user.Contact
} }
} }