added full gifts support

This commit is contained in:
onysd 2026-08-07 10:04:13 +03:00
parent ea5b86de8f
commit 354128c106
35 changed files with 1502 additions and 103 deletions

View file

@ -9,6 +9,7 @@ import (
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap"
"telesrv/internal/domain"
"telesrv/internal/store"
@ -81,6 +82,27 @@ func (r *Router) onMessagesGetInlineBotResults(ctx context.Context, req *tg.Mess
if err != nil {
return nil, err
}
// 内置进程内service bot 分支:@gif 没有 MTProto session、也没有 Bot API 消费者,
// 走下面的「推 updateBotInlineQuery + 挂起 25s」必然超时故同步问 responder。
//
// 结果仍必须登记进 inline registrymessages.sendInlineBotResult 用
// (query_id, result_id) 反查用户选中的那一条query_id==0 会让每次发送都以
// QUERY_ID_EMPTY 失败。registerCachedContext 正是「已有结果、只需分配
// query_id」这条路径与 cacheKey 命中时同一个函数),它不写 cacheKey 查询
// 缓存,因此管理员改动目录后下一次查询依旧立即生效。
if r.deps.ServiceBotInlineResults != nil && r.deps.ServiceBotInlineResults.HandlesInlineBot(bot.ID) {
results, handled, err := r.deps.ServiceBotInlineResults.OnInlineQuery(ctx, bot.ID, userID, req.Query, req.Offset)
if err != nil {
r.log.Warn("service bot inline query",
zap.Int64("bot_user_id", bot.ID), zap.Int64("user_id", userID), zap.Error(err))
return nil, internalErr()
}
if !handled {
return nil, botInvalidErr()
}
registered := r.inlines.registerCachedContext(ctx, r.clock.Now(), bot.ID, userID, peer, results)
return r.tgBotInlineResults(ctx, userID, registered), nil
}
cacheKey := inlineCacheKey{
botUserID: bot.ID,
userID: userID,

View file

@ -360,6 +360,29 @@ type ServiceBotCallbacks interface {
OnCallbackQuery(ctx context.Context, query domain.BotCallbackQuery) (domain.BotCallbackAnswer, bool, error)
}
// ServiceBotInlineResults answers messages.getInlineBotResults for built-in
// bots that run inside this process (@gif); app/bots implements it.
//
// Same rationale as ServiceBotCallbacks above: an internal bot has no MTProto
// session to receive updateBotInlineQuery and no Bot API consumer to drain the
// queue, so the ordinary push-and-wait-25s path could only ever time out. A bot
// claimed here is answered synchronously by the responder that owns it, and
// nothing is registered in the shared inline-query registry for it.
//
// A nil Deps.ServiceBotInlineResults keeps the edge behaviour exactly as it
// was: every inline query is pushed to the bot's session and waited on.
//
// HandlesInlineBot is deliberately its own method, not a reuse of
// ServiceBotCallbacks'/messages.BotResponder's shared HandlesBot: that one
// method already drives both private-message and callback routing for the
// bots it covers, and @gif should answer inline queries only, not also become
// eligible for private-message/callback dispatch it was never given a case
// for.
type ServiceBotInlineResults interface {
HandlesInlineBot(botUserID int64) bool
OnInlineQuery(ctx context.Context, botUserID, userID int64, query, offset string) (domain.BotInlineResults, bool, error)
}
// UserIdentityService 是 UsersService 的资料扩展能力,用于 username/phone 解析。
type UserIdentityService interface {
CheckUsername(ctx context.Context, userID int64, username string) (bool, error)
@ -1043,49 +1066,50 @@ type Deps struct {
// AuthKeySessionLayers is the protocol-only durable ordering boundary for
// explicit invokeWithLayer evidence. Production must wire the same auth-key
// store used by the MTProto edge; nil is reserved for isolated router tests.
AuthKeySessionLayers store.AuthKeySessionLayerStore
Account AccountService
Privacy PrivacyService
Help HelpService
AccountFreeze AccountFreezeService
AICompose AIComposeService
Ephemeral EphemeralService
EphemeralPush store.EphemeralPushBroker
Moderation ModerationService
Users UsersService
Usernames UsernameRegistryService
BotVerifications BotVerificationService
TelegramLogin TelegramLoginService
Updates UpdatesService
BootstrapUpdates store.BootstrapUpdateJobStore
BotAPIUpdates store.BotAPIUpdateStore
BotCallbacks store.BotCallbackRegistryStore
Contacts ContactsService
Dialogs DialogsService
Chatlists ChatlistsService
Messages MessagesService
Translation TranslationService
Stories StoriesService
Channels ChannelsService
Communities CommunitiesService
Files FilesService
PremiumPromo PremiumPromoService
Bots BotsService
ServiceBotCallbacks ServiceBotCallbacks
Polls PollsService
Phone PhoneService
GroupCalls GroupCallsService
LiveStreams LiveStreamsService
SFU sfu.Service
TURN turnsrv.Service
LangPack LangPackService
Sessions SessionBinder
Inline store.InlineRegistryStore
Limiter RateLimiter
Metrics Metrics
SecretChats SecretChatService
Passkey PasskeyService
Themes ThemeService
AuthKeySessionLayers store.AuthKeySessionLayerStore
Account AccountService
Privacy PrivacyService
Help HelpService
AccountFreeze AccountFreezeService
AICompose AIComposeService
Ephemeral EphemeralService
EphemeralPush store.EphemeralPushBroker
Moderation ModerationService
Users UsersService
Usernames UsernameRegistryService
BotVerifications BotVerificationService
TelegramLogin TelegramLoginService
Updates UpdatesService
BootstrapUpdates store.BootstrapUpdateJobStore
BotAPIUpdates store.BotAPIUpdateStore
BotCallbacks store.BotCallbackRegistryStore
Contacts ContactsService
Dialogs DialogsService
Chatlists ChatlistsService
Messages MessagesService
Translation TranslationService
Stories StoriesService
Channels ChannelsService
Communities CommunitiesService
Files FilesService
PremiumPromo PremiumPromoService
Bots BotsService
ServiceBotCallbacks ServiceBotCallbacks
ServiceBotInlineResults ServiceBotInlineResults
Polls PollsService
Phone PhoneService
GroupCalls GroupCallsService
LiveStreams LiveStreamsService
SFU sfu.Service
TURN turnsrv.Service
LangPack LangPackService
Sessions SessionBinder
Inline store.InlineRegistryStore
Limiter RateLimiter
Metrics Metrics
SecretChats SecretChatService
Passkey PasskeyService
Themes ThemeService
}
// ThemeService 抽象自定义云主题(app/themes):创建/更新/查询主题 + 维护每用户已安装列表。