148 lines
4.1 KiB
Go
148 lines
4.1 KiB
Go
package rpc
|
||
|
||
import (
|
||
"context"
|
||
|
||
"github.com/gotd/td/tg"
|
||
|
||
"telesrv/internal/compat/tdesktop"
|
||
"telesrv/internal/domain"
|
||
)
|
||
|
||
// 本文件把 reaction / sticker 资源 RPC 接到真实 seed 数据(documents / sticker_sets /
|
||
// available_reactions);Files 服务缺失或资源未导入时回退到 tdesktop 兼容 stub。
|
||
|
||
func (r *Router) onMessagesGetAvailableReactions(ctx context.Context, hash int) (tg.MessagesAvailableReactionsClass, error) {
|
||
if r.deps.Files == nil {
|
||
return tdesktop.AvailableReactions(hash), nil
|
||
}
|
||
reactions, err := r.deps.Files.ListAvailableReactions(ctx)
|
||
if err != nil {
|
||
return nil, internalErr()
|
||
}
|
||
if len(reactions) == 0 {
|
||
return tdesktop.AvailableReactions(hash), nil
|
||
}
|
||
catalogHash := availableReactionsHash(reactions)
|
||
if hash == catalogHash {
|
||
return &tg.MessagesAvailableReactionsNotModified{}, nil
|
||
}
|
||
docs, err := r.deps.Files.GetDocuments(ctx, reactionDocumentIDs(reactions))
|
||
if err != nil {
|
||
return nil, internalErr()
|
||
}
|
||
return tgAvailableReactions(reactions, documentsByID(docs), catalogHash), nil
|
||
}
|
||
|
||
func (r *Router) onMessagesGetStickerSet(ctx context.Context, req *tg.MessagesGetStickerSetRequest) (tg.MessagesStickerSetClass, error) {
|
||
if r.deps.Files == nil {
|
||
return tdesktop.StickerSet(req), nil
|
||
}
|
||
ref, ok := stickerSetRefFromInput(req.Stickerset)
|
||
if !ok {
|
||
return tdesktop.StickerSet(req), nil
|
||
}
|
||
set, docs, found, err := r.deps.Files.ResolveStickerSet(ctx, ref)
|
||
if err != nil {
|
||
return nil, internalErr()
|
||
}
|
||
if !found {
|
||
// 未 seed 的系统集 / 未知短名:回退兼容 stub,避免破坏客户端。
|
||
return tdesktop.StickerSet(req), nil
|
||
}
|
||
if req.Hash != 0 && req.Hash == set.Hash {
|
||
return &tg.MessagesStickerSetNotModified{}, nil
|
||
}
|
||
return tgMessagesStickerSet(set, docs), nil
|
||
}
|
||
|
||
func (r *Router) onMessagesGetAllStickers(ctx context.Context, hash int64) (tg.MessagesAllStickersClass, error) {
|
||
return r.allStickersForKind(ctx, hash, domain.StickerSetKindStickers)
|
||
}
|
||
|
||
func (r *Router) onMessagesGetEmojiStickers(ctx context.Context, hash int64) (tg.MessagesAllStickersClass, error) {
|
||
return r.allStickersForKind(ctx, hash, domain.StickerSetKindEmoji)
|
||
}
|
||
|
||
func (r *Router) allStickersForKind(ctx context.Context, hash int64, kind domain.StickerSetKind) (tg.MessagesAllStickersClass, error) {
|
||
if r.deps.Files == nil {
|
||
return messagesAllStickersEmpty(hash), nil
|
||
}
|
||
sets, err := r.deps.Files.ListStickerSets(ctx, kind)
|
||
if err != nil {
|
||
return nil, internalErr()
|
||
}
|
||
if len(sets) == 0 {
|
||
return messagesAllStickersEmpty(hash), nil
|
||
}
|
||
catalogHash := stickerSetsCatalogHash(sets)
|
||
if hash == catalogHash {
|
||
return &tg.MessagesAllStickersNotModified{}, nil
|
||
}
|
||
return &tg.MessagesAllStickers{Hash: catalogHash, Sets: tgStickerSets(sets)}, nil
|
||
}
|
||
|
||
func documentsByID(docs []domain.Document) map[int64]domain.Document {
|
||
m := make(map[int64]domain.Document, len(docs))
|
||
for _, d := range docs {
|
||
m[d.ID] = d
|
||
}
|
||
return m
|
||
}
|
||
|
||
// availableReactionsHash 用 reaction 的核心字段算稳定 hash(供 *NotModified 缓存判定)。
|
||
func availableReactionsHash(reactions []domain.AvailableReaction) int {
|
||
values := make([]int64, 0, len(reactions)*10)
|
||
for _, r := range reactions {
|
||
values = append(values,
|
||
int64(len([]rune(r.Reaction))),
|
||
boolHashValue(r.Inactive),
|
||
boolHashValue(r.Premium),
|
||
r.StaticIconID,
|
||
r.AppearAnimationID,
|
||
r.SelectAnimationID,
|
||
r.ActivateAnimationID,
|
||
r.EffectAnimationID,
|
||
r.AroundAnimationID,
|
||
r.CenterIconID,
|
||
)
|
||
}
|
||
return int(tdesktopCountHash(values) & 0x7fffffff)
|
||
}
|
||
|
||
func stickerSetsCatalogHash(sets []domain.StickerSet) int64 {
|
||
values := make([]int64, 0, len(sets))
|
||
for _, set := range sets {
|
||
if set.ID == 0 {
|
||
return 0
|
||
}
|
||
if set.Archived {
|
||
continue
|
||
}
|
||
values = append(values, int64(set.Hash))
|
||
}
|
||
return int64(tdesktopCountHash(values))
|
||
}
|
||
|
||
func boolHashValue(v bool) int64 {
|
||
if v {
|
||
return 1
|
||
}
|
||
return 0
|
||
}
|
||
|
||
func tdesktopCountHash(values []int64) uint64 {
|
||
var hash uint64
|
||
for _, value := range values {
|
||
hash = tdesktopHashUpdate(hash, value)
|
||
}
|
||
return hash
|
||
}
|
||
|
||
func tdesktopHashUpdate(hash uint64, value int64) uint64 {
|
||
hash ^= hash >> 21
|
||
hash ^= hash << 35
|
||
hash ^= hash >> 4
|
||
hash += uint64(value)
|
||
return hash
|
||
}
|