reactions: use allowed reactions when possible

Signed-off-by: Sumner Evans <sumner.evans@automattic.com>
This commit is contained in:
Sumner Evans
2024-09-25 16:43:13 -06:00
parent 81c913bdd3
commit ce1c28832e
6 changed files with 81 additions and 4 deletions

View File

@@ -49,4 +49,5 @@ func migrateLegacyConfig(helper up.Helper) {
bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "sync_update_limit"}, []string{"network", "sync", "update_limit"})
bridgeconfig.CopyToOtherLocation(helper, up.Int, []string{"bridge", "sync_create_limit"}, []string{"network", "sync", "create_limit"})
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "sync_direct_chats"}, []string{"network", "sync", "direct_chats"})
bridgeconfig.CopyToOtherLocation(helper, up.Bool, []string{"bridge", "always_custom_emoji_reaction"}, []string{"network", "always_custom_emoji_reaction"})
}

View File

@@ -44,9 +44,15 @@ type TelegramClient struct {
updatesManager *updates.Manager
clientCancel context.CancelFunc
appConfigLock sync.Mutex
appConfig map[string]any
appConfigHash int
availableReactionsLock sync.Mutex
availableReactions map[string]struct{}
availableReactionsHash int
availableReactionsFetched time.Time
telegramFmtParams *telegramfmt.FormatParams
matrixParser *matrixfmt.HTMLParser

View File

@@ -63,6 +63,8 @@ type TelegramConfig struct {
CreateLimit int `yaml:"create_limit"`
DirectChats bool `yaml:"direct_chats"`
} `yaml:"sync"`
AlwaysCustomEmojiReaction bool `yaml:"always_custom_emoji_reaction"`
}
func (c TelegramConfig) ShouldBridge(participantCount int) bool {
@@ -96,6 +98,7 @@ func upgradeConfig(helper up.Helper) {
helper.Copy(up.Int, "sync", "update_limit")
helper.Copy(up.Int, "sync", "create_limit")
helper.Copy(up.Bool, "sync", "direct_chats")
helper.Copy(up.Bool, "always_custom_emoji_reaction")
}
func (tg *TelegramConnector) GetConfig() (example string, data any, upgrader up.Upgrader) {

View File

@@ -70,3 +70,9 @@ sync:
create_limit: 15
# Whether or not to sync and create portals for direct chats at startup.
direct_chats: false
# Should the bridge send all unicode reactions as custom emoji reactions to
# Telegram? By default, the bridge only uses custom emojis for unicode emojis
# that aren't allowed in reactions.
always_custom_emoji_reaction: false

View File

@@ -285,6 +285,11 @@ func (t *TelegramClient) HandleMatrixMessageRemove(ctx context.Context, msg *bri
}
func (t *TelegramClient) PreHandleMatrixReaction(ctx context.Context, msg *bridgev2.MatrixReaction) (bridgev2.MatrixReactionPreResponse, error) {
log := zerolog.Ctx(ctx).With().
Str("conversion_direction", "to_telegram").
Str("handler", "pre_handle_matrix_reaction").
Str("key", msg.Content.RelatesTo.Key).
Logger()
var resp bridgev2.MatrixReactionPreResponse
var maxReactions int
@@ -293,7 +298,8 @@ func (t *TelegramClient) PreHandleMatrixReaction(ctx context.Context, msg *bridg
return resp, err
}
var emojiID networkid.EmojiID
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, msg.Content.RelatesTo.Key); err != nil {
return resp, err
@@ -304,12 +310,25 @@ func (t *TelegramClient) PreHandleMatrixReaction(ctx context.Context, msg *bridg
} else {
emojiID = ids.MakeEmojiIDFromDocumentID(documentID)
}
} else if documentID, ok := emojis.GetEmojiDocumentID(msg.Content.RelatesTo.Key); ok {
emojiID = ids.MakeEmojiIDFromDocumentID(documentID)
} else if t.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 {
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 {
emojiID = ids.MakeEmojiIDFromEmoticon(msg.Content.RelatesTo.Key)
if documentID, ok := emojis.GetEmojiDocumentID(keyNoVariation); ok {
log.Debug().Msg("Using custom emoji reaction")
emojiID = ids.MakeEmojiIDFromDocumentID(documentID)
}
}
log.Debug().Str("emoji_id", string(emojiID)).Msg("Pre-handled reaction")
return bridgev2.MatrixReactionPreResponse{
SenderID: t.userID,
EmojiID: emojiID,

View File

@@ -515,6 +515,8 @@ func (t *TelegramClient) inputPeerForPortalID(ctx context.Context, portalID netw
}
func (t *TelegramClient) getAppConfigCached(ctx context.Context) (map[string]any, error) {
t.appConfigLock.Lock()
defer t.appConfigLock.Unlock()
if t.appConfig == nil {
cfg, err := t.client.API().HelpGetAppConfig(ctx, t.appConfigHash)
if err != nil {
@@ -537,6 +539,46 @@ func (t *TelegramClient) getAppConfigCached(ctx context.Context) (map[string]any
return t.appConfig, nil
}
func (t *TelegramClient) getAvailableReactions(ctx context.Context) (map[string]struct{}, error) {
log := zerolog.Ctx(ctx).With().Str("handler", "get_available_reactions").Logger()
t.availableReactionsLock.Lock()
defer t.availableReactionsLock.Unlock()
if t.availableReactions == nil || time.Since(t.availableReactionsFetched) > 12*time.Hour {
cfg, err := t.client.API().MessagesGetAvailableReactions(ctx, t.availableReactionsHash)
if err != nil {
return nil, err
}
t.availableReactionsFetched = time.Now()
switch v := cfg.(type) {
case *tg.MessagesAvailableReactions:
availableReactions, ok := cfg.(*tg.MessagesAvailableReactions)
if !ok {
return nil, fmt.Errorf("failed to get app config: unexpected type %T", availableReactions)
}
log.Debug().Msg("Fetched new available reactions")
myGhost, err := t.main.Bridge.GetGhostByID(ctx, t.userID)
if err != nil {
log.Err(err).Msg("failed to get own ghost")
}
t.availableReactions = make(map[string]struct{}, len(availableReactions.Reactions))
for _, reaction := range availableReactions.Reactions {
if !reaction.Inactive && (myGhost.Metadata.(*GhostMetadata).IsPremium || !reaction.Premium) {
t.availableReactions[reaction.Reaction] = struct{}{}
}
}
t.availableReactionsHash = availableReactions.Hash
case *tg.MessagesAvailableReactionsNotModified:
log.Debug().Msg("Available reactions not modified")
default:
log.Error().Type("reaction_type", v).Msg("failed to get available reactions: unexpected type")
}
}
return t.availableReactions, nil
}
func (t *TelegramClient) transferEmojisToMatrix(ctx context.Context, customEmojiIDs []int64) (result map[networkid.EmojiID]string, err error) {
result, customEmojiIDs = emojis.ConvertKnownEmojis(customEmojiIDs)