owpengram-server/internal/rpc/messages_reactions_helpers.go
2026-09-01 12:06:31 +03:00

193 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package rpc
import (
"context"
"errors"
"strings"
"unicode/utf8"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)
func (r *Router) onMessagesUpdateSavedReactionTag(ctx context.Context, req *tg.MessagesUpdateSavedReactionTagRequest) (bool, error) {
userID, _, err := r.currentUserID(ctx)
if err != nil {
return false, internalErr()
}
reaction, err := domainMessageReactionFromTL(req.Reaction)
if err != nil {
return false, err
}
if !r.viewerPremium(ctx, userID) {
return false, premiumAccountRequiredErr()
}
title, ok := req.GetTitle()
if !ok {
title = ""
}
if utf8.RuneCountInString(title) > maxSavedReactionTagTitle {
return false, limitInvalidErr()
}
if r.deps.Messages != nil {
if err := r.deps.Messages.UpdateSavedReactionTag(ctx, userID, domain.SavedReactionTag{
UserID: userID,
Reaction: reaction,
Title: title,
}); err != nil {
return false, messageReactionErr(err)
}
}
r.pushUserUpdates(ctx, userID, &tg.Updates{
Updates: []tg.UpdateClass{&tg.UpdateSavedReactionTags{}},
Date: int(r.clock.Now().Unix()),
Seq: 0,
})
return true, nil
}
func (r *Router) reactionPeer(ctx context.Context, peer tg.InputPeerClass, savedPeer func() (tg.InputPeerClass, bool)) (int64, domain.Peer, error) {
userID, _, err := r.currentUserID(ctx)
if err != nil {
return 0, domain.Peer{}, internalErr()
}
out, err := r.checkedDomainPeerFromInputPeer(ctx, userID, peer)
if err != nil {
return 0, domain.Peer{}, err
}
if savedPeer != nil {
if input, ok := savedPeer(); ok && input != nil {
if _, err := r.checkedDomainPeerFromInputPeer(ctx, userID, input); err != nil {
return 0, domain.Peer{}, err
}
}
}
return userID, out, nil
}
func domainMessageReactionsFromTL(req *tg.MessagesSendReactionRequest) ([]domain.MessageReaction, error) {
if req == nil {
return nil, nil
}
reactions, ok := req.GetReaction()
if !ok || len(reactions) == 0 {
return nil, nil
}
out := make([]domain.MessageReaction, 0, len(reactions))
seen := make(map[string]struct{}, len(reactions))
for _, reaction := range reactions {
parsed, err := domainMessageReactionFromTL(reaction)
if err != nil {
return nil, err
}
key := parsed.Key()
if _, ok := seen[key]; ok {
continue
}
seen[key] = struct{}{}
out = append(out, parsed)
}
return out, nil
}
func optionalDomainMessageReaction(reaction tg.ReactionClass) (*domain.MessageReaction, error) {
if reaction == nil {
return nil, nil
}
if reactionClassNil(reaction) {
return nil, reactionInvalidErr()
}
out, err := domainMessageReactionFromTL(reaction)
if err != nil {
return nil, err
}
return &out, nil
}
func domainMessageReactionFromTL(reaction tg.ReactionClass) (domain.MessageReaction, error) {
if reactionClassNil(reaction) {
return domain.MessageReaction{}, reactionInvalidErr()
}
switch typed := reaction.(type) {
case *tg.ReactionEmoji:
emoticon := strings.TrimSpace(typed.Emoticon)
if emoticon == "" || utf8.RuneCountInString(emoticon) > domain.MaxChannelReactionEmoticonLength {
return domain.MessageReaction{}, reactionInvalidErr()
}
return domain.MessageReaction{Type: domain.MessageReactionEmoji, Emoticon: emoticon}, nil
case *tg.ReactionCustomEmoji:
if typed.DocumentID <= 0 {
return domain.MessageReaction{}, reactionInvalidErr()
}
return domain.MessageReaction{Type: domain.MessageReactionCustomEmoji, DocumentID: typed.DocumentID}, nil
case nil, *tg.ReactionEmpty, *tg.ReactionPaid:
return domain.MessageReaction{}, reactionInvalidErr()
default:
return domain.MessageReaction{}, inputConstructorInvalidErr()
}
}
func reactionClassNil(reaction tg.ReactionClass) bool {
switch typed := reaction.(type) {
case nil:
return true
case *tg.ReactionEmpty:
return typed == nil
case *tg.ReactionEmoji:
return typed == nil
case *tg.ReactionCustomEmoji:
return typed == nil
case *tg.ReactionPaid:
return typed == nil
default:
return false
}
}
func domainStoryReactionValueFromTL(reaction tg.ReactionClass) (domain.MessageReaction, error) {
if reactionClassNil(reaction) {
return domain.MessageReaction{}, reactionInvalidErr()
}
switch typed := reaction.(type) {
case *tg.ReactionEmoji:
return domainMessageReactionFromTL(typed)
case *tg.ReactionCustomEmoji:
if typed.DocumentID <= 0 {
return domain.MessageReaction{}, reactionInvalidErr()
}
return domain.MessageReaction{Type: domain.MessageReactionCustomEmoji, DocumentID: typed.DocumentID}, nil
case nil, *tg.ReactionEmpty, *tg.ReactionPaid:
return domain.MessageReaction{}, reactionInvalidErr()
default:
return domain.MessageReaction{}, inputConstructorInvalidErr()
}
}
func messageReactionErr(err error) error {
switch {
case errors.Is(err, domain.ErrMessageIDInvalid):
return messageIDInvalidErr()
case errors.Is(err, domain.ErrReactionInvalid):
return reactionInvalidErr()
default:
return internalErr()
}
}
func channelReactionErr(err error) error {
switch {
case errors.Is(err, domain.ErrMessageRandomIDDuplicate):
return randomIDDuplicateErr()
case errors.Is(err, domain.ErrMessageIDInvalid):
return messageIDInvalidErr()
case errors.Is(err, domain.ErrReactionInvalid):
return reactionInvalidErr()
case errors.Is(err, domain.ErrReactionsTooMany):
// 官方:消息去重 emoji 种类已达 reactions_uniq_max或 chat 自定义 reactions_limit
// 新种类 reaction 报 400 REACTIONS_TOO_MANY追加已有种类不受限。
return tgerr400("REACTIONS_TOO_MANY")
default:
return channelInvalidErr(err)
}
}