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