Merge remote-tracking branch 'upstream/main' into dev
This commit is contained in:
commit
6b29556ef8
836 changed files with 1598388 additions and 64684 deletions
|
|
@ -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.getWebBrowserSettings:telesrv 不接入网页浏览器(web bot)集成,返回空设置
|
||||
// (无内置浏览器例外、不强制外部浏览器)。Android 启动时会拉取,缺它会反复 500
|
||||
// NOT_IMPLEMENTED。空结构 Hash=0,客户端按默认(内置浏览器、无例外)渲染。
|
||||
any, error) {
|
||||
return true, nil
|
||||
})
|
||||
// account.getWebBrowserSettings:telesrv 不接入网页浏览器(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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/compat/tdesktop"
|
||||
"telesrv/internal/domain"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package rpc
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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},
|
||||
|
|
|
|||
283
internal/rpc/android_private_layer_gate_test.go
Normal file
283
internal/rpc/android_private_layer_gate_test.go
Normal 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()
|
||||
}
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
// P3:startBot 深链 + 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) (
|
||||
|
||||
// P3:startBot 深链 + 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_id(bot-only RPC 用)。
|
||||
layerRequest *tg.MessagesSetBotPrecheckoutResultsRequest) (any, error) {
|
||||
return r.onMessagesSetBotPrecheckoutResults(ctx, layerRequest)
|
||||
})
|
||||
}
|
||||
|
||||
// callerBotID 校验调用者本身是 bot 账号,返回其 user_id(bot-only RPC 用)。
|
||||
func (r *Router) callerBotID(ctx context.Context) (int64, error) {
|
||||
userID, _, err := r.currentUserID(ctx)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package rpc
|
|||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/gotd/td/tgerr"
|
||||
"github.com/iamxvbaba/td/tgerr"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import (
|
|||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package rpc
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package rpc
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"telesrv/internal/domain"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package rpc
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"strings"
|
||||
"telesrv/internal/domain"
|
||||
"testing"
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package rpc
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package rpc
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package rpc
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -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.3):nudge 被消费后客户端会触发
|
||||
// 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.3):nudge 被消费后客户端会触发
|
||||
// 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,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
106
internal/rpc/client_info_test.go
Normal file
106
internal/rpc/client_info_test.go
Normal 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package rpc
|
|||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"telesrv/internal/compat/tdesktop"
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package rpc
|
|||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package rpc
|
|||
import (
|
||||
"encoding/binary"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"encoding/binary"
|
||||
"testing"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package rpc
|
|||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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{}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package rpc
|
|||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package rpc
|
||||
|
||||
import (
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import (
|
|||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/sfu"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import (
|
|||
"strings"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/iamxvbaba/td/tg"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue