owpengram-server/internal/rpc/messages_register.go
2026-07-01 21:55:55 +08:00

548 lines
24 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"
"github.com/gotd/td/tg"
"telesrv/internal/compat/tdesktop"
"telesrv/internal/domain"
"unicode/utf8"
)
// registerMessages 注册 messages.* RPC handler。
func (r *Router) registerMessages(d *tg.ServerDispatcher) {
d.OnMessagesSetTyping(r.onMessagesSetTyping)
d.OnMessagesSaveDraft(r.onMessagesSaveDraft)
d.OnMessagesSaveDefaultSendAs(r.onMessagesSaveDefaultSendAs)
d.OnMessagesGetAllDrafts(r.onMessagesGetAllDrafts)
d.OnMessagesClearAllDrafts(r.onMessagesClearAllDrafts)
d.OnMessagesGetAllStickers(r.onMessagesGetAllStickers)
d.OnMessagesGetEmojiStickers(r.onMessagesGetEmojiStickers)
d.OnMessagesGetMaskStickers(r.onMessagesGetMaskStickers)
d.OnMessagesGetFeaturedStickers(r.onMessagesGetFeaturedStickers)
d.OnMessagesGetFeaturedEmojiStickers(r.onMessagesGetFeaturedEmojiStickers)
d.OnMessagesGetRecentStickers(r.onMessagesGetRecentStickers)
d.OnMessagesGetFavedStickers(r.onMessagesGetFavedStickers)
d.OnMessagesGetSavedGifs(r.onMessagesGetSavedGifs)
d.OnMessagesFaveSticker(r.onMessagesFaveSticker)
d.OnMessagesSaveRecentSticker(r.onMessagesSaveRecentSticker)
d.OnMessagesSaveGif(r.onMessagesSaveGif)
d.OnMessagesClearRecentStickers(r.onMessagesClearRecentStickers)
d.OnMessagesSendMessage(r.onMessagesSendMessage)
d.OnMessagesForwardMessages(r.onMessagesForwardMessages)
d.OnMessagesGetDialogFilters(r.onMessagesGetDialogFilters)
d.OnMessagesGetSuggestedDialogFilters(func(ctx context.Context) ([]tg.DialogFilterSuggested, error) {
return tdesktop.SuggestedDialogFilters(), nil
})
d.OnMessagesUpdateDialogFilter(r.onMessagesUpdateDialogFilter)
d.OnMessagesUpdateDialogFiltersOrder(r.onMessagesUpdateDialogFiltersOrder)
d.OnMessagesToggleDialogFilterTags(r.onMessagesToggleDialogFilterTags)
d.OnMessagesGetSavedDialogs(r.onMessagesGetSavedDialogs)
d.OnMessagesGetPinnedSavedDialogs(func(ctx context.Context) (tg.MessagesSavedDialogsClass, error) {
return r.onMessagesGetPinnedSavedDialogs(ctx)
})
d.OnMessagesToggleSavedDialogPin(r.onMessagesToggleSavedDialogPin)
d.OnMessagesReorderPinnedSavedDialogs(r.onMessagesReorderPinnedSavedDialogs)
d.OnMessagesGetSavedDialogsByID(r.onMessagesGetSavedDialogsByID)
d.OnMessagesGetSavedHistory(r.onMessagesGetSavedHistory)
d.OnMessagesReadSavedHistory(r.onMessagesReadSavedHistory)
d.OnMessagesDeleteSavedHistory(r.onMessagesDeleteSavedHistory)
d.OnMessagesGetCommonChats(r.onMessagesGetCommonChats)
d.OnMessagesGetDefaultHistoryTTL(r.onMessagesGetDefaultHistoryTTL)
d.OnMessagesSetHistoryTTL(r.onMessagesSetHistoryTTL)
d.OnMessagesSetDefaultHistoryTTL(r.onMessagesSetDefaultHistoryTTL)
d.OnMessagesGetSponsoredMessages(r.onMessagesGetSponsoredMessages)
d.OnMessagesGetWebPagePreview(r.onMessagesGetWebPagePreview)
d.OnMessagesRequestWebView(r.onMessagesRequestWebView)
d.OnMessagesProlongWebView(r.onMessagesProlongWebView)
d.OnMessagesSendWebViewResultMessage(r.onMessagesSendWebViewResultMessage)
d.OnMessagesRequestSimpleWebView(r.onMessagesRequestSimpleWebView)
d.OnMessagesGetBotApp(r.onMessagesGetBotApp)
d.OnMessagesRequestAppWebView(r.onMessagesRequestAppWebView)
d.OnMessagesRequestMainWebView(r.onMessagesRequestMainWebView)
d.OnMessagesSendWebViewData(r.onMessagesSendWebViewData)
d.OnMessagesSendBotRequestedPeer(r.onMessagesSendBotRequestedPeer)
d.OnMessagesGetPreparedInlineMessage(r.onMessagesGetPreparedInlineMessage)
d.OnMessagesGetEmojiGameInfo(r.onMessagesGetEmojiGameInfo)
d.OnMessagesGetGameHighScores(r.onMessagesGetGameHighScores)
d.OnMessagesGetInlineGameHighScores(r.onMessagesGetInlineGameHighScores)
d.OnMessagesSetGameScore(r.onMessagesSetGameScore)
d.OnMessagesSetInlineGameScore(r.onMessagesSetInlineGameScore)
d.OnMessagesUploadMedia(r.onMessagesUploadMedia)
d.OnMessagesSendMedia(r.onMessagesSendMedia)
d.OnMessagesSendMultiMedia(r.onMessagesSendMultiMedia)
d.OnMessagesReportSpam(r.onMessagesReportSpam)
d.OnMessagesReport(r.onMessagesReport)
d.OnMessagesReportReaction(r.onMessagesReportReaction)
d.OnMessagesReportMessagesDelivery(r.onMessagesReportMessagesDelivery)
d.OnMessagesReportReadMetrics(r.onMessagesReportReadMetrics)
d.OnMessagesReportMusicListen(r.onMessagesReportMusicListen)
d.OnMessagesReportSponsoredMessage(r.onMessagesReportSponsoredMessage)
d.OnMessagesReadMessageContents(r.onMessagesReadMessageContents)
d.OnMessagesGetMessagesViews(r.onMessagesGetMessagesViews)
d.OnMessagesGetUnreadMentions(r.onMessagesGetUnreadMentions)
d.OnMessagesReadMentions(r.onMessagesReadMentions)
d.OnMessagesGetSearchCounters(r.onMessagesGetSearchCounters)
d.OnMessagesGetReplies(r.onMessagesGetReplies)
d.OnMessagesGetDiscussionMessage(r.onMessagesGetDiscussionMessage)
d.OnMessagesReadDiscussion(r.onMessagesReadDiscussion)
d.OnMessagesGetForumTopics(r.onMessagesGetForumTopics)
d.OnMessagesGetForumTopicsByID(r.onMessagesGetForumTopicsByID)
d.OnMessagesGetOnlines(r.onMessagesGetOnlines)
d.OnMessagesGetAvailableReactions(r.onMessagesGetAvailableReactions)
d.OnMessagesGetAvailableEffects(r.onMessagesGetAvailableEffects)
d.OnMessagesGetStickers(r.onMessagesGetStickers)
d.OnMessagesInstallStickerSet(r.onMessagesInstallStickerSet)
d.OnMessagesUninstallStickerSet(r.onMessagesUninstallStickerSet)
d.OnMessagesReorderStickerSets(r.onMessagesReorderStickerSets)
d.OnMessagesToggleStickerSets(r.onMessagesToggleStickerSets)
d.OnMessagesGetMyStickers(r.onMessagesGetMyStickers)
d.OnMessagesGetArchivedStickers(func(ctx context.Context, req *tg.MessagesGetArchivedStickersRequest) (*tg.MessagesArchivedStickers, error) {
return &tg.MessagesArchivedStickers{
Count: 0,
Sets: []tg.StickerSetCoveredClass{},
}, nil
})
d.OnMessagesGetStickerSet(r.onMessagesGetStickerSet)
d.OnMessagesGetEmojiGroups(func(ctx context.Context, hash int) (tg.MessagesEmojiGroupsClass, error) {
return tdesktop.EmojiGroups(hash), nil
})
d.OnMessagesGetEmojiStatusGroups(func(ctx context.Context, hash int) (tg.MessagesEmojiGroupsClass, error) {
return tdesktop.EmojiStatusGroups(), nil
})
d.OnMessagesGetEmojiStickerGroups(func(ctx context.Context, hash int) (tg.MessagesEmojiGroupsClass, error) {
// 自定义 emoji 贴纸的分类(Premium);telesrv 未 seed custom-emoji 集,保持空。
return &tg.MessagesEmojiGroupsNotModified{}, nil
})
d.OnMessagesGetEmojiProfilePhotoGroups(func(ctx context.Context, hash int) (tg.MessagesEmojiGroupsClass, error) {
return tdesktop.EmojiProfilePhotoGroups(), nil
})
d.OnMessagesGetEmojiKeywords(r.onMessagesGetEmojiKeywords)
d.OnMessagesGetEmojiKeywordsDifference(r.onMessagesGetEmojiKeywordsDifference)
d.OnMessagesGetEmojiKeywordsLanguages(func(ctx context.Context, langcodes []string) ([]tg.EmojiLanguage, error) {
return []tg.EmojiLanguage{}, nil
})
d.OnMessagesGetCustomEmojiDocuments(r.onMessagesGetCustomEmojiDocuments)
d.OnMessagesGetAttachedStickers(r.onMessagesGetAttachedStickers)
d.OnMessagesSearchStickerSets(r.onMessagesSearchStickerSets)
d.OnMessagesSearchStickers(r.onMessagesSearchStickers)
d.OnMessagesGetAttachMenuBots(r.onMessagesGetAttachMenuBots)
d.OnMessagesGetAttachMenuBot(r.onMessagesGetAttachMenuBot)
d.OnMessagesToggleBotInAttachMenu(r.onMessagesToggleBotInAttachMenu)
d.OnMessagesGetQuickReplies(r.onMessagesGetQuickReplies)
d.OnMessagesCheckQuickReplyShortcut(r.onMessagesCheckQuickReplyShortcut)
d.OnMessagesReorderQuickReplies(r.onMessagesReorderQuickReplies)
d.OnMessagesEditQuickReplyShortcut(r.onMessagesEditQuickReplyShortcut)
d.OnMessagesDeleteQuickReplyShortcut(r.onMessagesDeleteQuickReplyShortcut)
d.OnMessagesGetQuickReplyMessages(r.onMessagesGetQuickReplyMessages)
d.OnMessagesSendQuickReplyMessages(r.onMessagesSendQuickReplyMessages)
d.OnMessagesDeleteQuickReplyMessages(r.onMessagesDeleteQuickReplyMessages)
d.OnMessagesGetWebPage(r.onMessagesGetWebPage)
d.OnMessagesGetDialogs(func(ctx context.Context, req *tg.MessagesGetDialogsRequest) (tg.MessagesDialogsClass, error) {
if r.deps.Dialogs == nil {
return &tg.MessagesDialogs{}, nil
}
userID, _, err := r.currentUserID(ctx)
if err != nil {
return nil, internalErr()
}
filter, err := r.dialogFilterFromRequest(ctx, userID, req)
if err != nil {
return nil, err
}
if filter.Hash != 0 {
hashCheck, err := r.deps.Dialogs.GetDialogsHash(ctx, userID, filter)
if err != nil {
return nil, internalErr()
}
if hashCheck.Known && hashCheck.Matched {
return &tg.MessagesDialogsNotModified{Count: hashCheck.Count}, nil
}
}
list, err := r.deps.Dialogs.GetDialogs(ctx, userID, filter)
if err != nil {
return nil, internalErr()
}
if ClientTypeFrom(ctx) == ClientTypeTDesktop && tdesktop.ShouldMergePinnedIntoInitialDialogs(filter) {
pinned, err := r.pinnedDialogsList(ctx, userID, domain.DialogMainFolderID)
if err != nil {
return nil, internalErr()
}
list = tdesktop.MergeInitialDialogsWithPinned(list, pinned)
}
if filter.Hash != 0 && list.Hash == filter.Hash {
return &tg.MessagesDialogsNotModified{Count: list.Count}, nil
}
return r.tgMessagesDialogs(ctx, userID, r.withDialogListPresence(ctx, userID, list)), nil
})
d.OnMessagesGetPinnedDialogs(func(ctx context.Context, folderID int) (*tg.MessagesPeerDialogs, error) {
id, _ := AuthKeyIDFrom(ctx)
userID, _, err := r.currentUserID(ctx)
if err != nil {
return nil, internalErr()
}
list, err := r.pinnedDialogsList(ctx, userID, folderID)
if err != nil {
return nil, internalErr()
}
st := domain.UpdateState{Date: int(r.clock.Now().Unix())}
if r.deps.Updates != nil {
var err error
st, err = r.deps.Updates.GetState(ctx, id, userID)
if err != nil {
return nil, internalErr()
}
}
return r.tgPeerDialogs(ctx, userID, r.withDialogListPresence(ctx, userID, list), st), nil
})
d.OnMessagesGetPeerDialogs(func(ctx context.Context, peers []tg.InputDialogPeerClass) (*tg.MessagesPeerDialogs, error) {
id, _ := AuthKeyIDFrom(ctx)
userID, _, err := r.currentUserID(ctx)
if err != nil {
return nil, internalErr()
}
// difference 类 catch-up FLOOD_WAIT设计 Phase 2 / §10.3DrKLO 收 nudge 对未加载频道
// 走 loadUnknownChannel→getPeerDialogs限速须同时覆盖它不止 getChannelDifference
if err := r.checkCatchupRateLimit(ctx, userID, peerDialogsRateLimitKeyPrefix); err != nil {
return nil, err
}
domainPeers, err := r.dialogPeersFromInput(ctx, userID, peers)
if err != nil {
return nil, err
}
var list domain.DialogList
if len(domainPeers) > 0 && r.deps.Dialogs != nil {
var err error
list, err = r.deps.Dialogs.GetPeerDialogs(ctx, userID, domainPeers)
if err != nil {
return nil, internalErr()
}
}
st := domain.UpdateState{Date: int(r.clock.Now().Unix())}
if r.deps.Updates != nil {
var err error
st, err = r.deps.Updates.GetState(ctx, id, userID)
if err != nil {
return nil, internalErr()
}
}
r.trackChannelInterest(ctx, userID, channelIDsFromDialogs(list)...)
return r.tgPeerDialogs(ctx, userID, r.withDialogListPresence(ctx, userID, list), st), nil
})
d.OnMessagesGetPeerSettings(r.onMessagesGetPeerSettings)
d.OnMessagesToggleDialogPin(r.onMessagesToggleDialogPin)
d.OnMessagesReorderPinnedDialogs(r.onMessagesReorderPinnedDialogs)
d.OnMessagesMarkDialogUnread(r.onMessagesMarkDialogUnread)
d.OnMessagesGetDialogUnreadMarks(r.onMessagesGetDialogUnreadMarks)
d.OnMessagesHidePeerSettingsBar(r.onMessagesHidePeerSettingsBar)
d.OnMessagesGetMessageEditData(r.onMessagesGetMessageEditData)
d.OnMessagesEditMessage(r.onMessagesEditMessage)
d.OnMessagesGetOutboxReadDate(r.onMessagesGetOutboxReadDate)
d.OnMessagesGetMessageReadParticipants(r.onMessagesGetMessageReadParticipants)
d.OnMessagesDeleteMessages(r.onMessagesDeleteMessages)
d.OnMessagesDeleteHistory(r.onMessagesDeleteHistory)
d.OnMessagesGetMessages(r.onMessagesGetMessages)
d.OnMessagesGetRichMessage(r.onMessagesGetRichMessage)
d.OnMessagesGetHistory(func(ctx context.Context, req *tg.MessagesGetHistoryRequest) (tg.MessagesMessagesClass, error) {
userID, _, err := r.currentUserID(ctx)
if err != nil {
return nil, internalErr()
}
filter, ok := r.messageFilterFromHistoryRequest(userID, req)
if !ok {
return messagesNotModifiedOrEmpty(req.Hash), nil
}
if filter.Peer.Type == domain.PeerTypeChannel {
if r.deps.Channels == nil {
return messagesNotModifiedOrEmpty(req.Hash), nil
}
if err := r.validateInputPeerChannelAccess(ctx, userID, req.Peer, filter.Peer.ID); err != nil {
return nil, err
}
if isLegacyInputPeerChat(req.Peer) {
return &tg.MessagesMessages{}, nil
}
history, err := r.deps.Channels.GetHistory(ctx, userID, domain.ChannelHistoryFilter{
ChannelID: filter.Peer.ID,
OffsetID: filter.OffsetID,
OffsetDate: filter.OffsetDate,
AddOffset: filter.AddOffset,
Limit: filter.Limit,
MaxID: filter.MaxID,
MinID: filter.MinID,
Hash: filter.Hash,
})
if err != nil {
return nil, channelInvalidErr(err)
}
history = r.enrichChannelHistory(ctx, userID, history)
r.trackChannelInterest(ctx, userID, filter.Peer.ID)
if filter.Hash != 0 && history.Hash == filter.Hash {
return &tg.MessagesMessagesNotModified{Count: history.Count}, nil
}
return r.tgChannelHistoryMessages(ctx, userID, history), nil
}
r.clearChannelInterest(ctx, userID)
if r.deps.Messages == nil {
return messagesNotModifiedOrEmpty(req.Hash), nil
}
list, err := r.deps.Messages.GetHistory(ctx, userID, filter)
if err != nil {
return nil, internalErr()
}
if filter.Hash != 0 && list.Hash == filter.Hash {
return &tg.MessagesMessagesNotModified{Count: list.Count}, nil
}
return r.tgMessagesMessages(ctx, userID, r.enrichMessageList(ctx, userID, list)), nil
})
d.OnMessagesReadHistory(func(ctx context.Context, req *tg.MessagesReadHistoryRequest) (*tg.MessagesAffectedMessages, error) {
id, _ := AuthKeyIDFrom(ctx)
userID, _, err := r.currentUserID(ctx)
if err != nil {
return nil, internalErr()
}
peer, peerErr := r.checkedDomainPeerFromInputPeer(ctx, userID, req.Peer)
if peerErr == nil && peer.Type == domain.PeerTypeChannel && r.deps.Channels != nil {
read, err := r.deps.Channels.ReadHistory(ctx, userID, domain.ReadChannelHistoryRequest{
UserID: userID,
ChannelID: peer.ID,
MaxID: req.MaxID,
Date: int(r.clock.Now().Unix()),
})
if err != nil {
return nil, channelInvalidErr(err)
}
event, err := r.recordChannelReadInbox(ctx, userID, read)
if err != nil {
return nil, err
}
r.pushChannelReadOutboxUpdates(ctx, read.ChannelID, read.OutboxUpdates)
r.advanceForumGeneralReadAfterChannelRead(ctx, userID, read)
if event.Pts != 0 {
return &tg.MessagesAffectedMessages{Pts: event.Pts, PtsCount: event.PtsCount}, nil
}
return r.affectedMessages(ctx, id, userID)
}
if peerErr != nil {
return nil, peerErr
}
if r.deps.Messages != nil {
sessionID, _ := SessionIDFrom(ctx)
read, err := r.deps.Messages.ReadHistory(ctx, userID, domain.ReadHistoryRequest{
OwnerUserID: userID,
Peer: peer,
MaxID: req.MaxID,
Date: int(r.clock.Now().Unix()),
OriginAuthKeyID: id,
OriginSessionID: sessionID,
})
if err != nil {
return nil, internalErr()
}
if read.Changed && read.InboxEvent.Pts != 0 {
r.pushCurrentReadHistoryEvent(ctx, read.InboxEvent)
r.pushReadHistoryEvent(ctx, read.OwnerUserID, read.InboxEvent)
if read.OutboxChanged && read.OutboxEvent.Pts != 0 {
r.pushReadHistoryEvent(ctx, read.OutboxUserID, read.OutboxEvent)
}
return &tg.MessagesAffectedMessages{Pts: read.InboxEvent.Pts, PtsCount: read.InboxEvent.PtsCount}, nil
}
}
return r.affectedMessages(ctx, id, userID)
})
d.OnMessagesSearch(func(ctx context.Context, req *tg.MessagesSearchRequest) (tg.MessagesMessagesClass, error) {
if utf8.RuneCountInString(req.Q) > maxMessageSearchQLength {
return nil, limitInvalidErr()
}
userID, _, err := r.currentUserID(ctx)
if err != nil {
return nil, internalErr()
}
filter := r.messageFilterFromSearchRequest(userID, req)
if filter.HasPeer && filter.Peer.Type == domain.PeerTypeChannel {
if r.deps.Channels == nil {
return messagesNotModifiedOrEmpty(req.Hash), nil
}
if isLegacyInputPeerChat(req.Peer) {
return &tg.MessagesMessages{}, nil
}
if searchFilterNeedsMediaStore(req.Filter) {
if mediaSearchCountOnlyRequest(req) {
view, err := r.resolveInputPeerChannelView(ctx, userID, req.Peer, filter.Peer.ID)
if err != nil {
return nil, channelInvalidErr(err)
}
counts, err := r.mediaCountsForPeer(ctx, userID, filter.Peer)
if err != nil {
return nil, channelInvalidErr(err)
}
out := &tg.MessagesChannelMessages{
Pts: view.Channel.Pts,
Count: counts.CountAny(mediaCategoriesForFilter(req.Filter)),
Messages: []tg.MessageClass{},
Chats: []tg.ChatClass{tgChannelChatForView(userID, view)},
Users: []tg.UserClass{},
}
r.applyStoryMaxIDsToMessages(ctx, userID, out)
return out, nil
}
if err := r.validateInputPeerChannelAccess(ctx, userID, req.Peer, filter.Peer.ID); err != nil {
return nil, err
}
categories := mediaCategoriesForFilter(req.Filter)
mediaReq := domain.MediaSearchRequest{
Categories: categories,
OffsetID: req.OffsetID,
AddOffset: domain.ClampMessageHistoryAddOffset(req.AddOffset),
Limit: req.Limit,
MaxID: req.MaxID,
MinID: req.MinID,
}
if mediaSearchCanReusePeerWideCount(req) {
counts, err := r.mediaCountsForPeer(ctx, userID, filter.Peer)
if err != nil {
return nil, channelInvalidErr(err)
}
mediaReq.KnownCount = counts.CountAny(categories)
mediaReq.HasKnownCount = true
}
history, err := r.deps.Channels.SearchChannelMedia(ctx, userID, filter.Peer.ID, mediaReq)
if err != nil {
return nil, channelInvalidErr(err)
}
history = r.enrichChannelHistory(ctx, userID, history)
return r.tgChannelHistoryMessages(ctx, userID, history), nil
}
if err := r.validateInputPeerChannelAccess(ctx, userID, req.Peer, filter.Peer.ID); err != nil {
return nil, err
}
chFilter, ok := r.channelHistoryFilterFromSearchRequest(userID, req, filter.Peer.ID)
if !ok {
return nil, peerIDInvalidErr()
}
history, err := r.deps.Channels.GetHistory(ctx, userID, chFilter)
if err != nil {
return nil, channelInvalidErr(err)
}
history = r.enrichChannelHistory(ctx, userID, history)
if chFilter.Hash != 0 && history.Hash == chFilter.Hash {
return &tg.MessagesMessagesNotModified{Count: history.Count}, nil
}
return r.tgChannelHistoryMessages(ctx, userID, history), nil
}
if _, ok := req.Filter.(*tg.InputMessagesFilterPinned); ok {
if _, err := r.checkedDomainPeerFromInputPeer(ctx, userID, req.Peer); err != nil {
return nil, err
}
if r.deps.Messages == nil || !filter.HasPeer || filter.Peer.Type != domain.PeerTypeUser {
return &tg.MessagesMessages{}, nil
}
// 私聊置顶列表:客户端置顶栏经 filterPinned 分页拉取,必须
// 带总数NotModified 哈希不参与该过滤器)。
filter.PinnedOnly = true
filter.NeedTotalCount = true
filter.Hash = 0
list, err := r.deps.Messages.Search(ctx, userID, filter)
if err != nil {
return nil, internalErr()
}
return r.tgMessagesMessages(ctx, userID, r.enrichMessageList(ctx, userID, list)), nil
}
if r.deps.Messages == nil {
return messagesNotModifiedOrEmpty(req.Hash), nil
}
if searchFilterNeedsMediaStore(req.Filter) {
peer, err := r.checkedDomainPeerFromInputPeer(ctx, userID, req.Peer)
if err != nil {
return nil, err
}
if peer.Type != domain.PeerTypeUser {
return &tg.MessagesMessages{}, nil
}
if mediaSearchCountOnlyRequest(req) {
counts, err := r.mediaCountsForPeer(ctx, userID, peer)
if err != nil {
return nil, internalErr()
}
return r.tgMessagesMessages(ctx, userID, domain.MessageList{
Count: counts.CountAny(mediaCategoriesForFilter(req.Filter)),
}), nil
}
categories := mediaCategoriesForFilter(req.Filter)
mediaReq := domain.MediaSearchRequest{
Categories: categories,
OffsetID: req.OffsetID,
AddOffset: domain.ClampMessageHistoryAddOffset(req.AddOffset),
Limit: req.Limit,
MaxID: req.MaxID,
MinID: req.MinID,
}
if mediaSearchCanReusePeerWideCount(req) {
counts, err := r.mediaCountsForPeer(ctx, userID, peer)
if err != nil {
return nil, internalErr()
}
mediaReq.KnownCount = counts.CountAny(categories)
mediaReq.HasKnownCount = true
}
list, err := r.deps.Messages.SearchPrivateMedia(ctx, userID, peer.ID, mediaReq)
if err != nil {
return nil, internalErr()
}
return r.tgMessagesMessages(ctx, userID, r.enrichMessageList(ctx, userID, list)), nil
}
list, err := r.deps.Messages.Search(ctx, userID, filter)
if err != nil {
return nil, internalErr()
}
if filter.Hash != 0 && list.Hash == filter.Hash {
return &tg.MessagesMessagesNotModified{Count: list.Count}, nil
}
return r.tgMessagesMessages(ctx, userID, r.enrichMessageList(ctx, userID, list)), nil
})
d.OnMessagesSearchGlobal(r.onMessagesSearchGlobal)
d.OnMessagesGetSearchResultsCalendar(r.onMessagesGetSearchResultsCalendar)
d.OnMessagesGetSearchResultsPositions(r.onMessagesGetSearchResultsPositions)
d.OnMessagesSendReaction(r.onMessagesSendReaction)
// 语音转文字无识别后端注册为显式失败TRANSCRIPTION_FAILEDpremium
// 客户端点击转录按钮得到优雅失败提示,而不是 NOT_IMPLEMENTED trace。
d.OnMessagesTranscribeAudio(func(ctx context.Context, req *tg.MessagesTranscribeAudioRequest) (*tg.MessagesTranscribedAudio, error) {
if _, _, err := r.currentUserID(ctx); err != nil {
return nil, internalErr()
}
return nil, tgerr400("TRANSCRIPTION_FAILED")
})
d.OnMessagesGetMessagesReactions(r.onMessagesGetMessagesReactions)
d.OnMessagesGetMessageReactionsList(r.onMessagesGetMessageReactionsList)
d.OnMessagesSetDefaultReaction(r.onMessagesSetDefaultReaction)
d.OnMessagesGetPaidReactionPrivacy(r.onMessagesGetPaidReactionPrivacy)
d.OnMessagesTogglePaidReactionPrivacy(r.onMessagesTogglePaidReactionPrivacy)
d.OnMessagesSendPaidReaction(r.onMessagesSendPaidReaction)
d.OnMessagesDeleteParticipantReactions(r.onMessagesDeleteParticipantReactions)
d.OnMessagesDeleteParticipantReaction(r.onMessagesDeleteParticipantReaction)
d.OnMessagesGetUnreadReactions(r.onMessagesGetUnreadReactions)
d.OnMessagesReadReactions(r.onMessagesReadReactions)
d.OnMessagesGetTopReactions(r.onMessagesGetTopReactions)
d.OnMessagesGetRecentReactions(r.onMessagesGetRecentReactions)
d.OnMessagesClearRecentReactions(r.onMessagesClearRecentReactions)
d.OnMessagesGetSavedReactionTags(r.onMessagesGetSavedReactionTags)
d.OnMessagesUpdateSavedReactionTag(r.onMessagesUpdateSavedReactionTag)
d.OnMessagesGetDefaultTagReactions(r.onMessagesGetDefaultTagReactions)
d.OnMessagesSendVote(r.onMessagesSendVote)
d.OnMessagesGetPollResults(r.onMessagesGetPollResults)
d.OnMessagesGetPollVotes(r.onMessagesGetPollVotes)
d.OnMessagesAddPollAnswer(r.onMessagesAddPollAnswer)
d.OnMessagesDeletePollAnswer(r.onMessagesDeletePollAnswer)
d.OnMessagesGetUnreadPollVotes(r.onMessagesGetUnreadPollVotes)
d.OnMessagesReadPollVotes(r.onMessagesReadPollVotes)
d.OnMessagesAppendTodoList(r.onMessagesAppendTodoList)
d.OnMessagesToggleTodoCompleted(r.onMessagesToggleTodoCompleted)
d.OnMessagesGetScheduledHistory(r.onMessagesGetScheduledHistory)
d.OnMessagesGetScheduledMessages(r.onMessagesGetScheduledMessages)
d.OnMessagesSendScheduledMessages(r.onMessagesSendScheduledMessages)
d.OnMessagesDeleteScheduledMessages(r.onMessagesDeleteScheduledMessages)
d.OnMessagesCreateForumTopic(r.onMessagesCreateForumTopic)
d.OnMessagesEditForumTopic(r.onMessagesEditForumTopic)
d.OnMessagesUpdatePinnedForumTopic(r.onMessagesUpdatePinnedForumTopic)
d.OnMessagesReorderPinnedForumTopics(r.onMessagesReorderPinnedForumTopics)
d.OnMessagesDeleteTopicHistory(r.onMessagesDeleteTopicHistory)
}