Merge remote-tracking branch 'upstream/main' into dev

This commit is contained in:
onysd 2026-07-18 09:19:27 +03:00
commit 6b29556ef8
836 changed files with 1598388 additions and 64684 deletions

View file

@ -5,101 +5,243 @@ import (
"errors"
"strings"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tlprofile"
ioscompat "telesrv/internal/compat/ios"
"telesrv/internal/compat/tdesktop"
"telesrv/internal/domain"
)
// registerAccount 注册 account.* RPC handler。
func (r *Router) registerAccount(d *tg.ServerDispatcher) {
d.OnAccountRegisterDevice(func(ctx context.Context, req *tg.AccountRegisterDeviceRequest) (bool, error) {
func (r *Router) registerAccount(d *tlprofile.Dispatcher) {
registerRPC[*tg.AccountRegisterDeviceRequest](d, tlprofile.SemanticMethodAccountRegisterDevice, func(ctx context.Context, req *tg.AccountRegisterDeviceRequest) (any, error) {
return true, nil
})
d.OnAccountUnregisterDevice(func(ctx context.Context, req *tg.AccountUnregisterDeviceRequest) (bool, error) {
registerRPC[*tg.AccountUnregisterDeviceRequest](d, tlprofile.SemanticMethodAccountUnregisterDevice, func(ctx context.Context, req *tg.AccountUnregisterDeviceRequest) (any, error) {
return true, nil
})
d.OnAccountUpdateDeviceLocked(func(ctx context.Context, period int) (bool, error) {
registerRPC[*tg.AccountUpdateDeviceLockedRequest](d, tlprofile.SemanticMethodAccountUpdateDeviceLocked, func(ctx context.Context, layerRequest *tg.AccountUpdateDeviceLockedRequest) (any, error) {
period := layerRequest.
Period
_ = period
if _, _, err := r.currentUserID(ctx); err != nil {
return false, internalErr()
}
return ioscompat.DeviceLockedUpdated(), nil
})
d.OnAccountSendChangePhoneCode(r.onAccountSendChangePhoneCode)
d.OnAccountChangePhone(r.onAccountChangePhone)
d.OnAccountCheckUsername(r.onAccountCheckUsername)
d.OnAccountUpdateProfile(r.onAccountUpdateProfile)
d.OnAccountUpdateUsername(r.onAccountUpdateUsername)
d.OnAccountUpdateBirthday(r.onAccountUpdateBirthday)
d.OnAccountUpdatePersonalChannel(r.onAccountUpdatePersonalChannel)
d.OnAccountGetPassword(r.onAccountGetPassword)
d.OnAccountGetNotifySettings(r.onAccountGetNotifySettings)
d.OnAccountUpdateNotifySettings(r.onAccountUpdateNotifySettings)
d.OnAccountResetNotifySettings(r.onAccountResetNotifySettings)
d.OnAccountGetPrivacy(r.onAccountGetPrivacy)
d.OnAccountSetPrivacy(r.onAccountSetPrivacy)
d.OnAccountGetAuthorizations(r.onAccountGetAuthorizations)
d.OnAccountResetAuthorization(r.onAccountResetAuthorization)
d.OnAccountGetPasswordSettings(r.onAccountGetPasswordSettings)
d.OnAccountUpdatePasswordSettings(r.onAccountUpdatePasswordSettings)
d.OnAccountConfirmPasswordEmail(r.onAccountConfirmPasswordEmail)
d.OnAccountResendPasswordEmail(r.onAccountResendPasswordEmail)
d.OnAccountCancelPasswordEmail(r.onAccountCancelPasswordEmail)
d.OnAccountSendVerifyEmailCode(r.onAccountSendVerifyEmailCode)
d.OnAccountVerifyEmail(r.onAccountVerifyEmail)
d.OnAccountGetDefaultEmojiStatuses(r.onAccountGetDefaultEmojiStatuses)
d.OnAccountGetCollectibleEmojiStatuses(func(ctx context.Context, hash int64) (tg.AccountEmojiStatusesClass, error) {
registerRPC[*tg.AccountSendChangePhoneCodeRequest](d, tlprofile.SemanticMethodAccountSendChangePhoneCode, func(ctx context.Context, layerRequest *tg.AccountSendChangePhoneCodeRequest) (any, error) {
return r.onAccountSendChangePhoneCode(ctx, layerRequest)
})
registerRPC[*tg.AccountChangePhoneRequest](d, tlprofile.SemanticMethodAccountChangePhone, func(ctx context.Context, layerRequest *tg.AccountChangePhoneRequest) (any, error) {
return r.onAccountChangePhone(ctx, layerRequest)
})
registerRPC[*tg.AccountCheckUsernameRequest](d, tlprofile.SemanticMethodAccountCheckUsername, func(ctx context.Context, layerRequest *tg.AccountCheckUsernameRequest) (any, error) {
return r.onAccountCheckUsername(ctx, layerRequest.
Username)
})
registerRPC[*tg.AccountUpdateProfileRequest](d, tlprofile.SemanticMethodAccountUpdateProfile, func(ctx context.Context, layerRequest *tg.AccountUpdateProfileRequest) (any, error) {
return r.onAccountUpdateProfile(ctx, layerRequest)
})
registerRPC[*tg.AccountUpdateUsernameRequest](d, tlprofile.SemanticMethodAccountUpdateUsername, func(ctx context.Context, layerRequest *tg.AccountUpdateUsernameRequest) (any, error) {
return r.onAccountUpdateUsername(ctx, layerRequest.
Username)
})
registerRPC[*tg.AccountUpdateBirthdayRequest](d, tlprofile.SemanticMethodAccountUpdateBirthday, func(ctx context.Context, layerRequest *tg.AccountUpdateBirthdayRequest) (any, error) {
return r.onAccountUpdateBirthday(ctx, layerRequest)
})
registerRPC[*tg.AccountUpdatePersonalChannelRequest](d, tlprofile.SemanticMethodAccountUpdatePersonalChannel, func(ctx context.Context, layerRequest *tg.AccountUpdatePersonalChannelRequest) (any, error) {
return r.onAccountUpdatePersonalChannel(ctx, layerRequest.
Channel)
})
registerRPC[*tg.AccountGetPasswordRequest](d, tlprofile.SemanticMethodAccountGetPassword, func(ctx context.Context, layerRequest *tg.AccountGetPasswordRequest) (any, error) {
return r.onAccountGetPassword(ctx)
})
registerRPC[*tg.AccountGetNotifySettingsRequest](d, tlprofile.SemanticMethodAccountGetNotifySettings, func(ctx context.Context, layerRequest *tg.AccountGetNotifySettingsRequest) (any, error) {
return r.onAccountGetNotifySettings(ctx, layerRequest.
Peer)
})
registerRPC[*tg.AccountUpdateNotifySettingsRequest](d, tlprofile.SemanticMethodAccountUpdateNotifySettings, func(ctx context.Context, layerRequest *tg.AccountUpdateNotifySettingsRequest) (any, error) {
return r.onAccountUpdateNotifySettings(ctx, layerRequest)
})
registerRPC[*tg.AccountResetNotifySettingsRequest](d, tlprofile.SemanticMethodAccountResetNotifySettings, func(ctx context.Context, layerRequest *tg.AccountResetNotifySettingsRequest) (any, error) {
return r.onAccountResetNotifySettings(ctx)
})
registerRPC[*tg.AccountGetPrivacyRequest](d, tlprofile.SemanticMethodAccountGetPrivacy, func(ctx context.Context, layerRequest *tg.AccountGetPrivacyRequest) (any, error) {
return r.onAccountGetPrivacy(ctx, layerRequest.
Key)
})
registerRPC[*tg.AccountSetPrivacyRequest](d, tlprofile.SemanticMethodAccountSetPrivacy, func(ctx context.Context, layerRequest *tg.AccountSetPrivacyRequest) (any, error) {
return r.onAccountSetPrivacy(ctx, layerRequest)
})
registerRPC[*tg.AccountGetAuthorizationsRequest](d, tlprofile.SemanticMethodAccountGetAuthorizations, func(ctx context.Context, layerRequest *tg.AccountGetAuthorizationsRequest) (any, error) {
return r.onAccountGetAuthorizations(ctx)
})
registerRPC[*tg.AccountResetAuthorizationRequest](d, tlprofile.SemanticMethodAccountResetAuthorization, func(ctx context.Context, layerRequest *tg.AccountResetAuthorizationRequest) (any, error) {
return r.onAccountResetAuthorization(ctx, layerRequest.
Hash)
})
registerRPC[*tg.AccountGetPasswordSettingsRequest](d, tlprofile.SemanticMethodAccountGetPasswordSettings, func(ctx context.Context, layerRequest *tg.AccountGetPasswordSettingsRequest) (any, error) {
return r.onAccountGetPasswordSettings(ctx, layerRequest.
Password)
})
registerRPC[*tg.AccountUpdatePasswordSettingsRequest](d, tlprofile.SemanticMethodAccountUpdatePasswordSettings, func(ctx context.Context, layerRequest *tg.AccountUpdatePasswordSettingsRequest) (any, error) {
return r.onAccountUpdatePasswordSettings(ctx, layerRequest)
})
registerRPC[*tg.AccountConfirmPasswordEmailRequest](d, tlprofile.SemanticMethodAccountConfirmPasswordEmail, func(ctx context.Context, layerRequest *tg.AccountConfirmPasswordEmailRequest) (any, error) {
return r.onAccountConfirmPasswordEmail(ctx, layerRequest.
Code)
})
registerRPC[*tg.AccountResendPasswordEmailRequest](d, tlprofile.SemanticMethodAccountResendPasswordEmail, func(ctx context.Context, layerRequest *tg.AccountResendPasswordEmailRequest) (any, error) {
return r.onAccountResendPasswordEmail(ctx)
})
registerRPC[*tg.AccountCancelPasswordEmailRequest](d, tlprofile.SemanticMethodAccountCancelPasswordEmail, func(ctx context.Context, layerRequest *tg.AccountCancelPasswordEmailRequest) (any, error) {
return r.onAccountCancelPasswordEmail(ctx)
})
registerRPC[*tg.AccountSendVerifyEmailCodeRequest](d, tlprofile.SemanticMethodAccountSendVerifyEmailCode, func(ctx context.Context, layerRequest *tg.AccountSendVerifyEmailCodeRequest) (any, error) {
return r.onAccountSendVerifyEmailCode(ctx, layerRequest)
})
registerRPC[*tg.AccountVerifyEmailRequest](d, tlprofile.SemanticMethodAccountVerifyEmail, func(ctx context.Context, layerRequest *tg.AccountVerifyEmailRequest) (any, error) {
return r.onAccountVerifyEmail(ctx, layerRequest)
})
registerRPC[*tg.AccountGetDefaultEmojiStatusesRequest](d, tlprofile.SemanticMethodAccountGetDefaultEmojiStatuses, func(ctx context.Context, layerRequest *tg.AccountGetDefaultEmojiStatusesRequest) (any, error) {
return r.onAccountGetDefaultEmojiStatuses(ctx, layerRequest.
Hash)
})
registerRPC[*tg.AccountGetCollectibleEmojiStatusesRequest](d, tlprofile.SemanticMethodAccountGetCollectibleEmojiStatuses, func(ctx context.Context, layerRequest *tg.AccountGetCollectibleEmojiStatusesRequest) (any, error) {
hash := layerRequest.
Hash
_ = hash
return tdesktop.CollectibleEmojiStatuses(), nil
})
d.OnAccountGetDefaultGroupPhotoEmojis(func(ctx context.Context, hash int64) (tg.EmojiListClass, error) {
registerRPC[*tg.AccountGetDefaultGroupPhotoEmojisRequest](d, tlprofile.SemanticMethodAccountGetDefaultGroupPhotoEmojis, func(ctx context.Context, layerRequest *tg.AccountGetDefaultGroupPhotoEmojisRequest) (any, error) {
hash := layerRequest.
Hash
_ = hash
return tdesktop.DefaultGroupPhotoEmojis(), nil
})
d.OnAccountGetConnectedBots(r.onAccountGetConnectedBots)
d.OnAccountUpdateBusinessWorkHours(r.onAccountUpdateBusinessWorkHours)
d.OnAccountUpdateBusinessLocation(r.onAccountUpdateBusinessLocation)
d.OnAccountUpdateBusinessIntro(r.onAccountUpdateBusinessIntro)
d.OnAccountUpdateBusinessGreetingMessage(r.onAccountUpdateBusinessGreetingMessage)
d.OnAccountUpdateBusinessAwayMessage(r.onAccountUpdateBusinessAwayMessage)
d.OnAccountGetBusinessChatLinks(r.onAccountGetBusinessChatLinks)
d.OnAccountCreateBusinessChatLink(r.onAccountCreateBusinessChatLink)
d.OnAccountEditBusinessChatLink(r.onAccountEditBusinessChatLink)
d.OnAccountDeleteBusinessChatLink(r.onAccountDeleteBusinessChatLink)
d.OnAccountResolveBusinessChatLink(r.onAccountResolveBusinessChatLink)
d.OnAccountUpdateConnectedBot(r.onAccountUpdateConnectedBot)
d.OnAccountGetBotBusinessConnection(func(ctx context.Context, connectionID string) (tg.UpdatesClass, error) {
registerRPC[*tg.AccountGetConnectedBotsRequest](d, tlprofile.SemanticMethodAccountGetConnectedBots, func(ctx context.Context, layerRequest *tg.AccountGetConnectedBotsRequest) (any, error) {
return r.onAccountGetConnectedBots(ctx)
})
registerRPC[*tg.AccountUpdateBusinessWorkHoursRequest](d, tlprofile.SemanticMethodAccountUpdateBusinessWorkHours, func(ctx context.Context, layerRequest *tg.AccountUpdateBusinessWorkHoursRequest) (any, error) {
return r.onAccountUpdateBusinessWorkHours(ctx, layerRequest)
})
registerRPC[*tg.AccountUpdateBusinessLocationRequest](d, tlprofile.SemanticMethodAccountUpdateBusinessLocation, func(ctx context.Context, layerRequest *tg.AccountUpdateBusinessLocationRequest) (any, error) {
return r.onAccountUpdateBusinessLocation(ctx, layerRequest)
})
registerRPC[*tg.AccountUpdateBusinessIntroRequest](d, tlprofile.SemanticMethodAccountUpdateBusinessIntro, func(ctx context.Context, layerRequest *tg.AccountUpdateBusinessIntroRequest) (any, error) {
return r.onAccountUpdateBusinessIntro(ctx, layerRequest)
})
registerRPC[*tg.AccountUpdateBusinessGreetingMessageRequest](d, tlprofile.SemanticMethodAccountUpdateBusinessGreetingMessage, func(ctx context.Context, layerRequest *tg.AccountUpdateBusinessGreetingMessageRequest) (any, error) {
return r.onAccountUpdateBusinessGreetingMessage(ctx, layerRequest)
})
registerRPC[*tg.AccountUpdateBusinessAwayMessageRequest](d, tlprofile.SemanticMethodAccountUpdateBusinessAwayMessage, func(ctx context.Context, layerRequest *tg.AccountUpdateBusinessAwayMessageRequest) (any, error) {
return r.onAccountUpdateBusinessAwayMessage(ctx, layerRequest)
})
registerRPC[*tg.AccountGetBusinessChatLinksRequest](d, tlprofile.SemanticMethodAccountGetBusinessChatLinks, func(ctx context.Context, layerRequest *tg.AccountGetBusinessChatLinksRequest) (any, error) {
return r.onAccountGetBusinessChatLinks(ctx)
})
registerRPC[*tg.AccountCreateBusinessChatLinkRequest](d, tlprofile.SemanticMethodAccountCreateBusinessChatLink, func(ctx context.Context, layerRequest *tg.AccountCreateBusinessChatLinkRequest) (any, error) {
return r.onAccountCreateBusinessChatLink(ctx, layerRequest.
Link)
})
registerRPC[*tg.AccountEditBusinessChatLinkRequest](d, tlprofile.SemanticMethodAccountEditBusinessChatLink, func(ctx context.Context, layerRequest *tg.AccountEditBusinessChatLinkRequest) (any, error) {
return r.onAccountEditBusinessChatLink(ctx, layerRequest)
})
registerRPC[*tg.AccountDeleteBusinessChatLinkRequest](d, tlprofile.SemanticMethodAccountDeleteBusinessChatLink, func(ctx context.Context, layerRequest *tg.AccountDeleteBusinessChatLinkRequest) (any, error) {
return r.onAccountDeleteBusinessChatLink(ctx, layerRequest.
Slug)
})
registerRPC[*tg.AccountResolveBusinessChatLinkRequest](d, tlprofile.SemanticMethodAccountResolveBusinessChatLink, func(ctx context.Context, layerRequest *tg.AccountResolveBusinessChatLinkRequest) (any, error) {
return r.onAccountResolveBusinessChatLink(ctx, layerRequest.
Slug)
})
registerRPC[*tg.AccountUpdateConnectedBotRequest](d, tlprofile.SemanticMethodAccountUpdateConnectedBot, func(ctx context.Context, layerRequest *tg.AccountUpdateConnectedBotRequest) (any, error) {
return r.onAccountUpdateConnectedBot(ctx, layerRequest)
})
registerRPC[*tg.AccountGetBotBusinessConnectionRequest](d, tlprofile.SemanticMethodAccountGetBotBusinessConnection, func(ctx context.Context, layerRequest *tg.AccountGetBotBusinessConnectionRequest) (any, error) {
connectionID := layerRequest.
ConnectionID
_ = connectionID
if _, _, err := r.currentUserID(ctx); err != nil {
return nil, internalErr()
}
return nil, tgerr400("BOT_BUSINESS_MISSING")
})
d.OnAccountToggleConnectedBotPaused(r.onAccountToggleConnectedBotPaused)
d.OnAccountDisablePeerConnectedBot(r.onAccountDisablePeerConnectedBot)
d.OnAccountGetReactionsNotifySettings(r.onAccountGetReactionsNotifySettings)
d.OnAccountSetReactionsNotifySettings(r.onAccountSetReactionsNotifySettings)
d.OnAccountGetContactSignUpNotification(r.onAccountGetContactSignUpNotification)
d.OnAccountSetContactSignUpNotification(r.onAccountSetContactSignUpNotification)
d.OnAccountGetThemes(r.onAccountGetThemes)
d.OnAccountGetChatThemes(func(ctx context.Context, hash int64) (tg.AccountThemesClass, error) {
registerRPC[*tg.AccountToggleConnectedBotPausedRequest](d, tlprofile.SemanticMethodAccountToggleConnectedBotPaused, func(ctx context.Context, layerRequest *tg.AccountToggleConnectedBotPausedRequest) (any, error) {
return r.onAccountToggleConnectedBotPaused(ctx, layerRequest)
})
registerRPC[*tg.AccountDisablePeerConnectedBotRequest](d, tlprofile.SemanticMethodAccountDisablePeerConnectedBot, func(ctx context.Context, layerRequest *tg.AccountDisablePeerConnectedBotRequest) (any, error) {
return r.onAccountDisablePeerConnectedBot(ctx, layerRequest.
Peer)
})
registerRPC[*tg.AccountGetReactionsNotifySettingsRequest](d, tlprofile.SemanticMethodAccountGetReactionsNotifySettings, func(ctx context.Context, layerRequest *tg.AccountGetReactionsNotifySettingsRequest) (any, error) {
return r.onAccountGetReactionsNotifySettings(ctx)
})
registerRPC[*tg.AccountSetReactionsNotifySettingsRequest](d, tlprofile.SemanticMethodAccountSetReactionsNotifySettings, func(ctx context.Context, layerRequest *tg.AccountSetReactionsNotifySettingsRequest) (any, error) {
return r.onAccountSetReactionsNotifySettings(ctx, layerRequest.
Settings)
})
registerRPC[*tg.AccountGetContactSignUpNotificationRequest](d, tlprofile.SemanticMethodAccountGetContactSignUpNotification, func(ctx context.Context, layerRequest *tg.AccountGetContactSignUpNotificationRequest) (any, error) {
return r.onAccountGetContactSignUpNotification(ctx)
})
registerRPC[*tg.AccountSetContactSignUpNotificationRequest](d, tlprofile.SemanticMethodAccountSetContactSignUpNotification, func(ctx context.Context, layerRequest *tg.AccountSetContactSignUpNotificationRequest) (any, error) {
return r.onAccountSetContactSignUpNotification(ctx, layerRequest.
Silent)
})
registerRPC[*tg.AccountGetThemesRequest](d, tlprofile.SemanticMethodAccountGetThemes, func(ctx context.Context, layerRequest *tg.AccountGetThemesRequest) (any, error) {
return r.onAccountGetThemes(ctx, layerRequest)
})
registerRPC[*tg.AccountGetChatThemesRequest](d, tlprofile.SemanticMethodAccountGetChatThemes, func(ctx context.Context, layerRequest *tg.AccountGetChatThemesRequest) (any, error) {
hash := layerRequest.
Hash
_ = hash
if _, _, err := r.currentUserID(ctx); err != nil {
return nil, internalErr()
}
return tdesktop.ChatThemes(hash), nil
})
registerRPC[
// 自定义云主题(Create a New Theme 全链路):upload→create→update→save→install→get。
d.OnAccountUploadTheme(r.onAccountUploadTheme)
d.OnAccountCreateTheme(r.onAccountCreateTheme)
d.OnAccountUpdateTheme(r.onAccountUpdateTheme)
d.OnAccountSaveTheme(r.onAccountSaveTheme)
d.OnAccountInstallTheme(r.onAccountInstallTheme)
d.OnAccountGetTheme(r.onAccountGetTheme)
d.OnAccountGetWallPapers(func(ctx context.Context, hash int64) (tg.AccountWallPapersClass, error) {
*tg.AccountUploadThemeRequest](d, tlprofile.SemanticMethodAccountUploadTheme, func(ctx context.Context, layerRequest *tg.AccountUploadThemeRequest) (any, error) {
return r.onAccountUploadTheme(ctx, layerRequest)
})
registerRPC[*tg.AccountCreateThemeRequest](d, tlprofile.SemanticMethodAccountCreateTheme, func(ctx context.Context, layerRequest *tg.AccountCreateThemeRequest) (any, error) {
return r.onAccountCreateTheme(ctx, layerRequest)
})
registerRPC[*tg.AccountUpdateThemeRequest](d, tlprofile.SemanticMethodAccountUpdateTheme, func(ctx context.Context, layerRequest *tg.AccountUpdateThemeRequest) (any, error) {
return r.onAccountUpdateTheme(ctx, layerRequest)
})
registerRPC[*tg.AccountSaveThemeRequest](d, tlprofile.SemanticMethodAccountSaveTheme, func(ctx context.Context, layerRequest *tg.AccountSaveThemeRequest) (any, error) {
return r.onAccountSaveTheme(ctx, layerRequest)
})
registerRPC[*tg.AccountInstallThemeRequest](d, tlprofile.SemanticMethodAccountInstallTheme, func(ctx context.Context, layerRequest *tg.AccountInstallThemeRequest) (any, error) {
return r.onAccountInstallTheme(ctx, layerRequest)
})
registerRPC[*tg.AccountGetThemeRequest](d, tlprofile.SemanticMethodAccountGetTheme, func(ctx context.Context, layerRequest *tg.AccountGetThemeRequest) (any, error) {
return r.onAccountGetTheme(ctx, layerRequest)
})
registerRPC[*tg.AccountGetWallPapersRequest](d, tlprofile.SemanticMethodAccountGetWallPapers, func(ctx context.Context, layerRequest *tg.AccountGetWallPapersRequest) (any, error) {
hash := layerRequest.
Hash
_ = hash
if _, _, err := r.currentUserID(ctx); err != nil {
return nil, internalErr()
}
return tdesktop.WallPapers(hash), nil
})
d.OnAccountGetWallPaper(func(ctx context.Context, wallpaper tg.InputWallPaperClass) (tg.WallPaperClass, error) {
registerRPC[*tg.AccountGetWallPaperRequest](d, tlprofile.SemanticMethodAccountGetWallPaper, func(ctx context.Context, layerRequest *tg.AccountGetWallPaperRequest) (any, error) {
wallpaper := layerRequest.
Wallpaper
_ = wallpaper
if _, _, err := r.currentUserID(ctx); err != nil {
return nil, internalErr()
}
@ -109,7 +251,11 @@ func (r *Router) registerAccount(d *tg.ServerDispatcher) {
}
return found, nil
})
d.OnAccountGetMultiWallPapers(func(ctx context.Context, wallpapers []tg.InputWallPaperClass) ([]tg.WallPaperClass, error) {
registerRPC[*tg.AccountGetMultiWallPapersRequest](d, tlprofile.SemanticMethodAccountGetMultiWallPapers, func(ctx context.Context, layerRequest *tg.AccountGetMultiWallPapersRequest) (any, error) {
wallpapers := layerRequest.
Wallpapers
_ = wallpapers
if _, _, err := r.currentUserID(ctx); err != nil {
return nil, internalErr()
}
@ -122,7 +268,7 @@ func (r *Router) registerAccount(d *tg.ServerDispatcher) {
}
return found, nil
})
d.OnAccountSaveWallPaper(func(ctx context.Context, req *tg.AccountSaveWallPaperRequest) (bool, error) {
registerRPC[*tg.AccountSaveWallPaperRequest](d, tlprofile.SemanticMethodAccountSaveWallPaper, func(ctx context.Context, req *tg.AccountSaveWallPaperRequest) (any, error) {
if _, _, err := r.currentUserID(ctx); err != nil {
return false, internalErr()
}
@ -134,7 +280,7 @@ func (r *Router) registerAccount(d *tg.ServerDispatcher) {
}
return true, nil
})
d.OnAccountInstallWallPaper(func(ctx context.Context, req *tg.AccountInstallWallPaperRequest) (bool, error) {
registerRPC[*tg.AccountInstallWallPaperRequest](d, tlprofile.SemanticMethodAccountInstallWallPaper, func(ctx context.Context, req *tg.AccountInstallWallPaperRequest) (any, error) {
if _, _, err := r.currentUserID(ctx); err != nil {
return false, internalErr()
}
@ -146,13 +292,13 @@ func (r *Router) registerAccount(d *tg.ServerDispatcher) {
}
return true, nil
})
d.OnAccountResetWallPapers(func(ctx context.Context) (bool, error) {
registerRPC[*tg.AccountResetWallPapersRequest](d, tlprofile.SemanticMethodAccountResetWallPapers, func(ctx context.Context, layerRequest *tg.AccountResetWallPapersRequest) (any, error) {
if _, _, err := r.currentUserID(ctx); err != nil {
return false, internalErr()
}
return true, nil
})
d.OnAccountGetUniqueGiftChatThemes(func(ctx context.Context, req *tg.AccountGetUniqueGiftChatThemesRequest) (tg.AccountChatThemesClass, error) {
registerRPC[*tg.AccountGetUniqueGiftChatThemesRequest](d, tlprofile.SemanticMethodAccountGetUniqueGiftChatThemes, func(ctx context.Context, req *tg.AccountGetUniqueGiftChatThemesRequest) (any, error) {
if _, _, err := r.currentUserID(ctx); err != nil {
return nil, internalErr()
}
@ -161,71 +307,151 @@ func (r *Router) registerAccount(d *tg.ServerDispatcher) {
}
return tdesktop.UniqueGiftChatThemes(req.Hash), nil
})
d.OnAccountGetRecentEmojiStatuses(func(ctx context.Context, hash int64) (tg.AccountEmojiStatusesClass, error) {
registerRPC[*tg.AccountGetRecentEmojiStatusesRequest](d, tlprofile.SemanticMethodAccountGetRecentEmojiStatuses, func(ctx context.Context, layerRequest *tg.AccountGetRecentEmojiStatusesRequest) (any, error) {
hash := layerRequest.
Hash
_ = hash
return &tg.AccountEmojiStatuses{Hash: 0, Statuses: []tg.EmojiStatusClass{}}, nil
})
d.OnAccountClearRecentEmojiStatuses(func(ctx context.Context) (bool, error) {
registerRPC[*tg.AccountClearRecentEmojiStatusesRequest](d, tlprofile.SemanticMethodAccountClearRecentEmojiStatuses, func(ctx context.Context, layerRequest *tg.AccountClearRecentEmojiStatusesRequest) (any, error) {
return true, nil
})
d.OnAccountUpdateEmojiStatus(r.onAccountUpdateEmojiStatus)
d.OnAccountUpdateColor(r.onAccountUpdateColor)
d.OnAccountGetDefaultProfilePhotoEmojis(r.onAccountGetDefaultProfilePhotoEmojis)
d.OnAccountGetDefaultBackgroundEmojis(r.onAccountGetDefaultBackgroundEmojis)
d.OnAccountGetChannelDefaultEmojiStatuses(func(ctx context.Context, hash int64) (tg.AccountEmojiStatusesClass, error) {
registerRPC[*tg.AccountUpdateEmojiStatusRequest](d, tlprofile.SemanticMethodAccountUpdateEmojiStatus, func(ctx context.Context, layerRequest *tg.AccountUpdateEmojiStatusRequest) (any, error) {
return r.onAccountUpdateEmojiStatus(ctx, layerRequest.
EmojiStatus)
})
registerRPC[*tg.AccountUpdateColorRequest](d, tlprofile.SemanticMethodAccountUpdateColor, func(ctx context.Context, layerRequest *tg.AccountUpdateColorRequest) (any, error) {
return r.onAccountUpdateColor(ctx, layerRequest)
})
registerRPC[*tg.AccountGetDefaultProfilePhotoEmojisRequest](d, tlprofile.SemanticMethodAccountGetDefaultProfilePhotoEmojis, func(ctx context.Context, layerRequest *tg.AccountGetDefaultProfilePhotoEmojisRequest) (any, error) {
return r.onAccountGetDefaultProfilePhotoEmojis(ctx, layerRequest.
Hash)
})
registerRPC[*tg.AccountGetDefaultBackgroundEmojisRequest](d, tlprofile.SemanticMethodAccountGetDefaultBackgroundEmojis, func(ctx context.Context, layerRequest *tg.AccountGetDefaultBackgroundEmojisRequest) (any, error) {
return r.onAccountGetDefaultBackgroundEmojis(ctx, layerRequest.
Hash)
})
registerRPC[*tg.AccountGetChannelDefaultEmojiStatusesRequest](d, tlprofile.SemanticMethodAccountGetChannelDefaultEmojiStatuses, func(ctx context.Context, layerRequest *tg.AccountGetChannelDefaultEmojiStatusesRequest) (any, error) {
hash := layerRequest.
Hash
_ = hash
return &tg.AccountEmojiStatuses{Hash: 0, Statuses: []tg.EmojiStatusClass{}}, nil
})
d.OnAccountGetChannelRestrictedStatusEmojis(func(ctx context.Context, hash int64) (tg.EmojiListClass, error) {
registerRPC[*tg.AccountGetChannelRestrictedStatusEmojisRequest](d, tlprofile.SemanticMethodAccountGetChannelRestrictedStatusEmojis, func(ctx context.Context, layerRequest *tg.AccountGetChannelRestrictedStatusEmojisRequest) (any, error) {
hash := layerRequest.
Hash
_ = hash
return tdesktop.DefaultGroupPhotoEmojis(), nil
})
d.OnAccountSetContentSettings(r.onAccountSetContentSettings)
d.OnAccountGetContentSettings(r.onAccountGetContentSettings)
d.OnAccountGetGlobalPrivacySettings(r.onAccountGetGlobalPrivacySettings)
d.OnAccountSetGlobalPrivacySettings(r.onAccountSetGlobalPrivacySettings)
d.OnAccountGetPasskeys(r.onAccountGetPasskeys)
d.OnAccountInitPasskeyRegistration(r.onAccountInitPasskeyRegistration)
d.OnAccountRegisterPasskey(r.onAccountRegisterPasskey)
d.OnAccountDeletePasskey(r.onAccountDeletePasskey)
d.OnAccountGetWebAuthorizations(func(ctx context.Context) (*tg.AccountWebAuthorizations, error) {
registerRPC[*tg.AccountSetContentSettingsRequest](d, tlprofile.SemanticMethodAccountSetContentSettings, func(ctx context.Context, layerRequest *tg.AccountSetContentSettingsRequest) (any, error) {
return r.onAccountSetContentSettings(ctx, layerRequest)
})
registerRPC[*tg.AccountGetContentSettingsRequest](d, tlprofile.SemanticMethodAccountGetContentSettings, func(ctx context.Context, layerRequest *tg.AccountGetContentSettingsRequest) (any, error) {
return r.onAccountGetContentSettings(ctx)
})
registerRPC[*tg.AccountGetGlobalPrivacySettingsRequest](d, tlprofile.SemanticMethodAccountGetGlobalPrivacySettings, func(ctx context.Context, layerRequest *tg.AccountGetGlobalPrivacySettingsRequest) (any, error) {
return r.onAccountGetGlobalPrivacySettings(ctx)
})
registerRPC[*tg.AccountSetGlobalPrivacySettingsRequest](d, tlprofile.SemanticMethodAccountSetGlobalPrivacySettings, func(ctx context.Context, layerRequest *tg.AccountSetGlobalPrivacySettingsRequest) (any, error) {
return r.onAccountSetGlobalPrivacySettings(ctx, layerRequest.
Settings)
})
registerRPC[*tg.AccountGetPasskeysRequest](d, tlprofile.SemanticMethodAccountGetPasskeys, func(ctx context.Context, layerRequest *tg.AccountGetPasskeysRequest) (any, error) {
return r.onAccountGetPasskeys(ctx)
})
registerRPC[*tg.AccountInitPasskeyRegistrationRequest](d, tlprofile.SemanticMethodAccountInitPasskeyRegistration, func(ctx context.Context, layerRequest *tg.AccountInitPasskeyRegistrationRequest) (any, error) {
return r.onAccountInitPasskeyRegistration(ctx)
})
registerRPC[*tg.AccountRegisterPasskeyRequest](d, tlprofile.SemanticMethodAccountRegisterPasskey, func(ctx context.Context, layerRequest *tg.AccountRegisterPasskeyRequest) (any, error) {
return r.onAccountRegisterPasskey(ctx, layerRequest.
Credential)
})
registerRPC[*tg.AccountDeletePasskeyRequest](d, tlprofile.SemanticMethodAccountDeletePasskey, func(ctx context.Context, layerRequest *tg.AccountDeletePasskeyRequest) (any, error) {
return r.onAccountDeletePasskey(ctx, layerRequest.
ID)
})
registerRPC[*tg.AccountGetWebAuthorizationsRequest](d, tlprofile.SemanticMethodAccountGetWebAuthorizations, func(ctx context.Context, layerRequest *tg.AccountGetWebAuthorizationsRequest) (any, error) {
return tdesktop.WebAuthorizations(), nil
})
d.OnAccountResetWebAuthorization(func(ctx context.Context, hash int64) (bool, error) {
registerRPC[*tg.AccountResetWebAuthorizationRequest](d, tlprofile.SemanticMethodAccountResetWebAuthorization, func(ctx context.Context, layerRequest *tg.AccountResetWebAuthorizationRequest) (any, error) {
hash := layerRequest.
Hash
_ = hash
return true, nil
})
d.OnAccountResetWebAuthorizations(func(ctx context.Context) (bool, error) {
registerRPC[*tg.AccountResetWebAuthorizationsRequest](d, tlprofile.SemanticMethodAccountResetWebAuthorizations, func(ctx context.Context, layerRequest *tg.AccountResetWebAuthorizationsRequest) (
// account.getWebBrowserSettingstelesrv 不接入网页浏览器web bot集成返回空设置
// 无内置浏览器例外、不强制外部浏览器。Android 启动时会拉取,缺它会反复 500
// NOT_IMPLEMENTED。空结构 Hash=0客户端按默认内置浏览器、无例外渲染。
any, error) {
return true, nil
})
// account.getWebBrowserSettingstelesrv 不接入网页浏览器web bot集成返回空设置
// 无内置浏览器例外、不强制外部浏览器。Android 启动时会拉取,缺它会反复 500
// NOT_IMPLEMENTED。空结构 Hash=0客户端按默认内置浏览器、无例外渲染。
d.OnAccountGetWebBrowserSettings(func(ctx context.Context, hash int64) (tg.AccountWebBrowserSettingsClass, error) {
registerRPC[*tg.AccountGetWebBrowserSettingsRequest](d, tlprofile.SemanticMethodAccountGetWebBrowserSettings, func(ctx context.Context, layerRequest *tg.AccountGetWebBrowserSettingsRequest) (any, error) {
hash := layerRequest.
Hash
_ = hash
return &tg.AccountWebBrowserSettings{}, nil
})
d.OnAccountGetNotifyExceptions(r.onAccountGetNotifyExceptions)
d.OnAccountGetAutoDownloadSettings(func(ctx context.Context) (*tg.AccountAutoDownloadSettings, error) {
registerRPC[*tg.AccountGetNotifyExceptionsRequest](d, tlprofile.SemanticMethodAccountGetNotifyExceptions, func(ctx context.Context, layerRequest *tg.AccountGetNotifyExceptionsRequest) (any, error) {
return r.onAccountGetNotifyExceptions(ctx, layerRequest)
})
registerRPC[*tg.AccountGetAutoDownloadSettingsRequest](d, tlprofile.SemanticMethodAccountGetAutoDownloadSettings, func(ctx context.Context, layerRequest *tg.AccountGetAutoDownloadSettingsRequest) (any, error) {
return tdesktop.AutoDownloadSettings(), nil
})
d.OnAccountSaveAutoDownloadSettings(func(ctx context.Context, req *tg.AccountSaveAutoDownloadSettingsRequest) (bool, error) {
registerRPC[*tg.AccountSaveAutoDownloadSettingsRequest](d, tlprofile.SemanticMethodAccountSaveAutoDownloadSettings, func(ctx context.Context, req *tg.AccountSaveAutoDownloadSettingsRequest) (any, error) {
return true, nil
})
d.OnAccountSaveMusic(r.onAccountSaveMusic)
d.OnAccountGetSavedMusicIDs(r.onAccountGetSavedMusicIDs)
d.OnAccountGetSavedRingtones(func(ctx context.Context, hash int64) (tg.AccountSavedRingtonesClass, error) {
registerRPC[*tg.AccountSaveMusicRequest](d, tlprofile.SemanticMethodAccountSaveMusic, func(ctx context.Context, layerRequest *tg.AccountSaveMusicRequest) (any, error) {
return r.onAccountSaveMusic(ctx, layerRequest)
})
registerRPC[*tg.AccountGetSavedMusicIDsRequest](d, tlprofile.SemanticMethodAccountGetSavedMusicIDs, func(ctx context.Context, layerRequest *tg.AccountGetSavedMusicIDsRequest) (any, error) {
return r.onAccountGetSavedMusicIDs(ctx, layerRequest.
Hash)
})
registerRPC[*tg.AccountGetSavedRingtonesRequest](d, tlprofile.SemanticMethodAccountGetSavedRingtones, func(ctx context.Context, layerRequest *tg.AccountGetSavedRingtonesRequest) (any, error) {
hash := layerRequest.
Hash
_ = hash
if _, _, err := r.currentUserID(ctx); err != nil {
return nil, internalErr()
}
return &tg.AccountSavedRingtones{Hash: 0, Ringtones: []tg.DocumentClass{}}, nil
})
d.OnAccountGetAccountTTL(r.onAccountGetAccountTTL)
d.OnAccountSetAccountTTL(r.onAccountSetAccountTTL)
d.OnAccountSetAuthorizationTTL(func(ctx context.Context, authorizationttldays int) (bool, error) {
registerRPC[*tg.AccountGetAccountTTLRequest](d, tlprofile.SemanticMethodAccountGetAccountTTL, func(ctx context.Context, layerRequest *tg.AccountGetAccountTTLRequest) (any, error) {
return r.onAccountGetAccountTTL(ctx)
})
registerRPC[*tg.AccountSetAccountTTLRequest](d, tlprofile.SemanticMethodAccountSetAccountTTL, func(ctx context.Context, layerRequest *tg.AccountSetAccountTTLRequest) (any, error) {
return r.onAccountSetAccountTTL(ctx, layerRequest.
TTL)
})
registerRPC[*tg.AccountSetAuthorizationTTLRequest](d, tlprofile.SemanticMethodAccountSetAuthorizationTTL, func(ctx context.Context, layerRequest *tg.AccountSetAuthorizationTTLRequest) (any, error) {
authorizationttldays := layerRequest.
AuthorizationTTLDays
_ = authorizationttldays
return true, nil
})
d.OnAccountChangeAuthorizationSettings(func(ctx context.Context, req *tg.AccountChangeAuthorizationSettingsRequest) (bool, error) {
registerRPC[*tg.AccountChangeAuthorizationSettingsRequest](d, tlprofile.SemanticMethodAccountChangeAuthorizationSettings, func(ctx context.Context, req *tg.AccountChangeAuthorizationSettingsRequest) (any, error) {
return true, nil
})
d.OnAccountResetPassword(r.onAccountResetPassword)
d.OnAccountDeclinePasswordReset(r.onAccountDeclinePasswordReset)
d.OnAccountUpdateStatus(r.onAccountUpdateStatus)
registerRPC[*tg.AccountResetPasswordRequest](d, tlprofile.SemanticMethodAccountResetPassword, func(ctx context.Context, layerRequest *tg.AccountResetPasswordRequest) (any, error) {
return r.onAccountResetPassword(ctx)
})
registerRPC[*tg.AccountDeclinePasswordResetRequest](d, tlprofile.SemanticMethodAccountDeclinePasswordReset, func(ctx context.Context, layerRequest *tg.AccountDeclinePasswordResetRequest) (any, error) {
return r.onAccountDeclinePasswordReset(ctx)
})
registerRPC[*tg.AccountUpdateStatusRequest](d, tlprofile.SemanticMethodAccountUpdateStatus, func(ctx context.Context, layerRequest *tg.AccountUpdateStatusRequest) (any, error) {
return r.onAccountUpdateStatus(ctx, layerRequest.
Offline)
})
}
func (r *Router) onAccountGetPassword(ctx context.Context) (*tg.AccountPassword, error) {
@ -1100,7 +1326,7 @@ func privacyErr(err error) error {
}
type accountReactionSettingsService interface {
GetReactionSettings(ctx context.Context, userID int64) (domain.AccountReactionSettings, error)
accountReactionSettingsReader
SetReactionsNotifySettings(ctx context.Context, userID int64, settings domain.ReactionsNotifySettings) (domain.AccountReactionSettings, error)
}

View file

@ -4,8 +4,8 @@ import (
"context"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appusers "telesrv/internal/app/users"

View file

@ -5,7 +5,7 @@ import (
"errors"
"strings"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -4,9 +4,9 @@ import (
"context"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap/zaptest"
appusers "telesrv/internal/app/users"

View file

@ -3,7 +3,7 @@ package rpc
import (
"context"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/compat/tdesktop"
"telesrv/internal/domain"

View file

@ -4,8 +4,8 @@ import (
"context"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appaccount "telesrv/internal/app/account"

View file

@ -5,7 +5,7 @@ import (
"go.uber.org/zap"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -5,8 +5,8 @@ import (
"testing"
"time"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appaccount "telesrv/internal/app/account"

View file

@ -4,8 +4,8 @@ import (
"context"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"telesrv/internal/domain"

View file

@ -4,9 +4,9 @@ import (
"context"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap/zaptest"
appaccount "telesrv/internal/app/account"

View file

@ -4,7 +4,7 @@ import (
"context"
"strings"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/compat/tdesktop"
"telesrv/internal/domain"

View file

@ -1,183 +0,0 @@
package rpc
import (
"context"
"github.com/gotd/td/bin"
"github.com/gotd/td/tg"
)
// DrKLO 12.8.1(Layer 227)发出的 theme 方法构造器比 gotd v0.158 的 schema 更新:
// gotd 的 ServerDispatcher 按构造器 id 匹配,这些「新」id 匹配不上而落到 fallback。
// 字段语义与 gotd 请求结构相同(仅 createTheme/updateTheme 的 settings 在线为单个对象、
// gotd 为 Vector;getTheme 多一个被忽略的 document_id),故这里按 DrKLO 字段序手动解码、
// 复用现有 handler。uploadTheme(0x1c3db333)/saveTheme(0xf257106c) 构造器与 gotd 一致,
// 无需 compat。
const (
legacyCreateThemeID = 0x8432c21f
legacyUpdateThemeID = 0x5cb367d5
legacyInstallThemeID = 0x7ae43737
legacyGetThemeID = 0x8d9d742b
)
// tryLegacyThemeRPC 在 fallback 中尝试处理 DrKLO 的新版 theme 构造器。
// handled=false 表示不是这些构造器,调用方继续原 fallback 流程。
func (r *Router) tryLegacyThemeRPC(ctx context.Context, b *bin.Buffer) (enc bin.Encoder, handled bool, err error) {
id, perr := b.PeekID()
if perr != nil {
return nil, false, nil
}
switch id {
case legacyCreateThemeID:
enc, err = r.legacyCreateTheme(ctx, b)
case legacyUpdateThemeID:
enc, err = r.legacyUpdateTheme(ctx, b)
case legacyInstallThemeID:
enc, err = r.legacyInstallTheme(ctx, b)
case legacyGetThemeID:
enc, err = r.legacyGetTheme(ctx, b)
default:
return nil, false, nil
}
return enc, true, err
}
func boolEncoder(v bool) bin.Encoder {
if v {
return &tg.BoolTrue{}
}
return &tg.BoolFalse{}
}
func (r *Router) legacyCreateTheme(ctx context.Context, b *bin.Buffer) (bin.Encoder, error) {
if _, err := b.ID(); err != nil {
return nil, inputConstructorInvalidErr()
}
flags, err := b.Int32()
if err != nil {
return nil, inputConstructorInvalidErr()
}
slug, err := b.String()
if err != nil {
return nil, inputConstructorInvalidErr()
}
title, err := b.String()
if err != nil {
return nil, inputConstructorInvalidErr()
}
req := &tg.AccountCreateThemeRequest{Slug: slug, Title: title}
if flags&(1<<2) != 0 {
doc, err := tg.DecodeInputDocument(b)
if err != nil {
return nil, inputConstructorInvalidErr()
}
req.SetDocument(doc)
}
if flags&(1<<3) != 0 {
var s tg.InputThemeSettings
if err := s.Decode(b); err != nil {
return nil, inputConstructorInvalidErr()
}
req.SetSettings([]tg.InputThemeSettings{s})
}
return r.onAccountCreateTheme(ctx, req)
}
func (r *Router) legacyUpdateTheme(ctx context.Context, b *bin.Buffer) (bin.Encoder, error) {
if _, err := b.ID(); err != nil {
return nil, inputConstructorInvalidErr()
}
flags, err := b.Int32()
if err != nil {
return nil, inputConstructorInvalidErr()
}
format, err := b.String()
if err != nil {
return nil, inputConstructorInvalidErr()
}
theme, err := tg.DecodeInputTheme(b)
if err != nil {
return nil, inputConstructorInvalidErr()
}
req := &tg.AccountUpdateThemeRequest{Format: format, Theme: theme}
if flags&(1<<0) != 0 {
slug, err := b.String()
if err != nil {
return nil, inputConstructorInvalidErr()
}
req.SetSlug(slug)
}
if flags&(1<<1) != 0 {
title, err := b.String()
if err != nil {
return nil, inputConstructorInvalidErr()
}
req.SetTitle(title)
}
if flags&(1<<2) != 0 {
doc, err := tg.DecodeInputDocument(b)
if err != nil {
return nil, inputConstructorInvalidErr()
}
req.SetDocument(doc)
}
if flags&(1<<3) != 0 {
var s tg.InputThemeSettings
if err := s.Decode(b); err != nil {
return nil, inputConstructorInvalidErr()
}
req.SetSettings([]tg.InputThemeSettings{s})
}
return r.onAccountUpdateTheme(ctx, req)
}
func (r *Router) legacyInstallTheme(ctx context.Context, b *bin.Buffer) (bin.Encoder, error) {
if _, err := b.ID(); err != nil {
return nil, inputConstructorInvalidErr()
}
flags, err := b.Int32()
if err != nil {
return nil, inputConstructorInvalidErr()
}
req := &tg.AccountInstallThemeRequest{}
if flags&(1<<0) != 0 {
req.SetDark(true)
}
// bit1 同时门控 format 与 theme(DrKLO 布局)。
if flags&(1<<1) != 0 {
format, err := b.String()
if err != nil {
return nil, inputConstructorInvalidErr()
}
theme, err := tg.DecodeInputTheme(b)
if err != nil {
return nil, inputConstructorInvalidErr()
}
req.SetFormat(format)
req.SetTheme(theme)
}
ok, err := r.onAccountInstallTheme(ctx, req)
if err != nil {
return nil, err
}
return boolEncoder(ok), nil
}
func (r *Router) legacyGetTheme(ctx context.Context, b *bin.Buffer) (bin.Encoder, error) {
if _, err := b.ID(); err != nil {
return nil, inputConstructorInvalidErr()
}
format, err := b.String()
if err != nil {
return nil, inputConstructorInvalidErr()
}
theme, err := tg.DecodeInputTheme(b)
if err != nil {
return nil, inputConstructorInvalidErr()
}
if _, err := b.Long(); err != nil { // document_id:被服务端忽略
return nil, inputConstructorInvalidErr()
}
req := &tg.AccountGetThemeRequest{Format: format, Theme: theme}
return r.onAccountGetTheme(ctx, req)
}

View file

@ -4,18 +4,24 @@ import (
"context"
"testing"
"github.com/gotd/td/bin"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap"
"go.uber.org/zap/zaptest/observer"
"telesrv/internal/domain"
)
const (
legacyCreateThemeID = 0x8432c21f
legacyUpdateThemeID = 0x5cb367d5
legacyInstallThemeID = 0x7ae43737
legacyGetThemeID = 0x8d9d742b
)
// TestLegacyThemeWireDispatch 验证 DrKLO theme 构造器经过 Router.Dispatch 的完整链路:
// layerwire 结构预检 -> gotd dispatcher fallback -> compat 解码 -> 现有 handler。
// 不能只直调 tryLegacyThemeRPC否则会掩盖预检早于 fallback 的路由回归。
// generated static overlay -> canonical request -> gotd dispatcher -> 现有 handler。
func TestLegacyThemeWireDispatch(t *testing.T) {
const userID = 1000010
ctx := WithUserID(context.Background(), userID)
@ -105,11 +111,15 @@ func TestLegacyThemeWireDispatch(t *testing.T) {
if err != nil {
t.Fatalf("installTheme legacy dispatch: %v", err)
}
if _, ok := enc.(*tg.BoolTrue); !ok {
t.Fatalf("installTheme legacy result = %T, want *tg.BoolTrue", enc)
var boolWire bin.Buffer
if err := enc.Encode(&boolWire); err != nil {
t.Fatalf("encode installTheme legacy result: %v", err)
}
if id, err := boolWire.ID(); err != nil || id != tg.BoolTrueTypeID {
t.Fatalf("installTheme legacy wire id = %#x err=%v, want boolTrue", id, err)
}
// 已声明 legacy 方法仍必须精确消费完整结构,截断字段不能到手写 decoder。
// 已声明 legacy 方法仍必须由静态 decoder 精确消费完整结构。
var malformed bin.Buffer
malformed.PutID(legacyCreateThemeID)
malformed.PutInt32(0)

View file

@ -4,10 +4,10 @@ import (
"context"
"testing"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap/zaptest"
themesapp "telesrv/internal/app/themes"

View file

@ -3,7 +3,7 @@ package rpc
import (
"context"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -5,20 +5,38 @@ import (
"errors"
"strings"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"github.com/iamxvbaba/td/tlprofile"
"telesrv/internal/domain"
)
func (r *Router) registerAiCompose(d *tg.ServerDispatcher) {
d.OnAicomposeGetTones(r.onAicomposeGetTones)
d.OnAicomposeCreateTone(r.onAicomposeCreateTone)
d.OnAicomposeUpdateTone(r.onAicomposeUpdateTone)
d.OnAicomposeSaveTone(r.onAicomposeSaveTone)
d.OnAicomposeDeleteTone(r.onAicomposeDeleteTone)
d.OnAicomposeGetTone(r.onAicomposeGetTone)
d.OnAicomposeGetToneExample(r.onAicomposeGetToneExample)
func (r *Router) registerAiCompose(d *tlprofile.Dispatcher) {
registerRPC[*tg.AicomposeGetTonesRequest](d, tlprofile.SemanticMethodAicomposeGetTones, func(ctx context.Context, layerRequest *tg.AicomposeGetTonesRequest) (any, error) {
return r.onAicomposeGetTones(ctx, layerRequest.
Hash)
})
registerRPC[*tg.AicomposeCreateToneRequest](d, tlprofile.SemanticMethodAicomposeCreateTone, func(ctx context.Context, layerRequest *tg.AicomposeCreateToneRequest) (any, error) {
return r.onAicomposeCreateTone(ctx, layerRequest)
})
registerRPC[*tg.AicomposeUpdateToneRequest](d, tlprofile.SemanticMethodAicomposeUpdateTone, func(ctx context.Context, layerRequest *tg.AicomposeUpdateToneRequest) (any, error) {
return r.onAicomposeUpdateTone(ctx, layerRequest)
})
registerRPC[*tg.AicomposeSaveToneRequest](d, tlprofile.SemanticMethodAicomposeSaveTone, func(ctx context.Context, layerRequest *tg.AicomposeSaveToneRequest) (any, error) {
return r.onAicomposeSaveTone(ctx, layerRequest)
})
registerRPC[*tg.AicomposeDeleteToneRequest](d, tlprofile.SemanticMethodAicomposeDeleteTone, func(ctx context.Context, layerRequest *tg.AicomposeDeleteToneRequest) (any, error) {
return r.onAicomposeDeleteTone(ctx, layerRequest.
Tone)
})
registerRPC[*tg.AicomposeGetToneRequest](d, tlprofile.SemanticMethodAicomposeGetTone, func(ctx context.Context, layerRequest *tg.AicomposeGetToneRequest) (any, error) {
return r.onAicomposeGetTone(ctx, layerRequest.
Tone)
})
registerRPC[*tg.AicomposeGetToneExampleRequest](d, tlprofile.SemanticMethodAicomposeGetToneExample, func(ctx context.Context, layerRequest *tg.AicomposeGetToneExampleRequest) (any, error) {
return r.onAicomposeGetToneExample(ctx, layerRequest)
})
}
func (r *Router) onAicomposeGetTones(ctx context.Context, hash int64) (tg.AicomposeTonesClass, error) {

View file

@ -4,9 +4,9 @@ import (
"context"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap/zaptest"
aiapp "telesrv/internal/app/ai"

View file

@ -7,9 +7,9 @@ import (
"go.uber.org/zap/zaptest"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
botsapp "telesrv/internal/app/bots"
appchannels "telesrv/internal/app/channels"
@ -105,15 +105,11 @@ func TestLegacyAndroidAuthSignUpAllowedBeforeAuthorization(t *testing.T) {
if err != nil {
t.Fatalf("dispatch legacy auth.signUp: %v", err)
}
// Routed through the unified layerwire inbound upgrade + the normal gotd
// dispatcher, which boxes a class result (auth.Authorization) as *...Box.
box, ok := enc.(*tg.AuthAuthorizationBox)
// Routed through the generated static client overlay and sparse semantic
// dispatcher, which exposes the canonical concrete result at this test seam.
authorization, ok := enc.(*tg.AuthAuthorization)
if !ok {
t.Fatalf("response = %T, want *tg.AuthAuthorizationBox", enc)
}
authorization, ok := box.Authorization.(*tg.AuthAuthorization)
if !ok {
t.Fatalf("authorization = %T, want auth.authorization", box.Authorization)
t.Fatalf("response = %T, want *tg.AuthAuthorization", enc)
}
user, ok := authorization.User.(*tg.User)
if !ok || user.ID != auth.signUpUser.ID {
@ -160,7 +156,7 @@ func TestModernAndroidChannelsInviteToChannelDispatch(t *testing.T) {
var in bin.Buffer
// DrKLO channels.inviteToChannel#199f3a6c — now handled by the unified
// layerwire client-alias table (pure id swap), not a dedicated handler.
// generated client overlay, not a dedicated handler.
in.PutID(0x199f3a6c)
if err := (&tg.ChannelsInviteToChannelRequest{
Channel: &tg.InputChannel{ChannelID: created.Channel.ID, AccessHash: created.Channel.AccessHash},

View file

@ -0,0 +1,283 @@
package rpc
import (
"encoding/binary"
"fmt"
"testing"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"github.com/iamxvbaba/td/tlprofile"
compatandroid "telesrv/internal/compat/android"
)
type androidPrivateLayerFixture struct {
name string
privateID uint32
semantic tlprofile.SemanticID
method string
wire func(*testing.T) []byte
}
// TestAndroidPrivateLayerRPCsAdaptAcrossCanonicalBoundary is the production
// admission gate for every audited DrKLO-private constructor. It proves both
// halves of the bridge after a canonical schema upgrade:
//
// - the generated static client overlay emits a complete request in the current canonical
// profile (Layer 228), never a stale Layer 227 intermediate; and
// - Router.AdmitLayer feeds that intermediate through the generated
// unknown-method view's AdaptCanonical path, yielding the exact Layer 227
// or Layer 228 wire call for the same semantic method.
func TestAndroidPrivateLayerRPCsAdaptAcrossCanonicalBoundary(t *testing.T) {
r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System)
fixtures := androidPrivateLayerFixtures()
if got, want := len(fixtures), 15; got != want {
t.Fatalf("private fixture count = %d, want %d", got, want)
}
for _, fixture := range fixtures {
fixture := fixture
t.Run(fixture.name, func(t *testing.T) {
raw := fixture.wire(t)
if len(raw) < 4 || binary.LittleEndian.Uint32(raw[:4]) != fixture.privateID {
t.Fatalf("fixture private id = %#x, want %#x", binary.LittleEndian.Uint32(raw[:4]), fixture.privateID)
}
private := bin.Buffer{Buf: append([]byte(nil), raw...)}
canonical, handled, err := compatandroid.UpgradePrivateLayerRPC(tlprofile.ProfileCanonical, &private, tlprofile.Limits{})
if err != nil || !handled || canonical == nil {
t.Fatalf("canonical upgrade = value:%v handled:%v err:%v", canonical != nil, handled, err)
}
if private.Len() != 0 {
t.Fatalf("canonical upgrade left %d private bytes", private.Len())
}
canonicalID, ok := tlprofile.WireID(tlprofile.ProfileCanonical, fixture.semantic)
if !ok {
t.Fatalf("canonical profile has no wire id for %s", fixture.method)
}
if got, peekErr := canonical.PeekID(); peekErr != nil || got != canonicalID {
t.Fatalf("canonical upgrade id = %#x err=%v, want %#x", got, peekErr, canonicalID)
}
for _, profile := range []tlprofile.Profile{tlprofile.Profile227, tlprofile.Profile228} {
profile := profile
t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) {
body := bin.Buffer{Buf: append([]byte(nil), raw...)}
admitted, err := r.AdmitLayer(profile, &body, tlprofile.Limits{})
if err != nil {
t.Fatalf("production exact admission: %v", err)
}
if body.Len() != 0 {
t.Fatalf("production exact admission left %d bytes", body.Len())
}
call := admitted.Call()
if call.Profile() != profile || call.Method() != fixture.semantic {
t.Fatalf("admitted call = profile:%d semantic:%#x, want profile:%d semantic:%#x", call.Profile(), call.Method(), profile, fixture.semantic)
}
category, method, ok := tlprofile.SemanticName(call.Method())
if !ok || category != "function" || method != fixture.method {
t.Fatalf("admitted semantic name = (%q,%q,%v), want (function,%q,true)", category, method, ok, fixture.method)
}
wantWireID, ok := tlprofile.WireID(profile, fixture.semantic)
if !ok || call.WireID() != wantWireID {
t.Fatalf("admitted exact id = %#x, want %#x (ok=%v)", call.WireID(), wantWireID, ok)
}
})
}
})
}
}
func androidPrivateLayerFixtures() []androidPrivateLayerFixture {
return []androidPrivateLayerFixture{
{
name: "messages.forwardMessages_alias", privateID: 0x41d41ade,
semantic: tlprofile.SemanticMethodMessagesForwardMessages, method: "messages.forwardMessages",
wire: func(*testing.T) []byte { return androidPrivateForwardMessagesWire() },
},
{
name: "channels.inviteToChannel_alias", privateID: 0x199f3a6c,
semantic: tlprofile.SemanticMethodChannelsInviteToChannel, method: "channels.inviteToChannel",
wire: func(t *testing.T) []byte {
return androidPrivateAliasWire(t, 0x199f3a6c, &tg.ChannelsInviteToChannelRequest{
Channel: &tg.InputChannel{ChannelID: 41, AccessHash: 42},
Users: []tg.InputUserClass{&tg.InputUser{UserID: 43, AccessHash: 44}},
})
},
},
{
name: "updates.getDifference_alias", privateID: 0x25939651,
semantic: tlprofile.SemanticMethodUpdatesGetDifference, method: "updates.getDifference",
wire: func(t *testing.T) []byte {
return androidPrivateAliasWire(t, 0x25939651, &tg.UpdatesGetDifferenceRequest{Pts: 100, Date: 200, Qts: 3})
},
},
{
name: "messages.createChat_alias", privateID: 0x0034a818,
semantic: tlprofile.SemanticMethodMessagesCreateChat, method: "messages.createChat",
wire: func(t *testing.T) []byte {
return androidPrivateAliasWire(t, 0x0034a818, &tg.MessagesCreateChatRequest{
Users: []tg.InputUserClass{&tg.InputUser{UserID: 51, AccessHash: 52}},
Title: "private group",
})
},
},
{
name: "messages.uploadMedia_transform", privateID: 0x519bc2b1,
semantic: tlprofile.SemanticMethodMessagesUploadMedia, method: "messages.uploadMedia",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x519bc2b1, func(body *bin.Buffer) error {
if err := (&tg.InputPeerSelf{}).Encode(body); err != nil {
return err
}
return (&tg.InputMediaUploadedPhoto{File: &tg.InputFile{ID: 61, Parts: 1, Name: "private.jpg"}}).Encode(body)
})
},
},
{
name: "auth.signUp_transform", privateID: 0x80eee427,
semantic: tlprofile.SemanticMethodAuthSignUp, method: "auth.signUp",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x80eee427, func(body *bin.Buffer) error {
body.PutString("+15550000228")
body.PutString("private-hash")
body.PutString("Private")
body.PutString("Layer")
return nil
})
},
},
{
name: "messages.getMessages_transform", privateID: 0x4222fa74,
semantic: tlprofile.SemanticMethodMessagesGetMessages, method: "messages.getMessages",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x4222fa74, func(body *bin.Buffer) error {
body.PutVectorHeader(2)
body.PutInt(71)
body.PutInt(72)
return nil
})
},
},
{
name: "channels.getMessages_transform", privateID: 0x93d7b347,
semantic: tlprofile.SemanticMethodChannelsGetMessages, method: "channels.getMessages",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x93d7b347, func(body *bin.Buffer) error {
if err := (&tg.InputChannel{ChannelID: 81, AccessHash: 82}).Encode(body); err != nil {
return err
}
body.PutVectorHeader(2)
body.PutInt(83)
body.PutInt(84)
return nil
})
},
},
{
name: "bots.exportBotToken_transform", privateID: 0x0063b089,
semantic: tlprofile.SemanticMethodBotsExportBotToken, method: "bots.exportBotToken",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x0063b089, func(body *bin.Buffer) error {
body.PutLong(91)
body.PutID(tg.BoolTrueTypeID)
return nil
})
},
},
{
name: "account.registerDevice_transform", privateID: 0x637ea878,
semantic: tlprofile.SemanticMethodAccountRegisterDevice, method: "account.registerDevice",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x637ea878, func(body *bin.Buffer) error {
body.PutInt(2)
body.PutString("private-device-token")
return nil
})
},
},
{
name: "contacts.search_transform", privateID: 0x11f812d8,
semantic: tlprofile.SemanticMethodContactsSearch, method: "contacts.search",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x11f812d8, func(body *bin.Buffer) error {
body.PutString("private-query")
body.PutInt(20)
return nil
})
},
},
{
name: "langpack.getLangPack_transform", privateID: 0x9ab5c58e,
semantic: tlprofile.SemanticMethodLangpackGetLangPack, method: "langpack.getLangPack",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x9ab5c58e, func(body *bin.Buffer) error {
body.PutString("en")
return nil
})
},
},
{
name: "langpack.getStrings_transform", privateID: 0x2e1ee318,
semantic: tlprofile.SemanticMethodLangpackGetStrings, method: "langpack.getStrings",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x2e1ee318, func(body *bin.Buffer) error {
body.PutString("en")
body.PutVectorHeader(2)
body.PutString("private.one")
body.PutString("private.two")
return nil
})
},
},
{
name: "langpack.getLanguages_transform", privateID: 0x800fd57d,
semantic: tlprofile.SemanticMethodLangpackGetLanguages, method: "langpack.getLanguages",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x800fd57d, func(*bin.Buffer) error { return nil })
},
},
{
name: "messages.editChatCreator_transform", privateID: 0x8f38cd1f,
semantic: tlprofile.SemanticMethodMessagesEditChatCreator, method: "messages.editChatCreator",
wire: func(t *testing.T) []byte {
return androidPrivateRawWire(t, 0x8f38cd1f, func(body *bin.Buffer) error {
if err := (&tg.InputChannel{ChannelID: 101, AccessHash: 102}).Encode(body); err != nil {
return err
}
if err := (&tg.InputUser{UserID: 103, AccessHash: 104}).Encode(body); err != nil {
return err
}
return (&tg.InputCheckPasswordEmpty{}).Encode(body)
})
},
},
}
}
func androidPrivateAliasWire(t *testing.T, privateID uint32, request bin.Encoder) []byte {
t.Helper()
var body bin.Buffer
if err := request.Encode(&body); err != nil {
t.Fatalf("encode private alias body: %v", err)
}
if body.Len() < 4 {
t.Fatal("encoded private alias body has no constructor id")
}
binary.LittleEndian.PutUint32(body.Buf[:4], privateID)
return body.Copy()
}
func androidPrivateRawWire(t *testing.T, privateID uint32, encodeBody func(*bin.Buffer) error) []byte {
t.Helper()
var body bin.Buffer
body.PutID(privateID)
if err := encodeBody(&body); err != nil {
t.Fatalf("encode private raw body: %v", err)
}
return body.Copy()
}

View file

@ -10,9 +10,10 @@ import (
"go.uber.org/zap"
"github.com/gotd/td/proto"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tlprofile"
"telesrv/internal/app/auth"
"telesrv/internal/domain"
)
@ -21,39 +22,97 @@ import (
const devCodeLength = 5
// registerAuth 注册 auth.* RPC handler。
func (r *Router) registerAuth(d *tg.ServerDispatcher) {
d.OnAuthBindTempAuthKey(r.onAuthBindTempAuthKey)
d.OnAuthExportLoginToken(r.onAuthExportLoginToken)
d.OnAuthImportLoginToken(r.onAuthImportLoginToken)
d.OnAuthAcceptLoginToken(r.onAuthAcceptLoginToken)
d.OnAuthExportAuthorization(func(ctx context.Context, dcid int) (*tg.AuthExportedAuthorization, error) {
func (r *Router) registerAuth(d *tlprofile.Dispatcher) {
registerRPC[*tg.AuthBindTempAuthKeyRequest](d, tlprofile.SemanticMethodAuthBindTempAuthKey, func(ctx context.Context, layerRequest *tg.AuthBindTempAuthKeyRequest) (any, error) {
return r.onAuthBindTempAuthKey(ctx, layerRequest)
})
registerRPC[*tg.AuthExportLoginTokenRequest](d, tlprofile.SemanticMethodAuthExportLoginToken, func(ctx context.Context, layerRequest *tg.AuthExportLoginTokenRequest) (any, error) {
return r.onAuthExportLoginToken(ctx, layerRequest)
})
registerRPC[*tg.AuthImportLoginTokenRequest](d, tlprofile.SemanticMethodAuthImportLoginToken, func(ctx context.Context, layerRequest *tg.AuthImportLoginTokenRequest) (any, error) {
return r.onAuthImportLoginToken(ctx, layerRequest.
Token)
})
registerRPC[*tg.AuthAcceptLoginTokenRequest](d, tlprofile.SemanticMethodAuthAcceptLoginToken, func(ctx context.Context, layerRequest *tg.AuthAcceptLoginTokenRequest) (any, error) {
return r.onAuthAcceptLoginToken(ctx, layerRequest.
Token)
})
registerRPC[*tg.AuthExportAuthorizationRequest](d, tlprofile.SemanticMethodAuthExportAuthorization, func(ctx context.Context, layerRequest *tg.AuthExportAuthorizationRequest) (any, error) {
dcid := layerRequest.
DCID
_ = dcid
return nil, dcIDInvalidErr()
})
d.OnAuthImportAuthorization(func(ctx context.Context, req *tg.AuthImportAuthorizationRequest) (tg.AuthAuthorizationClass, error) {
registerRPC[*tg.AuthImportAuthorizationRequest](d, tlprofile.SemanticMethodAuthImportAuthorization, func(ctx context.Context, req *tg.AuthImportAuthorizationRequest) (any, error) {
return nil, dcIDInvalidErr()
})
d.OnAuthDropTempAuthKeys(func(ctx context.Context, exceptauthkeys []int64) (bool, error) {
registerRPC[*tg.AuthDropTempAuthKeysRequest](d, tlprofile.SemanticMethodAuthDropTempAuthKeys, func(ctx context.Context, layerRequest *tg.AuthDropTempAuthKeysRequest) (any, error) {
exceptauthkeys := layerRequest.
ExceptAuthKeys
_ = exceptauthkeys
return true, nil
})
d.OnAuthInitPasskeyLogin(r.onAuthInitPasskeyLogin)
d.OnAuthFinishPasskeyLogin(r.onAuthFinishPasskeyLogin)
d.OnAuthSendCode(r.onAuthSendCode)
d.OnAuthResendCode(r.onAuthResendCode)
d.OnAuthCancelCode(r.onAuthCancelCode)
d.OnAuthSignIn(r.onAuthSignIn)
d.OnAuthSignUp(r.onAuthSignUp)
d.OnAuthImportBotAuthorization(r.onAuthImportBotAuthorization)
d.OnAuthLogOut(r.onAuthLogOut)
d.OnAuthResetAuthorizations(r.onAuthResetAuthorizations)
d.OnAuthCheckPassword(r.onAuthCheckPassword)
d.OnAuthRequestPasswordRecovery(r.onAuthRequestPasswordRecovery)
d.OnAuthRecoverPassword(r.onAuthRecoverPassword)
d.OnAuthCheckRecoveryPassword(r.onAuthCheckRecoveryPassword)
d.OnAuthResetLoginEmail(r.onAuthResetLoginEmail)
registerRPC[*tg.AuthInitPasskeyLoginRequest](d, tlprofile.SemanticMethodAuthInitPasskeyLogin, func(ctx context.Context, layerRequest *tg.AuthInitPasskeyLoginRequest) (any, error) {
return r.onAuthInitPasskeyLogin(ctx, layerRequest)
})
registerRPC[*tg.AuthFinishPasskeyLoginRequest](d, tlprofile.SemanticMethodAuthFinishPasskeyLogin, func(ctx context.Context, layerRequest *tg.AuthFinishPasskeyLoginRequest) (any, error) {
return r.onAuthFinishPasskeyLogin(ctx, layerRequest)
})
registerRPC[*tg.AuthSendCodeRequest](d, tlprofile.SemanticMethodAuthSendCode, func(ctx context.Context, layerRequest *tg.AuthSendCodeRequest) (any, error) {
return r.onAuthSendCode(ctx, layerRequest)
})
registerRPC[*tg.AuthResendCodeRequest](d, tlprofile.SemanticMethodAuthResendCode, func(ctx context.Context, layerRequest *tg.AuthResendCodeRequest) (any, error) {
return r.onAuthResendCode(ctx, layerRequest)
})
registerRPC[*tg.AuthCancelCodeRequest](d, tlprofile.SemanticMethodAuthCancelCode, func(ctx context.Context, layerRequest *tg.AuthCancelCodeRequest) (any, error) {
return r.onAuthCancelCode(ctx, layerRequest)
})
registerRPC[*tg.AuthSignInRequest](d, tlprofile.SemanticMethodAuthSignIn, func(ctx context.Context, layerRequest *tg.AuthSignInRequest) (any, error) {
return r.onAuthSignIn(ctx, layerRequest)
})
registerRPC[*tg.AuthSignUpRequest](d, tlprofile.SemanticMethodAuthSignUp, func(ctx context.Context, layerRequest *tg.AuthSignUpRequest) (any, error) {
return r.onAuthSignUp(ctx, layerRequest)
})
registerRPC[*tg.AuthImportBotAuthorizationRequest](d, tlprofile.SemanticMethodAuthImportBotAuthorization, func(ctx context.Context, layerRequest *tg.AuthImportBotAuthorizationRequest) (any, error) {
return r.onAuthImportBotAuthorization(ctx, layerRequest)
})
registerRPC[*tg.AuthLogOutRequest](d, tlprofile.SemanticMethodAuthLogOut, func(ctx context.Context, layerRequest *tg.AuthLogOutRequest) (any, error) {
return r.onAuthLogOut(ctx)
})
registerRPC[*tg.AuthResetAuthorizationsRequest](d, tlprofile.SemanticMethodAuthResetAuthorizations, func(ctx context.Context, layerRequest *tg.AuthResetAuthorizationsRequest) (any, error) {
return r.onAuthResetAuthorizations(ctx)
})
registerRPC[*tg.AuthCheckPasswordRequest](d, tlprofile.SemanticMethodAuthCheckPassword, func(ctx context.Context, layerRequest *tg.AuthCheckPasswordRequest) (any, error) {
return r.onAuthCheckPassword(ctx, layerRequest.
Password)
})
registerRPC[*tg.AuthRequestPasswordRecoveryRequest](d, tlprofile.SemanticMethodAuthRequestPasswordRecovery, func(ctx context.Context, layerRequest *tg.AuthRequestPasswordRecoveryRequest) (any, error) {
return r.onAuthRequestPasswordRecovery(ctx)
})
registerRPC[*tg.AuthRecoverPasswordRequest](d, tlprofile.SemanticMethodAuthRecoverPassword, func(ctx context.Context, layerRequest *tg.AuthRecoverPasswordRequest) (any, error) {
return r.onAuthRecoverPassword(ctx, layerRequest)
})
registerRPC[*tg.AuthCheckRecoveryPasswordRequest](d, tlprofile.SemanticMethodAuthCheckRecoveryPassword, func(ctx context.Context, layerRequest *tg.AuthCheckRecoveryPasswordRequest) (
// onAuthBindTempAuthKey 记录 TDesktop 的 PFS temp→perm auth key 绑定。
any, error) {
return r.onAuthCheckRecoveryPassword(ctx, layerRequest.
Code)
})
registerRPC[*tg.AuthResetLoginEmailRequest](d, tlprofile.SemanticMethodAuthResetLoginEmail, func(ctx context.Context, layerRequest *tg.AuthResetLoginEmailRequest) (any, error) {
return r.onAuthResetLoginEmail(ctx, layerRequest)
})
}
// onAuthBindTempAuthKey 记录 TDesktop 的 PFS temp→perm auth key 绑定。
func (r *Router) onAuthBindTempAuthKey(ctx context.Context, req *tg.AuthBindTempAuthKeyRequest) (bool, error) {
if !layerRPCProfileEvidenceFresh(ctx) {
// The inner request is outside MTProto's mutable msg_id window. It may be
// decoded request-locally, but acknowledging it would mutate the durable
// temp→perm identity and every live session from stale replay evidence.
return false, bindTempAuthKeyErr(auth.ErrTempAuthKeyEmpty)
}
if r.deps.Auth == nil {
return true, nil
}
@ -71,18 +130,95 @@ func (r *Router) onAuthBindTempAuthKey(ctx context.Context, req *tg.AuthBindTemp
}); err != nil {
return false, bindTempAuthKeyErr(err)
}
permID := authKeyIDFromInt64(req.PermAuthKeyID)
// temp key (re)bind 后立即作废其 temp→perm 解析缓存,确保下一帧按新绑定重新解析,
// 不被 TTL 内的旧 perm 缓存命中(防跨账号串号)。
if id != ([8]byte{}) {
r.tempKeyResolveCache.Delete(id)
}
if r.deps.Sessions != nil {
r.deps.Sessions.BindAuthKeyForSession(id, sessionID, authKeyIDFromInt64(req.PermAuthKeyID))
}
// Save atomically merged raw/permanent Layer observations. Both identities
// must now re-read that durable permanent primary; pre-bind process caches
// are not ordering evidence and cannot overwrite the transaction's winner.
r.invalidateAuthUserCache(id)
r.invalidateAuthUserCache(permID)
unlockLayerCommit := r.lockAuthLayerCommit(id, permID)
defer unlockLayerCommit()
r.invalidateBoundAuthKeyLayerResolution(id, permID)
if r.deps.Sessions != nil {
if all, ok := r.deps.Sessions.(RawAuthKeySessionBinder); ok {
all.BindAuthKeyForRawAuthKey(id, permID)
} else {
r.deps.Sessions.BindAuthKeyForSession(id, sessionID, permID)
}
}
layer, _, err := r.resolveAuthKeyLayerDefault(ctx, permID)
if err != nil {
if clearer, ok := r.deps.Sessions.(AuthKeyInheritedLayerClearer); ok {
clearer.ClearInheritedLayerForRawAuthKey(id)
}
if r.log != nil {
r.log.Warn("reload merged permanent layer after temp auth key bind failed",
zap.String("raw_auth_key_id", fmt.Sprintf("%x", id[:])),
zap.String("perm_auth_key_id", fmt.Sprintf("%x", permID[:])),
zap.Error(err))
}
return false, internalErr()
}
r.cacheBoundAuthKeyLayerResolution(id, permID)
if isSupportedLayer(layer) {
if refresher, ok := r.deps.Sessions.(AuthKeyLayerRefresher); ok {
refresher.RefreshInheritedLayerForRawAuthKey(id, layer)
} else if binder, ok := r.deps.Sessions.(AuthKeyLayerBinder); ok {
binder.SeedInheritedLayerForRawAuthKey(id, layer)
}
} else if clearer, ok := r.deps.Sessions.(AuthKeyInheritedLayerClearer); ok {
clearer.ClearInheritedLayerForRawAuthKey(id)
}
return true, nil
}
func (r *Router) invalidateBoundAuthKeyLayerResolution(authKeyIDs ...[8]byte) {
r.clientInfoMu.Lock()
defer r.clientInfoMu.Unlock()
for _, authKeyID := range authKeyIDs {
if info, ok := r.authInfo[authKeyID]; ok {
info.layer = 0
info.layerObservationID = 0
info.layerAdmissionSeq = 0
info.authKeyInfoChecked = false
info.authorizationChecked = false
info.layerBlocked = false
info.layerBlockedByAuthKey = false
r.authInfo[authKeyID] = info
}
}
}
func (r *Router) cacheBoundAuthKeyLayerResolution(rawAuthKeyID, permAuthKeyID [8]byte) {
r.clientInfoMu.Lock()
defer r.clientInfoMu.Unlock()
if r.authInfo == nil {
r.authInfo = make(map[[8]byte]clientSessionInfo)
}
if _, exists := r.authInfo[rawAuthKeyID]; !exists {
evictMapEntryIfFullLocked(r.authInfo, maxAuthInfoEntries)
}
canonical := r.authInfo[permAuthKeyID]
info := r.authInfo[rawAuthKeyID]
// The bind transaction made the permanent row authoritative for both
// identities. Copy its complete resolution tuple: a Layer without the same
// observation token (or a stale blocked bit) would let later cache merging
// manufacture an ordering state that never existed durably.
info.layer = canonical.layer
info.layerObservationID = canonical.layerObservationID
info.layerAdmissionSeq = canonical.layerAdmissionSeq
info.layerBlocked = canonical.layerBlocked
info.layerBlockedByAuthKey = canonical.layerBlockedByAuthKey
info.authKeyInfoChecked = canonical.authKeyInfoChecked
info.authorizationChecked = canonical.authorizationChecked
r.authInfo[rawAuthKeyID] = info
}
// onAuthExportLoginToken 给 QR 登录请求方返回短期 token扫码端接受后同一目标
// session 后续 export 会升级为 auth.loginTokenSuccess。
func (r *Router) onAuthExportLoginToken(ctx context.Context, req *tg.AuthExportLoginTokenRequest) (tg.AuthLoginTokenClass, error) {

View file

@ -8,8 +8,8 @@ import (
"testing"
"time"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"telesrv/internal/app/auth"

View file

@ -1,6 +1,6 @@
package rpc
import "github.com/gotd/td/tg"
import "github.com/iamxvbaba/td/tg"
// rpcAllowedWithoutAuthorization returns true for methods that are valid before
// an auth key is bound to a user. Everything else must fail with

View file

@ -5,7 +5,7 @@ import (
"testing"
"time"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"telesrv/internal/domain"
@ -47,6 +47,57 @@ func TestEmailSentCodeUsesDeliveryLength(t *testing.T) {
}
}
func TestAuthSignInRoutesOfficialEmailCodeCarriers(t *testing.T) {
const (
phone = "+86 188 0000 0021"
hash = "hash-email-login"
code = "654321"
)
tests := []struct {
name string
request func() *tg.AuthSignInRequest
wantPhoneCodeCalls int
wantEmailCodeCalls int
}{
{
name: "webk_phone_code",
request: func() *tg.AuthSignInRequest {
return &tg.AuthSignInRequest{PhoneNumber: phone, PhoneCodeHash: hash, PhoneCode: code}
},
wantPhoneCodeCalls: 1,
},
{
name: "tdesktop_android_email_verification",
request: func() *tg.AuthSignInRequest {
req := &tg.AuthSignInRequest{PhoneNumber: phone, PhoneCodeHash: hash}
req.SetEmailVerification(&tg.EmailVerificationCode{Code: code})
return req
},
wantEmailCodeCalls: 1,
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
authSvc := &captureAuthService{signInUser: domain.User{ID: 100200301, Phone: "8618800000021", FirstName: "Alice"}}
r := New(Config{}, Deps{Auth: authSvc}, zaptest.NewLogger(t), fixedClock{now: time.Unix(1700000000, 0)})
if _, err := r.onAuthSignIn(context.Background(), tc.request()); err != nil {
t.Fatalf("onAuthSignIn: %v", err)
}
if authSvc.signInCount != tc.wantPhoneCodeCalls || authSvc.signInWithEmailCount != tc.wantEmailCodeCalls {
t.Fatalf("SignIn/SignInWithEmail calls=%d/%d, want %d/%d", authSvc.signInCount, authSvc.signInWithEmailCount, tc.wantPhoneCodeCalls, tc.wantEmailCodeCalls)
}
if tc.wantPhoneCodeCalls == 1 && (authSvc.signInPhone != phone || authSvc.signInHash != hash || authSvc.signInCode != code) {
t.Fatalf("SignIn proof=%q/%q/%q, want %q/%q/%q", authSvc.signInPhone, authSvc.signInHash, authSvc.signInCode, phone, hash, code)
}
if tc.wantEmailCodeCalls == 1 && (authSvc.signInWithEmailPhone != phone || authSvc.signInWithEmailHash != hash || authSvc.signInWithEmailCode != code) {
t.Fatalf("SignInWithEmail proof=%q/%q/%q, want %q/%q/%q", authSvc.signInWithEmailPhone, authSvc.signInWithEmailHash, authSvc.signInWithEmailCode, phone, hash, code)
}
})
}
}
func TestAccountVerifyEmailLoginSetupReturnsSentCodeSuccess(t *testing.T) {
user := domain.User{
ID: 100200300,

View file

@ -4,8 +4,8 @@ import (
"context"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appaccount "telesrv/internal/app/account"

View file

@ -6,10 +6,10 @@ import (
"testing"
"time"
"github.com/gotd/td/clock"
"github.com/gotd/td/proto"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap/zaptest"
"telesrv/internal/domain"

View file

@ -8,7 +8,6 @@ import (
"go.uber.org/zap"
"telesrv/internal/domain"
"telesrv/internal/postresponse"
)
const (
@ -104,7 +103,10 @@ func (r *Router) enqueueLoginMessageBootstrap(ctx context.Context, msg domain.Me
}
}
func (r *Router) registerBootstrapAfterBaseline(ctx context.Context, userID int64) {
// publishBootstrapAfterBaseline runs only from the ordered post-response plan.
// It must never be called while the baseline rpc_result is merely encoded or
// queued, otherwise the bootstrap update can overtake that baseline on wire.
func (r *Router) publishBootstrapAfterBaseline(ctx context.Context, userID int64) {
if r.deps.BootstrapUpdates == nil || userID == 0 {
return
}
@ -113,19 +115,17 @@ func (r *Router) registerBootstrapAfterBaseline(ctx context.Context, userID int6
if !hasAuthKeyID || !hasSessionID {
return
}
postresponse.Register(ctx, func() {
cbCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
ready, err := r.deps.BootstrapUpdates.MarkReadyForSession(cbCtx, userID, authKeyID, sessionID)
if err != nil {
r.log.Warn("mark bootstrap updates ready", zap.Int64("user_id", userID), zap.Int64("session_id", sessionID), zap.Error(err))
return
}
if ready == 0 {
return
}
r.publishReadyBootstrapUpdates(cbCtx, ready, defaultBootstrapLease, r.log.Named("bootstrap"))
})
cbCtx, cancel := context.WithTimeout(ctx, updatesDeliveryPhaseTimeout)
defer cancel()
ready, err := r.deps.BootstrapUpdates.MarkReadyForSession(cbCtx, userID, authKeyID, sessionID)
if err != nil {
r.log.Warn("mark bootstrap updates ready", zap.Int64("user_id", userID), zap.Int64("session_id", sessionID), zap.Error(err))
return
}
if ready == 0 {
return
}
r.publishReadyBootstrapUpdates(cbCtx, ready, defaultBootstrapLease, r.log.Named("bootstrap"))
}
func (r *Router) publishReadyBootstrapUpdates(ctx context.Context, batch int, leaseTimeout time.Duration, log *zap.Logger) int {

View file

@ -6,7 +6,7 @@ import (
"testing"
"time"
"github.com/gotd/td/clock"
"github.com/iamxvbaba/td/clock"
"go.uber.org/zap/zaptest"
appbots "telesrv/internal/app/bots"

View file

@ -4,8 +4,9 @@ import (
"context"
"errors"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tlprofile"
"telesrv/internal/domain"
)
@ -22,58 +23,165 @@ import (
// bump bot_info_version命令变更后 bots_hooks.PushBotCommandsChanged 给在线相关用户
// 推 updateBotCommands扇出封顶 100无 pts离线/超界用户靠 version bump 在下次
// getFullUser 重拉兜底。
func (r *Router) registerBots(d *tg.ServerDispatcher) {
d.OnBotsSendCustomRequest(r.onBotsSendCustomRequest)
d.OnBotsAnswerWebhookJSONQuery(r.onBotsAnswerWebhookJSONQuery)
d.OnBotsSetBotBroadcastDefaultAdminRights(r.onBotsSetBotBroadcastDefaultAdminRights)
d.OnBotsSetBotGroupDefaultAdminRights(r.onBotsSetBotGroupDefaultAdminRights)
d.OnBotsSetBotCommands(r.onBotsSetBotCommands)
d.OnBotsResetBotCommands(r.onBotsResetBotCommands)
d.OnBotsGetBotCommands(r.onBotsGetBotCommands)
d.OnBotsSetBotInfo(r.onBotsSetBotInfo)
d.OnBotsGetBotInfo(r.onBotsGetBotInfo)
d.OnBotsSetBotMenuButton(r.onBotsSetBotMenuButton)
d.OnBotsGetBotMenuButton(r.onBotsGetBotMenuButton)
d.OnBotsReorderUsernames(r.onBotsReorderUsernames)
d.OnBotsToggleUsername(r.onBotsToggleUsername)
d.OnBotsCanSendMessage(r.onBotsCanSendMessage)
d.OnBotsAllowSendMessage(r.onBotsAllowSendMessage)
d.OnBotsInvokeWebViewCustomMethod(r.onBotsInvokeWebViewCustomMethod)
d.OnBotsGetPopularAppBots(r.onBotsGetPopularAppBots)
d.OnBotsAddPreviewMedia(r.onBotsAddPreviewMedia)
d.OnBotsEditPreviewMedia(r.onBotsEditPreviewMedia)
d.OnBotsDeletePreviewMedia(r.onBotsDeletePreviewMedia)
d.OnBotsReorderPreviewMedias(r.onBotsReorderPreviewMedias)
d.OnBotsGetPreviewInfo(r.onBotsGetPreviewInfo)
d.OnBotsGetPreviewMedias(r.onBotsGetPreviewMedias)
d.OnBotsUpdateUserEmojiStatus(r.onBotsUpdateUserEmojiStatus)
d.OnBotsToggleUserEmojiStatusPermission(r.onBotsToggleUserEmojiStatusPermission)
d.OnBotsCheckDownloadFileParams(r.onBotsCheckDownloadFileParams)
d.OnBotsGetAdminedBots(r.onBotsGetAdminedBots)
d.OnBotsUpdateStarRefProgram(r.onBotsUpdateStarRefProgram)
d.OnBotsSetCustomVerification(r.onBotsSetCustomVerification)
d.OnBotsGetBotRecommendations(r.onBotsGetBotRecommendations)
d.OnBotsCheckUsername(r.onBotsCheckUsername)
d.OnBotsCreateBot(r.onBotsCreateBot)
d.OnBotsExportBotToken(r.onBotsExportBotToken)
d.OnBotsRequestWebViewButton(r.onBotsRequestWebViewButton)
d.OnBotsGetRequestedWebViewButton(r.onBotsGetRequestedWebViewButton)
d.OnBotsGetAccessSettings(r.onBotsGetAccessSettings)
d.OnBotsEditAccessSettings(r.onBotsEditAccessSettings)
// P3startBot 深链 + inline callback 闭环。
d.OnMessagesStartBot(r.onMessagesStartBot)
d.OnMessagesGetBotCallbackAnswer(r.onMessagesGetBotCallbackAnswer)
d.OnMessagesSetBotCallbackAnswer(r.onMessagesSetBotCallbackAnswer)
d.OnMessagesGetInlineBotResults(r.onMessagesGetInlineBotResults)
d.OnMessagesSetInlineBotResults(r.onMessagesSetInlineBotResults)
d.OnMessagesSendInlineBotResult(r.onMessagesSendInlineBotResult)
d.OnMessagesSavePreparedInlineMessage(r.onMessagesSavePreparedInlineMessage)
d.OnMessagesEditInlineBotMessage(r.onMessagesEditInlineBotMessage)
d.OnMessagesSetBotShippingResults(r.onMessagesSetBotShippingResults)
d.OnMessagesSetBotPrecheckoutResults(r.onMessagesSetBotPrecheckoutResults)
func (r *Router) registerBots(d *tlprofile.Dispatcher) {
registerRPC[*tg.BotsSendCustomRequestRequest](d, tlprofile.SemanticMethodBotsSendCustomRequest, func(ctx context.Context, layerRequest *tg.BotsSendCustomRequestRequest) (any, error) {
return r.onBotsSendCustomRequest(ctx, layerRequest)
})
registerRPC[*tg.BotsAnswerWebhookJSONQueryRequest](d, tlprofile.SemanticMethodBotsAnswerWebhookJSONQuery, func(ctx context.Context, layerRequest *tg.BotsAnswerWebhookJSONQueryRequest) (any, error) {
return r.onBotsAnswerWebhookJSONQuery(ctx, layerRequest)
})
registerRPC[*tg.BotsSetBotBroadcastDefaultAdminRightsRequest](d, tlprofile.SemanticMethodBotsSetBotBroadcastDefaultAdminRights, func(ctx context.Context, layerRequest *tg.BotsSetBotBroadcastDefaultAdminRightsRequest) (any, error) {
return r.onBotsSetBotBroadcastDefaultAdminRights(ctx, layerRequest.
AdminRights)
})
registerRPC[*tg.BotsSetBotGroupDefaultAdminRightsRequest](d, tlprofile.SemanticMethodBotsSetBotGroupDefaultAdminRights, func(ctx context.Context, layerRequest *tg.BotsSetBotGroupDefaultAdminRightsRequest) (any, error) {
return r.onBotsSetBotGroupDefaultAdminRights(ctx, layerRequest.
AdminRights)
})
registerRPC[*tg.BotsSetBotCommandsRequest](d, tlprofile.SemanticMethodBotsSetBotCommands, func(ctx context.Context, layerRequest *tg.BotsSetBotCommandsRequest) (any, error) {
return r.onBotsSetBotCommands(ctx, layerRequest)
})
registerRPC[*tg.BotsResetBotCommandsRequest](d, tlprofile.SemanticMethodBotsResetBotCommands, func(ctx context.Context, layerRequest *tg.BotsResetBotCommandsRequest) (any, error) {
return r.onBotsResetBotCommands(ctx, layerRequest)
})
registerRPC[*tg.BotsGetBotCommandsRequest](d, tlprofile.SemanticMethodBotsGetBotCommands, func(ctx context.Context, layerRequest *tg.BotsGetBotCommandsRequest) (any, error) {
return r.onBotsGetBotCommands(ctx, layerRequest)
})
registerRPC[*tg.BotsSetBotInfoRequest](d, tlprofile.SemanticMethodBotsSetBotInfo, func(ctx context.Context, layerRequest *tg.BotsSetBotInfoRequest) (any, error) {
return r.onBotsSetBotInfo(ctx, layerRequest)
})
registerRPC[*tg.BotsGetBotInfoRequest](d, tlprofile.SemanticMethodBotsGetBotInfo, func(ctx context.Context, layerRequest *tg.BotsGetBotInfoRequest) (any, error) {
return r.onBotsGetBotInfo(ctx, layerRequest)
})
registerRPC[*tg.BotsSetBotMenuButtonRequest](d, tlprofile.SemanticMethodBotsSetBotMenuButton, func(ctx context.Context, layerRequest *tg.BotsSetBotMenuButtonRequest) (any, error) {
return r.onBotsSetBotMenuButton(ctx, layerRequest)
})
registerRPC[*tg.BotsGetBotMenuButtonRequest](d, tlprofile.SemanticMethodBotsGetBotMenuButton, func(ctx context.Context, layerRequest *tg.BotsGetBotMenuButtonRequest) (any, error) {
return r.onBotsGetBotMenuButton(ctx, layerRequest.
UserID)
})
registerRPC[*tg.BotsReorderUsernamesRequest](d, tlprofile.SemanticMethodBotsReorderUsernames, func(ctx context.Context, layerRequest *tg.BotsReorderUsernamesRequest) (any, error) {
return r.onBotsReorderUsernames(ctx, layerRequest)
})
registerRPC[*tg.BotsToggleUsernameRequest](d, tlprofile.SemanticMethodBotsToggleUsername, func(ctx context.Context, layerRequest *tg.BotsToggleUsernameRequest) (any, error) {
return r.onBotsToggleUsername(ctx, layerRequest)
})
registerRPC[*tg.BotsCanSendMessageRequest](d, tlprofile.SemanticMethodBotsCanSendMessage, func(ctx context.Context, layerRequest *tg.BotsCanSendMessageRequest) (any, error) {
return r.onBotsCanSendMessage(ctx, layerRequest.
Bot)
})
registerRPC[*tg.BotsAllowSendMessageRequest](d, tlprofile.SemanticMethodBotsAllowSendMessage, func(ctx context.Context, layerRequest *tg.BotsAllowSendMessageRequest) (any, error) {
return r.onBotsAllowSendMessage(ctx, layerRequest.
Bot)
})
registerRPC[*tg.BotsInvokeWebViewCustomMethodRequest](d, tlprofile.SemanticMethodBotsInvokeWebViewCustomMethod, func(ctx context.Context, layerRequest *tg.BotsInvokeWebViewCustomMethodRequest) (any, error) {
return r.onBotsInvokeWebViewCustomMethod(ctx, layerRequest)
})
registerRPC[*tg.BotsGetPopularAppBotsRequest](d, tlprofile.SemanticMethodBotsGetPopularAppBots, func(ctx context.Context, layerRequest *tg.BotsGetPopularAppBotsRequest) (any, error) {
return r.onBotsGetPopularAppBots(ctx, layerRequest)
})
registerRPC[*tg.BotsAddPreviewMediaRequest](d, tlprofile.SemanticMethodBotsAddPreviewMedia, func(ctx context.Context, layerRequest *tg.BotsAddPreviewMediaRequest) (any, error) {
return r.onBotsAddPreviewMedia(ctx, layerRequest)
})
registerRPC[*tg.BotsEditPreviewMediaRequest](d, tlprofile.SemanticMethodBotsEditPreviewMedia, func(ctx context.Context, layerRequest *tg.BotsEditPreviewMediaRequest) (any, error) {
return r.onBotsEditPreviewMedia(ctx, layerRequest)
})
registerRPC[*tg.BotsDeletePreviewMediaRequest](d, tlprofile.SemanticMethodBotsDeletePreviewMedia, func(ctx context.Context, layerRequest *tg.BotsDeletePreviewMediaRequest) (any, error) {
return r.onBotsDeletePreviewMedia(ctx, layerRequest)
})
registerRPC[*tg.BotsReorderPreviewMediasRequest](d, tlprofile.SemanticMethodBotsReorderPreviewMedias, func(ctx context.Context, layerRequest *tg.BotsReorderPreviewMediasRequest) (any, error) {
return r.onBotsReorderPreviewMedias(ctx, layerRequest)
})
registerRPC[*tg.BotsGetPreviewInfoRequest](d, tlprofile.SemanticMethodBotsGetPreviewInfo, func(ctx context.Context, layerRequest *tg.BotsGetPreviewInfoRequest) (any, error) {
return r.onBotsGetPreviewInfo(ctx, layerRequest)
})
registerRPC[*tg.BotsGetPreviewMediasRequest](d, tlprofile.SemanticMethodBotsGetPreviewMedias, func(ctx context.Context, layerRequest *tg.BotsGetPreviewMediasRequest) (any, error) {
return r.onBotsGetPreviewMedias(ctx, layerRequest.
Bot)
})
registerRPC[*tg.BotsUpdateUserEmojiStatusRequest](d, tlprofile.SemanticMethodBotsUpdateUserEmojiStatus, func(ctx context.Context, layerRequest *tg.BotsUpdateUserEmojiStatusRequest) (any, error) {
return r.onBotsUpdateUserEmojiStatus(ctx, layerRequest)
})
registerRPC[*tg.BotsToggleUserEmojiStatusPermissionRequest](d, tlprofile.SemanticMethodBotsToggleUserEmojiStatusPermission, func(ctx context.Context, layerRequest *tg.BotsToggleUserEmojiStatusPermissionRequest) (any, error) {
return r.onBotsToggleUserEmojiStatusPermission(ctx, layerRequest)
})
registerRPC[*tg.BotsCheckDownloadFileParamsRequest](d, tlprofile.SemanticMethodBotsCheckDownloadFileParams, func(ctx context.Context, layerRequest *tg.BotsCheckDownloadFileParamsRequest) (any, error) {
return r.onBotsCheckDownloadFileParams(ctx, layerRequest)
})
registerRPC[*tg.BotsGetAdminedBotsRequest](d, tlprofile.SemanticMethodBotsGetAdminedBots, func(ctx context.Context, layerRequest *tg.BotsGetAdminedBotsRequest) (any, error) {
return r.onBotsGetAdminedBots(ctx)
})
registerRPC[*tg.BotsUpdateStarRefProgramRequest](d, tlprofile.SemanticMethodBotsUpdateStarRefProgram, func(ctx context.Context, layerRequest *tg.BotsUpdateStarRefProgramRequest) (any, error) {
return r.onBotsUpdateStarRefProgram(ctx, layerRequest)
})
registerRPC[*tg.BotsSetCustomVerificationRequest](d, tlprofile.SemanticMethodBotsSetCustomVerification, func(ctx context.Context, layerRequest *tg.BotsSetCustomVerificationRequest) (any, error) {
return r.onBotsSetCustomVerification(ctx, layerRequest)
})
registerRPC[*tg.BotsGetBotRecommendationsRequest](d, tlprofile.SemanticMethodBotsGetBotRecommendations, func(ctx context.Context, layerRequest *tg.BotsGetBotRecommendationsRequest) (any, error) {
return r.onBotsGetBotRecommendations(ctx, layerRequest.
Bot)
})
registerRPC[*tg.BotsCheckUsernameRequest](d, tlprofile.SemanticMethodBotsCheckUsername, func(ctx context.Context, layerRequest *tg.BotsCheckUsernameRequest) (any, error) {
return r.onBotsCheckUsername(ctx, layerRequest.
Username)
})
registerRPC[*tg.BotsCreateBotRequest](d, tlprofile.SemanticMethodBotsCreateBot, func(ctx context.Context, layerRequest *tg.BotsCreateBotRequest) (any, error) {
return r.onBotsCreateBot(ctx, layerRequest)
})
registerRPC[*tg.BotsExportBotTokenRequest](d, tlprofile.SemanticMethodBotsExportBotToken, func(ctx context.Context, layerRequest *tg.BotsExportBotTokenRequest) (any, error) {
return r.onBotsExportBotToken(ctx, layerRequest)
})
registerRPC[*tg.BotsRequestWebViewButtonRequest](d, tlprofile.SemanticMethodBotsRequestWebViewButton, func(ctx context.Context, layerRequest *tg.BotsRequestWebViewButtonRequest) (any, error) {
return r.onBotsRequestWebViewButton(ctx, layerRequest)
})
registerRPC[*tg.BotsGetRequestedWebViewButtonRequest](d, tlprofile.SemanticMethodBotsGetRequestedWebViewButton, func(ctx context.Context, layerRequest *tg.BotsGetRequestedWebViewButtonRequest) (any, error) {
return r.onBotsGetRequestedWebViewButton(ctx, layerRequest)
})
registerRPC[*tg.BotsGetAccessSettingsRequest](d, tlprofile.SemanticMethodBotsGetAccessSettings, func(ctx context.Context, layerRequest *tg.BotsGetAccessSettingsRequest) (
// P3startBot 深链 + inline callback 闭环。
any, error) {
return r.onBotsGetAccessSettings(ctx, layerRequest.
Bot)
})
registerRPC[*tg.BotsEditAccessSettingsRequest](d, tlprofile.SemanticMethodBotsEditAccessSettings, func(ctx context.Context, layerRequest *tg.BotsEditAccessSettingsRequest) (any, error) {
return r.onBotsEditAccessSettings(ctx, layerRequest)
})
registerRPC[*tg.MessagesStartBotRequest](d, tlprofile.SemanticMethodMessagesStartBot, func(ctx context.Context, layerRequest *tg.MessagesStartBotRequest) (any, error) {
return r.onMessagesStartBot(ctx, layerRequest)
})
registerRPC[*tg.MessagesGetBotCallbackAnswerRequest](d, tlprofile.SemanticMethodMessagesGetBotCallbackAnswer, func(ctx context.Context, layerRequest *tg.MessagesGetBotCallbackAnswerRequest) (any, error) {
return r.onMessagesGetBotCallbackAnswer(ctx, layerRequest)
})
registerRPC[*tg.MessagesSetBotCallbackAnswerRequest](d, tlprofile.SemanticMethodMessagesSetBotCallbackAnswer, func(ctx context.Context, layerRequest *tg.MessagesSetBotCallbackAnswerRequest) (any, error) {
return r.onMessagesSetBotCallbackAnswer(ctx, layerRequest)
})
registerRPC[*tg.MessagesGetInlineBotResultsRequest](d, tlprofile.SemanticMethodMessagesGetInlineBotResults, func(ctx context.Context, layerRequest *tg.MessagesGetInlineBotResultsRequest) (any, error) {
return r.onMessagesGetInlineBotResults(ctx, layerRequest)
})
registerRPC[*tg.MessagesSetInlineBotResultsRequest](d, tlprofile.SemanticMethodMessagesSetInlineBotResults, func(ctx context.Context, layerRequest *tg.MessagesSetInlineBotResultsRequest) (any, error) {
return r.onMessagesSetInlineBotResults(ctx, layerRequest)
})
registerRPC[*tg.MessagesSendInlineBotResultRequest](d, tlprofile.SemanticMethodMessagesSendInlineBotResult, func(ctx context.Context, layerRequest *tg.MessagesSendInlineBotResultRequest) (any, error) {
return r.onMessagesSendInlineBotResult(ctx, layerRequest)
})
registerRPC[*tg.MessagesSavePreparedInlineMessageRequest](d, tlprofile.SemanticMethodMessagesSavePreparedInlineMessage, func(ctx context.Context, layerRequest *tg.MessagesSavePreparedInlineMessageRequest) (any, error) {
return r.onMessagesSavePreparedInlineMessage(ctx, layerRequest)
})
registerRPC[*tg.MessagesEditInlineBotMessageRequest](d, tlprofile.SemanticMethodMessagesEditInlineBotMessage, func(ctx context.Context, layerRequest *tg.MessagesEditInlineBotMessageRequest) (any, error) {
return r.onMessagesEditInlineBotMessage(ctx, layerRequest)
})
registerRPC[*tg.MessagesSetBotShippingResultsRequest](d, tlprofile.SemanticMethodMessagesSetBotShippingResults, func(ctx context.Context, layerRequest *tg.MessagesSetBotShippingResultsRequest) (any, error) {
return r.onMessagesSetBotShippingResults(ctx, layerRequest)
})
registerRPC[*tg.MessagesSetBotPrecheckoutResultsRequest](d, tlprofile.SemanticMethodMessagesSetBotPrecheckoutResults, func(ctx context.Context,
// callerBotID 校验调用者本身是 bot 账号,返回其 user_idbot-only RPC 用)。
layerRequest *tg.MessagesSetBotPrecheckoutResultsRequest) (any, error) {
return r.onMessagesSetBotPrecheckoutResults(ctx, layerRequest)
})
}
// callerBotID 校验调用者本身是 bot 账号,返回其 user_idbot-only RPC 用)。
func (r *Router) callerBotID(ctx context.Context) (int64, error) {
userID, _, err := r.currentUserID(ctx)
if err != nil {

View file

@ -5,8 +5,8 @@ import (
"time"
"unicode/utf8"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"telesrv/internal/domain"
)

View file

@ -3,7 +3,7 @@ package rpc
import (
"errors"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/tgerr"
"telesrv/internal/domain"
)

View file

@ -5,8 +5,8 @@ import (
"strings"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
botsapp "telesrv/internal/app/bots"

View file

@ -4,7 +4,7 @@ import (
"context"
"time"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap"
"telesrv/internal/domain"

View file

@ -4,8 +4,8 @@ import (
"context"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"telesrv/internal/domain"

View file

@ -7,8 +7,8 @@ import (
"time"
"unicode/utf8"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"telesrv/internal/domain"
"telesrv/internal/store"

View file

@ -5,7 +5,7 @@ import (
"crypto/sha256"
"encoding/binary"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -8,9 +8,9 @@ import (
"testing"
"time"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap/zaptest"
botsapp "telesrv/internal/app/bots"

View file

@ -13,7 +13,7 @@ import (
"strings"
"time"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -4,9 +4,9 @@ import (
"context"
"testing"
"github.com/gotd/td/bin"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"telesrv/internal/domain"
)

View file

@ -8,8 +8,8 @@ import (
"go.uber.org/zap/zaptest"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
botsapp "telesrv/internal/app/bots"
appusers "telesrv/internal/app/users"

View file

@ -4,8 +4,8 @@ import (
"context"
"unicode/utf8"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"telesrv/internal/domain"
)

View file

@ -3,7 +3,7 @@ package rpc
import (
"testing"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -7,7 +7,7 @@ import (
"sync/atomic"
"time"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap"
"telesrv/internal/domain"

View file

@ -8,10 +8,10 @@ import (
"testing"
"time"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/proto"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"telesrv/internal/domain"
@ -65,7 +65,7 @@ func newRecoveryFanoutSessions(onlineChannels []int64, release <-chan struct{})
}
}
func (s *recoveryFanoutSessions) PushToUserExceptAuthKeySession(ctx context.Context, _ int64, _ [8]byte, _ int64, _ proto.MessageType, msg bin.Encoder) (int, error) {
func (s *recoveryFanoutSessions) PushToUserExceptAuthKeySession(ctx context.Context, _ int64, _ [8]byte, _ int64, _ proto.MessageType, msg tg.UpdatesClass) (int, error) {
s.startOnce.Do(func() { close(s.pushStarted) })
if s.pushRelease != nil {
select {
@ -397,7 +397,7 @@ func newOverflowNudgeSessions(onlineByChannel map[int64][]int64) *overflowNudgeS
}
}
func (s *overflowNudgeSessions) PushToUserExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, typ proto.MessageType, msg bin.Encoder) (int, error) {
func (s *overflowNudgeSessions) PushToUserExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, typ proto.MessageType, msg tg.UpdatesClass) (int, error) {
if updates, ok := msg.(*tg.Updates); ok && len(updates.Updates) == 1 {
if nudge, ok := updates.Updates[0].(*tg.UpdateChannelTooLong); ok {
pts, _ := nudge.GetPts()
@ -445,7 +445,7 @@ func newNudgeSessions(online []int64) *nudgeSessions {
return &nudgeSessions{captureSessions: &captureSessions{}, online: online, byUser: map[int64]bin.Encoder{}}
}
func (s *nudgeSessions) PushToUserExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder) (int, error) {
func (s *nudgeSessions) PushToUserExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) {
s.mu.Lock()
s.byUser[userID] = msg
s.mu.Unlock()

View file

@ -4,7 +4,7 @@ import (
"context"
"testing"
"github.com/gotd/td/clock"
"github.com/iamxvbaba/td/clock"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"

View file

@ -5,7 +5,7 @@ import (
"fmt"
"time"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -2,8 +2,8 @@ package rpc
import (
"context"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"telesrv/internal/domain"
"testing"

View file

@ -2,7 +2,7 @@ package rpc
import (
"context"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
"unicode/utf8"
)

View file

@ -4,9 +4,9 @@ import (
"context"
"testing"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"
@ -64,12 +64,8 @@ func TestChannelsDeleteChannelCascadesMonoforumForbiddenRPC(t *testing.T) {
if err != nil {
t.Fatalf("dispatch get dialogs: %v", err)
}
box, ok := enc.(*tg.MessagesDialogsBox)
if !ok {
t.Fatalf("dialogs response = %T, want box", enc)
}
ids := map[int64]struct{}{}
switch d := box.Dialogs.(type) {
switch d := enc.(type) {
case *tg.MessagesDialogs:
for _, ch := range d.Chats {
if c, ok := ch.(*tg.Channel); ok {
@ -83,7 +79,7 @@ func TestChannelsDeleteChannelCascadesMonoforumForbiddenRPC(t *testing.T) {
}
}
default:
t.Fatalf("dialogs = %T, want messages.dialogs(Slice)", box.Dialogs)
t.Fatalf("dialogs = %T, want messages.dialogs(Slice)", enc)
}
return ids
}

View file

@ -2,7 +2,7 @@ package rpc
import (
"context"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -2,10 +2,10 @@ package rpc
import (
"context"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap/zaptest"
"strconv"
"strings"
@ -347,13 +347,12 @@ func TestChannelDialogCarriesChannelPts(t *testing.T) {
}
got := dispatch(&tg.MessagesGetDialogsRequest{OffsetPeer: &tg.InputPeerEmpty{}, Limit: 20})
box, ok := got.(*tg.MessagesDialogsBox)
dialogs, ok := got.(*tg.MessagesDialogs)
if !ok {
t.Fatalf("dialogs response = %T, want box", got)
t.Fatalf("dialogs response = %T, want *tg.MessagesDialogs", got)
}
dialogs, ok := box.Dialogs.(*tg.MessagesDialogs)
if !ok || len(dialogs.Dialogs) != 1 {
t.Fatalf("dialogs = %T %+v, want one channel dialog", box.Dialogs, box.Dialogs)
if len(dialogs.Dialogs) != 1 {
t.Fatalf("dialogs = %+v, want one channel dialog", dialogs)
}
dialog, ok := dialogs.Dialogs[0].(*tg.Dialog)
if !ok {

View file

@ -2,9 +2,9 @@ package rpc
import (
"context"
"github.com/gotd/td/clock"
"github.com/gotd/td/proto"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"strings"
appchannels "telesrv/internal/app/channels"

View file

@ -5,8 +5,8 @@ import (
"errors"
"strings"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"telesrv/internal/domain"
)

View file

@ -2,8 +2,8 @@ package rpc
import (
"context"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"strings"
appchannels "telesrv/internal/app/channels"

View file

@ -4,8 +4,8 @@ import (
"context"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"

View file

@ -5,8 +5,8 @@ import (
"testing"
"time"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"

View file

@ -3,7 +3,7 @@ package rpc
import (
"context"
"errors"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap"
"telesrv/internal/compat/tdesktop"
"telesrv/internal/domain"

View file

@ -3,8 +3,8 @@ package rpc
import (
"context"
"fmt"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"
appusers "telesrv/internal/app/users"

View file

@ -5,8 +5,8 @@ import (
"strings"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"
appusers "telesrv/internal/app/users"

View file

@ -3,8 +3,8 @@ package rpc
import (
"context"
"errors"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap"
"sort"
"strings"

View file

@ -8,7 +8,7 @@ import (
"strings"
"unicode/utf8"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)
@ -262,6 +262,9 @@ func (r *Router) onChannelsGetMessages(ctx context.Context, req *tg.ChannelsGetM
if err != nil {
return nil, err
}
if err := r.checkFrozenChannelParticipants(ctx, userID, channelID); err != nil {
return nil, err
}
ids := make([]int, 0, len(req.ID))
for _, input := range req.ID {
id, ok := inputMessageBoxID(input)

View file

@ -2,10 +2,10 @@ package rpc
import (
"context"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/proto"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"strconv"
"strings"
@ -58,13 +58,9 @@ func TestChannelsDeleteChannelReturnsForbiddenChatAndHidesDialogRPC(t *testing.T
if err != nil {
t.Fatalf("dispatch get dialogs: %v", err)
}
box, ok := enc.(*tg.MessagesDialogsBox)
dialogs, ok := enc.(*tg.MessagesDialogs)
if !ok {
t.Fatalf("dialogs response = %T, want box", enc)
}
dialogs, ok := box.Dialogs.(*tg.MessagesDialogs)
if !ok {
t.Fatalf("dialogs = %T %+v, want messages.dialogs", box.Dialogs, box.Dialogs)
t.Fatalf("dialogs response = %T, want *tg.MessagesDialogs", enc)
}
return dialogs
}
@ -380,7 +376,7 @@ func TestChannelsDeleteHistoryForEveryoneDrainsBatchesAndKeepsDialogVisible(t *t
if err != nil {
t.Fatalf("dispatch get dialogs: %v", err)
}
dialogs, ok := enc.(*tg.MessagesDialogsBox).Dialogs.(*tg.MessagesDialogs)
dialogs, ok := enc.(*tg.MessagesDialogs)
if !ok {
t.Fatalf("dialogs response = %T, want messages.dialogs", enc)
}

View file

@ -4,9 +4,9 @@ import (
"context"
"testing"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"
@ -103,9 +103,6 @@ func TestChannelMultiPinAndroidOpenAndJump(t *testing.T) {
Filter: &tg.InputMessagesFilterPinned{},
Limit: 40,
})
if box, ok := searchEnc.(*tg.MessagesMessagesBox); ok {
searchEnc = box.Messages
}
channelMessages, ok := searchEnc.(*tg.MessagesChannelMessages)
if !ok {
t.Fatalf("pinned search response = %T, want messages.channelMessages", searchEnc)

View file

@ -1,7 +1,7 @@
package rpc
import (
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"strings"
"telesrv/internal/domain"
"testing"

View file

@ -2,9 +2,9 @@ package rpc
import (
"context"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"
appdialogs "telesrv/internal/app/dialogs"
@ -102,13 +102,9 @@ func TestPublicChannelPreviewRPCsAllowNonMember(t *testing.T) {
if err != nil {
t.Fatalf("dispatch getHistory public preview: %v", err)
}
box, ok := enc.(*tg.MessagesMessagesBox)
history, ok := enc.(*tg.MessagesChannelMessages)
if !ok {
t.Fatalf("getHistory response = %T, want boxed messages", enc)
}
history, ok := box.Messages.(*tg.MessagesChannelMessages)
if !ok {
t.Fatalf("boxed getHistory = %T, want channel messages", box.Messages)
t.Fatalf("getHistory response = %T, want *tg.MessagesChannelMessages", enc)
}
foundPost := false
for _, item := range history.Messages {

View file

@ -3,7 +3,7 @@ package rpc
import (
"context"
"errors"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -1,101 +1,301 @@
package rpc
import (
"github.com/gotd/td/tg"
"context"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tlprofile"
)
// registerChannels 注册超级群/频道相关 RPC。messages.createChat 在这里注册,
// 因为 telesrv 将普通群创建直接实现为 megagroup。
func (r *Router) registerChannels(d *tg.ServerDispatcher) {
d.OnMessagesCreateChat(r.onMessagesCreateChat)
d.OnMessagesMigrateChat(r.onMessagesMigrateChat)
d.OnMessagesGetChats(r.onMessagesGetChats)
d.OnMessagesGetFullChat(r.onMessagesGetFullChat)
d.OnMessagesAddChatUser(r.onMessagesAddChatUser)
d.OnMessagesDeleteChatUser(r.onMessagesDeleteChatUser)
d.OnMessagesEditChatTitle(r.onMessagesEditChatTitle)
d.OnMessagesEditChatPhoto(r.onMessagesEditChatPhoto)
d.OnMessagesEditChatAdmin(r.onMessagesEditChatAdmin)
d.OnMessagesEditChatAbout(r.onMessagesEditChatAbout)
d.OnMessagesEditChatDefaultBannedRights(r.onMessagesEditChatDefaultBannedRights)
d.OnMessagesEditChatCreator(r.onMessagesEditChatCreator)
d.OnMessagesGetFutureChatCreatorAfterLeave(r.onMessagesGetFutureChatCreatorAfterLeave)
d.OnMessagesEditChatParticipantRank(r.onMessagesEditChatParticipantRank)
d.OnMessagesSetChatTheme(r.onMessagesSetChatTheme)
d.OnMessagesSetChatWallPaper(r.onMessagesSetChatWallPaper)
d.OnMessagesToggleNoForwards(r.onMessagesToggleNoForwards)
d.OnMessagesSetChatAvailableReactions(r.onMessagesSetChatAvailableReactions)
d.OnChannelsCreateChannel(r.onChannelsCreateChannel)
d.OnChannelsGetChannels(r.onChannelsGetChannels)
d.OnChannelsGetFullChannel(r.onChannelsGetFullChannel)
d.OnChannelsGetParticipants(r.onChannelsGetParticipants)
d.OnChannelsGetParticipant(r.onChannelsGetParticipant)
d.OnChannelsGetSendAs(r.onChannelsGetSendAs)
d.OnChannelsCheckUsername(r.onChannelsCheckUsername)
d.OnChannelsUpdateUsername(r.onChannelsUpdateUsername)
d.OnChannelsGetAdminedPublicChannels(r.onChannelsGetAdminedPublicChannels)
d.OnChannelsExportMessageLink(r.onChannelsExportMessageLink)
d.OnChannelsToggleSignatures(r.onChannelsToggleSignatures)
d.OnChannelsTogglePreHistoryHidden(r.onChannelsTogglePreHistoryHidden)
d.OnChannelsToggleSlowMode(r.onChannelsToggleSlowMode)
d.OnChannelsSetStickers(r.onChannelsSetStickers)
d.OnChannelsSetEmojiStickers(r.onChannelsSetEmojiStickers)
d.OnChannelsReorderUsernames(r.onChannelsReorderUsernames)
d.OnChannelsToggleUsername(r.onChannelsToggleUsername)
d.OnChannelsDeactivateAllUsernames(r.onChannelsDeactivateAllUsernames)
d.OnChannelsUpdateColor(r.onChannelsUpdateColor)
d.OnChannelsUpdateEmojiStatus(r.onChannelsUpdateEmojiStatus)
d.OnChannelsReadMessageContents(r.onChannelsReadMessageContents)
d.OnChannelsReportSpam(r.onChannelsReportSpam)
d.OnChannelsGetLeftChannels(r.onChannelsGetLeftChannels)
d.OnChannelsGetInactiveChannels(r.onChannelsGetInactiveChannels)
d.OnChannelsGetGroupsForDiscussion(r.onChannelsGetGroupsForDiscussion)
d.OnChannelsSetDiscussionGroup(r.onChannelsSetDiscussionGroup)
d.OnChannelsEditLocation(r.onChannelsEditLocation)
d.OnChannelsConvertToGigagroup(r.onChannelsConvertToGigagroup)
d.OnChannelsDeleteParticipantHistory(r.onChannelsDeleteParticipantHistory)
d.OnChannelsToggleJoinToSend(r.onChannelsToggleJoinToSend)
d.OnChannelsToggleJoinRequest(r.onChannelsToggleJoinRequest)
d.OnChannelsToggleForum(r.onChannelsToggleForum)
d.OnChannelsToggleAntiSpam(r.onChannelsToggleAntiSpam)
d.OnChannelsReportAntiSpamFalsePositive(r.onChannelsReportAntiSpamFalsePositive)
d.OnChannelsToggleParticipantsHidden(r.onChannelsToggleParticipantsHidden)
d.OnChannelsToggleViewForumAsMessages(r.onChannelsToggleViewForumAsMessages)
d.OnChannelsGetChannelRecommendations(r.onChannelsGetChannelRecommendations)
d.OnChannelsSetBoostsToUnblockRestrictions(r.onChannelsSetBoostsToUnblockRestrictions)
d.OnChannelsRestrictSponsoredMessages(r.onChannelsRestrictSponsoredMessages)
d.OnChannelsSearchPosts(r.onChannelsSearchPosts)
d.OnChannelsUpdatePaidMessagesPrice(r.onChannelsUpdatePaidMessagesPrice)
d.OnChannelsToggleAutotranslation(r.onChannelsToggleAutotranslation)
d.OnChannelsGetMessageAuthor(r.onChannelsGetMessageAuthor)
d.OnChannelsCheckSearchPostsFlood(r.onChannelsCheckSearchPostsFlood)
d.OnChannelsSetMainProfileTab(r.onChannelsSetMainProfileTab)
d.OnChannelsInviteToChannel(r.onChannelsInviteToChannel)
d.OnChannelsJoinChannel(r.onChannelsJoinChannel)
d.OnChannelsLeaveChannel(r.onChannelsLeaveChannel)
d.OnChannelsEditAdmin(r.onChannelsEditAdmin)
d.OnChannelsEditBanned(r.onChannelsEditBanned)
d.OnChannelsEditTitle(r.onChannelsEditTitle)
d.OnChannelsEditPhoto(r.onChannelsEditPhoto)
d.OnChannelsDeleteChannel(r.onChannelsDeleteChannel)
d.OnChannelsGetAdminLog(r.onChannelsGetAdminLog)
d.OnChannelsReadHistory(r.onChannelsReadHistory)
d.OnChannelsGetMessages(r.onChannelsGetMessages)
d.OnChannelsDeleteMessages(r.onChannelsDeleteMessages)
d.OnChannelsDeleteHistory(r.onChannelsDeleteHistory)
d.OnMessagesUpdatePinnedMessage(r.onMessagesUpdatePinnedMessage)
d.OnMessagesUnpinAllMessages(r.onMessagesUnpinAllMessages)
d.OnMessagesExportChatInvite(r.onMessagesExportChatInvite)
d.OnMessagesCheckChatInvite(r.onMessagesCheckChatInvite)
d.OnMessagesImportChatInvite(r.onMessagesImportChatInvite)
d.OnMessagesGetExportedChatInvites(r.onMessagesGetExportedChatInvites)
d.OnMessagesGetExportedChatInvite(r.onMessagesGetExportedChatInvite)
d.OnMessagesEditExportedChatInvite(r.onMessagesEditExportedChatInvite)
d.OnMessagesDeleteRevokedExportedChatInvites(r.onMessagesDeleteRevokedExportedChatInvites)
d.OnMessagesDeleteExportedChatInvite(r.onMessagesDeleteExportedChatInvite)
d.OnMessagesGetAdminsWithInvites(r.onMessagesGetAdminsWithInvites)
d.OnMessagesGetChatInviteImporters(r.onMessagesGetChatInviteImporters)
d.OnMessagesHideChatJoinRequest(r.onMessagesHideChatJoinRequest)
d.OnMessagesHideAllChatJoinRequests(r.onMessagesHideAllChatJoinRequests)
d.OnUpdatesGetChannelDifference(r.onUpdatesGetChannelDifference)
func (r *Router) registerChannels(d *tlprofile.Dispatcher) {
registerRPC[*tg.MessagesCreateChatRequest](d, tlprofile.SemanticMethodMessagesCreateChat, func(ctx context.Context, layerRequest *tg.MessagesCreateChatRequest) (any, error) {
return r.onMessagesCreateChat(ctx, layerRequest)
})
registerRPC[*tg.MessagesMigrateChatRequest](d, tlprofile.SemanticMethodMessagesMigrateChat, func(ctx context.Context, layerRequest *tg.MessagesMigrateChatRequest) (any, error) {
return r.onMessagesMigrateChat(ctx, layerRequest.
ChatID)
})
registerRPC[*tg.MessagesGetChatsRequest](d, tlprofile.SemanticMethodMessagesGetChats, func(ctx context.Context, layerRequest *tg.MessagesGetChatsRequest) (any, error) {
return r.onMessagesGetChats(ctx, layerRequest.
ID)
})
registerRPC[*tg.MessagesGetFullChatRequest](d, tlprofile.SemanticMethodMessagesGetFullChat, func(ctx context.Context, layerRequest *tg.MessagesGetFullChatRequest) (any, error) {
return r.onMessagesGetFullChat(ctx, layerRequest.
ChatID)
})
registerRPC[*tg.MessagesAddChatUserRequest](d, tlprofile.SemanticMethodMessagesAddChatUser, func(ctx context.Context, layerRequest *tg.MessagesAddChatUserRequest) (any, error) {
return r.onMessagesAddChatUser(ctx, layerRequest)
})
registerRPC[*tg.MessagesDeleteChatUserRequest](d, tlprofile.SemanticMethodMessagesDeleteChatUser, func(ctx context.Context, layerRequest *tg.MessagesDeleteChatUserRequest) (any, error) {
return r.onMessagesDeleteChatUser(ctx, layerRequest)
})
registerRPC[*tg.MessagesEditChatTitleRequest](d, tlprofile.SemanticMethodMessagesEditChatTitle, func(ctx context.Context, layerRequest *tg.MessagesEditChatTitleRequest) (any, error) {
return r.onMessagesEditChatTitle(ctx, layerRequest)
})
registerRPC[*tg.MessagesEditChatPhotoRequest](d, tlprofile.SemanticMethodMessagesEditChatPhoto, func(ctx context.Context, layerRequest *tg.MessagesEditChatPhotoRequest) (any, error) {
return r.onMessagesEditChatPhoto(ctx, layerRequest)
})
registerRPC[*tg.MessagesEditChatAdminRequest](d, tlprofile.SemanticMethodMessagesEditChatAdmin, func(ctx context.Context, layerRequest *tg.MessagesEditChatAdminRequest) (any, error) {
return r.onMessagesEditChatAdmin(ctx, layerRequest)
})
registerRPC[*tg.MessagesEditChatAboutRequest](d, tlprofile.SemanticMethodMessagesEditChatAbout, func(ctx context.Context, layerRequest *tg.MessagesEditChatAboutRequest) (any, error) {
return r.onMessagesEditChatAbout(ctx, layerRequest)
})
registerRPC[*tg.MessagesEditChatDefaultBannedRightsRequest](d, tlprofile.SemanticMethodMessagesEditChatDefaultBannedRights, func(ctx context.Context, layerRequest *tg.MessagesEditChatDefaultBannedRightsRequest) (any, error) {
return r.onMessagesEditChatDefaultBannedRights(ctx, layerRequest)
})
registerRPC[*tg.MessagesEditChatCreatorRequest](d, tlprofile.SemanticMethodMessagesEditChatCreator, func(ctx context.Context, layerRequest *tg.MessagesEditChatCreatorRequest) (any, error) {
return r.onMessagesEditChatCreator(ctx, layerRequest)
})
registerRPC[*tg.MessagesGetFutureChatCreatorAfterLeaveRequest](d, tlprofile.SemanticMethodMessagesGetFutureChatCreatorAfterLeave, func(ctx context.Context, layerRequest *tg.MessagesGetFutureChatCreatorAfterLeaveRequest) (any, error) {
return r.onMessagesGetFutureChatCreatorAfterLeave(ctx, layerRequest.
Peer)
})
registerRPC[*tg.MessagesEditChatParticipantRankRequest](d, tlprofile.SemanticMethodMessagesEditChatParticipantRank, func(ctx context.Context, layerRequest *tg.MessagesEditChatParticipantRankRequest) (any, error) {
return r.onMessagesEditChatParticipantRank(ctx, layerRequest)
})
registerRPC[*tg.MessagesSetChatThemeRequest](d, tlprofile.SemanticMethodMessagesSetChatTheme, func(ctx context.Context, layerRequest *tg.MessagesSetChatThemeRequest) (any, error) {
return r.onMessagesSetChatTheme(ctx, layerRequest)
})
registerRPC[*tg.MessagesSetChatWallPaperRequest](d, tlprofile.SemanticMethodMessagesSetChatWallPaper, func(ctx context.Context, layerRequest *tg.MessagesSetChatWallPaperRequest) (any, error) {
return r.onMessagesSetChatWallPaper(ctx, layerRequest)
})
registerRPC[*tg.MessagesToggleNoForwardsRequest](d, tlprofile.SemanticMethodMessagesToggleNoForwards, func(ctx context.Context, layerRequest *tg.MessagesToggleNoForwardsRequest) (any, error) {
return r.onMessagesToggleNoForwards(ctx, layerRequest)
})
registerRPC[*tg.MessagesSetChatAvailableReactionsRequest](d, tlprofile.SemanticMethodMessagesSetChatAvailableReactions, func(ctx context.Context, layerRequest *tg.MessagesSetChatAvailableReactionsRequest) (any, error) {
return r.onMessagesSetChatAvailableReactions(ctx, layerRequest)
})
registerRPC[*tg.ChannelsCreateChannelRequest](d, tlprofile.SemanticMethodChannelsCreateChannel, func(ctx context.Context, layerRequest *tg.ChannelsCreateChannelRequest) (any, error) {
return r.onChannelsCreateChannel(ctx, layerRequest)
})
registerRPC[*tg.ChannelsGetChannelsRequest](d, tlprofile.SemanticMethodChannelsGetChannels, func(ctx context.Context, layerRequest *tg.ChannelsGetChannelsRequest) (any, error) {
return r.onChannelsGetChannels(ctx, layerRequest.
ID)
})
registerRPC[*tg.ChannelsGetFullChannelRequest](d, tlprofile.SemanticMethodChannelsGetFullChannel, func(ctx context.Context, layerRequest *tg.ChannelsGetFullChannelRequest) (any, error) {
return r.onChannelsGetFullChannel(ctx, layerRequest.
Channel)
})
registerRPC[*tg.ChannelsGetParticipantsRequest](d, tlprofile.SemanticMethodChannelsGetParticipants, func(ctx context.Context, layerRequest *tg.ChannelsGetParticipantsRequest) (any, error) {
return r.onChannelsGetParticipants(ctx, layerRequest)
})
registerRPC[*tg.ChannelsGetParticipantRequest](d, tlprofile.SemanticMethodChannelsGetParticipant, func(ctx context.Context, layerRequest *tg.ChannelsGetParticipantRequest) (any, error) {
return r.onChannelsGetParticipant(ctx, layerRequest)
})
registerRPC[*tg.ChannelsGetSendAsRequest](d, tlprofile.SemanticMethodChannelsGetSendAs, func(ctx context.Context, layerRequest *tg.ChannelsGetSendAsRequest) (any, error) {
return r.onChannelsGetSendAs(ctx, layerRequest)
})
registerRPC[*tg.ChannelsCheckUsernameRequest](d, tlprofile.SemanticMethodChannelsCheckUsername, func(ctx context.Context, layerRequest *tg.ChannelsCheckUsernameRequest) (any, error) {
return r.onChannelsCheckUsername(ctx, layerRequest)
})
registerRPC[*tg.ChannelsUpdateUsernameRequest](d, tlprofile.SemanticMethodChannelsUpdateUsername, func(ctx context.Context, layerRequest *tg.ChannelsUpdateUsernameRequest) (any, error) {
return r.onChannelsUpdateUsername(ctx, layerRequest)
})
registerRPC[*tg.ChannelsGetAdminedPublicChannelsRequest](d, tlprofile.SemanticMethodChannelsGetAdminedPublicChannels, func(ctx context.Context, layerRequest *tg.ChannelsGetAdminedPublicChannelsRequest) (any, error) {
return r.onChannelsGetAdminedPublicChannels(ctx, layerRequest)
})
registerRPC[*tg.ChannelsExportMessageLinkRequest](d, tlprofile.SemanticMethodChannelsExportMessageLink, func(ctx context.Context, layerRequest *tg.ChannelsExportMessageLinkRequest) (any, error) {
return r.onChannelsExportMessageLink(ctx, layerRequest)
})
registerRPC[*tg.ChannelsToggleSignaturesRequest](d, tlprofile.SemanticMethodChannelsToggleSignatures, func(ctx context.Context, layerRequest *tg.ChannelsToggleSignaturesRequest) (any, error) {
return r.onChannelsToggleSignatures(ctx, layerRequest)
})
registerRPC[*tg.ChannelsTogglePreHistoryHiddenRequest](d, tlprofile.SemanticMethodChannelsTogglePreHistoryHidden, func(ctx context.Context, layerRequest *tg.ChannelsTogglePreHistoryHiddenRequest) (any, error) {
return r.onChannelsTogglePreHistoryHidden(ctx, layerRequest)
})
registerRPC[*tg.ChannelsToggleSlowModeRequest](d, tlprofile.SemanticMethodChannelsToggleSlowMode, func(ctx context.Context, layerRequest *tg.ChannelsToggleSlowModeRequest) (any, error) {
return r.onChannelsToggleSlowMode(ctx, layerRequest)
})
registerRPC[*tg.ChannelsSetStickersRequest](d, tlprofile.SemanticMethodChannelsSetStickers, func(ctx context.Context, layerRequest *tg.ChannelsSetStickersRequest) (any, error) {
return r.onChannelsSetStickers(ctx, layerRequest)
})
registerRPC[*tg.ChannelsSetEmojiStickersRequest](d, tlprofile.SemanticMethodChannelsSetEmojiStickers, func(ctx context.Context, layerRequest *tg.ChannelsSetEmojiStickersRequest) (any, error) {
return r.onChannelsSetEmojiStickers(ctx, layerRequest)
})
registerRPC[*tg.ChannelsReorderUsernamesRequest](d, tlprofile.SemanticMethodChannelsReorderUsernames, func(ctx context.Context, layerRequest *tg.ChannelsReorderUsernamesRequest) (any, error) {
return r.onChannelsReorderUsernames(ctx, layerRequest)
})
registerRPC[*tg.ChannelsToggleUsernameRequest](d, tlprofile.SemanticMethodChannelsToggleUsername, func(ctx context.Context, layerRequest *tg.ChannelsToggleUsernameRequest) (any, error) {
return r.onChannelsToggleUsername(ctx, layerRequest)
})
registerRPC[*tg.ChannelsDeactivateAllUsernamesRequest](d, tlprofile.SemanticMethodChannelsDeactivateAllUsernames, func(ctx context.Context, layerRequest *tg.ChannelsDeactivateAllUsernamesRequest) (any, error) {
return r.onChannelsDeactivateAllUsernames(ctx, layerRequest.
Channel)
})
registerRPC[*tg.ChannelsUpdateColorRequest](d, tlprofile.SemanticMethodChannelsUpdateColor, func(ctx context.Context, layerRequest *tg.ChannelsUpdateColorRequest) (any, error) {
return r.onChannelsUpdateColor(ctx, layerRequest)
})
registerRPC[*tg.ChannelsUpdateEmojiStatusRequest](d, tlprofile.SemanticMethodChannelsUpdateEmojiStatus, func(ctx context.Context, layerRequest *tg.ChannelsUpdateEmojiStatusRequest) (any, error) {
return r.onChannelsUpdateEmojiStatus(ctx, layerRequest)
})
registerRPC[*tg.ChannelsReadMessageContentsRequest](d, tlprofile.SemanticMethodChannelsReadMessageContents, func(ctx context.Context, layerRequest *tg.ChannelsReadMessageContentsRequest) (any, error) {
return r.onChannelsReadMessageContents(ctx, layerRequest)
})
registerRPC[*tg.ChannelsReportSpamRequest](d, tlprofile.SemanticMethodChannelsReportSpam, func(ctx context.Context, layerRequest *tg.ChannelsReportSpamRequest) (any, error) {
return r.onChannelsReportSpam(ctx, layerRequest)
})
registerRPC[*tg.ChannelsGetLeftChannelsRequest](d, tlprofile.SemanticMethodChannelsGetLeftChannels, func(ctx context.Context, layerRequest *tg.ChannelsGetLeftChannelsRequest) (any, error) {
return r.onChannelsGetLeftChannels(ctx, layerRequest.
Offset)
})
registerRPC[*tg.ChannelsGetInactiveChannelsRequest](d, tlprofile.SemanticMethodChannelsGetInactiveChannels, func(ctx context.Context, layerRequest *tg.ChannelsGetInactiveChannelsRequest) (any, error) {
return r.onChannelsGetInactiveChannels(ctx)
})
registerRPC[*tg.ChannelsGetGroupsForDiscussionRequest](d, tlprofile.SemanticMethodChannelsGetGroupsForDiscussion, func(ctx context.Context, layerRequest *tg.ChannelsGetGroupsForDiscussionRequest) (any, error) {
return r.onChannelsGetGroupsForDiscussion(ctx)
})
registerRPC[*tg.ChannelsSetDiscussionGroupRequest](d, tlprofile.SemanticMethodChannelsSetDiscussionGroup, func(ctx context.Context, layerRequest *tg.ChannelsSetDiscussionGroupRequest) (any, error) {
return r.onChannelsSetDiscussionGroup(ctx, layerRequest)
})
registerRPC[*tg.ChannelsEditLocationRequest](d, tlprofile.SemanticMethodChannelsEditLocation, func(ctx context.Context, layerRequest *tg.ChannelsEditLocationRequest) (any, error) {
return r.onChannelsEditLocation(ctx, layerRequest)
})
registerRPC[*tg.ChannelsConvertToGigagroupRequest](d, tlprofile.SemanticMethodChannelsConvertToGigagroup, func(ctx context.Context, layerRequest *tg.ChannelsConvertToGigagroupRequest) (any, error) {
return r.onChannelsConvertToGigagroup(ctx, layerRequest.
Channel)
})
registerRPC[*tg.ChannelsDeleteParticipantHistoryRequest](d, tlprofile.SemanticMethodChannelsDeleteParticipantHistory, func(ctx context.Context, layerRequest *tg.ChannelsDeleteParticipantHistoryRequest) (any, error) {
return r.onChannelsDeleteParticipantHistory(ctx, layerRequest)
})
registerRPC[*tg.ChannelsToggleJoinToSendRequest](d, tlprofile.SemanticMethodChannelsToggleJoinToSend, func(ctx context.Context, layerRequest *tg.ChannelsToggleJoinToSendRequest) (any, error) {
return r.onChannelsToggleJoinToSend(ctx, layerRequest)
})
registerRPC[*tg.ChannelsToggleJoinRequestRequest](d, tlprofile.SemanticMethodChannelsToggleJoinRequest, func(ctx context.Context, layerRequest *tg.ChannelsToggleJoinRequestRequest) (any, error) {
return r.onChannelsToggleJoinRequest(ctx, layerRequest)
})
registerRPC[*tg.ChannelsToggleForumRequest](d, tlprofile.SemanticMethodChannelsToggleForum, func(ctx context.Context, layerRequest *tg.ChannelsToggleForumRequest) (any, error) {
return r.onChannelsToggleForum(ctx, layerRequest)
})
registerRPC[*tg.ChannelsToggleAntiSpamRequest](d, tlprofile.SemanticMethodChannelsToggleAntiSpam, func(ctx context.Context, layerRequest *tg.ChannelsToggleAntiSpamRequest) (any, error) {
return r.onChannelsToggleAntiSpam(ctx, layerRequest)
})
registerRPC[*tg.ChannelsReportAntiSpamFalsePositiveRequest](d, tlprofile.SemanticMethodChannelsReportAntiSpamFalsePositive, func(ctx context.Context, layerRequest *tg.ChannelsReportAntiSpamFalsePositiveRequest) (any, error) {
return r.onChannelsReportAntiSpamFalsePositive(ctx, layerRequest)
})
registerRPC[*tg.ChannelsToggleParticipantsHiddenRequest](d, tlprofile.SemanticMethodChannelsToggleParticipantsHidden, func(ctx context.Context, layerRequest *tg.ChannelsToggleParticipantsHiddenRequest) (any, error) {
return r.onChannelsToggleParticipantsHidden(ctx, layerRequest)
})
registerRPC[*tg.ChannelsToggleViewForumAsMessagesRequest](d, tlprofile.SemanticMethodChannelsToggleViewForumAsMessages, func(ctx context.Context, layerRequest *tg.ChannelsToggleViewForumAsMessagesRequest) (any, error) {
return r.onChannelsToggleViewForumAsMessages(ctx, layerRequest)
})
registerRPC[*tg.ChannelsGetChannelRecommendationsRequest](d, tlprofile.SemanticMethodChannelsGetChannelRecommendations, func(ctx context.Context, layerRequest *tg.ChannelsGetChannelRecommendationsRequest) (any, error) {
return r.onChannelsGetChannelRecommendations(ctx, layerRequest)
})
registerRPC[*tg.ChannelsSetBoostsToUnblockRestrictionsRequest](d, tlprofile.SemanticMethodChannelsSetBoostsToUnblockRestrictions, func(ctx context.Context, layerRequest *tg.ChannelsSetBoostsToUnblockRestrictionsRequest) (any, error) {
return r.onChannelsSetBoostsToUnblockRestrictions(ctx, layerRequest)
})
registerRPC[*tg.ChannelsRestrictSponsoredMessagesRequest](d, tlprofile.SemanticMethodChannelsRestrictSponsoredMessages, func(ctx context.Context, layerRequest *tg.ChannelsRestrictSponsoredMessagesRequest) (any, error) {
return r.onChannelsRestrictSponsoredMessages(ctx, layerRequest)
})
registerRPC[*tg.ChannelsSearchPostsRequest](d, tlprofile.SemanticMethodChannelsSearchPosts, func(ctx context.Context, layerRequest *tg.ChannelsSearchPostsRequest) (any, error) {
return r.onChannelsSearchPosts(ctx, layerRequest)
})
registerRPC[*tg.ChannelsUpdatePaidMessagesPriceRequest](d, tlprofile.SemanticMethodChannelsUpdatePaidMessagesPrice, func(ctx context.Context, layerRequest *tg.ChannelsUpdatePaidMessagesPriceRequest) (any, error) {
return r.onChannelsUpdatePaidMessagesPrice(ctx, layerRequest)
})
registerRPC[*tg.ChannelsToggleAutotranslationRequest](d, tlprofile.SemanticMethodChannelsToggleAutotranslation, func(ctx context.Context, layerRequest *tg.ChannelsToggleAutotranslationRequest) (any, error) {
return r.onChannelsToggleAutotranslation(ctx, layerRequest)
})
registerRPC[*tg.ChannelsGetMessageAuthorRequest](d, tlprofile.SemanticMethodChannelsGetMessageAuthor, func(ctx context.Context, layerRequest *tg.ChannelsGetMessageAuthorRequest) (any, error) {
return r.onChannelsGetMessageAuthor(ctx, layerRequest)
})
registerRPC[*tg.ChannelsCheckSearchPostsFloodRequest](d, tlprofile.SemanticMethodChannelsCheckSearchPostsFlood, func(ctx context.Context, layerRequest *tg.ChannelsCheckSearchPostsFloodRequest) (any, error) {
return r.onChannelsCheckSearchPostsFlood(ctx, layerRequest)
})
registerRPC[*tg.ChannelsSetMainProfileTabRequest](d, tlprofile.SemanticMethodChannelsSetMainProfileTab, func(ctx context.Context, layerRequest *tg.ChannelsSetMainProfileTabRequest) (any, error) {
return r.onChannelsSetMainProfileTab(ctx, layerRequest)
})
registerRPC[*tg.ChannelsInviteToChannelRequest](d, tlprofile.SemanticMethodChannelsInviteToChannel, func(ctx context.Context, layerRequest *tg.ChannelsInviteToChannelRequest) (any, error) {
return r.onChannelsInviteToChannel(ctx, layerRequest)
})
registerRPC[*tg.ChannelsJoinChannelRequest](d, tlprofile.SemanticMethodChannelsJoinChannel, func(ctx context.Context, layerRequest *tg.ChannelsJoinChannelRequest) (any, error) {
return r.onChannelsJoinChannel(ctx, layerRequest.
Channel)
})
registerRPC[*tg.ChannelsLeaveChannelRequest](d, tlprofile.SemanticMethodChannelsLeaveChannel, func(ctx context.Context, layerRequest *tg.ChannelsLeaveChannelRequest) (any, error) {
return r.onChannelsLeaveChannel(ctx, layerRequest.
Channel)
})
registerRPC[*tg.ChannelsEditAdminRequest](d, tlprofile.SemanticMethodChannelsEditAdmin, func(ctx context.Context, layerRequest *tg.ChannelsEditAdminRequest) (any, error) {
return r.onChannelsEditAdmin(ctx, layerRequest)
})
registerRPC[*tg.ChannelsEditBannedRequest](d, tlprofile.SemanticMethodChannelsEditBanned, func(ctx context.Context, layerRequest *tg.ChannelsEditBannedRequest) (any, error) {
return r.onChannelsEditBanned(ctx, layerRequest)
})
registerRPC[*tg.ChannelsEditTitleRequest](d, tlprofile.SemanticMethodChannelsEditTitle, func(ctx context.Context, layerRequest *tg.ChannelsEditTitleRequest) (any, error) {
return r.onChannelsEditTitle(ctx, layerRequest)
})
registerRPC[*tg.ChannelsEditPhotoRequest](d, tlprofile.SemanticMethodChannelsEditPhoto, func(ctx context.Context, layerRequest *tg.ChannelsEditPhotoRequest) (any, error) {
return r.onChannelsEditPhoto(ctx, layerRequest)
})
registerRPC[*tg.ChannelsDeleteChannelRequest](d, tlprofile.SemanticMethodChannelsDeleteChannel, func(ctx context.Context, layerRequest *tg.ChannelsDeleteChannelRequest) (any, error) {
return r.onChannelsDeleteChannel(ctx, layerRequest.
Channel)
})
registerRPC[*tg.ChannelsGetAdminLogRequest](d, tlprofile.SemanticMethodChannelsGetAdminLog, func(ctx context.Context, layerRequest *tg.ChannelsGetAdminLogRequest) (any, error) {
return r.onChannelsGetAdminLog(ctx, layerRequest)
})
registerRPC[*tg.ChannelsReadHistoryRequest](d, tlprofile.SemanticMethodChannelsReadHistory, func(ctx context.Context, layerRequest *tg.ChannelsReadHistoryRequest) (any, error) {
return r.onChannelsReadHistory(ctx, layerRequest)
})
registerRPC[*tg.ChannelsGetMessagesRequest](d, tlprofile.SemanticMethodChannelsGetMessages, func(ctx context.Context, layerRequest *tg.ChannelsGetMessagesRequest) (any, error) {
return r.onChannelsGetMessages(ctx, layerRequest)
})
registerRPC[*tg.ChannelsDeleteMessagesRequest](d, tlprofile.SemanticMethodChannelsDeleteMessages, func(ctx context.Context, layerRequest *tg.ChannelsDeleteMessagesRequest) (any, error) {
return r.onChannelsDeleteMessages(ctx, layerRequest)
})
registerRPC[*tg.ChannelsDeleteHistoryRequest](d, tlprofile.SemanticMethodChannelsDeleteHistory, func(ctx context.Context, layerRequest *tg.ChannelsDeleteHistoryRequest) (any, error) {
return r.onChannelsDeleteHistory(ctx, layerRequest)
})
registerRPC[*tg.MessagesUpdatePinnedMessageRequest](d, tlprofile.SemanticMethodMessagesUpdatePinnedMessage, func(ctx context.Context, layerRequest *tg.MessagesUpdatePinnedMessageRequest) (any, error) {
return r.onMessagesUpdatePinnedMessage(ctx, layerRequest)
})
registerRPC[*tg.MessagesUnpinAllMessagesRequest](d, tlprofile.SemanticMethodMessagesUnpinAllMessages, func(ctx context.Context, layerRequest *tg.MessagesUnpinAllMessagesRequest) (any, error) {
return r.onMessagesUnpinAllMessages(ctx, layerRequest)
})
registerRPC[*tg.MessagesExportChatInviteRequest](d, tlprofile.SemanticMethodMessagesExportChatInvite, func(ctx context.Context, layerRequest *tg.MessagesExportChatInviteRequest) (any, error) {
return r.onMessagesExportChatInvite(ctx, layerRequest)
})
registerRPC[*tg.MessagesCheckChatInviteRequest](d, tlprofile.SemanticMethodMessagesCheckChatInvite, func(ctx context.Context, layerRequest *tg.MessagesCheckChatInviteRequest) (any, error) {
return r.onMessagesCheckChatInvite(ctx, layerRequest.
Hash)
})
registerRPC[*tg.MessagesImportChatInviteRequest](d, tlprofile.SemanticMethodMessagesImportChatInvite, func(ctx context.Context, layerRequest *tg.MessagesImportChatInviteRequest) (any, error) {
return r.onMessagesImportChatInvite(ctx, layerRequest.
Hash)
})
registerRPC[*tg.MessagesGetExportedChatInvitesRequest](d, tlprofile.SemanticMethodMessagesGetExportedChatInvites, func(ctx context.Context, layerRequest *tg.MessagesGetExportedChatInvitesRequest) (any, error) {
return r.onMessagesGetExportedChatInvites(ctx, layerRequest)
})
registerRPC[*tg.MessagesGetExportedChatInviteRequest](d, tlprofile.SemanticMethodMessagesGetExportedChatInvite, func(ctx context.Context, layerRequest *tg.MessagesGetExportedChatInviteRequest) (any, error) {
return r.onMessagesGetExportedChatInvite(ctx, layerRequest)
})
registerRPC[*tg.MessagesEditExportedChatInviteRequest](d, tlprofile.SemanticMethodMessagesEditExportedChatInvite, func(ctx context.Context, layerRequest *tg.MessagesEditExportedChatInviteRequest) (any, error) {
return r.onMessagesEditExportedChatInvite(ctx, layerRequest)
})
registerRPC[*tg.MessagesDeleteRevokedExportedChatInvitesRequest](d, tlprofile.SemanticMethodMessagesDeleteRevokedExportedChatInvites, func(ctx context.Context, layerRequest *tg.MessagesDeleteRevokedExportedChatInvitesRequest) (any, error) {
return r.onMessagesDeleteRevokedExportedChatInvites(ctx, layerRequest)
})
registerRPC[*tg.MessagesDeleteExportedChatInviteRequest](d, tlprofile.SemanticMethodMessagesDeleteExportedChatInvite, func(ctx context.Context, layerRequest *tg.MessagesDeleteExportedChatInviteRequest) (any, error) {
return r.onMessagesDeleteExportedChatInvite(ctx, layerRequest)
})
registerRPC[*tg.MessagesGetAdminsWithInvitesRequest](d, tlprofile.SemanticMethodMessagesGetAdminsWithInvites, func(ctx context.Context, layerRequest *tg.MessagesGetAdminsWithInvitesRequest) (any, error) {
return r.onMessagesGetAdminsWithInvites(ctx, layerRequest.
Peer)
})
registerRPC[*tg.MessagesGetChatInviteImportersRequest](d, tlprofile.SemanticMethodMessagesGetChatInviteImporters, func(ctx context.Context, layerRequest *tg.MessagesGetChatInviteImportersRequest) (any, error) {
return r.onMessagesGetChatInviteImporters(ctx, layerRequest)
})
registerRPC[*tg.MessagesHideChatJoinRequestRequest](d, tlprofile.SemanticMethodMessagesHideChatJoinRequest, func(ctx context.Context, layerRequest *tg.MessagesHideChatJoinRequestRequest) (any, error) {
return r.onMessagesHideChatJoinRequest(ctx, layerRequest)
})
registerRPC[*tg.MessagesHideAllChatJoinRequestsRequest](d, tlprofile.SemanticMethodMessagesHideAllChatJoinRequests, func(ctx context.Context, layerRequest *tg.MessagesHideAllChatJoinRequestsRequest) (any, error) {
return r.onMessagesHideAllChatJoinRequests(ctx, layerRequest)
})
registerRPC[*tg.UpdatesGetChannelDifferenceRequest](d, tlprofile.SemanticMethodUpdatesGetChannelDifference, func(ctx context.Context, layerRequest *tg.UpdatesGetChannelDifferenceRequest) (any, error) {
return r.onUpdatesGetChannelDifference(ctx, layerRequest)
})
}

View file

@ -6,8 +6,8 @@ import (
"testing"
"time"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"

View file

@ -3,7 +3,7 @@ package rpc
import (
"context"
"errors"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"strings"
"telesrv/internal/domain"
"unicode/utf8"

View file

@ -6,8 +6,8 @@ import (
"strings"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
appchannels "telesrv/internal/app/channels"

View file

@ -2,7 +2,7 @@ package rpc
import (
"context"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -4,8 +4,8 @@ import (
"context"
"errors"
"fmt"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"go.uber.org/zap"
"telesrv/internal/domain"
)
@ -174,7 +174,7 @@ func (r *Router) onMessagesUnpinAllMessages(ctx context.Context, req *tg.Message
// createChatNeedsLegacyChat decides whether messages.createChat returns the
// legacy chat-shaped response. Old DrKLO/TDesktop clients (and pre-initConnection
// sessions) expect it; modern clients get the canonical InvitedUsers response.
// The old createChat#34a818 id now upgrades via layerwire to the canonical id,
// The old createChat#34a818 id now upgrades via the gotdgen client overlay,
// and android client metadata is applied during that upgrade, so keying on
// ClientType (below) is sufficient — no per-request ctx flag is needed.
func createChatNeedsLegacyChat(ctx context.Context) bool {
@ -655,7 +655,7 @@ func (r *Router) channelIDFromLegacyInputPeerChecked(ctx context.Context, userID
func channelInvalidErr(err error) error {
switch {
case errors.Is(err, domain.ErrUserSendRestricted):
case errors.Is(err, domain.ErrUserFrozen):
return frozenMethodInvalidErr()
case errors.Is(err, domain.ErrChannelTitleInvalid):
return tgerr400("CHAT_TITLE_EMPTY")

View file

@ -2,7 +2,7 @@ package rpc
import (
"context"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -4,7 +4,7 @@ import (
"context"
"errors"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap"
"telesrv/internal/domain"
@ -18,15 +18,19 @@ func (r *Router) onUpdatesGetChannelDifference(ctx context.Context, req *tg.Upda
if err != nil {
return nil, internalErr()
}
// difference 类 catch-up FLOOD_WAIT设计 Phase 2 / §10.3nudge 被消费后客户端会触发
// getChannelDifference大群 nudge 全速前需限速防风暴。未配置阈值时不限速。
if err := r.checkCatchupRateLimit(ctx, userID, channelDifferenceRateLimitKeyPrefix); err != nil {
return nil, err
}
channelID, err := r.channelIDFromInput(ctx, userID, req.Channel)
if err != nil {
return nil, err
}
if err := r.checkFrozenChannelParticipants(ctx, userID, channelID); err != nil {
return nil, err
}
// difference 类 catch-up FLOOD_WAIT设计 Phase 2 / §10.3nudge 被消费后客户端会触发
// getChannelDifference大群 nudge 全速前需限速防风暴。未配置阈值时不限速。
// participant gate 必须先于限流写入,保证冻结拒绝没有副作用。
if err := r.checkCatchupRateLimit(ctx, userID, channelDifferenceRateLimitKeyPrefix); err != nil {
return nil, err
}
r.trackChannelInterest(ctx, userID, channelID)
diff, err := r.deps.Channels.GetDifference(ctx, userID, domain.ChannelDifferenceRequest{
UserID: userID,

View file

@ -2,9 +2,9 @@ package rpc
import (
"context"
"github.com/gotd/td/clock"
"github.com/gotd/td/proto"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/proto"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"strings"
appchannels "telesrv/internal/app/channels"

View file

@ -5,8 +5,8 @@ import (
"strings"
"testing"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
accountapp "telesrv/internal/app/account"

View file

@ -4,23 +4,51 @@ import (
"context"
"errors"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tlprofile"
"telesrv/internal/domain"
)
func (r *Router) registerChatlists(d *tg.ServerDispatcher) {
d.OnChatlistsExportChatlistInvite(r.onChatlistsExportChatlistInvite)
d.OnChatlistsDeleteExportedInvite(r.onChatlistsDeleteExportedInvite)
d.OnChatlistsEditExportedInvite(r.onChatlistsEditExportedInvite)
d.OnChatlistsGetExportedInvites(r.onChatlistsGetExportedInvites)
d.OnChatlistsCheckChatlistInvite(r.onChatlistsCheckChatlistInvite)
d.OnChatlistsJoinChatlistInvite(r.onChatlistsJoinChatlistInvite)
d.OnChatlistsGetChatlistUpdates(r.onChatlistsGetChatlistUpdates)
d.OnChatlistsJoinChatlistUpdates(r.onChatlistsJoinChatlistUpdates)
d.OnChatlistsHideChatlistUpdates(r.onChatlistsHideChatlistUpdates)
d.OnChatlistsGetLeaveChatlistSuggestions(r.onChatlistsGetLeaveChatlistSuggestions)
d.OnChatlistsLeaveChatlist(r.onChatlistsLeaveChatlist)
func (r *Router) registerChatlists(d *tlprofile.Dispatcher) {
registerRPC[*tg.ChatlistsExportChatlistInviteRequest](d, tlprofile.SemanticMethodChatlistsExportChatlistInvite, func(ctx context.Context, layerRequest *tg.ChatlistsExportChatlistInviteRequest) (any, error) {
return r.onChatlistsExportChatlistInvite(ctx, layerRequest)
})
registerRPC[*tg.ChatlistsDeleteExportedInviteRequest](d, tlprofile.SemanticMethodChatlistsDeleteExportedInvite, func(ctx context.Context, layerRequest *tg.ChatlistsDeleteExportedInviteRequest) (any, error) {
return r.onChatlistsDeleteExportedInvite(ctx, layerRequest)
})
registerRPC[*tg.ChatlistsEditExportedInviteRequest](d, tlprofile.SemanticMethodChatlistsEditExportedInvite, func(ctx context.Context, layerRequest *tg.ChatlistsEditExportedInviteRequest) (any, error) {
return r.onChatlistsEditExportedInvite(ctx, layerRequest)
})
registerRPC[*tg.ChatlistsGetExportedInvitesRequest](d, tlprofile.SemanticMethodChatlistsGetExportedInvites, func(ctx context.Context, layerRequest *tg.ChatlistsGetExportedInvitesRequest) (any, error) {
return r.onChatlistsGetExportedInvites(ctx, layerRequest.
Chatlist)
})
registerRPC[*tg.ChatlistsCheckChatlistInviteRequest](d, tlprofile.SemanticMethodChatlistsCheckChatlistInvite, func(ctx context.Context, layerRequest *tg.ChatlistsCheckChatlistInviteRequest) (any, error) {
return r.onChatlistsCheckChatlistInvite(ctx, layerRequest.
Slug)
})
registerRPC[*tg.ChatlistsJoinChatlistInviteRequest](d, tlprofile.SemanticMethodChatlistsJoinChatlistInvite, func(ctx context.Context, layerRequest *tg.ChatlistsJoinChatlistInviteRequest) (any, error) {
return r.onChatlistsJoinChatlistInvite(ctx, layerRequest)
})
registerRPC[*tg.ChatlistsGetChatlistUpdatesRequest](d, tlprofile.SemanticMethodChatlistsGetChatlistUpdates, func(ctx context.Context, layerRequest *tg.ChatlistsGetChatlistUpdatesRequest) (any, error) {
return r.onChatlistsGetChatlistUpdates(ctx, layerRequest.
Chatlist)
})
registerRPC[*tg.ChatlistsJoinChatlistUpdatesRequest](d, tlprofile.SemanticMethodChatlistsJoinChatlistUpdates, func(ctx context.Context, layerRequest *tg.ChatlistsJoinChatlistUpdatesRequest) (any, error) {
return r.onChatlistsJoinChatlistUpdates(ctx, layerRequest)
})
registerRPC[*tg.ChatlistsHideChatlistUpdatesRequest](d, tlprofile.SemanticMethodChatlistsHideChatlistUpdates, func(ctx context.Context, layerRequest *tg.ChatlistsHideChatlistUpdatesRequest) (any, error) {
return r.onChatlistsHideChatlistUpdates(ctx, layerRequest.
Chatlist)
})
registerRPC[*tg.ChatlistsGetLeaveChatlistSuggestionsRequest](d, tlprofile.SemanticMethodChatlistsGetLeaveChatlistSuggestions, func(ctx context.Context, layerRequest *tg.ChatlistsGetLeaveChatlistSuggestionsRequest) (any, error) {
return r.onChatlistsGetLeaveChatlistSuggestions(ctx, layerRequest.
Chatlist)
})
registerRPC[*tg.ChatlistsLeaveChatlistRequest](d, tlprofile.SemanticMethodChatlistsLeaveChatlist, func(ctx context.Context, layerRequest *tg.ChatlistsLeaveChatlistRequest) (any, error) {
return r.onChatlistsLeaveChatlist(ctx, layerRequest)
})
}
func (r *Router) onChatlistsExportChatlistInvite(ctx context.Context, req *tg.ChatlistsExportChatlistInviteRequest) (*tg.ChatlistsExportedChatlistInvite, error) {

View file

@ -4,9 +4,9 @@ import (
"context"
"testing"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap"
"telesrv/internal/domain"

View file

@ -0,0 +1,106 @@
package rpc
import (
"context"
"strings"
"testing"
"unicode/utf8"
)
func TestNormalizeClientInfoBoundsMetadataAfterClassification(t *testing.T) {
raw := ClientInfo{
APIID: 2040,
DeviceModel: "Mozilla/5.0 (iPhone) AppleWebKit/605.1.15 Safari/604.1 " + strings.Repeat("x", 160),
SystemVersion: strings.Repeat("iOS", 30),
AppVersion: strings.Repeat("2.2", 30),
SystemLangCode: strings.Repeat("zh-", 30),
LangPack: "webk" + strings.Repeat("x", 80),
LangCode: strings.Repeat("zh-", 30),
}
got := normalizeClientInfo(raw)
if got.ClientType() != ClientTypeTWeb {
t.Fatalf("client type = %s, want %s", got.ClientType(), ClientTypeTWeb)
}
assertClientMetadataRunes(t, "device model", got.DeviceModel, maxClientDeviceModelRunes)
assertClientMetadataRunes(t, "system version", got.SystemVersion, maxClientMetadataRunes)
assertClientMetadataRunes(t, "app version", got.AppVersion, maxClientMetadataRunes)
assertClientMetadataRunes(t, "system language", got.SystemLangCode, maxClientMetadataRunes)
assertClientMetadataRunes(t, "language pack", got.LangPack, maxClientMetadataRunes)
assertClientMetadataRunes(t, "language code", got.LangCode, maxClientMetadataRunes)
}
func TestNormalizeClientInfoUsesRuneLimitsAndProducesValidUTF8(t *testing.T) {
got := normalizeClientInfo(ClientInfo{
DeviceModel: strings.Repeat("\u754c", maxClientDeviceModelRunes+1),
SystemVersion: strings.Repeat("\U0001f4f1", maxClientMetadataRunes+1),
AppVersion: "2.2" + string([]byte{0xff}),
LangPack: "webk",
})
assertClientMetadataRunes(t, "device model", got.DeviceModel, maxClientDeviceModelRunes)
assertClientMetadataRunes(t, "system version", got.SystemVersion, maxClientMetadataRunes)
if !utf8.ValidString(got.AppVersion) {
t.Fatalf("app version is not valid UTF-8: %q", got.AppVersion)
}
}
func TestNormalizedClientInfoIsSharedByAuthPersistencePaths(t *testing.T) {
authKeyID := [8]byte{1, 2, 3, 4, 5, 6, 7, 8}
ctx := WithLayer(context.Background(), 227)
ctx = WithAuthKeyID(ctx, authKeyID)
ctx = WithClientInfo(ctx, ClientInfo{
APIID: 2040,
DeviceModel: "Mozilla/5.0 AppleWebKit/605.1.15 " + strings.Repeat("x", 160),
SystemVersion: strings.Repeat("iOS", 30),
AppVersion: strings.Repeat("2.2", 30),
LangPack: "webk",
})
info, ok := ClientInfoFrom(ctx)
if !ok {
t.Fatal("normalized client info missing from context")
}
authz := (&Router{}).authzFromCtx(ctx)
authKeyInfo := domainAuthKeyClientInfo(clientSessionInfo{
layer: LayerFrom(ctx),
hasClientInfo: true,
clientInfo: info,
})
if authz.DeviceModel != authKeyInfo.DeviceModel ||
authz.SystemVersion != authKeyInfo.SystemVersion ||
authz.AppVersion != authKeyInfo.AppVersion ||
authz.Platform != authKeyInfo.Platform ||
authz.APIID != authKeyInfo.APIID ||
authz.Layer != authKeyInfo.Layer {
t.Fatalf("authorization metadata %+v differs from auth-key metadata %+v", authz, authKeyInfo)
}
}
func TestNormalizeClientInfoPreservesMetadataWithinLimits(t *testing.T) {
raw := ClientInfo{
APIID: 4,
DeviceModel: "Google Pixel 9",
SystemVersion: "SDK 36",
AppVersion: "12.7.3",
SystemLangCode: "en-US",
LangPack: "android",
LangCode: "en",
}
got := normalizeClientInfo(raw)
if got.DeviceModel != raw.DeviceModel || got.SystemVersion != raw.SystemVersion ||
got.AppVersion != raw.AppVersion || got.SystemLangCode != raw.SystemLangCode ||
got.LangPack != raw.LangPack || got.LangCode != raw.LangCode {
t.Fatalf("metadata within limits changed: got %+v, want %+v", got, raw)
}
}
func assertClientMetadataRunes(t *testing.T, field, value string, want int) {
t.Helper()
if got := utf8.RuneCountInString(value); got != want {
t.Fatalf("%s rune count = %d, want %d", field, got, want)
}
if !utf8.ValidString(value) {
t.Fatalf("%s is not valid UTF-8", field)
}
}

View file

@ -5,7 +5,7 @@ import "context"
// withClientDriftMetadata 只在调用方已经用 constructor drift 证明客户端来源时
// 补最小 client 类型。它不是 unknown fallback不能在普通裸 RPC 上调用。
// DrKLO Android 的 client-private constructor 只能证明 Android 兼容路径,
// 不能替代 invokeWithLayer/auth_keys/authorizations 里的真实 layer
// 不能替代 invokeWithLayer 或同一 logical session 已冻结的真实 Layer 证据
func (r *Router) withClientDriftMetadata(ctx context.Context, typ ClientType) context.Context {
if typ == ClientTypeUnknown || ClientTypeFrom(ctx) != ClientTypeUnknown {
return ctx

View file

@ -7,9 +7,10 @@ import (
"strings"
"unicode/utf8"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap"
"github.com/iamxvbaba/td/tlprofile"
"telesrv/internal/app/contacts"
"telesrv/internal/compat/tdesktop"
"telesrv/internal/domain"
@ -28,38 +29,82 @@ const (
)
// registerContacts 注册 contacts.* RPC handler。
func (r *Router) registerContacts(d *tg.ServerDispatcher) {
d.OnContactsGetContacts(r.onContactsGetContacts)
d.OnContactsGetContactIDs(r.onContactsGetContactIDs)
d.OnContactsGetStatuses(r.onContactsGetStatuses)
d.OnContactsImportContacts(r.onContactsImportContacts)
d.OnContactsAddContact(r.onContactsAddContact)
d.OnContactsAcceptContact(r.onContactsAcceptContact)
d.OnContactsDeleteContacts(r.onContactsDeleteContacts)
d.OnContactsEditCloseFriends(r.onContactsEditCloseFriends)
d.OnContactsBlock(r.onContactsBlock)
d.OnContactsUnblock(r.onContactsUnblock)
d.OnContactsSetBlocked(r.onContactsSetBlocked)
d.OnContactsUpdateContactNote(r.onContactsUpdateContactNote)
d.OnContactsSearch(r.onContactsSearch)
d.OnContactsResolveUsername(r.onContactsResolveUsername)
d.OnContactsResolvePhone(r.onContactsResolvePhone)
d.OnContactsGetTopPeers(func(ctx context.Context, req *tg.ContactsGetTopPeersRequest) (tg.ContactsTopPeersClass, error) {
func (r *Router) registerContacts(d *tlprofile.Dispatcher) {
registerRPC[*tg.ContactsGetContactsRequest](d, tlprofile.SemanticMethodContactsGetContacts, func(ctx context.Context, layerRequest *tg.ContactsGetContactsRequest) (any, error) {
return r.onContactsGetContacts(ctx, layerRequest.
Hash)
})
registerRPC[*tg.ContactsGetContactIDsRequest](d, tlprofile.SemanticMethodContactsGetContactIDs, func(ctx context.Context, layerRequest *tg.ContactsGetContactIDsRequest) (any, error) {
return r.onContactsGetContactIDs(ctx, layerRequest.
Hash)
})
registerRPC[*tg.ContactsGetStatusesRequest](d, tlprofile.SemanticMethodContactsGetStatuses, func(ctx context.Context, layerRequest *tg.ContactsGetStatusesRequest) (any, error) {
return r.onContactsGetStatuses(ctx)
})
registerRPC[*tg.ContactsImportContactsRequest](d, tlprofile.SemanticMethodContactsImportContacts, func(ctx context.Context, layerRequest *tg.ContactsImportContactsRequest) (any, error) {
return r.onContactsImportContacts(ctx, layerRequest.
Contacts)
})
registerRPC[*tg.ContactsAddContactRequest](d, tlprofile.SemanticMethodContactsAddContact, func(ctx context.Context, layerRequest *tg.ContactsAddContactRequest) (any, error) {
return r.onContactsAddContact(ctx, layerRequest)
})
registerRPC[*tg.ContactsAcceptContactRequest](d, tlprofile.SemanticMethodContactsAcceptContact, func(ctx context.Context, layerRequest *tg.ContactsAcceptContactRequest) (any, error) {
return r.onContactsAcceptContact(ctx, layerRequest.
ID)
})
registerRPC[*tg.ContactsDeleteContactsRequest](d, tlprofile.SemanticMethodContactsDeleteContacts, func(ctx context.Context, layerRequest *tg.ContactsDeleteContactsRequest) (any, error) {
return r.onContactsDeleteContacts(ctx, layerRequest.
ID)
})
registerRPC[*tg.ContactsEditCloseFriendsRequest](d, tlprofile.SemanticMethodContactsEditCloseFriends, func(ctx context.Context, layerRequest *tg.ContactsEditCloseFriendsRequest) (any, error) {
return r.onContactsEditCloseFriends(ctx, layerRequest.
ID)
})
registerRPC[*tg.ContactsBlockRequest](d, tlprofile.SemanticMethodContactsBlock, func(ctx context.Context, layerRequest *tg.ContactsBlockRequest) (any, error) {
return r.onContactsBlock(ctx, layerRequest)
})
registerRPC[*tg.ContactsUnblockRequest](d, tlprofile.SemanticMethodContactsUnblock, func(ctx context.Context, layerRequest *tg.ContactsUnblockRequest) (any, error) {
return r.onContactsUnblock(ctx, layerRequest)
})
registerRPC[*tg.ContactsSetBlockedRequest](d, tlprofile.SemanticMethodContactsSetBlocked, func(ctx context.Context, layerRequest *tg.ContactsSetBlockedRequest) (any, error) {
return r.onContactsSetBlocked(ctx, layerRequest)
})
registerRPC[*tg.ContactsUpdateContactNoteRequest](d, tlprofile.SemanticMethodContactsUpdateContactNote, func(ctx context.Context, layerRequest *tg.ContactsUpdateContactNoteRequest) (any, error) {
return r.onContactsUpdateContactNote(ctx, layerRequest)
})
registerRPC[*tg.ContactsSearchRequest](d, tlprofile.SemanticMethodContactsSearch, func(ctx context.Context, layerRequest *tg.ContactsSearchRequest) (any, error) {
return r.onContactsSearch(ctx, layerRequest)
})
registerRPC[*tg.ContactsResolveUsernameRequest](d, tlprofile.SemanticMethodContactsResolveUsername, func(ctx context.Context, layerRequest *tg.ContactsResolveUsernameRequest) (any, error) {
return r.onContactsResolveUsername(ctx, layerRequest)
})
registerRPC[*tg.ContactsResolvePhoneRequest](d, tlprofile.SemanticMethodContactsResolvePhone, func(ctx context.Context, layerRequest *tg.ContactsResolvePhoneRequest) (any, error) {
return r.onContactsResolvePhone(ctx, layerRequest.
Phone)
})
registerRPC[*tg.ContactsGetTopPeersRequest](d, tlprofile.SemanticMethodContactsGetTopPeers, func(ctx context.Context, req *tg.ContactsGetTopPeersRequest) (any, error) {
return tdesktop.TopPeers(), nil
})
d.OnContactsGetBlocked(r.onContactsGetBlocked)
d.OnContactsGetBirthdays(func(ctx context.Context) (*tg.ContactsContactBirthdays, error) {
registerRPC[*tg.ContactsGetBlockedRequest](d, tlprofile.SemanticMethodContactsGetBlocked, func(ctx context.Context, layerRequest *tg.ContactsGetBlockedRequest) (any, error) {
return r.onContactsGetBlocked(ctx, layerRequest)
})
registerRPC[*tg.ContactsGetBirthdaysRequest](d, tlprofile.SemanticMethodContactsGetBirthdays, func(ctx context.Context, layerRequest *tg.ContactsGetBirthdaysRequest) (any, error) {
if _, _, err := r.currentUserID(ctx); err != nil {
return nil, internalErr()
}
return &tg.ContactsContactBirthdays{Contacts: []tg.ContactBirthday{}, Users: []tg.UserClass{}}, nil
})
d.OnContactsGetSponsoredPeers(func(ctx context.Context, q string) (tg.ContactsSponsoredPeersClass, error) {
registerRPC[*tg.ContactsGetSponsoredPeersRequest](d, tlprofile.SemanticMethodContactsGetSponsoredPeers, func(ctx context.Context, layerRequest *tg.ContactsGetSponsoredPeersRequest) (any, error) {
q := layerRequest.
Q
_ = q
if utf8.RuneCountInString(q) > maxContactSearchQLen {
return nil, limitInvalidErr()
}
return &tg.ContactsSponsoredPeersEmpty{}, nil
})
}
func (r *Router) onContactsEditCloseFriends(ctx context.Context, id []int64) (bool, error) {

View file

@ -1,8 +1,8 @@
package rpc
import (
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"telesrv/internal/domain"
"testing"

View file

@ -2,9 +2,9 @@ package rpc
import (
"context"
"github.com/gotd/td/bin"
"github.com/gotd/td/clock"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/clock"
"github.com/iamxvbaba/td/tg"
"go.uber.org/zap/zaptest"
"reflect"
"strings"
@ -83,12 +83,8 @@ func TestContactsEditCloseFriendsProjectsUserFlag(t *testing.T) {
if err != nil {
t.Fatalf("dispatch edit close friends: %v", err)
}
box, ok := enc.(*tg.BoolBox)
if !ok {
t.Fatalf("edit close friends result = %T, want BoolBox", enc)
}
if _, ok := box.Bool.(*tg.BoolTrue); !ok {
t.Fatalf("edit close friends bool = %T, want BoolTrue", box.Bool)
if value, ok := dispatchCanonicalValue(enc).(bool); !ok || !value {
t.Fatalf("edit close friends result = %#v (%T), want true", dispatchCanonicalValue(enc), enc)
}
var get bin.Buffer
@ -99,12 +95,11 @@ func TestContactsEditCloseFriendsProjectsUserFlag(t *testing.T) {
if err != nil {
t.Fatalf("dispatch get contacts: %v", err)
}
contactsBox, ok := got.(*tg.ContactsContactsBox)
list, ok := got.(*tg.ContactsContacts)
if !ok {
t.Fatalf("contacts result = %T %+v, want ContactsContactsBox", got, got)
t.Fatalf("contacts result = %T %+v, want *tg.ContactsContacts", got, got)
}
list, ok := contactsBox.Contacts.(*tg.ContactsContacts)
if !ok || len(list.Users) != 1 {
if len(list.Users) != 1 {
t.Fatalf("contacts result = %T %+v, want one contact user", got, got)
}
user, ok := list.Users[0].(*tg.User)

View file

@ -4,6 +4,9 @@ import (
"context"
"regexp"
"strings"
"unicode/utf8"
"github.com/iamxvbaba/td/tg"
)
type ctxKey int
@ -31,7 +34,12 @@ func inboundRPCBytesFrom(ctx context.Context) int {
return v
}
const currentClientLayer = 227
const currentClientLayer = tg.Layer
const (
maxClientDeviceModelRunes = 128
maxClientMetadataRunes = 64
)
var androidSDKVersionRE = regexp.MustCompile(`\bsdk\s+\d+\b`)
@ -96,11 +104,33 @@ func ClientTypeFrom(ctx context.Context) ClientType {
}
func normalizeClientInfo(info ClientInfo) ClientInfo {
// Classify against the complete wire metadata before bounding the values
// shared by auth-key and authorization persistence.
info.Type = detectClientType(info)
info.DeviceModel = truncateClientMetadata(info.DeviceModel, maxClientDeviceModelRunes)
info.SystemVersion = truncateClientMetadata(info.SystemVersion, maxClientMetadataRunes)
info.AppVersion = truncateClientMetadata(info.AppVersion, maxClientMetadataRunes)
info.SystemLangCode = truncateClientMetadata(info.SystemLangCode, maxClientMetadataRunes)
info.LangPack = truncateClientMetadata(info.LangPack, maxClientMetadataRunes)
info.LangCode = truncateClientMetadata(info.LangCode, maxClientMetadataRunes)
info.typeResolved = true
return info
}
func truncateClientMetadata(value string, maxRunes int) string {
if maxRunes <= 0 || value == "" {
return ""
}
if utf8.ValidString(value) && utf8.RuneCountInString(value) <= maxRunes {
return value
}
runes := []rune(value)
if len(runes) > maxRunes {
runes = runes[:maxRunes]
}
return string(runes)
}
func (info ClientInfo) ClientType() ClientType {
if info.typeResolved {
if knownClientType(info.Type) {

View file

@ -3,7 +3,7 @@ package rpc
import (
"context"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -1,7 +1,7 @@
package rpc
import (
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/compat/tdesktop"
"telesrv/internal/domain"
)

View file

@ -3,7 +3,7 @@ package rpc
import (
"testing"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -1,7 +1,7 @@
package rpc
import (
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -3,7 +3,7 @@ package rpc
import (
"encoding/binary"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -5,7 +5,7 @@ import (
"encoding/binary"
"testing"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -3,8 +3,8 @@ package rpc
import (
"errors"
"github.com/gotd/td/tg"
"github.com/gotd/td/tgerr"
"github.com/iamxvbaba/td/tg"
"github.com/iamxvbaba/td/tgerr"
"telesrv/internal/domain"
)

View file

@ -3,7 +3,7 @@ package rpc
import (
"strings"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -4,8 +4,8 @@ import (
"encoding/json"
"testing"
"github.com/gotd/td/bin"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -1,7 +1,7 @@
package rpc
import (
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)
@ -220,6 +220,25 @@ func tgMessageServiceAction(msg domain.Message) tg.MessageActionClass {
}
case domain.MessageServiceActionStarGift:
return tgMessageActionStarGift(m.ServiceAction.StarGift)
case domain.MessageServiceActionStarGiftUnique:
action := m.ServiceAction.StarGiftUnique
if action == nil {
return &tg.MessageActionEmpty{}
}
out := &tg.MessageActionStarGiftUnique{
Upgrade: action.Upgrade, Saved: action.Saved, PrepaidUpgrade: action.PrepaidUpgrade,
Gift: tgUniqueStarGift(action.Gift),
}
if action.FromUserID != 0 {
out.SetFromID(&tg.PeerUser{UserID: action.FromUserID})
}
if peer := tgPeer(action.Peer); peer != nil {
out.SetPeer(peer)
}
if action.SavedID != 0 {
out.SetSavedID(action.SavedID)
}
return out
default:
return &tg.MessageActionEmpty{}
}

View file

@ -2,11 +2,32 @@ package rpc
import (
"encoding/json"
"github.com/gotd/td/tg"
"sort"
"telesrv/internal/domain"
"github.com/iamxvbaba/td/tg"
"sort"
)
func tgLangPackLanguages(items []domain.LangPackLanguage) []tg.LangPackLanguage {
out := make([]tg.LangPackLanguage, 0, len(items))
for _, item := range items {
out = append(out, tg.LangPackLanguage{
Official: item.Official,
Rtl: item.Rtl,
Beta: item.Beta,
Name: item.Name,
NativeName: item.NativeName,
LangCode: item.LangCode,
BaseLangCode: item.BaseLangCode,
PluralCode: item.PluralCode,
StringsCount: item.StringsCount,
TranslatedCount: item.TranslatedCount,
TranslationsURL: item.TranslationsURL,
})
}
return out
}
func tgLangPackStrings(items []domain.LangPackString) []tg.LangPackStringClass {
out := make([]tg.LangPackStringClass, 0, len(items))
for _, item := range items {

View file

@ -3,7 +3,7 @@ package rpc
import (
"encoding/base64"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -1,7 +1,7 @@
package rpc
import (
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -5,7 +5,7 @@ import (
"fmt"
"strconv"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
"telesrv/internal/sfu"

View file

@ -6,7 +6,7 @@ import (
"strings"
"unicode/utf8"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -4,8 +4,8 @@ import (
"context"
"strconv"
"github.com/gotd/td/bin"
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/bin"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

View file

@ -1,7 +1,7 @@
package rpc
import (
"github.com/gotd/td/tg"
"github.com/iamxvbaba/td/tg"
"telesrv/internal/domain"
)

Some files were not shown because too many files have changed in this diff Show more