diff --git a/.env.example b/.env.example index d543def3..c8524daf 100644 --- a/.env.example +++ b/.env.example @@ -27,6 +27,14 @@ TELESRV_MTPROTO_RPC_TIMEOUT=30s TELESRV_MTPROTO_RPC_GLOBAL_WORKERS=256 TELESRV_MTPROTO_RPC_GLOBAL_MAX_TASKS=8192 TELESRV_MTPROTO_RPC_GLOBAL_MAX_BYTES=536870912 +# In-process 331s rpc_result ownership budgets: global >= auth >= session. +TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES=262144 +TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_BYTES=67108864 +TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_ENTRIES=32768 +TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_BYTES=33554432 +TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_ENTRIES=16384 +TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_BYTES=16777216 +TELESRV_MTPROTO_RPC_RESULT_PENDING_PER_AUTH=2048 # Process-wide in-flight transport wire + decrypted plaintext reservation. TELESRV_MTPROTO_INBOUND_FRAME_GLOBAL_MAX_BYTES=536870912 # Per-connection outbound mailboxes (normal/control) and process-wide resend pending bodies. diff --git a/README.md b/README.md index f52704fe..0885a2d2 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,11 @@ written in Go. It is a Telegram-like backend for real client compatibility, self-hosted chat experiments, protocol research, and long-running work toward a practical community server. +The protocol stack is built on the published +[`github.com/iamxvbaba/td`](https://github.com/iamxvbaba/td) module +(`v1.0.0`), using a canonical Layer 228 schema with exact Layer 225-228 +compatibility profiles. + If you are looking for a **Telegram server**, **MTProto server**, **Telegram backend**, **Telegram clone server**, or **self-hosted Telegram-like chat server**, this repository is the server-side implementation @@ -40,7 +45,7 @@ codebase. | Status | Feature | What works today | |---|---|---| -| ✅ | MTProto server edge | TCP transport, RSA key exchange, auth keys, encrypted sessions, salts, ack/resend, bad messages, RPC dispatch, and layer compatibility helpers. | +| ✅ | MTProto server edge | TCP transport, RSA key exchange, auth keys, encrypted sessions, salts, ack/resend, bad messages, RPC dispatch, canonical Layer 228, and exact Layer 225-228 compatibility profiles. | | ✅ | Login and accounts | Development login code, sign-in, sign-up, log-out, authorizations, account settings, SRP/password state, email/passkey-oriented paths. | | ✅ | Users and contacts | User profiles, usernames, profile photos, contact import/search, blocked/privacy state, presence, and last-seen style status. | | ✅ | Dialogs and sync | Dialog list, pinned dialogs, manual unread, folders/filters, drafts, read boundaries, durable updates, online fan-out, and offline difference recovery. | @@ -214,7 +219,8 @@ minimal protocol patch. Current Telegram Desktop baseline: - Telegram Desktop commit: `9caf32dffc90ddd9bb08ad5777b865f729fa167b` -- TL layer: 227 +- Canonical TL layer: 228 +- Exact compatibility profiles: Layer 225-228 - Local DC: `127.0.0.1:2398`, DC id `2` After `gramsrv` generates `data/server_rsa.pem`, export the matching public key: diff --git a/README.zh-CN.md b/README.zh-CN.md index a2941cdc..ef338132 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -4,6 +4,11 @@ 它是一个 Telegram-like backend,面向真实客户端兼容、自建聊天实验、协议研究, 以及一条长期可演进的社区 server 路线。 +协议栈基于已发布的 +[`github.com/iamxvbaba/td`](https://github.com/iamxvbaba/td) module +(`v1.0.0`),使用 canonical Layer 228 schema,并提供 exact Layer 225-228 +compatibility profiles。 + 如果你正在搜索 **Telegram server 实现**、**MTProto server 实现**、 **Telegram 后端**、**Telegram clone server**、**自建 Telegram-like 聊天服务器**, 这个仓库就是可以运行、研究和共同优化的 server 侧实现。 @@ -37,7 +42,7 @@ https://github.com/user-attachments/assets/25e651dc-a022-4d60-8b9b-ca3e8bfe216c | 状态 | 功能 | 当前已实现 | |---|---|---| -| ✅ | MTProto server 接入层 | TCP transport、RSA key exchange、auth key、加密 session、salt、ack/resend、bad message、RPC dispatch、layer 兼容辅助。 | +| ✅ | MTProto server 接入层 | TCP transport、RSA key exchange、auth key、加密 session、salt、ack/resend、bad message、RPC dispatch、canonical Layer 228,以及 exact Layer 225-228 compatibility profiles。 | | ✅ | 登录与账号 | 开发验证码登录、sign-in、sign-up、log-out、授权设备、账号设置、SRP/password 状态、email/passkey 相关路径。 | | ✅ | 用户与联系人 | 用户资料、username、头像、联系人导入/搜索、block/privacy 状态、presence、last seen。 | | ✅ | 会话与同步 | dialog list、置顶、手动未读、folders/filters、草稿、read boundary、durable updates、在线 fan-out、离线 difference 恢复。 | @@ -199,7 +204,8 @@ TELESRV_PUBLIC_APP_NAME=YourApp 当前 Telegram Desktop 基线: - Telegram Desktop commit:`9caf32dffc90ddd9bb08ad5777b865f729fa167b` -- TL layer:227 +- Canonical TL layer:228 +- Exact compatibility profiles:Layer 225-228 - 本地 DC:`127.0.0.1:2398`,DC id `2` 等 `gramsrv` 生成 `data/server_rsa.pem` 后,导出匹配的公钥: diff --git a/cmd/appearancefetch/main.go b/cmd/appearancefetch/main.go index 15515370..5d5b1866 100644 --- a/cmd/appearancefetch/main.go +++ b/cmd/appearancefetch/main.go @@ -1,5 +1,5 @@ // Command appearancefetch 从官方 Telegram 拉取墙纸 + 聊天主题,下载文档/缩略图, -// 生成 telesrv 外观 seed(default_appearance_seed.json + default_wallpapers/{documents,thumbs/m}/*.dat)。 +// 生成 telesrv 外观 seed(Default_appearance_seed.json + Default_wallpapers/{documents,thumbs/m}/*.dat)。 // 复用 internal/seed/appearance 的结构体保证 schema 完全一致。peer_colors 从现有 JSON 沿用。 // // 需登录(墙纸/主题接口非免登)。api 凭据用 TDesktop 开源公开的 id/hash。 @@ -21,10 +21,10 @@ import ( "path/filepath" "time" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/auth" - "github.com/gotd/td/telegram/downloader" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/auth" + "github.com/iamxvbaba/td/telegram/downloader" + "github.com/iamxvbaba/td/tg" "telesrv/internal/seed/appearance" ) @@ -114,8 +114,8 @@ func doFetch(ctx context.Context, client *telegram.Client, outDir string) error } api := client.API() - docsDir := filepath.Join(outDir, "default_wallpapers", "documents") - thumbsDir := filepath.Join(outDir, "default_wallpapers", "thumbs", "m") + docsDir := filepath.Join(outDir, "Default_wallpapers", "documents") + thumbsDir := filepath.Join(outDir, "Default_wallpapers", "thumbs", "m") if err := os.MkdirAll(docsDir, 0o755); err != nil { return err } @@ -169,7 +169,7 @@ func doFetch(ctx context.Context, client *telegram.Client, outDir string) error return appearance.Document{}, err } sum := sha256.Sum256(data) - out.Path = "default_wallpapers/documents/" + name + out.Path = "Default_wallpapers/documents/" + name out.SHA256 = hex.EncodeToString(sum[:]) // "m" 缩略图 for _, t := range doc.Thumbs { @@ -187,7 +187,7 @@ func doFetch(ctx context.Context, client *telegram.Client, outDir string) error tsum := sha256.Sum256(tdata) out.Thumbs = append(out.Thumbs, appearance.PhotoSize{ Kind: "size", Type: "m", W: ps.W, H: ps.H, Size: ps.Size, - Path: "default_wallpapers/thumbs/m/" + name, SHA256: hex.EncodeToString(tsum[:]), + Path: "Default_wallpapers/thumbs/m/" + name, SHA256: hex.EncodeToString(tsum[:]), }) break } @@ -390,7 +390,7 @@ func doFetch(ctx context.Context, client *telegram.Client, outDir string) error if err != nil { return err } - jsonPath := filepath.Join(outDir, "default_appearance_seed.json") + jsonPath := filepath.Join(outDir, "Default_appearance_seed.json") if err := os.WriteFile(jsonPath, out, 0o644); err != nil { return err } diff --git a/cmd/bots/botcheck/main.go b/cmd/bots/botcheck/main.go index d3cdb4e8..4de8b6c8 100644 --- a/cmd/bots/botcheck/main.go +++ b/cmd/bots/botcheck/main.go @@ -29,14 +29,14 @@ import ( "go.uber.org/zap" "github.com/gotd/log/logzap" - "github.com/gotd/td/exchange" - "github.com/gotd/td/mtproxy" - "github.com/gotd/td/mtproxy/obfuscator" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/mtproxy" + "github.com/iamxvbaba/td/mtproxy/obfuscator" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" "telesrv/internal/mtprotoedge" ) diff --git a/cmd/bots/botdemo/main.go b/cmd/bots/botdemo/main.go index 9d1d792c..383348f8 100644 --- a/cmd/bots/botdemo/main.go +++ b/cmd/bots/botdemo/main.go @@ -50,15 +50,15 @@ import ( "go.uber.org/zap" "github.com/gotd/log/logzap" - "github.com/gotd/td/exchange" - "github.com/gotd/td/mtproxy" - "github.com/gotd/td/mtproxy/obfuscator" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/telegram/uploader" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/mtproxy" + "github.com/iamxvbaba/td/mtproxy/obfuscator" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/telegram/uploader" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" "telesrv/internal/mtprotoedge" ) diff --git a/cmd/catalogfetch/main.go b/cmd/catalogfetch/main.go index 6159f4fd..d98913aa 100644 --- a/cmd/catalogfetch/main.go +++ b/cmd/catalogfetch/main.go @@ -19,8 +19,8 @@ import ( "path/filepath" "time" - "github.com/gotd/td/telegram" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/tg" ) const ( diff --git a/cmd/giftcheck/main.go b/cmd/giftcheck/main.go index 6ff8cdf1..228211a3 100644 --- a/cmd/giftcheck/main.go +++ b/cmd/giftcheck/main.go @@ -24,14 +24,14 @@ import ( "go.uber.org/zap" "github.com/gotd/log/logzap" - "github.com/gotd/td/exchange" - "github.com/gotd/td/mtproxy" - "github.com/gotd/td/mtproxy/obfuscator" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/mtproxy" + "github.com/iamxvbaba/td/mtproxy/obfuscator" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" "telesrv/internal/mtprotoedge" ) diff --git a/cmd/langpackfetch/main.go b/cmd/langpackfetch/main.go index ff6582eb..255fbd87 100644 --- a/cmd/langpackfetch/main.go +++ b/cmd/langpackfetch/main.go @@ -3,8 +3,9 @@ // 开源公开的 id/hash。 // // 用法: -// langpackfetch languages [pack] 列出某 pack(默认 android)的可用语言 -// langpackfetch [pack...] 拉取语言包(默认 packs = android ios macos) +// +// langpackfetch languages [pack] 列出某 pack(默认 android)的可用语言 +// langpackfetch [pack...] 拉取语言包(默认 packs = android ios macos) package main import ( @@ -16,8 +17,8 @@ import ( "strings" "time" - "github.com/gotd/td/telegram" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/tg" ) const ( diff --git a/cmd/starcheck/main.go b/cmd/starcheck/main.go index 3dabb254..d6fd746f 100644 --- a/cmd/starcheck/main.go +++ b/cmd/starcheck/main.go @@ -28,14 +28,14 @@ import ( "go.uber.org/zap" "github.com/gotd/log/logzap" - "github.com/gotd/td/exchange" - "github.com/gotd/td/mtproxy" - "github.com/gotd/td/mtproxy/obfuscator" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/mtproxy" + "github.com/iamxvbaba/td/mtproxy/obfuscator" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" "telesrv/internal/mtprotoedge" ) diff --git a/cmd/stickerfetch/main.go b/cmd/stickerfetch/main.go index 7cab7cfc..786dc429 100644 --- a/cmd/stickerfetch/main.go +++ b/cmd/stickerfetch/main.go @@ -27,9 +27,9 @@ import ( "strings" "time" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/downloader" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/downloader" + "github.com/iamxvbaba/td/tg" ) const ( diff --git a/cmd/stickerfetch/main_test.go b/cmd/stickerfetch/main_test.go index c1bfcebd..c5f2e3be 100644 --- a/cmd/stickerfetch/main_test.go +++ b/cmd/stickerfetch/main_test.go @@ -6,7 +6,7 @@ import ( "path/filepath" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) func TestSpecToInputSystemSets(t *testing.T) { diff --git a/cmd/telesrv/exe_integration_test.go b/cmd/telesrv/exe_integration_test.go index c0501585..29a736a6 100644 --- a/cmd/telesrv/exe_integration_test.go +++ b/cmd/telesrv/exe_integration_test.go @@ -14,16 +14,16 @@ import ( "go.uber.org/zap/zaptest" "github.com/gotd/log/logzap" - tdcrypto "github.com/gotd/td/crypto" - "github.com/gotd/td/exchange" - "github.com/gotd/td/mtproxy" - "github.com/gotd/td/mtproxy/obfuscator" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/session" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + tdcrypto "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/mtproxy" + "github.com/iamxvbaba/td/mtproxy/obfuscator" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/session" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" "telesrv/internal/mtprotoedge" ) diff --git a/cmd/telesrv/main.go b/cmd/telesrv/main.go index a0fe0ee9..9cc9e359 100644 --- a/cmd/telesrv/main.go +++ b/cmd/telesrv/main.go @@ -1,4 +1,4 @@ -// Command telesrv 是基于 gotd/td 的 Telegram-like server(第一兼容目标:Telegram Desktop)。 +// Command telesrv 是基于 iamxvbaba/td 的 Telegram-like server(第一兼容目标:Telegram Desktop)。 package main import ( @@ -18,9 +18,9 @@ import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" - "github.com/gotd/td/clock" - "github.com/gotd/td/exchange" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/tg" adminapp "telesrv/internal/admin" "telesrv/internal/adminapi" @@ -297,7 +297,8 @@ func run(logger *zap.Logger) error { return fmt.Errorf("parse listen port %q: %w", portStr, err) } - // tg.Layer 来自 gotd/td v0.158.0(Layer 227),与目标 TDesktop 基线对齐。 + // tg.Layer 由当前导入的 canonical schema 生成;纳入未来 Layer 后无需 + // 在 telesrv 另维护一份常量。 logger.Info("telesrv 启动", zap.String("listen", cfg.ListenAddr), zap.Int("dc", cfg.DC), @@ -473,6 +474,7 @@ func run(logger *zap.Logger) error { cfg.RetentionBatch, ).WithDispatchOutboxPoisonPolicy(cfg.OutboxPoisonRetention, cfg.OutboxPoisonCleanupInterval). WithBotAPIUpdateRetention(botAPIUpdateStore, cfg.BotAPIUpdateRetention). + WithAuthKeySessionLayerRetention(authKeyStore). WithLoginCodeDeliveryRetention(messageStore). WithUserUpdateRetention(updateEventStore). WithChannelUpdateRetention(channelStore). @@ -720,39 +722,40 @@ func run(logger *zap.Logger) error { TempKeyResolveCacheTTL: cfg.TempKeyResolveCacheTTL, TempKeyResolveCacheMaxEntries: cfg.TempKeyResolveCacheMaxEntries, }, rpc.Deps{ - Auth: authService, - Account: accountService, - Privacy: privacyService, - Help: help.NewService(helpStore, helpStore, help.WithMapboxToken(cfg.MapboxToken)), - AICompose: aiComposeService, - Users: usersService, - Updates: updatesService, - BootstrapUpdates: bootstrapUpdateStore, - BotAPIUpdates: botAPIUpdateStore, - Contacts: contactsService, - Dialogs: dialogsService, - Chatlists: chatlistsService, - Messages: messagesService, - Translation: translationService, - Channels: channelsService, - Files: filesService, - Bots: botsService, - Polls: pollsapp.NewService(pollStore), - Stories: storiesapp.NewService(storyStore, storiesapp.WithChannelStoryAccess(channelsService)), - Phone: phoneService, - SecretChats: secretChatService, - Stars: starsService, - Gifts: giftsService, - Passkey: passkeyService, - Themes: themeService, - GroupCalls: groupCallsService, - LiveStreams: liveStreamDep(liveStreamService), - SFU: sfuService, - TURN: turnService, - LangPack: langPackService, - Sessions: activeSessions, - Inline: inlineRegistryStore, - Limiter: rateLimiter, + Auth: authService, + AuthKeySessionLayers: authKeyStore, + Account: accountService, + Privacy: privacyService, + Help: help.NewService(helpStore, helpStore, help.WithMapboxToken(cfg.MapboxToken)), + AICompose: aiComposeService, + Users: usersService, + Updates: updatesService, + BootstrapUpdates: bootstrapUpdateStore, + BotAPIUpdates: botAPIUpdateStore, + Contacts: contactsService, + Dialogs: dialogsService, + Chatlists: chatlistsService, + Messages: messagesService, + Translation: translationService, + Channels: channelsService, + Files: filesService, + Bots: botsService, + Polls: pollsapp.NewService(pollStore), + Stories: storiesapp.NewService(storyStore, storiesapp.WithChannelStoryAccess(channelsService)), + Phone: phoneService, + SecretChats: secretChatService, + Stars: starsService, + Gifts: giftsService, + Passkey: passkeyService, + Themes: themeService, + GroupCalls: groupCallsService, + LiveStreams: liveStreamDep(liveStreamService), + SFU: sfuService, + TURN: turnService, + LangPack: langPackService, + Sessions: activeSessions, + Inline: inlineRegistryStore, + Limiter: rateLimiter, }, logger.Named("rpc"), clock.System) readModelListener := postgres.NewReadModelChangeListener(cfg.PostgresDSN, postgres.ReadModelCacheSet{ ReadModelVersions: readModelVersionStore, @@ -830,29 +833,36 @@ func run(logger *zap.Logger) error { } srv := mtprotoedge.New(mtprotoedge.Options{ - Logger: logger.Named("mtprotoedge"), - DC: cfg.DC, - RSAKey: rsaKey, - RPC: router, - AuthKeys: authKeyStore, - ActiveSessions: activeSessions, - ObfuscatedTCP: true, - WebSocket: cfg.WebSocketEnable, - WebSocketAllowedOrigins: cfg.WebSocketAllowedOrigins, - MaxConnections: cfg.MTProtoMaxConnections, - MaxConnectionsPerIP: cfg.MTProtoMaxConnectionsPerIP, - MaxConcurrentHandshakes: cfg.MTProtoMaxConcurrentHandshakes, - RPCMaxInflight: cfg.MTProtoRPCMaxInflight, - RPCQueueSize: cfg.MTProtoRPCQueueSize, - RPCTimeout: cfg.MTProtoRPCTimeout, - RPCGlobalWorkers: cfg.MTProtoRPCGlobalWorkers, - RPCGlobalMaxTasks: cfg.MTProtoRPCGlobalMaxTasks, - RPCGlobalMaxBytes: cfg.MTProtoRPCGlobalMaxBytes, - InboundFrameGlobalMaxBytes: cfg.MTProtoInboundFrameGlobalMaxBytes, - OutboundQueueSize: cfg.MTProtoOutboundQueueSize, - OutboundControlQueueSize: cfg.MTProtoOutboundControlQueueSize, - OutboundTrackedGlobalMaxBytes: cfg.MTProtoOutboundTrackedGlobalMaxBytes, - OutboundWriteGlobalMaxBytes: cfg.MTProtoOutboundWriteGlobalMaxBytes, + Logger: logger.Named("mtprotoedge"), + DC: cfg.DC, + RSAKey: rsaKey, + LayerRPC: router, + AuthKeys: authKeyStore, + ActiveSessions: activeSessions, + ObfuscatedTCP: true, + WebSocket: cfg.WebSocketEnable, + WebSocketAllowedOrigins: cfg.WebSocketAllowedOrigins, + MaxConnections: cfg.MTProtoMaxConnections, + MaxConnectionsPerIP: cfg.MTProtoMaxConnectionsPerIP, + MaxConcurrentHandshakes: cfg.MTProtoMaxConcurrentHandshakes, + RPCMaxInflight: cfg.MTProtoRPCMaxInflight, + RPCQueueSize: cfg.MTProtoRPCQueueSize, + RPCTimeout: cfg.MTProtoRPCTimeout, + RPCGlobalWorkers: cfg.MTProtoRPCGlobalWorkers, + RPCGlobalMaxTasks: cfg.MTProtoRPCGlobalMaxTasks, + RPCGlobalMaxBytes: cfg.MTProtoRPCGlobalMaxBytes, + RPCResultCacheMaxEntries: cfg.MTProtoRPCResultCacheMaxEntries, + RPCResultCacheMaxBytes: cfg.MTProtoRPCResultCacheMaxBytes, + RPCResultCacheAuthMaxEntries: cfg.MTProtoRPCResultCacheAuthMaxEntries, + RPCResultCacheAuthMaxBytes: cfg.MTProtoRPCResultCacheAuthMaxBytes, + RPCResultCacheSessionMaxEntries: cfg.MTProtoRPCResultCacheSessionMaxEntries, + RPCResultCacheSessionMaxBytes: cfg.MTProtoRPCResultCacheSessionMaxBytes, + RPCResultPendingPerAuth: cfg.MTProtoRPCResultPendingPerAuth, + InboundFrameGlobalMaxBytes: cfg.MTProtoInboundFrameGlobalMaxBytes, + OutboundQueueSize: cfg.MTProtoOutboundQueueSize, + OutboundControlQueueSize: cfg.MTProtoOutboundControlQueueSize, + OutboundTrackedGlobalMaxBytes: cfg.MTProtoOutboundTrackedGlobalMaxBytes, + OutboundWriteGlobalMaxBytes: cfg.MTProtoOutboundWriteGlobalMaxBytes, OnServing: func(_ net.Addr) { logger.Info("telesrv 服务就绪", zap.String("listen", cfg.ListenAddr), diff --git a/deploy/migrations/0087_auth_key_session_layers.down.sql b/deploy/migrations/0087_auth_key_session_layers.down.sql new file mode 100644 index 00000000..dc1c69d8 --- /dev/null +++ b/deploy/migrations/0087_auth_key_session_layers.down.sql @@ -0,0 +1,7 @@ +DROP TABLE IF EXISTS public.auth_key_session_layers; + +ALTER TABLE public.auth_keys + DROP CONSTRAINT IF EXISTS auth_keys_layer_observation_id_valid, + DROP COLUMN IF EXISTS layer_observation_id; + +DROP SEQUENCE IF EXISTS public.auth_key_layer_observation_seq; diff --git a/deploy/migrations/0087_auth_key_session_layers.up.sql b/deploy/migrations/0087_auth_key_session_layers.up.sql new file mode 100644 index 00000000..26c7d8cf --- /dev/null +++ b/deploy/migrations/0087_auth_key_session_layers.up.sql @@ -0,0 +1,38 @@ +-- Short-lived, durable per-session invokeWithLayer watermark. The in-process +-- exact-profile registry prevents ordinary replay rollback, while this table +-- closes the durable commit/restart and cross-instance replacement-connection +-- window for client msg_ids that are still fresh enough to be accepted by +-- MTProto. It does not broadcast profile changes into an already-live remote +-- physical connection; that connection remains frozen until its own selector. +CREATE SEQUENCE public.auth_key_layer_observation_seq AS bigint; + +ALTER TABLE public.auth_keys + ADD COLUMN layer_observation_id bigint NOT NULL DEFAULT 0, + ADD CONSTRAINT auth_keys_layer_observation_id_valid + CHECK (layer_observation_id >= 0); + +CREATE TABLE public.auth_key_session_layers ( + raw_auth_key_id bigint NOT NULL, + session_id bigint NOT NULL, + layer integer NOT NULL, + msg_id bigint NOT NULL, + observation_id bigint NOT NULL, + expires_at timestamptz NOT NULL, + PRIMARY KEY (raw_auth_key_id, session_id), + CONSTRAINT auth_key_session_layers_auth_key_fkey + FOREIGN KEY (raw_auth_key_id) + REFERENCES public.auth_keys(auth_key_id) + ON DELETE CASCADE, + CONSTRAINT auth_key_session_layers_layer_valid CHECK (layer > 0), + CONSTRAINT auth_key_session_layers_msg_id_valid + CHECK ( + msg_id > 0 + AND msg_id % 4 = 0 + AND (msg_id & 4294967295) <> 0 + ), + CONSTRAINT auth_key_session_layers_observation_id_valid + CHECK (observation_id > 0) +); + +CREATE INDEX auth_key_session_layers_expiry_idx + ON public.auth_key_session_layers (expires_at, raw_auth_key_id, session_id); diff --git a/docs/configuration.en.md b/docs/configuration.en.md index c08fadeb..38a77e82 100644 --- a/docs/configuration.en.md +++ b/docs/configuration.en.md @@ -33,6 +33,13 @@ This document describes every setting loaded by `internal/config`. Defaults and | `TELESRV_MTPROTO_RPC_GLOBAL_WORKERS` | int / `256` | Shared fair-scheduler worker count. | | `TELESRV_MTPROTO_RPC_GLOBAL_MAX_TASKS` | int / `8192` | Process-wide scheduled/in-flight RPC task cap. | | `TELESRV_MTPROTO_RPC_GLOBAL_MAX_BYTES` | int64 bytes / `536870912` | Process-wide queued/in-flight RPC request-body budget. | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES` | int / `262144` | Global ownership entries for pending owners, completed results, and tombstones during the in-process 331-second replay window. | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_BYTES` | int64 bytes / `67108864` | Global retained-byte budget. Owner admission reserves one byte; Put transfers it to a body or tombstone. Must be at least `16775168`. | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_ENTRIES` | int / `32768` | Per raw-auth-key ownership entries; charged together with global and session scopes. | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_BYTES` | int64 bytes / `33554432` | Per raw-auth-key retained bytes. Limits must satisfy `global >= auth >= session`. | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_ENTRIES` | int / `16384` | Per `raw auth key + session_id` ownership entries. | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_BYTES` | int64 bytes / `16777216` | Per `raw auth key + session_id` retained bytes; large enough for one legal outbound body. | +| `TELESRV_MTPROTO_RPC_RESULT_PENDING_PER_AUTH` | int / `2048` | Additional active-owner cap per raw auth key; no greater than global pending tasks or auth entries. | | `TELESRV_MTPROTO_INBOUND_FRAME_GLOBAL_MAX_BYTES` | int64 bytes / `536870912` | Process-wide reservation for transport wire bytes plus maximum decrypted plaintext, acquired before payload allocation. | | `TELESRV_MTPROTO_OUTBOUND_QUEUE_SIZE` | int / `128` | Per-connection normal outbound mailbox capacity. | | `TELESRV_MTPROTO_OUTBOUND_CONTROL_QUEUE_SIZE` | int / `32` | Per-connection control-message mailbox capacity. | diff --git a/docs/configuration.zh-CN.md b/docs/configuration.zh-CN.md index e9ed554d..0f0180d0 100644 --- a/docs/configuration.zh-CN.md +++ b/docs/configuration.zh-CN.md @@ -32,7 +32,14 @@ | `TELESRV_MTPROTO_RPC_TIMEOUT` | duration / `30s` | 调度后 RPC handler 的端到端超时。 | | `TELESRV_MTPROTO_RPC_GLOBAL_WORKERS` | int / `256` | 共享公平调度器 worker 数。 | | `TELESRV_MTPROTO_RPC_GLOBAL_MAX_TASKS` | int / `8192` | 进程级排队与执行中的 RPC task 上限。 | -| `TELESRV_MTPROTO_RPC_GLOBAL_MAX_BYTES` | int64 bytes / `536870912` | 进程级排队/执行中 RPC request body 字节预算。 | +| `TELESRV_MTPROTO_RPC_GLOBAL_MAX_BYTES` | int64 charge bytes / `536870912` | 进程级已预留/排队/执行中 RPC 内存 charge 预算;legacy 等于 copied body,exact 是 typed decode 前按 wire 与生成对象放大计算的保守 materialization charge,不代表可并发接收同等大小的 wire body。 | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES` | int / `262144` | 331 秒进程内重放窗口中,pending owner、completed `rpc_result` 与容量 tombstone 的全局 ownership 条目上限。owner 执行前先占 1 条,转 completed 时不重复计数。 | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_BYTES` | int64 bytes / `67108864` | 上述 ownership 的全局 retained-byte 上限;owner 先占 1 byte,Put 转移为真实 body 或 1-byte identity tombstone。不得低于 `16775168`(单条合法 outbound body 上限)。 | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_ENTRIES` | int / `32768` | 单 raw auth key 的 ownership 条目上限;与全局、session 层同时计费,防一个 auth key 吃满进程缓存。必须 `global >= auth >= session`。 | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_BYTES` | int64 bytes / `33554432` | 单 raw auth key retained-byte 上限;必须不低于单条合法 outbound body,且满足 byte 层级关系。 | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_ENTRIES` | int / `16384` | 单 `raw auth key + session_id` ownership 条目上限;不同 session 不共享该局部额度。 | +| `TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_BYTES` | int64 bytes / `16777216` | 单 `raw auth key + session_id` retained-byte 上限;默认略高于单条合法 outbound body,确保空预算时任一合法结果可完整进入。 | +| `TELESRV_MTPROTO_RPC_RESULT_PENDING_PER_AUTH` | int / `2048` | 单 raw auth key 的 active pending owner 附加上限;必须不大于 `RPC_GLOBAL_MAX_TASKS` 和 auth entry 上限。Put/Abort 都立即归还此 active 额度。 | | `TELESRV_MTPROTO_INBOUND_FRAME_GLOBAL_MAX_BYTES` | int64 bytes / `536870912` | transport wire 与最大解密明文的进程级在途预算,在分配 payload 前预留。 | | `TELESRV_MTPROTO_OUTBOUND_QUEUE_SIZE` | int / `128` | 单连接普通 outbound mailbox 容量。 | | `TELESRV_MTPROTO_OUTBOUND_CONTROL_QUEUE_SIZE` | int / `32` | 单连接控制消息 mailbox 容量。 | diff --git a/go.mod b/go.mod index f9ab166f..3688ffe4 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,7 @@ require ( github.com/golang-migrate/migrate/v4 v4.19.1 github.com/gotd/ige v0.2.2 github.com/gotd/log/logzap v0.1.1 - github.com/gotd/td v0.159.0 - github.com/gotd/tl v0.4.0 + github.com/iamxvbaba/td v1.0.0 github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa github.com/jackc/pgx/v5 v5.9.2 github.com/pion/datachannel v1.6.2 diff --git a/go.sum b/go.sum index 25db2642..3d710f5b 100644 --- a/go.sum +++ b/go.sum @@ -73,15 +73,13 @@ github.com/gotd/log/logzap v0.1.1 h1:O6l7d8HUbODe+UMcrM47eXYDwdJ6RNmpQejLjrlcEIQ github.com/gotd/log/logzap v0.1.1/go.mod h1:5ObZkITbfhbsBOLzBkzmMk9QxXc0eNQpimau7zRL+Y8= github.com/gotd/neo v0.1.5 h1:oj0iQfMbGClP8xI59x7fE/uHoTJD7NZH9oV1WNuPukQ= github.com/gotd/neo v0.1.5/go.mod h1:9A2a4bn9zL6FADufBdt7tZt+WMhvZoc5gWXihOPoiBQ= -github.com/gotd/td v0.159.0 h1:kKXt2NLmfIOgebbFS34FSlZbdydaf5fsta+nP69nP+w= -github.com/gotd/td v0.159.0/go.mod h1:rdZ2NfOMUViApJa3EvYJ94GAxENjCB0b98tJbfS9NCc= -github.com/gotd/tl v0.4.0 h1:8k2z0drujiPyhpLDa9PRm/yU1Gwlfn3iUzeInPiXwMA= -github.com/gotd/tl v0.4.0/go.mod h1:CMIcjPWFS4qxxJ+1Ce7U/ilbtPrkoVo/t8uhN5Y/D7c= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI= github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= +github.com/iamxvbaba/td v1.0.0 h1:dgwQPxZCRWEZIDY9qNeZgIe6jvF7KAdI9NM1mxhnl6w= +github.com/iamxvbaba/td v1.0.0/go.mod h1:oG/fu7sqGC7NznoBD8f3fmTy9NFR42+DMNtdCPStX04= github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw= github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= @@ -148,7 +146,6 @@ github.com/pion/transport/v4 v4.0.2 h1:ifYlPqNwsy6aKQ9y8yzxXlHae5431ZrH2avkD/Rn6 github.com/pion/transport/v4 v4.0.2/go.mod h1:06hFI+jCFcok2X2MekVufNZ/uzNZXivGBPfviSVcjgM= github.com/pion/turn/v5 v5.0.10 h1:mOMZjudflXpte5OsCnXztpUKwNXcpXIAzMBnq9TXOSQ= github.com/pion/turn/v5 v5.0.10/go.mod h1:u3XjBqy2Z4+NhCUpDoOSsNuQDrPLvKStlCGWk6sTQ1E= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -160,13 +157,8 @@ github.com/refraction-networking/utls v1.8.2 h1:j4Q1gJj0xngdeH+Ox/qND11aEfhpgoEv github.com/refraction-networking/utls v1.8.2/go.mod h1:jkSOEkLqn+S/jtpEHPOsVv/4V4EVnelwbMQl4vCWXAM= github.com/rogpeppe/go-internal v1.15.0 h1:D0RCU5rMAp+SpgkiNdrjfJ+LX4J1M32V2NeCY7EJ6hc= github.com/rogpeppe/go-internal v1.15.0/go.mod h1:DrUVZyrJU+txYW5/1kwtXQSMFio52ZOxX7yM1VHvnxs= -github.com/sebdah/goldie/v2 v2.5.3 h1:9ES/mNN+HNUbNWpVAlrzuZ7jE+Nrczbj8uFRjM7624Y= -github.com/sebdah/goldie/v2 v2.5.3/go.mod h1:oZ9fp0+se1eapSRjfYbsV/0Hqhbuu3bJVvKI/NNtssI= github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= diff --git a/internal/app/auth/doc.go b/internal/app/auth/doc.go index c20621fb..aa4ffc50 100644 --- a/internal/app/auth/doc.go +++ b/internal/app/auth/doc.go @@ -1,5 +1,5 @@ // Package auth 是认证应用服务:验证码、登录、注册、注销,以及 auth key 与 user 的绑定。 // 第一阶段用开发固定验证码,2FA 配置由 account 服务持久化查询。 // -// 输入输出在 RPC 边界使用 gotd/td/tg 类型,本包内部只用 internal/domain 模型。 +// 输入输出在 RPC 边界使用 iamxvbaba/td/tg 类型,本包内部只用 internal/domain 模型。 package auth diff --git a/internal/app/auth/service.go b/internal/app/auth/service.go index 893b18fa..f689450b 100644 --- a/internal/app/auth/service.go +++ b/internal/app/auth/service.go @@ -14,8 +14,8 @@ import ( "unicode/utf8" "github.com/gotd/ige" - "github.com/gotd/td/bin" - mtcrypto "github.com/gotd/td/crypto" + "github.com/iamxvbaba/td/bin" + mtcrypto "github.com/iamxvbaba/td/crypto" "telesrv/internal/domain" "telesrv/internal/mail" @@ -188,6 +188,9 @@ func WithLoginEmail(opts LoginEmailOptions) Option { // NewService 创建登录服务。fixedCode 为开发固定验证码。 func NewService(users store.UserStore, auths store.AuthorizationStore, codes store.CodeStore, authKeys store.AuthKeyStore, tempKeys store.TempAuthKeyBindingStore, fixedCode string, opts ...Option) *Service { s := &Service{users: users, auths: auths, codes: codes, authKeys: authKeys, tempKeys: tempKeys, fixedCode: fixedCode, codeTTL: 5 * time.Minute, codeMaxAttempts: 5, loginEmailCodeLength: 6} + if linker, ok := auths.(store.AuthKeyAuthorityLinker); ok && authKeys != nil { + linker.LinkAuthKeyAuthority(authKeys) + } for _, opt := range opts { opt(s) } @@ -1102,13 +1105,6 @@ func (s *Service) Authorization(ctx context.Context, authKeyID [8]byte) (domain. return s.auths.ByAuthKey(ctx, authKeyID) } -func (s *Service) UpdateAuthorizationLayer(ctx context.Context, authKeyID [8]byte, layer int) error { - if s == nil || s.auths == nil || authKeyID == ([8]byte{}) || layer <= 0 { - return nil - } - return s.auths.UpdateLayer(ctx, authKeyID, layer) -} - func (s *Service) AuthKeyClientInfo(ctx context.Context, authKeyID [8]byte) (domain.AuthKeyClientInfo, bool, error) { if s == nil || s.authKeys == nil || authKeyID == ([8]byte{}) { return domain.AuthKeyClientInfo{}, false, nil @@ -1118,12 +1114,13 @@ func (s *Service) AuthKeyClientInfo(ctx context.Context, authKeyID [8]byte) (dom return domain.AuthKeyClientInfo{}, found, err } info := domain.AuthKeyClientInfo{ - Layer: key.Layer, - DeviceModel: key.DeviceModel, - Platform: key.Platform, - SystemVersion: key.SystemVersion, - APIID: key.APIID, - AppVersion: key.AppVersion, + Layer: key.Layer, + LayerObservationID: key.LayerObservationID, + DeviceModel: key.DeviceModel, + Platform: key.Platform, + SystemVersion: key.SystemVersion, + APIID: key.APIID, + AppVersion: key.AppVersion, } if info.Layer == 0 && info.DeviceModel == "" && info.Platform == "" && info.SystemVersion == "" && info.APIID == 0 && info.AppVersion == "" { @@ -1147,7 +1144,15 @@ func (s *Service) UpdateAuthKeyClientInfo(ctx context.Context, authKeyID [8]byte return err } if s.auths != nil { - return s.auths.UpdateClientInfo(ctx, authKeyID, info) + // Layer is an ordered protocol fact. Its authorization-table mirror is + // advanced atomically by the durable Layer evidence/bind transactions. + // A generic metadata update is deliberately two-store and can race such + // a transaction, so it must never write an older Layer after the primary + // auth_keys row has already advanced. + authorizationInfo := info + authorizationInfo.Layer = 0 + authorizationInfo.LayerObservationID = 0 + return s.auths.UpdateClientInfo(ctx, authKeyID, authorizationInfo) } return nil } diff --git a/internal/app/auth/service_test.go b/internal/app/auth/service_test.go index c0c802d2..3eef2980 100644 --- a/internal/app/auth/service_test.go +++ b/internal/app/auth/service_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - mtcrypto "github.com/gotd/td/crypto" + mtcrypto "github.com/iamxvbaba/td/crypto" "telesrv/internal/domain" "telesrv/internal/store" @@ -135,7 +135,7 @@ func TestBindTempAuthKeyClassifiesExpiryWithoutDestroyingPermanentKey(t *testing } } -func TestUpdateAuthKeyClientInfoConvergesAuthorizationMetadata(t *testing.T) { +func TestUpdateAuthKeyClientInfoConvergesMemoryAuthorizationToAuthKeyLayerAuthority(t *testing.T) { ctx := context.Background() keys := memory.NewAuthKeyStore() authz := memory.NewAuthorizationStore() @@ -144,6 +144,7 @@ func TestUpdateAuthKeyClientInfoConvergesAuthorizationMetadata(t *testing.T) { if err := authz.Bind(ctx, domain.Authorization{ AuthKeyID: key.ID, UserID: 1780243200, + Layer: 220, Platform: "unknown", }); err != nil { t.Fatalf("bind authorization: %v", err) @@ -171,6 +172,7 @@ func TestUpdateAuthKeyClientInfoConvergesAuthorizationMetadata(t *testing.T) { t.Fatalf("get authorization: found=%v err=%v", found, err) } if storedKey.Platform != "ios" || storedAuth.Platform != "ios" || + storedKey.Layer != info.Layer || storedAuth.Layer != info.Layer || storedKey.DeviceModel != info.DeviceModel || storedAuth.DeviceModel != info.DeviceModel || storedKey.AppVersion != info.AppVersion || storedAuth.AppVersion != info.AppVersion { t.Fatalf("client metadata did not converge: key=%+v authorization=%+v", storedKey, storedAuth) diff --git a/internal/app/files/photos.go b/internal/app/files/photos.go index fce5bd96..b6f74436 100644 --- a/internal/app/files/photos.go +++ b/internal/app/files/photos.go @@ -10,7 +10,7 @@ import ( "image" "image/color" stddraw "image/draw" - _ "image/jpeg" // 注册 jpeg DecodeConfig,用于读取上传头像/图片尺寸 + "image/jpeg" "image/png" "io" "math" @@ -24,8 +24,8 @@ import ( _ "golang.org/x/image/webp" // 注册 webp Decode,用于 custom emoji / sticker 静态缩略图合成 ) -// 头像与图片消息共用的尺寸 type:'a' 小图(≤160),'c' 大图,'x' 通用下载尺寸。 -// 同一份上传字节在多个 location_key 下建 blob(不做实际缩放,dev 主路径足够)。 +// 头像使用真实的 's'(≤150)/'a'(≤160)/'c'(原图) rendition;图片消息使用 +// 'm' 缩略与 'x' 大图。每个头像 location_key 的元数据尺寸必须与实际 blob 一致。 // UploadProfilePhoto 把已上传文件组装成头像 Photo,落 blob/photos/profile_photos,并设为当前头像。 func (s *Service) UploadProfilePhoto(ctx context.Context, ownerType domain.PeerType, ownerID int64, file domain.UploadedFileRef, date int) (domain.Photo, error) { @@ -103,8 +103,8 @@ func (s *Service) GetDocument(ctx context.Context, id int64) (domain.Document, b return s.media.GetDocument(ctx, id) } -// CreateAvatarFromUpload 把已上传文件组装成头像 Photo('a'/'c' 尺寸,匹配 InputPeerPhotoFileLocation -// big/small 与 channelFull 合成尺寸的下载路径),不绑定 profile_photos。用于频道 editPhoto。 +// CreateAvatarFromUpload 把已上传文件组装成头像 Photo('s'/'a'/'c' 尺寸,'a'/'c' 匹配 +// InputPeerPhotoFileLocation big/small 与 channelFull 下载路径),不绑定 profile_photos。用于频道 editPhoto。 func (s *Service) CreateAvatarFromUpload(ctx context.Context, file domain.UploadedFileRef) (domain.Photo, error) { data, err := s.assembleUpload(ctx, file.OwnerUserID, file.FileID, file.Parts) if err != nil { @@ -113,7 +113,7 @@ func (s *Service) CreateAvatarFromUpload(ctx context.Context, file domain.Upload if len(data) == 0 { return domain.Photo{}, domain.ErrPhotoInvalid } - return s.createPhoto(ctx, data, photoSizeSpecsForAvatar(data)) + return s.createAvatarPhoto(ctx, data) } // CreateAvatarVideoFromUpload stores an animated profile video as photo.video_sizes. @@ -151,7 +151,7 @@ func (s *Service) createAvatarVideoFromUpload(ctx context.Context, file domain.U } s.blobCache.put(blob.LocationKey, blob) stillBytes := s.avatarVideoStill(ctx, body, extraSizes) - sizes, err := s.putPhotoStaticSizes(ctx, photoID, stillBytes, photoSizeSpecsForAvatar(stillBytes)) + sizes, err := s.putAvatarStaticSizes(ctx, photoID, stillBytes, photoSizeSpecsForAvatar(stillBytes)) if err != nil { return domain.Photo{}, err } @@ -192,7 +192,7 @@ func (s *Service) CreateAvatarMarkup(ctx context.Context, size domain.PhotoSize) } photoID := randomID() stillBytes := s.generatedAvatarStill(ctx, size) - sizes, err := s.putPhotoStaticSizes(ctx, photoID, stillBytes, photoSizeSpecsForAvatar(stillBytes)) + sizes, err := s.putAvatarStaticSizes(ctx, photoID, stillBytes, photoSizeSpecsForAvatar(stillBytes)) if err != nil { return domain.Photo{}, err } @@ -605,6 +605,26 @@ func (s *Service) createPhoto(ctx context.Context, data []byte, specs []photoSiz return photo, nil } +func (s *Service) createAvatarPhoto(ctx context.Context, data []byte) (domain.Photo, error) { + photoID := randomID() + sizes, err := s.putAvatarStaticSizes(ctx, photoID, data, photoSizeSpecsForAvatar(data)) + if err != nil { + return domain.Photo{}, err + } + photo := domain.Photo{ + ID: photoID, + AccessHash: randomID(), + FileReference: randomFileReference(), + Date: int(time.Now().Unix()), + DCID: s.dc, + Sizes: sizes, + } + if err := s.media.PutPhoto(ctx, photo); err != nil { + return domain.Photo{}, err + } + return photo, nil +} + func (s *Service) putPhotoStaticSizes(ctx context.Context, photoID int64, data []byte, specs []photoSizeSpec) ([]domain.PhotoSize, error) { objectKey, err := s.blobs.Put(ctx, data) if err != nil { @@ -630,6 +650,87 @@ func (s *Service) putPhotoStaticSizes(ctx context.Context, photoID int64, data [ return sizes, nil } +// putAvatarStaticSizes stores independently rendered avatar sizes. DrKLO uses the +// photos.uploadProfilePhoto response's closest 150px size as an immediate local +// location, while UserProfilePhoto updates synthesize the canonical 'a' location. +// Keeping a real 's' rendition therefore gives those two states distinct keys and, +// more importantly, keeps every advertised size backed by matching image bytes. +func (s *Service) putAvatarStaticSizes(ctx context.Context, photoID int64, data []byte, specs []photoSizeSpec) ([]domain.PhotoSize, error) { + src, format, err := image.Decode(bytes.NewReader(data)) + if err != nil || src.Bounds().Dx() <= 0 || src.Bounds().Dy() <= 0 { + return nil, domain.ErrPhotoInvalid + } + sizes := make([]domain.PhotoSize, 0, len(specs)) + for _, spec := range specs { + rendition, err := avatarRendition(data, src, format, spec) + if err != nil { + return nil, err + } + objectKey, err := s.blobs.Put(ctx, rendition) + if err != nil { + return nil, err + } + blob := domain.FileBlob{ + LocationKey: fmt.Sprintf("photo:%d:%s", photoID, spec.Type), + Backend: domain.MediaBackend(s.blobs.Name()), + ObjectKey: objectKey, + Size: int64(len(rendition)), + MimeType: imageMimeType(rendition), + } + if err := s.media.PutFileBlob(ctx, blob); err != nil { + return nil, err + } + s.blobCache.put(blob.LocationKey, blob) + s.prewarmSmallBlob(objectKey, rendition) + sizes = append(sizes, domain.PhotoSize{ + Kind: domain.PhotoSizeKindDefault, + Type: spec.Type, + W: spec.W, + H: spec.H, + Size: len(rendition), + }) + } + return sizes, nil +} + +func avatarRendition(original []byte, src image.Image, format string, spec photoSizeSpec) ([]byte, error) { + bounds := src.Bounds() + if bounds.Dx() == spec.W && bounds.Dy() == spec.H { + return append([]byte(nil), original...), nil + } + if spec.W <= 0 || spec.H <= 0 { + return nil, domain.ErrPhotoInvalid + } + dst := image.NewRGBA(image.Rect(0, 0, spec.W, spec.H)) + srcRect := centerCropRect(bounds, spec.W, spec.H) + xdraw.CatmullRom.Scale(dst, dst.Bounds(), src, srcRect, xdraw.Src, nil) + + var buf bytes.Buffer + if format == "jpeg" { + if err := jpeg.Encode(&buf, dst, &jpeg.Options{Quality: 90}); err != nil { + return nil, err + } + } else if err := png.Encode(&buf, dst); err != nil { + return nil, err + } + return buf.Bytes(), nil +} + +func centerCropRect(bounds image.Rectangle, targetW, targetH int) image.Rectangle { + sourceW, sourceH := bounds.Dx(), bounds.Dy() + if int64(sourceW)*int64(targetH) > int64(sourceH)*int64(targetW) { + cropW := maxInt(1, sourceH*targetW/targetH) + x := bounds.Min.X + (sourceW-cropW)/2 + return image.Rect(x, bounds.Min.Y, x+cropW, bounds.Max.Y) + } + if int64(sourceW)*int64(targetH) < int64(sourceH)*int64(targetW) { + cropH := maxInt(1, sourceW*targetH/targetW) + y := bounds.Min.Y + (sourceH-cropH)/2 + return image.Rect(bounds.Min.X, y, bounds.Max.X, y+cropH) + } + return bounds +} + func (s *Service) putDocumentThumb(ctx context.Context, docID int64, thumbData []byte) (domain.PhotoSize, error) { if len(thumbData) == 0 { return domain.PhotoSize{}, fmt.Errorf("empty document thumbnail") @@ -723,12 +824,15 @@ type photoSizeSpec struct { func photoSizeSpecsForAvatar(data []byte) []photoSizeSpec { w, h := imageDimensions(data, 640, 640) - small := 160 - if w < small { - small = w + shortSide := w + if h < shortSide { + shortSide = h } + sSize := minInt(shortSide, 150) + aSize := minInt(shortSide, 160) return []photoSizeSpec{ - {Type: "a", W: small, H: small}, + {Type: "s", W: sSize, H: sSize}, + {Type: "a", W: aSize, H: aSize}, {Type: "c", W: w, H: h}, } } @@ -767,10 +871,14 @@ const ( avatarMarkupMaxSourceBytes = 2 << 20 // emoji/sticker thumb 小对象保护线。 ) -// avatarVideoStill 生成动画头像的静态尺寸字节:优先抽取上传视频首帧——动画头像 -// (emoji/sticker 构造器或自选视频)的首帧就是用户在客户端看到的真实画面(彩色 -// emoji、圆角、布局都一致);抽帧不可用时回退到按 markup 服务端合成。 +// avatarVideoStill 生成动画头像的静态尺寸字节。emoji/sticker markup 能解析到 +// 服务端缩略图时优先合成:DrKLO 生成的 MP4 第一帧可能只有背景渐变,直接抽第一帧 +// 会让静态头像永久缺少 emoji。普通视频或 markup 资源不可用时才回退 ffmpeg 首帧。 func (s *Service) avatarVideoStill(ctx context.Context, body assembledUploadBlob, extraSizes []domain.PhotoSize) []byte { + markup := avatarStillMarkup(extraSizes) + if still, ok := s.generatedAvatarMarkupStill(ctx, markup); ok { + return still + } if s.thumbs != nil && body.Size > 0 && body.Size <= videoThumbnailMaxInputBytes { data, total, err := s.blobs.GetRange(ctx, body.ObjectKey, 0, body.Size) if err == nil && int64(len(data)) == total && total == body.Size { @@ -789,17 +897,30 @@ func (s *Service) avatarVideoStill(ctx context.Context, body assembledUploadBlob zap.Error(err)) } } - return s.generatedAvatarStill(ctx, avatarStillMarkup(extraSizes)) + return s.generatedAvatarStill(ctx, markup) } func (s *Service) generatedAvatarStill(ctx context.Context, markup domain.PhotoSize) []byte { img := generatedAvatarBackground(markup.BackgroundColors) - if overlay, tintWhite, ok := s.avatarMarkupOverlay(ctx, markup); ok { - drawAvatarMarkup(img, overlay, tintWhite) + if still, ok := s.generatedAvatarMarkupStillOnBackground(ctx, markup, img); ok { + return still } return encodeAvatarPNG(img) } +func (s *Service) generatedAvatarMarkupStill(ctx context.Context, markup domain.PhotoSize) ([]byte, bool) { + return s.generatedAvatarMarkupStillOnBackground(ctx, markup, generatedAvatarBackground(markup.BackgroundColors)) +} + +func (s *Service) generatedAvatarMarkupStillOnBackground(ctx context.Context, markup domain.PhotoSize, img *image.RGBA) ([]byte, bool) { + overlay, tintWhite, ok := s.avatarMarkupOverlay(ctx, markup) + if !ok { + return nil, false + } + drawAvatarMarkup(img, overlay, tintWhite) + return encodeAvatarPNG(img), true +} + func generatedAvatarBackground(colors []int) *image.RGBA { if len(colors) == 0 { colors = []int{0x5b8def, 0x53c6a4} @@ -865,6 +986,11 @@ func (s *Service) avatarMarkupOverlay(ctx context.Context, markup domain.PhotoSi zap.Error(err)) return nil, false, false } + // Seed 的 1x1 透明图只是“没有可用静态资源”的显式占位,不是可合成 + // 内容。把它视为 unavailable,交给调用方回退到 ffmpeg 视频首帧。 + if img.Bounds().Dx() <= 1 || img.Bounds().Dy() <= 1 { + return nil, false, false + } return img, documentIsTextColorEmoji(doc), true } diff --git a/internal/app/files/photos_test.go b/internal/app/files/photos_test.go index ca37adaa..10058a66 100644 --- a/internal/app/files/photos_test.go +++ b/internal/app/files/photos_test.go @@ -223,6 +223,57 @@ func TestCreatePhotoFromBytesStoresDownloadableMessageSizes(t *testing.T) { } } +func TestCreateAvatarFromUploadStoresRealSizedRenditions(t *testing.T) { + ctx := context.Background() + media := newFakeMediaStore() + blobs, err := NewLocalFS(t.TempDir()) + if err != nil { + t.Fatalf("NewLocalFS: %v", err) + } + svc := NewService(media, blobs, 2) + data := testJPEG(t, 640, 480) + if _, err := svc.SaveFilePart(ctx, 10, 301, 0, data); err != nil { + t.Fatalf("SaveFilePart: %v", err) + } + + photo, err := svc.CreateAvatarFromUpload(ctx, domain.UploadedFileRef{ + OwnerUserID: 10, + FileID: 301, + Parts: 1, + Name: "avatar.jpg", + }) + if err != nil { + t.Fatalf("CreateAvatarFromUpload: %v", err) + } + wants := map[string]image.Point{ + "s": {X: 150, Y: 150}, + "a": {X: 160, Y: 160}, + "c": {X: 640, Y: 480}, + } + if len(photo.Sizes) != len(wants) { + t.Fatalf("avatar sizes = %+v, want s/a/c", photo.Sizes) + } + objectKeys := map[string]struct{}{} + for _, size := range photo.Sizes { + want, ok := wants[size.Type] + if !ok || size.W != want.X || size.H != want.Y { + t.Fatalf("avatar size = %+v, want one of %v", size, wants) + } + assertAvatarImageSize(t, svc, photo.ID, size.Type, want.X, want.Y, "image/jpeg") + blob, found, err := media.GetFileBlob(ctx, fmt.Sprintf("photo:%d:%s", photo.ID, size.Type)) + if err != nil || !found { + t.Fatalf("avatar %s blob found=%v err=%v", size.Type, found, err) + } + if blob.Size != int64(size.Size) { + t.Fatalf("avatar %s blob size=%d metadata size=%d", size.Type, blob.Size, size.Size) + } + objectKeys[blob.ObjectKey] = struct{}{} + } + if len(objectKeys) != 3 { + t.Fatalf("avatar object keys = %v, want distinct s/a/c renditions", objectKeys) + } +} + func TestCreateDocumentFromBytesStoresBodyAndAttributes(t *testing.T) { ctx := context.Background() media := newFakeMediaStore() @@ -299,8 +350,9 @@ func TestCreateAvatarMarkupGeneratesDownloadableStaticSizes(t *testing.T) { if !domain.PhotoHasVideo(photo.Sizes) { t.Fatalf("avatar markup photo sizes = %+v, want video markup", photo.Sizes) } - assertDownloadableAvatarSize(t, svc, photo.ID, "a") - assertDownloadableAvatarSize(t, svc, photo.ID, "c") + assertDownloadableAvatarSize(t, svc, photo.ID, "s", 150) + assertDownloadableAvatarSize(t, svc, photo.ID, "a", 160) + assertDownloadableAvatarSize(t, svc, photo.ID, "c", 640) } // TestCreateAvatarMarkupComposesEmojiThumbIntoStaticSizes 守护两个行为: @@ -433,8 +485,9 @@ func TestCreateAvatarVideoMarkupGeneratesDownloadableStaticSizes(t *testing.T) { if err != nil { t.Fatalf("CreateAvatarVideoMarkupFromUpload: %v", err) } - assertDownloadableAvatarSize(t, svc, photo.ID, "a") - assertDownloadableAvatarSize(t, svc, photo.ID, "c") + assertDownloadableAvatarSize(t, svc, photo.ID, "s", 150) + assertDownloadableAvatarSize(t, svc, photo.ID, "a", 160) + assertDownloadableAvatarSize(t, svc, photo.ID, "c", 640) chunk, found, err := svc.GetFile(ctx, domain.FileDownloadRequest{ LocationKey: fmt.Sprintf("photo:%d:u", photo.ID), Offset: 0, @@ -448,9 +501,9 @@ func TestCreateAvatarVideoMarkupGeneratesDownloadableStaticSizes(t *testing.T) { } } -// TestCreateAvatarVideoMarkupStillUsesVideoFirstFrame 守护动画头像静态尺寸优先取 -// 上传视频首帧(客户端真实渲染画面),而不是服务端合成的近似 still。 -func TestCreateAvatarVideoMarkupStillUsesVideoFirstFrame(t *testing.T) { +// TestCreateAvatarVideoMarkupFallsBackToVideoFirstFrame 守护 markup document/thumb +// 不可用时仍可从上传视频抽帧,不能让普通动画头像失去静态尺寸。 +func TestCreateAvatarVideoMarkupFallsBackToVideoFirstFrame(t *testing.T) { ctx := context.Background() media := newFakeMediaStore() blobs, err := NewLocalFS(t.TempDir()) @@ -479,7 +532,7 @@ func TestCreateAvatarVideoMarkupStillUsesVideoFirstFrame(t *testing.T) { t.Fatalf("thumbnailer calls = %d, want 1", thumbnailer.calls) } chunk, found, err := svc.GetFile(ctx, domain.FileDownloadRequest{ - LocationKey: fmt.Sprintf("photo:%d:a", photo.ID), + LocationKey: fmt.Sprintf("photo:%d:c", photo.ID), Offset: 0, Limit: 1 << 20, }) @@ -492,9 +545,112 @@ func TestCreateAvatarVideoMarkupStillUsesVideoFirstFrame(t *testing.T) { if chunk.MimeType != "image/jpeg" { t.Fatalf("avatar still mime = %q, want image/jpeg from extracted frame", chunk.MimeType) } + assertAvatarImageSize(t, svc, photo.ID, "s", 150, 150, "image/jpeg") + assertAvatarImageSize(t, svc, photo.ID, "a", 160, 160, "image/jpeg") } -func assertDownloadableAvatarSize(t *testing.T, svc *Service, photoID int64, sizeType string) { +func TestCreateAvatarVideoMarkupRejectsSyntheticPreviewAndFallsBackToVideo(t *testing.T) { + ctx := context.Background() + media := newFakeMediaStore() + blobs, err := NewLocalFS(t.TempDir()) + if err != nil { + t.Fatalf("NewLocalFS: %v", err) + } + const emojiID = int64(78) + if err := media.PutDocument(ctx, domain.Document{ + ID: emojiID, + MimeType: "application/x-tgsticker", + Thumbs: []domain.PhotoSize{{ + Kind: domain.PhotoSizeKindCached, Type: "m", W: 1, H: 1, + Bytes: append([]byte(nil), seedSyntheticTGStickerPreviewThumbPNG...), + }}, + }); err != nil { + t.Fatalf("PutDocument: %v", err) + } + frame := testJPEG(t, 640, 640) + thumbnailer := &fakeVideoThumbnailer{thumb: frame} + svc := NewService(media, blobs, 2, WithVideoThumbnailer(thumbnailer)) + if _, err := svc.SaveFilePart(ctx, 10, 503, 0, []byte("profile-video-without-server-preview")); err != nil { + t.Fatalf("SaveFilePart: %v", err) + } + photo, err := svc.CreateAvatarVideoMarkupFromUpload(ctx, + domain.UploadedFileRef{OwnerUserID: 10, FileID: 503, Parts: 1, Name: "avatar.mp4"}, + 0, + domain.PhotoSize{Kind: domain.PhotoSizeKindVideoEmojiMarkup, EmojiID: emojiID, BackgroundColors: []int{0x112233}}) + if err != nil { + t.Fatalf("CreateAvatarVideoMarkupFromUpload: %v", err) + } + if thumbnailer.calls != 1 { + t.Fatalf("thumbnailer calls = %d, want synthetic preview rejected and video fallback used", thumbnailer.calls) + } + chunk, found, err := svc.GetFile(ctx, domain.FileDownloadRequest{LocationKey: fmt.Sprintf("photo:%d:c", photo.ID), Limit: 1 << 20}) + if err != nil || !found { + t.Fatalf("avatar c blob found=%v err=%v", found, err) + } + if !bytes.Equal(chunk.Bytes, frame) { + t.Fatal("avatar still did not use extracted video frame after rejecting synthetic preview") + } +} + +// TestCreateAvatarVideoMarkupPrefersComposedStill 守护 DrKLO emoji 构造器边界: +// 客户端生成 MP4 的第一帧可能只有渐变背景;只要 markup thumb 可解析,静态头像 +// 必须用服务端合成结果,确保 emoji 在当前 session 回显和冷启动中都可见。 +func TestCreateAvatarVideoMarkupPrefersComposedStill(t *testing.T) { + ctx := context.Background() + media := newFakeMediaStore() + blobs, err := NewLocalFS(t.TempDir()) + if err != nil { + t.Fatalf("NewLocalFS: %v", err) + } + const emojiID = int64(501) + if err := media.PutDocument(ctx, domain.Document{ + ID: emojiID, + MimeType: "application/x-tgsticker", + Thumbs: []domain.PhotoSize{{ + Kind: domain.PhotoSizeKindCached, + Type: "m", + W: 64, + H: 64, + Bytes: testTransparentThumbPNG(t), + }}, + }); err != nil { + t.Fatalf("PutDocument: %v", err) + } + thumbnailer := &fakeVideoThumbnailer{thumb: testJPEG(t, 320, 320)} + svc := NewService(media, blobs, 2, WithVideoThumbnailer(thumbnailer)) + if _, err := svc.SaveFilePart(ctx, 10, 502, 0, []byte("background-only-profile-video")); err != nil { + t.Fatalf("SaveFilePart: %v", err) + } + + photo, err := svc.CreateAvatarVideoMarkupFromUpload(ctx, + domain.UploadedFileRef{OwnerUserID: 10, FileID: 502, Parts: 1, Name: "avatar.mp4"}, + 0, + domain.PhotoSize{ + Kind: domain.PhotoSizeKindVideoEmojiMarkup, + EmojiID: emojiID, + BackgroundColors: []int{0x112233, 0x445566}, + }) + if err != nil { + t.Fatalf("CreateAvatarVideoMarkupFromUpload: %v", err) + } + if thumbnailer.calls != 0 { + t.Fatalf("thumbnailer calls = %d, want 0 when markup still is available", thumbnailer.calls) + } + r, g, b, _ := avatarStillCenterPixel(t, svc, photo.ID) + if r < 200 || g > 90 || b > 90 { + t.Fatalf("composed center pixel rgb=(%d,%d,%d), want visible red emoji overlay", r, g, b) + } + assertDownloadableAvatarSize(t, svc, photo.ID, "s", 150) + assertDownloadableAvatarSize(t, svc, photo.ID, "a", 160) + assertDownloadableAvatarSize(t, svc, photo.ID, "c", 640) +} + +func assertDownloadableAvatarSize(t *testing.T, svc *Service, photoID int64, sizeType string, side int) { + t.Helper() + assertAvatarImageSize(t, svc, photoID, sizeType, side, side, "image/png") +} + +func assertAvatarImageSize(t *testing.T, svc *Service, photoID int64, sizeType string, wantW, wantH int, wantMime string) { t.Helper() chunk, found, err := svc.GetFile(context.Background(), domain.FileDownloadRequest{ LocationKey: fmt.Sprintf("photo:%d:%s", photoID, sizeType), @@ -504,8 +660,15 @@ func assertDownloadableAvatarSize(t *testing.T, svc *Service, photoID int64, siz if err != nil || !found { t.Fatalf("avatar %s blob found=%v err=%v", sizeType, found, err) } - if len(chunk.Bytes) == 0 || chunk.MimeType != "image/png" { - t.Fatalf("avatar %s chunk mime=%q bytes=%d, want image/png bytes", sizeType, chunk.MimeType, len(chunk.Bytes)) + if len(chunk.Bytes) == 0 || chunk.MimeType != wantMime { + t.Fatalf("avatar %s chunk mime=%q bytes=%d, want %s bytes", sizeType, chunk.MimeType, len(chunk.Bytes), wantMime) + } + img, _, err := image.Decode(bytes.NewReader(chunk.Bytes)) + if err != nil { + t.Fatalf("decode avatar %s: %v", sizeType, err) + } + if gotW, gotH := img.Bounds().Dx(), img.Bounds().Dy(); gotW != wantW || gotH != wantH { + t.Fatalf("avatar %s pixels=%dx%d, want %dx%d", sizeType, gotW, gotH, wantW, wantH) } } diff --git a/internal/app/files/seed.go b/internal/app/files/seed.go index 1e22fc28..8764318a 100644 --- a/internal/app/files/seed.go +++ b/internal/app/files/seed.go @@ -81,6 +81,7 @@ func (s *Service) SeedMedia(ctx context.Context, root string, maxRegularSets int // 这样向已部署(非空 store)的 data/sticker-seed 丢新集后重启即可生效,无需清库重 seed。 // 仅当检测到旧版缩略图/可渲染预览元数据缺失时 force=true 全量重导修复。 forceSticker := false + previewState := fmt.Sprintf("%s:dc=%d", seedStickerPreviewStateVersion, s.dc) if n, err := s.media.CountStickerSets(ctx); err != nil { return stats, err } else if n > 0 { @@ -88,11 +89,18 @@ func (s *Service) SeedMedia(ctx context.Context, root string, maxRegularSets int if err != nil { return stats, err } - forceSticker = stale + migrated, err := s.seedStateMatches(ctx, seedStickerPreviewStateKey, previewState) + if err != nil { + return stats, err + } + forceSticker = stale || !migrated } if err := s.seedStickerSets(ctx, root, maxRegularSets, forceSticker, &stats); err != nil { return stats, fmt.Errorf("seed sticker sets: %w", err) } + if err := s.putSeedState(ctx, seedStickerPreviewStateKey, previewState); err != nil { + return stats, fmt.Errorf("record sticker preview seed state: %w", err) + } s.logSeedPhase("sticker_sets", phaseStarted, phaseBefore, stats) phaseStarted = time.Now() @@ -379,6 +387,10 @@ func (s *Service) importDocument(ctx context.Context, dj seedDocumentJSON, binDi if dj.ID == 0 { return domain.Document{}, nil } + existing, existingFound, err := s.media.GetDocument(ctx, dj.ID) + if err != nil { + return domain.Document{}, err + } ref, _ := hex.DecodeString(dj.FileReference) doc := domain.Document{ ID: dj.ID, @@ -436,27 +448,40 @@ func (s *Service) importDocument(ctx context.Context, dj seedDocumentJSON, binDi if err != nil { return domain.Document{}, err } - objectKey, err := s.blobs.Put(ctx, data) - if err != nil { - return domain.Document{}, err - } ps.Size = len(data) - if err := s.media.PutFileBlob(ctx, domain.FileBlob{ - LocationKey: fmt.Sprintf("doc:%d:%s", doc.ID, ps.Type), - Backend: domain.MediaBackend(s.blobs.Name()), - ObjectKey: objectKey, - Size: int64(len(data)), - MimeType: seedThumbMimeType(data), - }); err != nil { - return domain.Document{}, err - } ps = seedInlineCachedDocumentThumb(ps, data) - s.prewarmSmallBlob(objectKey, data) - stats.Blobs++ + // A duplicate document can be present in several catalogs. Do not replace a + // better already-persisted preview (and its shared location key) with a lower + // quality rendition from the catalog imported later. + if prior, ok := seedDocumentThumbByType(existing.Thumbs, ps.Type); existingFound && ok && seedPhotoSizeBetter(prior, ps) { + ps = prior + } else { + objectKey, err := s.blobs.Put(ctx, data) + if err != nil { + return domain.Document{}, err + } + if err := s.media.PutFileBlob(ctx, domain.FileBlob{ + LocationKey: fmt.Sprintf("doc:%d:%s", doc.ID, ps.Type), + Backend: domain.MediaBackend(s.blobs.Name()), + ObjectKey: objectKey, + Size: int64(len(data)), + MimeType: seedThumbMimeType(data), + }); err != nil { + return domain.Document{}, err + } + s.prewarmSmallBlob(objectKey, data) + stats.Blobs++ + } } thumbs = append(thumbs, ps) } doc.Thumbs = thumbs + if existingFound { + doc.Thumbs = mergeSeedDocumentThumbs(existing.Thumbs, doc.Thumbs) + } + if err := s.ensureSeedCachedThumbBlobs(ctx, doc, stats); err != nil { + return domain.Document{}, err + } if err := s.ensureTGStickerPreviewThumb(ctx, &doc, stats); err != nil { return domain.Document{}, err @@ -700,6 +725,138 @@ func seedInlineCachedDocumentThumb(ps domain.PhotoSize, data []byte) domain.Phot return ps } +// mergeSeedDocumentThumbs makes duplicate seed imports monotonic for preview quality. +// PhotoSize.Type is also the blob location suffix, so only one winner per type may be +// advertised. Incoming metadata wins ties; a richer existing preview wins downgrades. +func mergeSeedDocumentThumbs(existing, incoming []domain.PhotoSize) []domain.PhotoSize { + out := append([]domain.PhotoSize(nil), incoming...) + byType := make(map[string]int, len(out)) + for i, thumb := range out { + if thumb.Type != "" { + byType[thumb.Type] = i + } + } + for _, thumb := range existing { + if thumb.Type != "" { + if i, ok := byType[thumb.Type]; ok { + if seedPhotoSizeBetter(thumb, out[i]) { + out[i] = thumb + } + continue + } + byType[thumb.Type] = len(out) + } + out = append(out, thumb) + } + + hasRealPreview := false + for _, thumb := range out { + if !seedSyntheticTGStickerPreviewThumb(thumb) && seedPhotoSizePreviewTier(thumb) > 1 { + hasRealPreview = true + break + } + } + if !hasRealPreview { + return out + } + filtered := out[:0] + for _, thumb := range out { + if !seedSyntheticTGStickerPreviewThumb(thumb) { + filtered = append(filtered, thumb) + } + } + return filtered +} + +func seedDocumentThumbByType(thumbs []domain.PhotoSize, typ string) (domain.PhotoSize, bool) { + for _, thumb := range thumbs { + if thumb.Type == typ { + return thumb, true + } + } + return domain.PhotoSize{}, false +} + +func seedPhotoSizeBetter(a, b domain.PhotoSize) bool { + aTier, bTier := seedPhotoSizePreviewTier(a), seedPhotoSizePreviewTier(b) + if aTier != bTier { + return aTier > bTier + } + aArea, bArea := int64(a.W)*int64(a.H), int64(b.W)*int64(b.H) + if aArea != bArea { + return aArea > bArea + } + aPayload, bPayload := len(a.Bytes)+a.Size, len(b.Bytes)+b.Size + return aPayload > bPayload +} + +func seedPhotoSizePreviewTier(thumb domain.PhotoSize) int { + if seedSyntheticTGStickerPreviewThumb(thumb) { + return 0 + } + switch thumb.Kind { + case domain.PhotoSizeKindCached: + if len(thumb.Bytes) > 0 && thumb.W > 0 && thumb.H > 0 { + return 4 + } + case domain.PhotoSizeKindDefault, domain.PhotoSizeKindProgressive: + if thumb.Size > 0 && thumb.W > 0 && thumb.H > 0 { + return 4 + } + case domain.PhotoSizeKindPath, domain.PhotoSizeKindStripped: + if len(thumb.Bytes) > 0 { + return 3 + } + } + return 1 +} + +func seedSyntheticTGStickerPreviewThumb(thumb domain.PhotoSize) bool { + return thumb.Kind == domain.PhotoSizeKindCached && + thumb.Type == seedSyntheticDocumentThumbType && + thumb.W == 1 && thumb.H == 1 && + bytes.Equal(thumb.Bytes, seedSyntheticTGStickerPreviewThumbPNG) +} + +// ensureSeedCachedThumbBlobs keeps the RPC conversion invariant: document cached +// previews are exposed as downloadable PhotoSize entries, so every advertised type +// must have a matching blob even when the source JSON carried the bytes inline. +func (s *Service) ensureSeedCachedThumbBlobs(ctx context.Context, doc domain.Document, stats *SeedStats) error { + for _, thumb := range doc.Thumbs { + if thumb.Kind != domain.PhotoSizeKindCached || thumb.Type == "" || len(thumb.Bytes) == 0 { + continue + } + locationKey := fmt.Sprintf("doc:%d:%s", doc.ID, thumb.Type) + mimeType := seedThumbMimeType(thumb.Bytes) + stored, found, err := s.media.GetFileBlob(ctx, locationKey) + if err != nil { + return err + } + if found && stored.Size == int64(len(thumb.Bytes)) && stored.MimeType == mimeType { + continue + } + if s.blobs == nil { + return fmt.Errorf("blob backend not configured for cached document thumb %s", locationKey) + } + objectKey, err := s.blobs.Put(ctx, thumb.Bytes) + if err != nil { + return err + } + if err := s.media.PutFileBlob(ctx, domain.FileBlob{ + LocationKey: locationKey, + Backend: domain.MediaBackend(s.blobs.Name()), + ObjectKey: objectKey, + Size: int64(len(thumb.Bytes)), + MimeType: mimeType, + }); err != nil { + return err + } + s.prewarmSmallBlob(objectKey, thumb.Bytes) + stats.Blobs++ + } + return nil +} + func (s *Service) ensureTGStickerPreviewThumb(ctx context.Context, doc *domain.Document, stats *SeedStats) error { if !seedDocumentNeedsSyntheticTGStickerPreviewThumb(*doc) { return nil @@ -826,11 +983,12 @@ func (s *Service) documentsNeedSeedRepair(ctx context.Context, ids []int64) (boo if err != nil { return false, err } - if ok { - want := seedThumbMimeType(thumb.Bytes) - if want != "application/octet-stream" && blob.MimeType != want { - return true, nil - } + if !ok { + return true, nil + } + want := seedThumbMimeType(thumb.Bytes) + if blob.Size != int64(len(thumb.Bytes)) || (want != "application/octet-stream" && blob.MimeType != want) { + return true, nil } } } diff --git a/internal/app/files/seed_state.go b/internal/app/files/seed_state.go index c674f06a..0c0d1d5b 100644 --- a/internal/app/files/seed_state.go +++ b/internal/app/files/seed_state.go @@ -10,13 +10,20 @@ import ( "os" "path/filepath" "sort" + + "telesrv/internal/domain" ) const ( seedEffectsStateKey = "files.effects" seedEffectsStateVersion = "effects-v2" - seedAppearanceStateKey = "files.appearance" - seedAppearanceStateVersion = "appearance-v1" + seedStickerPreviewStateKey = "files.sticker_previews" + // v2 explicitly rebuilds sticker documents written before duplicate seed imports + // became monotonic. Those databases may contain an effects-generated transparent + // 1x1 preview where the sticker catalog has a real static thumbnail. + seedStickerPreviewStateVersion = "sticker-previews-v2-monotonic" + seedAppearanceStateKey = "files.appearance" + seedAppearanceStateVersion = "appearance-v1" ) func (s *Service) seedStateMatches(ctx context.Context, key, want string) (bool, error) { @@ -88,16 +95,17 @@ func seedDocumentJSONLocationKeys(dj seedDocumentJSON, index seedDirIndex) []str } for _, tj := range dj.Thumbs { ps, downloadable := seedPhotoSize(tj) - if !downloadable || ps.Type == "" { + if ps.Type == "" { continue } - if _, ok := index.thumb[dj.ID][ps.Type]; ok { + if downloadable { + if _, ok := index.thumb[dj.ID][ps.Type]; ok { + keys = append(keys, fmt.Sprintf("doc:%d:%s", dj.ID, ps.Type)) + } + } else if ps.Kind == domain.PhotoSizeKindCached && len(ps.Bytes) > 0 && ps.W > 0 && ps.H > 0 { keys = append(keys, fmt.Sprintf("doc:%d:%s", dj.ID, ps.Type)) } } - if seedDocumentJSONNeedsSyntheticTGStickerPreviewThumb(dj) { - keys = append(keys, fmt.Sprintf("doc:%d:%s", dj.ID, seedSyntheticDocumentThumbType)) - } return keys } @@ -144,6 +152,28 @@ func (s *Service) seedDocumentJSONsReady(ctx context.Context, docs []seedDocumen if doc.DCID != s.dc || doc.MimeType != dj.MimeType || doc.Size != dj.Size { return false, nil } + // A catalog without its own thumbnail may share this document with a richer + // catalog. Readiness follows the preview that is actually stored instead of + // demanding the synthetic "m" key and repeatedly downgrading that richer + // document on every import. + if seedDocumentJSONNeedsSyntheticTGStickerPreviewThumb(dj) { + if len(doc.Thumbs) == 0 { + return false, nil + } + for _, thumb := range doc.Thumbs { + switch thumb.Kind { + case domain.PhotoSizeKindDefault, domain.PhotoSizeKindProgressive, domain.PhotoSizeKindCached: + if thumb.Type == "" { + return false, nil + } + key := fmt.Sprintf("doc:%d:%s", doc.ID, thumb.Type) + if _, seen := seenLocationKeys[key]; !seen { + seenLocationKeys[key] = struct{}{} + locationKeys = append(locationKeys, key) + } + } + } + } delete(expected, doc.ID) } if len(expected) > 0 { diff --git a/internal/app/files/seed_test.go b/internal/app/files/seed_test.go index 2b53614b..bde84378 100644 --- a/internal/app/files/seed_test.go +++ b/internal/app/files/seed_test.go @@ -1,6 +1,7 @@ package files import ( + "bytes" "context" "fmt" "os" @@ -463,8 +464,8 @@ func TestSeedMediaRepairsPartialReactionBlobs(t *testing.T) { if err != nil { t.Fatalf("repair seed: %v", err) } - if stats.Reactions != 1 || stats.Blobs != 3 || stats.Skipped { - t.Fatalf("repair stats = %+v, want repair import", stats) + if stats.Reactions != 1 || stats.Blobs != 2 || stats.Skipped { + t.Fatalf("repair stats = %+v, want two missing/revalidated main blobs without rewriting intact preview", stats) } if _, ok, _ := media.GetFileBlob(context.Background(), "doc:2222222"); !ok { t.Fatal("missing reaction blob was not repaired") @@ -609,8 +610,113 @@ func TestSeedMediaSkipsUnchangedEffectsDocuments(t *testing.T) { if err != nil { t.Fatalf("repair seed: %v", err) } - if repaired.Effects != 1 || repaired.Documents != 1 || repaired.Blobs != 2 { - t.Fatalf("repair stats = %+v, want missing blob to force reimport", repaired) + if repaired.Effects != 1 || repaired.Documents != 1 || repaired.Blobs != 1 { + t.Fatalf("repair stats = %+v, want missing main blob repaired without rewriting intact preview", repaired) + } +} + +func TestSeedEffectsDoesNotDowngradeSharedStickerPreview(t *testing.T) { + ctx := context.Background() + seedDir := t.TempDir() + const sourceID int64 = 7777777 + realThumb := writeStatusPackWithThumbSeed(t, seedDir, sourceID, 29) + writeEffectsSeed(t, seedDir, sourceID) + + media := newFakeMediaStore() + blobs, err := NewLocalFS(t.TempDir()) + if err != nil { + t.Fatalf("local fs: %v", err) + } + svc := NewService(media, blobs, 2) + first, err := svc.SeedMedia(ctx, seedDir, 0) + if err != nil { + t.Fatalf("first seed: %v", err) + } + if first.StickerSets != 1 || first.Effects != 1 { + t.Fatalf("first stats = %+v, want shared sticker and effect catalogs", first) + } + + doc, ok, err := media.GetDocument(ctx, sourceID) + if err != nil || !ok { + t.Fatalf("shared document ok=%v err=%v", ok, err) + } + thumb, ok := findCachedThumb(doc.Thumbs) + if !ok { + t.Fatalf("shared document thumbs = %+v, want real cached preview", doc.Thumbs) + } + if thumb.W != 128 || thumb.H != 128 || !bytes.Equal(thumb.Bytes, realThumb) || seedSyntheticTGStickerPreviewThumb(thumb) { + t.Fatalf("shared preview = %+v, want original 128x128 catalog thumbnail", thumb) + } + blob, ok, err := media.GetFileBlob(ctx, fmt.Sprintf("doc:%d:m", sourceID)) + if err != nil || !ok { + t.Fatalf("shared preview blob ok=%v err=%v", ok, err) + } + if blob.MimeType != "image/jpeg" || blob.Size != int64(len(realThumb)) { + t.Fatalf("shared preview blob = %+v, want real JPEG metadata", blob) + } + chunk, ok, err := svc.GetFile(ctx, domain.FileDownloadRequest{LocationKey: fmt.Sprintf("doc:%d:m", sourceID), Limit: 1024}) + if err != nil || !ok { + t.Fatalf("get shared preview ok=%v err=%v", ok, err) + } + if !bytes.Equal(chunk.Bytes, realThumb) { + t.Fatalf("downloaded shared preview = %x, want %x", chunk.Bytes, realThumb) + } + + second, err := svc.SeedMedia(ctx, seedDir, 0) + if err != nil { + t.Fatalf("second seed: %v", err) + } + if second.Documents != 0 || second.Blobs != 0 { + t.Fatalf("second stats = %+v, want shared rich preview to satisfy effects readiness", second) + } +} + +func TestSeedMediaMigratesSyntheticStickerPreviewToExportedThumbnail(t *testing.T) { + ctx := context.Background() + seedDir := t.TempDir() + const sourceID int64 = 8888888 + realThumb := writeStatusPackWithThumbSeed(t, seedDir, sourceID, 31) + + media := newFakeMediaStore() + if err := media.PutDocument(ctx, domain.Document{ + ID: sourceID, + MimeType: "application/x-tgsticker", + Thumbs: []domain.PhotoSize{{ + Kind: domain.PhotoSizeKindCached, Type: seedSyntheticDocumentThumbType, + W: 1, H: 1, Bytes: append([]byte(nil), seedSyntheticTGStickerPreviewThumbPNG...), + }}, + }); err != nil { + t.Fatalf("put stale document: %v", err) + } + if err := media.PutStickerSet(ctx, domain.StickerSet{ + ID: 773947703670341676, AccessHash: 1, ShortName: "StatusPack", Title: "Status Pack", + Hash: 31, Kind: domain.StickerSetKindEmoji, Emojis: true, DocumentIDs: []int64{sourceID}, + }); err != nil { + t.Fatalf("put stale sticker set: %v", err) + } + + blobs, err := NewLocalFS(t.TempDir()) + if err != nil { + t.Fatalf("local fs: %v", err) + } + svc := NewService(media, blobs, 2) + stats, err := svc.SeedMedia(ctx, seedDir, 0) + if err != nil { + t.Fatalf("migration seed: %v", err) + } + if stats.StickerSets != 1 || stats.Documents != 1 { + t.Fatalf("migration stats = %+v, want forced sticker document rebuild", stats) + } + doc, ok, err := media.GetDocument(ctx, sourceID) + if err != nil || !ok { + t.Fatalf("migrated document ok=%v err=%v", ok, err) + } + thumb, ok := findCachedThumb(doc.Thumbs) + if !ok || thumb.W != 128 || thumb.H != 128 || !bytes.Equal(thumb.Bytes, realThumb) { + t.Fatalf("migrated thumbs = %+v, want exported 128x128 preview", doc.Thumbs) + } + if state, ok, err := media.GetSeedState(ctx, seedStickerPreviewStateKey); err != nil || !ok || state == "" { + t.Fatalf("preview migration state = %q ok=%v err=%v", state, ok, err) } } @@ -735,6 +841,28 @@ func writeStatusPackWithoutThumbSeed(t *testing.T, seedDir string, sourceID int6 } } +func writeStatusPackWithThumbSeed(t *testing.T, seedDir string, sourceID int64, setHash int) []byte { + t.Helper() + setDir := filepath.Join(seedDir, "telegram_emoji_export", "StatusPack_773947703670341676") + stickersDir := filepath.Join(setDir, "stickers") + if err := os.MkdirAll(stickersDir, 0o755); err != nil { + t.Fatal(err) + } + realThumb := []byte{0xff, 0xd8, 0xff, 0xdb, 0, 4, 0xff, 0xd9} + raw := fmt.Sprintf(`{"result":{"set":{"id":773947703670341676,"access_hash":1,"title":"Status Pack","short_name":"StatusPack","count":1,"hash":%d,"emojis":true,"packs":[{"emoticon":"👋","documents":[%d]}]},"packs":[{"emoticon":"👋","documents":[%d]}],"documents":[{"id":%d,"access_hash":2,"file_reference":"","date":"2026-06-29T00:00:00Z","mime_type":"application/x-tgsticker","size":4,"dc_id":4,"attributes":[{"_":"DocumentAttributeImageSize","w":512,"h":512},{"_":"DocumentAttributeCustomEmoji","alt":"👋","text_color":true,"stickerset":{"id":773947703670341676,"access_hash":1}},{"_":"DocumentAttributeFilename","file_name":"AnimatedSticker.tgs"}],"thumbs":[{"_":"PhotoPathSize","type":"j","bytes":"01"},{"_":"PhotoSize","type":"m","w":128,"h":128,"size":%d}]}]}}`, setHash, sourceID, sourceID, sourceID, len(realThumb)) + if err := os.WriteFile(filepath.Join(setDir, "set_info.json"), []byte(raw), 0o644); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(stickersDir, fmt.Sprintf("status_%d.tgs", sourceID)), []byte("tgs!"), 0o644); err != nil { + t.Fatal(err) + } + thumbName := fmt.Sprintf("status_%d_thumb1_PhotoSize_typem_128x128.jpg", sourceID) + if err := os.WriteFile(filepath.Join(stickersDir, thumbName), realThumb, 0o644); err != nil { + t.Fatal(err) + } + return realThumb +} + func writeEffectsSeed(t *testing.T, seedDir string, sourceID int64) { t.Helper() docsDir := filepath.Join(seedDir, "telegram_effects_export", "documents") @@ -992,7 +1120,7 @@ func TestDocumentsNeedInlineCachedThumbsDetectsStaleMime(t *testing.T) { if err := media.PutDocument(ctx, doc); err != nil { t.Fatalf("put doc: %v", err) } - if err := media.PutFileBlob(ctx, domain.FileBlob{LocationKey: "doc:100:m", MimeType: "image/jpeg"}); err != nil { + if err := media.PutFileBlob(ctx, domain.FileBlob{LocationKey: "doc:100:m", Size: int64(len(webp)), MimeType: "image/jpeg"}); err != nil { t.Fatalf("put blob: %v", err) } svc := NewService(media, nil, 2) @@ -1004,7 +1132,7 @@ func TestDocumentsNeedInlineCachedThumbsDetectsStaleMime(t *testing.T) { t.Fatal("expected stale mime to require repair") } - if err := media.PutFileBlob(ctx, domain.FileBlob{LocationKey: "doc:100:m", MimeType: "image/webp"}); err != nil { + if err := media.PutFileBlob(ctx, domain.FileBlob{LocationKey: "doc:100:m", Size: int64(len(webp)), MimeType: "image/webp"}); err != nil { t.Fatalf("put repaired blob: %v", err) } stale, err = svc.documentsNeedInlineCachedThumbs(ctx, []int64{doc.ID}) diff --git a/internal/app/maintenance/retention.go b/internal/app/maintenance/retention.go index a45a1f99..073e784d 100644 --- a/internal/app/maintenance/retention.go +++ b/internal/app/maintenance/retention.go @@ -17,6 +17,13 @@ type TempAuthKeyRetentionStore interface { DeleteExpired(ctx context.Context, expiredBefore int64, limit int) (int, error) } +// AuthKeySessionLayerRetentionStore reclaims expired short-lived Layer +// watermarks. Selector freshness, not retention timing, is the correctness +// gate; this worker only bounds durable storage. +type AuthKeySessionLayerRetentionStore interface { + DeleteExpiredSessionLayers(ctx context.Context, limit int) (int, error) +} + // OrphanAuthKeyRetentionStore 回收从未形成授权/temp binding 的旧握手 key。 // protected 是当前连接注册表实际使用的 raw auth_key_id 快照。 type OrphanAuthKeyRetentionStore interface { @@ -86,7 +93,8 @@ const ( // updates 服务通过普通 differenceSlice checkpoint 推进,不发送 differenceTooLong。 type RetentionWorker struct { outbox DispatchOutboxRetentionStore - tempKeys TempAuthKeyRetentionStore // 可为 nil(不回收 temp key 绑定) + tempKeys TempAuthKeyRetentionStore // 可为 nil(不回收 temp key 绑定) + authKeySessionLayers AuthKeySessionLayerRetentionStore botAPIUpdates BotAPIUpdateRetentionStore // 可为 nil(不回收 Bot API 队列) userUpdates UserUpdateEventRetentionStore channelUpdates ChannelUpdateEventRetentionStore @@ -176,6 +184,13 @@ func (w *RetentionWorker) WithLoginCodeDeliveryRetention(store LoginCodeDelivery return w } +// WithAuthKeySessionLayerRetention enables bounded seek cleanup for expired +// per-session Layer evidence. +func (w *RetentionWorker) WithAuthKeySessionLayerRetention(store AuthKeySessionLayerRetentionStore) *RetentionWorker { + w.authKeySessionLayers = store + return w +} + // WithOrphanAuthKeyRetention 启用未授权握手 key 的有界回收。active 必须提供 raw key, // 不能提供 temp→perm business key;否则未登录或 PFS 连接会被误判为 orphan。 func (w *RetentionWorker) WithOrphanAuthKeyRetention(store OrphanAuthKeyRetentionStore, active ActiveRawAuthKeyProvider, retention time.Duration) *RetentionWorker { @@ -243,6 +258,14 @@ func (w *RetentionWorker) runOutboxPoisonOnce(ctx context.Context) { } func (w *RetentionWorker) runRetentionOnce(ctx context.Context) { + if w.authKeySessionLayers != nil { + deleted, err := w.authKeySessionLayers.DeleteExpiredSessionLayers(ctx, w.batch) + if err != nil { + w.logger.Warn("回收过期 auth-key session Layer 证据失败", zap.Error(err)) + } else if deleted > 0 { + w.logger.Info("回收过期 auth-key session Layer 证据完成", zap.Int("deleted", deleted)) + } + } if w.loginCodeDeliveries != nil { deleted, err := w.loginCodeDeliveries.DeleteExpiredLoginCodeDeliveries(ctx, time.Now(), w.batch) if err != nil { diff --git a/internal/app/phone/service.go b/internal/app/phone/service.go index fb97c500..8420cd4f 100644 --- a/internal/app/phone/service.go +++ b/internal/app/phone/service.go @@ -9,7 +9,7 @@ import ( "strings" "time" - "github.com/gotd/td/clock" + "github.com/iamxvbaba/td/clock" "telesrv/internal/domain" ) diff --git a/internal/app/phone/service_test.go b/internal/app/phone/service_test.go index 50909cc3..8f99239d 100644 --- a/internal/app/phone/service_test.go +++ b/internal/app/phone/service_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/gotd/td/clock" + "github.com/iamxvbaba/td/clock" "telesrv/internal/domain" ) diff --git a/internal/app/updates/contiguous_test.go b/internal/app/updates/contiguous_test.go index b7be9f18..aa5804cc 100644 --- a/internal/app/updates/contiguous_test.go +++ b/internal/app/updates/contiguous_test.go @@ -148,7 +148,14 @@ func TestGetStateDoesNotConfirmUnfetchedEvents(t *testing.T) { if err != nil { t.Fatalf("GetState after difference: %v", err) } - if st.Pts != 2 { - t.Fatalf("GetState after difference pts=%d, want confirmed pts=2", st.Pts) + if st.Pts != 1 { + t.Fatalf("GetState before delivery commit pts=%d, want confirmed pts=1", st.Pts) + } + if err := svc.CommitDeliveredState(ctx, authKeyID, userID, diff.State, domain.UpdateStateCommitDeliveredOnly); err != nil { + t.Fatalf("CommitDeliveredState: %v", err) + } + st, err = svc.GetState(ctx, authKeyID, userID) + if err != nil || st.Pts != 2 { + t.Fatalf("GetState after delivery commit = %+v err=%v, want pts=2", st, err) } } diff --git a/internal/app/updates/service.go b/internal/app/updates/service.go index 889488ee..1cd2036a 100644 --- a/internal/app/updates/service.go +++ b/internal/app/updates/service.go @@ -135,27 +135,34 @@ func (s *Service) ConfirmEvent(ctx context.Context, authKeyID [8]byte, userID in return s.saveConfirmedState(ctx, authKeyID, userID, domain.UpdateState{Pts: event.Pts, Date: date, Seq: 0}) } -// AcknowledgeCurrentState 返回账号当前最大连续状态,并把该设备的确认水位推进到此。 -// -// 供 updates.getState 使用:协议语义是客户端宣告「从现在开始同步」,启动期的 -// 离线数据由 getDialogs 快照承载(TDesktop 不持久化 pts,每次启动都走此路径)。 -// 若改为返回设备旧确认水位,客户端会在 getDialogs 最新快照之上再重放历史差分, -// 造成未读重复累计、dialog 预览被旧消息抢占。持久化 pts 的客户端(Android) -// 启动时直接带本地 pts 调 getDifference,不经过 getState,不受影响。 -func (s *Service) AcknowledgeCurrentState(ctx context.Context, authKeyID [8]byte, userID int64) (domain.UpdateState, error) { - st, err := s.currentState(ctx, userID) +// ObserveDifferenceRequest records only the cursor a client carried into this +// request. It is deliberately independent from response delivery: even when +// encoding or the socket write later fails, the request still proves the client +// already owned this (clamped) cursor before contacting us. +func (s *Service) ObserveDifferenceRequest(ctx context.Context, authKeyID [8]byte, userID int64, from domain.UpdateState) (domain.UpdateState, error) { + current, err := s.currentState(ctx, userID) if err != nil { return domain.UpdateState{}, err } - if err := s.saveConfirmedState(ctx, authKeyID, userID, st); err != nil { + from = clampDifferenceState(from, current) + if err := s.observeClientState(ctx, authKeyID, userID, from); err != nil { return domain.UpdateState{}, err } - // getState 明确建立“从当前快照开始同步”的 baseline;即使响应丢失,客户端也会 - // 重试 getState/重新拉 snapshot,而不会依赖 baseline 之前的 durable event。 - if err := s.observeClientState(ctx, authKeyID, userID, st); err != nil { - return domain.UpdateState{}, err + return from, nil +} + +// CommitDeliveredState persists the exact cursor justified by a physically +// delivered RPC result. The store owns the atomic/monotonic invariant because +// delivery callbacks from different responses may complete out of order. +func (s *Service) CommitDeliveredState(ctx context.Context, authKeyID [8]byte, userID int64, st domain.UpdateState, mode domain.UpdateStateCommitMode) error { + if s.states == nil { + return nil } - return st, nil + if mode != domain.UpdateStateCommitDeliveredOnly && mode != domain.UpdateStateCommitDeliveredAndObservedBaseline { + return fmt.Errorf("invalid delivered update state commit mode %d", mode) + } + st.Seq = 0 + return s.states.CommitDeliveredState(ctx, authKeyID, userID, st, mode) } // getDifferenceLimit 是单次 getDifference 返回的最大连续事件数;超出置 Partial 让客户端翻页。 @@ -171,19 +178,9 @@ func (s *Service) GetDifference(ctx context.Context, authKeyID [8]byte, userID i if err != nil { return domain.UpdateDifference{}, err } - // 只把客户端在本次请求中实际带回的 cursor 记为 observed。绝不能把本次将要 - // 返回的 State 当确认:响应可能在 socket/进程故障中丢失。恶意/损坏客户端带来的 - // 超前 pts 钳到账号当前连续水位,避免把 retention 安全边界推过 durable truth。 - observed := from - if observed.Pts < 0 { - observed.Pts = 0 - } - if observed.Pts > st.Pts { - observed.Pts = st.Pts - } - if err := s.observeClientState(ctx, authKeyID, userID, observed); err != nil { - return domain.UpdateDifference{}, err - } + // Computation is pure with respect to device confirmed/observed state. The + // request observer and physical-delivery commit are explicit caller phases. + from = clampDifferenceState(from, st) // TDesktop 不支持账号级 updates.differenceTooLong。retention 只能删除所有授权 // 设备都已确认的共同前缀;当前设备若仍带更旧 pts,用一个空的普通 // differenceSlice 把 IntermediateState 推进到已确认 checkpoint,再从 live tail 续拉。 @@ -196,9 +193,6 @@ func (s *Service) GetDifference(ctx context.Context, authKeyID [8]byte, userID i if from.Date != 0 { st.Date = from.Date } - if err := s.saveConfirmedState(ctx, authKeyID, userID, st); err != nil { - return domain.UpdateDifference{}, err - } return domain.UpdateDifference{State: st}, nil } events, err := s.events.ListAfter(ctx, userID, from.Pts, getDifferenceLimit) @@ -246,9 +240,6 @@ func (s *Service) GetDifference(ctx context.Context, authKeyID [8]byte, userID i if len(contiguous) > 0 { out.Date = contiguous[len(contiguous)-1].Date } - if err := s.saveConfirmedState(ctx, authKeyID, userID, out); err != nil { - return domain.UpdateDifference{}, err - } return domain.UpdateDifference{ State: out, Events: contiguous, @@ -276,12 +267,20 @@ func (s *Service) retainedPrefixCheckpoint(ctx context.Context, authKeyID [8]byt } else if checkpoint.Date == 0 { checkpoint.Date = current.Date } - if err := s.saveConfirmedState(ctx, authKeyID, userID, checkpoint); err != nil { - return domain.UpdateDifference{}, false, err - } return domain.UpdateDifference{State: checkpoint, Partial: true}, true, nil } +func clampDifferenceState(from, current domain.UpdateState) domain.UpdateState { + if from.Pts < 0 { + from.Pts = 0 + } + if from.Pts > current.Pts { + from.Pts = current.Pts + } + from.Seq = 0 + return from +} + func (s *Service) currentState(ctx context.Context, userID int64) (domain.UpdateState, error) { current, err := s.currentPts(ctx, userID) if err != nil { diff --git a/internal/app/updates/service_test.go b/internal/app/updates/service_test.go index 306ac495..55a8b8dd 100644 --- a/internal/app/updates/service_test.go +++ b/internal/app/updates/service_test.go @@ -490,11 +490,10 @@ func TestDeleteMessagesPtsRangeFeedsGetDifference(t *testing.T) { } } -// TestAcknowledgeCurrentStateAdvancesConfirmedWatermark 验证 updates.getState -// 的语义:返回账号当前最新连续 pts(而非设备旧确认水位),并把确认水位推进 -// 到此——TDesktop 不持久化 pts,启动靠 getState+getDialogs 快照对齐,返回旧 -// 水位会诱导其重放快照前差分(未读重复累计、dialog 预览被旧消息抢占)。 -func TestAcknowledgeCurrentStateAdvancesConfirmedWatermark(t *testing.T) { +// TestCurrentStateCommitsAuditedBaselineOnlyAfterDelivery verifies that +// computing a getState result is side-effect free and that its physically +// delivered baseline advances confirmed+observed atomically. +func TestCurrentStateCommitsAuditedBaselineOnlyAfterDelivery(t *testing.T) { ctx := context.Background() var authKeyID [8]byte authKeyID[0] = 11 @@ -509,8 +508,8 @@ func TestAcknowledgeCurrentStateAdvancesConfirmedWatermark(t *testing.T) { t.Fatalf("append: %v", err) } // 设备确认水位停在 pts=1 后账号又推进两格。 - if _, err := svc.GetDifference(ctx, authKeyID, userID, domain.UpdateState{Pts: 1}); err != nil { - t.Fatalf("GetDifference: %v", err) + if err := states.Save(ctx, authKeyID, userID, domain.UpdateState{Pts: 1, Date: 1700000001}); err != nil { + t.Fatalf("seed confirmed state: %v", err) } for pts := 2; pts <= 3; pts++ { if err := events.Append(ctx, userID, domain.UpdateEvent{ @@ -521,23 +520,33 @@ func TestAcknowledgeCurrentStateAdvancesConfirmedWatermark(t *testing.T) { } } - st, err := svc.AcknowledgeCurrentState(ctx, authKeyID, userID) + st, err := svc.CurrentState(ctx, userID) if err != nil { - t.Fatalf("AcknowledgeCurrentState: %v", err) + t.Fatalf("CurrentState: %v", err) } if st.Pts != 3 { - t.Fatalf("acknowledged state pts = %d, want account current 3", st.Pts) + t.Fatalf("current state pts = %d, want account current 3", st.Pts) } - confirmed, err := svc.GetState(ctx, authKeyID, userID) + confirmed, _, err := svc.ConfirmedState(ctx, authKeyID, userID) if err != nil { - t.Fatalf("GetState after acknowledge: %v", err) + t.Fatalf("ConfirmedState before delivery: %v", err) } - if confirmed.Pts != 3 { - t.Fatalf("confirmed watermark = %d, want advanced to 3", confirmed.Pts) + if confirmed.Pts != 1 { + t.Fatalf("confirmed before delivery = %d, want 1", confirmed.Pts) + } + if _, ok := states.ObservedClientState(authKeyID, userID); ok { + t.Fatal("computed getState unexpectedly advanced observed") + } + if err := svc.CommitDeliveredState(ctx, authKeyID, userID, st, domain.UpdateStateCommitDeliveredAndObservedBaseline); err != nil { + t.Fatalf("CommitDeliveredState: %v", err) + } + confirmed, _, err = svc.ConfirmedState(ctx, authKeyID, userID) + if err != nil || confirmed.Pts != 3 { + t.Fatalf("confirmed after delivery = %+v err=%v, want pts=3", confirmed, err) } observed, ok := states.ObservedClientState(authKeyID, userID) if !ok || observed.Pts != 3 { - t.Fatalf("getState observed watermark = %+v/%v, want pts=3", observed, ok) + t.Fatalf("observed after delivered baseline = %+v/%v, want pts=3", observed, ok) } } @@ -559,7 +568,11 @@ func TestGetDifferenceRetainsOnlyClientObservedInputCursor(t *testing.T) { // 服务端把 pts=1..2 放进 response,并不证明客户端收到了 response;observed 只能 // 保持在本次 request 实际携带的 pts=0。 - diff, err := svc.GetDifference(ctx, authKeyID, userID, domain.UpdateState{Pts: 0, Date: 1700000100}) + from, err := svc.ObserveDifferenceRequest(ctx, authKeyID, userID, domain.UpdateState{Pts: 0, Date: 1700000100}) + if err != nil { + t.Fatalf("observe first request: %v", err) + } + diff, err := svc.GetDifference(ctx, authKeyID, userID, from) if err != nil { t.Fatalf("first difference: %v", err) } @@ -570,10 +583,23 @@ func TestGetDifferenceRetainsOnlyClientObservedInputCursor(t *testing.T) { if !ok || observed.Pts != 0 { t.Fatalf("observed after merely sending response = %+v/%v, want pts=0", observed, ok) } + if _, found, err := svc.ConfirmedState(ctx, authKeyID, userID); err != nil || found { + t.Fatalf("computed response advanced confirmed: found=%v err=%v", found, err) + } + if err := svc.CommitDeliveredState(ctx, authKeyID, userID, diff.State, domain.UpdateStateCommitDeliveredOnly); err != nil { + t.Fatalf("commit delivered difference: %v", err) + } + if confirmed, found, err := svc.ConfirmedState(ctx, authKeyID, userID); err != nil || !found || confirmed.Pts != 2 { + t.Fatalf("confirmed after delivery = %+v/%v err=%v, want pts=2", confirmed, found, err) + } + observed, _ = states.ObservedClientState(authKeyID, userID) + if observed.Pts != 0 { + t.Fatalf("delivered difference advanced observed to %d, want 0", observed.Pts) + } // 客户端下一次明确带回 pts=2 后,才允许 retention 把共同安全水位推进到 2。 - if _, err := svc.GetDifference(ctx, authKeyID, userID, domain.UpdateState{Pts: 2, Date: 1700000102}); err != nil { - t.Fatalf("confirming difference: %v", err) + if _, err := svc.ObserveDifferenceRequest(ctx, authKeyID, userID, domain.UpdateState{Pts: 2, Date: 1700000102}); err != nil { + t.Fatalf("observing next request: %v", err) } observed, ok = states.ObservedClientState(authKeyID, userID) if !ok || observed.Pts != 2 { @@ -624,6 +650,15 @@ func TestGetDifferenceBelowRetainedFloorUsesEmptySliceCheckpoint(t *testing.T) { if !checkpoint.Partial || len(checkpoint.Events) != 0 || checkpoint.State.Pts != 2 || checkpoint.State.Date != 1700000202 { t.Fatalf("checkpoint difference = %+v, want empty differenceSlice at pts/date 2/1700000202", checkpoint) } + if _, found, err := svc.ConfirmedState(ctx, authKeyID, userID); err != nil || found { + t.Fatalf("computed checkpoint advanced confirmed: found=%v err=%v", found, err) + } + if err := svc.CommitDeliveredState(ctx, authKeyID, userID, checkpoint.State, domain.UpdateStateCommitDeliveredOnly); err != nil { + t.Fatalf("commit delivered checkpoint: %v", err) + } + if confirmed, found, err := svc.ConfirmedState(ctx, authKeyID, userID); err != nil || !found || confirmed.Pts != 2 { + t.Fatalf("confirmed checkpoint = %+v/%v err=%v, want pts=2", confirmed, found, err) + } tail, err := svc.GetDifference(ctx, authKeyID, userID, checkpoint.State) if err != nil { @@ -722,6 +757,10 @@ func (s *captureStateStore) Save(_ context.Context, authKeyID [8]byte, userID in return nil } +func (s *captureStateStore) CommitDeliveredState(ctx context.Context, authKeyID [8]byte, userID int64, state domain.UpdateState, _ domain.UpdateStateCommitMode) error { + return s.Save(ctx, authKeyID, userID, state) +} + func (s *captureStateStore) ObserveClientState(_ context.Context, _ [8]byte, _ int64, _ domain.UpdateState) error { return nil } diff --git a/internal/compat/android/layer_rpc.go b/internal/compat/android/layer_rpc.go new file mode 100644 index 00000000..6ad05a69 --- /dev/null +++ b/internal/compat/android/layer_rpc.go @@ -0,0 +1,38 @@ +package android + +import ( + "errors" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/tg" +) + +var ErrPrivateLayerRPCInvalid = errors.New("android private layer RPC is invalid") + +// AdaptPrivateLayerRPC invokes the provenance-locked static gotdgen overlay +// from the generated unknown-method view. Nested values decode with the exact +// connection profile and the canonical request is re-profiled by gotd core. +func AdaptPrivateLayerRPC(view tg.LayerRPCUnknownMethodView) (tg.LayerOutboundCall, bool, error) { + outbound, handled, err := view.AdaptClientRPCOverlay(tg.LayerClientRPCOverlayDrkloAndroid) + if err == nil && !handled { + outbound, handled, err = view.AdaptClientRPCOverlay(tg.LayerClientRPCOverlayDrkloAndroidTheme) + } + if err != nil { + return tg.LayerOutboundCall{}, handled, errors.Join(ErrPrivateLayerRPCInvalid, err) + } + return outbound, handled, nil +} + +// UpgradePrivateLayerRPC is retained only for Router.Dispatch's legacy test +// seam. Production admission uses AdaptPrivateLayerRPC above so its decode +// shares the outer generated request budget. +func UpgradePrivateLayerRPC(profile tg.LayerProfile, in *bin.Buffer, limits tg.LayerDecodeLimits) (*bin.Buffer, bool, error) { + upgraded, handled, err := tg.AdaptClientRPCOverlayWithLimits(profile, tg.LayerClientRPCOverlayDrkloAndroid, in, limits) + if err == nil && !handled { + upgraded, handled, err = tg.AdaptClientRPCOverlayWithLimits(profile, tg.LayerClientRPCOverlayDrkloAndroidTheme, in, limits) + } + if err != nil { + return nil, handled, errors.Join(ErrPrivateLayerRPCInvalid, err) + } + return upgraded, handled, nil +} diff --git a/internal/compat/android/layer_rpc_test.go b/internal/compat/android/layer_rpc_test.go new file mode 100644 index 00000000..6dd9c53c --- /dev/null +++ b/internal/compat/android/layer_rpc_test.go @@ -0,0 +1,54 @@ +package android + +import ( + "errors" + "testing" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/tg" +) + +func TestUpgradePrivateLayerRPCOnlyAcceptsAuditedAndroidConstructors(t *testing.T) { + // DrKLO messages.forwardMessages private CRC has a body identical to the + // canonical request for the flags=0 empty-vector case. + private := bin.Buffer{} + private.PutID(0x41d41ade) + private.PutInt(0) + private.PutID(0x7f3b18ea) // inputPeerEmpty + private.PutVectorHeader(0) + private.PutVectorHeader(0) + private.PutID(0x7f3b18ea) // inputPeerEmpty + + in := &bin.Buffer{Buf: private.Copy()} + upgraded, ok, err := UpgradePrivateLayerRPC(tg.LayerProfileCanonical, in, tg.LayerDecodeLimits{}) + if err != nil || !ok { + t.Fatalf("upgrade private method = ok:%v err:%v", ok, err) + } + if in.Len() != 0 { + t.Fatalf("successful private method left %d bytes", in.Len()) + } + if id, peekErr := upgraded.PeekID(); peekErr != nil || id != 0x13704a7c { + t.Fatalf("canonical id = %#x err=%v", id, peekErr) + } + + official := bin.Buffer{} + official.PutID(0xb921bd04) // arbitrary non-private/official constructor + if value, handled, err := UpgradePrivateLayerRPC(tg.LayerProfileCanonical, &official, tg.LayerDecodeLimits{}); value != nil || handled || err != nil { + t.Fatalf("non-private method = value:%v handled:%v err:%v", value, handled, err) + } +} + +func TestGeneratedPrivateLayerRPCOverlayHasAllAuditedMethods(t *testing.T) { + if got, want := tg.LayerClientRPCOverlayMethodCount(tg.LayerClientRPCOverlayDrkloAndroid), 15; got != want { + t.Fatalf("generated DrKLO method count = %d, want %d", got, want) + } +} + +func TestUpgradePrivateLayerRPCRejectsMalformedBody(t *testing.T) { + malformed := bin.Buffer{} + malformed.PutID(0x41d41ade) + _, ok, err := UpgradePrivateLayerRPC(tg.LayerProfileCanonical, &malformed, tg.LayerDecodeLimits{}) + if !ok || !errors.Is(err, ErrPrivateLayerRPCInvalid) { + t.Fatalf("malformed private method = ok:%v err:%v", ok, err) + } +} diff --git a/internal/compat/ios/minimal.go b/internal/compat/ios/minimal.go index b0f6410d..f6702707 100644 --- a/internal/compat/ios/minimal.go +++ b/internal/compat/ios/minimal.go @@ -1,6 +1,6 @@ package ios -import "github.com/gotd/td/tg" +import "github.com/iamxvbaba/td/tg" // NoAppUpdate is the bounded answer used until telesrv has an application // release catalog. It makes iOS keep its installed build and retry on its diff --git a/internal/compat/layerwire/README.md b/internal/compat/layerwire/README.md deleted file mode 100644 index 4dd10d49..00000000 --- a/internal/compat/layerwire/README.md +++ /dev/null @@ -1,142 +0,0 @@ -# layerwire 操作手册(多 Layer 向后兼容) - -> 本文是 **怎么操作**(runbook)。**为什么这么设计**见 [`docs/layer-compat-220-227-design.md`](../../../docs/layer-compat-220-227-design.md)。 -> 改这个包前请先读完本文 + 设计文档。所有命令都从 **telesrv 模块根目录**执行。 - -## 这个包是干什么的 - -让 telesrv 同时正确服务 **Layer 220–227** 的客户端,而业务 handler / gotd 永远只跑 canonical(227)、一行不改。 -- **出站**:把 227 对象降级成老客户端能解的 wire 形态(`Transcode`)。 -- **入站**:把老客户端发来的旧构造器升级成 227 请求,再交正常 gotd dispatcher(`UpgradeInbound`)。 - -两个正交维度(**务必分清**): -- **官方层漂移**:构造器在 layer N 的字段/CRC 与 227 不同。真值=官方 TDesktop `api.tl` 各层。**自动从 schema 生成**。 -- **客户端构造器漂移**:某客户端(如 DrKLO Android)手维护的 TL 实际发了个旧 layer 的官方构造器,但它声明的整体 layer 却是新的。真值=该客户端源码(TLRPC.java)。**声明在 `client-drift.tl` / `client_aliases.go`**。 - -## 文件地图 - -| 文件 | 角色 | 谁改 | -|---|---|---| -| `schema/canonical-227.tl` | **embed**,运行期 walker 的 227 字段布局(= gotd `td/_schema/tdesktop.tl` 的副本) | gotd 升级时 re-sync | -| `_schema/layer-2NN.tl` | 历史层官方 schema(从 TDesktop git 抽,**仅生成期用**,下划线=不编译/不 embed) | 升级/下探 floor 时抽取 | -| `schema/client-drift.tl` | **声明式**:客户端发的旧构造器老布局(body 与 227 不同的) | 发现客户端漂移时 +1 行 | -| `schema/routable-compat.tl` | **仅结构预检**:已有 RPC fallback adapter 的非 canonical wire 布局(当前只含 4 个 DrKLO theme 构造器);与 canonical 图合并后完整 walk,但不自动升级 | 收敛既有手写 adapter 时维护,禁止借此新增业务 fallback | -| `client_aliases.go` | 客户端漂移里 **body 与 227 字节一致**的,纯 `老CRC→227CRC` | 发现纯换 CRC 漂移时 +1 条 | -| `tables_gen.go` | **生成产物**(勿手改):官方层降级表 + 入站升级表 + 新类型集 | 跑 `gen` 重生成 | -| `gen/main.go` | 生成器:对拍 schema、证明机械性、产 `tables_gen.go` | 升级逻辑变更时 | -| `layout.go` `walk.go` `tables.go` | 通用解释器(读/丈量/递归转码)| 核心,少动 | -| `fallback.go` | 出站手写兜底(结构性 / 227-only 类型)| CoverageGate 报缺时 | -| `inbound.go` | 入站通用升级引擎 + `fieldConverters` + `driftFieldRenames` | DriftCoverage 报缺时 | - -## 核心命令 - -```bash -# 复核 schema 差异数字(不改文件) -go run ./internal/compat/layerwire/gen -report - -# 重新生成 tables_gen.go(官方层漂移表) -go run ./internal/compat/layerwire/gen -emit internal/compat/layerwire/tables_gen.go - -# 全部护栏(漂移门禁 + 对各历史层真实 schema 对拍 + 性能基准) -go test ./internal/compat/layerwire/ -go test ./internal/compat/layerwire/ -run '^$' -bench . -benchmem # 性能 - -# 改完务必: -gofmt -w internal/compat/layerwire/ && go build ./... && go vet ./internal/... -``` - ---- - -## 操作 1:gotd 升级(canonical layer 上移,例 227 → 230) - -> gotd bump 是显式任务(见 AGENTS.md 铁律 #6)。canonical schema 随之变化,按下列步骤同步。 - -1. **同步 canonical schema**(gotd 的就是实际编出的字节): - ```bash - cp ../td/_schema/tdesktop.tl internal/compat/layerwire/schema/canonical-230.tl - rm internal/compat/layerwire/schema/canonical-227.tl - ``` - 改 `layout.go`:`//go:embed schema/canonical-230.tl`、`const CanonicalLayer = 230`。 -2. **把原 canonical 层并入历史 TO 层**:现在 227/228/229 成了"老层",从 TDesktop git 抽进 `_schema/`(见文末「抽取 api.tl@N」)。 -3. **改生成期常量**:`gen/main.go` 的 `canonicalLayer = 230`。(`supportedFloor` 不变。) -4. **重生成 + 复核**: - ```bash - go run ./internal/compat/layerwire/gen -report # 看 changed/new 数字是否合理 - go run ./internal/compat/layerwire/gen -emit internal/compat/layerwire/tables_gen.go - ``` -5. **跑护栏、按报告 triage**: - ```bash - go test ./internal/compat/layerwire/ - ``` - - `TestCoverageGate` 失败 = 出现了 telesrv 可达但没处理的 227(新 canonical)-only / 结构性类型 → 去 `fallback.go` 加 by-type 兜底或结构性转换,或确认 telesrv 不发就加进 `unemittedAllowlist`(`gate_test.go`,附理由)。 - - 生成器 `-report` 里 "structural" 列出的需手写转换(参照 `fallback.go transcodePollAnswerVoters`)。 -6. `gofmt`/`build`/`vet`/全量 `go test`。真机 220/老层/新层各一台回归。 - -## 操作 2:下探 floor(支持更老客户端,例 220 → 215) - -1. 从 TDesktop git 抽 `layer-215.tl … layer-219.tl` 进 `_schema/`(见文末)。 -2. 改 `supportedFloor`:`layout.go` 的 `SupportedFloor = 215` **和** `gen/main.go` 的 `supportedFloor = 215`(两处都要)。 -3. `go run ... -emit ...` 重生成 → `go test`。 -4. 越老的层结构性差异越多,按 `TestCoverageGate` / 生成器 report triage(同操作 1 第 5 步)。 - -## 操作 3:新增「客户端构造器漂移」(最常见) - -触发:某客户端发的旧构造器导致 `NOT_IMPLEMENTED`(入站)或对端渲染异常;或主动审计客户端源码发现它发旧 CRC。 - -1. **拿到老构造器的精确 TL 定义**: - - 优先看该客户端源码的序列化(DrKLO Android:`TMessagesProj/.../TLRPC.java` 的 `serializeToStream`,按 `writeInt32/writeString/...` 顺序还原字段)。 - - 或它是某旧 layer 官方构造器:`git -C ../tdesktop/tdesktop log -S"#" -- ` 找到所在层,再取该层定义。 -2. **判断 body 是否与 227 字节一致**: - - **一致**(只是 CRC 不同;典型=227 只追加了 flag-gated 可选字段而客户端不设)→ 往 `client_aliases.go clientMethodAliases` 加 `0x<老CRC>: 0x<227CRC>`。 - - **不一致**(缺 flags 整数 / 字段类型变了 / 缺必填字段)→ 往 `schema/client-drift.tl` 加**一行老布局 TL**(用 method 的限定名,结果类型随便填合法值,引擎只按名字匹配 227)。 -3. **跑测试**: - ```bash - go test ./internal/compat/layerwire/ -run TestInbound - ``` - - 绿 = 通用引擎已能自动升级(复制共享字段 + 插 flags=0 + 按 kind 补默认)。**完事**。 - - `TestInboundDriftCoverage` 报 `needs converter A->B` = 有字段类型变更 → 往 `inbound.go fieldConverters` 加一条 `"A->B"`(可复用,参照 `Vector->Vector`)。 - - 报 `field X not defaultable` 或字段**改名** → 往 `inbound.go driftFieldRenames` 加 `"\x00<227字段>": "<老字段>"`(参照 `bots.exportBotToken\x00bot`)。 -4. **绝不**为此写一个新的 `handleLegacyXxx` 解码 handler——统一走数据 + 通用引擎。`routable-compat.tl` 只给既存 DrKLO theme fallback 补 dispatcher 前结构门禁,不是新增 adapter 的入口。 - -## 操作 4:出站 `TestCoverageGate` 失败 - -说明 telesrv 现在会发某个"经保留字段可达"的 227-only / 结构性类型,但没处理。 -- 该类**有同抽象类的老成员**可降级 → `fallback.go` 加 `newTypeFallbacksByType["<抽象类>"]`(如 `PageBlock→pageBlockUnsupported`)。 -- 是**结构性变更类型**且 telesrv 真发 → `fallback.go structuralTransforms` 加手写转换。 -- **确认 telesrv 不发** → 加进 `gate_test.go unemittedAllowlist`(**必须附理由**,引用出站构造器审计)。 - ---- - -## 护栏:每个测试拦什么 - -| 测试 | 拦截 | -|---|---| -| `TestWalkConsumesCanonicalObjects` | 解释器读不全某个 227 类型(字段布局漏) | -| `TestTranscodeDowngradeValid` | 降级输出对 220..226 **真实 schema** 解析失败/有残留字节 | -| `TestTranscodeChangedTypeNestedInUnchangedContainer` | 「外层 CRC 不变但内含变更类型」被误整段拷贝 | -| `TestCoverageGate` | 出站 227-only/结构性类型无 handler 又不在 allowlist(gotd bump/客户端升级引入新形态时报) | -| `TestInboundDriftCoverage` | `client-drift.tl` 某条目无法自动升级(缺 converter/rename) | -| `TestInboundBodyTransforms` / `TestInboundCRCSwaps` | 入站升级产出不是合法 227 请求 | -| `TestNegotiatedLayerStickyContract` | layer 协商的 `(layer, ok)` 契约(避免缓存驱逐把老客户端误降回 227) | - -**运行期 fail-safe**:出站遇未处理类型 → `Transcode` 返错 → 边界记日志并发 canonical 字节(连接存活,单对象可能渲染异常)。入站遇未覆盖旧 CRC → 落 gotd dispatcher → `NOT_IMPLEMENTED`(须按 AGENTS.md #5 进 compatibility trace + 矩阵)。**护栏的意义就是把这些从"线上撞见"提前到"提交期/测试期发现"。** - -## 抽取 api.tl@N(操作 1/2 用) - -```bash -TD=../tdesktop/tdesktop -APITL=Telegram/SourceFiles/mtproto/scheme/api.tl - -# 找 layer N 的提交(取最后一个写入 "// LAYER N" 的;可能有初版+修订,选最全的) -git -C "$TD" log --oneline -S"// LAYER N" -- "$APITL" - -# 抽取(务必校验文件末尾确是 "// LAYER N") -git -C "$TD" show :"$APITL" > internal/compat/layerwire/_schema/layer-N.tl -tail -1 internal/compat/layerwire/_schema/layer-N.tl # 应为: // LAYER N -``` - -各层→commit 对照见设计文档 §3 表(220..227 的 canonical 抽取点)。`gotd/tl` 解析器能直接吃 TDesktop api.tl,无需改格式。 - -## 稳态心法 - -**喂新 schema(gotd 或更老层)→ 跑 `gen` + `go test` → 护栏吐出短清单 → 人只处理新出现的 fallback / 结构性 / converter / rename。** 不再有"运行时撞 NOT_IMPLEMENTED 再手写 handler"。 diff --git a/internal/compat/layerwire/_schema/layer-220.tl b/internal/compat/layerwire/_schema/layer-220.tl deleted file mode 100644 index 8803fc0e..00000000 --- a/internal/compat/layerwire/_schema/layer-220.tl +++ /dev/null @@ -1,2882 +0,0 @@ -boolFalse#bc799737 = Bool; -boolTrue#997275b5 = Bool; - -true#3fedd339 = True; - -vector#1cb5c415 {t:Type} # [ t ] = Vector t; - -error#c4b9f9bb code:int text:string = Error; - -null#56730bcc = Null; - -inputPeerEmpty#7f3b18ea = InputPeer; -inputPeerSelf#7da07ec9 = InputPeer; -inputPeerChat#35a95cb9 chat_id:long = InputPeer; -inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; -inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer; -inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer; -inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer; - -inputUserEmpty#b98886cf = InputUser; -inputUserSelf#f7c1b13f = InputUser; -inputUser#f21158c6 user_id:long access_hash:long = InputUser; -inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser; - -inputPhoneContact#6a1dc4be flags:# client_id:long phone:string first_name:string last_name:string note:flags.0?TextWithEntities = InputContact; - -inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; -inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; -inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile; - -inputMediaEmpty#9664f57f = InputMedia; -inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; -inputMediaPhoto#b3ba0635 flags:# spoiler:flags.1?true id:InputPhoto ttl_seconds:flags.0?int = InputMedia; -inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; -inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; -inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; -inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; -inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; -inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; -inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; -inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; -inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector solution:flags.1?string solution_entities:flags.1?Vector = InputMedia; -inputMediaDice#e66fbf7b emoticon:string = InputMedia; -inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; -inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; -inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; -inputMediaTodo#9fc55fde todo:TodoList = InputMedia; - -inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; -inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; -inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; - -inputGeoPointEmpty#e4c123d6 = InputGeoPoint; -inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint; - -inputPhotoEmpty#1cd7bf0d = InputPhoto; -inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; - -inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; -inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; -inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; -inputTakeoutFileLocation#29be5899 = InputFileLocation; -inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; -inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; -inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; -inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; - -peerUser#59511722 user_id:long = Peer; -peerChat#36c6019a chat_id:long = Peer; -peerChannel#a2a5371e channel_id:long = Peer; - -storage.fileUnknown#aa963b05 = storage.FileType; -storage.filePartial#40bc6f52 = storage.FileType; -storage.fileJpeg#7efe0e = storage.FileType; -storage.fileGif#cae1aadf = storage.FileType; -storage.filePng#a4f63c0 = storage.FileType; -storage.filePdf#ae1e508d = storage.FileType; -storage.fileMp3#528a0677 = storage.FileType; -storage.fileMov#4b09ebbc = storage.FileType; -storage.fileMp4#b3cea0e4 = storage.FileType; -storage.fileWebp#1081464c = storage.FileType; - -userEmpty#d3bc4b7a id:long = User; -user#31774388 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true bot_business:flags2.11?true bot_has_main_app:flags2.13?true bot_forum_view:flags2.16?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?RecentStory color:flags2.8?PeerColor profile_color:flags2.9?PeerColor bot_active_users:flags2.12?int bot_verification_icon:flags2.14?long send_paid_messages_stars:flags2.15?long = User; - -userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; - -userStatusEmpty#9d05049 = UserStatus; -userStatusOnline#edb93949 expires:int = UserStatus; -userStatusOffline#8c703f was_online:int = UserStatus; -userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus; -userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus; -userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; - -chatEmpty#29562865 id:long = Chat; -chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; -chatForbidden#6592a1a7 id:long title:string = Chat; -channel#1c32b11c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?RecentStory color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat; -channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; - -chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#e4e0b29d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab = ChatFull; - -chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; -chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; -chatParticipantAdmin#a0933f5b user_id:long inviter_id:long date:int = ChatParticipant; - -chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants; -chatParticipants#3cbc93f8 chat_id:long participants:Vector version:int = ChatParticipants; - -chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; - -messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; -message#b92f76cf flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int = Message; -messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; - -messageMediaEmpty#3ded6320 = MessageMedia; -messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; -messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; -messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; -messageMediaUnsupported#9f84f49e = MessageMedia; -messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; -messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; -messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; -messageMediaGame#fdb19008 game:Game = MessageMedia; -messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia; -messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia; -messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; -messageMediaDice#3f7ee58b value:int emoticon:string = MessageMedia; -messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; -messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; -messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; -messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; -messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector = MessageMedia; -messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia; - -messageActionEmpty#b6aef7b0 = MessageAction; -messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; -messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; -messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; -messageActionChatDeletePhoto#95e3fbef = MessageAction; -messageActionChatAddUser#15cefd00 users:Vector = MessageAction; -messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction; -messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction; -messageActionChannelCreate#95d2ac92 title:string = MessageAction; -messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction; -messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction; -messageActionPinMessage#94bd38ed = MessageAction; -messageActionHistoryClear#9fbab604 = MessageAction; -messageActionGameScore#92a72876 game_id:long score:int = MessageAction; -messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction; -messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction; -messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; -messageActionScreenshotTaken#4792929b = MessageAction; -messageActionCustomAction#fae69f56 message:string = MessageAction; -messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction; -messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; -messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; -messageActionContactSignUp#f3f25f76 = MessageAction; -messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction; -messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; -messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector = MessageAction; -messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction; -messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; -messageActionSetChatTheme#b91bbd3a theme:ChatTheme = MessageAction; -messageActionChatJoinedByRequest#ebbca3cb = MessageAction; -messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction; -messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction; -messageActionGiftPremium#48e91302 flags:# currency:string amount:long days:int crypto_currency:flags.0?string crypto_amount:flags.0?long message:flags.1?TextWithEntities = MessageAction; -messageActionTopicCreate#d999256 flags:# title_missing:flags.1?true title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction; -messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction; -messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; -messageActionRequestedPeer#31518e9b button_id:int peers:Vector = MessageAction; -messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; -messageActionGiftCode#31c48347 flags:# via_giveaway:flags.0?true unclaimed:flags.5?true boost_peer:flags.1?Peer days:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long message:flags.4?TextWithEntities = MessageAction; -messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction; -messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction; -messageActionBoostApply#cc02aa6d boosts:int = MessageAction; -messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; -messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; -messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; -messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; -messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction; -messageActionStarGiftUnique#95728543 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long = MessageAction; -messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; -messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; -messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; -messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; -messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; -messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction; -messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction; -messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction; -messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction; -messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction; -messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction; -messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction; - -dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; -dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; - -photoEmpty#2331b22d id:long = Photo; -photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = Photo; - -photoSizeEmpty#e17e23c type:string = PhotoSize; -photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; -photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; -photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; -photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; -photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; - -geoPointEmpty#1117dd5f = GeoPoint; -geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; - -auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; -auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; -auth.sentCodePaymentRequired#e0955a3c store_product:string phone_code_hash:string support_email_address:string support_email_subject:string currency:string amount:long = auth.SentCode; - -auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; -auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; - -auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; - -inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; -inputNotifyUsers#193b4417 = InputNotifyPeer; -inputNotifyChats#4a95e84e = InputNotifyPeer; -inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; -inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer; - -inputPeerNotifySettings#cacb6ae2 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_sound:flags.8?NotificationSound = InputPeerNotifySettings; - -peerNotifySettings#99622c0c flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_ios_sound:flags.8?NotificationSound stories_android_sound:flags.9?NotificationSound stories_other_sound:flags.10?NotificationSound = PeerNotifySettings; - -peerSettings#f47741f7 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true business_bot_paused:flags.11?true business_bot_can_reply:flags.12?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int business_bot_id:flags.13?long business_bot_manage_url:flags.13?string charge_paid_message_stars:flags.14?long registration_month:flags.15?string phone_country:flags.16?string name_change_date:flags.17?int photo_change_date:flags.18?int = PeerSettings; - -wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; -wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; - -inputReportReasonSpam#58dbcab8 = ReportReason; -inputReportReasonViolence#1e22c78d = ReportReason; -inputReportReasonPornography#2e59d922 = ReportReason; -inputReportReasonChildAbuse#adf44ee3 = ReportReason; -inputReportReasonOther#c1e4a2b1 = ReportReason; -inputReportReasonCopyright#9b89f93a = ReportReason; -inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; -inputReportReasonFake#f5ddd6e7 = ReportReason; -inputReportReasonIllegalDrugs#a8eb2be = ReportReason; -inputReportReasonPersonalDetails#9ec7863d = ReportReason; - -userFull#a02bc13e flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme:flags.15?ChatTheme private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int main_tab:flags2.20?ProfileTab saved_music:flags2.21?Document note:flags2.22?TextWithEntities = UserFull; - -contact#145ade0b user_id:long mutual:Bool = Contact; - -importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; - -contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; - -contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; -contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; - -contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; - -contacts.blocked#ade1591 blocked:Vector chats:Vector users:Vector = contacts.Blocked; -contacts.blockedSlice#e1664194 count:int blocked:Vector chats:Vector users:Vector = contacts.Blocked; - -messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; - -messages.messages#1d73e7ea messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#5f206716 flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesNotModified#74535f21 count:int = messages.Messages; - -messages.chats#64ff9fd5 chats:Vector = messages.Chats; -messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; - -messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; - -messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; - -inputMessagesFilterEmpty#57e2f66c = MessagesFilter; -inputMessagesFilterPhotos#9609a51c = MessagesFilter; -inputMessagesFilterVideo#9fc00e65 = MessagesFilter; -inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; -inputMessagesFilterDocument#9eddf188 = MessagesFilter; -inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; -inputMessagesFilterGif#ffc86587 = MessagesFilter; -inputMessagesFilterVoice#50f5c392 = MessagesFilter; -inputMessagesFilterMusic#3751b49e = MessagesFilter; -inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; -inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; -inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; -inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; -inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; -inputMessagesFilterGeo#e7026d0d = MessagesFilter; -inputMessagesFilterContacts#e062db83 = MessagesFilter; -inputMessagesFilterPinned#1bb00451 = MessagesFilter; - -updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; -updateMessageID#4e90bfd6 id:int random_id:long = Update; -updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; -updateUserTyping#2a17bf5c flags:# user_id:long top_msg_id:flags.0?int action:SendMessageAction = Update; -updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update; -updateChatParticipants#7761198 participants:ChatParticipants = Update; -updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; -updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector = Update; -updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update; -updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; -updateEncryptedChatTyping#1710f156 chat_id:int = Update; -updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; -updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; -updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update; -updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update; -updateDcOptions#8e5e9873 dc_options:Vector = Update; -updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; -updateServiceNotification#ebe46819 flags:# popup:flags.0?true invert_media:flags.2?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; -updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; -updateUserPhone#5492a13 user_id:long phone:string = Update; -updateReadHistoryInbox#9e84bc99 flags:# folder_id:flags.0?int peer:Peer top_msg_id:flags.1?int max_id:int still_unread_count:int pts:int pts_count:int = Update; -updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; -updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; -updateReadMessagesContents#f8227181 flags:# messages:Vector pts:int pts_count:int date:flags.0?int = Update; -updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; -updateChannel#635b4c09 channel_id:long = Update; -updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update; -updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; -updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; -updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; -updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Update; -updateStickerSets#31c24808 flags:# masks:flags.0?true emojis:flags.1?true = Update; -updateSavedGifs#9375341e = Update; -updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; -updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; -updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; -updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; -updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; -updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update; -updateReadFeaturedStickers#571d2742 = Update; -updateRecentStickers#9a422c20 = Update; -updateConfig#a229dd06 = Update; -updatePtsChanged#3354678f = Update; -updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update; -updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; -updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; -updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; -updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; -updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update; -updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; -updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; -updateLangPackTooLong#46560264 lang_code:string = Update; -updateLangPack#56022f4d difference:LangPackDifference = Update; -updateFavedStickers#e511996d = Update; -updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector = Update; -updateContactsReset#7084a7be = Update; -updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; -updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update; -updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; -updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; -updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; -updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update; -updatePeerLocated#b4afcfb0 peers:Vector = Update; -updateNewScheduledMessage#39a51dfb message:Message = Update; -updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector sent_messages:flags.0?Vector = Update; -updateTheme#8216fba3 theme:Theme = Update; -updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update; -updateLoginToken#564fe691 = Update; -updateMessagePollVote#24f40e77 poll_id:long peer:Peer options:Vector qts:int = Update; -updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update; -updateDialogFilterOrder#a5d72105 order:Vector = Update; -updateDialogFilters#3504914f = Update; -updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update; -updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update; -updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update; -updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update; -updatePeerBlocked#ebe07752 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer = Update; -updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; -updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; -updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChat#f89a6a4e chat_id:long = Update; -updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; -updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update; -updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; -updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update; -updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update; -updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; -updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; -updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update; -updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update; -updateAttachMenuBots#17b7a20b = Update; -updateWebViewResultSent#1592b79d query_id:long = Update; -updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update; -updateSavedRingtones#74d8be99 = Update; -updateTranscribedAudio#84cd5a flags:# pending:flags.0?true peer:Peer msg_id:int transcription_id:long text:string = Update; -updateReadFeaturedEmojiStickers#fb4c496c = Update; -updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update; -updateRecentEmojiStatuses#30f443db = Update; -updateRecentReactions#6f7863f4 = Update; -updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update; -updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector = Update; -updateUser#20529438 user_id:long = Update; -updateAutoSaveSettings#ec05b097 = Update; -updateStory#75b3b798 peer:Peer story:StoryItem = Update; -updateReadStories#f74e932b peer:Peer max_id:int = Update; -updateStoryID#1bf335b9 id:int random_id:long = Update; -updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update; -updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update; -updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update; -updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update; -updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update; -updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector new_reactions:Vector qts:int = Update; -updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector qts:int = Update; -updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; -updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector = Update; -updateSavedReactionTags#39c67432 = Update; -updateSmsJob#f16269d4 job_id:string = Update; -updateQuickReplies#f9470ab2 quick_replies:Vector = Update; -updateNewQuickReply#f53da717 quick_reply:QuickReply = Update; -updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update; -updateQuickReplyMessage#3e050d0f message:Message = Update; -updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector = Update; -updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Update; -updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; -updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; -updateStarsBalance#4e80a379 balance:StarsAmount = Update; -updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; -updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; -updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; -updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; -updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; -updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; -updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update; -updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = Update; -updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update; -updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update; -updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector = Update; -updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector = Update; -updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update; -updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update; - -updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; - -updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; -updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; -updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; -updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; - -updatesTooLong#e317af7e = Updates; -updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShort#78d4dec1 update:Update date:int = Updates; -updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; -updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; -updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; -photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; - -photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; - -upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; -upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; - -dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; - -config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config; - -nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; - -help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate; -help.noAppUpdate#c45a6536 = help.AppUpdate; - -help.inviteText#18cb9f78 message:string = help.InviteText; - -encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; -encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat; -encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; -encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; -encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat; - -inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; - -encryptedFileEmpty#c21f497e = EncryptedFile; -encryptedFile#a8008cd8 id:long access_hash:long size:long dc_id:int key_fingerprint:int = EncryptedFile; - -inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; -inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; -inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; -inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; - -encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; -encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; - -messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; -messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; - -messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; -messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; - -inputDocumentEmpty#72f0eaae = InputDocument; -inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; - -documentEmpty#36f8c871 id:long = Document; -document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector video_thumbs:flags.1?Vector dc_id:int attributes:Vector = Document; - -help.support#17c6b5f6 phone_number:string user:User = help.Support; - -notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; -notifyUsers#b4c83b4c = NotifyPeer; -notifyChats#c007cec3 = NotifyPeer; -notifyBroadcasts#d612e8ef = NotifyPeer; -notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer; - -sendMessageTypingAction#16bf744e = SendMessageAction; -sendMessageCancelAction#fd5ec8f5 = SendMessageAction; -sendMessageRecordVideoAction#a187d66f = SendMessageAction; -sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; -sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; -sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; -sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; -sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; -sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; -sendMessageChooseContactAction#628cbc6f = SendMessageAction; -sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; -sendMessageRecordRoundAction#88f27fbc = SendMessageAction; -sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; -speakingInGroupCallAction#d92c2285 = SendMessageAction; -sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; -sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; -sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction; -sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction; -sendMessageTextDraftAction#376d975c random_id:long text:TextWithEntities = SendMessageAction; - -contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; - -inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; -inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; -inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; -inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; -inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; -inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; -inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; -inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey; -inputPrivacyKeyVoiceMessages#aee69d68 = InputPrivacyKey; -inputPrivacyKeyAbout#3823cc40 = InputPrivacyKey; -inputPrivacyKeyBirthday#d65a11cc = InputPrivacyKey; -inputPrivacyKeyStarGiftsAutoSave#e1732341 = InputPrivacyKey; -inputPrivacyKeyNoPaidMessages#bdc597b4 = InputPrivacyKey; -inputPrivacyKeySavedMusic#4dbe9226 = InputPrivacyKey; - -privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; -privacyKeyChatInvite#500e6dfa = PrivacyKey; -privacyKeyPhoneCall#3d662b7b = PrivacyKey; -privacyKeyPhoneP2P#39491cc8 = PrivacyKey; -privacyKeyForwards#69ec56a3 = PrivacyKey; -privacyKeyProfilePhoto#96151fed = PrivacyKey; -privacyKeyPhoneNumber#d19ae46d = PrivacyKey; -privacyKeyAddedByPhone#42ffd42b = PrivacyKey; -privacyKeyVoiceMessages#697f414 = PrivacyKey; -privacyKeyAbout#a486b761 = PrivacyKey; -privacyKeyBirthday#2000a518 = PrivacyKey; -privacyKeyStarGiftsAutoSave#2ca4fdf8 = PrivacyKey; -privacyKeyNoPaidMessages#17d348d2 = PrivacyKey; -privacyKeySavedMusic#ff7a571b = PrivacyKey; - -inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; -inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; -inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; -inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; -inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; -inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; -inputPrivacyValueAllowChatParticipants#840649cf chats:Vector = InputPrivacyRule; -inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector = InputPrivacyRule; -inputPrivacyValueAllowCloseFriends#2f453e49 = InputPrivacyRule; -inputPrivacyValueAllowPremium#77cdc9f1 = InputPrivacyRule; -inputPrivacyValueAllowBots#5a4fcce5 = InputPrivacyRule; -inputPrivacyValueDisallowBots#c4e57915 = InputPrivacyRule; - -privacyValueAllowContacts#fffe1bac = PrivacyRule; -privacyValueAllowAll#65427b82 = PrivacyRule; -privacyValueAllowUsers#b8905fb2 users:Vector = PrivacyRule; -privacyValueDisallowContacts#f888fa1a = PrivacyRule; -privacyValueDisallowAll#8b73e763 = PrivacyRule; -privacyValueDisallowUsers#e4621141 users:Vector = PrivacyRule; -privacyValueAllowChatParticipants#6b134e8e chats:Vector = PrivacyRule; -privacyValueDisallowChatParticipants#41c87565 chats:Vector = PrivacyRule; -privacyValueAllowCloseFriends#f7e8d89b = PrivacyRule; -privacyValueAllowPremium#ece9814b = PrivacyRule; -privacyValueAllowBots#21461b5d = PrivacyRule; -privacyValueDisallowBots#f6a5f82f = PrivacyRule; - -account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; - -accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; - -documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; -documentAttributeAnimated#11b58939 = DocumentAttribute; -documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; -documentAttributeVideo#43c57c48 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double video_codec:flags.5?string = DocumentAttribute; -documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; -documentAttributeFilename#15590068 file_name:string = DocumentAttribute; -documentAttributeHasStickers#9801d2f7 = DocumentAttribute; -documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute; - -messages.stickersNotModified#f1749a22 = messages.Stickers; -messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; - -stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; - -messages.allStickersNotModified#e86602c3 = messages.AllStickers; -messages.allStickers#cdbbcebb hash:long sets:Vector = messages.AllStickers; - -messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; - -webPageEmpty#211a1788 flags:# id:long url:flags.0?string = WebPage; -webPagePending#b0d13e47 flags:# id:long url:flags.0?string date:int = WebPage; -webPage#e89c45b2 flags:# has_large_media:flags.13?true video_cover_photo:flags.14?true id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector = WebPage; -webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; - -authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; - -account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector = account.Authorizations; - -account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password; - -account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; - -account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; - -auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; - -receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; - -chatInviteExported#a22cbd96 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int subscription_expired:flags.10?int title:flags.8?string subscription_pricing:flags.9?StarsSubscriptionPricing = ExportedChatInvite; -chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite; - -chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#5c9d3702 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true can_refulfill_subscription:flags.11?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector color:int subscription_pricing:flags.10?StarsSubscriptionPricing subscription_form_id:flags.12?long bot_verification:flags.13?BotVerification = ChatInvite; -chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; - -inputStickerSetEmpty#ffb62b95 = InputStickerSet; -inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; -inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; -inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; -inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; -inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet; -inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet; -inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; -inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; -inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet; -inputStickerSetTonGifts#1cf671a0 = InputStickerSet; - -stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; - -messages.stickerSet#6e153f16 set:StickerSet packs:Vector keywords:Vector documents:Vector = messages.StickerSet; -messages.stickerSetNotModified#d3f924eb = messages.StickerSet; - -botCommand#c27ac8c7 command:string description:string = BotCommand; - -botInfo#4d8a0299 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton privacy_policy_url:flags.7?string app_settings:flags.8?BotAppSettings verifier_settings:flags.9?BotVerifierSettings = BotInfo; - -keyboardButton#a2fa4880 text:string = KeyboardButton; -keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; -keyboardButtonCallback#35bbdb6b flags:# requires_password:flags.0?true text:string data:bytes = KeyboardButton; -keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; -keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; -keyboardButtonSwitchInline#93b9fbb5 flags:# same_peer:flags.0?true text:string query:string peer_types:flags.1?Vector = KeyboardButton; -keyboardButtonGame#50f41ccf text:string = KeyboardButton; -keyboardButtonBuy#afd93fbb text:string = KeyboardButton; -keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; -inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; -keyboardButtonRequestPoll#bbc7515d flags:# quiz:flags.0?Bool text:string = KeyboardButton; -inputKeyboardButtonUserProfile#e988037b text:string user_id:InputUser = KeyboardButton; -keyboardButtonUserProfile#308660c1 text:string user_id:long = KeyboardButton; -keyboardButtonWebView#13767230 text:string url:string = KeyboardButton; -keyboardButtonSimpleWebView#a0c0505c text:string url:string = KeyboardButton; -keyboardButtonRequestPeer#53d7bfd8 text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -inputKeyboardButtonRequestPeer#c9662d05 flags:# name_requested:flags.0?true username_requested:flags.1?true photo_requested:flags.2?true text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -keyboardButtonCopy#75d2698e text:string copy_text:string = KeyboardButton; - -keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; - -replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; -replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup; -replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector placeholder:flags.3?string = ReplyMarkup; -replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; - -messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; -messageEntityMention#fa04579d offset:int length:int = MessageEntity; -messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; -messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; -messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; -messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; -messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; -messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; -messageEntityCode#28a20571 offset:int length:int = MessageEntity; -messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; -messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; -messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity; -inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; -messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; -messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; -messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity; -messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; -messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; -messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; -messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; -messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity; - -inputChannelEmpty#ee8c1e86 = InputChannel; -inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; -inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel; - -contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; - -messageRange#ae30253 min_id:int max_id:int = MessageRange; - -updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; -updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; -updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; - -channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; -channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; - -channelParticipant#cb397619 flags:# user_id:long date:int subscription_until_date:flags.0?int = ChannelParticipant; -channelParticipantSelf#4f607bef flags:# via_request:flags.0?true user_id:long inviter_id:long date:int subscription_until_date:flags.1?int = ChannelParticipant; -channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; -channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; -channelParticipantBanned#6df8014e flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights = ChannelParticipant; -channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; - -channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; -channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; -channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; -channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; -channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; -channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; -channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; -channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; - -channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; -channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; - -channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; - -help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; - -messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; -messages.savedGifs#84a02a0d hash:long gifs:Vector = messages.SavedGifs; - -inputBotInlineMessageMediaAuto#3380c786 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaWebPage#bddcc510 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true optional:flags.6?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; - -botInlineMessageMediaAuto#764cf810 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; -botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; - -messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector cache_time:int users:Vector = messages.BotResults; - -exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; - -messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader; - -auth.codeTypeSms#72a3158c = auth.CodeType; -auth.codeTypeCall#741cd3e3 = auth.CodeType; -auth.codeTypeFlashCall#226ccefb = auth.CodeType; -auth.codeTypeMissedCall#d61ad6ee = auth.CodeType; -auth.codeTypeFragmentSms#6ed998c = auth.CodeType; - -auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; -auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; -auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; -auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType; -auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; -auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; -auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; -auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; -auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; -auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; - -messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; - -messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; - -inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; -inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID; - -inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; - -messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; - -topPeer#edcdc05b peer:Peer rating:double = TopPeer; - -topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; -topPeerCategoryBotsInline#148677e2 = TopPeerCategory; -topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; -topPeerCategoryGroups#bd17a14a = TopPeerCategory; -topPeerCategoryChannels#161d9628 = TopPeerCategory; -topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; -topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; -topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; -topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory; - -topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; - -contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; -contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; -contacts.topPeersDisabled#b52c939d = contacts.TopPeers; - -draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; -draftMessage#96eaa5eb flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost = DraftMessage; - -messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; -messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; - -messages.recentStickersNotModified#b17f890 = messages.RecentStickers; -messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; - -messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; - -messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; -messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; - -stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; -stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; -stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector keywords:Vector documents:Vector = StickerSetCovered; -stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered; - -maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; - -inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; -inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; - -game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; - -inputGameID#32c3e77 id:long access_hash:long = InputGame; -inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; - -highScore#73a379eb pos:int user_id:long score:int = HighScore; - -messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; - -textEmpty#dc3d824f = RichText; -textPlain#744694e0 text:string = RichText; -textBold#6724abc4 text:RichText = RichText; -textItalic#d912a59c text:RichText = RichText; -textUnderline#c12622c4 text:RichText = RichText; -textStrike#9bf8bb95 text:RichText = RichText; -textFixed#6c3f19b9 text:RichText = RichText; -textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; -textEmail#de5a0dd6 text:RichText email:string = RichText; -textConcat#7e6260d7 texts:Vector = RichText; -textSubscript#ed6a8504 text:RichText = RichText; -textSuperscript#c7fb5e01 text:RichText = RichText; -textMarked#34b8621 text:RichText = RichText; -textPhone#1ccb966a text:RichText phone:string = RichText; -textImage#81ccf4f document_id:long w:int h:int = RichText; -textAnchor#35553762 text:RichText name:string = RichText; - -pageBlockUnsupported#13567e8a = PageBlock; -pageBlockTitle#70abc3fd text:RichText = PageBlock; -pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; -pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; -pageBlockHeader#bfd064ec text:RichText = PageBlock; -pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; -pageBlockParagraph#467a0766 text:RichText = PageBlock; -pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; -pageBlockFooter#48870999 text:RichText = PageBlock; -pageBlockDivider#db20b188 = PageBlock; -pageBlockAnchor#ce0d37b0 name:string = PageBlock; -pageBlockList#e4e88011 items:Vector = PageBlock; -pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; -pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; -pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; -pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; -pageBlockCover#39f23300 cover:PageBlock = PageBlock; -pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; -pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; -pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; -pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; -pageBlockChannel#ef1751b5 channel:Chat = PageBlock; -pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; -pageBlockKicker#1e148390 text:RichText = PageBlock; -pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; -pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; -pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; -pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; -pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; - -phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; -phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; -phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; -phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; -phoneCallDiscardReasonMigrateConferenceCall#9fbbf1f7 slug:string = PhoneCallDiscardReason; - -dataJSON#7d748d04 data:string = DataJSON; - -labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; - -invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector terms_url:flags.10?string subscription_period:flags.11?int = Invoice; - -paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; - -postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; - -paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; - -paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; - -webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; -webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; - -inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; - -inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; -inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; -inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation; - -upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; - -payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector users:Vector = payments.PaymentForm; -payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector = payments.PaymentForm; -payments.paymentFormStarGift#b425cfe1 form_id:long invoice:Invoice = payments.PaymentForm; - -payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; - -payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; -payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; - -payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; -payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector = payments.PaymentReceipt; - -payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; - -inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; -inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials; - -account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; - -shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; - -inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem; - -inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; - -phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#30535af5 flags:# p2p_allowed:flags.5?true video:flags.6?true conference_supported:flags.8?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int custom_parameters:flags.7?DataJSON = PhoneCall; -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; - -phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; -phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection; - -phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector = PhoneCallProtocol; - -phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; - -upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; -upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; - -cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; - -cdnConfig#5725e40a public_keys:Vector = CdnConfig; - -langPackString#cad181f6 key:string value:string = LangPackString; -langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; -langPackStringDeleted#2979eeb2 key:string = LangPackString; - -langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; - -langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; - -channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; -channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector new_value:Vector = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAutotranslation#c517f77e new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; - -channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; - -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true = ChannelAdminLogEventsFilter; - -popularContact#5ce14175 client_id:long importers:int = PopularContact; - -messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; -messages.favedStickers#2cb51097 hash:long packs:Vector stickers:Vector = messages.FavedStickers; - -recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; -recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl; -recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl; -recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; -recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; - -help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; - -inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; - -webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; - -account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; - -inputMessageID#a676a322 id:int = InputMessage; -inputMessageReplyTo#bad88395 id:int = InputMessage; -inputMessagePinned#86872538 = InputMessage; -inputMessageCallbackQuery#acfa1a7e id:int query_id:long = InputMessage; - -inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; -inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; - -dialogPeer#e56dbf05 peer:Peer = DialogPeer; -dialogPeerFolder#514519e2 folder_id:int = DialogPeer; - -messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; -messages.foundStickerSets#8af09dd2 hash:long sets:Vector = messages.FoundStickerSets; - -fileHash#f39b035c offset:long limit:int hash:bytes = FileHash; - -inputClientProxy#75588b3f address:string port:int = InputClientProxy; - -help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; -help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; - -inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; -inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; - -secureFileEmpty#64199744 = SecureFile; -secureFile#7d09c27e id:long access_hash:long size:long dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; - -secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; - -securePlainPhone#7d6099dd phone:string = SecurePlainData; -securePlainEmail#21ec5a5f email:string = SecurePlainData; - -secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; -secureValueTypePassport#3dac6a00 = SecureValueType; -secureValueTypeDriverLicense#6e425c4 = SecureValueType; -secureValueTypeIdentityCard#a0d0744b = SecureValueType; -secureValueTypeInternalPassport#99a48f23 = SecureValueType; -secureValueTypeAddress#cbe31e26 = SecureValueType; -secureValueTypeUtilityBill#fc36954e = SecureValueType; -secureValueTypeBankStatement#89137c0d = SecureValueType; -secureValueTypeRentalAgreement#8b883488 = SecureValueType; -secureValueTypePassportRegistration#99e3806a = SecureValueType; -secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; -secureValueTypePhone#b320aadb = SecureValueType; -secureValueTypeEmail#8e3ca7ee = SecureValueType; - -secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; - -inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; - -secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; - -secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; -secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; -secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; - -secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; - -account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; - -account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; - -help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; -help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; - -savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; - -account.takeout#4dba4501 id:long = account.Takeout; - -passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; -passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; - -securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; -securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; -securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; - -secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; - -inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; -inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; - -secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; -secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; - -help.passportConfigNotModified#bfb9f457 = help.PassportConfig; -help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; - -inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; - -jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; - -jsonNull#3f6d7b68 = JSONValue; -jsonBool#c7345e6a value:Bool = JSONValue; -jsonNumber#2be0dfa4 value:double = JSONValue; -jsonString#b71e767a value:string = JSONValue; -jsonArray#f7444763 value:Vector = JSONValue; -jsonObject#99c1d49d value:Vector = JSONValue; - -pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; - -pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; - -pageCaption#6f747657 text:RichText credit:RichText = PageCaption; - -pageListItemText#b92fb6cd text:RichText = PageListItem; -pageListItemBlocks#25e073fc blocks:Vector = PageListItem; - -pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; -pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; - -pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; - -page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector views:flags.3?int = Page; - -help.supportName#8c05f1c9 name:string = help.SupportName; - -help.userInfoEmpty#f3ae2eed = help.UserInfo; -help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; - -pollAnswer#ff16e2ca text:TextWithEntities option:bytes = PollAnswer; - -poll#58747131 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:TextWithEntities answers:Vector close_period:flags.4?int close_date:flags.5?int = Poll; - -pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters; - -pollResults#7adf2420 flags:# min:flags.0?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector = PollResults; - -chatOnlines#f041e250 onlines:int = ChatOnlines; - -statsURL#47a971e0 url:string = StatsURL; - -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true = ChatAdminRights; - -chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true until_date:int = ChatBannedRights; - -inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; -inputWallPaperSlug#72091c80 slug:string = InputWallPaper; -inputWallPaperNoFile#967a462e id:long = InputWallPaper; - -account.wallPapersNotModified#1c199183 = account.WallPapers; -account.wallPapers#cdc3858c hash:long wallpapers:Vector = account.WallPapers; - -codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true unknown_number:flags.9?true logout_tokens:flags.6?Vector token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings; - -wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings; - -autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings; - -account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; - -emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector = EmojiKeyword; -emojiKeywordDeleted#236df622 keyword:string emoticons:Vector = EmojiKeyword; - -emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector = EmojiKeywordsDifference; - -emojiURL#a575739d url:string = EmojiURL; - -emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; - -folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; - -inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; - -folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; - -messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; - -urlAuthResultRequest#92d33a0e flags:# request_write_access:flags.0?true bot:User domain:string = UrlAuthResult; -urlAuthResultAccepted#8f8c0e4e url:string = UrlAuthResult; -urlAuthResultDefault#a9d6db1f = UrlAuthResult; - -channelLocationEmpty#bfb5ad8b = ChannelLocation; -channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation; - -peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated; -peerSelfLocated#f8ec284b expires:int = PeerLocated; - -restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason; - -inputTheme#3c5693e9 id:long access_hash:long = InputTheme; -inputThemeSlug#f5890df1 slug:string = InputTheme; - -theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector emoticon:flags.6?string installs_count:flags.4?int = Theme; - -account.themesNotModified#f41eb622 = account.Themes; -account.themes#9a3d8c6d hash:long themes:Vector = account.Themes; - -auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken; -auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken; -auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken; - -account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings; - -messages.inactiveChats#a927fec5 dates:Vector chats:Vector users:Vector = messages.InactiveChats; - -baseThemeClassic#c3a12462 = BaseTheme; -baseThemeDay#fbd81688 = BaseTheme; -baseThemeNight#b7b31ea8 = BaseTheme; -baseThemeTinted#6d5f77ee = BaseTheme; -baseThemeArctic#5b11125a = BaseTheme; - -inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; - -themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; - -webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; -webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; -webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; -webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; -webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; -webPageAttributeStarGiftAuction#1c641c2 gift:StarGift end_date:int = WebPageAttribute; - -messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; - -bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl; - -payments.bankCardData#3e24e573 title:string open_urls:Vector = payments.BankCardData; - -dialogFilter#aa472651 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector exclude_peers:Vector = DialogFilter; -dialogFilterDefault#363293ae = DialogFilter; -dialogFilterChatlist#96537bd7 flags:# has_my_invites:flags.26?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector = DialogFilter; - -dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested; - -statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays; - -statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev; - -statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue; - -statsGraphAsync#4a27eb2d token:string = StatsGraph; -statsGraphError#bedc9822 error:string = StatsGraph; -statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph; - -stats.broadcastStats#396ca5fc period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev reactions_per_post:StatsAbsValueAndPrev views_per_story:StatsAbsValueAndPrev shares_per_story:StatsAbsValueAndPrev reactions_per_story:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_posts_interactions:Vector = stats.BroadcastStats; - -help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; -help.promoData#8a4d87a flags:# proxy:flags.0?true expires:int peer:flags.3?Peer psa_type:flags.1?string psa_message:flags.2?string pending_suggestions:Vector dismissed_suggestions:Vector custom_pending_suggestion:flags.4?PendingSuggestion chats:Vector users:Vector = help.PromoData; - -videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; -videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector = VideoSize; -videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector = VideoSize; - -statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster; - -statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; - -statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; - -stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; - -globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; - -help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; - -help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector = help.Country; - -help.countriesListNotModified#93cc1f32 = help.CountriesList; -help.countriesList#87d0759e countries:Vector hash:int = help.CountriesList; - -messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews; - -messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; - -messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; - -messageReplyHeader#6917560b flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector quote_offset:flags.10?int todo_item_id:flags.11?int = MessageReplyHeader; -messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader; - -messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; - -peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; - -stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; - -groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall; - -inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -inputGroupCallSlug#fe06823f slug:string = InputGroupCall; -inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall; - -groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant; - -phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; - -phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; - -inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; -inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; -inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType; -inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType; -inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType; -inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType; - -messages.historyImport#1662af0b id:long = messages.HistoryImport; - -messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed; - -messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector = messages.AffectedFoundMessages; - -chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter; - -messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; - -messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; -messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; - -messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; - -chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites; - -messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; - -messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; - -phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; - -phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; - -groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector = GroupCallParticipantVideoSourceGroup; - -groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector audio_source:flags.1?int = GroupCallParticipantVideo; - -stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName; - -botCommandScopeDefault#2f6cb2ab = BotCommandScope; -botCommandScopeUsers#3c4f04d8 = BotCommandScope; -botCommandScopeChats#6fe1a881 = BotCommandScope; -botCommandScopeChatAdmins#b9aa606a = BotCommandScope; -botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope; -botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope; -botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope; - -account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult; -account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; -account.resetPasswordOk#e926d63e = account.ResetPasswordResult; - -chatTheme#c3dffc04 emoticon:string = ChatTheme; -chatThemeUniqueGift#3458f9c8 gift:StarGift theme_settings:Vector = ChatTheme; - -account.chatThemesNotModified#e011e1c4 = account.ChatThemes; -account.chatThemes#be098173 flags:# hash:long themes:Vector chats:Vector users:Vector next_offset:flags.0?string = account.ChatThemes; - -sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage; - -messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; -messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; - -searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; - -messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector messages:Vector chats:Vector users:Vector = messages.SearchResultsCalendar; - -searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition; - -messages.searchResultsPositions#53b22baf count:int positions:Vector = messages.SearchResultsPositions; - -channels.sendAsPeers#f496b0c6 peers:Vector chats:Vector users:Vector = channels.SendAsPeers; - -users.userFull#3b6d152e full_user:UserFull chats:Vector users:Vector = users.UserFull; - -messages.peerSettings#6880b94d settings:PeerSettings chats:Vector users:Vector = messages.PeerSettings; - -auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut; - -reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; - -messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector recent_reactions:flags.1?Vector top_reactors:flags.4?Vector = MessageReactions; - -messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.MessageReactionsList; - -availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; - -messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions; -messages.availableReactions#768e3aad hash:int reactions:Vector = messages.AvailableReactions; - -messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true my:flags.2?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction; - -groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel; - -phone.groupCallStreamChannels#d0e482b2 channels:Vector = phone.GroupCallStreamChannels; - -phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl; - -attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; - -attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector = AttachMenuBotIcon; - -attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector icons:Vector = AttachMenuBot; - -attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; -attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector = AttachMenuBots; - -attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector = AttachMenuBotsBot; - -webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true fullscreen:flags.2?true query_id:flags.0?long url:string = WebViewResult; - -webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent; - -botMenuButtonDefault#7533a588 = BotMenuButton; -botMenuButtonCommands#4258c205 = BotMenuButton; -botMenuButton#c7b57ce6 text:string url:string = BotMenuButton; - -account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones; -account.savedRingtones#c1e92cc5 hash:long ringtones:Vector = account.SavedRingtones; - -notificationSoundDefault#97e8bebe = NotificationSound; -notificationSoundNone#6f0c34df = NotificationSound; -notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound; -notificationSoundRingtone#ff6c8049 id:long = NotificationSound; - -account.savedRingtone#b7263f6d = account.SavedRingtone; -account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone; - -attachMenuPeerTypeSameBotPM#7d6be90e = AttachMenuPeerType; -attachMenuPeerTypeBotPM#c32bfa1a = AttachMenuPeerType; -attachMenuPeerTypePM#f146d31f = AttachMenuPeerType; -attachMenuPeerTypeChat#509113f = AttachMenuPeerType; -attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; - -inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; -inputInvoiceSlug#c326caef slug:string = InputInvoice; -inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; -inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice; -inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice; -inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; -inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; -inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; -inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; -inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice; -inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice; - -payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; - -messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; - -help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; - -inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose; -inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentPremiumGiftCode#fb790393 flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long message:flags.1?TextWithEntities = InputStorePaymentPurpose; -inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsTopup#f9a2a6cb flags:# stars:long currency:string amount:long spend_purpose_peer:flags.0?InputPeer = InputStorePaymentPurpose; -inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; -inputStorePaymentAuthCode#9bb2636d flags:# restore:flags.0?true phone_number:string phone_code_hash:string currency:string amount:long = InputStorePaymentPurpose; - -paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; - -emojiStatusEmpty#2de11aae = EmojiStatus; -emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus; -emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus; -inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus; - -account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses; -account.emojiStatuses#90c467d1 hash:long statuses:Vector = account.EmojiStatuses; - -reactionEmpty#79f5d419 = Reaction; -reactionEmoji#1b2286b8 emoticon:string = Reaction; -reactionCustomEmoji#8935fc73 document_id:long = Reaction; -reactionPaid#523da4eb = Reaction; - -chatReactionsNone#eafc32bc = ChatReactions; -chatReactionsAll#52928bca flags:# allow_custom:flags.0?true = ChatReactions; -chatReactionsSome#661d4037 reactions:Vector = ChatReactions; - -messages.reactionsNotModified#b06fdbdf = messages.Reactions; -messages.reactions#eafdf716 hash:long reactions:Vector = messages.Reactions; - -emailVerifyPurposeLoginSetup#4345be73 phone_number:string phone_code_hash:string = EmailVerifyPurpose; -emailVerifyPurposeLoginChange#527d22eb = EmailVerifyPurpose; -emailVerifyPurposePassport#bbf51685 = EmailVerifyPurpose; - -emailVerificationCode#922e55a9 code:string = EmailVerification; -emailVerificationGoogle#db909ec2 token:string = EmailVerification; -emailVerificationApple#96d074fd token:string = EmailVerification; - -account.emailVerified#2b96cd1b email:string = account.EmailVerified; -account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified; - -premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption; - -sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer; - -messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia; -messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia; - -stickerKeyword#fcfeb29c document_id:long keyword:Vector = StickerKeyword; - -username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username; - -forumTopicDeleted#23f109b id:int = ForumTopic; -forumTopic#cdff0eca flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true title_missing:flags.7?true id:int date:int peer:Peer title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic; - -messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector messages:Vector chats:Vector users:Vector pts:int = messages.ForumTopics; - -defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL; - -exportedContactToken#41bf109b url:string expires:int = ExportedContactToken; - -requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType; -requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; - -emojiListNotModified#481eadfa = EmojiList; -emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; - -emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; - -messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; -messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; - -textWithEntities#751f3146 text:string entities:Vector = TextWithEntities; - -messages.translateResult#33db32f8 result:Vector = messages.TranslatedText; - -autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings; - -autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException; - -account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector chats:Vector users:Vector = account.AutoSaveSettings; - -help.appConfigNotModified#7cde641d = help.AppConfig; -help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig; - -inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp; -inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp; - -botAppNotModified#5da674b7 = BotApp; -botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; - -messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp; - -inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; - -readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; - -inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist; - -exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector = ExportedChatlistInvite; - -chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite; - -chatlists.exportedInvites#10ab6dc7 invites:Vector chats:Vector users:Vector = chatlists.ExportedInvites; - -chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector already_peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; -chatlists.chatlistInvite#f10ece2f flags:# title_noanimate:flags.1?true title:TextWithEntities emoticon:flags.0?string peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; - -chatlists.chatlistUpdates#93bd878d missing_peers:Vector chats:Vector users:Vector = chatlists.ChatlistUpdates; - -bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo; - -messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote; -messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote; -messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector date:int = MessagePeerVote; - -storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector reactions_count:flags.4?int recent_viewers:flags.0?Vector = StoryViews; - -storyItemDeleted#51e6ee4f id:int = StoryItem; -storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true live:flags.9?true id:int date:int expire_date:int = StoryItem; -storyItem#edf164f1 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector = StoryItem; - -stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; -stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; - -stories.stories#63c3dd0a flags:# count:int stories:Vector pinned_to_top:flags.0?Vector chats:Vector users:Vector = stories.Stories; - -storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView; -storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView; -storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView; - -stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryViewsList; - -stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; - -inputReplyToMessage#869fbe10 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int = InputReplyTo; -inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; -inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; - -exportedStoryLink#3fc9053b link:string = ExportedStoryLink; - -storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; - -mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates; - -mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea; -inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea; -mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea; -mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea; -mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; -inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; -mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; -mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea; -mediaAreaStarGift#5787686d coordinates:MediaAreaCoordinates slug:string = MediaArea; - -peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; - -stories.peerStories#cae68768 stories:PeerStories chats:Vector users:Vector = stories.PeerStories; - -messages.webPage#fd5e12bd webpage:WebPage chats:Vector users:Vector = messages.WebPage; - -premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption; - -payments.checkedGiftCode#eb983f8f flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int days:int used_date:flags.1?int chats:Vector users:Vector = payments.CheckedGiftCode; - -payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; -payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo; - -prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; -prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway; - -boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost; - -premium.boostsList#86f8613c flags:# count:int boosts:Vector next_offset:flags.0?string users:Vector = premium.BoostsList; - -myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost; - -premium.myBoosts#9ae228e2 my_boosts:Vector chats:Vector users:Vector = premium.MyBoosts; - -premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector my_boost_slots:flags.2?Vector = premium.BoostsStatus; - -storyFwdHeader#b826e150 flags:# modified:flags.3?true from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader; - -postInteractionCountersMessage#e7058e7f msg_id:int views:int forwards:int reactions:int = PostInteractionCounters; -postInteractionCountersStory#8a480e27 story_id:int views:int forwards:int reactions:int = PostInteractionCounters; - -stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats; - -publicForwardMessage#1f2bf4a message:Message = PublicForward; -publicForwardStory#edf3add0 peer:Peer story:StoryItem = PublicForward; - -stats.publicForwards#93037e20 flags:# count:int forwards:Vector next_offset:flags.0?string chats:Vector users:Vector = stats.PublicForwards; - -peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor; -peerColorCollectible#b9c0639a flags:# collectible_id:long gift_emoji_id:long background_emoji_id:long accent_color:int colors:Vector dark_accent_color:flags.0?int dark_colors:flags.1?Vector = PeerColor; -inputPeerColorCollectible#b8ea86a9 collectible_id:long = PeerColor; - -help.peerColorSet#26219a58 colors:Vector = help.PeerColorSet; -help.peerColorProfileSet#767d61eb palette_colors:Vector bg_colors:Vector story_colors:Vector = help.PeerColorSet; - -help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption; - -help.peerColorsNotModified#2ba1f5ce = help.PeerColors; -help.peerColors#f8ed08 hash:int colors:Vector = help.PeerColors; - -storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction; -storyReactionPublicForward#bbab2643 message:Message = StoryReaction; -storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; - -stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; - -savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; -monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; - -messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; - -savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; - -messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; -messages.savedReactionTags#3259950a tags:Vector hash:long = messages.SavedReactionTags; - -outboxReadDate#3bb842ac date:int = OutboxReadDate; - -smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin; - -smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status; - -smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob; - -businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen; - -businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector = BusinessWorkHours; - -businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation; - -inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = InputBusinessRecipients; - -businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = BusinessRecipients; - -businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule; - -inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage; - -businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage; - -inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage; - -businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage; - -timezone#ff9289f5 id:string name:string utc_offset:int = Timezone; - -help.timezonesListNotModified#970708cc = help.TimezonesList; -help.timezonesList#7b74ed71 timezones:Vector hash:int = help.TimezonesList; - -quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply; - -inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut; -inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; - -messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; -messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; - -connectedBot#cd64636c flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights = ConnectedBot; - -account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; - -messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector = messages.DialogFilters; - -birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; - -botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; - -inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; - -businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro; - -messages.myStickers#faff629d count:int sets:Vector = messages.MyStickers; - -inputCollectibleUsername#e39460a9 username:string = InputCollectible; -inputCollectiblePhone#a2e214a4 phone:string = InputCollectible; - -fragment.collectibleInfo#6ebdff91 purchase_date:int currency:string amount:long crypto_currency:string crypto_amount:long url:string = fragment.CollectibleInfo; - -inputBusinessBotRecipients#c4e5921e flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = InputBusinessBotRecipients; - -businessBotRecipients#b88cf373 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = BusinessBotRecipients; - -contactBirthday#1d998733 contact_id:long birthday:Birthday = ContactBirthday; - -contacts.contactBirthdays#114ff30d contacts:Vector users:Vector = contacts.ContactBirthdays; - -missingInvitee#628c9224 flags:# premium_would_allow_invite:flags.0?true premium_required_for_pm:flags.1?true user_id:long = MissingInvitee; - -messages.invitedUsers#7f5defa6 updates:Updates missing_invitees:Vector = messages.InvitedUsers; - -inputBusinessChatLink#11679fa7 flags:# message:string entities:flags.0?Vector title:flags.1?string = InputBusinessChatLink; - -businessChatLink#b4ae666f flags:# link:string message:string entities:flags.0?Vector title:flags.1?string views:int = BusinessChatLink; - -account.businessChatLinks#ec43a2d1 links:Vector chats:Vector users:Vector = account.BusinessChatLinks; - -account.resolvedBusinessChatLinks#9a23af21 flags:# peer:Peer message:string entities:flags.0?Vector chats:Vector users:Vector = account.ResolvedBusinessChatLinks; - -requestedPeerUser#d62ff46a flags:# user_id:long first_name:flags.0?string last_name:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChat#7307544f flags:# chat_id:long title:flags.0?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChannel#8ba403e4 flags:# channel_id:long title:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; - -sponsoredMessageReportOption#430d3150 text:string option:bytes = SponsoredMessageReportOption; - -channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:Vector = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; - -reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; -reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; - -reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; - -availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; - -messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; -messages.availableEffects#bddb616e hash:int effects:Vector documents:Vector = messages.AvailableEffects; - -factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck; - -starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer; -starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer; -starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; -starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; -starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; -starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; -starsTransactionPeerAds#60682812 = StarsTransactionPeer; -starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; - -starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; - -starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true posts_search:flags.24?true stargift_prepaid_upgrade:flags.25?true stargift_drop_original_details:flags.26?true phonegroup_message:flags.27?true stargift_auction_bid:flags.28?true offer:flags.29?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction; - -payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; - -foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; - -stories.foundStories#e2de7737 flags:# count:int stories:Vector next_offset:flags.0?string chats:Vector users:Vector = stories.FoundStories; - -geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; - -starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; - -payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; - -payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; - -payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl; - -inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; - -starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption; - -bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector = bots.PopularAppBots; - -botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia; - -bots.previewInfo#ca71d64 media:Vector lang_codes:Vector = bots.PreviewInfo; - -starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing; - -starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true bot_canceled:flags.7?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string title:flags.4?string photo:flags.5?WebDocument invoice_slug:flags.6?string = StarsSubscription; - -messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; - -starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; - -starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; - -starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift; -starGiftUnique#569d64c9 flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int = StarGift; - -payments.starGiftsNotModified#a388a368 = payments.StarGifts; -payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; - -messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; - -reportResultChooseOption#f0e4e0b6 title:string options:Vector = ReportResult; -reportResultAddComment#6f09ac31 flags:# optional:flags.0?true option:bytes = ReportResult; -reportResultReported#8db33c4b = ReportResult; - -messages.botPreparedInlineMessage#8ecf0511 id:string expire_date:int = messages.BotPreparedInlineMessage; - -messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult peer_types:Vector cache_time:int users:Vector = messages.PreparedInlineMessage; - -botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings; - -starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram; - -connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef; - -payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector = payments.ConnectedStarRefBots; - -payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; - -starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount; -starsTonAmount#74aee3e0 amount:long = StarsAmount; - -messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers; -messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector = messages.FoundStickers; - -botVerifierSettings#b0cd6617 flags:# can_modify_custom_description:flags.1?true icon:long company:string custom_description:flags.0?string = BotVerifierSettings; - -botVerification#f93cd45c bot_id:long icon:long description:string = BotVerification; - -starGiftAttributeModel#39d99013 name:string document:Document rarity_permille:int = StarGiftAttribute; -starGiftAttributePattern#13acff19 name:string document:Document rarity_permille:int = StarGiftAttribute; -starGiftAttributeBackdrop#d93d859c name:string backdrop_id:int center_color:int edge_color:int pattern_color:int text_color:int rarity_permille:int = StarGiftAttribute; -starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute; - -payments.starGiftUpgradePreview#3de1dfed sample_attributes:Vector prices:Vector next_prices:Vector = payments.StarGiftUpgradePreview; - -users.users#62d706b8 users:Vector = users.Users; -users.usersSlice#315a4974 count:int users:Vector = users.Users; - -payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector users:Vector = payments.UniqueStarGift; - -messages.webPagePreview#8c9a88ac media:MessageMedia chats:Vector users:Vector = messages.WebPagePreview; - -savedStarGift#ead6805e flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int = SavedStarGift; - -payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; - -inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift; -inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift; -inputSavedStarGiftSlug#2085c238 slug:string = InputSavedStarGift; - -payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl; - -paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy; -paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy; -paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy; - -account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRevenue; - -requirementToContactEmpty#50a9839 = RequirementToContact; -requirementToContactPremium#e581e4e9 = RequirementToContact; -requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; - -businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; - -disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true disallow_stargifts_from_channels:flags.4?true = DisallowedGiftsSettings; - -sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; - -contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; -contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; - -starGiftAttributeIdModel#48aaae3c document_id:long = StarGiftAttributeId; -starGiftAttributeIdPattern#4a162433 document_id:long = StarGiftAttributeId; -starGiftAttributeIdBackdrop#1f01c757 backdrop_id:int = StarGiftAttributeId; - -starGiftAttributeCounter#2eb1b658 attribute:StarGiftAttributeId count:int = StarGiftAttributeCounter; - -payments.resaleStarGifts#947a12df flags:# count:int gifts:Vector next_offset:flags.0?string attributes:flags.1?Vector attributes_hash:flags.1?long chats:Vector counters:flags.2?Vector users:Vector = payments.ResaleStarGifts; - -stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount; - -pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion; - -todoItem#cba9a52f id:int title:TextWithEntities = TodoItem; - -todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector = TodoList; - -todoCompletion#221bb5e4 id:int completed_by:Peer date:int = TodoCompletion; - -suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost; - -starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating; - -starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection; - -payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; -payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; - -storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; - -stories.albumsNotModified#564edaeb = stories.Albums; -stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; - -searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; - -payments.uniqueStarGiftValueInfo#512fe446 flags:# last_sale_on_fragment:flags.1?true value_is_average:flags.6?true currency:string value:long initial_sale_date:int initial_sale_stars:long initial_sale_price:long last_sale_date:flags.0?int last_sale_price:flags.0?long floor_price:flags.2?long average_price:flags.3?long listed_count:flags.4?int fragment_listed_count:flags.5?int fragment_listed_url:flags.5?string = payments.UniqueStarGiftValueInfo; - -profileTabPosts#b98cd696 = ProfileTab; -profileTabGifts#4d4bd46a = ProfileTab; -profileTabMedia#72c64955 = ProfileTab; -profileTabFiles#ab339c00 = ProfileTab; -profileTabMusic#9f27d26e = ProfileTab; -profileTabVoice#e477092e = ProfileTab; -profileTabLinks#d3656499 = ProfileTab; -profileTabGifs#a2c0f695 = ProfileTab; - -users.savedMusicNotModified#e3878aa4 count:int = users.SavedMusic; -users.savedMusic#34a2f297 count:int documents:Vector = users.SavedMusic; - -account.savedMusicIdsNotModified#4fc81d6e = account.SavedMusicIds; -account.savedMusicIds#998d6636 ids:Vector = account.SavedMusicIds; - -payments.checkCanSendGiftResultOk#374fa7ad = payments.CheckCanSendGiftResult; -payments.checkCanSendGiftResultFail#d5e58274 reason:TextWithEntities = payments.CheckCanSendGiftResult; - -inputChatThemeEmpty#83268483 = InputChatTheme; -inputChatTheme#c93de95c emoticon:string = InputChatTheme; -inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme; - -starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice; - -groupCallMessage#1a8afc7e flags:# from_admin:flags.1?true id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage; - -groupCallDonor#ee430c85 flags:# top:flags.0?true my:flags.1?true peer_id:flags.3?Peer stars:long = GroupCallDonor; - -phone.groupCallStars#9d1dbd26 total_stars:long top_donors:Vector chats:Vector users:Vector = phone.GroupCallStars; - -recentStory#711d692d flags:# live:flags.0?true max_id:flags.1?int = RecentStory; - -auctionBidLevel#310240cc pos:int amount:long date:int = AuctionBidLevel; - -starGiftAuctionStateNotModified#fe333952 = StarGiftAuctionState; -starGiftAuctionState#771a4e66 version:int start_date:int end_date:int min_bid_amount:long bid_levels:Vector top_bidders:Vector next_round_at:int last_gift_num:int gifts_left:int current_round:int total_rounds:int rounds:Vector = StarGiftAuctionState; -starGiftAuctionStateFinished#972dabbf flags:# start_date:int end_date:int average_price:long listed_count:flags.0?int fragment_listed_count:flags.1?int fragment_listed_url:flags.1?string = StarGiftAuctionState; - -starGiftAuctionUserState#2eeed1c4 flags:# returned:flags.1?true bid_amount:flags.0?long bid_date:flags.0?int min_bid_amount:flags.0?long bid_peer:flags.0?Peer acquired_count:int = StarGiftAuctionUserState; - -payments.starGiftAuctionState#6b39f4ec gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState timeout:int users:Vector chats:Vector = payments.StarGiftAuctionState; - -starGiftAuctionAcquiredGift#42b00348 flags:# name_hidden:flags.0?true peer:Peer date:int bid_amount:long round:int pos:int message:flags.1?TextWithEntities gift_num:flags.2?int = StarGiftAuctionAcquiredGift; - -payments.starGiftAuctionAcquiredGifts#7d5bd1f0 gifts:Vector users:Vector chats:Vector = payments.StarGiftAuctionAcquiredGifts; - -starGiftActiveAuctionState#d31bc45d gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState = StarGiftActiveAuctionState; - -payments.starGiftActiveAuctionsNotModified#db33dad0 = payments.StarGiftActiveAuctions; -payments.starGiftActiveAuctions#aef6abbc auctions:Vector users:Vector chats:Vector = payments.StarGiftActiveAuctions; - -inputStarGiftAuction#2e16c98 gift_id:long = InputStarGiftAuction; -inputStarGiftAuctionSlug#7ab58308 slug:string = InputStarGiftAuction; - -passkey#98613ebf flags:# id:string name:string date:int software_emoji_id:flags.0?long last_usage_date:flags.1?int = Passkey; - -account.passkeys#f8e0aa1c passkeys:Vector = account.Passkeys; - -account.passkeyRegistrationOptions#e16b5ce1 options:DataJSON = account.PasskeyRegistrationOptions; - -auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions; - -inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse; -inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse; - -inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential; - -starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground; - -starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound; -starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound; - -payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector = payments.StarGiftUpgradeAttributes; - ----functions--- - -invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; -invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; -initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; -invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; -invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; -invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; -invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; -invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; -invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; -invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X; -invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X; - -auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; -auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; -auth.signIn#8d52a951 flags:# phone_number:string phone_code_hash:string phone_code:flags.0?string email_verification:flags.1?EmailVerification = auth.Authorization; -auth.logOut#3e72ba19 = auth.LoggedOut; -auth.resetAuthorizations#9fab0d1a = Bool; -auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; -auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; -auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; -auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; -auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; -auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; -auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; -auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode; -auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; -auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; -auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; -auth.acceptLoginToken#e894ad4d token:bytes = Authorization; -auth.checkRecoveryPassword#d36bf79 code:string = Bool; -auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; -auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool; -auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; -auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; -auth.checkPaidAuth#56e59f9c phone_number:string phone_code_hash:string form_id:long = auth.SentCode; -auth.initPasskeyLogin#518ad0b7 api_id:int api_hash:string = auth.PasskeyLoginOptions; -auth.finishPasskeyLogin#9857ad07 flags:# credential:InputPasskeyCredential from_dc_id:flags.0?int from_auth_key_id:flags.0?long = auth.Authorization; - -account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; -account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; -account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; -account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; -account.resetNotifySettings#db7e1747 = Bool; -account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; -account.updateStatus#6628562c offline:Bool = Bool; -account.getWallPapers#7967d36 hash:long = account.WallPapers; -account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool; -account.checkUsername#2714d86c username:string = Bool; -account.updateUsername#3e0bdd7c username:string = User; -account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; -account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; -account.deleteAccount#a2c0cf74 flags:# reason:string password:flags.0?InputCheckPasswordSRP = Bool; -account.getAccountTTL#8fc711d = AccountDaysTTL; -account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; -account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; -account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; -account.updateDeviceLocked#38df3532 period:int = Bool; -account.getAuthorizations#e320c158 = account.Authorizations; -account.resetAuthorization#df77f3bc hash:long = Bool; -account.getPassword#548a30f5 = account.Password; -account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; -account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; -account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; -account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; -account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; -account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; -account.resetWebAuthorization#2d01b9ef hash:long = Bool; -account.resetWebAuthorizations#682d2594 = Bool; -account.getAllSecureValues#b288bc7d = Vector; -account.getSecureValue#73665bc2 types:Vector = Vector; -account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; -account.deleteSecureValue#b880bc4b types:Vector = Bool; -account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm; -account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; -account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; -account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; -account.sendVerifyEmailCode#98e037bb purpose:EmailVerifyPurpose email:string = account.SentEmailCode; -account.verifyEmail#32da4cf purpose:EmailVerifyPurpose verification:EmailVerification = account.EmailVerified; -account.initTakeoutSession#8ef3eab0 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?long = account.Takeout; -account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; -account.confirmPasswordEmail#8fdf1920 code:string = Bool; -account.resendPasswordEmail#7a7f2a15 = Bool; -account.cancelPasswordEmail#c1cbd5b6 = Bool; -account.getContactSignUpNotification#9f07c728 = Bool; -account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; -account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true compare_stories:flags.2?true peer:flags.0?InputNotifyPeer = Updates; -account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; -account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; -account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; -account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; -account.resetWallPapers#bb3b9804 = Bool; -account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; -account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; -account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document; -account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool; -account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool; -account.getTheme#3a5869ec format:string theme:InputTheme = Theme; -account.getThemes#7206e458 format:string hash:long = account.Themes; -account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool; -account.getContentSettings#8b9b4dae = account.ContentSettings; -account.getMultiWallPapers#65ad71dc wallpapers:Vector = Vector; -account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings; -account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; -account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; -account.resetPassword#9308ce1b = account.ResetPasswordResult; -account.declinePasswordReset#4c9409f6 = Bool; -account.getChatThemes#d638de89 hash:long = account.Themes; -account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; -account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; -account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones; -account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone; -account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document; -account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool; -account.getDefaultEmojiStatuses#d6753386 hash:long = account.EmojiStatuses; -account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; -account.clearRecentEmojiStatuses#18201aae = Bool; -account.reorderUsernames#ef500eab order:Vector = Bool; -account.toggleUsername#58d6b376 username:string active:Bool = Bool; -account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList; -account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList; -account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings; -account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool; -account.deleteAutoSaveExceptions#53bc0020 = Bool; -account.invalidateSignInCodes#ca8ae8ba codes:Vector = Bool; -account.updateColor#684d214e flags:# for_profile:flags.1?true color:flags.2?PeerColor = Bool; -account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList; -account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses; -account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList; -account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool; -account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool; -account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool; -account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool; -account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates; -account.getConnectedBots#4ea4c80f = account.ConnectedBots; -account.getBotBusinessConnection#76a86270 connection_id:string = Updates; -account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool; -account.toggleConnectedBotPaused#646e1097 peer:InputPeer paused:Bool = Bool; -account.disablePeerConnectedBot#5e437ed9 peer:InputPeer = Bool; -account.updateBirthday#cc6e0c11 flags:# birthday:flags.0?Birthday = Bool; -account.createBusinessChatLink#8851e68e link:InputBusinessChatLink = BusinessChatLink; -account.editBusinessChatLink#8c3410af slug:string link:InputBusinessChatLink = BusinessChatLink; -account.deleteBusinessChatLink#60073674 slug:string = Bool; -account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks; -account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks; -account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool; -account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool; -account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings; -account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings; -account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses; -account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue; -account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool; -account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool; -account.saveMusic#b26732a9 flags:# unsave:flags.0?true id:InputDocument after_id:flags.1?InputDocument = Bool; -account.getSavedMusicIds#e09d5faf hash:long = account.SavedMusicIds; -account.getUniqueGiftChatThemes#e42ce9c9 offset:string limit:int hash:long = account.ChatThemes; -account.initPasskeyRegistration#429547e8 = account.PasskeyRegistrationOptions; -account.registerPasskey#55b41fd6 credential:InputPasskeyCredential = Passkey; -account.getPasskeys#ea1f0c52 = account.Passkeys; -account.deletePasskey#f5b5563f id:string = Bool; - -users.getUsers#d91a548 id:Vector = Vector; -users.getFullUser#b60f5918 id:InputUser = users.UserFull; -users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; -users.getRequirementsToContact#d89a83a3 id:Vector = Vector; -users.getSavedMusic#788d7fe3 id:InputUser offset:int limit:int hash:long = users.SavedMusic; -users.getSavedMusicByID#7573a4e9 id:InputUser documents:Vector = users.SavedMusic; -users.suggestBirthday#fc533372 id:InputUser birthday:Birthday = Updates; - -contacts.getContactIDs#7adc669d hash:long = Vector; -contacts.getStatuses#c4a353ee = Vector; -contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; -contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; -contacts.deleteContacts#96a0e00 id:Vector = Updates; -contacts.deleteByPhones#1013fd9e phones:Vector = Bool; -contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; -contacts.search#11f812d8 q:string limit:int = contacts.Found; -contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer; -contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true offset:int limit:int hash:long = contacts.TopPeers; -contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; -contacts.resetSaved#879537f1 = Bool; -contacts.getSaved#82f1e39f = Vector; -contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; -contacts.addContact#d9ba2e54 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string note:flags.1?TextWithEntities = Updates; -contacts.acceptContact#f831a20f id:InputUser = Updates; -contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates; -contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates; -contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer; -contacts.exportContactToken#f8654027 = ExportedContactToken; -contacts.importContactToken#13005788 token:string = User; -contacts.editCloseFriends#ba6705f0 id:Vector = Bool; -contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector limit:int = Bool; -contacts.getBirthdays#daeda864 = contacts.ContactBirthdays; -contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers; -contacts.updateContactNote#139f63fb id:InputUser note:TextWithEntities = Bool; - -messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; -messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; -messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; -messages.receivedMessages#5a954c0 max_id:int = Vector; -messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; -messages.sendMessage#545cd15a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.sendMedia#330e77f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.forwardMessages#13704a7c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; -messages.reportSpam#cf1592db peer:InputPeer = Bool; -messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; -messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; -messages.getChats#49e9528f id:Vector = messages.Chats; -messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; -messages.editChatTitle#73783ffd chat_id:long title:string = Updates; -messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates; -messages.addChatUser#cbc6d107 chat_id:long user_id:InputUser fwd_limit:int = messages.InvitedUsers; -messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates; -messages.createChat#92ceddd4 flags:# users:Vector title:string ttl_period:flags.0?int = messages.InvitedUsers; -messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; -messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; -messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; -messages.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool; -messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; -messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; -messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; -messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.receivedQueue#55a5bb66 max_qts:int = Vector; -messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; -messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; -messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers; -messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers; -messages.getWebPagePreview#570d6f6f flags:# message:string entities:flags.3?Vector = messages.WebPagePreview; -messages.exportChatInvite#a455de90 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string subscription_pricing:flags.5?StarsSubscriptionPricing = ExportedChatInvite; -messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; -messages.importChatInvite#6c50051c hash:string = Updates; -messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet; -messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; -messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; -messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; -messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool = messages.MessageViews; -messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; -messages.migrateChat#a2875319 chat_id:long = Updates; -messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true groups_only:flags.2?true users_only:flags.3?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; -messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Bool; -messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document; -messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; -messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; -messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; -messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool; -messages.sendInlineBotResult#c0cf7646 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut allow_paid_stars:flags.21?long = Updates; -messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; -messages.editMessage#51e842e1 flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.15?int schedule_repeat_period:flags.18?int quick_reply_shortcut_id:flags.17?int = Updates; -messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; -messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; -messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; -messages.saveDraft#54ae308e flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost = Bool; -messages.getAllDrafts#6a3f8d65 = Updates; -messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; -messages.readFeaturedStickers#5b118126 id:Vector = Bool; -messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; -messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; -messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; -messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers; -messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; -messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; -messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; -messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; -messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; -messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; -messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats; -messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage; -messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; -messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; -messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; -messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; -messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia; -messages.sendScreenshotNotification#a1405817 peer:InputPeer reply_to:InputReplyTo random_id:long = Updates; -messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers; -messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; -messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; -messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; -messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSplitRanges#1cff7e08 = Vector; -messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool; -messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector; -messages.clearAllDrafts#7e58ee9c = Bool; -messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates; -messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; -messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates; -messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; -messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; -messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; -messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; -messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; -messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; -messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; -messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector = Vector; -messages.requestUrlAuth#198fb446 flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; -messages.acceptUrlAuth#b12c7125 flags:# write_allowed:flags.0?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; -messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; -messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages; -messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; -messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector = Updates; -messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector = Updates; -messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList; -messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector = Bool; -messages.getDialogFilters#efd48c89 = messages.DialogFilters; -messages.getSuggestedDialogFilters#a29cd42c = Vector; -messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool; -messages.updateDialogFiltersOrder#c563c1e4 order:Vector = Bool; -messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers; -messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; -messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; -messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.deleteChat#5bd0ee50 chat_id:long = Bool; -messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; -messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; -messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport; -messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; -messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; -messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; -messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; -messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite; -messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; -messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; -messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; -messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true subscription_expired:flags.3?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; -messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; -messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; -messages.setChatTheme#81202c9 peer:InputPeer theme:InputChatTheme = Updates; -messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector; -messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; -messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; -messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; -messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; -messages.toggleNoForwards#b11eafa2 peer:InputPeer enabled:Bool = Updates; -messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; -messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector = Updates; -messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector = Updates; -messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList; -messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int paid_enabled:flags.1?Bool = Updates; -messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; -messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool; -messages.translateText#63183030 flags:# peer:flags.0?InputPeer id:flags.0?Vector text:flags.1?Vector to_lang:string = messages.TranslatedText; -messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages; -messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; -messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; -messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; -messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; -messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; -messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true fullscreen:flags.8?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; -messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; -messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; -messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool; -messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector = Vector; -messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers; -messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers; -messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer = Bool; -messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions; -messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions; -messages.clearRecentReactions#9dfeefb4 = Bool; -messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector = Updates; -messages.setDefaultHistoryTTL#9eb51445 period:int = Bool; -messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL; -messages.sendBotRequestedPeer#91b2d060 peer:InputPeer msg_id:int button_id:int requested_peers:Vector = Updates; -messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups; -messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups; -messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups; -messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; -messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; -messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; -messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; -messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; -messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; -messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; -messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; -messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags; -messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; -messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; -messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate; -messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies; -messages.reorderQuickReplies#60331907 order:Vector = Bool; -messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool; -messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool; -messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool; -messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector hash:long = messages.Messages; -messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vector random_id:Vector = Updates; -messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; -messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; -messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; -messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; -messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; -messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; -messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; -messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; -messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates; -messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool; -messages.getPaidReactionPrivacy#472455aa = Updates; -messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; -messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; -messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; -messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages; -messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; -messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; -messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; -messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; -messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; -messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; -messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; -messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; -messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates; -messages.getForumTopics#3ba47bff flags:# peer:InputPeer q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; -messages.getForumTopicsByID#af0a4a08 peer:InputPeer topics:Vector = messages.ForumTopics; -messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates; -messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates; -messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector = Updates; -messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; -messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory; - -updates.getState#edd4882a = updates.State; -updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; -updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; - -photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo; -photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo; -photos.deletePhotos#87cf7f2f id:Vector = Vector; -photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; -photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo; - -upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; -upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File; -upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; -upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; -upload.getCdnFile#395f69da file_token:bytes offset:long limit:int = upload.CdnFile; -upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; -upload.getCdnFileHashes#91dc3f31 file_token:bytes offset:long = Vector; -upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector; - -help.getConfig#c4f9186b = Config; -help.getNearestDc#1fb33026 = NearestDc; -help.getAppUpdate#522d5a7d source:string = help.AppUpdate; -help.getInviteText#4d392343 = help.InviteText; -help.getSupport#9cdf08cd = help.Support; -help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; -help.getCdnConfig#52029342 = CdnConfig; -help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; -help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; -help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; -help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; -help.getAppConfig#61e3f854 hash:int = help.AppConfig; -help.saveAppLog#6f02f748 events:Vector = Bool; -help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; -help.getSupportName#d360e72c = help.SupportName; -help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; -help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; -help.getPromoData#c0977421 = help.PromoData; -help.hidePromoData#1e251c95 peer:InputPeer = Bool; -help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; -help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; -help.getPremiumPromo#b81b93d4 = help.PremiumPromo; -help.getPeerColors#da80f42f hash:int = help.PeerColors; -help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors; -help.getTimezonesList#49b30240 hash:int = help.TimezonesList; - -channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; -channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; -channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector = Bool; -channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; -channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; -channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; -channels.getChannels#a7f6bbb id:Vector = messages.Chats; -channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; -channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates; -channels.editAdmin#d33c8902 channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:string = Updates; -channels.editTitle#566decd0 channel:InputChannel title:string = Updates; -channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; -channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; -channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; -channels.joinChannel#24b524c5 channel:InputChannel = Updates; -channels.leaveChannel#f836aa95 channel:InputChannel = Updates; -channels.inviteToChannel#c9e33d54 channel:InputChannel users:Vector = messages.InvitedUsers; -channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; -channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; -channels.toggleSignatures#418d549c flags:# signatures_enabled:flags.0?true profiles_enabled:flags.1?true channel:InputChannel = Updates; -channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_personal:flags.2?true = messages.Chats; -channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; -channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; -channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; -channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates; -channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; -channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; -channels.getGroupsForDiscussion#f5dad378 = messages.Chats; -channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; -channels.editCreator#8f38cd1f channel:InputChannel user_id:InputUser password:InputCheckPasswordSRP = Updates; -channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; -channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; -channels.getInactiveChannels#11e831ee = messages.InactiveChats; -channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; -channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true for_live_stories:flags.1?true peer:InputPeer = channels.SendAsPeers; -channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory; -channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates; -channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates; -channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector = Bool; -channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool; -channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool; -channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates; -channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates; -channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool; -channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; -channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates; -channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; -channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats; -channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates; -channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates; -channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; -channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; -channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; -channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; -channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; -channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood; -channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool; - -bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; -bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; -bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector = Bool; -bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool; -bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector; -bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool; -bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton; -bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool; -bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool; -bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool; -bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo; -bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector = Bool; -bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool; -bots.canSendMessage#1359f4e6 bot:InputUser = Bool; -bots.allowSendMessage#f132e3ef bot:InputUser = Updates; -bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; -bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; -bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia; -bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia; -bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector = Bool; -bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector = Bool; -bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo; -bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; -bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool; -bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; -bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; -bots.getAdminedBots#b0711d83 = Vector; -bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram; -bots.setCustomVerification#8b89dfbd flags:# enabled:flags.1?true bot:flags.0?InputUser peer:InputPeer custom_description:flags.2?string = Bool; -bots.getBotRecommendations#a1b70815 bot:InputUser = users.Users; - -payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; -payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; -payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; -payments.sendPaymentForm#2d03522f flags:# form_id:long invoice:InputInvoice requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; -payments.getSavedInfo#227d824b = payments.SavedInfo; -payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; -payments.getBankCardData#2e79d779 number:string = payments.BankCardData; -payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; -payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; -payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; -payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector; -payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; -payments.applyGiftCode#f6e26854 slug:string = Updates; -payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; -payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; -payments.getStarsTopupOptions#c00ec7d3 = Vector; -payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus; -payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; -payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult; -payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; -payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats; -payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; -payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; -payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector = payments.StarsStatus; -payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; -payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; -payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; -payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; -payments.getStarsGiveawayOptions#bd1efd3e = Vector; -payments.getStarGifts#c4563590 hash:int = payments.StarGifts; -payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool; -payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool; -payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; -payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; -payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots; -payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; -payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview; -payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates; -payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates; -payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift; -payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_unique:flags.4?true sort_by_value:flags.5?true exclude_upgradable:flags.7?true exclude_unupgradable:flags.8?true peer_color_available:flags.9?true exclude_hosted:flags.10?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts; -payments.getSavedStarGift#b455a106 stargift:Vector = payments.SavedStarGifts; -payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; -payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; -payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; -payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; -payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; -payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; -payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; -payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; -payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector = Bool; -payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool; -payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections; -payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo; -payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult; -payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState; -payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts; -payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions; -payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates; -payments.sendStarGiftOffer#8fb86b41 flags:# peer:InputPeer slug:string price:StarsAmount duration:int random_id:long allow_paid_stars:flags.0?long = Updates; -payments.getStarGiftUpgradeAttributes#6d038b58 gift_id:long = payments.StarGiftUpgradeAttributes; - -stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; -stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; -stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; -stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; -stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet; -stickers.checkShortName#284b3639 short_name:string = Bool; -stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName; -stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet; -stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet; -stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool; -stickers.replaceSticker#4696459a sticker:InputDocument new_sticker:InputStickerSetItem = messages.StickerSet; - -phone.getCallConfig#55451fa9 = DataJSON; -phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; -phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; -phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; -phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; -phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; -phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; -phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; -phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates; -phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; -phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; -phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; -phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates; -phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; -phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; -phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; -phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; -phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; -phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; -phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; -phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; -phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; -phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; -phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; -phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates; -phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates; -phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels; -phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl; -phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool; -phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates; -phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector block:bytes = Updates; -phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates; -phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates; -phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates; -phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates; -phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates; -phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool; -phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector = Updates; -phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates; -phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars; -phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool; - -langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; -langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; -langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; -langpack.getLanguages#42c6978f lang_pack:string = Vector; -langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; - -folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; - -stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats; -stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; -stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; -stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards; -stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; -stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; -stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards; - -chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; -chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; -chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector = ExportedChatlistInvite; -chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites; -chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite; -chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector = Updates; -chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates; -chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector = Updates; -chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool; -chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector; -chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector = Updates; - -stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount; -stories.sendStory#737fc2ec flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector = Updates; -stories.editStory#b583ba46 flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector = Updates; -stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; -stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; -stories.getAllStories#eeb0d625 flags:# next:flags.1?true hidden:flags.2?true state:flags.0?string = stories.AllStories; -stories.getPinnedStories#5821a5dc peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector = stories.Stories; -stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool; -stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector; -stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector = Bool; -stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList; -stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector = stories.StoryViews; -stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; -stories.report#19d8eb45 peer:InputPeer id:Vector option:bytes message:string = ReportResult; -stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates; -stories.sendReaction#7fd736b2 flags:# add_to_recent:flags.0?true peer:InputPeer story_id:int reaction:Reaction = Updates; -stories.getPeerStories#2c4ada50 peer:InputPeer = stories.PeerStories; -stories.getAllReadPeerStories#9b5ae7f9 = Updates; -stories.getPeerMaxIDs#78499170 id:Vector = Vector; -stories.getChatsToSend#a56a8b60 = messages.Chats; -stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; -stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; -stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; -stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories; -stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector = StoryAlbum; -stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector add_stories:flags.2?Vector order:flags.3?Vector = StoryAlbum; -stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector = Bool; -stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool; -stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums; -stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories; -stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates; - -premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; -premium.getMyBoosts#be77b4a = premium.MyBoosts; -premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; -premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; -premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; - -smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin; -smsjobs.join#a74ece2d = Bool; -smsjobs.leave#9898ad73 = Bool; -smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool; -smsjobs.getStatus#10a698e8 = smsjobs.Status; -smsjobs.getSmsJob#778d902f job_id:string = SmsJob; -smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; - -fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; - -// LAYER 220 diff --git a/internal/compat/layerwire/_schema/layer-221.tl b/internal/compat/layerwire/_schema/layer-221.tl deleted file mode 100644 index a2495076..00000000 --- a/internal/compat/layerwire/_schema/layer-221.tl +++ /dev/null @@ -1,2892 +0,0 @@ -boolFalse#bc799737 = Bool; -boolTrue#997275b5 = Bool; - -true#3fedd339 = True; - -vector#1cb5c415 {t:Type} # [ t ] = Vector t; - -error#c4b9f9bb code:int text:string = Error; - -null#56730bcc = Null; - -inputPeerEmpty#7f3b18ea = InputPeer; -inputPeerSelf#7da07ec9 = InputPeer; -inputPeerChat#35a95cb9 chat_id:long = InputPeer; -inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; -inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer; -inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer; -inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer; - -inputUserEmpty#b98886cf = InputUser; -inputUserSelf#f7c1b13f = InputUser; -inputUser#f21158c6 user_id:long access_hash:long = InputUser; -inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser; - -inputPhoneContact#6a1dc4be flags:# client_id:long phone:string first_name:string last_name:string note:flags.0?TextWithEntities = InputContact; - -inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; -inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; -inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile; - -inputMediaEmpty#9664f57f = InputMedia; -inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; -inputMediaPhoto#b3ba0635 flags:# spoiler:flags.1?true id:InputPhoto ttl_seconds:flags.0?int = InputMedia; -inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; -inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; -inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; -inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; -inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; -inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; -inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; -inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; -inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector solution:flags.1?string solution_entities:flags.1?Vector = InputMedia; -inputMediaDice#e66fbf7b emoticon:string = InputMedia; -inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; -inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; -inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; -inputMediaTodo#9fc55fde todo:TodoList = InputMedia; -inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia; - -inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; -inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; -inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; - -inputGeoPointEmpty#e4c123d6 = InputGeoPoint; -inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint; - -inputPhotoEmpty#1cd7bf0d = InputPhoto; -inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; - -inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; -inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; -inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; -inputTakeoutFileLocation#29be5899 = InputFileLocation; -inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; -inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; -inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; -inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; - -peerUser#59511722 user_id:long = Peer; -peerChat#36c6019a chat_id:long = Peer; -peerChannel#a2a5371e channel_id:long = Peer; - -storage.fileUnknown#aa963b05 = storage.FileType; -storage.filePartial#40bc6f52 = storage.FileType; -storage.fileJpeg#7efe0e = storage.FileType; -storage.fileGif#cae1aadf = storage.FileType; -storage.filePng#a4f63c0 = storage.FileType; -storage.filePdf#ae1e508d = storage.FileType; -storage.fileMp3#528a0677 = storage.FileType; -storage.fileMov#4b09ebbc = storage.FileType; -storage.fileMp4#b3cea0e4 = storage.FileType; -storage.fileWebp#1081464c = storage.FileType; - -userEmpty#d3bc4b7a id:long = User; -user#31774388 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true bot_business:flags2.11?true bot_has_main_app:flags2.13?true bot_forum_view:flags2.16?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?RecentStory color:flags2.8?PeerColor profile_color:flags2.9?PeerColor bot_active_users:flags2.12?int bot_verification_icon:flags2.14?long send_paid_messages_stars:flags2.15?long = User; - -userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; - -userStatusEmpty#9d05049 = UserStatus; -userStatusOnline#edb93949 expires:int = UserStatus; -userStatusOffline#8c703f was_online:int = UserStatus; -userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus; -userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus; -userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; - -chatEmpty#29562865 id:long = Chat; -chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; -chatForbidden#6592a1a7 id:long title:string = Chat; -channel#1c32b11c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?RecentStory color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat; -channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; - -chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#e4e0b29d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab = ChatFull; - -chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; -chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; -chatParticipantAdmin#a0933f5b user_id:long inviter_id:long date:int = ChatParticipant; - -chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants; -chatParticipants#3cbc93f8 chat_id:long participants:Vector version:int = ChatParticipants; - -chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; - -messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; -message#9cb490e9 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string = Message; -messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; - -messageMediaEmpty#3ded6320 = MessageMedia; -messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; -messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; -messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; -messageMediaUnsupported#9f84f49e = MessageMedia; -messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; -messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; -messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; -messageMediaGame#fdb19008 game:Game = MessageMedia; -messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia; -messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia; -messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; -messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia; -messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; -messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; -messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; -messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; -messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector = MessageMedia; -messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia; - -messageActionEmpty#b6aef7b0 = MessageAction; -messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; -messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; -messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; -messageActionChatDeletePhoto#95e3fbef = MessageAction; -messageActionChatAddUser#15cefd00 users:Vector = MessageAction; -messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction; -messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction; -messageActionChannelCreate#95d2ac92 title:string = MessageAction; -messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction; -messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction; -messageActionPinMessage#94bd38ed = MessageAction; -messageActionHistoryClear#9fbab604 = MessageAction; -messageActionGameScore#92a72876 game_id:long score:int = MessageAction; -messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction; -messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction; -messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; -messageActionScreenshotTaken#4792929b = MessageAction; -messageActionCustomAction#fae69f56 message:string = MessageAction; -messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction; -messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; -messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; -messageActionContactSignUp#f3f25f76 = MessageAction; -messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction; -messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; -messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector = MessageAction; -messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction; -messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; -messageActionSetChatTheme#b91bbd3a theme:ChatTheme = MessageAction; -messageActionChatJoinedByRequest#ebbca3cb = MessageAction; -messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction; -messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction; -messageActionGiftPremium#48e91302 flags:# currency:string amount:long days:int crypto_currency:flags.0?string crypto_amount:flags.0?long message:flags.1?TextWithEntities = MessageAction; -messageActionTopicCreate#d999256 flags:# title_missing:flags.1?true title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction; -messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction; -messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; -messageActionRequestedPeer#31518e9b button_id:int peers:Vector = MessageAction; -messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; -messageActionGiftCode#31c48347 flags:# via_giveaway:flags.0?true unclaimed:flags.5?true boost_peer:flags.1?Peer days:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long message:flags.4?TextWithEntities = MessageAction; -messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction; -messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction; -messageActionBoostApply#cc02aa6d boosts:int = MessageAction; -messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; -messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; -messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; -messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; -messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction; -messageActionStarGiftUnique#95728543 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long = MessageAction; -messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; -messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; -messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; -messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; -messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; -messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction; -messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction; -messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction; -messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction; -messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction; -messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction; -messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction; - -dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; -dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; - -photoEmpty#2331b22d id:long = Photo; -photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = Photo; - -photoSizeEmpty#e17e23c type:string = PhotoSize; -photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; -photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; -photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; -photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; -photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; - -geoPointEmpty#1117dd5f = GeoPoint; -geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; - -auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; -auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; -auth.sentCodePaymentRequired#e0955a3c store_product:string phone_code_hash:string support_email_address:string support_email_subject:string currency:string amount:long = auth.SentCode; - -auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; -auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; - -auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; - -inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; -inputNotifyUsers#193b4417 = InputNotifyPeer; -inputNotifyChats#4a95e84e = InputNotifyPeer; -inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; -inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer; - -inputPeerNotifySettings#cacb6ae2 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_sound:flags.8?NotificationSound = InputPeerNotifySettings; - -peerNotifySettings#99622c0c flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_ios_sound:flags.8?NotificationSound stories_android_sound:flags.9?NotificationSound stories_other_sound:flags.10?NotificationSound = PeerNotifySettings; - -peerSettings#f47741f7 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true business_bot_paused:flags.11?true business_bot_can_reply:flags.12?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int business_bot_id:flags.13?long business_bot_manage_url:flags.13?string charge_paid_message_stars:flags.14?long registration_month:flags.15?string phone_country:flags.16?string name_change_date:flags.17?int photo_change_date:flags.18?int = PeerSettings; - -wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; -wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; - -inputReportReasonSpam#58dbcab8 = ReportReason; -inputReportReasonViolence#1e22c78d = ReportReason; -inputReportReasonPornography#2e59d922 = ReportReason; -inputReportReasonChildAbuse#adf44ee3 = ReportReason; -inputReportReasonOther#c1e4a2b1 = ReportReason; -inputReportReasonCopyright#9b89f93a = ReportReason; -inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; -inputReportReasonFake#f5ddd6e7 = ReportReason; -inputReportReasonIllegalDrugs#a8eb2be = ReportReason; -inputReportReasonPersonalDetails#9ec7863d = ReportReason; - -userFull#a02bc13e flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme:flags.15?ChatTheme private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int main_tab:flags2.20?ProfileTab saved_music:flags2.21?Document note:flags2.22?TextWithEntities = UserFull; - -contact#145ade0b user_id:long mutual:Bool = Contact; - -importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; - -contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; - -contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; -contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; - -contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; - -contacts.blocked#ade1591 blocked:Vector chats:Vector users:Vector = contacts.Blocked; -contacts.blockedSlice#e1664194 count:int blocked:Vector chats:Vector users:Vector = contacts.Blocked; - -messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; - -messages.messages#1d73e7ea messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#5f206716 flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesNotModified#74535f21 count:int = messages.Messages; - -messages.chats#64ff9fd5 chats:Vector = messages.Chats; -messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; - -messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; - -messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; - -inputMessagesFilterEmpty#57e2f66c = MessagesFilter; -inputMessagesFilterPhotos#9609a51c = MessagesFilter; -inputMessagesFilterVideo#9fc00e65 = MessagesFilter; -inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; -inputMessagesFilterDocument#9eddf188 = MessagesFilter; -inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; -inputMessagesFilterGif#ffc86587 = MessagesFilter; -inputMessagesFilterVoice#50f5c392 = MessagesFilter; -inputMessagesFilterMusic#3751b49e = MessagesFilter; -inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; -inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; -inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; -inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; -inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; -inputMessagesFilterGeo#e7026d0d = MessagesFilter; -inputMessagesFilterContacts#e062db83 = MessagesFilter; -inputMessagesFilterPinned#1bb00451 = MessagesFilter; - -updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; -updateMessageID#4e90bfd6 id:int random_id:long = Update; -updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; -updateUserTyping#2a17bf5c flags:# user_id:long top_msg_id:flags.0?int action:SendMessageAction = Update; -updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update; -updateChatParticipants#7761198 participants:ChatParticipants = Update; -updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; -updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector = Update; -updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update; -updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; -updateEncryptedChatTyping#1710f156 chat_id:int = Update; -updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; -updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; -updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update; -updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update; -updateDcOptions#8e5e9873 dc_options:Vector = Update; -updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; -updateServiceNotification#ebe46819 flags:# popup:flags.0?true invert_media:flags.2?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; -updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; -updateUserPhone#5492a13 user_id:long phone:string = Update; -updateReadHistoryInbox#9e84bc99 flags:# folder_id:flags.0?int peer:Peer top_msg_id:flags.1?int max_id:int still_unread_count:int pts:int pts_count:int = Update; -updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; -updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; -updateReadMessagesContents#f8227181 flags:# messages:Vector pts:int pts_count:int date:flags.0?int = Update; -updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; -updateChannel#635b4c09 channel_id:long = Update; -updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update; -updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; -updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; -updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; -updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Update; -updateStickerSets#31c24808 flags:# masks:flags.0?true emojis:flags.1?true = Update; -updateSavedGifs#9375341e = Update; -updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; -updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; -updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; -updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; -updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; -updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update; -updateReadFeaturedStickers#571d2742 = Update; -updateRecentStickers#9a422c20 = Update; -updateConfig#a229dd06 = Update; -updatePtsChanged#3354678f = Update; -updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update; -updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; -updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; -updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; -updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; -updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update; -updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; -updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; -updateLangPackTooLong#46560264 lang_code:string = Update; -updateLangPack#56022f4d difference:LangPackDifference = Update; -updateFavedStickers#e511996d = Update; -updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector = Update; -updateContactsReset#7084a7be = Update; -updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; -updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update; -updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; -updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; -updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; -updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update; -updatePeerLocated#b4afcfb0 peers:Vector = Update; -updateNewScheduledMessage#39a51dfb message:Message = Update; -updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector sent_messages:flags.0?Vector = Update; -updateTheme#8216fba3 theme:Theme = Update; -updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update; -updateLoginToken#564fe691 = Update; -updateMessagePollVote#24f40e77 poll_id:long peer:Peer options:Vector qts:int = Update; -updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update; -updateDialogFilterOrder#a5d72105 order:Vector = Update; -updateDialogFilters#3504914f = Update; -updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update; -updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update; -updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update; -updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update; -updatePeerBlocked#ebe07752 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer = Update; -updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; -updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; -updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChat#f89a6a4e chat_id:long = Update; -updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; -updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update; -updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; -updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update; -updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update; -updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; -updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; -updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update; -updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update; -updateAttachMenuBots#17b7a20b = Update; -updateWebViewResultSent#1592b79d query_id:long = Update; -updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update; -updateSavedRingtones#74d8be99 = Update; -updateTranscribedAudio#84cd5a flags:# pending:flags.0?true peer:Peer msg_id:int transcription_id:long text:string = Update; -updateReadFeaturedEmojiStickers#fb4c496c = Update; -updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update; -updateRecentEmojiStatuses#30f443db = Update; -updateRecentReactions#6f7863f4 = Update; -updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update; -updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector = Update; -updateUser#20529438 user_id:long = Update; -updateAutoSaveSettings#ec05b097 = Update; -updateStory#75b3b798 peer:Peer story:StoryItem = Update; -updateReadStories#f74e932b peer:Peer max_id:int = Update; -updateStoryID#1bf335b9 id:int random_id:long = Update; -updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update; -updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update; -updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update; -updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update; -updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update; -updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector new_reactions:Vector qts:int = Update; -updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector qts:int = Update; -updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; -updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector = Update; -updateSavedReactionTags#39c67432 = Update; -updateSmsJob#f16269d4 job_id:string = Update; -updateQuickReplies#f9470ab2 quick_replies:Vector = Update; -updateNewQuickReply#f53da717 quick_reply:QuickReply = Update; -updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update; -updateQuickReplyMessage#3e050d0f message:Message = Update; -updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector = Update; -updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Update; -updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; -updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; -updateStarsBalance#4e80a379 balance:StarsAmount = Update; -updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; -updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; -updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; -updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; -updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; -updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; -updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update; -updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = Update; -updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update; -updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update; -updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector = Update; -updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector = Update; -updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update; -updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update; -updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update; - -updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; - -updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; -updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; -updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; -updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; - -updatesTooLong#e317af7e = Updates; -updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShort#78d4dec1 update:Update date:int = Updates; -updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; -updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; -updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; -photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; - -photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; - -upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; -upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; - -dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; - -config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config; - -nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; - -help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate; -help.noAppUpdate#c45a6536 = help.AppUpdate; - -help.inviteText#18cb9f78 message:string = help.InviteText; - -encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; -encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat; -encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; -encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; -encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat; - -inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; - -encryptedFileEmpty#c21f497e = EncryptedFile; -encryptedFile#a8008cd8 id:long access_hash:long size:long dc_id:int key_fingerprint:int = EncryptedFile; - -inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; -inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; -inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; -inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; - -encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; -encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; - -messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; -messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; - -messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; -messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; - -inputDocumentEmpty#72f0eaae = InputDocument; -inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; - -documentEmpty#36f8c871 id:long = Document; -document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector video_thumbs:flags.1?Vector dc_id:int attributes:Vector = Document; - -help.support#17c6b5f6 phone_number:string user:User = help.Support; - -notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; -notifyUsers#b4c83b4c = NotifyPeer; -notifyChats#c007cec3 = NotifyPeer; -notifyBroadcasts#d612e8ef = NotifyPeer; -notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer; - -sendMessageTypingAction#16bf744e = SendMessageAction; -sendMessageCancelAction#fd5ec8f5 = SendMessageAction; -sendMessageRecordVideoAction#a187d66f = SendMessageAction; -sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; -sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; -sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; -sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; -sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; -sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; -sendMessageChooseContactAction#628cbc6f = SendMessageAction; -sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; -sendMessageRecordRoundAction#88f27fbc = SendMessageAction; -sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; -speakingInGroupCallAction#d92c2285 = SendMessageAction; -sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; -sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; -sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction; -sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction; -sendMessageTextDraftAction#376d975c random_id:long text:TextWithEntities = SendMessageAction; - -contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; - -inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; -inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; -inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; -inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; -inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; -inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; -inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; -inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey; -inputPrivacyKeyVoiceMessages#aee69d68 = InputPrivacyKey; -inputPrivacyKeyAbout#3823cc40 = InputPrivacyKey; -inputPrivacyKeyBirthday#d65a11cc = InputPrivacyKey; -inputPrivacyKeyStarGiftsAutoSave#e1732341 = InputPrivacyKey; -inputPrivacyKeyNoPaidMessages#bdc597b4 = InputPrivacyKey; -inputPrivacyKeySavedMusic#4dbe9226 = InputPrivacyKey; - -privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; -privacyKeyChatInvite#500e6dfa = PrivacyKey; -privacyKeyPhoneCall#3d662b7b = PrivacyKey; -privacyKeyPhoneP2P#39491cc8 = PrivacyKey; -privacyKeyForwards#69ec56a3 = PrivacyKey; -privacyKeyProfilePhoto#96151fed = PrivacyKey; -privacyKeyPhoneNumber#d19ae46d = PrivacyKey; -privacyKeyAddedByPhone#42ffd42b = PrivacyKey; -privacyKeyVoiceMessages#697f414 = PrivacyKey; -privacyKeyAbout#a486b761 = PrivacyKey; -privacyKeyBirthday#2000a518 = PrivacyKey; -privacyKeyStarGiftsAutoSave#2ca4fdf8 = PrivacyKey; -privacyKeyNoPaidMessages#17d348d2 = PrivacyKey; -privacyKeySavedMusic#ff7a571b = PrivacyKey; - -inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; -inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; -inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; -inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; -inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; -inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; -inputPrivacyValueAllowChatParticipants#840649cf chats:Vector = InputPrivacyRule; -inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector = InputPrivacyRule; -inputPrivacyValueAllowCloseFriends#2f453e49 = InputPrivacyRule; -inputPrivacyValueAllowPremium#77cdc9f1 = InputPrivacyRule; -inputPrivacyValueAllowBots#5a4fcce5 = InputPrivacyRule; -inputPrivacyValueDisallowBots#c4e57915 = InputPrivacyRule; - -privacyValueAllowContacts#fffe1bac = PrivacyRule; -privacyValueAllowAll#65427b82 = PrivacyRule; -privacyValueAllowUsers#b8905fb2 users:Vector = PrivacyRule; -privacyValueDisallowContacts#f888fa1a = PrivacyRule; -privacyValueDisallowAll#8b73e763 = PrivacyRule; -privacyValueDisallowUsers#e4621141 users:Vector = PrivacyRule; -privacyValueAllowChatParticipants#6b134e8e chats:Vector = PrivacyRule; -privacyValueDisallowChatParticipants#41c87565 chats:Vector = PrivacyRule; -privacyValueAllowCloseFriends#f7e8d89b = PrivacyRule; -privacyValueAllowPremium#ece9814b = PrivacyRule; -privacyValueAllowBots#21461b5d = PrivacyRule; -privacyValueDisallowBots#f6a5f82f = PrivacyRule; - -account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; - -accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; - -documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; -documentAttributeAnimated#11b58939 = DocumentAttribute; -documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; -documentAttributeVideo#43c57c48 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double video_codec:flags.5?string = DocumentAttribute; -documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; -documentAttributeFilename#15590068 file_name:string = DocumentAttribute; -documentAttributeHasStickers#9801d2f7 = DocumentAttribute; -documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute; - -messages.stickersNotModified#f1749a22 = messages.Stickers; -messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; - -stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; - -messages.allStickersNotModified#e86602c3 = messages.AllStickers; -messages.allStickers#cdbbcebb hash:long sets:Vector = messages.AllStickers; - -messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; - -webPageEmpty#211a1788 flags:# id:long url:flags.0?string = WebPage; -webPagePending#b0d13e47 flags:# id:long url:flags.0?string date:int = WebPage; -webPage#e89c45b2 flags:# has_large_media:flags.13?true video_cover_photo:flags.14?true id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector = WebPage; -webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; - -authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; - -account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector = account.Authorizations; - -account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password; - -account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; - -account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; - -auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; - -receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; - -chatInviteExported#a22cbd96 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int subscription_expired:flags.10?int title:flags.8?string subscription_pricing:flags.9?StarsSubscriptionPricing = ExportedChatInvite; -chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite; - -chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#5c9d3702 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true can_refulfill_subscription:flags.11?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector color:int subscription_pricing:flags.10?StarsSubscriptionPricing subscription_form_id:flags.12?long bot_verification:flags.13?BotVerification = ChatInvite; -chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; - -inputStickerSetEmpty#ffb62b95 = InputStickerSet; -inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; -inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; -inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; -inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; -inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet; -inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet; -inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; -inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; -inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet; -inputStickerSetTonGifts#1cf671a0 = InputStickerSet; - -stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; - -messages.stickerSet#6e153f16 set:StickerSet packs:Vector keywords:Vector documents:Vector = messages.StickerSet; -messages.stickerSetNotModified#d3f924eb = messages.StickerSet; - -botCommand#c27ac8c7 command:string description:string = BotCommand; - -botInfo#4d8a0299 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton privacy_policy_url:flags.7?string app_settings:flags.8?BotAppSettings verifier_settings:flags.9?BotVerifierSettings = BotInfo; - -keyboardButton#a2fa4880 text:string = KeyboardButton; -keyboardButtonUrl#258aff05 text:string url:string = KeyboardButton; -keyboardButtonCallback#35bbdb6b flags:# requires_password:flags.0?true text:string data:bytes = KeyboardButton; -keyboardButtonRequestPhone#b16a6c29 text:string = KeyboardButton; -keyboardButtonRequestGeoLocation#fc796b3f text:string = KeyboardButton; -keyboardButtonSwitchInline#93b9fbb5 flags:# same_peer:flags.0?true text:string query:string peer_types:flags.1?Vector = KeyboardButton; -keyboardButtonGame#50f41ccf text:string = KeyboardButton; -keyboardButtonBuy#afd93fbb text:string = KeyboardButton; -keyboardButtonUrlAuth#10b78d29 flags:# text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; -inputKeyboardButtonUrlAuth#d02e7fd4 flags:# request_write_access:flags.0?true text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; -keyboardButtonRequestPoll#bbc7515d flags:# quiz:flags.0?Bool text:string = KeyboardButton; -inputKeyboardButtonUserProfile#e988037b text:string user_id:InputUser = KeyboardButton; -keyboardButtonUserProfile#308660c1 text:string user_id:long = KeyboardButton; -keyboardButtonWebView#13767230 text:string url:string = KeyboardButton; -keyboardButtonSimpleWebView#a0c0505c text:string url:string = KeyboardButton; -keyboardButtonRequestPeer#53d7bfd8 text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -inputKeyboardButtonRequestPeer#c9662d05 flags:# name_requested:flags.0?true username_requested:flags.1?true photo_requested:flags.2?true text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -keyboardButtonCopy#75d2698e text:string copy_text:string = KeyboardButton; - -keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; - -replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; -replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup; -replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector placeholder:flags.3?string = ReplyMarkup; -replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; - -messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; -messageEntityMention#fa04579d offset:int length:int = MessageEntity; -messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; -messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; -messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; -messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; -messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; -messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; -messageEntityCode#28a20571 offset:int length:int = MessageEntity; -messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; -messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; -messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity; -inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; -messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; -messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; -messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity; -messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; -messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; -messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; -messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; -messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity; - -inputChannelEmpty#ee8c1e86 = InputChannel; -inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; -inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel; - -contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; - -messageRange#ae30253 min_id:int max_id:int = MessageRange; - -updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; -updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; -updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; - -channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; -channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; - -channelParticipant#cb397619 flags:# user_id:long date:int subscription_until_date:flags.0?int = ChannelParticipant; -channelParticipantSelf#4f607bef flags:# via_request:flags.0?true user_id:long inviter_id:long date:int subscription_until_date:flags.1?int = ChannelParticipant; -channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; -channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; -channelParticipantBanned#6df8014e flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights = ChannelParticipant; -channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; - -channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; -channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; -channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; -channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; -channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; -channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; -channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; -channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; - -channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; -channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; - -channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; - -help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; - -messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; -messages.savedGifs#84a02a0d hash:long gifs:Vector = messages.SavedGifs; - -inputBotInlineMessageMediaAuto#3380c786 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaWebPage#bddcc510 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true optional:flags.6?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; - -botInlineMessageMediaAuto#764cf810 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; -botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; - -messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector cache_time:int users:Vector = messages.BotResults; - -exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; - -messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader; - -auth.codeTypeSms#72a3158c = auth.CodeType; -auth.codeTypeCall#741cd3e3 = auth.CodeType; -auth.codeTypeFlashCall#226ccefb = auth.CodeType; -auth.codeTypeMissedCall#d61ad6ee = auth.CodeType; -auth.codeTypeFragmentSms#6ed998c = auth.CodeType; - -auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; -auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; -auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; -auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType; -auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; -auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; -auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; -auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; -auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; -auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; - -messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; - -messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; - -inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; -inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID; - -inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; - -messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; - -topPeer#edcdc05b peer:Peer rating:double = TopPeer; - -topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; -topPeerCategoryBotsInline#148677e2 = TopPeerCategory; -topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; -topPeerCategoryGroups#bd17a14a = TopPeerCategory; -topPeerCategoryChannels#161d9628 = TopPeerCategory; -topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; -topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; -topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; -topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory; - -topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; - -contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; -contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; -contacts.topPeersDisabled#b52c939d = contacts.TopPeers; - -draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; -draftMessage#96eaa5eb flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost = DraftMessage; - -messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; -messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; - -messages.recentStickersNotModified#b17f890 = messages.RecentStickers; -messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; - -messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; - -messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; -messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; - -stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; -stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; -stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector keywords:Vector documents:Vector = StickerSetCovered; -stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered; - -maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; - -inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; -inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; - -game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; - -inputGameID#32c3e77 id:long access_hash:long = InputGame; -inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; - -highScore#73a379eb pos:int user_id:long score:int = HighScore; - -messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; - -textEmpty#dc3d824f = RichText; -textPlain#744694e0 text:string = RichText; -textBold#6724abc4 text:RichText = RichText; -textItalic#d912a59c text:RichText = RichText; -textUnderline#c12622c4 text:RichText = RichText; -textStrike#9bf8bb95 text:RichText = RichText; -textFixed#6c3f19b9 text:RichText = RichText; -textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; -textEmail#de5a0dd6 text:RichText email:string = RichText; -textConcat#7e6260d7 texts:Vector = RichText; -textSubscript#ed6a8504 text:RichText = RichText; -textSuperscript#c7fb5e01 text:RichText = RichText; -textMarked#34b8621 text:RichText = RichText; -textPhone#1ccb966a text:RichText phone:string = RichText; -textImage#81ccf4f document_id:long w:int h:int = RichText; -textAnchor#35553762 text:RichText name:string = RichText; - -pageBlockUnsupported#13567e8a = PageBlock; -pageBlockTitle#70abc3fd text:RichText = PageBlock; -pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; -pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; -pageBlockHeader#bfd064ec text:RichText = PageBlock; -pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; -pageBlockParagraph#467a0766 text:RichText = PageBlock; -pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; -pageBlockFooter#48870999 text:RichText = PageBlock; -pageBlockDivider#db20b188 = PageBlock; -pageBlockAnchor#ce0d37b0 name:string = PageBlock; -pageBlockList#e4e88011 items:Vector = PageBlock; -pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; -pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; -pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; -pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; -pageBlockCover#39f23300 cover:PageBlock = PageBlock; -pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; -pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; -pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; -pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; -pageBlockChannel#ef1751b5 channel:Chat = PageBlock; -pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; -pageBlockKicker#1e148390 text:RichText = PageBlock; -pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; -pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; -pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; -pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; -pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; - -phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; -phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; -phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; -phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; -phoneCallDiscardReasonMigrateConferenceCall#9fbbf1f7 slug:string = PhoneCallDiscardReason; - -dataJSON#7d748d04 data:string = DataJSON; - -labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; - -invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector terms_url:flags.10?string subscription_period:flags.11?int = Invoice; - -paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; - -postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; - -paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; - -paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; - -webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; -webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; - -inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; - -inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; -inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; -inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation; - -upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; - -payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector users:Vector = payments.PaymentForm; -payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector = payments.PaymentForm; -payments.paymentFormStarGift#b425cfe1 form_id:long invoice:Invoice = payments.PaymentForm; - -payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; - -payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; -payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; - -payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; -payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector = payments.PaymentReceipt; - -payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; - -inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; -inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials; - -account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; - -shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; - -inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem; - -inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; - -phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#30535af5 flags:# p2p_allowed:flags.5?true video:flags.6?true conference_supported:flags.8?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int custom_parameters:flags.7?DataJSON = PhoneCall; -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; - -phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; -phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection; - -phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector = PhoneCallProtocol; - -phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; - -upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; -upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; - -cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; - -cdnConfig#5725e40a public_keys:Vector = CdnConfig; - -langPackString#cad181f6 key:string value:string = LangPackString; -langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; -langPackStringDeleted#2979eeb2 key:string = LangPackString; - -langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; - -langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; - -channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; -channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector new_value:Vector = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAutotranslation#c517f77e new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; - -channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; - -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true = ChannelAdminLogEventsFilter; - -popularContact#5ce14175 client_id:long importers:int = PopularContact; - -messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; -messages.favedStickers#2cb51097 hash:long packs:Vector stickers:Vector = messages.FavedStickers; - -recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; -recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl; -recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl; -recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; -recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; - -help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; - -inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; - -webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; - -account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; - -inputMessageID#a676a322 id:int = InputMessage; -inputMessageReplyTo#bad88395 id:int = InputMessage; -inputMessagePinned#86872538 = InputMessage; -inputMessageCallbackQuery#acfa1a7e id:int query_id:long = InputMessage; - -inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; -inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; - -dialogPeer#e56dbf05 peer:Peer = DialogPeer; -dialogPeerFolder#514519e2 folder_id:int = DialogPeer; - -messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; -messages.foundStickerSets#8af09dd2 hash:long sets:Vector = messages.FoundStickerSets; - -fileHash#f39b035c offset:long limit:int hash:bytes = FileHash; - -inputClientProxy#75588b3f address:string port:int = InputClientProxy; - -help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; -help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; - -inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; -inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; - -secureFileEmpty#64199744 = SecureFile; -secureFile#7d09c27e id:long access_hash:long size:long dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; - -secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; - -securePlainPhone#7d6099dd phone:string = SecurePlainData; -securePlainEmail#21ec5a5f email:string = SecurePlainData; - -secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; -secureValueTypePassport#3dac6a00 = SecureValueType; -secureValueTypeDriverLicense#6e425c4 = SecureValueType; -secureValueTypeIdentityCard#a0d0744b = SecureValueType; -secureValueTypeInternalPassport#99a48f23 = SecureValueType; -secureValueTypeAddress#cbe31e26 = SecureValueType; -secureValueTypeUtilityBill#fc36954e = SecureValueType; -secureValueTypeBankStatement#89137c0d = SecureValueType; -secureValueTypeRentalAgreement#8b883488 = SecureValueType; -secureValueTypePassportRegistration#99e3806a = SecureValueType; -secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; -secureValueTypePhone#b320aadb = SecureValueType; -secureValueTypeEmail#8e3ca7ee = SecureValueType; - -secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; - -inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; - -secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; - -secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; -secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; -secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; - -secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; - -account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; - -account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; - -help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; -help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; - -savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; - -account.takeout#4dba4501 id:long = account.Takeout; - -passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; -passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; - -securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; -securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; -securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; - -secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; - -inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; -inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; - -secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; -secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; - -help.passportConfigNotModified#bfb9f457 = help.PassportConfig; -help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; - -inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; - -jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; - -jsonNull#3f6d7b68 = JSONValue; -jsonBool#c7345e6a value:Bool = JSONValue; -jsonNumber#2be0dfa4 value:double = JSONValue; -jsonString#b71e767a value:string = JSONValue; -jsonArray#f7444763 value:Vector = JSONValue; -jsonObject#99c1d49d value:Vector = JSONValue; - -pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; - -pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; - -pageCaption#6f747657 text:RichText credit:RichText = PageCaption; - -pageListItemText#b92fb6cd text:RichText = PageListItem; -pageListItemBlocks#25e073fc blocks:Vector = PageListItem; - -pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; -pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; - -pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; - -page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector views:flags.3?int = Page; - -help.supportName#8c05f1c9 name:string = help.SupportName; - -help.userInfoEmpty#f3ae2eed = help.UserInfo; -help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; - -pollAnswer#ff16e2ca text:TextWithEntities option:bytes = PollAnswer; - -poll#58747131 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:TextWithEntities answers:Vector close_period:flags.4?int close_date:flags.5?int = Poll; - -pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters; - -pollResults#7adf2420 flags:# min:flags.0?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector = PollResults; - -chatOnlines#f041e250 onlines:int = ChatOnlines; - -statsURL#47a971e0 url:string = StatsURL; - -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true = ChatAdminRights; - -chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true until_date:int = ChatBannedRights; - -inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; -inputWallPaperSlug#72091c80 slug:string = InputWallPaper; -inputWallPaperNoFile#967a462e id:long = InputWallPaper; - -account.wallPapersNotModified#1c199183 = account.WallPapers; -account.wallPapers#cdc3858c hash:long wallpapers:Vector = account.WallPapers; - -codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true unknown_number:flags.9?true logout_tokens:flags.6?Vector token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings; - -wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings; - -autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings; - -account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; - -emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector = EmojiKeyword; -emojiKeywordDeleted#236df622 keyword:string emoticons:Vector = EmojiKeyword; - -emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector = EmojiKeywordsDifference; - -emojiURL#a575739d url:string = EmojiURL; - -emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; - -folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; - -inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; - -folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; - -messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; - -urlAuthResultRequest#92d33a0e flags:# request_write_access:flags.0?true bot:User domain:string = UrlAuthResult; -urlAuthResultAccepted#8f8c0e4e url:string = UrlAuthResult; -urlAuthResultDefault#a9d6db1f = UrlAuthResult; - -channelLocationEmpty#bfb5ad8b = ChannelLocation; -channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation; - -peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated; -peerSelfLocated#f8ec284b expires:int = PeerLocated; - -restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason; - -inputTheme#3c5693e9 id:long access_hash:long = InputTheme; -inputThemeSlug#f5890df1 slug:string = InputTheme; - -theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector emoticon:flags.6?string installs_count:flags.4?int = Theme; - -account.themesNotModified#f41eb622 = account.Themes; -account.themes#9a3d8c6d hash:long themes:Vector = account.Themes; - -auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken; -auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken; -auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken; - -account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings; - -messages.inactiveChats#a927fec5 dates:Vector chats:Vector users:Vector = messages.InactiveChats; - -baseThemeClassic#c3a12462 = BaseTheme; -baseThemeDay#fbd81688 = BaseTheme; -baseThemeNight#b7b31ea8 = BaseTheme; -baseThemeTinted#6d5f77ee = BaseTheme; -baseThemeArctic#5b11125a = BaseTheme; - -inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; - -themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; - -webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; -webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; -webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; -webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; -webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; -webPageAttributeStarGiftAuction#1c641c2 gift:StarGift end_date:int = WebPageAttribute; - -messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; - -bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl; - -payments.bankCardData#3e24e573 title:string open_urls:Vector = payments.BankCardData; - -dialogFilter#aa472651 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector exclude_peers:Vector = DialogFilter; -dialogFilterDefault#363293ae = DialogFilter; -dialogFilterChatlist#96537bd7 flags:# has_my_invites:flags.26?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector = DialogFilter; - -dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested; - -statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays; - -statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev; - -statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue; - -statsGraphAsync#4a27eb2d token:string = StatsGraph; -statsGraphError#bedc9822 error:string = StatsGraph; -statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph; - -stats.broadcastStats#396ca5fc period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev reactions_per_post:StatsAbsValueAndPrev views_per_story:StatsAbsValueAndPrev shares_per_story:StatsAbsValueAndPrev reactions_per_story:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_posts_interactions:Vector = stats.BroadcastStats; - -help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; -help.promoData#8a4d87a flags:# proxy:flags.0?true expires:int peer:flags.3?Peer psa_type:flags.1?string psa_message:flags.2?string pending_suggestions:Vector dismissed_suggestions:Vector custom_pending_suggestion:flags.4?PendingSuggestion chats:Vector users:Vector = help.PromoData; - -videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; -videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector = VideoSize; -videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector = VideoSize; - -statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster; - -statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; - -statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; - -stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; - -globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; - -help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; - -help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector = help.Country; - -help.countriesListNotModified#93cc1f32 = help.CountriesList; -help.countriesList#87d0759e countries:Vector hash:int = help.CountriesList; - -messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews; - -messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; - -messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; - -messageReplyHeader#6917560b flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector quote_offset:flags.10?int todo_item_id:flags.11?int = MessageReplyHeader; -messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader; - -messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; - -peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; - -stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; - -groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall; - -inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -inputGroupCallSlug#fe06823f slug:string = InputGroupCall; -inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall; - -groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant; - -phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; - -phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; - -inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; -inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; -inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType; -inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType; -inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType; -inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType; - -messages.historyImport#1662af0b id:long = messages.HistoryImport; - -messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed; - -messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector = messages.AffectedFoundMessages; - -chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter; - -messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; - -messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; -messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; - -messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; - -chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites; - -messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; - -messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; - -phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; - -phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; - -groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector = GroupCallParticipantVideoSourceGroup; - -groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector audio_source:flags.1?int = GroupCallParticipantVideo; - -stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName; - -botCommandScopeDefault#2f6cb2ab = BotCommandScope; -botCommandScopeUsers#3c4f04d8 = BotCommandScope; -botCommandScopeChats#6fe1a881 = BotCommandScope; -botCommandScopeChatAdmins#b9aa606a = BotCommandScope; -botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope; -botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope; -botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope; - -account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult; -account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; -account.resetPasswordOk#e926d63e = account.ResetPasswordResult; - -chatTheme#c3dffc04 emoticon:string = ChatTheme; -chatThemeUniqueGift#3458f9c8 gift:StarGift theme_settings:Vector = ChatTheme; - -account.chatThemesNotModified#e011e1c4 = account.ChatThemes; -account.chatThemes#be098173 flags:# hash:long themes:Vector chats:Vector users:Vector next_offset:flags.0?string = account.ChatThemes; - -sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage; - -messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; -messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; - -searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; - -messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector messages:Vector chats:Vector users:Vector = messages.SearchResultsCalendar; - -searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition; - -messages.searchResultsPositions#53b22baf count:int positions:Vector = messages.SearchResultsPositions; - -channels.sendAsPeers#f496b0c6 peers:Vector chats:Vector users:Vector = channels.SendAsPeers; - -users.userFull#3b6d152e full_user:UserFull chats:Vector users:Vector = users.UserFull; - -messages.peerSettings#6880b94d settings:PeerSettings chats:Vector users:Vector = messages.PeerSettings; - -auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut; - -reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; - -messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector recent_reactions:flags.1?Vector top_reactors:flags.4?Vector = MessageReactions; - -messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.MessageReactionsList; - -availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; - -messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions; -messages.availableReactions#768e3aad hash:int reactions:Vector = messages.AvailableReactions; - -messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true my:flags.2?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction; - -groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel; - -phone.groupCallStreamChannels#d0e482b2 channels:Vector = phone.GroupCallStreamChannels; - -phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl; - -attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; - -attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector = AttachMenuBotIcon; - -attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector icons:Vector = AttachMenuBot; - -attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; -attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector = AttachMenuBots; - -attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector = AttachMenuBotsBot; - -webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true fullscreen:flags.2?true query_id:flags.0?long url:string = WebViewResult; - -webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent; - -botMenuButtonDefault#7533a588 = BotMenuButton; -botMenuButtonCommands#4258c205 = BotMenuButton; -botMenuButton#c7b57ce6 text:string url:string = BotMenuButton; - -account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones; -account.savedRingtones#c1e92cc5 hash:long ringtones:Vector = account.SavedRingtones; - -notificationSoundDefault#97e8bebe = NotificationSound; -notificationSoundNone#6f0c34df = NotificationSound; -notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound; -notificationSoundRingtone#ff6c8049 id:long = NotificationSound; - -account.savedRingtone#b7263f6d = account.SavedRingtone; -account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone; - -attachMenuPeerTypeSameBotPM#7d6be90e = AttachMenuPeerType; -attachMenuPeerTypeBotPM#c32bfa1a = AttachMenuPeerType; -attachMenuPeerTypePM#f146d31f = AttachMenuPeerType; -attachMenuPeerTypeChat#509113f = AttachMenuPeerType; -attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; - -inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; -inputInvoiceSlug#c326caef slug:string = InputInvoice; -inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; -inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice; -inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice; -inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; -inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; -inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; -inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; -inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice; -inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice; - -payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; - -messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; - -help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; - -inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose; -inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentPremiumGiftCode#fb790393 flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long message:flags.1?TextWithEntities = InputStorePaymentPurpose; -inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsTopup#f9a2a6cb flags:# stars:long currency:string amount:long spend_purpose_peer:flags.0?InputPeer = InputStorePaymentPurpose; -inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; -inputStorePaymentAuthCode#9bb2636d flags:# restore:flags.0?true phone_number:string phone_code_hash:string currency:string amount:long = InputStorePaymentPurpose; - -paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; - -emojiStatusEmpty#2de11aae = EmojiStatus; -emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus; -emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus; -inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus; - -account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses; -account.emojiStatuses#90c467d1 hash:long statuses:Vector = account.EmojiStatuses; - -reactionEmpty#79f5d419 = Reaction; -reactionEmoji#1b2286b8 emoticon:string = Reaction; -reactionCustomEmoji#8935fc73 document_id:long = Reaction; -reactionPaid#523da4eb = Reaction; - -chatReactionsNone#eafc32bc = ChatReactions; -chatReactionsAll#52928bca flags:# allow_custom:flags.0?true = ChatReactions; -chatReactionsSome#661d4037 reactions:Vector = ChatReactions; - -messages.reactionsNotModified#b06fdbdf = messages.Reactions; -messages.reactions#eafdf716 hash:long reactions:Vector = messages.Reactions; - -emailVerifyPurposeLoginSetup#4345be73 phone_number:string phone_code_hash:string = EmailVerifyPurpose; -emailVerifyPurposeLoginChange#527d22eb = EmailVerifyPurpose; -emailVerifyPurposePassport#bbf51685 = EmailVerifyPurpose; - -emailVerificationCode#922e55a9 code:string = EmailVerification; -emailVerificationGoogle#db909ec2 token:string = EmailVerification; -emailVerificationApple#96d074fd token:string = EmailVerification; - -account.emailVerified#2b96cd1b email:string = account.EmailVerified; -account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified; - -premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption; - -sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer; - -messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia; -messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia; - -stickerKeyword#fcfeb29c document_id:long keyword:Vector = StickerKeyword; - -username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username; - -forumTopicDeleted#23f109b id:int = ForumTopic; -forumTopic#cdff0eca flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true title_missing:flags.7?true id:int date:int peer:Peer title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic; - -messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector messages:Vector chats:Vector users:Vector pts:int = messages.ForumTopics; - -defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL; - -exportedContactToken#41bf109b url:string expires:int = ExportedContactToken; - -requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType; -requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; - -emojiListNotModified#481eadfa = EmojiList; -emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; - -emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; - -messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; -messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; - -textWithEntities#751f3146 text:string entities:Vector = TextWithEntities; - -messages.translateResult#33db32f8 result:Vector = messages.TranslatedText; - -autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings; - -autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException; - -account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector chats:Vector users:Vector = account.AutoSaveSettings; - -help.appConfigNotModified#7cde641d = help.AppConfig; -help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig; - -inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp; -inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp; - -botAppNotModified#5da674b7 = BotApp; -botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; - -messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp; - -inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; - -readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; - -inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist; - -exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector = ExportedChatlistInvite; - -chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite; - -chatlists.exportedInvites#10ab6dc7 invites:Vector chats:Vector users:Vector = chatlists.ExportedInvites; - -chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector already_peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; -chatlists.chatlistInvite#f10ece2f flags:# title_noanimate:flags.1?true title:TextWithEntities emoticon:flags.0?string peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; - -chatlists.chatlistUpdates#93bd878d missing_peers:Vector chats:Vector users:Vector = chatlists.ChatlistUpdates; - -bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo; - -messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote; -messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote; -messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector date:int = MessagePeerVote; - -storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector reactions_count:flags.4?int recent_viewers:flags.0?Vector = StoryViews; - -storyItemDeleted#51e6ee4f id:int = StoryItem; -storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true live:flags.9?true id:int date:int expire_date:int = StoryItem; -storyItem#edf164f1 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector = StoryItem; - -stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; -stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; - -stories.stories#63c3dd0a flags:# count:int stories:Vector pinned_to_top:flags.0?Vector chats:Vector users:Vector = stories.Stories; - -storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView; -storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView; -storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView; - -stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryViewsList; - -stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; - -inputReplyToMessage#869fbe10 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int = InputReplyTo; -inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; -inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; - -exportedStoryLink#3fc9053b link:string = ExportedStoryLink; - -storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; - -mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates; - -mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea; -inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea; -mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea; -mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea; -mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; -inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; -mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; -mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea; -mediaAreaStarGift#5787686d coordinates:MediaAreaCoordinates slug:string = MediaArea; - -peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; - -stories.peerStories#cae68768 stories:PeerStories chats:Vector users:Vector = stories.PeerStories; - -messages.webPage#fd5e12bd webpage:WebPage chats:Vector users:Vector = messages.WebPage; - -premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption; - -payments.checkedGiftCode#eb983f8f flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int days:int used_date:flags.1?int chats:Vector users:Vector = payments.CheckedGiftCode; - -payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; -payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo; - -prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; -prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway; - -boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost; - -premium.boostsList#86f8613c flags:# count:int boosts:Vector next_offset:flags.0?string users:Vector = premium.BoostsList; - -myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost; - -premium.myBoosts#9ae228e2 my_boosts:Vector chats:Vector users:Vector = premium.MyBoosts; - -premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector my_boost_slots:flags.2?Vector = premium.BoostsStatus; - -storyFwdHeader#b826e150 flags:# modified:flags.3?true from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader; - -postInteractionCountersMessage#e7058e7f msg_id:int views:int forwards:int reactions:int = PostInteractionCounters; -postInteractionCountersStory#8a480e27 story_id:int views:int forwards:int reactions:int = PostInteractionCounters; - -stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats; - -publicForwardMessage#1f2bf4a message:Message = PublicForward; -publicForwardStory#edf3add0 peer:Peer story:StoryItem = PublicForward; - -stats.publicForwards#93037e20 flags:# count:int forwards:Vector next_offset:flags.0?string chats:Vector users:Vector = stats.PublicForwards; - -peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor; -peerColorCollectible#b9c0639a flags:# collectible_id:long gift_emoji_id:long background_emoji_id:long accent_color:int colors:Vector dark_accent_color:flags.0?int dark_colors:flags.1?Vector = PeerColor; -inputPeerColorCollectible#b8ea86a9 collectible_id:long = PeerColor; - -help.peerColorSet#26219a58 colors:Vector = help.PeerColorSet; -help.peerColorProfileSet#767d61eb palette_colors:Vector bg_colors:Vector story_colors:Vector = help.PeerColorSet; - -help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption; - -help.peerColorsNotModified#2ba1f5ce = help.PeerColors; -help.peerColors#f8ed08 hash:int colors:Vector = help.PeerColors; - -storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction; -storyReactionPublicForward#bbab2643 message:Message = StoryReaction; -storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; - -stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; - -savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; -monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; - -messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; - -savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; - -messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; -messages.savedReactionTags#3259950a tags:Vector hash:long = messages.SavedReactionTags; - -outboxReadDate#3bb842ac date:int = OutboxReadDate; - -smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin; - -smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status; - -smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob; - -businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen; - -businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector = BusinessWorkHours; - -businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation; - -inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = InputBusinessRecipients; - -businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = BusinessRecipients; - -businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule; - -inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage; - -businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage; - -inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage; - -businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage; - -timezone#ff9289f5 id:string name:string utc_offset:int = Timezone; - -help.timezonesListNotModified#970708cc = help.TimezonesList; -help.timezonesList#7b74ed71 timezones:Vector hash:int = help.TimezonesList; - -quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply; - -inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut; -inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; - -messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; -messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; - -connectedBot#cd64636c flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights = ConnectedBot; - -account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; - -messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector = messages.DialogFilters; - -birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; - -botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; - -inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; - -businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro; - -messages.myStickers#faff629d count:int sets:Vector = messages.MyStickers; - -inputCollectibleUsername#e39460a9 username:string = InputCollectible; -inputCollectiblePhone#a2e214a4 phone:string = InputCollectible; - -fragment.collectibleInfo#6ebdff91 purchase_date:int currency:string amount:long crypto_currency:string crypto_amount:long url:string = fragment.CollectibleInfo; - -inputBusinessBotRecipients#c4e5921e flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = InputBusinessBotRecipients; - -businessBotRecipients#b88cf373 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = BusinessBotRecipients; - -contactBirthday#1d998733 contact_id:long birthday:Birthday = ContactBirthday; - -contacts.contactBirthdays#114ff30d contacts:Vector users:Vector = contacts.ContactBirthdays; - -missingInvitee#628c9224 flags:# premium_would_allow_invite:flags.0?true premium_required_for_pm:flags.1?true user_id:long = MissingInvitee; - -messages.invitedUsers#7f5defa6 updates:Updates missing_invitees:Vector = messages.InvitedUsers; - -inputBusinessChatLink#11679fa7 flags:# message:string entities:flags.0?Vector title:flags.1?string = InputBusinessChatLink; - -businessChatLink#b4ae666f flags:# link:string message:string entities:flags.0?Vector title:flags.1?string views:int = BusinessChatLink; - -account.businessChatLinks#ec43a2d1 links:Vector chats:Vector users:Vector = account.BusinessChatLinks; - -account.resolvedBusinessChatLinks#9a23af21 flags:# peer:Peer message:string entities:flags.0?Vector chats:Vector users:Vector = account.ResolvedBusinessChatLinks; - -requestedPeerUser#d62ff46a flags:# user_id:long first_name:flags.0?string last_name:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChat#7307544f flags:# chat_id:long title:flags.0?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChannel#8ba403e4 flags:# channel_id:long title:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; - -sponsoredMessageReportOption#430d3150 text:string option:bytes = SponsoredMessageReportOption; - -channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:Vector = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; - -reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; -reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; - -reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; - -availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; - -messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; -messages.availableEffects#bddb616e hash:int effects:Vector documents:Vector = messages.AvailableEffects; - -factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck; - -starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer; -starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer; -starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; -starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; -starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; -starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; -starsTransactionPeerAds#60682812 = StarsTransactionPeer; -starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; - -starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; - -starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true posts_search:flags.24?true stargift_prepaid_upgrade:flags.25?true stargift_drop_original_details:flags.26?true phonegroup_message:flags.27?true stargift_auction_bid:flags.28?true offer:flags.29?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction; - -payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; - -foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; - -stories.foundStories#e2de7737 flags:# count:int stories:Vector next_offset:flags.0?string chats:Vector users:Vector = stories.FoundStories; - -geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; - -starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; - -payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; - -payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; - -payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl; - -inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; - -starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption; - -bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector = bots.PopularAppBots; - -botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia; - -bots.previewInfo#ca71d64 media:Vector lang_codes:Vector = bots.PreviewInfo; - -starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing; - -starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true bot_canceled:flags.7?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string title:flags.4?string photo:flags.5?WebDocument invoice_slug:flags.6?string = StarsSubscription; - -messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; - -starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; - -starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; - -starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift; -starGiftUnique#569d64c9 flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int = StarGift; - -payments.starGiftsNotModified#a388a368 = payments.StarGifts; -payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; - -messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; - -reportResultChooseOption#f0e4e0b6 title:string options:Vector = ReportResult; -reportResultAddComment#6f09ac31 flags:# optional:flags.0?true option:bytes = ReportResult; -reportResultReported#8db33c4b = ReportResult; - -messages.botPreparedInlineMessage#8ecf0511 id:string expire_date:int = messages.BotPreparedInlineMessage; - -messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult peer_types:Vector cache_time:int users:Vector = messages.PreparedInlineMessage; - -botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings; - -starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram; - -connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef; - -payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector = payments.ConnectedStarRefBots; - -payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; - -starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount; -starsTonAmount#74aee3e0 amount:long = StarsAmount; - -messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers; -messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector = messages.FoundStickers; - -botVerifierSettings#b0cd6617 flags:# can_modify_custom_description:flags.1?true icon:long company:string custom_description:flags.0?string = BotVerifierSettings; - -botVerification#f93cd45c bot_id:long icon:long description:string = BotVerification; - -starGiftAttributeModel#39d99013 name:string document:Document rarity_permille:int = StarGiftAttribute; -starGiftAttributePattern#13acff19 name:string document:Document rarity_permille:int = StarGiftAttribute; -starGiftAttributeBackdrop#d93d859c name:string backdrop_id:int center_color:int edge_color:int pattern_color:int text_color:int rarity_permille:int = StarGiftAttribute; -starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute; - -payments.starGiftUpgradePreview#3de1dfed sample_attributes:Vector prices:Vector next_prices:Vector = payments.StarGiftUpgradePreview; - -users.users#62d706b8 users:Vector = users.Users; -users.usersSlice#315a4974 count:int users:Vector = users.Users; - -payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector users:Vector = payments.UniqueStarGift; - -messages.webPagePreview#8c9a88ac media:MessageMedia chats:Vector users:Vector = messages.WebPagePreview; - -savedStarGift#ead6805e flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int = SavedStarGift; - -payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; - -inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift; -inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift; -inputSavedStarGiftSlug#2085c238 slug:string = InputSavedStarGift; - -payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl; - -paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy; -paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy; -paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy; - -account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRevenue; - -requirementToContactEmpty#50a9839 = RequirementToContact; -requirementToContactPremium#e581e4e9 = RequirementToContact; -requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; - -businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; - -disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true disallow_stargifts_from_channels:flags.4?true = DisallowedGiftsSettings; - -sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; - -contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; -contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; - -starGiftAttributeIdModel#48aaae3c document_id:long = StarGiftAttributeId; -starGiftAttributeIdPattern#4a162433 document_id:long = StarGiftAttributeId; -starGiftAttributeIdBackdrop#1f01c757 backdrop_id:int = StarGiftAttributeId; - -starGiftAttributeCounter#2eb1b658 attribute:StarGiftAttributeId count:int = StarGiftAttributeCounter; - -payments.resaleStarGifts#947a12df flags:# count:int gifts:Vector next_offset:flags.0?string attributes:flags.1?Vector attributes_hash:flags.1?long chats:Vector counters:flags.2?Vector users:Vector = payments.ResaleStarGifts; - -stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount; - -pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion; - -todoItem#cba9a52f id:int title:TextWithEntities = TodoItem; - -todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector = TodoList; - -todoCompletion#221bb5e4 id:int completed_by:Peer date:int = TodoCompletion; - -suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost; - -starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating; - -starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection; - -payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; -payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; - -storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; - -stories.albumsNotModified#564edaeb = stories.Albums; -stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; - -searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; - -payments.uniqueStarGiftValueInfo#512fe446 flags:# last_sale_on_fragment:flags.1?true value_is_average:flags.6?true currency:string value:long initial_sale_date:int initial_sale_stars:long initial_sale_price:long last_sale_date:flags.0?int last_sale_price:flags.0?long floor_price:flags.2?long average_price:flags.3?long listed_count:flags.4?int fragment_listed_count:flags.5?int fragment_listed_url:flags.5?string = payments.UniqueStarGiftValueInfo; - -profileTabPosts#b98cd696 = ProfileTab; -profileTabGifts#4d4bd46a = ProfileTab; -profileTabMedia#72c64955 = ProfileTab; -profileTabFiles#ab339c00 = ProfileTab; -profileTabMusic#9f27d26e = ProfileTab; -profileTabVoice#e477092e = ProfileTab; -profileTabLinks#d3656499 = ProfileTab; -profileTabGifs#a2c0f695 = ProfileTab; - -users.savedMusicNotModified#e3878aa4 count:int = users.SavedMusic; -users.savedMusic#34a2f297 count:int documents:Vector = users.SavedMusic; - -account.savedMusicIdsNotModified#4fc81d6e = account.SavedMusicIds; -account.savedMusicIds#998d6636 ids:Vector = account.SavedMusicIds; - -payments.checkCanSendGiftResultOk#374fa7ad = payments.CheckCanSendGiftResult; -payments.checkCanSendGiftResultFail#d5e58274 reason:TextWithEntities = payments.CheckCanSendGiftResult; - -inputChatThemeEmpty#83268483 = InputChatTheme; -inputChatTheme#c93de95c emoticon:string = InputChatTheme; -inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme; - -starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice; - -groupCallMessage#1a8afc7e flags:# from_admin:flags.1?true id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage; - -groupCallDonor#ee430c85 flags:# top:flags.0?true my:flags.1?true peer_id:flags.3?Peer stars:long = GroupCallDonor; - -phone.groupCallStars#9d1dbd26 total_stars:long top_donors:Vector chats:Vector users:Vector = phone.GroupCallStars; - -recentStory#711d692d flags:# live:flags.0?true max_id:flags.1?int = RecentStory; - -auctionBidLevel#310240cc pos:int amount:long date:int = AuctionBidLevel; - -starGiftAuctionStateNotModified#fe333952 = StarGiftAuctionState; -starGiftAuctionState#771a4e66 version:int start_date:int end_date:int min_bid_amount:long bid_levels:Vector top_bidders:Vector next_round_at:int last_gift_num:int gifts_left:int current_round:int total_rounds:int rounds:Vector = StarGiftAuctionState; -starGiftAuctionStateFinished#972dabbf flags:# start_date:int end_date:int average_price:long listed_count:flags.0?int fragment_listed_count:flags.1?int fragment_listed_url:flags.1?string = StarGiftAuctionState; - -starGiftAuctionUserState#2eeed1c4 flags:# returned:flags.1?true bid_amount:flags.0?long bid_date:flags.0?int min_bid_amount:flags.0?long bid_peer:flags.0?Peer acquired_count:int = StarGiftAuctionUserState; - -payments.starGiftAuctionState#6b39f4ec gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState timeout:int users:Vector chats:Vector = payments.StarGiftAuctionState; - -starGiftAuctionAcquiredGift#42b00348 flags:# name_hidden:flags.0?true peer:Peer date:int bid_amount:long round:int pos:int message:flags.1?TextWithEntities gift_num:flags.2?int = StarGiftAuctionAcquiredGift; - -payments.starGiftAuctionAcquiredGifts#7d5bd1f0 gifts:Vector users:Vector chats:Vector = payments.StarGiftAuctionAcquiredGifts; - -starGiftActiveAuctionState#d31bc45d gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState = StarGiftActiveAuctionState; - -payments.starGiftActiveAuctionsNotModified#db33dad0 = payments.StarGiftActiveAuctions; -payments.starGiftActiveAuctions#aef6abbc auctions:Vector users:Vector chats:Vector = payments.StarGiftActiveAuctions; - -inputStarGiftAuction#2e16c98 gift_id:long = InputStarGiftAuction; -inputStarGiftAuctionSlug#7ab58308 slug:string = InputStarGiftAuction; - -passkey#98613ebf flags:# id:string name:string date:int software_emoji_id:flags.0?long last_usage_date:flags.1?int = Passkey; - -account.passkeys#f8e0aa1c passkeys:Vector = account.Passkeys; - -account.passkeyRegistrationOptions#e16b5ce1 options:DataJSON = account.PasskeyRegistrationOptions; - -auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions; - -inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse; -inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse; - -inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential; -inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential; - -starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground; - -starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound; -starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound; - -payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector = payments.StarGiftUpgradeAttributes; - -messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome; - -messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo; -messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector plays_left:flags.0?int = messages.EmojiGameInfo; - ----functions--- - -invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; -invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; -initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; -invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; -invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; -invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; -invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; -invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; -invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; -invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X; -invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X; - -auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; -auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; -auth.signIn#8d52a951 flags:# phone_number:string phone_code_hash:string phone_code:flags.0?string email_verification:flags.1?EmailVerification = auth.Authorization; -auth.logOut#3e72ba19 = auth.LoggedOut; -auth.resetAuthorizations#9fab0d1a = Bool; -auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; -auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; -auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; -auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; -auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; -auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; -auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; -auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode; -auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; -auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; -auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; -auth.acceptLoginToken#e894ad4d token:bytes = Authorization; -auth.checkRecoveryPassword#d36bf79 code:string = Bool; -auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; -auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool; -auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; -auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; -auth.checkPaidAuth#56e59f9c phone_number:string phone_code_hash:string form_id:long = auth.SentCode; -auth.initPasskeyLogin#518ad0b7 api_id:int api_hash:string = auth.PasskeyLoginOptions; -auth.finishPasskeyLogin#9857ad07 flags:# credential:InputPasskeyCredential from_dc_id:flags.0?int from_auth_key_id:flags.0?long = auth.Authorization; - -account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; -account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; -account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; -account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; -account.resetNotifySettings#db7e1747 = Bool; -account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; -account.updateStatus#6628562c offline:Bool = Bool; -account.getWallPapers#7967d36 hash:long = account.WallPapers; -account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool; -account.checkUsername#2714d86c username:string = Bool; -account.updateUsername#3e0bdd7c username:string = User; -account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; -account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; -account.deleteAccount#a2c0cf74 flags:# reason:string password:flags.0?InputCheckPasswordSRP = Bool; -account.getAccountTTL#8fc711d = AccountDaysTTL; -account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; -account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; -account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; -account.updateDeviceLocked#38df3532 period:int = Bool; -account.getAuthorizations#e320c158 = account.Authorizations; -account.resetAuthorization#df77f3bc hash:long = Bool; -account.getPassword#548a30f5 = account.Password; -account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; -account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; -account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; -account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; -account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; -account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; -account.resetWebAuthorization#2d01b9ef hash:long = Bool; -account.resetWebAuthorizations#682d2594 = Bool; -account.getAllSecureValues#b288bc7d = Vector; -account.getSecureValue#73665bc2 types:Vector = Vector; -account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; -account.deleteSecureValue#b880bc4b types:Vector = Bool; -account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm; -account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; -account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; -account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; -account.sendVerifyEmailCode#98e037bb purpose:EmailVerifyPurpose email:string = account.SentEmailCode; -account.verifyEmail#32da4cf purpose:EmailVerifyPurpose verification:EmailVerification = account.EmailVerified; -account.initTakeoutSession#8ef3eab0 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?long = account.Takeout; -account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; -account.confirmPasswordEmail#8fdf1920 code:string = Bool; -account.resendPasswordEmail#7a7f2a15 = Bool; -account.cancelPasswordEmail#c1cbd5b6 = Bool; -account.getContactSignUpNotification#9f07c728 = Bool; -account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; -account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true compare_stories:flags.2?true peer:flags.0?InputNotifyPeer = Updates; -account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; -account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; -account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; -account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; -account.resetWallPapers#bb3b9804 = Bool; -account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; -account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; -account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document; -account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool; -account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool; -account.getTheme#3a5869ec format:string theme:InputTheme = Theme; -account.getThemes#7206e458 format:string hash:long = account.Themes; -account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool; -account.getContentSettings#8b9b4dae = account.ContentSettings; -account.getMultiWallPapers#65ad71dc wallpapers:Vector = Vector; -account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings; -account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; -account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; -account.resetPassword#9308ce1b = account.ResetPasswordResult; -account.declinePasswordReset#4c9409f6 = Bool; -account.getChatThemes#d638de89 hash:long = account.Themes; -account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; -account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; -account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones; -account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone; -account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document; -account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool; -account.getDefaultEmojiStatuses#d6753386 hash:long = account.EmojiStatuses; -account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; -account.clearRecentEmojiStatuses#18201aae = Bool; -account.reorderUsernames#ef500eab order:Vector = Bool; -account.toggleUsername#58d6b376 username:string active:Bool = Bool; -account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList; -account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList; -account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings; -account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool; -account.deleteAutoSaveExceptions#53bc0020 = Bool; -account.invalidateSignInCodes#ca8ae8ba codes:Vector = Bool; -account.updateColor#684d214e flags:# for_profile:flags.1?true color:flags.2?PeerColor = Bool; -account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList; -account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses; -account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList; -account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool; -account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool; -account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool; -account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool; -account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates; -account.getConnectedBots#4ea4c80f = account.ConnectedBots; -account.getBotBusinessConnection#76a86270 connection_id:string = Updates; -account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool; -account.toggleConnectedBotPaused#646e1097 peer:InputPeer paused:Bool = Bool; -account.disablePeerConnectedBot#5e437ed9 peer:InputPeer = Bool; -account.updateBirthday#cc6e0c11 flags:# birthday:flags.0?Birthday = Bool; -account.createBusinessChatLink#8851e68e link:InputBusinessChatLink = BusinessChatLink; -account.editBusinessChatLink#8c3410af slug:string link:InputBusinessChatLink = BusinessChatLink; -account.deleteBusinessChatLink#60073674 slug:string = Bool; -account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks; -account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks; -account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool; -account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool; -account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings; -account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings; -account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses; -account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue; -account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool; -account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool; -account.saveMusic#b26732a9 flags:# unsave:flags.0?true id:InputDocument after_id:flags.1?InputDocument = Bool; -account.getSavedMusicIds#e09d5faf hash:long = account.SavedMusicIds; -account.getUniqueGiftChatThemes#e42ce9c9 offset:string limit:int hash:long = account.ChatThemes; -account.initPasskeyRegistration#429547e8 = account.PasskeyRegistrationOptions; -account.registerPasskey#55b41fd6 credential:InputPasskeyCredential = Passkey; -account.getPasskeys#ea1f0c52 = account.Passkeys; -account.deletePasskey#f5b5563f id:string = Bool; - -users.getUsers#d91a548 id:Vector = Vector; -users.getFullUser#b60f5918 id:InputUser = users.UserFull; -users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; -users.getRequirementsToContact#d89a83a3 id:Vector = Vector; -users.getSavedMusic#788d7fe3 id:InputUser offset:int limit:int hash:long = users.SavedMusic; -users.getSavedMusicByID#7573a4e9 id:InputUser documents:Vector = users.SavedMusic; -users.suggestBirthday#fc533372 id:InputUser birthday:Birthday = Updates; - -contacts.getContactIDs#7adc669d hash:long = Vector; -contacts.getStatuses#c4a353ee = Vector; -contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; -contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; -contacts.deleteContacts#96a0e00 id:Vector = Updates; -contacts.deleteByPhones#1013fd9e phones:Vector = Bool; -contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; -contacts.search#11f812d8 q:string limit:int = contacts.Found; -contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer; -contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true offset:int limit:int hash:long = contacts.TopPeers; -contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; -contacts.resetSaved#879537f1 = Bool; -contacts.getSaved#82f1e39f = Vector; -contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; -contacts.addContact#d9ba2e54 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string note:flags.1?TextWithEntities = Updates; -contacts.acceptContact#f831a20f id:InputUser = Updates; -contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates; -contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates; -contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer; -contacts.exportContactToken#f8654027 = ExportedContactToken; -contacts.importContactToken#13005788 token:string = User; -contacts.editCloseFriends#ba6705f0 id:Vector = Bool; -contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector limit:int = Bool; -contacts.getBirthdays#daeda864 = contacts.ContactBirthdays; -contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers; -contacts.updateContactNote#139f63fb id:InputUser note:TextWithEntities = Bool; - -messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; -messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; -messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; -messages.receivedMessages#5a954c0 max_id:int = Vector; -messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; -messages.sendMessage#545cd15a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.sendMedia#330e77f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.forwardMessages#13704a7c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; -messages.reportSpam#cf1592db peer:InputPeer = Bool; -messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; -messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; -messages.getChats#49e9528f id:Vector = messages.Chats; -messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; -messages.editChatTitle#73783ffd chat_id:long title:string = Updates; -messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates; -messages.addChatUser#cbc6d107 chat_id:long user_id:InputUser fwd_limit:int = messages.InvitedUsers; -messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates; -messages.createChat#92ceddd4 flags:# users:Vector title:string ttl_period:flags.0?int = messages.InvitedUsers; -messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; -messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; -messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; -messages.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool; -messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; -messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; -messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; -messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.receivedQueue#55a5bb66 max_qts:int = Vector; -messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; -messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; -messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers; -messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers; -messages.getWebPagePreview#570d6f6f flags:# message:string entities:flags.3?Vector = messages.WebPagePreview; -messages.exportChatInvite#a455de90 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string subscription_pricing:flags.5?StarsSubscriptionPricing = ExportedChatInvite; -messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; -messages.importChatInvite#6c50051c hash:string = Updates; -messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet; -messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; -messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; -messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; -messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool = messages.MessageViews; -messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; -messages.migrateChat#a2875319 chat_id:long = Updates; -messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true groups_only:flags.2?true users_only:flags.3?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; -messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Bool; -messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document; -messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; -messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; -messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; -messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool; -messages.sendInlineBotResult#c0cf7646 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut allow_paid_stars:flags.21?long = Updates; -messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; -messages.editMessage#51e842e1 flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.15?int schedule_repeat_period:flags.18?int quick_reply_shortcut_id:flags.17?int = Updates; -messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; -messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; -messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; -messages.saveDraft#54ae308e flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost = Bool; -messages.getAllDrafts#6a3f8d65 = Updates; -messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; -messages.readFeaturedStickers#5b118126 id:Vector = Bool; -messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; -messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; -messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; -messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers; -messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; -messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; -messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; -messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; -messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; -messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; -messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats; -messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage; -messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; -messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; -messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; -messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; -messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia; -messages.sendScreenshotNotification#a1405817 peer:InputPeer reply_to:InputReplyTo random_id:long = Updates; -messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers; -messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; -messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; -messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; -messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSplitRanges#1cff7e08 = Vector; -messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool; -messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector; -messages.clearAllDrafts#7e58ee9c = Bool; -messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates; -messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; -messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates; -messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; -messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; -messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; -messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; -messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; -messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; -messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; -messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector = Vector; -messages.requestUrlAuth#198fb446 flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; -messages.acceptUrlAuth#b12c7125 flags:# write_allowed:flags.0?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; -messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; -messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages; -messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; -messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector = Updates; -messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector = Updates; -messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList; -messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector = Bool; -messages.getDialogFilters#efd48c89 = messages.DialogFilters; -messages.getSuggestedDialogFilters#a29cd42c = Vector; -messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool; -messages.updateDialogFiltersOrder#c563c1e4 order:Vector = Bool; -messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers; -messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; -messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; -messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.deleteChat#5bd0ee50 chat_id:long = Bool; -messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; -messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; -messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport; -messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; -messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; -messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; -messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; -messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite; -messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; -messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; -messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; -messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true subscription_expired:flags.3?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; -messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; -messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; -messages.setChatTheme#81202c9 peer:InputPeer theme:InputChatTheme = Updates; -messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector; -messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; -messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; -messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; -messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; -messages.toggleNoForwards#b11eafa2 peer:InputPeer enabled:Bool = Updates; -messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; -messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector = Updates; -messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector = Updates; -messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList; -messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int paid_enabled:flags.1?Bool = Updates; -messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; -messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool; -messages.translateText#63183030 flags:# peer:flags.0?InputPeer id:flags.0?Vector text:flags.1?Vector to_lang:string = messages.TranslatedText; -messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages; -messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; -messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; -messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; -messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; -messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; -messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true fullscreen:flags.8?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; -messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; -messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; -messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool; -messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector = Vector; -messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers; -messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers; -messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer = Bool; -messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions; -messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions; -messages.clearRecentReactions#9dfeefb4 = Bool; -messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector = Updates; -messages.setDefaultHistoryTTL#9eb51445 period:int = Bool; -messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL; -messages.sendBotRequestedPeer#91b2d060 peer:InputPeer msg_id:int button_id:int requested_peers:Vector = Updates; -messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups; -messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups; -messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups; -messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; -messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; -messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; -messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; -messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; -messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; -messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; -messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; -messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags; -messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; -messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; -messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate; -messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies; -messages.reorderQuickReplies#60331907 order:Vector = Bool; -messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool; -messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool; -messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool; -messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector hash:long = messages.Messages; -messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vector random_id:Vector = Updates; -messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; -messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; -messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; -messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; -messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; -messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; -messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; -messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; -messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates; -messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool; -messages.getPaidReactionPrivacy#472455aa = Updates; -messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; -messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; -messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; -messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages; -messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; -messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; -messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; -messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; -messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; -messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; -messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; -messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; -messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates; -messages.getForumTopics#3ba47bff flags:# peer:InputPeer q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; -messages.getForumTopicsByID#af0a4a08 peer:InputPeer topics:Vector = messages.ForumTopics; -messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates; -messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates; -messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector = Updates; -messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; -messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory; -messages.getEmojiGameInfo#fb7e8ca7 = messages.EmojiGameInfo; -messages.summarizeText#9d4104e2 flags:# peer:InputPeer id:int to_lang:flags.0?string = TextWithEntities; - -updates.getState#edd4882a = updates.State; -updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; -updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; - -photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo; -photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo; -photos.deletePhotos#87cf7f2f id:Vector = Vector; -photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; -photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo; - -upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; -upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File; -upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; -upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; -upload.getCdnFile#395f69da file_token:bytes offset:long limit:int = upload.CdnFile; -upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; -upload.getCdnFileHashes#91dc3f31 file_token:bytes offset:long = Vector; -upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector; - -help.getConfig#c4f9186b = Config; -help.getNearestDc#1fb33026 = NearestDc; -help.getAppUpdate#522d5a7d source:string = help.AppUpdate; -help.getInviteText#4d392343 = help.InviteText; -help.getSupport#9cdf08cd = help.Support; -help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; -help.getCdnConfig#52029342 = CdnConfig; -help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; -help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; -help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; -help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; -help.getAppConfig#61e3f854 hash:int = help.AppConfig; -help.saveAppLog#6f02f748 events:Vector = Bool; -help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; -help.getSupportName#d360e72c = help.SupportName; -help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; -help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; -help.getPromoData#c0977421 = help.PromoData; -help.hidePromoData#1e251c95 peer:InputPeer = Bool; -help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; -help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; -help.getPremiumPromo#b81b93d4 = help.PremiumPromo; -help.getPeerColors#da80f42f hash:int = help.PeerColors; -help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors; -help.getTimezonesList#49b30240 hash:int = help.TimezonesList; - -channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; -channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; -channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector = Bool; -channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; -channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; -channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; -channels.getChannels#a7f6bbb id:Vector = messages.Chats; -channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; -channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates; -channels.editAdmin#d33c8902 channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:string = Updates; -channels.editTitle#566decd0 channel:InputChannel title:string = Updates; -channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; -channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; -channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; -channels.joinChannel#24b524c5 channel:InputChannel = Updates; -channels.leaveChannel#f836aa95 channel:InputChannel = Updates; -channels.inviteToChannel#c9e33d54 channel:InputChannel users:Vector = messages.InvitedUsers; -channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; -channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; -channels.toggleSignatures#418d549c flags:# signatures_enabled:flags.0?true profiles_enabled:flags.1?true channel:InputChannel = Updates; -channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_personal:flags.2?true = messages.Chats; -channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; -channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; -channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; -channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates; -channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; -channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; -channels.getGroupsForDiscussion#f5dad378 = messages.Chats; -channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; -channels.editCreator#8f38cd1f channel:InputChannel user_id:InputUser password:InputCheckPasswordSRP = Updates; -channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; -channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; -channels.getInactiveChannels#11e831ee = messages.InactiveChats; -channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; -channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true for_live_stories:flags.1?true peer:InputPeer = channels.SendAsPeers; -channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory; -channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates; -channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates; -channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector = Bool; -channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool; -channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool; -channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates; -channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates; -channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool; -channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; -channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates; -channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; -channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats; -channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates; -channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates; -channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; -channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; -channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; -channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; -channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; -channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood; -channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool; - -bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; -bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; -bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector = Bool; -bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool; -bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector; -bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool; -bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton; -bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool; -bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool; -bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool; -bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo; -bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector = Bool; -bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool; -bots.canSendMessage#1359f4e6 bot:InputUser = Bool; -bots.allowSendMessage#f132e3ef bot:InputUser = Updates; -bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; -bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; -bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia; -bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia; -bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector = Bool; -bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector = Bool; -bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo; -bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; -bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool; -bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; -bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; -bots.getAdminedBots#b0711d83 = Vector; -bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram; -bots.setCustomVerification#8b89dfbd flags:# enabled:flags.1?true bot:flags.0?InputUser peer:InputPeer custom_description:flags.2?string = Bool; -bots.getBotRecommendations#a1b70815 bot:InputUser = users.Users; - -payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; -payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; -payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; -payments.sendPaymentForm#2d03522f flags:# form_id:long invoice:InputInvoice requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; -payments.getSavedInfo#227d824b = payments.SavedInfo; -payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; -payments.getBankCardData#2e79d779 number:string = payments.BankCardData; -payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; -payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; -payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; -payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector; -payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; -payments.applyGiftCode#f6e26854 slug:string = Updates; -payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; -payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; -payments.getStarsTopupOptions#c00ec7d3 = Vector; -payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus; -payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; -payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult; -payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; -payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats; -payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; -payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; -payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector = payments.StarsStatus; -payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; -payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; -payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; -payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; -payments.getStarsGiveawayOptions#bd1efd3e = Vector; -payments.getStarGifts#c4563590 hash:int = payments.StarGifts; -payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool; -payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool; -payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; -payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; -payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots; -payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; -payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview; -payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates; -payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates; -payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift; -payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_unique:flags.4?true sort_by_value:flags.5?true exclude_upgradable:flags.7?true exclude_unupgradable:flags.8?true peer_color_available:flags.9?true exclude_hosted:flags.10?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts; -payments.getSavedStarGift#b455a106 stargift:Vector = payments.SavedStarGifts; -payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; -payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; -payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; -payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; -payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; -payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; -payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; -payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; -payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector = Bool; -payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool; -payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections; -payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo; -payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult; -payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState; -payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts; -payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions; -payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates; -payments.sendStarGiftOffer#8fb86b41 flags:# peer:InputPeer slug:string price:StarsAmount duration:int random_id:long allow_paid_stars:flags.0?long = Updates; -payments.getStarGiftUpgradeAttributes#6d038b58 gift_id:long = payments.StarGiftUpgradeAttributes; - -stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; -stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; -stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; -stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; -stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet; -stickers.checkShortName#284b3639 short_name:string = Bool; -stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName; -stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet; -stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet; -stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool; -stickers.replaceSticker#4696459a sticker:InputDocument new_sticker:InputStickerSetItem = messages.StickerSet; - -phone.getCallConfig#55451fa9 = DataJSON; -phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; -phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; -phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; -phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; -phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; -phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; -phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; -phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates; -phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; -phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; -phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; -phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates; -phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; -phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; -phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; -phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; -phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; -phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; -phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; -phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; -phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; -phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; -phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; -phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates; -phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates; -phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels; -phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl; -phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool; -phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates; -phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector block:bytes = Updates; -phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates; -phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates; -phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates; -phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates; -phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates; -phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool; -phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector = Updates; -phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates; -phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars; -phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool; - -langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; -langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; -langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; -langpack.getLanguages#42c6978f lang_pack:string = Vector; -langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; - -folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; - -stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats; -stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; -stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; -stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards; -stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; -stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; -stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards; - -chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; -chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; -chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector = ExportedChatlistInvite; -chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites; -chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite; -chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector = Updates; -chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates; -chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector = Updates; -chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool; -chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector; -chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector = Updates; - -stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount; -stories.sendStory#737fc2ec flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector = Updates; -stories.editStory#b583ba46 flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector = Updates; -stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; -stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; -stories.getAllStories#eeb0d625 flags:# next:flags.1?true hidden:flags.2?true state:flags.0?string = stories.AllStories; -stories.getPinnedStories#5821a5dc peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector = stories.Stories; -stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool; -stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector; -stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector = Bool; -stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList; -stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector = stories.StoryViews; -stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; -stories.report#19d8eb45 peer:InputPeer id:Vector option:bytes message:string = ReportResult; -stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates; -stories.sendReaction#7fd736b2 flags:# add_to_recent:flags.0?true peer:InputPeer story_id:int reaction:Reaction = Updates; -stories.getPeerStories#2c4ada50 peer:InputPeer = stories.PeerStories; -stories.getAllReadPeerStories#9b5ae7f9 = Updates; -stories.getPeerMaxIDs#78499170 id:Vector = Vector; -stories.getChatsToSend#a56a8b60 = messages.Chats; -stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; -stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; -stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; -stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories; -stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector = StoryAlbum; -stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector add_stories:flags.2?Vector order:flags.3?Vector = StoryAlbum; -stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector = Bool; -stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool; -stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums; -stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories; -stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates; - -premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; -premium.getMyBoosts#be77b4a = premium.MyBoosts; -premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; -premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; -premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; - -smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin; -smsjobs.join#a74ece2d = Bool; -smsjobs.leave#9898ad73 = Bool; -smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool; -smsjobs.getStatus#10a698e8 = smsjobs.Status; -smsjobs.getSmsJob#778d902f job_id:string = SmsJob; -smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; - -fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; - -// LAYER 221 diff --git a/internal/compat/layerwire/_schema/layer-222.tl b/internal/compat/layerwire/_schema/layer-222.tl deleted file mode 100644 index 77968bd2..00000000 --- a/internal/compat/layerwire/_schema/layer-222.tl +++ /dev/null @@ -1,2906 +0,0 @@ -boolFalse#bc799737 = Bool; -boolTrue#997275b5 = Bool; - -true#3fedd339 = True; - -vector#1cb5c415 {t:Type} # [ t ] = Vector t; - -error#c4b9f9bb code:int text:string = Error; - -null#56730bcc = Null; - -inputPeerEmpty#7f3b18ea = InputPeer; -inputPeerSelf#7da07ec9 = InputPeer; -inputPeerChat#35a95cb9 chat_id:long = InputPeer; -inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; -inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer; -inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer; -inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer; - -inputUserEmpty#b98886cf = InputUser; -inputUserSelf#f7c1b13f = InputUser; -inputUser#f21158c6 user_id:long access_hash:long = InputUser; -inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser; - -inputPhoneContact#6a1dc4be flags:# client_id:long phone:string first_name:string last_name:string note:flags.0?TextWithEntities = InputContact; - -inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; -inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; -inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile; - -inputMediaEmpty#9664f57f = InputMedia; -inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; -inputMediaPhoto#b3ba0635 flags:# spoiler:flags.1?true id:InputPhoto ttl_seconds:flags.0?int = InputMedia; -inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; -inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; -inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; -inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; -inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; -inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; -inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; -inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; -inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector solution:flags.1?string solution_entities:flags.1?Vector = InputMedia; -inputMediaDice#e66fbf7b emoticon:string = InputMedia; -inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; -inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; -inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; -inputMediaTodo#9fc55fde todo:TodoList = InputMedia; -inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia; - -inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; -inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; -inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; - -inputGeoPointEmpty#e4c123d6 = InputGeoPoint; -inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint; - -inputPhotoEmpty#1cd7bf0d = InputPhoto; -inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; - -inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; -inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; -inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; -inputTakeoutFileLocation#29be5899 = InputFileLocation; -inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; -inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; -inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; -inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; - -peerUser#59511722 user_id:long = Peer; -peerChat#36c6019a chat_id:long = Peer; -peerChannel#a2a5371e channel_id:long = Peer; - -storage.fileUnknown#aa963b05 = storage.FileType; -storage.filePartial#40bc6f52 = storage.FileType; -storage.fileJpeg#7efe0e = storage.FileType; -storage.fileGif#cae1aadf = storage.FileType; -storage.filePng#a4f63c0 = storage.FileType; -storage.filePdf#ae1e508d = storage.FileType; -storage.fileMp3#528a0677 = storage.FileType; -storage.fileMov#4b09ebbc = storage.FileType; -storage.fileMp4#b3cea0e4 = storage.FileType; -storage.fileWebp#1081464c = storage.FileType; - -userEmpty#d3bc4b7a id:long = User; -user#31774388 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true bot_business:flags2.11?true bot_has_main_app:flags2.13?true bot_forum_view:flags2.16?true bot_forum_can_manage_topics:flags2.17?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?RecentStory color:flags2.8?PeerColor profile_color:flags2.9?PeerColor bot_active_users:flags2.12?int bot_verification_icon:flags2.14?long send_paid_messages_stars:flags2.15?long = User; - -userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; - -userStatusEmpty#9d05049 = UserStatus; -userStatusOnline#edb93949 expires:int = UserStatus; -userStatusOffline#8c703f was_online:int = UserStatus; -userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus; -userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus; -userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; - -chatEmpty#29562865 id:long = Chat; -chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; -chatForbidden#6592a1a7 id:long title:string = Chat; -channel#1c32b11c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?RecentStory color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat; -channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true monoforum:flags.10?true id:long access_hash:long title:string until_date:flags.16?int = Chat; - -chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#e4e0b29d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab = ChatFull; - -chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; -chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; -chatParticipantAdmin#a0933f5b user_id:long inviter_id:long date:int = ChatParticipant; - -chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants; -chatParticipants#3cbc93f8 chat_id:long participants:Vector version:int = ChatParticipants; - -chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; - -messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; -message#9cb490e9 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string = Message; -messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; - -messageMediaEmpty#3ded6320 = MessageMedia; -messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; -messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; -messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; -messageMediaUnsupported#9f84f49e = MessageMedia; -messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; -messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; -messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; -messageMediaGame#fdb19008 game:Game = MessageMedia; -messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia; -messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia; -messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; -messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia; -messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; -messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; -messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; -messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; -messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector = MessageMedia; -messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia; - -messageActionEmpty#b6aef7b0 = MessageAction; -messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; -messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; -messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; -messageActionChatDeletePhoto#95e3fbef = MessageAction; -messageActionChatAddUser#15cefd00 users:Vector = MessageAction; -messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction; -messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction; -messageActionChannelCreate#95d2ac92 title:string = MessageAction; -messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction; -messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction; -messageActionPinMessage#94bd38ed = MessageAction; -messageActionHistoryClear#9fbab604 = MessageAction; -messageActionGameScore#92a72876 game_id:long score:int = MessageAction; -messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction; -messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction; -messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; -messageActionScreenshotTaken#4792929b = MessageAction; -messageActionCustomAction#fae69f56 message:string = MessageAction; -messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction; -messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; -messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; -messageActionContactSignUp#f3f25f76 = MessageAction; -messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction; -messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; -messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector = MessageAction; -messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction; -messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; -messageActionSetChatTheme#b91bbd3a theme:ChatTheme = MessageAction; -messageActionChatJoinedByRequest#ebbca3cb = MessageAction; -messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction; -messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction; -messageActionGiftPremium#48e91302 flags:# currency:string amount:long days:int crypto_currency:flags.0?string crypto_amount:flags.0?long message:flags.1?TextWithEntities = MessageAction; -messageActionTopicCreate#d999256 flags:# title_missing:flags.1?true title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction; -messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction; -messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; -messageActionRequestedPeer#31518e9b button_id:int peers:Vector = MessageAction; -messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; -messageActionGiftCode#31c48347 flags:# via_giveaway:flags.0?true unclaimed:flags.5?true boost_peer:flags.1?Peer days:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long message:flags.4?TextWithEntities = MessageAction; -messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction; -messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction; -messageActionBoostApply#cc02aa6d boosts:int = MessageAction; -messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; -messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; -messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; -messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; -messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction; -messageActionStarGiftUnique#e6c31522 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true craft:flags.16?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long can_craft_at:flags.15?int = MessageAction; -messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; -messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; -messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; -messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; -messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; -messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction; -messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction; -messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction; -messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction; -messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction; -messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction; -messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction; -messageActionNewCreatorPending#b07ed085 new_creator_id:long = MessageAction; -messageActionChangeCreator#e188503b new_creator_id:long = MessageAction; - -dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; -dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; - -photoEmpty#2331b22d id:long = Photo; -photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = Photo; - -photoSizeEmpty#e17e23c type:string = PhotoSize; -photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; -photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; -photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; -photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; -photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; - -geoPointEmpty#1117dd5f = GeoPoint; -geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; - -auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; -auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; -auth.sentCodePaymentRequired#e0955a3c store_product:string phone_code_hash:string support_email_address:string support_email_subject:string currency:string amount:long = auth.SentCode; - -auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; -auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; - -auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; - -inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; -inputNotifyUsers#193b4417 = InputNotifyPeer; -inputNotifyChats#4a95e84e = InputNotifyPeer; -inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; -inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer; - -inputPeerNotifySettings#cacb6ae2 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_sound:flags.8?NotificationSound = InputPeerNotifySettings; - -peerNotifySettings#99622c0c flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_ios_sound:flags.8?NotificationSound stories_android_sound:flags.9?NotificationSound stories_other_sound:flags.10?NotificationSound = PeerNotifySettings; - -peerSettings#f47741f7 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true business_bot_paused:flags.11?true business_bot_can_reply:flags.12?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int business_bot_id:flags.13?long business_bot_manage_url:flags.13?string charge_paid_message_stars:flags.14?long registration_month:flags.15?string phone_country:flags.16?string name_change_date:flags.17?int photo_change_date:flags.18?int = PeerSettings; - -wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; -wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; - -inputReportReasonSpam#58dbcab8 = ReportReason; -inputReportReasonViolence#1e22c78d = ReportReason; -inputReportReasonPornography#2e59d922 = ReportReason; -inputReportReasonChildAbuse#adf44ee3 = ReportReason; -inputReportReasonOther#c1e4a2b1 = ReportReason; -inputReportReasonCopyright#9b89f93a = ReportReason; -inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; -inputReportReasonFake#f5ddd6e7 = ReportReason; -inputReportReasonIllegalDrugs#a8eb2be = ReportReason; -inputReportReasonPersonalDetails#9ec7863d = ReportReason; - -userFull#a02bc13e flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme:flags.15?ChatTheme private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int main_tab:flags2.20?ProfileTab saved_music:flags2.21?Document note:flags2.22?TextWithEntities = UserFull; - -contact#145ade0b user_id:long mutual:Bool = Contact; - -importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; - -contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; - -contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; -contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; - -contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; - -contacts.blocked#ade1591 blocked:Vector chats:Vector users:Vector = contacts.Blocked; -contacts.blockedSlice#e1664194 count:int blocked:Vector chats:Vector users:Vector = contacts.Blocked; - -messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; - -messages.messages#1d73e7ea messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#5f206716 flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesNotModified#74535f21 count:int = messages.Messages; - -messages.chats#64ff9fd5 chats:Vector = messages.Chats; -messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; - -messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; - -messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; - -inputMessagesFilterEmpty#57e2f66c = MessagesFilter; -inputMessagesFilterPhotos#9609a51c = MessagesFilter; -inputMessagesFilterVideo#9fc00e65 = MessagesFilter; -inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; -inputMessagesFilterDocument#9eddf188 = MessagesFilter; -inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; -inputMessagesFilterGif#ffc86587 = MessagesFilter; -inputMessagesFilterVoice#50f5c392 = MessagesFilter; -inputMessagesFilterMusic#3751b49e = MessagesFilter; -inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; -inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; -inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; -inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; -inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; -inputMessagesFilterGeo#e7026d0d = MessagesFilter; -inputMessagesFilterContacts#e062db83 = MessagesFilter; -inputMessagesFilterPinned#1bb00451 = MessagesFilter; - -updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; -updateMessageID#4e90bfd6 id:int random_id:long = Update; -updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; -updateUserTyping#2a17bf5c flags:# user_id:long top_msg_id:flags.0?int action:SendMessageAction = Update; -updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update; -updateChatParticipants#7761198 participants:ChatParticipants = Update; -updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; -updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector = Update; -updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update; -updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; -updateEncryptedChatTyping#1710f156 chat_id:int = Update; -updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; -updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; -updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update; -updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update; -updateDcOptions#8e5e9873 dc_options:Vector = Update; -updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; -updateServiceNotification#ebe46819 flags:# popup:flags.0?true invert_media:flags.2?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; -updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; -updateUserPhone#5492a13 user_id:long phone:string = Update; -updateReadHistoryInbox#9e84bc99 flags:# folder_id:flags.0?int peer:Peer top_msg_id:flags.1?int max_id:int still_unread_count:int pts:int pts_count:int = Update; -updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; -updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; -updateReadMessagesContents#f8227181 flags:# messages:Vector pts:int pts_count:int date:flags.0?int = Update; -updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; -updateChannel#635b4c09 channel_id:long = Update; -updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update; -updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; -updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; -updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; -updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Update; -updateStickerSets#31c24808 flags:# masks:flags.0?true emojis:flags.1?true = Update; -updateSavedGifs#9375341e = Update; -updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; -updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; -updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; -updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; -updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; -updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update; -updateReadFeaturedStickers#571d2742 = Update; -updateRecentStickers#9a422c20 = Update; -updateConfig#a229dd06 = Update; -updatePtsChanged#3354678f = Update; -updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update; -updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; -updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; -updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; -updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; -updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update; -updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; -updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; -updateLangPackTooLong#46560264 lang_code:string = Update; -updateLangPack#56022f4d difference:LangPackDifference = Update; -updateFavedStickers#e511996d = Update; -updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector = Update; -updateContactsReset#7084a7be = Update; -updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; -updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update; -updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; -updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; -updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; -updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update; -updatePeerLocated#b4afcfb0 peers:Vector = Update; -updateNewScheduledMessage#39a51dfb message:Message = Update; -updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector sent_messages:flags.0?Vector = Update; -updateTheme#8216fba3 theme:Theme = Update; -updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update; -updateLoginToken#564fe691 = Update; -updateMessagePollVote#24f40e77 poll_id:long peer:Peer options:Vector qts:int = Update; -updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update; -updateDialogFilterOrder#a5d72105 order:Vector = Update; -updateDialogFilters#3504914f = Update; -updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update; -updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update; -updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update; -updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update; -updatePeerBlocked#ebe07752 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer = Update; -updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; -updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; -updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChat#f89a6a4e chat_id:long = Update; -updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; -updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update; -updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; -updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update; -updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update; -updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; -updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; -updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update; -updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update; -updateAttachMenuBots#17b7a20b = Update; -updateWebViewResultSent#1592b79d query_id:long = Update; -updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update; -updateSavedRingtones#74d8be99 = Update; -updateTranscribedAudio#84cd5a flags:# pending:flags.0?true peer:Peer msg_id:int transcription_id:long text:string = Update; -updateReadFeaturedEmojiStickers#fb4c496c = Update; -updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update; -updateRecentEmojiStatuses#30f443db = Update; -updateRecentReactions#6f7863f4 = Update; -updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update; -updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector = Update; -updateUser#20529438 user_id:long = Update; -updateAutoSaveSettings#ec05b097 = Update; -updateStory#75b3b798 peer:Peer story:StoryItem = Update; -updateReadStories#f74e932b peer:Peer max_id:int = Update; -updateStoryID#1bf335b9 id:int random_id:long = Update; -updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update; -updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update; -updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update; -updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update; -updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update; -updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector new_reactions:Vector qts:int = Update; -updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector qts:int = Update; -updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; -updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector = Update; -updateSavedReactionTags#39c67432 = Update; -updateSmsJob#f16269d4 job_id:string = Update; -updateQuickReplies#f9470ab2 quick_replies:Vector = Update; -updateNewQuickReply#f53da717 quick_reply:QuickReply = Update; -updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update; -updateQuickReplyMessage#3e050d0f message:Message = Update; -updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector = Update; -updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Update; -updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; -updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; -updateStarsBalance#4e80a379 balance:StarsAmount = Update; -updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; -updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; -updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; -updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; -updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; -updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; -updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update; -updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = Update; -updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update; -updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update; -updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector = Update; -updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector = Update; -updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update; -updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update; -updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update; -updateStarGiftCraftFail#ac072444 = Update; - -updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; - -updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; -updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; -updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; -updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; - -updatesTooLong#e317af7e = Updates; -updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShort#78d4dec1 update:Update date:int = Updates; -updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; -updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; -updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; -photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; - -photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; - -upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; -upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; - -dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; - -config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config; - -nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; - -help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate; -help.noAppUpdate#c45a6536 = help.AppUpdate; - -help.inviteText#18cb9f78 message:string = help.InviteText; - -encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; -encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat; -encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; -encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; -encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat; - -inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; - -encryptedFileEmpty#c21f497e = EncryptedFile; -encryptedFile#a8008cd8 id:long access_hash:long size:long dc_id:int key_fingerprint:int = EncryptedFile; - -inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; -inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; -inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; -inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; - -encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; -encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; - -messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; -messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; - -messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; -messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; - -inputDocumentEmpty#72f0eaae = InputDocument; -inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; - -documentEmpty#36f8c871 id:long = Document; -document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector video_thumbs:flags.1?Vector dc_id:int attributes:Vector = Document; - -help.support#17c6b5f6 phone_number:string user:User = help.Support; - -notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; -notifyUsers#b4c83b4c = NotifyPeer; -notifyChats#c007cec3 = NotifyPeer; -notifyBroadcasts#d612e8ef = NotifyPeer; -notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer; - -sendMessageTypingAction#16bf744e = SendMessageAction; -sendMessageCancelAction#fd5ec8f5 = SendMessageAction; -sendMessageRecordVideoAction#a187d66f = SendMessageAction; -sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; -sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; -sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; -sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; -sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; -sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; -sendMessageChooseContactAction#628cbc6f = SendMessageAction; -sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; -sendMessageRecordRoundAction#88f27fbc = SendMessageAction; -sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; -speakingInGroupCallAction#d92c2285 = SendMessageAction; -sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; -sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; -sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction; -sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction; -sendMessageTextDraftAction#376d975c random_id:long text:TextWithEntities = SendMessageAction; - -contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; - -inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; -inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; -inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; -inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; -inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; -inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; -inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; -inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey; -inputPrivacyKeyVoiceMessages#aee69d68 = InputPrivacyKey; -inputPrivacyKeyAbout#3823cc40 = InputPrivacyKey; -inputPrivacyKeyBirthday#d65a11cc = InputPrivacyKey; -inputPrivacyKeyStarGiftsAutoSave#e1732341 = InputPrivacyKey; -inputPrivacyKeyNoPaidMessages#bdc597b4 = InputPrivacyKey; -inputPrivacyKeySavedMusic#4dbe9226 = InputPrivacyKey; - -privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; -privacyKeyChatInvite#500e6dfa = PrivacyKey; -privacyKeyPhoneCall#3d662b7b = PrivacyKey; -privacyKeyPhoneP2P#39491cc8 = PrivacyKey; -privacyKeyForwards#69ec56a3 = PrivacyKey; -privacyKeyProfilePhoto#96151fed = PrivacyKey; -privacyKeyPhoneNumber#d19ae46d = PrivacyKey; -privacyKeyAddedByPhone#42ffd42b = PrivacyKey; -privacyKeyVoiceMessages#697f414 = PrivacyKey; -privacyKeyAbout#a486b761 = PrivacyKey; -privacyKeyBirthday#2000a518 = PrivacyKey; -privacyKeyStarGiftsAutoSave#2ca4fdf8 = PrivacyKey; -privacyKeyNoPaidMessages#17d348d2 = PrivacyKey; -privacyKeySavedMusic#ff7a571b = PrivacyKey; - -inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; -inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; -inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; -inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; -inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; -inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; -inputPrivacyValueAllowChatParticipants#840649cf chats:Vector = InputPrivacyRule; -inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector = InputPrivacyRule; -inputPrivacyValueAllowCloseFriends#2f453e49 = InputPrivacyRule; -inputPrivacyValueAllowPremium#77cdc9f1 = InputPrivacyRule; -inputPrivacyValueAllowBots#5a4fcce5 = InputPrivacyRule; -inputPrivacyValueDisallowBots#c4e57915 = InputPrivacyRule; - -privacyValueAllowContacts#fffe1bac = PrivacyRule; -privacyValueAllowAll#65427b82 = PrivacyRule; -privacyValueAllowUsers#b8905fb2 users:Vector = PrivacyRule; -privacyValueDisallowContacts#f888fa1a = PrivacyRule; -privacyValueDisallowAll#8b73e763 = PrivacyRule; -privacyValueDisallowUsers#e4621141 users:Vector = PrivacyRule; -privacyValueAllowChatParticipants#6b134e8e chats:Vector = PrivacyRule; -privacyValueDisallowChatParticipants#41c87565 chats:Vector = PrivacyRule; -privacyValueAllowCloseFriends#f7e8d89b = PrivacyRule; -privacyValueAllowPremium#ece9814b = PrivacyRule; -privacyValueAllowBots#21461b5d = PrivacyRule; -privacyValueDisallowBots#f6a5f82f = PrivacyRule; - -account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; - -accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; - -documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; -documentAttributeAnimated#11b58939 = DocumentAttribute; -documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; -documentAttributeVideo#43c57c48 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double video_codec:flags.5?string = DocumentAttribute; -documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; -documentAttributeFilename#15590068 file_name:string = DocumentAttribute; -documentAttributeHasStickers#9801d2f7 = DocumentAttribute; -documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute; - -messages.stickersNotModified#f1749a22 = messages.Stickers; -messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; - -stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; - -messages.allStickersNotModified#e86602c3 = messages.AllStickers; -messages.allStickers#cdbbcebb hash:long sets:Vector = messages.AllStickers; - -messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; - -webPageEmpty#211a1788 flags:# id:long url:flags.0?string = WebPage; -webPagePending#b0d13e47 flags:# id:long url:flags.0?string date:int = WebPage; -webPage#e89c45b2 flags:# has_large_media:flags.13?true video_cover_photo:flags.14?true id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector = WebPage; -webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; - -authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; - -account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector = account.Authorizations; - -account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password; - -account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; - -account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; - -auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; - -receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; - -chatInviteExported#a22cbd96 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int subscription_expired:flags.10?int title:flags.8?string subscription_pricing:flags.9?StarsSubscriptionPricing = ExportedChatInvite; -chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite; - -chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#5c9d3702 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true can_refulfill_subscription:flags.11?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector color:int subscription_pricing:flags.10?StarsSubscriptionPricing subscription_form_id:flags.12?long bot_verification:flags.13?BotVerification = ChatInvite; -chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; - -inputStickerSetEmpty#ffb62b95 = InputStickerSet; -inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; -inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; -inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; -inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; -inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet; -inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet; -inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; -inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; -inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet; -inputStickerSetTonGifts#1cf671a0 = InputStickerSet; - -stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; - -messages.stickerSet#6e153f16 set:StickerSet packs:Vector keywords:Vector documents:Vector = messages.StickerSet; -messages.stickerSetNotModified#d3f924eb = messages.StickerSet; - -botCommand#c27ac8c7 command:string description:string = BotCommand; - -botInfo#4d8a0299 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton privacy_policy_url:flags.7?string app_settings:flags.8?BotAppSettings verifier_settings:flags.9?BotVerifierSettings = BotInfo; - -keyboardButton#7d170cff flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrl#d80c25ec flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonCallback#e62bc960 flags:# requires_password:flags.0?true style:flags.10?KeyboardButtonStyle text:string data:bytes = KeyboardButton; -keyboardButtonRequestPhone#417efd8f flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonRequestGeoLocation#aa40f94d flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonSwitchInline#991399fc flags:# same_peer:flags.0?true style:flags.10?KeyboardButtonStyle text:string query:string peer_types:flags.1?Vector = KeyboardButton; -keyboardButtonGame#89c590f9 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonBuy#3fa53905 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrlAuth#f51006f9 flags:# style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; -inputKeyboardButtonUrlAuth#68013e72 flags:# request_write_access:flags.0?true style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; -keyboardButtonRequestPoll#7a11d782 flags:# style:flags.10?KeyboardButtonStyle quiz:flags.0?Bool text:string = KeyboardButton; -inputKeyboardButtonUserProfile#7d5e07c7 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:InputUser = KeyboardButton; -keyboardButtonUserProfile#c0fd5d09 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:long = KeyboardButton; -keyboardButtonWebView#e846b1a0 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonSimpleWebView#e15c4370 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonRequestPeer#5b0f15f5 flags:# style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -inputKeyboardButtonRequestPeer#2b78156 flags:# name_requested:flags.0?true username_requested:flags.1?true photo_requested:flags.2?true style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -keyboardButtonCopy#bcc4af10 flags:# style:flags.10?KeyboardButtonStyle text:string copy_text:string = KeyboardButton; - -keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; - -replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; -replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup; -replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector placeholder:flags.3?string = ReplyMarkup; -replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; - -messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; -messageEntityMention#fa04579d offset:int length:int = MessageEntity; -messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; -messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; -messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; -messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; -messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; -messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; -messageEntityCode#28a20571 offset:int length:int = MessageEntity; -messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; -messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; -messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity; -inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; -messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; -messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; -messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity; -messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; -messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; -messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; -messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; -messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity; - -inputChannelEmpty#ee8c1e86 = InputChannel; -inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; -inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel; - -contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; - -messageRange#ae30253 min_id:int max_id:int = MessageRange; - -updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; -updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; -updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; - -channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; -channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; - -channelParticipant#cb397619 flags:# user_id:long date:int subscription_until_date:flags.0?int = ChannelParticipant; -channelParticipantSelf#4f607bef flags:# via_request:flags.0?true user_id:long inviter_id:long date:int subscription_until_date:flags.1?int = ChannelParticipant; -channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; -channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; -channelParticipantBanned#6df8014e flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights = ChannelParticipant; -channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; - -channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; -channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; -channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; -channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; -channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; -channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; -channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; -channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; - -channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; -channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; - -channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; - -help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; - -messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; -messages.savedGifs#84a02a0d hash:long gifs:Vector = messages.SavedGifs; - -inputBotInlineMessageMediaAuto#3380c786 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaWebPage#bddcc510 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true optional:flags.6?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; - -botInlineMessageMediaAuto#764cf810 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; -botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; - -messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector cache_time:int users:Vector = messages.BotResults; - -exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; - -messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader; - -auth.codeTypeSms#72a3158c = auth.CodeType; -auth.codeTypeCall#741cd3e3 = auth.CodeType; -auth.codeTypeFlashCall#226ccefb = auth.CodeType; -auth.codeTypeMissedCall#d61ad6ee = auth.CodeType; -auth.codeTypeFragmentSms#6ed998c = auth.CodeType; - -auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; -auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; -auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; -auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType; -auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; -auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; -auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; -auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; -auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; -auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; - -messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; - -messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; - -inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; -inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID; - -inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; - -messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; - -topPeer#edcdc05b peer:Peer rating:double = TopPeer; - -topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; -topPeerCategoryBotsInline#148677e2 = TopPeerCategory; -topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; -topPeerCategoryGroups#bd17a14a = TopPeerCategory; -topPeerCategoryChannels#161d9628 = TopPeerCategory; -topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; -topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; -topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; -topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory; - -topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; - -contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; -contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; -contacts.topPeersDisabled#b52c939d = contacts.TopPeers; - -draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; -draftMessage#96eaa5eb flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost = DraftMessage; - -messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; -messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; - -messages.recentStickersNotModified#b17f890 = messages.RecentStickers; -messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; - -messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; - -messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; -messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; - -stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; -stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; -stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector keywords:Vector documents:Vector = StickerSetCovered; -stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered; - -maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; - -inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; -inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; - -game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; - -inputGameID#32c3e77 id:long access_hash:long = InputGame; -inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; - -highScore#73a379eb pos:int user_id:long score:int = HighScore; - -messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; - -textEmpty#dc3d824f = RichText; -textPlain#744694e0 text:string = RichText; -textBold#6724abc4 text:RichText = RichText; -textItalic#d912a59c text:RichText = RichText; -textUnderline#c12622c4 text:RichText = RichText; -textStrike#9bf8bb95 text:RichText = RichText; -textFixed#6c3f19b9 text:RichText = RichText; -textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; -textEmail#de5a0dd6 text:RichText email:string = RichText; -textConcat#7e6260d7 texts:Vector = RichText; -textSubscript#ed6a8504 text:RichText = RichText; -textSuperscript#c7fb5e01 text:RichText = RichText; -textMarked#34b8621 text:RichText = RichText; -textPhone#1ccb966a text:RichText phone:string = RichText; -textImage#81ccf4f document_id:long w:int h:int = RichText; -textAnchor#35553762 text:RichText name:string = RichText; - -pageBlockUnsupported#13567e8a = PageBlock; -pageBlockTitle#70abc3fd text:RichText = PageBlock; -pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; -pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; -pageBlockHeader#bfd064ec text:RichText = PageBlock; -pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; -pageBlockParagraph#467a0766 text:RichText = PageBlock; -pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; -pageBlockFooter#48870999 text:RichText = PageBlock; -pageBlockDivider#db20b188 = PageBlock; -pageBlockAnchor#ce0d37b0 name:string = PageBlock; -pageBlockList#e4e88011 items:Vector = PageBlock; -pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; -pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; -pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; -pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; -pageBlockCover#39f23300 cover:PageBlock = PageBlock; -pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; -pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; -pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; -pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; -pageBlockChannel#ef1751b5 channel:Chat = PageBlock; -pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; -pageBlockKicker#1e148390 text:RichText = PageBlock; -pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; -pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; -pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; -pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; -pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; - -phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; -phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; -phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; -phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; -phoneCallDiscardReasonMigrateConferenceCall#9fbbf1f7 slug:string = PhoneCallDiscardReason; - -dataJSON#7d748d04 data:string = DataJSON; - -labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; - -invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector terms_url:flags.10?string subscription_period:flags.11?int = Invoice; - -paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; - -postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; - -paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; - -paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; - -webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; -webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; - -inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; - -inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; -inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; -inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation; - -upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; - -payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector users:Vector = payments.PaymentForm; -payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector = payments.PaymentForm; -payments.paymentFormStarGift#b425cfe1 form_id:long invoice:Invoice = payments.PaymentForm; - -payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; - -payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; -payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; - -payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; -payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector = payments.PaymentReceipt; - -payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; - -inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; -inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials; - -account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; - -shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; - -inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem; - -inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; - -phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#30535af5 flags:# p2p_allowed:flags.5?true video:flags.6?true conference_supported:flags.8?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int custom_parameters:flags.7?DataJSON = PhoneCall; -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; - -phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; -phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection; - -phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector = PhoneCallProtocol; - -phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; - -upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; -upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; - -cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; - -cdnConfig#5725e40a public_keys:Vector = CdnConfig; - -langPackString#cad181f6 key:string value:string = LangPackString; -langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; -langPackStringDeleted#2979eeb2 key:string = LangPackString; - -langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; - -langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; - -channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; -channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector new_value:Vector = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAutotranslation#c517f77e new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; - -channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; - -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true = ChannelAdminLogEventsFilter; - -popularContact#5ce14175 client_id:long importers:int = PopularContact; - -messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; -messages.favedStickers#2cb51097 hash:long packs:Vector stickers:Vector = messages.FavedStickers; - -recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; -recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl; -recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl; -recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; -recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; - -help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; - -inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; - -webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; - -account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; - -inputMessageID#a676a322 id:int = InputMessage; -inputMessageReplyTo#bad88395 id:int = InputMessage; -inputMessagePinned#86872538 = InputMessage; -inputMessageCallbackQuery#acfa1a7e id:int query_id:long = InputMessage; - -inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; -inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; - -dialogPeer#e56dbf05 peer:Peer = DialogPeer; -dialogPeerFolder#514519e2 folder_id:int = DialogPeer; - -messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; -messages.foundStickerSets#8af09dd2 hash:long sets:Vector = messages.FoundStickerSets; - -fileHash#f39b035c offset:long limit:int hash:bytes = FileHash; - -inputClientProxy#75588b3f address:string port:int = InputClientProxy; - -help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; -help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; - -inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; -inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; - -secureFileEmpty#64199744 = SecureFile; -secureFile#7d09c27e id:long access_hash:long size:long dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; - -secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; - -securePlainPhone#7d6099dd phone:string = SecurePlainData; -securePlainEmail#21ec5a5f email:string = SecurePlainData; - -secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; -secureValueTypePassport#3dac6a00 = SecureValueType; -secureValueTypeDriverLicense#6e425c4 = SecureValueType; -secureValueTypeIdentityCard#a0d0744b = SecureValueType; -secureValueTypeInternalPassport#99a48f23 = SecureValueType; -secureValueTypeAddress#cbe31e26 = SecureValueType; -secureValueTypeUtilityBill#fc36954e = SecureValueType; -secureValueTypeBankStatement#89137c0d = SecureValueType; -secureValueTypeRentalAgreement#8b883488 = SecureValueType; -secureValueTypePassportRegistration#99e3806a = SecureValueType; -secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; -secureValueTypePhone#b320aadb = SecureValueType; -secureValueTypeEmail#8e3ca7ee = SecureValueType; - -secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; - -inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; - -secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; - -secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; -secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; -secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; - -secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; - -account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; - -account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; - -help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; -help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; - -savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; - -account.takeout#4dba4501 id:long = account.Takeout; - -passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; -passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; - -securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; -securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; -securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; - -secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; - -inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; -inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; - -secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; -secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; - -help.passportConfigNotModified#bfb9f457 = help.PassportConfig; -help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; - -inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; - -jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; - -jsonNull#3f6d7b68 = JSONValue; -jsonBool#c7345e6a value:Bool = JSONValue; -jsonNumber#2be0dfa4 value:double = JSONValue; -jsonString#b71e767a value:string = JSONValue; -jsonArray#f7444763 value:Vector = JSONValue; -jsonObject#99c1d49d value:Vector = JSONValue; - -pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; - -pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; - -pageCaption#6f747657 text:RichText credit:RichText = PageCaption; - -pageListItemText#b92fb6cd text:RichText = PageListItem; -pageListItemBlocks#25e073fc blocks:Vector = PageListItem; - -pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; -pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; - -pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; - -page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector views:flags.3?int = Page; - -help.supportName#8c05f1c9 name:string = help.SupportName; - -help.userInfoEmpty#f3ae2eed = help.UserInfo; -help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; - -pollAnswer#ff16e2ca text:TextWithEntities option:bytes = PollAnswer; - -poll#58747131 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:TextWithEntities answers:Vector close_period:flags.4?int close_date:flags.5?int = Poll; - -pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters; - -pollResults#7adf2420 flags:# min:flags.0?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector = PollResults; - -chatOnlines#f041e250 onlines:int = ChatOnlines; - -statsURL#47a971e0 url:string = StatsURL; - -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true = ChatAdminRights; - -chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true until_date:int = ChatBannedRights; - -inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; -inputWallPaperSlug#72091c80 slug:string = InputWallPaper; -inputWallPaperNoFile#967a462e id:long = InputWallPaper; - -account.wallPapersNotModified#1c199183 = account.WallPapers; -account.wallPapers#cdc3858c hash:long wallpapers:Vector = account.WallPapers; - -codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true unknown_number:flags.9?true logout_tokens:flags.6?Vector token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings; - -wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings; - -autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings; - -account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; - -emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector = EmojiKeyword; -emojiKeywordDeleted#236df622 keyword:string emoticons:Vector = EmojiKeyword; - -emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector = EmojiKeywordsDifference; - -emojiURL#a575739d url:string = EmojiURL; - -emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; - -folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; - -inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; - -folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; - -messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; - -urlAuthResultRequest#32fabf1a flags:# request_write_access:flags.0?true request_phone_number:flags.1?true bot:User domain:string browser:flags.2?string platform:flags.2?string ip:flags.2?string region:flags.2?string = UrlAuthResult; -urlAuthResultAccepted#623a8fa0 flags:# url:flags.0?string = UrlAuthResult; -urlAuthResultDefault#a9d6db1f = UrlAuthResult; - -channelLocationEmpty#bfb5ad8b = ChannelLocation; -channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation; - -peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated; -peerSelfLocated#f8ec284b expires:int = PeerLocated; - -restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason; - -inputTheme#3c5693e9 id:long access_hash:long = InputTheme; -inputThemeSlug#f5890df1 slug:string = InputTheme; - -theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector emoticon:flags.6?string installs_count:flags.4?int = Theme; - -account.themesNotModified#f41eb622 = account.Themes; -account.themes#9a3d8c6d hash:long themes:Vector = account.Themes; - -auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken; -auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken; -auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken; - -account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings; - -messages.inactiveChats#a927fec5 dates:Vector chats:Vector users:Vector = messages.InactiveChats; - -baseThemeClassic#c3a12462 = BaseTheme; -baseThemeDay#fbd81688 = BaseTheme; -baseThemeNight#b7b31ea8 = BaseTheme; -baseThemeTinted#6d5f77ee = BaseTheme; -baseThemeArctic#5b11125a = BaseTheme; - -inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; - -themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; - -webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; -webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; -webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; -webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; -webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; -webPageAttributeStarGiftAuction#1c641c2 gift:StarGift end_date:int = WebPageAttribute; - -messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; - -bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl; - -payments.bankCardData#3e24e573 title:string open_urls:Vector = payments.BankCardData; - -dialogFilter#aa472651 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector exclude_peers:Vector = DialogFilter; -dialogFilterDefault#363293ae = DialogFilter; -dialogFilterChatlist#96537bd7 flags:# has_my_invites:flags.26?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector = DialogFilter; - -dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested; - -statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays; - -statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev; - -statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue; - -statsGraphAsync#4a27eb2d token:string = StatsGraph; -statsGraphError#bedc9822 error:string = StatsGraph; -statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph; - -stats.broadcastStats#396ca5fc period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev reactions_per_post:StatsAbsValueAndPrev views_per_story:StatsAbsValueAndPrev shares_per_story:StatsAbsValueAndPrev reactions_per_story:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_posts_interactions:Vector = stats.BroadcastStats; - -help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; -help.promoData#8a4d87a flags:# proxy:flags.0?true expires:int peer:flags.3?Peer psa_type:flags.1?string psa_message:flags.2?string pending_suggestions:Vector dismissed_suggestions:Vector custom_pending_suggestion:flags.4?PendingSuggestion chats:Vector users:Vector = help.PromoData; - -videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; -videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector = VideoSize; -videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector = VideoSize; - -statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster; - -statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; - -statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; - -stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; - -globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; - -help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; - -help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector = help.Country; - -help.countriesListNotModified#93cc1f32 = help.CountriesList; -help.countriesList#87d0759e countries:Vector hash:int = help.CountriesList; - -messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews; - -messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; - -messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; - -messageReplyHeader#6917560b flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector quote_offset:flags.10?int todo_item_id:flags.11?int = MessageReplyHeader; -messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader; - -messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; - -peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; - -stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; - -groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall; - -inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -inputGroupCallSlug#fe06823f slug:string = InputGroupCall; -inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall; - -groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant; - -phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; - -phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; - -inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; -inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; -inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType; -inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType; -inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType; -inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType; - -messages.historyImport#1662af0b id:long = messages.HistoryImport; - -messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed; - -messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector = messages.AffectedFoundMessages; - -chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter; - -messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; - -messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; -messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; - -messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; - -chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites; - -messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; - -messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; - -phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; - -phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; - -groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector = GroupCallParticipantVideoSourceGroup; - -groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector audio_source:flags.1?int = GroupCallParticipantVideo; - -stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName; - -botCommandScopeDefault#2f6cb2ab = BotCommandScope; -botCommandScopeUsers#3c4f04d8 = BotCommandScope; -botCommandScopeChats#6fe1a881 = BotCommandScope; -botCommandScopeChatAdmins#b9aa606a = BotCommandScope; -botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope; -botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope; -botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope; - -account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult; -account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; -account.resetPasswordOk#e926d63e = account.ResetPasswordResult; - -chatTheme#c3dffc04 emoticon:string = ChatTheme; -chatThemeUniqueGift#3458f9c8 gift:StarGift theme_settings:Vector = ChatTheme; - -account.chatThemesNotModified#e011e1c4 = account.ChatThemes; -account.chatThemes#be098173 flags:# hash:long themes:Vector chats:Vector users:Vector next_offset:flags.0?string = account.ChatThemes; - -sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage; - -messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; -messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; - -searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; - -messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector messages:Vector chats:Vector users:Vector = messages.SearchResultsCalendar; - -searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition; - -messages.searchResultsPositions#53b22baf count:int positions:Vector = messages.SearchResultsPositions; - -channels.sendAsPeers#f496b0c6 peers:Vector chats:Vector users:Vector = channels.SendAsPeers; - -users.userFull#3b6d152e full_user:UserFull chats:Vector users:Vector = users.UserFull; - -messages.peerSettings#6880b94d settings:PeerSettings chats:Vector users:Vector = messages.PeerSettings; - -auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut; - -reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; - -messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector recent_reactions:flags.1?Vector top_reactors:flags.4?Vector = MessageReactions; - -messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.MessageReactionsList; - -availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; - -messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions; -messages.availableReactions#768e3aad hash:int reactions:Vector = messages.AvailableReactions; - -messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true my:flags.2?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction; - -groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel; - -phone.groupCallStreamChannels#d0e482b2 channels:Vector = phone.GroupCallStreamChannels; - -phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl; - -attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; - -attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector = AttachMenuBotIcon; - -attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector icons:Vector = AttachMenuBot; - -attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; -attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector = AttachMenuBots; - -attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector = AttachMenuBotsBot; - -webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true fullscreen:flags.2?true query_id:flags.0?long url:string = WebViewResult; - -webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent; - -botMenuButtonDefault#7533a588 = BotMenuButton; -botMenuButtonCommands#4258c205 = BotMenuButton; -botMenuButton#c7b57ce6 text:string url:string = BotMenuButton; - -account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones; -account.savedRingtones#c1e92cc5 hash:long ringtones:Vector = account.SavedRingtones; - -notificationSoundDefault#97e8bebe = NotificationSound; -notificationSoundNone#6f0c34df = NotificationSound; -notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound; -notificationSoundRingtone#ff6c8049 id:long = NotificationSound; - -account.savedRingtone#b7263f6d = account.SavedRingtone; -account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone; - -attachMenuPeerTypeSameBotPM#7d6be90e = AttachMenuPeerType; -attachMenuPeerTypeBotPM#c32bfa1a = AttachMenuPeerType; -attachMenuPeerTypePM#f146d31f = AttachMenuPeerType; -attachMenuPeerTypeChat#509113f = AttachMenuPeerType; -attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; - -inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; -inputInvoiceSlug#c326caef slug:string = InputInvoice; -inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; -inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice; -inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice; -inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; -inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; -inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; -inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; -inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice; -inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice; - -payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; - -messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; - -help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; - -inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose; -inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentPremiumGiftCode#fb790393 flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long message:flags.1?TextWithEntities = InputStorePaymentPurpose; -inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsTopup#f9a2a6cb flags:# stars:long currency:string amount:long spend_purpose_peer:flags.0?InputPeer = InputStorePaymentPurpose; -inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; -inputStorePaymentAuthCode#9bb2636d flags:# restore:flags.0?true phone_number:string phone_code_hash:string currency:string amount:long = InputStorePaymentPurpose; - -paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; - -emojiStatusEmpty#2de11aae = EmojiStatus; -emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus; -emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus; -inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus; - -account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses; -account.emojiStatuses#90c467d1 hash:long statuses:Vector = account.EmojiStatuses; - -reactionEmpty#79f5d419 = Reaction; -reactionEmoji#1b2286b8 emoticon:string = Reaction; -reactionCustomEmoji#8935fc73 document_id:long = Reaction; -reactionPaid#523da4eb = Reaction; - -chatReactionsNone#eafc32bc = ChatReactions; -chatReactionsAll#52928bca flags:# allow_custom:flags.0?true = ChatReactions; -chatReactionsSome#661d4037 reactions:Vector = ChatReactions; - -messages.reactionsNotModified#b06fdbdf = messages.Reactions; -messages.reactions#eafdf716 hash:long reactions:Vector = messages.Reactions; - -emailVerifyPurposeLoginSetup#4345be73 phone_number:string phone_code_hash:string = EmailVerifyPurpose; -emailVerifyPurposeLoginChange#527d22eb = EmailVerifyPurpose; -emailVerifyPurposePassport#bbf51685 = EmailVerifyPurpose; - -emailVerificationCode#922e55a9 code:string = EmailVerification; -emailVerificationGoogle#db909ec2 token:string = EmailVerification; -emailVerificationApple#96d074fd token:string = EmailVerification; - -account.emailVerified#2b96cd1b email:string = account.EmailVerified; -account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified; - -premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption; - -sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer; - -messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia; -messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia; - -stickerKeyword#fcfeb29c document_id:long keyword:Vector = StickerKeyword; - -username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username; - -forumTopicDeleted#23f109b id:int = ForumTopic; -forumTopic#cdff0eca flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true title_missing:flags.7?true id:int date:int peer:Peer title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic; - -messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector messages:Vector chats:Vector users:Vector pts:int = messages.ForumTopics; - -defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL; - -exportedContactToken#41bf109b url:string expires:int = ExportedContactToken; - -requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType; -requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; - -emojiListNotModified#481eadfa = EmojiList; -emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; - -emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; - -messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; -messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; - -textWithEntities#751f3146 text:string entities:Vector = TextWithEntities; - -messages.translateResult#33db32f8 result:Vector = messages.TranslatedText; - -autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings; - -autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException; - -account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector chats:Vector users:Vector = account.AutoSaveSettings; - -help.appConfigNotModified#7cde641d = help.AppConfig; -help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig; - -inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp; -inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp; - -botAppNotModified#5da674b7 = BotApp; -botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; - -messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp; - -inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; - -readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; - -inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist; - -exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector = ExportedChatlistInvite; - -chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite; - -chatlists.exportedInvites#10ab6dc7 invites:Vector chats:Vector users:Vector = chatlists.ExportedInvites; - -chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector already_peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; -chatlists.chatlistInvite#f10ece2f flags:# title_noanimate:flags.1?true title:TextWithEntities emoticon:flags.0?string peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; - -chatlists.chatlistUpdates#93bd878d missing_peers:Vector chats:Vector users:Vector = chatlists.ChatlistUpdates; - -bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo; - -messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote; -messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote; -messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector date:int = MessagePeerVote; - -storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector reactions_count:flags.4?int recent_viewers:flags.0?Vector = StoryViews; - -storyItemDeleted#51e6ee4f id:int = StoryItem; -storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true live:flags.9?true id:int date:int expire_date:int = StoryItem; -storyItem#edf164f1 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector = StoryItem; - -stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; -stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; - -stories.stories#63c3dd0a flags:# count:int stories:Vector pinned_to_top:flags.0?Vector chats:Vector users:Vector = stories.Stories; - -storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView; -storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView; -storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView; - -stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryViewsList; - -stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; - -inputReplyToMessage#869fbe10 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int = InputReplyTo; -inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; -inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; - -exportedStoryLink#3fc9053b link:string = ExportedStoryLink; - -storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; - -mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates; - -mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea; -inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea; -mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea; -mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea; -mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; -inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; -mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; -mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea; -mediaAreaStarGift#5787686d coordinates:MediaAreaCoordinates slug:string = MediaArea; - -peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; - -stories.peerStories#cae68768 stories:PeerStories chats:Vector users:Vector = stories.PeerStories; - -messages.webPage#fd5e12bd webpage:WebPage chats:Vector users:Vector = messages.WebPage; - -premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption; - -payments.checkedGiftCode#eb983f8f flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int days:int used_date:flags.1?int chats:Vector users:Vector = payments.CheckedGiftCode; - -payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; -payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo; - -prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; -prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway; - -boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost; - -premium.boostsList#86f8613c flags:# count:int boosts:Vector next_offset:flags.0?string users:Vector = premium.BoostsList; - -myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost; - -premium.myBoosts#9ae228e2 my_boosts:Vector chats:Vector users:Vector = premium.MyBoosts; - -premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector my_boost_slots:flags.2?Vector = premium.BoostsStatus; - -storyFwdHeader#b826e150 flags:# modified:flags.3?true from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader; - -postInteractionCountersMessage#e7058e7f msg_id:int views:int forwards:int reactions:int = PostInteractionCounters; -postInteractionCountersStory#8a480e27 story_id:int views:int forwards:int reactions:int = PostInteractionCounters; - -stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats; - -publicForwardMessage#1f2bf4a message:Message = PublicForward; -publicForwardStory#edf3add0 peer:Peer story:StoryItem = PublicForward; - -stats.publicForwards#93037e20 flags:# count:int forwards:Vector next_offset:flags.0?string chats:Vector users:Vector = stats.PublicForwards; - -peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor; -peerColorCollectible#b9c0639a flags:# collectible_id:long gift_emoji_id:long background_emoji_id:long accent_color:int colors:Vector dark_accent_color:flags.0?int dark_colors:flags.1?Vector = PeerColor; -inputPeerColorCollectible#b8ea86a9 collectible_id:long = PeerColor; - -help.peerColorSet#26219a58 colors:Vector = help.PeerColorSet; -help.peerColorProfileSet#767d61eb palette_colors:Vector bg_colors:Vector story_colors:Vector = help.PeerColorSet; - -help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption; - -help.peerColorsNotModified#2ba1f5ce = help.PeerColors; -help.peerColors#f8ed08 hash:int colors:Vector = help.PeerColors; - -storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction; -storyReactionPublicForward#bbab2643 message:Message = StoryReaction; -storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; - -stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; - -savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; -monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; - -messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; - -savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; - -messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; -messages.savedReactionTags#3259950a tags:Vector hash:long = messages.SavedReactionTags; - -outboxReadDate#3bb842ac date:int = OutboxReadDate; - -smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin; - -smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status; - -smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob; - -businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen; - -businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector = BusinessWorkHours; - -businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation; - -inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = InputBusinessRecipients; - -businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = BusinessRecipients; - -businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule; - -inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage; - -businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage; - -inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage; - -businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage; - -timezone#ff9289f5 id:string name:string utc_offset:int = Timezone; - -help.timezonesListNotModified#970708cc = help.TimezonesList; -help.timezonesList#7b74ed71 timezones:Vector hash:int = help.TimezonesList; - -quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply; - -inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut; -inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; - -messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; -messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; - -connectedBot#cd64636c flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights = ConnectedBot; - -account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; - -messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector = messages.DialogFilters; - -birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; - -botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; - -inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; - -businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro; - -messages.myStickers#faff629d count:int sets:Vector = messages.MyStickers; - -inputCollectibleUsername#e39460a9 username:string = InputCollectible; -inputCollectiblePhone#a2e214a4 phone:string = InputCollectible; - -fragment.collectibleInfo#6ebdff91 purchase_date:int currency:string amount:long crypto_currency:string crypto_amount:long url:string = fragment.CollectibleInfo; - -inputBusinessBotRecipients#c4e5921e flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = InputBusinessBotRecipients; - -businessBotRecipients#b88cf373 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = BusinessBotRecipients; - -contactBirthday#1d998733 contact_id:long birthday:Birthday = ContactBirthday; - -contacts.contactBirthdays#114ff30d contacts:Vector users:Vector = contacts.ContactBirthdays; - -missingInvitee#628c9224 flags:# premium_would_allow_invite:flags.0?true premium_required_for_pm:flags.1?true user_id:long = MissingInvitee; - -messages.invitedUsers#7f5defa6 updates:Updates missing_invitees:Vector = messages.InvitedUsers; - -inputBusinessChatLink#11679fa7 flags:# message:string entities:flags.0?Vector title:flags.1?string = InputBusinessChatLink; - -businessChatLink#b4ae666f flags:# link:string message:string entities:flags.0?Vector title:flags.1?string views:int = BusinessChatLink; - -account.businessChatLinks#ec43a2d1 links:Vector chats:Vector users:Vector = account.BusinessChatLinks; - -account.resolvedBusinessChatLinks#9a23af21 flags:# peer:Peer message:string entities:flags.0?Vector chats:Vector users:Vector = account.ResolvedBusinessChatLinks; - -requestedPeerUser#d62ff46a flags:# user_id:long first_name:flags.0?string last_name:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChat#7307544f flags:# chat_id:long title:flags.0?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChannel#8ba403e4 flags:# channel_id:long title:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; - -sponsoredMessageReportOption#430d3150 text:string option:bytes = SponsoredMessageReportOption; - -channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:Vector = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; - -reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; -reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; - -reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; - -availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; - -messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; -messages.availableEffects#bddb616e hash:int effects:Vector documents:Vector = messages.AvailableEffects; - -factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck; - -starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer; -starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer; -starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; -starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; -starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; -starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; -starsTransactionPeerAds#60682812 = StarsTransactionPeer; -starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; - -starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; - -starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true posts_search:flags.24?true stargift_prepaid_upgrade:flags.25?true stargift_drop_original_details:flags.26?true phonegroup_message:flags.27?true stargift_auction_bid:flags.28?true offer:flags.29?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction; - -payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; - -foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; - -stories.foundStories#e2de7737 flags:# count:int stories:Vector next_offset:flags.0?string chats:Vector users:Vector = stories.FoundStories; - -geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; - -starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; - -payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; - -payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; - -payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl; - -inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; - -starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption; - -bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector = bots.PopularAppBots; - -botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia; - -bots.previewInfo#ca71d64 media:Vector lang_codes:Vector = bots.PreviewInfo; - -starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing; - -starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true bot_canceled:flags.7?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string title:flags.4?string photo:flags.5?WebDocument invoice_slug:flags.6?string = StarsSubscription; - -messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; - -starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; - -starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; - -starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift; -starGiftUnique#85f0a9cd flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true burned:flags.14?true crafted:flags.15?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int craft_chance_permille:flags.16?int = StarGift; - -payments.starGiftsNotModified#a388a368 = payments.StarGifts; -payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; - -messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; - -reportResultChooseOption#f0e4e0b6 title:string options:Vector = ReportResult; -reportResultAddComment#6f09ac31 flags:# optional:flags.0?true option:bytes = ReportResult; -reportResultReported#8db33c4b = ReportResult; - -messages.botPreparedInlineMessage#8ecf0511 id:string expire_date:int = messages.BotPreparedInlineMessage; - -messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult peer_types:Vector cache_time:int users:Vector = messages.PreparedInlineMessage; - -botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings; - -starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram; - -connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef; - -payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector = payments.ConnectedStarRefBots; - -payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; - -starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount; -starsTonAmount#74aee3e0 amount:long = StarsAmount; - -messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers; -messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector = messages.FoundStickers; - -botVerifierSettings#b0cd6617 flags:# can_modify_custom_description:flags.1?true icon:long company:string custom_description:flags.0?string = BotVerifierSettings; - -botVerification#f93cd45c bot_id:long icon:long description:string = BotVerification; - -starGiftAttributeModel#565251e2 flags:# crafted:flags.0?true name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributePattern#4e7085ea name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeBackdrop#9f2504e4 name:string backdrop_id:int center_color:int edge_color:int pattern_color:int text_color:int rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute; - -payments.starGiftUpgradePreview#3de1dfed sample_attributes:Vector prices:Vector next_prices:Vector = payments.StarGiftUpgradePreview; - -users.users#62d706b8 users:Vector = users.Users; -users.usersSlice#315a4974 count:int users:Vector = users.Users; - -payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector users:Vector = payments.UniqueStarGift; - -messages.webPagePreview#8c9a88ac media:MessageMedia chats:Vector users:Vector = messages.WebPagePreview; - -savedStarGift#41df43fc flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int can_craft_at:flags.20?int = SavedStarGift; - -payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; - -inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift; -inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift; -inputSavedStarGiftSlug#2085c238 slug:string = InputSavedStarGift; - -payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl; - -paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy; -paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy; -paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy; - -account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRevenue; - -requirementToContactEmpty#50a9839 = RequirementToContact; -requirementToContactPremium#e581e4e9 = RequirementToContact; -requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; - -businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; - -disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true disallow_stargifts_from_channels:flags.4?true = DisallowedGiftsSettings; - -sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; - -contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; -contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; - -starGiftAttributeIdModel#48aaae3c document_id:long = StarGiftAttributeId; -starGiftAttributeIdPattern#4a162433 document_id:long = StarGiftAttributeId; -starGiftAttributeIdBackdrop#1f01c757 backdrop_id:int = StarGiftAttributeId; - -starGiftAttributeCounter#2eb1b658 attribute:StarGiftAttributeId count:int = StarGiftAttributeCounter; - -payments.resaleStarGifts#947a12df flags:# count:int gifts:Vector next_offset:flags.0?string attributes:flags.1?Vector attributes_hash:flags.1?long chats:Vector counters:flags.2?Vector users:Vector = payments.ResaleStarGifts; - -stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount; - -pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion; - -todoItem#cba9a52f id:int title:TextWithEntities = TodoItem; - -todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector = TodoList; - -todoCompletion#221bb5e4 id:int completed_by:Peer date:int = TodoCompletion; - -suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost; - -starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating; - -starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection; - -payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; -payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; - -storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; - -stories.albumsNotModified#564edaeb = stories.Albums; -stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; - -searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; - -payments.uniqueStarGiftValueInfo#512fe446 flags:# last_sale_on_fragment:flags.1?true value_is_average:flags.6?true currency:string value:long initial_sale_date:int initial_sale_stars:long initial_sale_price:long last_sale_date:flags.0?int last_sale_price:flags.0?long floor_price:flags.2?long average_price:flags.3?long listed_count:flags.4?int fragment_listed_count:flags.5?int fragment_listed_url:flags.5?string = payments.UniqueStarGiftValueInfo; - -profileTabPosts#b98cd696 = ProfileTab; -profileTabGifts#4d4bd46a = ProfileTab; -profileTabMedia#72c64955 = ProfileTab; -profileTabFiles#ab339c00 = ProfileTab; -profileTabMusic#9f27d26e = ProfileTab; -profileTabVoice#e477092e = ProfileTab; -profileTabLinks#d3656499 = ProfileTab; -profileTabGifs#a2c0f695 = ProfileTab; - -users.savedMusicNotModified#e3878aa4 count:int = users.SavedMusic; -users.savedMusic#34a2f297 count:int documents:Vector = users.SavedMusic; - -account.savedMusicIdsNotModified#4fc81d6e = account.SavedMusicIds; -account.savedMusicIds#998d6636 ids:Vector = account.SavedMusicIds; - -payments.checkCanSendGiftResultOk#374fa7ad = payments.CheckCanSendGiftResult; -payments.checkCanSendGiftResultFail#d5e58274 reason:TextWithEntities = payments.CheckCanSendGiftResult; - -inputChatThemeEmpty#83268483 = InputChatTheme; -inputChatTheme#c93de95c emoticon:string = InputChatTheme; -inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme; - -starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice; - -groupCallMessage#1a8afc7e flags:# from_admin:flags.1?true id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage; - -groupCallDonor#ee430c85 flags:# top:flags.0?true my:flags.1?true peer_id:flags.3?Peer stars:long = GroupCallDonor; - -phone.groupCallStars#9d1dbd26 total_stars:long top_donors:Vector chats:Vector users:Vector = phone.GroupCallStars; - -recentStory#711d692d flags:# live:flags.0?true max_id:flags.1?int = RecentStory; - -auctionBidLevel#310240cc pos:int amount:long date:int = AuctionBidLevel; - -starGiftAuctionStateNotModified#fe333952 = StarGiftAuctionState; -starGiftAuctionState#771a4e66 version:int start_date:int end_date:int min_bid_amount:long bid_levels:Vector top_bidders:Vector next_round_at:int last_gift_num:int gifts_left:int current_round:int total_rounds:int rounds:Vector = StarGiftAuctionState; -starGiftAuctionStateFinished#972dabbf flags:# start_date:int end_date:int average_price:long listed_count:flags.0?int fragment_listed_count:flags.1?int fragment_listed_url:flags.1?string = StarGiftAuctionState; - -starGiftAuctionUserState#2eeed1c4 flags:# returned:flags.1?true bid_amount:flags.0?long bid_date:flags.0?int min_bid_amount:flags.0?long bid_peer:flags.0?Peer acquired_count:int = StarGiftAuctionUserState; - -payments.starGiftAuctionState#6b39f4ec gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState timeout:int users:Vector chats:Vector = payments.StarGiftAuctionState; - -starGiftAuctionAcquiredGift#42b00348 flags:# name_hidden:flags.0?true peer:Peer date:int bid_amount:long round:int pos:int message:flags.1?TextWithEntities gift_num:flags.2?int = StarGiftAuctionAcquiredGift; - -payments.starGiftAuctionAcquiredGifts#7d5bd1f0 gifts:Vector users:Vector chats:Vector = payments.StarGiftAuctionAcquiredGifts; - -starGiftActiveAuctionState#d31bc45d gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState = StarGiftActiveAuctionState; - -payments.starGiftActiveAuctionsNotModified#db33dad0 = payments.StarGiftActiveAuctions; -payments.starGiftActiveAuctions#aef6abbc auctions:Vector users:Vector chats:Vector = payments.StarGiftActiveAuctions; - -inputStarGiftAuction#2e16c98 gift_id:long = InputStarGiftAuction; -inputStarGiftAuctionSlug#7ab58308 slug:string = InputStarGiftAuction; - -passkey#98613ebf flags:# id:string name:string date:int software_emoji_id:flags.0?long last_usage_date:flags.1?int = Passkey; - -account.passkeys#f8e0aa1c passkeys:Vector = account.Passkeys; - -account.passkeyRegistrationOptions#e16b5ce1 options:DataJSON = account.PasskeyRegistrationOptions; - -auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions; - -inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse; -inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse; - -inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential; -inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential; - -starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground; - -starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound; -starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound; - -payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector = payments.StarGiftUpgradeAttributes; - -messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome; - -messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo; -messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector plays_left:flags.0?int = messages.EmojiGameInfo; - -starGiftAttributeRarity#36437737 permille:int = StarGiftAttributeRarity; -starGiftAttributeRarityUncommon#dbce6389 = StarGiftAttributeRarity; -starGiftAttributeRarityRare#f08d516b = StarGiftAttributeRarity; -starGiftAttributeRarityEpic#78fbf3a8 = StarGiftAttributeRarity; -starGiftAttributeRarityLegendary#cef7e7a8 = StarGiftAttributeRarity; - -keyboardButtonStyle#4fdd3430 flags:# bg_primary:flags.0?true bg_danger:flags.1?true bg_success:flags.2?true icon:flags.3?long = KeyboardButtonStyle; - ----functions--- - -invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; -invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; -initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; -invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; -invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; -invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; -invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; -invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; -invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; -invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X; -invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X; - -auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; -auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; -auth.signIn#8d52a951 flags:# phone_number:string phone_code_hash:string phone_code:flags.0?string email_verification:flags.1?EmailVerification = auth.Authorization; -auth.logOut#3e72ba19 = auth.LoggedOut; -auth.resetAuthorizations#9fab0d1a = Bool; -auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; -auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; -auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; -auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; -auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; -auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; -auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; -auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode; -auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; -auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; -auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; -auth.acceptLoginToken#e894ad4d token:bytes = Authorization; -auth.checkRecoveryPassword#d36bf79 code:string = Bool; -auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; -auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool; -auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; -auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; -auth.checkPaidAuth#56e59f9c phone_number:string phone_code_hash:string form_id:long = auth.SentCode; -auth.initPasskeyLogin#518ad0b7 api_id:int api_hash:string = auth.PasskeyLoginOptions; -auth.finishPasskeyLogin#9857ad07 flags:# credential:InputPasskeyCredential from_dc_id:flags.0?int from_auth_key_id:flags.0?long = auth.Authorization; - -account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; -account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; -account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; -account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; -account.resetNotifySettings#db7e1747 = Bool; -account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; -account.updateStatus#6628562c offline:Bool = Bool; -account.getWallPapers#7967d36 hash:long = account.WallPapers; -account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool; -account.checkUsername#2714d86c username:string = Bool; -account.updateUsername#3e0bdd7c username:string = User; -account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; -account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; -account.deleteAccount#a2c0cf74 flags:# reason:string password:flags.0?InputCheckPasswordSRP = Bool; -account.getAccountTTL#8fc711d = AccountDaysTTL; -account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; -account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; -account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; -account.updateDeviceLocked#38df3532 period:int = Bool; -account.getAuthorizations#e320c158 = account.Authorizations; -account.resetAuthorization#df77f3bc hash:long = Bool; -account.getPassword#548a30f5 = account.Password; -account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; -account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; -account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; -account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; -account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; -account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; -account.resetWebAuthorization#2d01b9ef hash:long = Bool; -account.resetWebAuthorizations#682d2594 = Bool; -account.getAllSecureValues#b288bc7d = Vector; -account.getSecureValue#73665bc2 types:Vector = Vector; -account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; -account.deleteSecureValue#b880bc4b types:Vector = Bool; -account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm; -account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; -account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; -account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; -account.sendVerifyEmailCode#98e037bb purpose:EmailVerifyPurpose email:string = account.SentEmailCode; -account.verifyEmail#32da4cf purpose:EmailVerifyPurpose verification:EmailVerification = account.EmailVerified; -account.initTakeoutSession#8ef3eab0 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?long = account.Takeout; -account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; -account.confirmPasswordEmail#8fdf1920 code:string = Bool; -account.resendPasswordEmail#7a7f2a15 = Bool; -account.cancelPasswordEmail#c1cbd5b6 = Bool; -account.getContactSignUpNotification#9f07c728 = Bool; -account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; -account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true compare_stories:flags.2?true peer:flags.0?InputNotifyPeer = Updates; -account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; -account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; -account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; -account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; -account.resetWallPapers#bb3b9804 = Bool; -account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; -account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; -account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document; -account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool; -account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool; -account.getTheme#3a5869ec format:string theme:InputTheme = Theme; -account.getThemes#7206e458 format:string hash:long = account.Themes; -account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool; -account.getContentSettings#8b9b4dae = account.ContentSettings; -account.getMultiWallPapers#65ad71dc wallpapers:Vector = Vector; -account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings; -account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; -account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; -account.resetPassword#9308ce1b = account.ResetPasswordResult; -account.declinePasswordReset#4c9409f6 = Bool; -account.getChatThemes#d638de89 hash:long = account.Themes; -account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; -account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; -account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones; -account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone; -account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document; -account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool; -account.getDefaultEmojiStatuses#d6753386 hash:long = account.EmojiStatuses; -account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; -account.clearRecentEmojiStatuses#18201aae = Bool; -account.reorderUsernames#ef500eab order:Vector = Bool; -account.toggleUsername#58d6b376 username:string active:Bool = Bool; -account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList; -account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList; -account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings; -account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool; -account.deleteAutoSaveExceptions#53bc0020 = Bool; -account.invalidateSignInCodes#ca8ae8ba codes:Vector = Bool; -account.updateColor#684d214e flags:# for_profile:flags.1?true color:flags.2?PeerColor = Bool; -account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList; -account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses; -account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList; -account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool; -account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool; -account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool; -account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool; -account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates; -account.getConnectedBots#4ea4c80f = account.ConnectedBots; -account.getBotBusinessConnection#76a86270 connection_id:string = Updates; -account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool; -account.toggleConnectedBotPaused#646e1097 peer:InputPeer paused:Bool = Bool; -account.disablePeerConnectedBot#5e437ed9 peer:InputPeer = Bool; -account.updateBirthday#cc6e0c11 flags:# birthday:flags.0?Birthday = Bool; -account.createBusinessChatLink#8851e68e link:InputBusinessChatLink = BusinessChatLink; -account.editBusinessChatLink#8c3410af slug:string link:InputBusinessChatLink = BusinessChatLink; -account.deleteBusinessChatLink#60073674 slug:string = Bool; -account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks; -account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks; -account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool; -account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool; -account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings; -account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings; -account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses; -account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue; -account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool; -account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool; -account.saveMusic#b26732a9 flags:# unsave:flags.0?true id:InputDocument after_id:flags.1?InputDocument = Bool; -account.getSavedMusicIds#e09d5faf hash:long = account.SavedMusicIds; -account.getUniqueGiftChatThemes#e42ce9c9 offset:string limit:int hash:long = account.ChatThemes; -account.initPasskeyRegistration#429547e8 = account.PasskeyRegistrationOptions; -account.registerPasskey#55b41fd6 credential:InputPasskeyCredential = Passkey; -account.getPasskeys#ea1f0c52 = account.Passkeys; -account.deletePasskey#f5b5563f id:string = Bool; - -users.getUsers#d91a548 id:Vector = Vector; -users.getFullUser#b60f5918 id:InputUser = users.UserFull; -users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; -users.getRequirementsToContact#d89a83a3 id:Vector = Vector; -users.getSavedMusic#788d7fe3 id:InputUser offset:int limit:int hash:long = users.SavedMusic; -users.getSavedMusicByID#7573a4e9 id:InputUser documents:Vector = users.SavedMusic; -users.suggestBirthday#fc533372 id:InputUser birthday:Birthday = Updates; - -contacts.getContactIDs#7adc669d hash:long = Vector; -contacts.getStatuses#c4a353ee = Vector; -contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; -contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; -contacts.deleteContacts#96a0e00 id:Vector = Updates; -contacts.deleteByPhones#1013fd9e phones:Vector = Bool; -contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; -contacts.search#11f812d8 q:string limit:int = contacts.Found; -contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer; -contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true offset:int limit:int hash:long = contacts.TopPeers; -contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; -contacts.resetSaved#879537f1 = Bool; -contacts.getSaved#82f1e39f = Vector; -contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; -contacts.addContact#d9ba2e54 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string note:flags.1?TextWithEntities = Updates; -contacts.acceptContact#f831a20f id:InputUser = Updates; -contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates; -contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates; -contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer; -contacts.exportContactToken#f8654027 = ExportedContactToken; -contacts.importContactToken#13005788 token:string = User; -contacts.editCloseFriends#ba6705f0 id:Vector = Bool; -contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector limit:int = Bool; -contacts.getBirthdays#daeda864 = contacts.ContactBirthdays; -contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers; -contacts.updateContactNote#139f63fb id:InputUser note:TextWithEntities = Bool; - -messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; -messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; -messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; -messages.receivedMessages#5a954c0 max_id:int = Vector; -messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; -messages.sendMessage#545cd15a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.sendMedia#330e77f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.forwardMessages#13704a7c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; -messages.reportSpam#cf1592db peer:InputPeer = Bool; -messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; -messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; -messages.getChats#49e9528f id:Vector = messages.Chats; -messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; -messages.editChatTitle#73783ffd chat_id:long title:string = Updates; -messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates; -messages.addChatUser#cbc6d107 chat_id:long user_id:InputUser fwd_limit:int = messages.InvitedUsers; -messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates; -messages.createChat#92ceddd4 flags:# users:Vector title:string ttl_period:flags.0?int = messages.InvitedUsers; -messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; -messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; -messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; -messages.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool; -messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; -messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; -messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; -messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.receivedQueue#55a5bb66 max_qts:int = Vector; -messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; -messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; -messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers; -messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers; -messages.getWebPagePreview#570d6f6f flags:# message:string entities:flags.3?Vector = messages.WebPagePreview; -messages.exportChatInvite#a455de90 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string subscription_pricing:flags.5?StarsSubscriptionPricing = ExportedChatInvite; -messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; -messages.importChatInvite#6c50051c hash:string = Updates; -messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet; -messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; -messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; -messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; -messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool = messages.MessageViews; -messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; -messages.migrateChat#a2875319 chat_id:long = Updates; -messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true groups_only:flags.2?true users_only:flags.3?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; -messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Bool; -messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document; -messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; -messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; -messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; -messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool; -messages.sendInlineBotResult#c0cf7646 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut allow_paid_stars:flags.21?long = Updates; -messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; -messages.editMessage#51e842e1 flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.15?int schedule_repeat_period:flags.18?int quick_reply_shortcut_id:flags.17?int = Updates; -messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; -messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; -messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; -messages.saveDraft#54ae308e flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost = Bool; -messages.getAllDrafts#6a3f8d65 = Updates; -messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; -messages.readFeaturedStickers#5b118126 id:Vector = Bool; -messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; -messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; -messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; -messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers; -messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; -messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; -messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; -messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; -messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; -messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; -messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats; -messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage; -messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; -messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; -messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; -messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; -messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia; -messages.sendScreenshotNotification#a1405817 peer:InputPeer reply_to:InputReplyTo random_id:long = Updates; -messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers; -messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; -messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; -messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; -messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSplitRanges#1cff7e08 = Vector; -messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool; -messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector; -messages.clearAllDrafts#7e58ee9c = Bool; -messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates; -messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; -messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates; -messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; -messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; -messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; -messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; -messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; -messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; -messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; -messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector = Vector; -messages.requestUrlAuth#198fb446 flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; -messages.acceptUrlAuth#b12c7125 flags:# write_allowed:flags.0?true share_phone_number:flags.3?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string = UrlAuthResult; -messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; -messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages; -messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; -messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector = Updates; -messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector = Updates; -messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList; -messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector = Bool; -messages.getDialogFilters#efd48c89 = messages.DialogFilters; -messages.getSuggestedDialogFilters#a29cd42c = Vector; -messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool; -messages.updateDialogFiltersOrder#c563c1e4 order:Vector = Bool; -messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers; -messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; -messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; -messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.deleteChat#5bd0ee50 chat_id:long = Bool; -messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; -messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; -messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport; -messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; -messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; -messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; -messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; -messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite; -messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; -messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; -messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; -messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true subscription_expired:flags.3?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; -messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; -messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; -messages.setChatTheme#81202c9 peer:InputPeer theme:InputChatTheme = Updates; -messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector; -messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; -messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; -messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; -messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; -messages.toggleNoForwards#b11eafa2 peer:InputPeer enabled:Bool = Updates; -messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; -messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector = Updates; -messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector = Updates; -messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList; -messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int paid_enabled:flags.1?Bool = Updates; -messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; -messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool; -messages.translateText#63183030 flags:# peer:flags.0?InputPeer id:flags.0?Vector text:flags.1?Vector to_lang:string = messages.TranslatedText; -messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages; -messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; -messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; -messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; -messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; -messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; -messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true fullscreen:flags.8?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; -messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; -messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; -messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool; -messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector = Vector; -messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers; -messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers; -messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer = Bool; -messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions; -messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions; -messages.clearRecentReactions#9dfeefb4 = Bool; -messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector = Updates; -messages.setDefaultHistoryTTL#9eb51445 period:int = Bool; -messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL; -messages.sendBotRequestedPeer#91b2d060 peer:InputPeer msg_id:int button_id:int requested_peers:Vector = Updates; -messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups; -messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups; -messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups; -messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; -messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; -messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; -messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; -messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; -messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; -messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; -messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; -messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags; -messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; -messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; -messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate; -messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies; -messages.reorderQuickReplies#60331907 order:Vector = Bool; -messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool; -messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool; -messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool; -messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector hash:long = messages.Messages; -messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vector random_id:Vector = Updates; -messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; -messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; -messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; -messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; -messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; -messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; -messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; -messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; -messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates; -messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool; -messages.getPaidReactionPrivacy#472455aa = Updates; -messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; -messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; -messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; -messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages; -messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; -messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; -messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; -messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; -messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; -messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; -messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; -messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; -messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates; -messages.getForumTopics#3ba47bff flags:# peer:InputPeer q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; -messages.getForumTopicsByID#af0a4a08 peer:InputPeer topics:Vector = messages.ForumTopics; -messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates; -messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates; -messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector = Updates; -messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; -messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory; -messages.getEmojiGameInfo#fb7e8ca7 = messages.EmojiGameInfo; -messages.summarizeText#9d4104e2 flags:# peer:InputPeer id:int to_lang:flags.0?string = TextWithEntities; - -updates.getState#edd4882a = updates.State; -updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; -updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; - -photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo; -photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo; -photos.deletePhotos#87cf7f2f id:Vector = Vector; -photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; -photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo; - -upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; -upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File; -upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; -upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; -upload.getCdnFile#395f69da file_token:bytes offset:long limit:int = upload.CdnFile; -upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; -upload.getCdnFileHashes#91dc3f31 file_token:bytes offset:long = Vector; -upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector; - -help.getConfig#c4f9186b = Config; -help.getNearestDc#1fb33026 = NearestDc; -help.getAppUpdate#522d5a7d source:string = help.AppUpdate; -help.getInviteText#4d392343 = help.InviteText; -help.getSupport#9cdf08cd = help.Support; -help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; -help.getCdnConfig#52029342 = CdnConfig; -help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; -help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; -help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; -help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; -help.getAppConfig#61e3f854 hash:int = help.AppConfig; -help.saveAppLog#6f02f748 events:Vector = Bool; -help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; -help.getSupportName#d360e72c = help.SupportName; -help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; -help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; -help.getPromoData#c0977421 = help.PromoData; -help.hidePromoData#1e251c95 peer:InputPeer = Bool; -help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; -help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; -help.getPremiumPromo#b81b93d4 = help.PremiumPromo; -help.getPeerColors#da80f42f hash:int = help.PeerColors; -help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors; -help.getTimezonesList#49b30240 hash:int = help.TimezonesList; - -channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; -channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; -channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector = Bool; -channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; -channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; -channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; -channels.getChannels#a7f6bbb id:Vector = messages.Chats; -channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; -channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates; -channels.editAdmin#d33c8902 channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:string = Updates; -channels.editTitle#566decd0 channel:InputChannel title:string = Updates; -channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; -channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; -channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; -channels.joinChannel#24b524c5 channel:InputChannel = Updates; -channels.leaveChannel#f836aa95 channel:InputChannel = Updates; -channels.inviteToChannel#c9e33d54 channel:InputChannel users:Vector = messages.InvitedUsers; -channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; -channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; -channels.toggleSignatures#418d549c flags:# signatures_enabled:flags.0?true profiles_enabled:flags.1?true channel:InputChannel = Updates; -channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_personal:flags.2?true = messages.Chats; -channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; -channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; -channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; -channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates; -channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; -channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; -channels.getGroupsForDiscussion#f5dad378 = messages.Chats; -channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; -channels.editCreator#8f38cd1f channel:InputChannel user_id:InputUser password:InputCheckPasswordSRP = Updates; -channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; -channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; -channels.getInactiveChannels#11e831ee = messages.InactiveChats; -channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; -channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true for_live_stories:flags.1?true peer:InputPeer = channels.SendAsPeers; -channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory; -channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates; -channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates; -channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector = Bool; -channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool; -channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool; -channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates; -channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates; -channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool; -channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; -channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates; -channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; -channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats; -channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates; -channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates; -channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; -channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; -channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; -channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; -channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; -channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood; -channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool; -channels.getFutureCreatorAfterLeave#a00918af channel:InputChannel = User; - -bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; -bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; -bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector = Bool; -bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool; -bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector; -bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool; -bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton; -bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool; -bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool; -bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool; -bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo; -bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector = Bool; -bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool; -bots.canSendMessage#1359f4e6 bot:InputUser = Bool; -bots.allowSendMessage#f132e3ef bot:InputUser = Updates; -bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; -bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; -bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia; -bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia; -bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector = Bool; -bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector = Bool; -bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo; -bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; -bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool; -bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; -bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; -bots.getAdminedBots#b0711d83 = Vector; -bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram; -bots.setCustomVerification#8b89dfbd flags:# enabled:flags.1?true bot:flags.0?InputUser peer:InputPeer custom_description:flags.2?string = Bool; -bots.getBotRecommendations#a1b70815 bot:InputUser = users.Users; - -payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; -payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; -payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; -payments.sendPaymentForm#2d03522f flags:# form_id:long invoice:InputInvoice requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; -payments.getSavedInfo#227d824b = payments.SavedInfo; -payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; -payments.getBankCardData#2e79d779 number:string = payments.BankCardData; -payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; -payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; -payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; -payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector; -payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; -payments.applyGiftCode#f6e26854 slug:string = Updates; -payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; -payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; -payments.getStarsTopupOptions#c00ec7d3 = Vector; -payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus; -payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; -payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult; -payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; -payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats; -payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; -payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; -payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector = payments.StarsStatus; -payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; -payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; -payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; -payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; -payments.getStarsGiveawayOptions#bd1efd3e = Vector; -payments.getStarGifts#c4563590 hash:int = payments.StarGifts; -payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool; -payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool; -payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; -payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; -payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots; -payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; -payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview; -payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates; -payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates; -payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift; -payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_unique:flags.4?true sort_by_value:flags.5?true exclude_upgradable:flags.7?true exclude_unupgradable:flags.8?true peer_color_available:flags.9?true exclude_hosted:flags.10?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts; -payments.getSavedStarGift#b455a106 stargift:Vector = payments.SavedStarGifts; -payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; -payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; -payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; -payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; -payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true for_craft:flags.4?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; -payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; -payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; -payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; -payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector = Bool; -payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool; -payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections; -payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo; -payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult; -payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState; -payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts; -payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions; -payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates; -payments.sendStarGiftOffer#8fb86b41 flags:# peer:InputPeer slug:string price:StarsAmount duration:int random_id:long allow_paid_stars:flags.0?long = Updates; -payments.getStarGiftUpgradeAttributes#6d038b58 gift_id:long = payments.StarGiftUpgradeAttributes; -payments.getCraftStarGifts#fd05dd00 gift_id:long offset:string limit:int = payments.SavedStarGifts; -payments.craftStarGift#b0f9684f stargift:Vector = Updates; - -stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; -stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; -stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; -stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; -stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet; -stickers.checkShortName#284b3639 short_name:string = Bool; -stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName; -stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet; -stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet; -stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool; -stickers.replaceSticker#4696459a sticker:InputDocument new_sticker:InputStickerSetItem = messages.StickerSet; - -phone.getCallConfig#55451fa9 = DataJSON; -phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; -phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; -phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; -phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; -phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; -phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; -phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; -phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates; -phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; -phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; -phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; -phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates; -phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; -phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; -phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; -phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; -phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; -phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; -phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; -phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; -phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; -phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; -phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; -phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates; -phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates; -phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels; -phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl; -phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool; -phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates; -phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector block:bytes = Updates; -phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates; -phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates; -phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates; -phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates; -phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates; -phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool; -phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector = Updates; -phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates; -phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars; -phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool; - -langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; -langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; -langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; -langpack.getLanguages#42c6978f lang_pack:string = Vector; -langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; - -folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; - -stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats; -stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; -stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; -stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards; -stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; -stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; -stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards; - -chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; -chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; -chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector = ExportedChatlistInvite; -chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites; -chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite; -chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector = Updates; -chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates; -chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector = Updates; -chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool; -chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector; -chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector = Updates; - -stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount; -stories.sendStory#737fc2ec flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector = Updates; -stories.editStory#b583ba46 flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector = Updates; -stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; -stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; -stories.getAllStories#eeb0d625 flags:# next:flags.1?true hidden:flags.2?true state:flags.0?string = stories.AllStories; -stories.getPinnedStories#5821a5dc peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector = stories.Stories; -stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool; -stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector; -stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector = Bool; -stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList; -stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector = stories.StoryViews; -stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; -stories.report#19d8eb45 peer:InputPeer id:Vector option:bytes message:string = ReportResult; -stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates; -stories.sendReaction#7fd736b2 flags:# add_to_recent:flags.0?true peer:InputPeer story_id:int reaction:Reaction = Updates; -stories.getPeerStories#2c4ada50 peer:InputPeer = stories.PeerStories; -stories.getAllReadPeerStories#9b5ae7f9 = Updates; -stories.getPeerMaxIDs#78499170 id:Vector = Vector; -stories.getChatsToSend#a56a8b60 = messages.Chats; -stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; -stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; -stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; -stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories; -stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector = StoryAlbum; -stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector add_stories:flags.2?Vector order:flags.3?Vector = StoryAlbum; -stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector = Bool; -stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool; -stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums; -stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories; -stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates; - -premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; -premium.getMyBoosts#be77b4a = premium.MyBoosts; -premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; -premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; -premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; - -smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin; -smsjobs.join#a74ece2d = Bool; -smsjobs.leave#9898ad73 = Bool; -smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool; -smsjobs.getStatus#10a698e8 = smsjobs.Status; -smsjobs.getSmsJob#778d902f job_id:string = SmsJob; -smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; - -fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; - -// LAYER 222 diff --git a/internal/compat/layerwire/_schema/layer-223.tl b/internal/compat/layerwire/_schema/layer-223.tl deleted file mode 100644 index bca9aecc..00000000 --- a/internal/compat/layerwire/_schema/layer-223.tl +++ /dev/null @@ -1,2914 +0,0 @@ -boolFalse#bc799737 = Bool; -boolTrue#997275b5 = Bool; - -true#3fedd339 = True; - -vector#1cb5c415 {t:Type} # [ t ] = Vector t; - -error#c4b9f9bb code:int text:string = Error; - -null#56730bcc = Null; - -inputPeerEmpty#7f3b18ea = InputPeer; -inputPeerSelf#7da07ec9 = InputPeer; -inputPeerChat#35a95cb9 chat_id:long = InputPeer; -inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; -inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer; -inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer; -inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer; - -inputUserEmpty#b98886cf = InputUser; -inputUserSelf#f7c1b13f = InputUser; -inputUser#f21158c6 user_id:long access_hash:long = InputUser; -inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser; - -inputPhoneContact#6a1dc4be flags:# client_id:long phone:string first_name:string last_name:string note:flags.0?TextWithEntities = InputContact; - -inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; -inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; -inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile; - -inputMediaEmpty#9664f57f = InputMedia; -inputMediaUploadedPhoto#1e287d04 flags:# spoiler:flags.2?true file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int = InputMedia; -inputMediaPhoto#b3ba0635 flags:# spoiler:flags.1?true id:InputPhoto ttl_seconds:flags.0?int = InputMedia; -inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; -inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; -inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; -inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; -inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; -inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; -inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; -inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; -inputMediaPoll#f94e5f1 flags:# poll:Poll correct_answers:flags.0?Vector solution:flags.1?string solution_entities:flags.1?Vector = InputMedia; -inputMediaDice#e66fbf7b emoticon:string = InputMedia; -inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; -inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; -inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; -inputMediaTodo#9fc55fde todo:TodoList = InputMedia; -inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia; - -inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; -inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; -inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; - -inputGeoPointEmpty#e4c123d6 = InputGeoPoint; -inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint; - -inputPhotoEmpty#1cd7bf0d = InputPhoto; -inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; - -inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; -inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; -inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; -inputTakeoutFileLocation#29be5899 = InputFileLocation; -inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; -inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; -inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; -inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; - -peerUser#59511722 user_id:long = Peer; -peerChat#36c6019a chat_id:long = Peer; -peerChannel#a2a5371e channel_id:long = Peer; - -storage.fileUnknown#aa963b05 = storage.FileType; -storage.filePartial#40bc6f52 = storage.FileType; -storage.fileJpeg#7efe0e = storage.FileType; -storage.fileGif#cae1aadf = storage.FileType; -storage.filePng#a4f63c0 = storage.FileType; -storage.filePdf#ae1e508d = storage.FileType; -storage.fileMp3#528a0677 = storage.FileType; -storage.fileMov#4b09ebbc = storage.FileType; -storage.fileMp4#b3cea0e4 = storage.FileType; -storage.fileWebp#1081464c = storage.FileType; - -userEmpty#d3bc4b7a id:long = User; -user#31774388 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true bot_business:flags2.11?true bot_has_main_app:flags2.13?true bot_forum_view:flags2.16?true bot_forum_can_manage_topics:flags2.17?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?RecentStory color:flags2.8?PeerColor profile_color:flags2.9?PeerColor bot_active_users:flags2.12?int bot_verification_icon:flags2.14?long send_paid_messages_stars:flags2.15?long = User; - -userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; - -userStatusEmpty#9d05049 = UserStatus; -userStatusOnline#edb93949 expires:int = UserStatus; -userStatusOffline#8c703f was_online:int = UserStatus; -userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus; -userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus; -userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; - -chatEmpty#29562865 id:long = Chat; -chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; -chatForbidden#6592a1a7 id:long title:string = Chat; -channel#1c32b11c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?RecentStory color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat; -channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true monoforum:flags.10?true id:long access_hash:long title:string until_date:flags.16?int = Chat; - -chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#e4e0b29d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab = ChatFull; - -chatParticipant#38e79fde flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; -chatParticipantCreator#e1f867b8 flags:# user_id:long rank:flags.0?string = ChatParticipant; -chatParticipantAdmin#360d5d2 flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; - -chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants; -chatParticipants#3cbc93f8 chat_id:long participants:Vector version:int = ChatParticipants; - -chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; - -messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; -message#3ae56482 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int from_rank:flags2.12?string peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string = Message; -messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; - -messageMediaEmpty#3ded6320 = MessageMedia; -messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; -messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; -messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; -messageMediaUnsupported#9f84f49e = MessageMedia; -messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; -messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; -messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; -messageMediaGame#fdb19008 game:Game = MessageMedia; -messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia; -messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia; -messageMediaPoll#4bd6e798 poll:Poll results:PollResults = MessageMedia; -messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia; -messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; -messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; -messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; -messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; -messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector = MessageMedia; -messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia; - -messageActionEmpty#b6aef7b0 = MessageAction; -messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; -messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; -messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; -messageActionChatDeletePhoto#95e3fbef = MessageAction; -messageActionChatAddUser#15cefd00 users:Vector = MessageAction; -messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction; -messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction; -messageActionChannelCreate#95d2ac92 title:string = MessageAction; -messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction; -messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction; -messageActionPinMessage#94bd38ed = MessageAction; -messageActionHistoryClear#9fbab604 = MessageAction; -messageActionGameScore#92a72876 game_id:long score:int = MessageAction; -messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction; -messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction; -messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; -messageActionScreenshotTaken#4792929b = MessageAction; -messageActionCustomAction#fae69f56 message:string = MessageAction; -messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction; -messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; -messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; -messageActionContactSignUp#f3f25f76 = MessageAction; -messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction; -messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; -messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector = MessageAction; -messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction; -messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; -messageActionSetChatTheme#b91bbd3a theme:ChatTheme = MessageAction; -messageActionChatJoinedByRequest#ebbca3cb = MessageAction; -messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction; -messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction; -messageActionGiftPremium#48e91302 flags:# currency:string amount:long days:int crypto_currency:flags.0?string crypto_amount:flags.0?long message:flags.1?TextWithEntities = MessageAction; -messageActionTopicCreate#d999256 flags:# title_missing:flags.1?true title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction; -messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction; -messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; -messageActionRequestedPeer#31518e9b button_id:int peers:Vector = MessageAction; -messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; -messageActionGiftCode#31c48347 flags:# via_giveaway:flags.0?true unclaimed:flags.5?true boost_peer:flags.1?Peer days:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long message:flags.4?TextWithEntities = MessageAction; -messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction; -messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction; -messageActionBoostApply#cc02aa6d boosts:int = MessageAction; -messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; -messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; -messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; -messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; -messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction; -messageActionStarGiftUnique#e6c31522 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true craft:flags.16?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long can_craft_at:flags.15?int = MessageAction; -messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; -messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; -messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; -messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; -messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; -messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction; -messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction; -messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction; -messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction; -messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction; -messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction; -messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction; -messageActionNewCreatorPending#b07ed085 new_creator_id:long = MessageAction; -messageActionChangeCreator#e188503b new_creator_id:long = MessageAction; -messageActionNoForwardsToggle#bf7d6572 prev_value:Bool new_value:Bool = MessageAction; -messageActionNoForwardsRequest#3e2793ba flags:# expired:flags.0?true prev_value:Bool new_value:Bool = MessageAction; - -dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; -dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; - -photoEmpty#2331b22d id:long = Photo; -photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = Photo; - -photoSizeEmpty#e17e23c type:string = PhotoSize; -photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; -photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; -photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; -photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; -photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; - -geoPointEmpty#1117dd5f = GeoPoint; -geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; - -auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; -auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; -auth.sentCodePaymentRequired#e0955a3c store_product:string phone_code_hash:string support_email_address:string support_email_subject:string currency:string amount:long = auth.SentCode; - -auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; -auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; - -auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; - -inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; -inputNotifyUsers#193b4417 = InputNotifyPeer; -inputNotifyChats#4a95e84e = InputNotifyPeer; -inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; -inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer; - -inputPeerNotifySettings#cacb6ae2 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_sound:flags.8?NotificationSound = InputPeerNotifySettings; - -peerNotifySettings#99622c0c flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_ios_sound:flags.8?NotificationSound stories_android_sound:flags.9?NotificationSound stories_other_sound:flags.10?NotificationSound = PeerNotifySettings; - -peerSettings#f47741f7 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true business_bot_paused:flags.11?true business_bot_can_reply:flags.12?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int business_bot_id:flags.13?long business_bot_manage_url:flags.13?string charge_paid_message_stars:flags.14?long registration_month:flags.15?string phone_country:flags.16?string name_change_date:flags.17?int photo_change_date:flags.18?int = PeerSettings; - -wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; -wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; - -inputReportReasonSpam#58dbcab8 = ReportReason; -inputReportReasonViolence#1e22c78d = ReportReason; -inputReportReasonPornography#2e59d922 = ReportReason; -inputReportReasonChildAbuse#adf44ee3 = ReportReason; -inputReportReasonOther#c1e4a2b1 = ReportReason; -inputReportReasonCopyright#9b89f93a = ReportReason; -inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; -inputReportReasonFake#f5ddd6e7 = ReportReason; -inputReportReasonIllegalDrugs#a8eb2be = ReportReason; -inputReportReasonPersonalDetails#9ec7863d = ReportReason; - -userFull#a02bc13e flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true noforwards_my_enabled:flags2.23?true noforwards_peer_enabled:flags2.24?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme:flags.15?ChatTheme private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int main_tab:flags2.20?ProfileTab saved_music:flags2.21?Document note:flags2.22?TextWithEntities = UserFull; - -contact#145ade0b user_id:long mutual:Bool = Contact; - -importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; - -contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; - -contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; -contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; - -contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; - -contacts.blocked#ade1591 blocked:Vector chats:Vector users:Vector = contacts.Blocked; -contacts.blockedSlice#e1664194 count:int blocked:Vector chats:Vector users:Vector = contacts.Blocked; - -messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; - -messages.messages#1d73e7ea messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#5f206716 flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesNotModified#74535f21 count:int = messages.Messages; - -messages.chats#64ff9fd5 chats:Vector = messages.Chats; -messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; - -messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; - -messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; - -inputMessagesFilterEmpty#57e2f66c = MessagesFilter; -inputMessagesFilterPhotos#9609a51c = MessagesFilter; -inputMessagesFilterVideo#9fc00e65 = MessagesFilter; -inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; -inputMessagesFilterDocument#9eddf188 = MessagesFilter; -inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; -inputMessagesFilterGif#ffc86587 = MessagesFilter; -inputMessagesFilterVoice#50f5c392 = MessagesFilter; -inputMessagesFilterMusic#3751b49e = MessagesFilter; -inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; -inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; -inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; -inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; -inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; -inputMessagesFilterGeo#e7026d0d = MessagesFilter; -inputMessagesFilterContacts#e062db83 = MessagesFilter; -inputMessagesFilterPinned#1bb00451 = MessagesFilter; - -updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; -updateMessageID#4e90bfd6 id:int random_id:long = Update; -updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; -updateUserTyping#2a17bf5c flags:# user_id:long top_msg_id:flags.0?int action:SendMessageAction = Update; -updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update; -updateChatParticipants#7761198 participants:ChatParticipants = Update; -updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; -updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector = Update; -updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update; -updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; -updateEncryptedChatTyping#1710f156 chat_id:int = Update; -updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; -updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; -updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update; -updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update; -updateDcOptions#8e5e9873 dc_options:Vector = Update; -updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; -updateServiceNotification#ebe46819 flags:# popup:flags.0?true invert_media:flags.2?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; -updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; -updateUserPhone#5492a13 user_id:long phone:string = Update; -updateReadHistoryInbox#9e84bc99 flags:# folder_id:flags.0?int peer:Peer top_msg_id:flags.1?int max_id:int still_unread_count:int pts:int pts_count:int = Update; -updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; -updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; -updateReadMessagesContents#f8227181 flags:# messages:Vector pts:int pts_count:int date:flags.0?int = Update; -updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; -updateChannel#635b4c09 channel_id:long = Update; -updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update; -updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; -updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; -updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; -updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Update; -updateStickerSets#31c24808 flags:# masks:flags.0?true emojis:flags.1?true = Update; -updateSavedGifs#9375341e = Update; -updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; -updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; -updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; -updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; -updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; -updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update; -updateReadFeaturedStickers#571d2742 = Update; -updateRecentStickers#9a422c20 = Update; -updateConfig#a229dd06 = Update; -updatePtsChanged#3354678f = Update; -updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update; -updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; -updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; -updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; -updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; -updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update; -updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; -updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; -updateLangPackTooLong#46560264 lang_code:string = Update; -updateLangPack#56022f4d difference:LangPackDifference = Update; -updateFavedStickers#e511996d = Update; -updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector = Update; -updateContactsReset#7084a7be = Update; -updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; -updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update; -updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; -updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; -updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; -updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update; -updatePeerLocated#b4afcfb0 peers:Vector = Update; -updateNewScheduledMessage#39a51dfb message:Message = Update; -updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector sent_messages:flags.0?Vector = Update; -updateTheme#8216fba3 theme:Theme = Update; -updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update; -updateLoginToken#564fe691 = Update; -updateMessagePollVote#24f40e77 poll_id:long peer:Peer options:Vector qts:int = Update; -updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update; -updateDialogFilterOrder#a5d72105 order:Vector = Update; -updateDialogFilters#3504914f = Update; -updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update; -updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update; -updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update; -updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update; -updatePeerBlocked#ebe07752 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer = Update; -updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; -updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; -updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChat#f89a6a4e chat_id:long = Update; -updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; -updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update; -updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; -updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update; -updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update; -updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; -updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; -updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update; -updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update; -updateAttachMenuBots#17b7a20b = Update; -updateWebViewResultSent#1592b79d query_id:long = Update; -updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update; -updateSavedRingtones#74d8be99 = Update; -updateTranscribedAudio#84cd5a flags:# pending:flags.0?true peer:Peer msg_id:int transcription_id:long text:string = Update; -updateReadFeaturedEmojiStickers#fb4c496c = Update; -updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update; -updateRecentEmojiStatuses#30f443db = Update; -updateRecentReactions#6f7863f4 = Update; -updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update; -updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector = Update; -updateUser#20529438 user_id:long = Update; -updateAutoSaveSettings#ec05b097 = Update; -updateStory#75b3b798 peer:Peer story:StoryItem = Update; -updateReadStories#f74e932b peer:Peer max_id:int = Update; -updateStoryID#1bf335b9 id:int random_id:long = Update; -updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update; -updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update; -updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update; -updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update; -updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update; -updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector new_reactions:Vector qts:int = Update; -updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector qts:int = Update; -updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; -updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector = Update; -updateSavedReactionTags#39c67432 = Update; -updateSmsJob#f16269d4 job_id:string = Update; -updateQuickReplies#f9470ab2 quick_replies:Vector = Update; -updateNewQuickReply#f53da717 quick_reply:QuickReply = Update; -updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update; -updateQuickReplyMessage#3e050d0f message:Message = Update; -updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector = Update; -updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Update; -updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; -updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; -updateStarsBalance#4e80a379 balance:StarsAmount = Update; -updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; -updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; -updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; -updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; -updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; -updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; -updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update; -updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = Update; -updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update; -updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update; -updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector = Update; -updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector = Update; -updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update; -updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update; -updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update; -updateStarGiftCraftFail#ac072444 = Update; -updateChatParticipantRank#bd8367b9 chat_id:long user_id:long rank:string version:int = Update; - -updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; - -updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; -updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; -updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; -updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; - -updatesTooLong#e317af7e = Updates; -updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShort#78d4dec1 update:Update date:int = Updates; -updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; -updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; -updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; -photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; - -photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; - -upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; -upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; - -dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; - -config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config; - -nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; - -help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate; -help.noAppUpdate#c45a6536 = help.AppUpdate; - -help.inviteText#18cb9f78 message:string = help.InviteText; - -encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; -encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat; -encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; -encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; -encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat; - -inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; - -encryptedFileEmpty#c21f497e = EncryptedFile; -encryptedFile#a8008cd8 id:long access_hash:long size:long dc_id:int key_fingerprint:int = EncryptedFile; - -inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; -inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; -inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; -inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; - -encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; -encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; - -messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; -messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; - -messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; -messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; - -inputDocumentEmpty#72f0eaae = InputDocument; -inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; - -documentEmpty#36f8c871 id:long = Document; -document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector video_thumbs:flags.1?Vector dc_id:int attributes:Vector = Document; - -help.support#17c6b5f6 phone_number:string user:User = help.Support; - -notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; -notifyUsers#b4c83b4c = NotifyPeer; -notifyChats#c007cec3 = NotifyPeer; -notifyBroadcasts#d612e8ef = NotifyPeer; -notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer; - -sendMessageTypingAction#16bf744e = SendMessageAction; -sendMessageCancelAction#fd5ec8f5 = SendMessageAction; -sendMessageRecordVideoAction#a187d66f = SendMessageAction; -sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; -sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; -sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; -sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; -sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; -sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; -sendMessageChooseContactAction#628cbc6f = SendMessageAction; -sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; -sendMessageRecordRoundAction#88f27fbc = SendMessageAction; -sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; -speakingInGroupCallAction#d92c2285 = SendMessageAction; -sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; -sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; -sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction; -sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction; -sendMessageTextDraftAction#376d975c random_id:long text:TextWithEntities = SendMessageAction; - -contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; - -inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; -inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; -inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; -inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; -inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; -inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; -inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; -inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey; -inputPrivacyKeyVoiceMessages#aee69d68 = InputPrivacyKey; -inputPrivacyKeyAbout#3823cc40 = InputPrivacyKey; -inputPrivacyKeyBirthday#d65a11cc = InputPrivacyKey; -inputPrivacyKeyStarGiftsAutoSave#e1732341 = InputPrivacyKey; -inputPrivacyKeyNoPaidMessages#bdc597b4 = InputPrivacyKey; -inputPrivacyKeySavedMusic#4dbe9226 = InputPrivacyKey; - -privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; -privacyKeyChatInvite#500e6dfa = PrivacyKey; -privacyKeyPhoneCall#3d662b7b = PrivacyKey; -privacyKeyPhoneP2P#39491cc8 = PrivacyKey; -privacyKeyForwards#69ec56a3 = PrivacyKey; -privacyKeyProfilePhoto#96151fed = PrivacyKey; -privacyKeyPhoneNumber#d19ae46d = PrivacyKey; -privacyKeyAddedByPhone#42ffd42b = PrivacyKey; -privacyKeyVoiceMessages#697f414 = PrivacyKey; -privacyKeyAbout#a486b761 = PrivacyKey; -privacyKeyBirthday#2000a518 = PrivacyKey; -privacyKeyStarGiftsAutoSave#2ca4fdf8 = PrivacyKey; -privacyKeyNoPaidMessages#17d348d2 = PrivacyKey; -privacyKeySavedMusic#ff7a571b = PrivacyKey; - -inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; -inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; -inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; -inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; -inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; -inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; -inputPrivacyValueAllowChatParticipants#840649cf chats:Vector = InputPrivacyRule; -inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector = InputPrivacyRule; -inputPrivacyValueAllowCloseFriends#2f453e49 = InputPrivacyRule; -inputPrivacyValueAllowPremium#77cdc9f1 = InputPrivacyRule; -inputPrivacyValueAllowBots#5a4fcce5 = InputPrivacyRule; -inputPrivacyValueDisallowBots#c4e57915 = InputPrivacyRule; - -privacyValueAllowContacts#fffe1bac = PrivacyRule; -privacyValueAllowAll#65427b82 = PrivacyRule; -privacyValueAllowUsers#b8905fb2 users:Vector = PrivacyRule; -privacyValueDisallowContacts#f888fa1a = PrivacyRule; -privacyValueDisallowAll#8b73e763 = PrivacyRule; -privacyValueDisallowUsers#e4621141 users:Vector = PrivacyRule; -privacyValueAllowChatParticipants#6b134e8e chats:Vector = PrivacyRule; -privacyValueDisallowChatParticipants#41c87565 chats:Vector = PrivacyRule; -privacyValueAllowCloseFriends#f7e8d89b = PrivacyRule; -privacyValueAllowPremium#ece9814b = PrivacyRule; -privacyValueAllowBots#21461b5d = PrivacyRule; -privacyValueDisallowBots#f6a5f82f = PrivacyRule; - -account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; - -accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; - -documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; -documentAttributeAnimated#11b58939 = DocumentAttribute; -documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; -documentAttributeVideo#43c57c48 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double video_codec:flags.5?string = DocumentAttribute; -documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; -documentAttributeFilename#15590068 file_name:string = DocumentAttribute; -documentAttributeHasStickers#9801d2f7 = DocumentAttribute; -documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute; - -messages.stickersNotModified#f1749a22 = messages.Stickers; -messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; - -stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; - -messages.allStickersNotModified#e86602c3 = messages.AllStickers; -messages.allStickers#cdbbcebb hash:long sets:Vector = messages.AllStickers; - -messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; - -webPageEmpty#211a1788 flags:# id:long url:flags.0?string = WebPage; -webPagePending#b0d13e47 flags:# id:long url:flags.0?string date:int = WebPage; -webPage#e89c45b2 flags:# has_large_media:flags.13?true video_cover_photo:flags.14?true id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector = WebPage; -webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; - -authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; - -account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector = account.Authorizations; - -account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password; - -account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; - -account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; - -auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; - -receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; - -chatInviteExported#a22cbd96 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int subscription_expired:flags.10?int title:flags.8?string subscription_pricing:flags.9?StarsSubscriptionPricing = ExportedChatInvite; -chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite; - -chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#5c9d3702 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true can_refulfill_subscription:flags.11?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector color:int subscription_pricing:flags.10?StarsSubscriptionPricing subscription_form_id:flags.12?long bot_verification:flags.13?BotVerification = ChatInvite; -chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; - -inputStickerSetEmpty#ffb62b95 = InputStickerSet; -inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; -inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; -inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; -inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; -inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet; -inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet; -inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; -inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; -inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet; -inputStickerSetTonGifts#1cf671a0 = InputStickerSet; - -stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; - -messages.stickerSet#6e153f16 set:StickerSet packs:Vector keywords:Vector documents:Vector = messages.StickerSet; -messages.stickerSetNotModified#d3f924eb = messages.StickerSet; - -botCommand#c27ac8c7 command:string description:string = BotCommand; - -botInfo#4d8a0299 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton privacy_policy_url:flags.7?string app_settings:flags.8?BotAppSettings verifier_settings:flags.9?BotVerifierSettings = BotInfo; - -keyboardButton#7d170cff flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrl#d80c25ec flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonCallback#e62bc960 flags:# requires_password:flags.0?true style:flags.10?KeyboardButtonStyle text:string data:bytes = KeyboardButton; -keyboardButtonRequestPhone#417efd8f flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonRequestGeoLocation#aa40f94d flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonSwitchInline#991399fc flags:# same_peer:flags.0?true style:flags.10?KeyboardButtonStyle text:string query:string peer_types:flags.1?Vector = KeyboardButton; -keyboardButtonGame#89c590f9 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonBuy#3fa53905 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrlAuth#f51006f9 flags:# style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; -inputKeyboardButtonUrlAuth#68013e72 flags:# request_write_access:flags.0?true style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; -keyboardButtonRequestPoll#7a11d782 flags:# style:flags.10?KeyboardButtonStyle quiz:flags.0?Bool text:string = KeyboardButton; -inputKeyboardButtonUserProfile#7d5e07c7 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:InputUser = KeyboardButton; -keyboardButtonUserProfile#c0fd5d09 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:long = KeyboardButton; -keyboardButtonWebView#e846b1a0 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonSimpleWebView#e15c4370 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonRequestPeer#5b0f15f5 flags:# style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -inputKeyboardButtonRequestPeer#2b78156 flags:# name_requested:flags.0?true username_requested:flags.1?true photo_requested:flags.2?true style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -keyboardButtonCopy#bcc4af10 flags:# style:flags.10?KeyboardButtonStyle text:string copy_text:string = KeyboardButton; - -keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; - -replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; -replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup; -replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector placeholder:flags.3?string = ReplyMarkup; -replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; - -messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; -messageEntityMention#fa04579d offset:int length:int = MessageEntity; -messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; -messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; -messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; -messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; -messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; -messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; -messageEntityCode#28a20571 offset:int length:int = MessageEntity; -messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; -messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; -messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity; -inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; -messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; -messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; -messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity; -messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; -messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; -messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; -messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; -messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity; -messageEntityFormattedDate#904ac7c7 flags:# relative:flags.0?true short_time:flags.1?true long_time:flags.2?true short_date:flags.3?true long_date:flags.4?true day_of_week:flags.5?true offset:int length:int date:int = MessageEntity; - -inputChannelEmpty#ee8c1e86 = InputChannel; -inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; -inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel; - -contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; - -messageRange#ae30253 min_id:int max_id:int = MessageRange; - -updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; -updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; -updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; - -channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; -channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; - -channelParticipant#1bd54456 flags:# user_id:long date:int subscription_until_date:flags.0?int rank:flags.2?string = ChannelParticipant; -channelParticipantSelf#a9478a1a flags:# via_request:flags.0?true user_id:long inviter_id:long date:int subscription_until_date:flags.1?int rank:flags.2?string = ChannelParticipant; -channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; -channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; -channelParticipantBanned#d5f0ad91 flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights rank:flags.2?string = ChannelParticipant; -channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; - -channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; -channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; -channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; -channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; -channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; -channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; -channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; -channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; - -channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; -channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; - -channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; - -help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; - -messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; -messages.savedGifs#84a02a0d hash:long gifs:Vector = messages.SavedGifs; - -inputBotInlineMessageMediaAuto#3380c786 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaWebPage#bddcc510 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true optional:flags.6?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; - -botInlineMessageMediaAuto#764cf810 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; -botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; - -messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector cache_time:int users:Vector = messages.BotResults; - -exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; - -messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader; - -auth.codeTypeSms#72a3158c = auth.CodeType; -auth.codeTypeCall#741cd3e3 = auth.CodeType; -auth.codeTypeFlashCall#226ccefb = auth.CodeType; -auth.codeTypeMissedCall#d61ad6ee = auth.CodeType; -auth.codeTypeFragmentSms#6ed998c = auth.CodeType; - -auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; -auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; -auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; -auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType; -auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; -auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; -auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; -auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; -auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; -auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; - -messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; - -messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; - -inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; -inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID; - -inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; - -messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; - -topPeer#edcdc05b peer:Peer rating:double = TopPeer; - -topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; -topPeerCategoryBotsInline#148677e2 = TopPeerCategory; -topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; -topPeerCategoryGroups#bd17a14a = TopPeerCategory; -topPeerCategoryChannels#161d9628 = TopPeerCategory; -topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; -topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; -topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; -topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory; - -topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; - -contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; -contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; -contacts.topPeersDisabled#b52c939d = contacts.TopPeers; - -draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; -draftMessage#96eaa5eb flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost = DraftMessage; - -messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; -messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; - -messages.recentStickersNotModified#b17f890 = messages.RecentStickers; -messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; - -messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; - -messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; -messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; - -stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; -stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; -stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector keywords:Vector documents:Vector = StickerSetCovered; -stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered; - -maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; - -inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; -inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; - -game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; - -inputGameID#32c3e77 id:long access_hash:long = InputGame; -inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; - -highScore#73a379eb pos:int user_id:long score:int = HighScore; - -messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; - -textEmpty#dc3d824f = RichText; -textPlain#744694e0 text:string = RichText; -textBold#6724abc4 text:RichText = RichText; -textItalic#d912a59c text:RichText = RichText; -textUnderline#c12622c4 text:RichText = RichText; -textStrike#9bf8bb95 text:RichText = RichText; -textFixed#6c3f19b9 text:RichText = RichText; -textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; -textEmail#de5a0dd6 text:RichText email:string = RichText; -textConcat#7e6260d7 texts:Vector = RichText; -textSubscript#ed6a8504 text:RichText = RichText; -textSuperscript#c7fb5e01 text:RichText = RichText; -textMarked#34b8621 text:RichText = RichText; -textPhone#1ccb966a text:RichText phone:string = RichText; -textImage#81ccf4f document_id:long w:int h:int = RichText; -textAnchor#35553762 text:RichText name:string = RichText; - -pageBlockUnsupported#13567e8a = PageBlock; -pageBlockTitle#70abc3fd text:RichText = PageBlock; -pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; -pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; -pageBlockHeader#bfd064ec text:RichText = PageBlock; -pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; -pageBlockParagraph#467a0766 text:RichText = PageBlock; -pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; -pageBlockFooter#48870999 text:RichText = PageBlock; -pageBlockDivider#db20b188 = PageBlock; -pageBlockAnchor#ce0d37b0 name:string = PageBlock; -pageBlockList#e4e88011 items:Vector = PageBlock; -pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; -pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; -pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; -pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; -pageBlockCover#39f23300 cover:PageBlock = PageBlock; -pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; -pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; -pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; -pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; -pageBlockChannel#ef1751b5 channel:Chat = PageBlock; -pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; -pageBlockKicker#1e148390 text:RichText = PageBlock; -pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; -pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; -pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; -pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; -pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; - -phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; -phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; -phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; -phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; -phoneCallDiscardReasonMigrateConferenceCall#9fbbf1f7 slug:string = PhoneCallDiscardReason; - -dataJSON#7d748d04 data:string = DataJSON; - -labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; - -invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector terms_url:flags.10?string subscription_period:flags.11?int = Invoice; - -paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; - -postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; - -paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; - -paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; - -webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; -webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; - -inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; - -inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; -inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; -inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation; - -upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; - -payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector users:Vector = payments.PaymentForm; -payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector = payments.PaymentForm; -payments.paymentFormStarGift#b425cfe1 form_id:long invoice:Invoice = payments.PaymentForm; - -payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; - -payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; -payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; - -payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; -payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector = payments.PaymentReceipt; - -payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; - -inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; -inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials; - -account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; - -shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; - -inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem; - -inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; - -phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#30535af5 flags:# p2p_allowed:flags.5?true video:flags.6?true conference_supported:flags.8?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int custom_parameters:flags.7?DataJSON = PhoneCall; -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; - -phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; -phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection; - -phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector = PhoneCallProtocol; - -phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; - -upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; -upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; - -cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; - -cdnConfig#5725e40a public_keys:Vector = CdnConfig; - -langPackString#cad181f6 key:string value:string = LangPackString; -langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; -langPackStringDeleted#2979eeb2 key:string = LangPackString; - -langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; - -langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; - -channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; -channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector new_value:Vector = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAutotranslation#c517f77e new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantEditRank#5806b4ec user_id:long prev_rank:string new_rank:string = ChannelAdminLogEventAction; - -channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; - -channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; - -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true edit_rank:flags.19?true = ChannelAdminLogEventsFilter; - -popularContact#5ce14175 client_id:long importers:int = PopularContact; - -messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; -messages.favedStickers#2cb51097 hash:long packs:Vector stickers:Vector = messages.FavedStickers; - -recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; -recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl; -recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl; -recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; -recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; - -help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; - -inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; - -webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; - -account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; - -inputMessageID#a676a322 id:int = InputMessage; -inputMessageReplyTo#bad88395 id:int = InputMessage; -inputMessagePinned#86872538 = InputMessage; -inputMessageCallbackQuery#acfa1a7e id:int query_id:long = InputMessage; - -inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; -inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; - -dialogPeer#e56dbf05 peer:Peer = DialogPeer; -dialogPeerFolder#514519e2 folder_id:int = DialogPeer; - -messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; -messages.foundStickerSets#8af09dd2 hash:long sets:Vector = messages.FoundStickerSets; - -fileHash#f39b035c offset:long limit:int hash:bytes = FileHash; - -inputClientProxy#75588b3f address:string port:int = InputClientProxy; - -help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; -help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; - -inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; -inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; - -secureFileEmpty#64199744 = SecureFile; -secureFile#7d09c27e id:long access_hash:long size:long dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; - -secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; - -securePlainPhone#7d6099dd phone:string = SecurePlainData; -securePlainEmail#21ec5a5f email:string = SecurePlainData; - -secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; -secureValueTypePassport#3dac6a00 = SecureValueType; -secureValueTypeDriverLicense#6e425c4 = SecureValueType; -secureValueTypeIdentityCard#a0d0744b = SecureValueType; -secureValueTypeInternalPassport#99a48f23 = SecureValueType; -secureValueTypeAddress#cbe31e26 = SecureValueType; -secureValueTypeUtilityBill#fc36954e = SecureValueType; -secureValueTypeBankStatement#89137c0d = SecureValueType; -secureValueTypeRentalAgreement#8b883488 = SecureValueType; -secureValueTypePassportRegistration#99e3806a = SecureValueType; -secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; -secureValueTypePhone#b320aadb = SecureValueType; -secureValueTypeEmail#8e3ca7ee = SecureValueType; - -secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; - -inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; - -secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; - -secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; -secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; -secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; - -secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; - -account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; - -account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; - -help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; -help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; - -savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; - -account.takeout#4dba4501 id:long = account.Takeout; - -passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; -passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; - -securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; -securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; -securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; - -secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; - -inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; -inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; - -secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; -secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; - -help.passportConfigNotModified#bfb9f457 = help.PassportConfig; -help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; - -inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; - -jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; - -jsonNull#3f6d7b68 = JSONValue; -jsonBool#c7345e6a value:Bool = JSONValue; -jsonNumber#2be0dfa4 value:double = JSONValue; -jsonString#b71e767a value:string = JSONValue; -jsonArray#f7444763 value:Vector = JSONValue; -jsonObject#99c1d49d value:Vector = JSONValue; - -pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; - -pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; - -pageCaption#6f747657 text:RichText credit:RichText = PageCaption; - -pageListItemText#b92fb6cd text:RichText = PageListItem; -pageListItemBlocks#25e073fc blocks:Vector = PageListItem; - -pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; -pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; - -pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; - -page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector views:flags.3?int = Page; - -help.supportName#8c05f1c9 name:string = help.SupportName; - -help.userInfoEmpty#f3ae2eed = help.UserInfo; -help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; - -pollAnswer#ff16e2ca text:TextWithEntities option:bytes = PollAnswer; - -poll#58747131 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true question:TextWithEntities answers:Vector close_period:flags.4?int close_date:flags.5?int = Poll; - -pollAnswerVoters#3b6ddad2 flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int = PollAnswerVoters; - -pollResults#7adf2420 flags:# min:flags.0?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector = PollResults; - -chatOnlines#f041e250 onlines:int = ChatOnlines; - -statsURL#47a971e0 url:string = StatsURL; - -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true manage_ranks:flags.18?true = ChatAdminRights; - -chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true edit_rank:flags.26?true until_date:int = ChatBannedRights; - -inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; -inputWallPaperSlug#72091c80 slug:string = InputWallPaper; -inputWallPaperNoFile#967a462e id:long = InputWallPaper; - -account.wallPapersNotModified#1c199183 = account.WallPapers; -account.wallPapers#cdc3858c hash:long wallpapers:Vector = account.WallPapers; - -codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true unknown_number:flags.9?true logout_tokens:flags.6?Vector token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings; - -wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings; - -autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings; - -account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; - -emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector = EmojiKeyword; -emojiKeywordDeleted#236df622 keyword:string emoticons:Vector = EmojiKeyword; - -emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector = EmojiKeywordsDifference; - -emojiURL#a575739d url:string = EmojiURL; - -emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; - -folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; - -inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; - -folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; - -messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; - -urlAuthResultRequest#f8f8eb1e flags:# request_write_access:flags.0?true request_phone_number:flags.1?true match_codes_first:flags.5?true bot:User domain:string browser:flags.2?string platform:flags.2?string ip:flags.2?string region:flags.2?string match_codes:flags.3?Vector user_id_hint:flags.4?long = UrlAuthResult; -urlAuthResultAccepted#623a8fa0 flags:# url:flags.0?string = UrlAuthResult; -urlAuthResultDefault#a9d6db1f = UrlAuthResult; - -channelLocationEmpty#bfb5ad8b = ChannelLocation; -channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation; - -peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated; -peerSelfLocated#f8ec284b expires:int = PeerLocated; - -restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason; - -inputTheme#3c5693e9 id:long access_hash:long = InputTheme; -inputThemeSlug#f5890df1 slug:string = InputTheme; - -theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector emoticon:flags.6?string installs_count:flags.4?int = Theme; - -account.themesNotModified#f41eb622 = account.Themes; -account.themes#9a3d8c6d hash:long themes:Vector = account.Themes; - -auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken; -auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken; -auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken; - -account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings; - -messages.inactiveChats#a927fec5 dates:Vector chats:Vector users:Vector = messages.InactiveChats; - -baseThemeClassic#c3a12462 = BaseTheme; -baseThemeDay#fbd81688 = BaseTheme; -baseThemeNight#b7b31ea8 = BaseTheme; -baseThemeTinted#6d5f77ee = BaseTheme; -baseThemeArctic#5b11125a = BaseTheme; - -inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; - -themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; - -webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; -webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; -webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; -webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; -webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; -webPageAttributeStarGiftAuction#1c641c2 gift:StarGift end_date:int = WebPageAttribute; - -messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; - -bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl; - -payments.bankCardData#3e24e573 title:string open_urls:Vector = payments.BankCardData; - -dialogFilter#aa472651 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector exclude_peers:Vector = DialogFilter; -dialogFilterDefault#363293ae = DialogFilter; -dialogFilterChatlist#96537bd7 flags:# has_my_invites:flags.26?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector = DialogFilter; - -dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested; - -statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays; - -statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev; - -statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue; - -statsGraphAsync#4a27eb2d token:string = StatsGraph; -statsGraphError#bedc9822 error:string = StatsGraph; -statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph; - -stats.broadcastStats#396ca5fc period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev reactions_per_post:StatsAbsValueAndPrev views_per_story:StatsAbsValueAndPrev shares_per_story:StatsAbsValueAndPrev reactions_per_story:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_posts_interactions:Vector = stats.BroadcastStats; - -help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; -help.promoData#8a4d87a flags:# proxy:flags.0?true expires:int peer:flags.3?Peer psa_type:flags.1?string psa_message:flags.2?string pending_suggestions:Vector dismissed_suggestions:Vector custom_pending_suggestion:flags.4?PendingSuggestion chats:Vector users:Vector = help.PromoData; - -videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; -videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector = VideoSize; -videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector = VideoSize; - -statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster; - -statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; - -statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; - -stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; - -globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; - -help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; - -help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector = help.Country; - -help.countriesListNotModified#93cc1f32 = help.CountriesList; -help.countriesList#87d0759e countries:Vector hash:int = help.CountriesList; - -messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews; - -messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; - -messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; - -messageReplyHeader#6917560b flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector quote_offset:flags.10?int todo_item_id:flags.11?int = MessageReplyHeader; -messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader; - -messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; - -peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; - -stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; - -groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall; - -inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -inputGroupCallSlug#fe06823f slug:string = InputGroupCall; -inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall; - -groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant; - -phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; - -phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; - -inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; -inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; -inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType; -inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType; -inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType; -inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType; - -messages.historyImport#1662af0b id:long = messages.HistoryImport; - -messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed; - -messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector = messages.AffectedFoundMessages; - -chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter; - -messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; - -messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; -messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; - -messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; - -chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites; - -messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; - -messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; - -phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; - -phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; - -groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector = GroupCallParticipantVideoSourceGroup; - -groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector audio_source:flags.1?int = GroupCallParticipantVideo; - -stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName; - -botCommandScopeDefault#2f6cb2ab = BotCommandScope; -botCommandScopeUsers#3c4f04d8 = BotCommandScope; -botCommandScopeChats#6fe1a881 = BotCommandScope; -botCommandScopeChatAdmins#b9aa606a = BotCommandScope; -botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope; -botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope; -botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope; - -account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult; -account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; -account.resetPasswordOk#e926d63e = account.ResetPasswordResult; - -chatTheme#c3dffc04 emoticon:string = ChatTheme; -chatThemeUniqueGift#3458f9c8 gift:StarGift theme_settings:Vector = ChatTheme; - -account.chatThemesNotModified#e011e1c4 = account.ChatThemes; -account.chatThemes#be098173 flags:# hash:long themes:Vector chats:Vector users:Vector next_offset:flags.0?string = account.ChatThemes; - -sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage; - -messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; -messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; - -searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; - -messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector messages:Vector chats:Vector users:Vector = messages.SearchResultsCalendar; - -searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition; - -messages.searchResultsPositions#53b22baf count:int positions:Vector = messages.SearchResultsPositions; - -channels.sendAsPeers#f496b0c6 peers:Vector chats:Vector users:Vector = channels.SendAsPeers; - -users.userFull#3b6d152e full_user:UserFull chats:Vector users:Vector = users.UserFull; - -messages.peerSettings#6880b94d settings:PeerSettings chats:Vector users:Vector = messages.PeerSettings; - -auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut; - -reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; - -messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector recent_reactions:flags.1?Vector top_reactors:flags.4?Vector = MessageReactions; - -messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.MessageReactionsList; - -availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; - -messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions; -messages.availableReactions#768e3aad hash:int reactions:Vector = messages.AvailableReactions; - -messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true my:flags.2?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction; - -groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel; - -phone.groupCallStreamChannels#d0e482b2 channels:Vector = phone.GroupCallStreamChannels; - -phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl; - -attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; - -attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector = AttachMenuBotIcon; - -attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector icons:Vector = AttachMenuBot; - -attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; -attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector = AttachMenuBots; - -attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector = AttachMenuBotsBot; - -webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true fullscreen:flags.2?true query_id:flags.0?long url:string = WebViewResult; - -webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent; - -botMenuButtonDefault#7533a588 = BotMenuButton; -botMenuButtonCommands#4258c205 = BotMenuButton; -botMenuButton#c7b57ce6 text:string url:string = BotMenuButton; - -account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones; -account.savedRingtones#c1e92cc5 hash:long ringtones:Vector = account.SavedRingtones; - -notificationSoundDefault#97e8bebe = NotificationSound; -notificationSoundNone#6f0c34df = NotificationSound; -notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound; -notificationSoundRingtone#ff6c8049 id:long = NotificationSound; - -account.savedRingtone#b7263f6d = account.SavedRingtone; -account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone; - -attachMenuPeerTypeSameBotPM#7d6be90e = AttachMenuPeerType; -attachMenuPeerTypeBotPM#c32bfa1a = AttachMenuPeerType; -attachMenuPeerTypePM#f146d31f = AttachMenuPeerType; -attachMenuPeerTypeChat#509113f = AttachMenuPeerType; -attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; - -inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; -inputInvoiceSlug#c326caef slug:string = InputInvoice; -inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; -inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice; -inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice; -inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; -inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; -inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; -inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; -inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice; -inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice; - -payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; - -messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; - -help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; - -inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose; -inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentPremiumGiftCode#fb790393 flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long message:flags.1?TextWithEntities = InputStorePaymentPurpose; -inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsTopup#f9a2a6cb flags:# stars:long currency:string amount:long spend_purpose_peer:flags.0?InputPeer = InputStorePaymentPurpose; -inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; -inputStorePaymentAuthCode#9bb2636d flags:# restore:flags.0?true phone_number:string phone_code_hash:string currency:string amount:long = InputStorePaymentPurpose; - -paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; - -emojiStatusEmpty#2de11aae = EmojiStatus; -emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus; -emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus; -inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus; - -account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses; -account.emojiStatuses#90c467d1 hash:long statuses:Vector = account.EmojiStatuses; - -reactionEmpty#79f5d419 = Reaction; -reactionEmoji#1b2286b8 emoticon:string = Reaction; -reactionCustomEmoji#8935fc73 document_id:long = Reaction; -reactionPaid#523da4eb = Reaction; - -chatReactionsNone#eafc32bc = ChatReactions; -chatReactionsAll#52928bca flags:# allow_custom:flags.0?true = ChatReactions; -chatReactionsSome#661d4037 reactions:Vector = ChatReactions; - -messages.reactionsNotModified#b06fdbdf = messages.Reactions; -messages.reactions#eafdf716 hash:long reactions:Vector = messages.Reactions; - -emailVerifyPurposeLoginSetup#4345be73 phone_number:string phone_code_hash:string = EmailVerifyPurpose; -emailVerifyPurposeLoginChange#527d22eb = EmailVerifyPurpose; -emailVerifyPurposePassport#bbf51685 = EmailVerifyPurpose; - -emailVerificationCode#922e55a9 code:string = EmailVerification; -emailVerificationGoogle#db909ec2 token:string = EmailVerification; -emailVerificationApple#96d074fd token:string = EmailVerification; - -account.emailVerified#2b96cd1b email:string = account.EmailVerified; -account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified; - -premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption; - -sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer; - -messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia; -messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia; - -stickerKeyword#fcfeb29c document_id:long keyword:Vector = StickerKeyword; - -username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username; - -forumTopicDeleted#23f109b id:int = ForumTopic; -forumTopic#cdff0eca flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true title_missing:flags.7?true id:int date:int peer:Peer title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic; - -messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector messages:Vector chats:Vector users:Vector pts:int = messages.ForumTopics; - -defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL; - -exportedContactToken#41bf109b url:string expires:int = ExportedContactToken; - -requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType; -requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; - -emojiListNotModified#481eadfa = EmojiList; -emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; - -emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; - -messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; -messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; - -textWithEntities#751f3146 text:string entities:Vector = TextWithEntities; - -messages.translateResult#33db32f8 result:Vector = messages.TranslatedText; - -autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings; - -autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException; - -account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector chats:Vector users:Vector = account.AutoSaveSettings; - -help.appConfigNotModified#7cde641d = help.AppConfig; -help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig; - -inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp; -inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp; - -botAppNotModified#5da674b7 = BotApp; -botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; - -messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp; - -inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; - -readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; - -inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist; - -exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector = ExportedChatlistInvite; - -chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite; - -chatlists.exportedInvites#10ab6dc7 invites:Vector chats:Vector users:Vector = chatlists.ExportedInvites; - -chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector already_peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; -chatlists.chatlistInvite#f10ece2f flags:# title_noanimate:flags.1?true title:TextWithEntities emoticon:flags.0?string peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; - -chatlists.chatlistUpdates#93bd878d missing_peers:Vector chats:Vector users:Vector = chatlists.ChatlistUpdates; - -bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo; - -messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote; -messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote; -messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector date:int = MessagePeerVote; - -storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector reactions_count:flags.4?int recent_viewers:flags.0?Vector = StoryViews; - -storyItemDeleted#51e6ee4f id:int = StoryItem; -storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true live:flags.9?true id:int date:int expire_date:int = StoryItem; -storyItem#edf164f1 flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector = StoryItem; - -stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; -stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; - -stories.stories#63c3dd0a flags:# count:int stories:Vector pinned_to_top:flags.0?Vector chats:Vector users:Vector = stories.Stories; - -storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView; -storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView; -storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView; - -stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryViewsList; - -stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; - -inputReplyToMessage#869fbe10 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int = InputReplyTo; -inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; -inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; - -exportedStoryLink#3fc9053b link:string = ExportedStoryLink; - -storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; - -mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates; - -mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea; -inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea; -mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea; -mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea; -mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; -inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; -mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; -mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea; -mediaAreaStarGift#5787686d coordinates:MediaAreaCoordinates slug:string = MediaArea; - -peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; - -stories.peerStories#cae68768 stories:PeerStories chats:Vector users:Vector = stories.PeerStories; - -messages.webPage#fd5e12bd webpage:WebPage chats:Vector users:Vector = messages.WebPage; - -premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption; - -payments.checkedGiftCode#eb983f8f flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int days:int used_date:flags.1?int chats:Vector users:Vector = payments.CheckedGiftCode; - -payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; -payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo; - -prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; -prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway; - -boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost; - -premium.boostsList#86f8613c flags:# count:int boosts:Vector next_offset:flags.0?string users:Vector = premium.BoostsList; - -myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost; - -premium.myBoosts#9ae228e2 my_boosts:Vector chats:Vector users:Vector = premium.MyBoosts; - -premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector my_boost_slots:flags.2?Vector = premium.BoostsStatus; - -storyFwdHeader#b826e150 flags:# modified:flags.3?true from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader; - -postInteractionCountersMessage#e7058e7f msg_id:int views:int forwards:int reactions:int = PostInteractionCounters; -postInteractionCountersStory#8a480e27 story_id:int views:int forwards:int reactions:int = PostInteractionCounters; - -stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats; - -publicForwardMessage#1f2bf4a message:Message = PublicForward; -publicForwardStory#edf3add0 peer:Peer story:StoryItem = PublicForward; - -stats.publicForwards#93037e20 flags:# count:int forwards:Vector next_offset:flags.0?string chats:Vector users:Vector = stats.PublicForwards; - -peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor; -peerColorCollectible#b9c0639a flags:# collectible_id:long gift_emoji_id:long background_emoji_id:long accent_color:int colors:Vector dark_accent_color:flags.0?int dark_colors:flags.1?Vector = PeerColor; -inputPeerColorCollectible#b8ea86a9 collectible_id:long = PeerColor; - -help.peerColorSet#26219a58 colors:Vector = help.PeerColorSet; -help.peerColorProfileSet#767d61eb palette_colors:Vector bg_colors:Vector story_colors:Vector = help.PeerColorSet; - -help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption; - -help.peerColorsNotModified#2ba1f5ce = help.PeerColors; -help.peerColors#f8ed08 hash:int colors:Vector = help.PeerColors; - -storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction; -storyReactionPublicForward#bbab2643 message:Message = StoryReaction; -storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; - -stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; - -savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; -monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; - -messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; - -savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; - -messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; -messages.savedReactionTags#3259950a tags:Vector hash:long = messages.SavedReactionTags; - -outboxReadDate#3bb842ac date:int = OutboxReadDate; - -smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin; - -smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status; - -smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob; - -businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen; - -businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector = BusinessWorkHours; - -businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation; - -inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = InputBusinessRecipients; - -businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = BusinessRecipients; - -businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule; - -inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage; - -businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage; - -inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage; - -businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage; - -timezone#ff9289f5 id:string name:string utc_offset:int = Timezone; - -help.timezonesListNotModified#970708cc = help.TimezonesList; -help.timezonesList#7b74ed71 timezones:Vector hash:int = help.TimezonesList; - -quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply; - -inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut; -inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; - -messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; -messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; - -connectedBot#cd64636c flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights = ConnectedBot; - -account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; - -messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector = messages.DialogFilters; - -birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; - -botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; - -inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; - -businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro; - -messages.myStickers#faff629d count:int sets:Vector = messages.MyStickers; - -inputCollectibleUsername#e39460a9 username:string = InputCollectible; -inputCollectiblePhone#a2e214a4 phone:string = InputCollectible; - -fragment.collectibleInfo#6ebdff91 purchase_date:int currency:string amount:long crypto_currency:string crypto_amount:long url:string = fragment.CollectibleInfo; - -inputBusinessBotRecipients#c4e5921e flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = InputBusinessBotRecipients; - -businessBotRecipients#b88cf373 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = BusinessBotRecipients; - -contactBirthday#1d998733 contact_id:long birthday:Birthday = ContactBirthday; - -contacts.contactBirthdays#114ff30d contacts:Vector users:Vector = contacts.ContactBirthdays; - -missingInvitee#628c9224 flags:# premium_would_allow_invite:flags.0?true premium_required_for_pm:flags.1?true user_id:long = MissingInvitee; - -messages.invitedUsers#7f5defa6 updates:Updates missing_invitees:Vector = messages.InvitedUsers; - -inputBusinessChatLink#11679fa7 flags:# message:string entities:flags.0?Vector title:flags.1?string = InputBusinessChatLink; - -businessChatLink#b4ae666f flags:# link:string message:string entities:flags.0?Vector title:flags.1?string views:int = BusinessChatLink; - -account.businessChatLinks#ec43a2d1 links:Vector chats:Vector users:Vector = account.BusinessChatLinks; - -account.resolvedBusinessChatLinks#9a23af21 flags:# peer:Peer message:string entities:flags.0?Vector chats:Vector users:Vector = account.ResolvedBusinessChatLinks; - -requestedPeerUser#d62ff46a flags:# user_id:long first_name:flags.0?string last_name:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChat#7307544f flags:# chat_id:long title:flags.0?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChannel#8ba403e4 flags:# channel_id:long title:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; - -sponsoredMessageReportOption#430d3150 text:string option:bytes = SponsoredMessageReportOption; - -channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:Vector = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; - -reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; -reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; - -reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; - -availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; - -messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; -messages.availableEffects#bddb616e hash:int effects:Vector documents:Vector = messages.AvailableEffects; - -factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck; - -starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer; -starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer; -starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; -starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; -starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; -starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; -starsTransactionPeerAds#60682812 = StarsTransactionPeer; -starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; - -starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; - -starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true posts_search:flags.24?true stargift_prepaid_upgrade:flags.25?true stargift_drop_original_details:flags.26?true phonegroup_message:flags.27?true stargift_auction_bid:flags.28?true offer:flags.29?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction; - -payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; - -foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; - -stories.foundStories#e2de7737 flags:# count:int stories:Vector next_offset:flags.0?string chats:Vector users:Vector = stories.FoundStories; - -geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; - -starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; - -payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; - -payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; - -payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl; - -inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; - -starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption; - -bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector = bots.PopularAppBots; - -botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia; - -bots.previewInfo#ca71d64 media:Vector lang_codes:Vector = bots.PreviewInfo; - -starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing; - -starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true bot_canceled:flags.7?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string title:flags.4?string photo:flags.5?WebDocument invoice_slug:flags.6?string = StarsSubscription; - -messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; - -starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; - -starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; - -starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift; -starGiftUnique#85f0a9cd flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true burned:flags.14?true crafted:flags.15?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int craft_chance_permille:flags.16?int = StarGift; - -payments.starGiftsNotModified#a388a368 = payments.StarGifts; -payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; - -messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; - -reportResultChooseOption#f0e4e0b6 title:string options:Vector = ReportResult; -reportResultAddComment#6f09ac31 flags:# optional:flags.0?true option:bytes = ReportResult; -reportResultReported#8db33c4b = ReportResult; - -messages.botPreparedInlineMessage#8ecf0511 id:string expire_date:int = messages.BotPreparedInlineMessage; - -messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult peer_types:Vector cache_time:int users:Vector = messages.PreparedInlineMessage; - -botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings; - -starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram; - -connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef; - -payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector = payments.ConnectedStarRefBots; - -payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; - -starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount; -starsTonAmount#74aee3e0 amount:long = StarsAmount; - -messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers; -messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector = messages.FoundStickers; - -botVerifierSettings#b0cd6617 flags:# can_modify_custom_description:flags.1?true icon:long company:string custom_description:flags.0?string = BotVerifierSettings; - -botVerification#f93cd45c bot_id:long icon:long description:string = BotVerification; - -starGiftAttributeModel#565251e2 flags:# crafted:flags.0?true name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributePattern#4e7085ea name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeBackdrop#9f2504e4 name:string backdrop_id:int center_color:int edge_color:int pattern_color:int text_color:int rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute; - -payments.starGiftUpgradePreview#3de1dfed sample_attributes:Vector prices:Vector next_prices:Vector = payments.StarGiftUpgradePreview; - -users.users#62d706b8 users:Vector = users.Users; -users.usersSlice#315a4974 count:int users:Vector = users.Users; - -payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector users:Vector = payments.UniqueStarGift; - -messages.webPagePreview#8c9a88ac media:MessageMedia chats:Vector users:Vector = messages.WebPagePreview; - -savedStarGift#41df43fc flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int can_craft_at:flags.20?int = SavedStarGift; - -payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; - -inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift; -inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift; -inputSavedStarGiftSlug#2085c238 slug:string = InputSavedStarGift; - -payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl; - -paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy; -paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy; -paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy; - -account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRevenue; - -requirementToContactEmpty#50a9839 = RequirementToContact; -requirementToContactPremium#e581e4e9 = RequirementToContact; -requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; - -businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; - -disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true disallow_stargifts_from_channels:flags.4?true = DisallowedGiftsSettings; - -sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; - -contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; -contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; - -starGiftAttributeIdModel#48aaae3c document_id:long = StarGiftAttributeId; -starGiftAttributeIdPattern#4a162433 document_id:long = StarGiftAttributeId; -starGiftAttributeIdBackdrop#1f01c757 backdrop_id:int = StarGiftAttributeId; - -starGiftAttributeCounter#2eb1b658 attribute:StarGiftAttributeId count:int = StarGiftAttributeCounter; - -payments.resaleStarGifts#947a12df flags:# count:int gifts:Vector next_offset:flags.0?string attributes:flags.1?Vector attributes_hash:flags.1?long chats:Vector counters:flags.2?Vector users:Vector = payments.ResaleStarGifts; - -stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount; - -pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion; - -todoItem#cba9a52f id:int title:TextWithEntities = TodoItem; - -todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector = TodoList; - -todoCompletion#221bb5e4 id:int completed_by:Peer date:int = TodoCompletion; - -suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost; - -starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating; - -starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection; - -payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; -payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; - -storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; - -stories.albumsNotModified#564edaeb = stories.Albums; -stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; - -searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; - -payments.uniqueStarGiftValueInfo#512fe446 flags:# last_sale_on_fragment:flags.1?true value_is_average:flags.6?true currency:string value:long initial_sale_date:int initial_sale_stars:long initial_sale_price:long last_sale_date:flags.0?int last_sale_price:flags.0?long floor_price:flags.2?long average_price:flags.3?long listed_count:flags.4?int fragment_listed_count:flags.5?int fragment_listed_url:flags.5?string = payments.UniqueStarGiftValueInfo; - -profileTabPosts#b98cd696 = ProfileTab; -profileTabGifts#4d4bd46a = ProfileTab; -profileTabMedia#72c64955 = ProfileTab; -profileTabFiles#ab339c00 = ProfileTab; -profileTabMusic#9f27d26e = ProfileTab; -profileTabVoice#e477092e = ProfileTab; -profileTabLinks#d3656499 = ProfileTab; -profileTabGifs#a2c0f695 = ProfileTab; - -users.savedMusicNotModified#e3878aa4 count:int = users.SavedMusic; -users.savedMusic#34a2f297 count:int documents:Vector = users.SavedMusic; - -account.savedMusicIdsNotModified#4fc81d6e = account.SavedMusicIds; -account.savedMusicIds#998d6636 ids:Vector = account.SavedMusicIds; - -payments.checkCanSendGiftResultOk#374fa7ad = payments.CheckCanSendGiftResult; -payments.checkCanSendGiftResultFail#d5e58274 reason:TextWithEntities = payments.CheckCanSendGiftResult; - -inputChatThemeEmpty#83268483 = InputChatTheme; -inputChatTheme#c93de95c emoticon:string = InputChatTheme; -inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme; - -starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice; - -groupCallMessage#1a8afc7e flags:# from_admin:flags.1?true id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage; - -groupCallDonor#ee430c85 flags:# top:flags.0?true my:flags.1?true peer_id:flags.3?Peer stars:long = GroupCallDonor; - -phone.groupCallStars#9d1dbd26 total_stars:long top_donors:Vector chats:Vector users:Vector = phone.GroupCallStars; - -recentStory#711d692d flags:# live:flags.0?true max_id:flags.1?int = RecentStory; - -auctionBidLevel#310240cc pos:int amount:long date:int = AuctionBidLevel; - -starGiftAuctionStateNotModified#fe333952 = StarGiftAuctionState; -starGiftAuctionState#771a4e66 version:int start_date:int end_date:int min_bid_amount:long bid_levels:Vector top_bidders:Vector next_round_at:int last_gift_num:int gifts_left:int current_round:int total_rounds:int rounds:Vector = StarGiftAuctionState; -starGiftAuctionStateFinished#972dabbf flags:# start_date:int end_date:int average_price:long listed_count:flags.0?int fragment_listed_count:flags.1?int fragment_listed_url:flags.1?string = StarGiftAuctionState; - -starGiftAuctionUserState#2eeed1c4 flags:# returned:flags.1?true bid_amount:flags.0?long bid_date:flags.0?int min_bid_amount:flags.0?long bid_peer:flags.0?Peer acquired_count:int = StarGiftAuctionUserState; - -payments.starGiftAuctionState#6b39f4ec gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState timeout:int users:Vector chats:Vector = payments.StarGiftAuctionState; - -starGiftAuctionAcquiredGift#42b00348 flags:# name_hidden:flags.0?true peer:Peer date:int bid_amount:long round:int pos:int message:flags.1?TextWithEntities gift_num:flags.2?int = StarGiftAuctionAcquiredGift; - -payments.starGiftAuctionAcquiredGifts#7d5bd1f0 gifts:Vector users:Vector chats:Vector = payments.StarGiftAuctionAcquiredGifts; - -starGiftActiveAuctionState#d31bc45d gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState = StarGiftActiveAuctionState; - -payments.starGiftActiveAuctionsNotModified#db33dad0 = payments.StarGiftActiveAuctions; -payments.starGiftActiveAuctions#aef6abbc auctions:Vector users:Vector chats:Vector = payments.StarGiftActiveAuctions; - -inputStarGiftAuction#2e16c98 gift_id:long = InputStarGiftAuction; -inputStarGiftAuctionSlug#7ab58308 slug:string = InputStarGiftAuction; - -passkey#98613ebf flags:# id:string name:string date:int software_emoji_id:flags.0?long last_usage_date:flags.1?int = Passkey; - -account.passkeys#f8e0aa1c passkeys:Vector = account.Passkeys; - -account.passkeyRegistrationOptions#e16b5ce1 options:DataJSON = account.PasskeyRegistrationOptions; - -auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions; - -inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse; -inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse; - -inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential; -inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential; - -starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground; - -starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound; -starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound; - -payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector = payments.StarGiftUpgradeAttributes; - -messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome; - -messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo; -messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector plays_left:flags.0?int = messages.EmojiGameInfo; - -starGiftAttributeRarity#36437737 permille:int = StarGiftAttributeRarity; -starGiftAttributeRarityUncommon#dbce6389 = StarGiftAttributeRarity; -starGiftAttributeRarityRare#f08d516b = StarGiftAttributeRarity; -starGiftAttributeRarityEpic#78fbf3a8 = StarGiftAttributeRarity; -starGiftAttributeRarityLegendary#cef7e7a8 = StarGiftAttributeRarity; - -keyboardButtonStyle#4fdd3430 flags:# bg_primary:flags.0?true bg_danger:flags.1?true bg_success:flags.2?true icon:flags.3?long = KeyboardButtonStyle; - ----functions--- - -invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; -invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; -initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; -invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; -invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; -invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; -invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; -invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; -invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; -invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X; -invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X; - -auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; -auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; -auth.signIn#8d52a951 flags:# phone_number:string phone_code_hash:string phone_code:flags.0?string email_verification:flags.1?EmailVerification = auth.Authorization; -auth.logOut#3e72ba19 = auth.LoggedOut; -auth.resetAuthorizations#9fab0d1a = Bool; -auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; -auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; -auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; -auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; -auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; -auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; -auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; -auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode; -auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; -auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; -auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; -auth.acceptLoginToken#e894ad4d token:bytes = Authorization; -auth.checkRecoveryPassword#d36bf79 code:string = Bool; -auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; -auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool; -auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; -auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; -auth.checkPaidAuth#56e59f9c phone_number:string phone_code_hash:string form_id:long = auth.SentCode; -auth.initPasskeyLogin#518ad0b7 api_id:int api_hash:string = auth.PasskeyLoginOptions; -auth.finishPasskeyLogin#9857ad07 flags:# credential:InputPasskeyCredential from_dc_id:flags.0?int from_auth_key_id:flags.0?long = auth.Authorization; - -account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; -account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; -account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; -account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; -account.resetNotifySettings#db7e1747 = Bool; -account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; -account.updateStatus#6628562c offline:Bool = Bool; -account.getWallPapers#7967d36 hash:long = account.WallPapers; -account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool; -account.checkUsername#2714d86c username:string = Bool; -account.updateUsername#3e0bdd7c username:string = User; -account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; -account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; -account.deleteAccount#a2c0cf74 flags:# reason:string password:flags.0?InputCheckPasswordSRP = Bool; -account.getAccountTTL#8fc711d = AccountDaysTTL; -account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; -account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; -account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; -account.updateDeviceLocked#38df3532 period:int = Bool; -account.getAuthorizations#e320c158 = account.Authorizations; -account.resetAuthorization#df77f3bc hash:long = Bool; -account.getPassword#548a30f5 = account.Password; -account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; -account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; -account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; -account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; -account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; -account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; -account.resetWebAuthorization#2d01b9ef hash:long = Bool; -account.resetWebAuthorizations#682d2594 = Bool; -account.getAllSecureValues#b288bc7d = Vector; -account.getSecureValue#73665bc2 types:Vector = Vector; -account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; -account.deleteSecureValue#b880bc4b types:Vector = Bool; -account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm; -account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; -account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; -account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; -account.sendVerifyEmailCode#98e037bb purpose:EmailVerifyPurpose email:string = account.SentEmailCode; -account.verifyEmail#32da4cf purpose:EmailVerifyPurpose verification:EmailVerification = account.EmailVerified; -account.initTakeoutSession#8ef3eab0 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?long = account.Takeout; -account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; -account.confirmPasswordEmail#8fdf1920 code:string = Bool; -account.resendPasswordEmail#7a7f2a15 = Bool; -account.cancelPasswordEmail#c1cbd5b6 = Bool; -account.getContactSignUpNotification#9f07c728 = Bool; -account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; -account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true compare_stories:flags.2?true peer:flags.0?InputNotifyPeer = Updates; -account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; -account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; -account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; -account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; -account.resetWallPapers#bb3b9804 = Bool; -account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; -account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; -account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document; -account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool; -account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool; -account.getTheme#3a5869ec format:string theme:InputTheme = Theme; -account.getThemes#7206e458 format:string hash:long = account.Themes; -account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool; -account.getContentSettings#8b9b4dae = account.ContentSettings; -account.getMultiWallPapers#65ad71dc wallpapers:Vector = Vector; -account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings; -account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; -account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; -account.resetPassword#9308ce1b = account.ResetPasswordResult; -account.declinePasswordReset#4c9409f6 = Bool; -account.getChatThemes#d638de89 hash:long = account.Themes; -account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; -account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; -account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones; -account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone; -account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document; -account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool; -account.getDefaultEmojiStatuses#d6753386 hash:long = account.EmojiStatuses; -account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; -account.clearRecentEmojiStatuses#18201aae = Bool; -account.reorderUsernames#ef500eab order:Vector = Bool; -account.toggleUsername#58d6b376 username:string active:Bool = Bool; -account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList; -account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList; -account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings; -account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool; -account.deleteAutoSaveExceptions#53bc0020 = Bool; -account.invalidateSignInCodes#ca8ae8ba codes:Vector = Bool; -account.updateColor#684d214e flags:# for_profile:flags.1?true color:flags.2?PeerColor = Bool; -account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList; -account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses; -account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList; -account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool; -account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool; -account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool; -account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool; -account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates; -account.getConnectedBots#4ea4c80f = account.ConnectedBots; -account.getBotBusinessConnection#76a86270 connection_id:string = Updates; -account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool; -account.toggleConnectedBotPaused#646e1097 peer:InputPeer paused:Bool = Bool; -account.disablePeerConnectedBot#5e437ed9 peer:InputPeer = Bool; -account.updateBirthday#cc6e0c11 flags:# birthday:flags.0?Birthday = Bool; -account.createBusinessChatLink#8851e68e link:InputBusinessChatLink = BusinessChatLink; -account.editBusinessChatLink#8c3410af slug:string link:InputBusinessChatLink = BusinessChatLink; -account.deleteBusinessChatLink#60073674 slug:string = Bool; -account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks; -account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks; -account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool; -account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool; -account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings; -account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings; -account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses; -account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue; -account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool; -account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool; -account.saveMusic#b26732a9 flags:# unsave:flags.0?true id:InputDocument after_id:flags.1?InputDocument = Bool; -account.getSavedMusicIds#e09d5faf hash:long = account.SavedMusicIds; -account.getUniqueGiftChatThemes#e42ce9c9 offset:string limit:int hash:long = account.ChatThemes; -account.initPasskeyRegistration#429547e8 = account.PasskeyRegistrationOptions; -account.registerPasskey#55b41fd6 credential:InputPasskeyCredential = Passkey; -account.getPasskeys#ea1f0c52 = account.Passkeys; -account.deletePasskey#f5b5563f id:string = Bool; - -users.getUsers#d91a548 id:Vector = Vector; -users.getFullUser#b60f5918 id:InputUser = users.UserFull; -users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; -users.getRequirementsToContact#d89a83a3 id:Vector = Vector; -users.getSavedMusic#788d7fe3 id:InputUser offset:int limit:int hash:long = users.SavedMusic; -users.getSavedMusicByID#7573a4e9 id:InputUser documents:Vector = users.SavedMusic; -users.suggestBirthday#fc533372 id:InputUser birthday:Birthday = Updates; - -contacts.getContactIDs#7adc669d hash:long = Vector; -contacts.getStatuses#c4a353ee = Vector; -contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; -contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; -contacts.deleteContacts#96a0e00 id:Vector = Updates; -contacts.deleteByPhones#1013fd9e phones:Vector = Bool; -contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; -contacts.search#11f812d8 q:string limit:int = contacts.Found; -contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer; -contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true offset:int limit:int hash:long = contacts.TopPeers; -contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; -contacts.resetSaved#879537f1 = Bool; -contacts.getSaved#82f1e39f = Vector; -contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; -contacts.addContact#d9ba2e54 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string note:flags.1?TextWithEntities = Updates; -contacts.acceptContact#f831a20f id:InputUser = Updates; -contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates; -contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates; -contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer; -contacts.exportContactToken#f8654027 = ExportedContactToken; -contacts.importContactToken#13005788 token:string = User; -contacts.editCloseFriends#ba6705f0 id:Vector = Bool; -contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector limit:int = Bool; -contacts.getBirthdays#daeda864 = contacts.ContactBirthdays; -contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers; -contacts.updateContactNote#139f63fb id:InputUser note:TextWithEntities = Bool; - -messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; -messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; -messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; -messages.receivedMessages#5a954c0 max_id:int = Vector; -messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; -messages.sendMessage#545cd15a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.sendMedia#330e77f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.forwardMessages#13704a7c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; -messages.reportSpam#cf1592db peer:InputPeer = Bool; -messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; -messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; -messages.getChats#49e9528f id:Vector = messages.Chats; -messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; -messages.editChatTitle#73783ffd chat_id:long title:string = Updates; -messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates; -messages.addChatUser#cbc6d107 chat_id:long user_id:InputUser fwd_limit:int = messages.InvitedUsers; -messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates; -messages.createChat#92ceddd4 flags:# users:Vector title:string ttl_period:flags.0?int = messages.InvitedUsers; -messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; -messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; -messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; -messages.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool; -messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; -messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; -messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; -messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.receivedQueue#55a5bb66 max_qts:int = Vector; -messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; -messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; -messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers; -messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers; -messages.getWebPagePreview#570d6f6f flags:# message:string entities:flags.3?Vector = messages.WebPagePreview; -messages.exportChatInvite#a455de90 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string subscription_pricing:flags.5?StarsSubscriptionPricing = ExportedChatInvite; -messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; -messages.importChatInvite#6c50051c hash:string = Updates; -messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet; -messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; -messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; -messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; -messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool = messages.MessageViews; -messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; -messages.migrateChat#a2875319 chat_id:long = Updates; -messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true groups_only:flags.2?true users_only:flags.3?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; -messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Bool; -messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document; -messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; -messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; -messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; -messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool; -messages.sendInlineBotResult#c0cf7646 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut allow_paid_stars:flags.21?long = Updates; -messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; -messages.editMessage#51e842e1 flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.15?int schedule_repeat_period:flags.18?int quick_reply_shortcut_id:flags.17?int = Updates; -messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; -messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; -messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; -messages.saveDraft#54ae308e flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost = Bool; -messages.getAllDrafts#6a3f8d65 = Updates; -messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; -messages.readFeaturedStickers#5b118126 id:Vector = Bool; -messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; -messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; -messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; -messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers; -messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; -messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; -messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; -messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; -messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; -messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; -messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats; -messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage; -messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; -messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; -messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; -messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; -messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia; -messages.sendScreenshotNotification#a1405817 peer:InputPeer reply_to:InputReplyTo random_id:long = Updates; -messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers; -messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; -messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; -messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; -messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSplitRanges#1cff7e08 = Vector; -messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool; -messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector; -messages.clearAllDrafts#7e58ee9c = Bool; -messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates; -messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; -messages.getPollResults#73bb643b peer:InputPeer msg_id:int = Updates; -messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; -messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; -messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; -messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; -messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; -messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; -messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; -messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector = Vector; -messages.requestUrlAuth#894cc99c flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string in_app_origin:flags.3?string = UrlAuthResult; -messages.acceptUrlAuth#67a3f0de flags:# write_allowed:flags.0?true share_phone_number:flags.3?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string match_code:flags.4?string = UrlAuthResult; -messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; -messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages; -messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; -messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector = Updates; -messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector = Updates; -messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList; -messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector = Bool; -messages.getDialogFilters#efd48c89 = messages.DialogFilters; -messages.getSuggestedDialogFilters#a29cd42c = Vector; -messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool; -messages.updateDialogFiltersOrder#c563c1e4 order:Vector = Bool; -messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers; -messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; -messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; -messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.deleteChat#5bd0ee50 chat_id:long = Bool; -messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; -messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; -messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport; -messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; -messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; -messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; -messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; -messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite; -messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; -messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; -messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; -messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true subscription_expired:flags.3?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; -messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; -messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; -messages.setChatTheme#81202c9 peer:InputPeer theme:InputChatTheme = Updates; -messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector; -messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; -messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; -messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; -messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; -messages.toggleNoForwards#b2081a35 flags:# peer:InputPeer enabled:Bool request_msg_id:flags.0?int = Updates; -messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; -messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector = Updates; -messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector = Updates; -messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList; -messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int paid_enabled:flags.1?Bool = Updates; -messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; -messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool; -messages.translateText#63183030 flags:# peer:flags.0?InputPeer id:flags.0?Vector text:flags.1?Vector to_lang:string = messages.TranslatedText; -messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages; -messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; -messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; -messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; -messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; -messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; -messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true fullscreen:flags.8?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; -messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; -messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; -messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool; -messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector = Vector; -messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers; -messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers; -messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer = Bool; -messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions; -messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions; -messages.clearRecentReactions#9dfeefb4 = Bool; -messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector = Updates; -messages.setDefaultHistoryTTL#9eb51445 period:int = Bool; -messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL; -messages.sendBotRequestedPeer#91b2d060 peer:InputPeer msg_id:int button_id:int requested_peers:Vector = Updates; -messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups; -messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups; -messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups; -messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; -messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; -messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; -messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; -messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; -messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; -messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; -messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; -messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags; -messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; -messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; -messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate; -messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies; -messages.reorderQuickReplies#60331907 order:Vector = Bool; -messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool; -messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool; -messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool; -messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector hash:long = messages.Messages; -messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vector random_id:Vector = Updates; -messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; -messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; -messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; -messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; -messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; -messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; -messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; -messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; -messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates; -messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool; -messages.getPaidReactionPrivacy#472455aa = Updates; -messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; -messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; -messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; -messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages; -messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; -messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; -messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; -messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; -messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; -messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; -messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; -messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; -messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates; -messages.getForumTopics#3ba47bff flags:# peer:InputPeer q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; -messages.getForumTopicsByID#af0a4a08 peer:InputPeer topics:Vector = messages.ForumTopics; -messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates; -messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates; -messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector = Updates; -messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; -messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory; -messages.getEmojiGameInfo#fb7e8ca7 = messages.EmojiGameInfo; -messages.summarizeText#9d4104e2 flags:# peer:InputPeer id:int to_lang:flags.0?string = TextWithEntities; -messages.editChatCreator#f743b857 peer:InputPeer user_id:InputUser password:InputCheckPasswordSRP = Updates; -messages.getFutureChatCreatorAfterLeave#3b7d0ea6 peer:InputPeer = User; -messages.editChatParticipantRank#a00f32b0 peer:InputPeer participant:InputPeer rank:string = Updates; -messages.declineUrlAuth#35436bbc url:string = Bool; -messages.checkUrlAuthMatchCode#c9a47b0b url:string match_code:string = Bool; - -updates.getState#edd4882a = updates.State; -updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; -updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; - -photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo; -photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo; -photos.deletePhotos#87cf7f2f id:Vector = Vector; -photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; -photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo; - -upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; -upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File; -upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; -upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; -upload.getCdnFile#395f69da file_token:bytes offset:long limit:int = upload.CdnFile; -upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; -upload.getCdnFileHashes#91dc3f31 file_token:bytes offset:long = Vector; -upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector; - -help.getConfig#c4f9186b = Config; -help.getNearestDc#1fb33026 = NearestDc; -help.getAppUpdate#522d5a7d source:string = help.AppUpdate; -help.getInviteText#4d392343 = help.InviteText; -help.getSupport#9cdf08cd = help.Support; -help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; -help.getCdnConfig#52029342 = CdnConfig; -help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; -help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; -help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; -help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; -help.getAppConfig#61e3f854 hash:int = help.AppConfig; -help.saveAppLog#6f02f748 events:Vector = Bool; -help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; -help.getSupportName#d360e72c = help.SupportName; -help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; -help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; -help.getPromoData#c0977421 = help.PromoData; -help.hidePromoData#1e251c95 peer:InputPeer = Bool; -help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; -help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; -help.getPremiumPromo#b81b93d4 = help.PremiumPromo; -help.getPeerColors#da80f42f hash:int = help.PeerColors; -help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors; -help.getTimezonesList#49b30240 hash:int = help.TimezonesList; - -channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; -channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; -channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector = Bool; -channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; -channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; -channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; -channels.getChannels#a7f6bbb id:Vector = messages.Chats; -channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; -channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates; -channels.editAdmin#9a98ad68 flags:# channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:flags.0?string = Updates; -channels.editTitle#566decd0 channel:InputChannel title:string = Updates; -channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; -channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; -channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; -channels.joinChannel#24b524c5 channel:InputChannel = Updates; -channels.leaveChannel#f836aa95 channel:InputChannel = Updates; -channels.inviteToChannel#c9e33d54 channel:InputChannel users:Vector = messages.InvitedUsers; -channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; -channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; -channels.toggleSignatures#418d549c flags:# signatures_enabled:flags.0?true profiles_enabled:flags.1?true channel:InputChannel = Updates; -channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_personal:flags.2?true = messages.Chats; -channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; -channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; -channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; -channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates; -channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; -channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; -channels.getGroupsForDiscussion#f5dad378 = messages.Chats; -channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; -channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; -channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; -channels.getInactiveChannels#11e831ee = messages.InactiveChats; -channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; -channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true for_live_stories:flags.1?true peer:InputPeer = channels.SendAsPeers; -channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory; -channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates; -channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates; -channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector = Bool; -channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool; -channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool; -channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates; -channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates; -channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool; -channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; -channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates; -channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; -channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats; -channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates; -channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates; -channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; -channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; -channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; -channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; -channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; -channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood; -channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool; - -bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; -bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; -bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector = Bool; -bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool; -bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector; -bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool; -bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton; -bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool; -bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool; -bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool; -bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo; -bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector = Bool; -bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool; -bots.canSendMessage#1359f4e6 bot:InputUser = Bool; -bots.allowSendMessage#f132e3ef bot:InputUser = Updates; -bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; -bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; -bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia; -bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia; -bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector = Bool; -bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector = Bool; -bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo; -bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; -bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool; -bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; -bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; -bots.getAdminedBots#b0711d83 = Vector; -bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram; -bots.setCustomVerification#8b89dfbd flags:# enabled:flags.1?true bot:flags.0?InputUser peer:InputPeer custom_description:flags.2?string = Bool; -bots.getBotRecommendations#a1b70815 bot:InputUser = users.Users; - -payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; -payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; -payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; -payments.sendPaymentForm#2d03522f flags:# form_id:long invoice:InputInvoice requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; -payments.getSavedInfo#227d824b = payments.SavedInfo; -payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; -payments.getBankCardData#2e79d779 number:string = payments.BankCardData; -payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; -payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; -payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; -payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector; -payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; -payments.applyGiftCode#f6e26854 slug:string = Updates; -payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; -payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; -payments.getStarsTopupOptions#c00ec7d3 = Vector; -payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus; -payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; -payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult; -payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; -payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats; -payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; -payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; -payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector = payments.StarsStatus; -payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; -payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; -payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; -payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; -payments.getStarsGiveawayOptions#bd1efd3e = Vector; -payments.getStarGifts#c4563590 hash:int = payments.StarGifts; -payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool; -payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool; -payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; -payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; -payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots; -payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; -payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview; -payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates; -payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates; -payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift; -payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_unique:flags.4?true sort_by_value:flags.5?true exclude_upgradable:flags.7?true exclude_unupgradable:flags.8?true peer_color_available:flags.9?true exclude_hosted:flags.10?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts; -payments.getSavedStarGift#b455a106 stargift:Vector = payments.SavedStarGifts; -payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; -payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; -payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; -payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; -payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true for_craft:flags.4?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; -payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; -payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; -payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; -payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector = Bool; -payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool; -payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections; -payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo; -payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult; -payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState; -payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts; -payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions; -payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates; -payments.sendStarGiftOffer#8fb86b41 flags:# peer:InputPeer slug:string price:StarsAmount duration:int random_id:long allow_paid_stars:flags.0?long = Updates; -payments.getStarGiftUpgradeAttributes#6d038b58 gift_id:long = payments.StarGiftUpgradeAttributes; -payments.getCraftStarGifts#fd05dd00 gift_id:long offset:string limit:int = payments.SavedStarGifts; -payments.craftStarGift#b0f9684f stargift:Vector = Updates; - -stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; -stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; -stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; -stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; -stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet; -stickers.checkShortName#284b3639 short_name:string = Bool; -stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName; -stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet; -stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet; -stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool; -stickers.replaceSticker#4696459a sticker:InputDocument new_sticker:InputStickerSetItem = messages.StickerSet; - -phone.getCallConfig#55451fa9 = DataJSON; -phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; -phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; -phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; -phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; -phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; -phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; -phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; -phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates; -phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; -phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; -phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; -phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates; -phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; -phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; -phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; -phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; -phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; -phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; -phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; -phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; -phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; -phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; -phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; -phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates; -phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates; -phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels; -phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl; -phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool; -phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates; -phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector block:bytes = Updates; -phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates; -phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates; -phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates; -phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates; -phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates; -phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool; -phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector = Updates; -phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates; -phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars; -phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool; - -langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; -langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; -langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; -langpack.getLanguages#42c6978f lang_pack:string = Vector; -langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; - -folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; - -stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats; -stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; -stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; -stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards; -stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; -stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; -stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards; - -chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; -chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; -chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector = ExportedChatlistInvite; -chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites; -chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite; -chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector = Updates; -chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates; -chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector = Updates; -chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool; -chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector; -chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector = Updates; - -stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount; -stories.sendStory#737fc2ec flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector = Updates; -stories.editStory#b583ba46 flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector = Updates; -stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; -stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; -stories.getAllStories#eeb0d625 flags:# next:flags.1?true hidden:flags.2?true state:flags.0?string = stories.AllStories; -stories.getPinnedStories#5821a5dc peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector = stories.Stories; -stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool; -stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector; -stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector = Bool; -stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList; -stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector = stories.StoryViews; -stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; -stories.report#19d8eb45 peer:InputPeer id:Vector option:bytes message:string = ReportResult; -stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates; -stories.sendReaction#7fd736b2 flags:# add_to_recent:flags.0?true peer:InputPeer story_id:int reaction:Reaction = Updates; -stories.getPeerStories#2c4ada50 peer:InputPeer = stories.PeerStories; -stories.getAllReadPeerStories#9b5ae7f9 = Updates; -stories.getPeerMaxIDs#78499170 id:Vector = Vector; -stories.getChatsToSend#a56a8b60 = messages.Chats; -stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; -stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; -stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; -stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories; -stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector = StoryAlbum; -stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector add_stories:flags.2?Vector order:flags.3?Vector = StoryAlbum; -stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector = Bool; -stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool; -stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums; -stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories; -stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates; - -premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; -premium.getMyBoosts#be77b4a = premium.MyBoosts; -premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; -premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; -premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; - -smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin; -smsjobs.join#a74ece2d = Bool; -smsjobs.leave#9898ad73 = Bool; -smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool; -smsjobs.getStatus#10a698e8 = smsjobs.Status; -smsjobs.getSmsJob#778d902f job_id:string = SmsJob; -smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; - -fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; - -// LAYER 223 diff --git a/internal/compat/layerwire/_schema/layer-224.tl b/internal/compat/layerwire/_schema/layer-224.tl deleted file mode 100644 index ca55a99a..00000000 --- a/internal/compat/layerwire/_schema/layer-224.tl +++ /dev/null @@ -1,2944 +0,0 @@ -boolFalse#bc799737 = Bool; -boolTrue#997275b5 = Bool; - -true#3fedd339 = True; - -vector#1cb5c415 {t:Type} # [ t ] = Vector t; - -error#c4b9f9bb code:int text:string = Error; - -null#56730bcc = Null; - -inputPeerEmpty#7f3b18ea = InputPeer; -inputPeerSelf#7da07ec9 = InputPeer; -inputPeerChat#35a95cb9 chat_id:long = InputPeer; -inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; -inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer; -inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer; -inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer; - -inputUserEmpty#b98886cf = InputUser; -inputUserSelf#f7c1b13f = InputUser; -inputUser#f21158c6 user_id:long access_hash:long = InputUser; -inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser; - -inputPhoneContact#6a1dc4be flags:# client_id:long phone:string first_name:string last_name:string note:flags.0?TextWithEntities = InputContact; - -inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; -inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; -inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile; - -inputMediaEmpty#9664f57f = InputMedia; -inputMediaUploadedPhoto#7d8375da flags:# spoiler:flags.2?true live_photo:flags.3?true file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int video:flags.3?InputDocument = InputMedia; -inputMediaPhoto#e3af4434 flags:# spoiler:flags.1?true live_photo:flags.2?true id:InputPhoto ttl_seconds:flags.0?int video:flags.2?InputDocument = InputMedia; -inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; -inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; -inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; -inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; -inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; -inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; -inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; -inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; -inputMediaPoll#883a4108 flags:# poll:Poll correct_answers:flags.0?Vector attached_media:flags.3?InputMedia solution:flags.1?string solution_entities:flags.1?Vector solution_media:flags.2?InputMedia = InputMedia; -inputMediaDice#e66fbf7b emoticon:string = InputMedia; -inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; -inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; -inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; -inputMediaTodo#9fc55fde todo:TodoList = InputMedia; -inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia; - -inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; -inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; -inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; - -inputGeoPointEmpty#e4c123d6 = InputGeoPoint; -inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint; - -inputPhotoEmpty#1cd7bf0d = InputPhoto; -inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; - -inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; -inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; -inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; -inputTakeoutFileLocation#29be5899 = InputFileLocation; -inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; -inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; -inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; -inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; - -peerUser#59511722 user_id:long = Peer; -peerChat#36c6019a chat_id:long = Peer; -peerChannel#a2a5371e channel_id:long = Peer; - -storage.fileUnknown#aa963b05 = storage.FileType; -storage.filePartial#40bc6f52 = storage.FileType; -storage.fileJpeg#7efe0e = storage.FileType; -storage.fileGif#cae1aadf = storage.FileType; -storage.filePng#a4f63c0 = storage.FileType; -storage.filePdf#ae1e508d = storage.FileType; -storage.fileMp3#528a0677 = storage.FileType; -storage.fileMov#4b09ebbc = storage.FileType; -storage.fileMp4#b3cea0e4 = storage.FileType; -storage.fileWebp#1081464c = storage.FileType; - -userEmpty#d3bc4b7a id:long = User; -user#31774388 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true bot_business:flags2.11?true bot_has_main_app:flags2.13?true bot_forum_view:flags2.16?true bot_forum_can_manage_topics:flags2.17?true bot_can_manage_bots:flags2.18?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?RecentStory color:flags2.8?PeerColor profile_color:flags2.9?PeerColor bot_active_users:flags2.12?int bot_verification_icon:flags2.14?long send_paid_messages_stars:flags2.15?long = User; - -userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; - -userStatusEmpty#9d05049 = UserStatus; -userStatusOnline#edb93949 expires:int = UserStatus; -userStatusOffline#8c703f was_online:int = UserStatus; -userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus; -userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus; -userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; - -chatEmpty#29562865 id:long = Chat; -chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; -chatForbidden#6592a1a7 id:long title:string = Chat; -channel#1c32b11c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?RecentStory color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat; -channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true monoforum:flags.10?true id:long access_hash:long title:string until_date:flags.16?int = Chat; - -chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#e4e0b29d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab = ChatFull; - -chatParticipant#38e79fde flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; -chatParticipantCreator#e1f867b8 flags:# user_id:long rank:flags.0?string = ChatParticipant; -chatParticipantAdmin#360d5d2 flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; - -chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants; -chatParticipants#3cbc93f8 chat_id:long participants:Vector version:int = ChatParticipants; - -chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; - -messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; -message#3ae56482 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int from_rank:flags2.12?string peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string = Message; -messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; - -messageMediaEmpty#3ded6320 = MessageMedia; -messageMediaPhoto#e216eb63 flags:# spoiler:flags.3?true live_photo:flags.4?true photo:flags.0?Photo ttl_seconds:flags.2?int video:flags.4?Document = MessageMedia; -messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; -messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; -messageMediaUnsupported#9f84f49e = MessageMedia; -messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; -messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; -messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; -messageMediaGame#fdb19008 game:Game = MessageMedia; -messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia; -messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia; -messageMediaPoll#773f4e66 flags:# poll:Poll results:PollResults attached_media:flags.0?MessageMedia = MessageMedia; -messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia; -messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; -messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; -messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; -messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; -messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector = MessageMedia; -messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia; - -messageActionEmpty#b6aef7b0 = MessageAction; -messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; -messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; -messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; -messageActionChatDeletePhoto#95e3fbef = MessageAction; -messageActionChatAddUser#15cefd00 users:Vector = MessageAction; -messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction; -messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction; -messageActionChannelCreate#95d2ac92 title:string = MessageAction; -messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction; -messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction; -messageActionPinMessage#94bd38ed = MessageAction; -messageActionHistoryClear#9fbab604 = MessageAction; -messageActionGameScore#92a72876 game_id:long score:int = MessageAction; -messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction; -messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction; -messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; -messageActionScreenshotTaken#4792929b = MessageAction; -messageActionCustomAction#fae69f56 message:string = MessageAction; -messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction; -messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; -messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; -messageActionContactSignUp#f3f25f76 = MessageAction; -messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction; -messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; -messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector = MessageAction; -messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction; -messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; -messageActionSetChatTheme#b91bbd3a theme:ChatTheme = MessageAction; -messageActionChatJoinedByRequest#ebbca3cb = MessageAction; -messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction; -messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction; -messageActionGiftPremium#48e91302 flags:# currency:string amount:long days:int crypto_currency:flags.0?string crypto_amount:flags.0?long message:flags.1?TextWithEntities = MessageAction; -messageActionTopicCreate#d999256 flags:# title_missing:flags.1?true title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction; -messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction; -messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; -messageActionRequestedPeer#31518e9b button_id:int peers:Vector = MessageAction; -messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; -messageActionGiftCode#31c48347 flags:# via_giveaway:flags.0?true unclaimed:flags.5?true boost_peer:flags.1?Peer days:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long message:flags.4?TextWithEntities = MessageAction; -messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction; -messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction; -messageActionBoostApply#cc02aa6d boosts:int = MessageAction; -messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; -messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; -messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; -messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; -messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction; -messageActionStarGiftUnique#e6c31522 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true craft:flags.16?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long can_craft_at:flags.15?int = MessageAction; -messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; -messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; -messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; -messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; -messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; -messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction; -messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction; -messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction; -messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction; -messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction; -messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction; -messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction; -messageActionNewCreatorPending#b07ed085 new_creator_id:long = MessageAction; -messageActionChangeCreator#e188503b new_creator_id:long = MessageAction; -messageActionNoForwardsToggle#bf7d6572 prev_value:Bool new_value:Bool = MessageAction; -messageActionNoForwardsRequest#3e2793ba flags:# expired:flags.0?true prev_value:Bool new_value:Bool = MessageAction; -messageActionPollAppendAnswer#9da1cd6c answer:PollAnswer = MessageAction; -messageActionPollDeleteAnswer#399674dc answer:PollAnswer = MessageAction; -messageActionManagedBotCreated#16605e3e bot_id:long = MessageAction; - -dialog#fc89f7f3 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; -dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; - -photoEmpty#2331b22d id:long = Photo; -photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = Photo; - -photoSizeEmpty#e17e23c type:string = PhotoSize; -photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; -photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; -photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; -photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; -photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; - -geoPointEmpty#1117dd5f = GeoPoint; -geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; - -auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; -auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; -auth.sentCodePaymentRequired#e0955a3c store_product:string phone_code_hash:string support_email_address:string support_email_subject:string currency:string amount:long = auth.SentCode; - -auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; -auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; - -auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; - -inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; -inputNotifyUsers#193b4417 = InputNotifyPeer; -inputNotifyChats#4a95e84e = InputNotifyPeer; -inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; -inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer; - -inputPeerNotifySettings#cacb6ae2 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_sound:flags.8?NotificationSound = InputPeerNotifySettings; - -peerNotifySettings#99622c0c flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_ios_sound:flags.8?NotificationSound stories_android_sound:flags.9?NotificationSound stories_other_sound:flags.10?NotificationSound = PeerNotifySettings; - -peerSettings#f47741f7 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true business_bot_paused:flags.11?true business_bot_can_reply:flags.12?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int business_bot_id:flags.13?long business_bot_manage_url:flags.13?string charge_paid_message_stars:flags.14?long registration_month:flags.15?string phone_country:flags.16?string name_change_date:flags.17?int photo_change_date:flags.18?int = PeerSettings; - -wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; -wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; - -inputReportReasonSpam#58dbcab8 = ReportReason; -inputReportReasonViolence#1e22c78d = ReportReason; -inputReportReasonPornography#2e59d922 = ReportReason; -inputReportReasonChildAbuse#adf44ee3 = ReportReason; -inputReportReasonOther#c1e4a2b1 = ReportReason; -inputReportReasonCopyright#9b89f93a = ReportReason; -inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; -inputReportReasonFake#f5ddd6e7 = ReportReason; -inputReportReasonIllegalDrugs#a8eb2be = ReportReason; -inputReportReasonPersonalDetails#9ec7863d = ReportReason; - -userFull#6cbe645 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true noforwards_my_enabled:flags2.23?true noforwards_peer_enabled:flags2.24?true unofficial_security_risk:flags2.26?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme:flags.15?ChatTheme private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int main_tab:flags2.20?ProfileTab saved_music:flags2.21?Document note:flags2.22?TextWithEntities bot_manager_id:flags2.25?long = UserFull; - -contact#145ade0b user_id:long mutual:Bool = Contact; - -importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; - -contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; - -contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; -contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; - -contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; - -contacts.blocked#ade1591 blocked:Vector chats:Vector users:Vector = contacts.Blocked; -contacts.blockedSlice#e1664194 count:int blocked:Vector chats:Vector users:Vector = contacts.Blocked; - -messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; - -messages.messages#1d73e7ea messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#5f206716 flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesNotModified#74535f21 count:int = messages.Messages; - -messages.chats#64ff9fd5 chats:Vector = messages.Chats; -messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; - -messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; - -messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; - -inputMessagesFilterEmpty#57e2f66c = MessagesFilter; -inputMessagesFilterPhotos#9609a51c = MessagesFilter; -inputMessagesFilterVideo#9fc00e65 = MessagesFilter; -inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; -inputMessagesFilterDocument#9eddf188 = MessagesFilter; -inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; -inputMessagesFilterGif#ffc86587 = MessagesFilter; -inputMessagesFilterVoice#50f5c392 = MessagesFilter; -inputMessagesFilterMusic#3751b49e = MessagesFilter; -inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; -inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; -inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; -inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; -inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; -inputMessagesFilterGeo#e7026d0d = MessagesFilter; -inputMessagesFilterContacts#e062db83 = MessagesFilter; -inputMessagesFilterPinned#1bb00451 = MessagesFilter; -inputMessagesFilterPoll#fa2bc90a = MessagesFilter; - -updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; -updateMessageID#4e90bfd6 id:int random_id:long = Update; -updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; -updateUserTyping#2a17bf5c flags:# user_id:long top_msg_id:flags.0?int action:SendMessageAction = Update; -updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update; -updateChatParticipants#7761198 participants:ChatParticipants = Update; -updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; -updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector = Update; -updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update; -updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; -updateEncryptedChatTyping#1710f156 chat_id:int = Update; -updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; -updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; -updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update; -updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update; -updateDcOptions#8e5e9873 dc_options:Vector = Update; -updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; -updateServiceNotification#ebe46819 flags:# popup:flags.0?true invert_media:flags.2?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; -updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; -updateUserPhone#5492a13 user_id:long phone:string = Update; -updateReadHistoryInbox#9e84bc99 flags:# folder_id:flags.0?int peer:Peer top_msg_id:flags.1?int max_id:int still_unread_count:int pts:int pts_count:int = Update; -updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; -updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; -updateReadMessagesContents#f8227181 flags:# messages:Vector pts:int pts_count:int date:flags.0?int = Update; -updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; -updateChannel#635b4c09 channel_id:long = Update; -updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update; -updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; -updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; -updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; -updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Update; -updateStickerSets#31c24808 flags:# masks:flags.0?true emojis:flags.1?true = Update; -updateSavedGifs#9375341e = Update; -updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; -updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; -updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; -updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; -updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; -updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update; -updateReadFeaturedStickers#571d2742 = Update; -updateRecentStickers#9a422c20 = Update; -updateConfig#a229dd06 = Update; -updatePtsChanged#3354678f = Update; -updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update; -updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; -updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; -updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; -updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; -updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update; -updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; -updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; -updateLangPackTooLong#46560264 lang_code:string = Update; -updateLangPack#56022f4d difference:LangPackDifference = Update; -updateFavedStickers#e511996d = Update; -updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector = Update; -updateContactsReset#7084a7be = Update; -updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; -updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update; -updateMessagePoll#d64c522b flags:# peer:flags.1?Peer msg_id:flags.1?int top_msg_id:flags.2?int poll_id:long poll:flags.0?Poll results:PollResults = Update; -updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; -updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; -updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update; -updatePeerLocated#b4afcfb0 peers:Vector = Update; -updateNewScheduledMessage#39a51dfb message:Message = Update; -updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector sent_messages:flags.0?Vector = Update; -updateTheme#8216fba3 theme:Theme = Update; -updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update; -updateLoginToken#564fe691 = Update; -updateMessagePollVote#7699f014 poll_id:long peer:Peer options:Vector positions:Vector qts:int = Update; -updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update; -updateDialogFilterOrder#a5d72105 order:Vector = Update; -updateDialogFilters#3504914f = Update; -updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update; -updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update; -updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update; -updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update; -updatePeerBlocked#ebe07752 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer = Update; -updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; -updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; -updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChat#f89a6a4e chat_id:long = Update; -updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; -updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update; -updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; -updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update; -updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update; -updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; -updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; -updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update; -updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update; -updateAttachMenuBots#17b7a20b = Update; -updateWebViewResultSent#1592b79d query_id:long = Update; -updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update; -updateSavedRingtones#74d8be99 = Update; -updateTranscribedAudio#84cd5a flags:# pending:flags.0?true peer:Peer msg_id:int transcription_id:long text:string = Update; -updateReadFeaturedEmojiStickers#fb4c496c = Update; -updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update; -updateRecentEmojiStatuses#30f443db = Update; -updateRecentReactions#6f7863f4 = Update; -updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update; -updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector = Update; -updateUser#20529438 user_id:long = Update; -updateAutoSaveSettings#ec05b097 = Update; -updateStory#75b3b798 peer:Peer story:StoryItem = Update; -updateReadStories#f74e932b peer:Peer max_id:int = Update; -updateStoryID#1bf335b9 id:int random_id:long = Update; -updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update; -updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update; -updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update; -updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update; -updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update; -updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector new_reactions:Vector qts:int = Update; -updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector qts:int = Update; -updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; -updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector = Update; -updateSavedReactionTags#39c67432 = Update; -updateSmsJob#f16269d4 job_id:string = Update; -updateQuickReplies#f9470ab2 quick_replies:Vector = Update; -updateNewQuickReply#f53da717 quick_reply:QuickReply = Update; -updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update; -updateQuickReplyMessage#3e050d0f message:Message = Update; -updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector = Update; -updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Update; -updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; -updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; -updateStarsBalance#4e80a379 balance:StarsAmount = Update; -updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; -updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; -updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; -updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; -updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; -updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; -updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update; -updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = Update; -updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update; -updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update; -updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector = Update; -updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector = Update; -updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update; -updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update; -updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update; -updateStarGiftCraftFail#ac072444 = Update; -updateChatParticipantRank#bd8367b9 chat_id:long user_id:long rank:string version:int = Update; -updateManagedBot#4880ed9a user_id:long bot_id:long qts:int = Update; - -updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; - -updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; -updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; -updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; -updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; - -updatesTooLong#e317af7e = Updates; -updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShort#78d4dec1 update:Update date:int = Updates; -updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; -updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; -updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; -photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; - -photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; - -upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; -upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; - -dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; - -config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config; - -nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; - -help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate; -help.noAppUpdate#c45a6536 = help.AppUpdate; - -help.inviteText#18cb9f78 message:string = help.InviteText; - -encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; -encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat; -encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; -encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; -encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat; - -inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; - -encryptedFileEmpty#c21f497e = EncryptedFile; -encryptedFile#a8008cd8 id:long access_hash:long size:long dc_id:int key_fingerprint:int = EncryptedFile; - -inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; -inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; -inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; -inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; - -encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; -encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; - -messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; -messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; - -messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; -messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; - -inputDocumentEmpty#72f0eaae = InputDocument; -inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; - -documentEmpty#36f8c871 id:long = Document; -document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector video_thumbs:flags.1?Vector dc_id:int attributes:Vector = Document; - -help.support#17c6b5f6 phone_number:string user:User = help.Support; - -notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; -notifyUsers#b4c83b4c = NotifyPeer; -notifyChats#c007cec3 = NotifyPeer; -notifyBroadcasts#d612e8ef = NotifyPeer; -notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer; - -sendMessageTypingAction#16bf744e = SendMessageAction; -sendMessageCancelAction#fd5ec8f5 = SendMessageAction; -sendMessageRecordVideoAction#a187d66f = SendMessageAction; -sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; -sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; -sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; -sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; -sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; -sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; -sendMessageChooseContactAction#628cbc6f = SendMessageAction; -sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; -sendMessageRecordRoundAction#88f27fbc = SendMessageAction; -sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; -speakingInGroupCallAction#d92c2285 = SendMessageAction; -sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; -sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; -sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction; -sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction; -sendMessageTextDraftAction#376d975c random_id:long text:TextWithEntities = SendMessageAction; - -contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; - -inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; -inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; -inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; -inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; -inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; -inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; -inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; -inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey; -inputPrivacyKeyVoiceMessages#aee69d68 = InputPrivacyKey; -inputPrivacyKeyAbout#3823cc40 = InputPrivacyKey; -inputPrivacyKeyBirthday#d65a11cc = InputPrivacyKey; -inputPrivacyKeyStarGiftsAutoSave#e1732341 = InputPrivacyKey; -inputPrivacyKeyNoPaidMessages#bdc597b4 = InputPrivacyKey; -inputPrivacyKeySavedMusic#4dbe9226 = InputPrivacyKey; - -privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; -privacyKeyChatInvite#500e6dfa = PrivacyKey; -privacyKeyPhoneCall#3d662b7b = PrivacyKey; -privacyKeyPhoneP2P#39491cc8 = PrivacyKey; -privacyKeyForwards#69ec56a3 = PrivacyKey; -privacyKeyProfilePhoto#96151fed = PrivacyKey; -privacyKeyPhoneNumber#d19ae46d = PrivacyKey; -privacyKeyAddedByPhone#42ffd42b = PrivacyKey; -privacyKeyVoiceMessages#697f414 = PrivacyKey; -privacyKeyAbout#a486b761 = PrivacyKey; -privacyKeyBirthday#2000a518 = PrivacyKey; -privacyKeyStarGiftsAutoSave#2ca4fdf8 = PrivacyKey; -privacyKeyNoPaidMessages#17d348d2 = PrivacyKey; -privacyKeySavedMusic#ff7a571b = PrivacyKey; - -inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; -inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; -inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; -inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; -inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; -inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; -inputPrivacyValueAllowChatParticipants#840649cf chats:Vector = InputPrivacyRule; -inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector = InputPrivacyRule; -inputPrivacyValueAllowCloseFriends#2f453e49 = InputPrivacyRule; -inputPrivacyValueAllowPremium#77cdc9f1 = InputPrivacyRule; -inputPrivacyValueAllowBots#5a4fcce5 = InputPrivacyRule; -inputPrivacyValueDisallowBots#c4e57915 = InputPrivacyRule; - -privacyValueAllowContacts#fffe1bac = PrivacyRule; -privacyValueAllowAll#65427b82 = PrivacyRule; -privacyValueAllowUsers#b8905fb2 users:Vector = PrivacyRule; -privacyValueDisallowContacts#f888fa1a = PrivacyRule; -privacyValueDisallowAll#8b73e763 = PrivacyRule; -privacyValueDisallowUsers#e4621141 users:Vector = PrivacyRule; -privacyValueAllowChatParticipants#6b134e8e chats:Vector = PrivacyRule; -privacyValueDisallowChatParticipants#41c87565 chats:Vector = PrivacyRule; -privacyValueAllowCloseFriends#f7e8d89b = PrivacyRule; -privacyValueAllowPremium#ece9814b = PrivacyRule; -privacyValueAllowBots#21461b5d = PrivacyRule; -privacyValueDisallowBots#f6a5f82f = PrivacyRule; - -account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; - -accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; - -documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; -documentAttributeAnimated#11b58939 = DocumentAttribute; -documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; -documentAttributeVideo#43c57c48 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double video_codec:flags.5?string = DocumentAttribute; -documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; -documentAttributeFilename#15590068 file_name:string = DocumentAttribute; -documentAttributeHasStickers#9801d2f7 = DocumentAttribute; -documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute; - -messages.stickersNotModified#f1749a22 = messages.Stickers; -messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; - -stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; - -messages.allStickersNotModified#e86602c3 = messages.AllStickers; -messages.allStickers#cdbbcebb hash:long sets:Vector = messages.AllStickers; - -messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; - -webPageEmpty#211a1788 flags:# id:long url:flags.0?string = WebPage; -webPagePending#b0d13e47 flags:# id:long url:flags.0?string date:int = WebPage; -webPage#e89c45b2 flags:# has_large_media:flags.13?true video_cover_photo:flags.14?true id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector = WebPage; -webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; - -authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; - -account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector = account.Authorizations; - -account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password; - -account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; - -account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; - -auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; - -receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; - -chatInviteExported#a22cbd96 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int subscription_expired:flags.10?int title:flags.8?string subscription_pricing:flags.9?StarsSubscriptionPricing = ExportedChatInvite; -chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite; - -chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#5c9d3702 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true can_refulfill_subscription:flags.11?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector color:int subscription_pricing:flags.10?StarsSubscriptionPricing subscription_form_id:flags.12?long bot_verification:flags.13?BotVerification = ChatInvite; -chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; - -inputStickerSetEmpty#ffb62b95 = InputStickerSet; -inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; -inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; -inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; -inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; -inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet; -inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet; -inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; -inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; -inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet; -inputStickerSetTonGifts#1cf671a0 = InputStickerSet; - -stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; - -messages.stickerSet#6e153f16 set:StickerSet packs:Vector keywords:Vector documents:Vector = messages.StickerSet; -messages.stickerSetNotModified#d3f924eb = messages.StickerSet; - -botCommand#c27ac8c7 command:string description:string = BotCommand; - -botInfo#4d8a0299 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton privacy_policy_url:flags.7?string app_settings:flags.8?BotAppSettings verifier_settings:flags.9?BotVerifierSettings = BotInfo; - -keyboardButton#7d170cff flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrl#d80c25ec flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonCallback#e62bc960 flags:# requires_password:flags.0?true style:flags.10?KeyboardButtonStyle text:string data:bytes = KeyboardButton; -keyboardButtonRequestPhone#417efd8f flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonRequestGeoLocation#aa40f94d flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonSwitchInline#991399fc flags:# same_peer:flags.0?true style:flags.10?KeyboardButtonStyle text:string query:string peer_types:flags.1?Vector = KeyboardButton; -keyboardButtonGame#89c590f9 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonBuy#3fa53905 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrlAuth#f51006f9 flags:# style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; -inputKeyboardButtonUrlAuth#68013e72 flags:# request_write_access:flags.0?true style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; -keyboardButtonRequestPoll#7a11d782 flags:# style:flags.10?KeyboardButtonStyle quiz:flags.0?Bool text:string = KeyboardButton; -inputKeyboardButtonUserProfile#7d5e07c7 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:InputUser = KeyboardButton; -keyboardButtonUserProfile#c0fd5d09 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:long = KeyboardButton; -keyboardButtonWebView#e846b1a0 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonSimpleWebView#e15c4370 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonRequestPeer#5b0f15f5 flags:# style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -inputKeyboardButtonRequestPeer#2b78156 flags:# name_requested:flags.0?true username_requested:flags.1?true photo_requested:flags.2?true style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -keyboardButtonCopy#bcc4af10 flags:# style:flags.10?KeyboardButtonStyle text:string copy_text:string = KeyboardButton; - -keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; - -replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; -replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup; -replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector placeholder:flags.3?string = ReplyMarkup; -replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; - -messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; -messageEntityMention#fa04579d offset:int length:int = MessageEntity; -messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; -messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; -messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; -messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; -messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; -messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; -messageEntityCode#28a20571 offset:int length:int = MessageEntity; -messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; -messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; -messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity; -inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; -messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; -messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; -messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity; -messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; -messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; -messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; -messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; -messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity; -messageEntityFormattedDate#904ac7c7 flags:# relative:flags.0?true short_time:flags.1?true long_time:flags.2?true short_date:flags.3?true long_date:flags.4?true day_of_week:flags.5?true offset:int length:int date:int = MessageEntity; -messageEntityDiffInsert#71777116 offset:int length:int = MessageEntity; -messageEntityDiffReplace#c6c1e5a7 offset:int length:int old_text:string = MessageEntity; -messageEntityDiffDelete#652c1c5 offset:int length:int = MessageEntity; - -inputChannelEmpty#ee8c1e86 = InputChannel; -inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; -inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel; - -contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; - -messageRange#ae30253 min_id:int max_id:int = MessageRange; - -updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; -updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; -updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; - -channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; -channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; - -channelParticipant#1bd54456 flags:# user_id:long date:int subscription_until_date:flags.0?int rank:flags.2?string = ChannelParticipant; -channelParticipantSelf#a9478a1a flags:# via_request:flags.0?true user_id:long inviter_id:long date:int subscription_until_date:flags.1?int rank:flags.2?string = ChannelParticipant; -channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; -channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; -channelParticipantBanned#d5f0ad91 flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights rank:flags.2?string = ChannelParticipant; -channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; - -channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; -channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; -channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; -channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; -channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; -channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; -channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; -channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; - -channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; -channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; - -channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; - -help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; - -messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; -messages.savedGifs#84a02a0d hash:long gifs:Vector = messages.SavedGifs; - -inputBotInlineMessageMediaAuto#3380c786 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaWebPage#bddcc510 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true optional:flags.6?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; - -botInlineMessageMediaAuto#764cf810 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; -botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; - -messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector cache_time:int users:Vector = messages.BotResults; - -exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; - -messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader; - -auth.codeTypeSms#72a3158c = auth.CodeType; -auth.codeTypeCall#741cd3e3 = auth.CodeType; -auth.codeTypeFlashCall#226ccefb = auth.CodeType; -auth.codeTypeMissedCall#d61ad6ee = auth.CodeType; -auth.codeTypeFragmentSms#6ed998c = auth.CodeType; - -auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; -auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; -auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; -auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType; -auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; -auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; -auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; -auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; -auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; -auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; - -messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; - -messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; - -inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; -inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID; - -inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; - -messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; - -topPeer#edcdc05b peer:Peer rating:double = TopPeer; - -topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; -topPeerCategoryBotsInline#148677e2 = TopPeerCategory; -topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; -topPeerCategoryGroups#bd17a14a = TopPeerCategory; -topPeerCategoryChannels#161d9628 = TopPeerCategory; -topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; -topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; -topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; -topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory; - -topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; - -contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; -contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; -contacts.topPeersDisabled#b52c939d = contacts.TopPeers; - -draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; -draftMessage#96eaa5eb flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost = DraftMessage; - -messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; -messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; - -messages.recentStickersNotModified#b17f890 = messages.RecentStickers; -messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; - -messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; - -messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; -messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; - -stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; -stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; -stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector keywords:Vector documents:Vector = StickerSetCovered; -stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered; - -maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; - -inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; -inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; - -game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; - -inputGameID#32c3e77 id:long access_hash:long = InputGame; -inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; - -highScore#73a379eb pos:int user_id:long score:int = HighScore; - -messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; - -textEmpty#dc3d824f = RichText; -textPlain#744694e0 text:string = RichText; -textBold#6724abc4 text:RichText = RichText; -textItalic#d912a59c text:RichText = RichText; -textUnderline#c12622c4 text:RichText = RichText; -textStrike#9bf8bb95 text:RichText = RichText; -textFixed#6c3f19b9 text:RichText = RichText; -textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; -textEmail#de5a0dd6 text:RichText email:string = RichText; -textConcat#7e6260d7 texts:Vector = RichText; -textSubscript#ed6a8504 text:RichText = RichText; -textSuperscript#c7fb5e01 text:RichText = RichText; -textMarked#34b8621 text:RichText = RichText; -textPhone#1ccb966a text:RichText phone:string = RichText; -textImage#81ccf4f document_id:long w:int h:int = RichText; -textAnchor#35553762 text:RichText name:string = RichText; - -pageBlockUnsupported#13567e8a = PageBlock; -pageBlockTitle#70abc3fd text:RichText = PageBlock; -pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; -pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; -pageBlockHeader#bfd064ec text:RichText = PageBlock; -pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; -pageBlockParagraph#467a0766 text:RichText = PageBlock; -pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; -pageBlockFooter#48870999 text:RichText = PageBlock; -pageBlockDivider#db20b188 = PageBlock; -pageBlockAnchor#ce0d37b0 name:string = PageBlock; -pageBlockList#e4e88011 items:Vector = PageBlock; -pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; -pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; -pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; -pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; -pageBlockCover#39f23300 cover:PageBlock = PageBlock; -pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; -pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; -pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; -pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; -pageBlockChannel#ef1751b5 channel:Chat = PageBlock; -pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; -pageBlockKicker#1e148390 text:RichText = PageBlock; -pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; -pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; -pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; -pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; -pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; - -phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; -phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; -phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; -phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; -phoneCallDiscardReasonMigrateConferenceCall#9fbbf1f7 slug:string = PhoneCallDiscardReason; - -dataJSON#7d748d04 data:string = DataJSON; - -labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; - -invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector terms_url:flags.10?string subscription_period:flags.11?int = Invoice; - -paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; - -postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; - -paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; - -paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; - -webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; -webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; - -inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; - -inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; -inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; -inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation; - -upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; - -payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector users:Vector = payments.PaymentForm; -payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector = payments.PaymentForm; -payments.paymentFormStarGift#b425cfe1 form_id:long invoice:Invoice = payments.PaymentForm; - -payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; - -payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; -payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; - -payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; -payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector = payments.PaymentReceipt; - -payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; - -inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; -inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials; - -account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; - -shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; - -inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem; - -inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; - -phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#30535af5 flags:# p2p_allowed:flags.5?true video:flags.6?true conference_supported:flags.8?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int custom_parameters:flags.7?DataJSON = PhoneCall; -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; - -phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; -phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection; - -phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector = PhoneCallProtocol; - -phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; - -upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; -upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; - -cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; - -cdnConfig#5725e40a public_keys:Vector = CdnConfig; - -langPackString#cad181f6 key:string value:string = LangPackString; -langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; -langPackStringDeleted#2979eeb2 key:string = LangPackString; - -langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; - -langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; - -channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; -channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector new_value:Vector = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAutotranslation#c517f77e new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantEditRank#5806b4ec user_id:long prev_rank:string new_rank:string = ChannelAdminLogEventAction; - -channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; - -channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; - -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true edit_rank:flags.19?true = ChannelAdminLogEventsFilter; - -popularContact#5ce14175 client_id:long importers:int = PopularContact; - -messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; -messages.favedStickers#2cb51097 hash:long packs:Vector stickers:Vector = messages.FavedStickers; - -recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; -recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl; -recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl; -recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; -recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; - -help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; - -inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; - -webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; - -account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; - -inputMessageID#a676a322 id:int = InputMessage; -inputMessageReplyTo#bad88395 id:int = InputMessage; -inputMessagePinned#86872538 = InputMessage; -inputMessageCallbackQuery#acfa1a7e id:int query_id:long = InputMessage; - -inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; -inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; - -dialogPeer#e56dbf05 peer:Peer = DialogPeer; -dialogPeerFolder#514519e2 folder_id:int = DialogPeer; - -messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; -messages.foundStickerSets#8af09dd2 hash:long sets:Vector = messages.FoundStickerSets; - -fileHash#f39b035c offset:long limit:int hash:bytes = FileHash; - -inputClientProxy#75588b3f address:string port:int = InputClientProxy; - -help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; -help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; - -inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; -inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; - -secureFileEmpty#64199744 = SecureFile; -secureFile#7d09c27e id:long access_hash:long size:long dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; - -secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; - -securePlainPhone#7d6099dd phone:string = SecurePlainData; -securePlainEmail#21ec5a5f email:string = SecurePlainData; - -secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; -secureValueTypePassport#3dac6a00 = SecureValueType; -secureValueTypeDriverLicense#6e425c4 = SecureValueType; -secureValueTypeIdentityCard#a0d0744b = SecureValueType; -secureValueTypeInternalPassport#99a48f23 = SecureValueType; -secureValueTypeAddress#cbe31e26 = SecureValueType; -secureValueTypeUtilityBill#fc36954e = SecureValueType; -secureValueTypeBankStatement#89137c0d = SecureValueType; -secureValueTypeRentalAgreement#8b883488 = SecureValueType; -secureValueTypePassportRegistration#99e3806a = SecureValueType; -secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; -secureValueTypePhone#b320aadb = SecureValueType; -secureValueTypeEmail#8e3ca7ee = SecureValueType; - -secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; - -inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; - -secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; - -secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; -secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; -secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; - -secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; - -account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; - -account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; - -help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; -help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; - -savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; - -account.takeout#4dba4501 id:long = account.Takeout; - -passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; -passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; - -securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; -securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; -securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; - -secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; - -inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; -inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; - -secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; -secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; - -help.passportConfigNotModified#bfb9f457 = help.PassportConfig; -help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; - -inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; - -jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; - -jsonNull#3f6d7b68 = JSONValue; -jsonBool#c7345e6a value:Bool = JSONValue; -jsonNumber#2be0dfa4 value:double = JSONValue; -jsonString#b71e767a value:string = JSONValue; -jsonArray#f7444763 value:Vector = JSONValue; -jsonObject#99c1d49d value:Vector = JSONValue; - -pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; - -pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; - -pageCaption#6f747657 text:RichText credit:RichText = PageCaption; - -pageListItemText#b92fb6cd text:RichText = PageListItem; -pageListItemBlocks#25e073fc blocks:Vector = PageListItem; - -pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; -pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; - -pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; - -page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector views:flags.3?int = Page; - -help.supportName#8c05f1c9 name:string = help.SupportName; - -help.userInfoEmpty#f3ae2eed = help.UserInfo; -help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; - -pollAnswer#4b7d786a flags:# text:TextWithEntities option:bytes media:flags.0?MessageMedia added_by:flags.1?Peer date:flags.1?int = PollAnswer; -inputPollAnswer#199fed96 flags:# text:TextWithEntities media:flags.0?InputMedia = PollAnswer; - -poll#b8425be9 id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true open_answers:flags.6?true revoting_disabled:flags.7?true shuffle_answers:flags.8?true hide_results_until_close:flags.9?true creator:flags.10?true question:TextWithEntities answers:Vector close_period:flags.4?int close_date:flags.5?int hash:long = Poll; - -pollAnswerVoters#3645230a flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:flags.2?int recent_voters:flags.2?Vector = PollAnswerVoters; - -pollResults#ba7bb15e flags:# min:flags.0?true has_unread_votes:flags.6?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector solution_media:flags.5?MessageMedia = PollResults; - -chatOnlines#f041e250 onlines:int = ChatOnlines; - -statsURL#47a971e0 url:string = StatsURL; - -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true manage_ranks:flags.18?true = ChatAdminRights; - -chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true edit_rank:flags.26?true until_date:int = ChatBannedRights; - -inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; -inputWallPaperSlug#72091c80 slug:string = InputWallPaper; -inputWallPaperNoFile#967a462e id:long = InputWallPaper; - -account.wallPapersNotModified#1c199183 = account.WallPapers; -account.wallPapers#cdc3858c hash:long wallpapers:Vector = account.WallPapers; - -codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true unknown_number:flags.9?true logout_tokens:flags.6?Vector token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings; - -wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings; - -autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings; - -account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; - -emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector = EmojiKeyword; -emojiKeywordDeleted#236df622 keyword:string emoticons:Vector = EmojiKeyword; - -emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector = EmojiKeywordsDifference; - -emojiURL#a575739d url:string = EmojiURL; - -emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; - -folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; - -inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; - -folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; - -messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; - -urlAuthResultRequest#3cd623ec flags:# request_write_access:flags.0?true request_phone_number:flags.1?true match_codes_first:flags.5?true is_app:flags.6?true bot:User domain:string browser:flags.2?string platform:flags.2?string ip:flags.2?string region:flags.2?string match_codes:flags.3?Vector user_id_hint:flags.4?long verified_app_name:flags.7?string = UrlAuthResult; -urlAuthResultAccepted#623a8fa0 flags:# url:flags.0?string = UrlAuthResult; -urlAuthResultDefault#a9d6db1f = UrlAuthResult; - -channelLocationEmpty#bfb5ad8b = ChannelLocation; -channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation; - -peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated; -peerSelfLocated#f8ec284b expires:int = PeerLocated; - -restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason; - -inputTheme#3c5693e9 id:long access_hash:long = InputTheme; -inputThemeSlug#f5890df1 slug:string = InputTheme; - -theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector emoticon:flags.6?string installs_count:flags.4?int = Theme; - -account.themesNotModified#f41eb622 = account.Themes; -account.themes#9a3d8c6d hash:long themes:Vector = account.Themes; - -auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken; -auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken; -auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken; - -account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings; - -messages.inactiveChats#a927fec5 dates:Vector chats:Vector users:Vector = messages.InactiveChats; - -baseThemeClassic#c3a12462 = BaseTheme; -baseThemeDay#fbd81688 = BaseTheme; -baseThemeNight#b7b31ea8 = BaseTheme; -baseThemeTinted#6d5f77ee = BaseTheme; -baseThemeArctic#5b11125a = BaseTheme; - -inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; - -themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; - -webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; -webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; -webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; -webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; -webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; -webPageAttributeStarGiftAuction#1c641c2 gift:StarGift end_date:int = WebPageAttribute; - -messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; - -bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl; - -payments.bankCardData#3e24e573 title:string open_urls:Vector = payments.BankCardData; - -dialogFilter#aa472651 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector exclude_peers:Vector = DialogFilter; -dialogFilterDefault#363293ae = DialogFilter; -dialogFilterChatlist#96537bd7 flags:# has_my_invites:flags.26?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector = DialogFilter; - -dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested; - -statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays; - -statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev; - -statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue; - -statsGraphAsync#4a27eb2d token:string = StatsGraph; -statsGraphError#bedc9822 error:string = StatsGraph; -statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph; - -stats.broadcastStats#396ca5fc period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev reactions_per_post:StatsAbsValueAndPrev views_per_story:StatsAbsValueAndPrev shares_per_story:StatsAbsValueAndPrev reactions_per_story:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_posts_interactions:Vector = stats.BroadcastStats; - -help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; -help.promoData#8a4d87a flags:# proxy:flags.0?true expires:int peer:flags.3?Peer psa_type:flags.1?string psa_message:flags.2?string pending_suggestions:Vector dismissed_suggestions:Vector custom_pending_suggestion:flags.4?PendingSuggestion chats:Vector users:Vector = help.PromoData; - -videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; -videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector = VideoSize; -videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector = VideoSize; - -statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster; - -statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; - -statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; - -stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; - -globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; - -help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; - -help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector = help.Country; - -help.countriesListNotModified#93cc1f32 = help.CountriesList; -help.countriesList#87d0759e countries:Vector hash:int = help.CountriesList; - -messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews; - -messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; - -messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; - -messageReplyHeader#1b97dd66 flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector quote_offset:flags.10?int todo_item_id:flags.11?int poll_option:flags.12?bytes = MessageReplyHeader; -messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader; - -messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; - -peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; - -stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; - -groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall; - -inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -inputGroupCallSlug#fe06823f slug:string = InputGroupCall; -inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall; - -groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant; - -phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; - -phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; - -inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; -inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; -inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType; -inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType; -inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType; -inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType; - -messages.historyImport#1662af0b id:long = messages.HistoryImport; - -messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed; - -messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector = messages.AffectedFoundMessages; - -chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter; - -messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; - -messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; -messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; - -messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; - -chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites; - -messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; - -messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; - -phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; - -phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; - -groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector = GroupCallParticipantVideoSourceGroup; - -groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector audio_source:flags.1?int = GroupCallParticipantVideo; - -stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName; - -botCommandScopeDefault#2f6cb2ab = BotCommandScope; -botCommandScopeUsers#3c4f04d8 = BotCommandScope; -botCommandScopeChats#6fe1a881 = BotCommandScope; -botCommandScopeChatAdmins#b9aa606a = BotCommandScope; -botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope; -botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope; -botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope; - -account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult; -account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; -account.resetPasswordOk#e926d63e = account.ResetPasswordResult; - -chatTheme#c3dffc04 emoticon:string = ChatTheme; -chatThemeUniqueGift#3458f9c8 gift:StarGift theme_settings:Vector = ChatTheme; - -account.chatThemesNotModified#e011e1c4 = account.ChatThemes; -account.chatThemes#be098173 flags:# hash:long themes:Vector chats:Vector users:Vector next_offset:flags.0?string = account.ChatThemes; - -sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage; - -messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; -messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; - -searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; - -messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector messages:Vector chats:Vector users:Vector = messages.SearchResultsCalendar; - -searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition; - -messages.searchResultsPositions#53b22baf count:int positions:Vector = messages.SearchResultsPositions; - -channels.sendAsPeers#f496b0c6 peers:Vector chats:Vector users:Vector = channels.SendAsPeers; - -users.userFull#3b6d152e full_user:UserFull chats:Vector users:Vector = users.UserFull; - -messages.peerSettings#6880b94d settings:PeerSettings chats:Vector users:Vector = messages.PeerSettings; - -auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut; - -reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; - -messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector recent_reactions:flags.1?Vector top_reactors:flags.4?Vector = MessageReactions; - -messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.MessageReactionsList; - -availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; - -messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions; -messages.availableReactions#768e3aad hash:int reactions:Vector = messages.AvailableReactions; - -messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true my:flags.2?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction; - -groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel; - -phone.groupCallStreamChannels#d0e482b2 channels:Vector = phone.GroupCallStreamChannels; - -phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl; - -attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; - -attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector = AttachMenuBotIcon; - -attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector icons:Vector = AttachMenuBot; - -attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; -attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector = AttachMenuBots; - -attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector = AttachMenuBotsBot; - -webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true fullscreen:flags.2?true query_id:flags.0?long url:string = WebViewResult; - -webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent; - -botMenuButtonDefault#7533a588 = BotMenuButton; -botMenuButtonCommands#4258c205 = BotMenuButton; -botMenuButton#c7b57ce6 text:string url:string = BotMenuButton; - -account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones; -account.savedRingtones#c1e92cc5 hash:long ringtones:Vector = account.SavedRingtones; - -notificationSoundDefault#97e8bebe = NotificationSound; -notificationSoundNone#6f0c34df = NotificationSound; -notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound; -notificationSoundRingtone#ff6c8049 id:long = NotificationSound; - -account.savedRingtone#b7263f6d = account.SavedRingtone; -account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone; - -attachMenuPeerTypeSameBotPM#7d6be90e = AttachMenuPeerType; -attachMenuPeerTypeBotPM#c32bfa1a = AttachMenuPeerType; -attachMenuPeerTypePM#f146d31f = AttachMenuPeerType; -attachMenuPeerTypeChat#509113f = AttachMenuPeerType; -attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; - -inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; -inputInvoiceSlug#c326caef slug:string = InputInvoice; -inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; -inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice; -inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice; -inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; -inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; -inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; -inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; -inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice; -inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice; - -payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; - -messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; - -help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; - -inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose; -inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentPremiumGiftCode#fb790393 flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long message:flags.1?TextWithEntities = InputStorePaymentPurpose; -inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsTopup#f9a2a6cb flags:# stars:long currency:string amount:long spend_purpose_peer:flags.0?InputPeer = InputStorePaymentPurpose; -inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; -inputStorePaymentAuthCode#9bb2636d flags:# restore:flags.0?true phone_number:string phone_code_hash:string currency:string amount:long = InputStorePaymentPurpose; - -paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; - -emojiStatusEmpty#2de11aae = EmojiStatus; -emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus; -emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus; -inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus; - -account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses; -account.emojiStatuses#90c467d1 hash:long statuses:Vector = account.EmojiStatuses; - -reactionEmpty#79f5d419 = Reaction; -reactionEmoji#1b2286b8 emoticon:string = Reaction; -reactionCustomEmoji#8935fc73 document_id:long = Reaction; -reactionPaid#523da4eb = Reaction; - -chatReactionsNone#eafc32bc = ChatReactions; -chatReactionsAll#52928bca flags:# allow_custom:flags.0?true = ChatReactions; -chatReactionsSome#661d4037 reactions:Vector = ChatReactions; - -messages.reactionsNotModified#b06fdbdf = messages.Reactions; -messages.reactions#eafdf716 hash:long reactions:Vector = messages.Reactions; - -emailVerifyPurposeLoginSetup#4345be73 phone_number:string phone_code_hash:string = EmailVerifyPurpose; -emailVerifyPurposeLoginChange#527d22eb = EmailVerifyPurpose; -emailVerifyPurposePassport#bbf51685 = EmailVerifyPurpose; - -emailVerificationCode#922e55a9 code:string = EmailVerification; -emailVerificationGoogle#db909ec2 token:string = EmailVerification; -emailVerificationApple#96d074fd token:string = EmailVerification; - -account.emailVerified#2b96cd1b email:string = account.EmailVerified; -account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified; - -premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption; - -sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer; - -messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia; -messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia; - -stickerKeyword#fcfeb29c document_id:long keyword:Vector = StickerKeyword; - -username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username; - -forumTopicDeleted#23f109b id:int = ForumTopic; -forumTopic#fcdad815 flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true title_missing:flags.7?true id:int date:int peer:Peer title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic; - -messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector messages:Vector chats:Vector users:Vector pts:int = messages.ForumTopics; - -defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL; - -exportedContactToken#41bf109b url:string expires:int = ExportedContactToken; - -requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType; -requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeCreateBot#3e81e078 flags:# bot_managed:flags.0?true suggested_name:flags.1?string suggested_username:flags.2?string = RequestPeerType; - -emojiListNotModified#481eadfa = EmojiList; -emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; - -emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; - -messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; -messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; - -textWithEntities#751f3146 text:string entities:Vector = TextWithEntities; - -messages.translateResult#33db32f8 result:Vector = messages.TranslatedText; - -autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings; - -autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException; - -account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector chats:Vector users:Vector = account.AutoSaveSettings; - -help.appConfigNotModified#7cde641d = help.AppConfig; -help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig; - -inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp; -inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp; - -botAppNotModified#5da674b7 = BotApp; -botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; - -messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp; - -inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; - -readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; - -inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist; - -exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector = ExportedChatlistInvite; - -chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite; - -chatlists.exportedInvites#10ab6dc7 invites:Vector chats:Vector users:Vector = chatlists.ExportedInvites; - -chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector already_peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; -chatlists.chatlistInvite#f10ece2f flags:# title_noanimate:flags.1?true title:TextWithEntities emoticon:flags.0?string peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; - -chatlists.chatlistUpdates#93bd878d missing_peers:Vector chats:Vector users:Vector = chatlists.ChatlistUpdates; - -bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo; - -messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote; -messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote; -messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector date:int = MessagePeerVote; - -storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector reactions_count:flags.4?int recent_viewers:flags.0?Vector = StoryViews; - -storyItemDeleted#51e6ee4f id:int = StoryItem; -storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true live:flags.9?true id:int date:int expire_date:int = StoryItem; -storyItem#16a4b93c flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector music:flags.20?Document = StoryItem; - -stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; -stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; - -stories.stories#63c3dd0a flags:# count:int stories:Vector pinned_to_top:flags.0?Vector chats:Vector users:Vector = stories.Stories; - -storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView; -storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView; -storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView; - -stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryViewsList; - -stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; - -inputReplyToMessage#3bd4b7c2 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int poll_option:flags.7?bytes = InputReplyTo; -inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; -inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; - -exportedStoryLink#3fc9053b link:string = ExportedStoryLink; - -storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; - -mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates; - -mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea; -inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea; -mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea; -mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea; -mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; -inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; -mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; -mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea; -mediaAreaStarGift#5787686d coordinates:MediaAreaCoordinates slug:string = MediaArea; - -peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; - -stories.peerStories#cae68768 stories:PeerStories chats:Vector users:Vector = stories.PeerStories; - -messages.webPage#fd5e12bd webpage:WebPage chats:Vector users:Vector = messages.WebPage; - -premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption; - -payments.checkedGiftCode#eb983f8f flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int days:int used_date:flags.1?int chats:Vector users:Vector = payments.CheckedGiftCode; - -payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; -payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo; - -prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; -prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway; - -boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost; - -premium.boostsList#86f8613c flags:# count:int boosts:Vector next_offset:flags.0?string users:Vector = premium.BoostsList; - -myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost; - -premium.myBoosts#9ae228e2 my_boosts:Vector chats:Vector users:Vector = premium.MyBoosts; - -premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector my_boost_slots:flags.2?Vector = premium.BoostsStatus; - -storyFwdHeader#b826e150 flags:# modified:flags.3?true from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader; - -postInteractionCountersMessage#e7058e7f msg_id:int views:int forwards:int reactions:int = PostInteractionCounters; -postInteractionCountersStory#8a480e27 story_id:int views:int forwards:int reactions:int = PostInteractionCounters; - -stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats; - -publicForwardMessage#1f2bf4a message:Message = PublicForward; -publicForwardStory#edf3add0 peer:Peer story:StoryItem = PublicForward; - -stats.publicForwards#93037e20 flags:# count:int forwards:Vector next_offset:flags.0?string chats:Vector users:Vector = stats.PublicForwards; - -peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor; -peerColorCollectible#b9c0639a flags:# collectible_id:long gift_emoji_id:long background_emoji_id:long accent_color:int colors:Vector dark_accent_color:flags.0?int dark_colors:flags.1?Vector = PeerColor; -inputPeerColorCollectible#b8ea86a9 collectible_id:long = PeerColor; - -help.peerColorSet#26219a58 colors:Vector = help.PeerColorSet; -help.peerColorProfileSet#767d61eb palette_colors:Vector bg_colors:Vector story_colors:Vector = help.PeerColorSet; - -help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption; - -help.peerColorsNotModified#2ba1f5ce = help.PeerColors; -help.peerColors#f8ed08 hash:int colors:Vector = help.PeerColors; - -storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction; -storyReactionPublicForward#bbab2643 message:Message = StoryReaction; -storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; - -stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; - -savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; -monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; - -messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; - -savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; - -messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; -messages.savedReactionTags#3259950a tags:Vector hash:long = messages.SavedReactionTags; - -outboxReadDate#3bb842ac date:int = OutboxReadDate; - -smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin; - -smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status; - -smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob; - -businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen; - -businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector = BusinessWorkHours; - -businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation; - -inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = InputBusinessRecipients; - -businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = BusinessRecipients; - -businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule; - -inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage; - -businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage; - -inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage; - -businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage; - -timezone#ff9289f5 id:string name:string utc_offset:int = Timezone; - -help.timezonesListNotModified#970708cc = help.TimezonesList; -help.timezonesList#7b74ed71 timezones:Vector hash:int = help.TimezonesList; - -quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply; - -inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut; -inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; - -messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; -messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; - -connectedBot#cd64636c flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights = ConnectedBot; - -account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; - -messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector = messages.DialogFilters; - -birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; - -botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; - -inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; - -businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro; - -messages.myStickers#faff629d count:int sets:Vector = messages.MyStickers; - -inputCollectibleUsername#e39460a9 username:string = InputCollectible; -inputCollectiblePhone#a2e214a4 phone:string = InputCollectible; - -fragment.collectibleInfo#6ebdff91 purchase_date:int currency:string amount:long crypto_currency:string crypto_amount:long url:string = fragment.CollectibleInfo; - -inputBusinessBotRecipients#c4e5921e flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = InputBusinessBotRecipients; - -businessBotRecipients#b88cf373 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = BusinessBotRecipients; - -contactBirthday#1d998733 contact_id:long birthday:Birthday = ContactBirthday; - -contacts.contactBirthdays#114ff30d contacts:Vector users:Vector = contacts.ContactBirthdays; - -missingInvitee#628c9224 flags:# premium_would_allow_invite:flags.0?true premium_required_for_pm:flags.1?true user_id:long = MissingInvitee; - -messages.invitedUsers#7f5defa6 updates:Updates missing_invitees:Vector = messages.InvitedUsers; - -inputBusinessChatLink#11679fa7 flags:# message:string entities:flags.0?Vector title:flags.1?string = InputBusinessChatLink; - -businessChatLink#b4ae666f flags:# link:string message:string entities:flags.0?Vector title:flags.1?string views:int = BusinessChatLink; - -account.businessChatLinks#ec43a2d1 links:Vector chats:Vector users:Vector = account.BusinessChatLinks; - -account.resolvedBusinessChatLinks#9a23af21 flags:# peer:Peer message:string entities:flags.0?Vector chats:Vector users:Vector = account.ResolvedBusinessChatLinks; - -requestedPeerUser#d62ff46a flags:# user_id:long first_name:flags.0?string last_name:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChat#7307544f flags:# chat_id:long title:flags.0?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChannel#8ba403e4 flags:# channel_id:long title:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; - -sponsoredMessageReportOption#430d3150 text:string option:bytes = SponsoredMessageReportOption; - -channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:Vector = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; - -reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; -reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; - -reactionsNotifySettings#71e4ea58 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom poll_votes_notify_from:flags.2?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; - -availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; - -messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; -messages.availableEffects#bddb616e hash:int effects:Vector documents:Vector = messages.AvailableEffects; - -factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck; - -starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer; -starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer; -starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; -starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; -starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; -starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; -starsTransactionPeerAds#60682812 = StarsTransactionPeer; -starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; - -starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; - -starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true posts_search:flags.24?true stargift_prepaid_upgrade:flags.25?true stargift_drop_original_details:flags.26?true phonegroup_message:flags.27?true stargift_auction_bid:flags.28?true offer:flags.29?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction; - -payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; - -foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; - -stories.foundStories#e2de7737 flags:# count:int stories:Vector next_offset:flags.0?string chats:Vector users:Vector = stories.FoundStories; - -geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; - -starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; - -payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; - -payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; - -payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl; - -inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; - -starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption; - -bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector = bots.PopularAppBots; - -botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia; - -bots.previewInfo#ca71d64 media:Vector lang_codes:Vector = bots.PreviewInfo; - -starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing; - -starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true bot_canceled:flags.7?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string title:flags.4?string photo:flags.5?WebDocument invoice_slug:flags.6?string = StarsSubscription; - -messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; - -starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; - -starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; - -starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift; -starGiftUnique#85f0a9cd flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true burned:flags.14?true crafted:flags.15?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int craft_chance_permille:flags.16?int = StarGift; - -payments.starGiftsNotModified#a388a368 = payments.StarGifts; -payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; - -messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; - -reportResultChooseOption#f0e4e0b6 title:string options:Vector = ReportResult; -reportResultAddComment#6f09ac31 flags:# optional:flags.0?true option:bytes = ReportResult; -reportResultReported#8db33c4b = ReportResult; - -messages.botPreparedInlineMessage#8ecf0511 id:string expire_date:int = messages.BotPreparedInlineMessage; - -messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult peer_types:Vector cache_time:int users:Vector = messages.PreparedInlineMessage; - -botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings; - -starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram; - -connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef; - -payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector = payments.ConnectedStarRefBots; - -payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; - -starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount; -starsTonAmount#74aee3e0 amount:long = StarsAmount; - -messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers; -messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector = messages.FoundStickers; - -botVerifierSettings#b0cd6617 flags:# can_modify_custom_description:flags.1?true icon:long company:string custom_description:flags.0?string = BotVerifierSettings; - -botVerification#f93cd45c bot_id:long icon:long description:string = BotVerification; - -starGiftAttributeModel#565251e2 flags:# crafted:flags.0?true name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributePattern#4e7085ea name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeBackdrop#9f2504e4 name:string backdrop_id:int center_color:int edge_color:int pattern_color:int text_color:int rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute; - -payments.starGiftUpgradePreview#3de1dfed sample_attributes:Vector prices:Vector next_prices:Vector = payments.StarGiftUpgradePreview; - -users.users#62d706b8 users:Vector = users.Users; -users.usersSlice#315a4974 count:int users:Vector = users.Users; - -payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector users:Vector = payments.UniqueStarGift; - -messages.webPagePreview#8c9a88ac media:MessageMedia chats:Vector users:Vector = messages.WebPagePreview; - -savedStarGift#41df43fc flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int can_craft_at:flags.20?int = SavedStarGift; - -payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; - -inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift; -inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift; -inputSavedStarGiftSlug#2085c238 slug:string = InputSavedStarGift; - -payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl; - -paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy; -paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy; -paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy; - -account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRevenue; - -requirementToContactEmpty#50a9839 = RequirementToContact; -requirementToContactPremium#e581e4e9 = RequirementToContact; -requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; - -businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; - -disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true disallow_stargifts_from_channels:flags.4?true = DisallowedGiftsSettings; - -sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; - -contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; -contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; - -starGiftAttributeIdModel#48aaae3c document_id:long = StarGiftAttributeId; -starGiftAttributeIdPattern#4a162433 document_id:long = StarGiftAttributeId; -starGiftAttributeIdBackdrop#1f01c757 backdrop_id:int = StarGiftAttributeId; - -starGiftAttributeCounter#2eb1b658 attribute:StarGiftAttributeId count:int = StarGiftAttributeCounter; - -payments.resaleStarGifts#947a12df flags:# count:int gifts:Vector next_offset:flags.0?string attributes:flags.1?Vector attributes_hash:flags.1?long chats:Vector counters:flags.2?Vector users:Vector = payments.ResaleStarGifts; - -stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount; - -pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion; - -todoItem#cba9a52f id:int title:TextWithEntities = TodoItem; - -todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector = TodoList; - -todoCompletion#221bb5e4 id:int completed_by:Peer date:int = TodoCompletion; - -suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost; - -starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating; - -starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection; - -payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; -payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; - -storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; - -stories.albumsNotModified#564edaeb = stories.Albums; -stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; - -searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; - -payments.uniqueStarGiftValueInfo#512fe446 flags:# last_sale_on_fragment:flags.1?true value_is_average:flags.6?true currency:string value:long initial_sale_date:int initial_sale_stars:long initial_sale_price:long last_sale_date:flags.0?int last_sale_price:flags.0?long floor_price:flags.2?long average_price:flags.3?long listed_count:flags.4?int fragment_listed_count:flags.5?int fragment_listed_url:flags.5?string = payments.UniqueStarGiftValueInfo; - -profileTabPosts#b98cd696 = ProfileTab; -profileTabGifts#4d4bd46a = ProfileTab; -profileTabMedia#72c64955 = ProfileTab; -profileTabFiles#ab339c00 = ProfileTab; -profileTabMusic#9f27d26e = ProfileTab; -profileTabVoice#e477092e = ProfileTab; -profileTabLinks#d3656499 = ProfileTab; -profileTabGifs#a2c0f695 = ProfileTab; - -users.savedMusicNotModified#e3878aa4 count:int = users.SavedMusic; -users.savedMusic#34a2f297 count:int documents:Vector = users.SavedMusic; - -account.savedMusicIdsNotModified#4fc81d6e = account.SavedMusicIds; -account.savedMusicIds#998d6636 ids:Vector = account.SavedMusicIds; - -payments.checkCanSendGiftResultOk#374fa7ad = payments.CheckCanSendGiftResult; -payments.checkCanSendGiftResultFail#d5e58274 reason:TextWithEntities = payments.CheckCanSendGiftResult; - -inputChatThemeEmpty#83268483 = InputChatTheme; -inputChatTheme#c93de95c emoticon:string = InputChatTheme; -inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme; - -starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice; - -groupCallMessage#1a8afc7e flags:# from_admin:flags.1?true id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage; - -groupCallDonor#ee430c85 flags:# top:flags.0?true my:flags.1?true peer_id:flags.3?Peer stars:long = GroupCallDonor; - -phone.groupCallStars#9d1dbd26 total_stars:long top_donors:Vector chats:Vector users:Vector = phone.GroupCallStars; - -recentStory#711d692d flags:# live:flags.0?true max_id:flags.1?int = RecentStory; - -auctionBidLevel#310240cc pos:int amount:long date:int = AuctionBidLevel; - -starGiftAuctionStateNotModified#fe333952 = StarGiftAuctionState; -starGiftAuctionState#771a4e66 version:int start_date:int end_date:int min_bid_amount:long bid_levels:Vector top_bidders:Vector next_round_at:int last_gift_num:int gifts_left:int current_round:int total_rounds:int rounds:Vector = StarGiftAuctionState; -starGiftAuctionStateFinished#972dabbf flags:# start_date:int end_date:int average_price:long listed_count:flags.0?int fragment_listed_count:flags.1?int fragment_listed_url:flags.1?string = StarGiftAuctionState; - -starGiftAuctionUserState#2eeed1c4 flags:# returned:flags.1?true bid_amount:flags.0?long bid_date:flags.0?int min_bid_amount:flags.0?long bid_peer:flags.0?Peer acquired_count:int = StarGiftAuctionUserState; - -payments.starGiftAuctionState#6b39f4ec gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState timeout:int users:Vector chats:Vector = payments.StarGiftAuctionState; - -starGiftAuctionAcquiredGift#42b00348 flags:# name_hidden:flags.0?true peer:Peer date:int bid_amount:long round:int pos:int message:flags.1?TextWithEntities gift_num:flags.2?int = StarGiftAuctionAcquiredGift; - -payments.starGiftAuctionAcquiredGifts#7d5bd1f0 gifts:Vector users:Vector chats:Vector = payments.StarGiftAuctionAcquiredGifts; - -starGiftActiveAuctionState#d31bc45d gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState = StarGiftActiveAuctionState; - -payments.starGiftActiveAuctionsNotModified#db33dad0 = payments.StarGiftActiveAuctions; -payments.starGiftActiveAuctions#aef6abbc auctions:Vector users:Vector chats:Vector = payments.StarGiftActiveAuctions; - -inputStarGiftAuction#2e16c98 gift_id:long = InputStarGiftAuction; -inputStarGiftAuctionSlug#7ab58308 slug:string = InputStarGiftAuction; - -passkey#98613ebf flags:# id:string name:string date:int software_emoji_id:flags.0?long last_usage_date:flags.1?int = Passkey; - -account.passkeys#f8e0aa1c passkeys:Vector = account.Passkeys; - -account.passkeyRegistrationOptions#e16b5ce1 options:DataJSON = account.PasskeyRegistrationOptions; - -auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions; - -inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse; -inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse; - -inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential; -inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential; - -starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground; - -starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound; -starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound; - -payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector = payments.StarGiftUpgradeAttributes; - -messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome; - -messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo; -messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector plays_left:flags.0?int = messages.EmojiGameInfo; - -starGiftAttributeRarity#36437737 permille:int = StarGiftAttributeRarity; -starGiftAttributeRarityUncommon#dbce6389 = StarGiftAttributeRarity; -starGiftAttributeRarityRare#f08d516b = StarGiftAttributeRarity; -starGiftAttributeRarityEpic#78fbf3a8 = StarGiftAttributeRarity; -starGiftAttributeRarityLegendary#cef7e7a8 = StarGiftAttributeRarity; - -keyboardButtonStyle#4fdd3430 flags:# bg_primary:flags.0?true bg_danger:flags.1?true bg_success:flags.2?true icon:flags.3?long = KeyboardButtonStyle; - -inputMessageReadMetric#402b4495 msg_id:int view_id:long time_in_view_ms:int active_time_in_view_ms:int height_to_viewport_ratio_permille:int seen_range_ratio_permille:int = InputMessageReadMetric; - -bots.exportedBotToken#3c60b621 token:string = bots.ExportedBotToken; - -bots.requestedButton#f13bbcd7 webapp_req_id:string = bots.RequestedButton; - -messages.composedMessageWithAI#90d7adfa flags:# result_text:TextWithEntities diff_text:flags.0?TextWithEntities = messages.ComposedMessageWithAI; - ----functions--- - -invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; -invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; -initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; -invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; -invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; -invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; -invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; -invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; -invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; -invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X; -invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X; - -auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; -auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; -auth.signIn#8d52a951 flags:# phone_number:string phone_code_hash:string phone_code:flags.0?string email_verification:flags.1?EmailVerification = auth.Authorization; -auth.logOut#3e72ba19 = auth.LoggedOut; -auth.resetAuthorizations#9fab0d1a = Bool; -auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; -auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; -auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; -auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; -auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; -auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; -auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; -auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode; -auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; -auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; -auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; -auth.acceptLoginToken#e894ad4d token:bytes = Authorization; -auth.checkRecoveryPassword#d36bf79 code:string = Bool; -auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; -auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool; -auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; -auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; -auth.checkPaidAuth#56e59f9c phone_number:string phone_code_hash:string form_id:long = auth.SentCode; -auth.initPasskeyLogin#518ad0b7 api_id:int api_hash:string = auth.PasskeyLoginOptions; -auth.finishPasskeyLogin#9857ad07 flags:# credential:InputPasskeyCredential from_dc_id:flags.0?int from_auth_key_id:flags.0?long = auth.Authorization; - -account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; -account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; -account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; -account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; -account.resetNotifySettings#db7e1747 = Bool; -account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; -account.updateStatus#6628562c offline:Bool = Bool; -account.getWallPapers#7967d36 hash:long = account.WallPapers; -account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool; -account.checkUsername#2714d86c username:string = Bool; -account.updateUsername#3e0bdd7c username:string = User; -account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; -account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; -account.deleteAccount#a2c0cf74 flags:# reason:string password:flags.0?InputCheckPasswordSRP = Bool; -account.getAccountTTL#8fc711d = AccountDaysTTL; -account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; -account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; -account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; -account.updateDeviceLocked#38df3532 period:int = Bool; -account.getAuthorizations#e320c158 = account.Authorizations; -account.resetAuthorization#df77f3bc hash:long = Bool; -account.getPassword#548a30f5 = account.Password; -account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; -account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; -account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; -account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; -account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; -account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; -account.resetWebAuthorization#2d01b9ef hash:long = Bool; -account.resetWebAuthorizations#682d2594 = Bool; -account.getAllSecureValues#b288bc7d = Vector; -account.getSecureValue#73665bc2 types:Vector = Vector; -account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; -account.deleteSecureValue#b880bc4b types:Vector = Bool; -account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm; -account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; -account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; -account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; -account.sendVerifyEmailCode#98e037bb purpose:EmailVerifyPurpose email:string = account.SentEmailCode; -account.verifyEmail#32da4cf purpose:EmailVerifyPurpose verification:EmailVerification = account.EmailVerified; -account.initTakeoutSession#8ef3eab0 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?long = account.Takeout; -account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; -account.confirmPasswordEmail#8fdf1920 code:string = Bool; -account.resendPasswordEmail#7a7f2a15 = Bool; -account.cancelPasswordEmail#c1cbd5b6 = Bool; -account.getContactSignUpNotification#9f07c728 = Bool; -account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; -account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true compare_stories:flags.2?true peer:flags.0?InputNotifyPeer = Updates; -account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; -account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; -account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; -account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; -account.resetWallPapers#bb3b9804 = Bool; -account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; -account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; -account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document; -account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool; -account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool; -account.getTheme#3a5869ec format:string theme:InputTheme = Theme; -account.getThemes#7206e458 format:string hash:long = account.Themes; -account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool; -account.getContentSettings#8b9b4dae = account.ContentSettings; -account.getMultiWallPapers#65ad71dc wallpapers:Vector = Vector; -account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings; -account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; -account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; -account.resetPassword#9308ce1b = account.ResetPasswordResult; -account.declinePasswordReset#4c9409f6 = Bool; -account.getChatThemes#d638de89 hash:long = account.Themes; -account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; -account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; -account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones; -account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone; -account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document; -account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool; -account.getDefaultEmojiStatuses#d6753386 hash:long = account.EmojiStatuses; -account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; -account.clearRecentEmojiStatuses#18201aae = Bool; -account.reorderUsernames#ef500eab order:Vector = Bool; -account.toggleUsername#58d6b376 username:string active:Bool = Bool; -account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList; -account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList; -account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings; -account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool; -account.deleteAutoSaveExceptions#53bc0020 = Bool; -account.invalidateSignInCodes#ca8ae8ba codes:Vector = Bool; -account.updateColor#684d214e flags:# for_profile:flags.1?true color:flags.2?PeerColor = Bool; -account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList; -account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses; -account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList; -account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool; -account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool; -account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool; -account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool; -account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates; -account.getConnectedBots#4ea4c80f = account.ConnectedBots; -account.getBotBusinessConnection#76a86270 connection_id:string = Updates; -account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool; -account.toggleConnectedBotPaused#646e1097 peer:InputPeer paused:Bool = Bool; -account.disablePeerConnectedBot#5e437ed9 peer:InputPeer = Bool; -account.updateBirthday#cc6e0c11 flags:# birthday:flags.0?Birthday = Bool; -account.createBusinessChatLink#8851e68e link:InputBusinessChatLink = BusinessChatLink; -account.editBusinessChatLink#8c3410af slug:string link:InputBusinessChatLink = BusinessChatLink; -account.deleteBusinessChatLink#60073674 slug:string = Bool; -account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks; -account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks; -account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool; -account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool; -account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings; -account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings; -account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses; -account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue; -account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool; -account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool; -account.saveMusic#b26732a9 flags:# unsave:flags.0?true id:InputDocument after_id:flags.1?InputDocument = Bool; -account.getSavedMusicIds#e09d5faf hash:long = account.SavedMusicIds; -account.getUniqueGiftChatThemes#e42ce9c9 offset:string limit:int hash:long = account.ChatThemes; -account.initPasskeyRegistration#429547e8 = account.PasskeyRegistrationOptions; -account.registerPasskey#55b41fd6 credential:InputPasskeyCredential = Passkey; -account.getPasskeys#ea1f0c52 = account.Passkeys; -account.deletePasskey#f5b5563f id:string = Bool; - -users.getUsers#d91a548 id:Vector = Vector; -users.getFullUser#b60f5918 id:InputUser = users.UserFull; -users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; -users.getRequirementsToContact#d89a83a3 id:Vector = Vector; -users.getSavedMusic#788d7fe3 id:InputUser offset:int limit:int hash:long = users.SavedMusic; -users.getSavedMusicByID#7573a4e9 id:InputUser documents:Vector = users.SavedMusic; -users.suggestBirthday#fc533372 id:InputUser birthday:Birthday = Updates; - -contacts.getContactIDs#7adc669d hash:long = Vector; -contacts.getStatuses#c4a353ee = Vector; -contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; -contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; -contacts.deleteContacts#96a0e00 id:Vector = Updates; -contacts.deleteByPhones#1013fd9e phones:Vector = Bool; -contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; -contacts.search#11f812d8 q:string limit:int = contacts.Found; -contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer; -contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true offset:int limit:int hash:long = contacts.TopPeers; -contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; -contacts.resetSaved#879537f1 = Bool; -contacts.getSaved#82f1e39f = Vector; -contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; -contacts.addContact#d9ba2e54 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string note:flags.1?TextWithEntities = Updates; -contacts.acceptContact#f831a20f id:InputUser = Updates; -contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates; -contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates; -contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer; -contacts.exportContactToken#f8654027 = ExportedContactToken; -contacts.importContactToken#13005788 token:string = User; -contacts.editCloseFriends#ba6705f0 id:Vector = Bool; -contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector limit:int = Bool; -contacts.getBirthdays#daeda864 = contacts.ContactBirthdays; -contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers; -contacts.updateContactNote#139f63fb id:InputUser note:TextWithEntities = Bool; - -messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; -messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; -messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; -messages.receivedMessages#5a954c0 max_id:int = Vector; -messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; -messages.sendMessage#545cd15a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.sendMedia#330e77f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.forwardMessages#13704a7c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; -messages.reportSpam#cf1592db peer:InputPeer = Bool; -messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; -messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; -messages.getChats#49e9528f id:Vector = messages.Chats; -messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; -messages.editChatTitle#73783ffd chat_id:long title:string = Updates; -messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates; -messages.addChatUser#cbc6d107 chat_id:long user_id:InputUser fwd_limit:int = messages.InvitedUsers; -messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates; -messages.createChat#92ceddd4 flags:# users:Vector title:string ttl_period:flags.0?int = messages.InvitedUsers; -messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; -messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; -messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; -messages.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool; -messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; -messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; -messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; -messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.receivedQueue#55a5bb66 max_qts:int = Vector; -messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; -messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; -messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers; -messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers; -messages.getWebPagePreview#570d6f6f flags:# message:string entities:flags.3?Vector = messages.WebPagePreview; -messages.exportChatInvite#a455de90 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string subscription_pricing:flags.5?StarsSubscriptionPricing = ExportedChatInvite; -messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; -messages.importChatInvite#6c50051c hash:string = Updates; -messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet; -messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; -messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; -messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; -messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool = messages.MessageViews; -messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; -messages.migrateChat#a2875319 chat_id:long = Updates; -messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true groups_only:flags.2?true users_only:flags.3?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; -messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Bool; -messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document; -messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; -messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; -messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; -messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool; -messages.sendInlineBotResult#c0cf7646 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut allow_paid_stars:flags.21?long = Updates; -messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; -messages.editMessage#51e842e1 flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.15?int schedule_repeat_period:flags.18?int quick_reply_shortcut_id:flags.17?int = Updates; -messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; -messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; -messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; -messages.saveDraft#54ae308e flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost = Bool; -messages.getAllDrafts#6a3f8d65 = Updates; -messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; -messages.readFeaturedStickers#5b118126 id:Vector = Bool; -messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; -messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; -messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; -messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers; -messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; -messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; -messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; -messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; -messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; -messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; -messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats; -messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage; -messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; -messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; -messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; -messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; -messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia; -messages.sendScreenshotNotification#a1405817 peer:InputPeer reply_to:InputReplyTo random_id:long = Updates; -messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers; -messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; -messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; -messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; -messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSplitRanges#1cff7e08 = Vector; -messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool; -messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector; -messages.clearAllDrafts#7e58ee9c = Bool; -messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates; -messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; -messages.getPollResults#eda3e33b peer:InputPeer msg_id:int poll_hash:long = Updates; -messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; -messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; -messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; -messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; -messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; -messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; -messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; -messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector = Vector; -messages.requestUrlAuth#894cc99c flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string in_app_origin:flags.3?string = UrlAuthResult; -messages.acceptUrlAuth#67a3f0de flags:# write_allowed:flags.0?true share_phone_number:flags.3?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string match_code:flags.4?string = UrlAuthResult; -messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; -messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages; -messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; -messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector = Updates; -messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector = Updates; -messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList; -messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector = Bool; -messages.getDialogFilters#efd48c89 = messages.DialogFilters; -messages.getSuggestedDialogFilters#a29cd42c = Vector; -messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool; -messages.updateDialogFiltersOrder#c563c1e4 order:Vector = Bool; -messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers; -messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; -messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; -messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.deleteChat#5bd0ee50 chat_id:long = Bool; -messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; -messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; -messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport; -messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; -messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; -messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; -messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; -messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite; -messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; -messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; -messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; -messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true subscription_expired:flags.3?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; -messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; -messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; -messages.setChatTheme#81202c9 peer:InputPeer theme:InputChatTheme = Updates; -messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector; -messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; -messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; -messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; -messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; -messages.toggleNoForwards#b2081a35 flags:# peer:InputPeer enabled:Bool request_msg_id:flags.0?int = Updates; -messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; -messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector = Updates; -messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector = Updates; -messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList; -messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int paid_enabled:flags.1?Bool = Updates; -messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; -messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool; -messages.translateText#a5eec345 flags:# peer:flags.0?InputPeer id:flags.0?Vector text:flags.1?Vector to_lang:string tone:flags.2?string = messages.TranslatedText; -messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages; -messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; -messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; -messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; -messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; -messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; -messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true fullscreen:flags.8?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; -messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; -messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; -messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool; -messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector = Vector; -messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers; -messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers; -messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer = Bool; -messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions; -messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions; -messages.clearRecentReactions#9dfeefb4 = Bool; -messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector = Updates; -messages.setDefaultHistoryTTL#9eb51445 period:int = Bool; -messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL; -messages.sendBotRequestedPeer#6c5cf2a7 flags:# peer:InputPeer msg_id:flags.0?int webapp_req_id:flags.1?string button_id:int requested_peers:Vector = Updates; -messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups; -messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups; -messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups; -messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; -messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; -messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; -messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; -messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; -messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; -messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; -messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; -messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags; -messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; -messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; -messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate; -messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies; -messages.reorderQuickReplies#60331907 order:Vector = Bool; -messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool; -messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool; -messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool; -messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector hash:long = messages.Messages; -messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vector random_id:Vector = Updates; -messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; -messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; -messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; -messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; -messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; -messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; -messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; -messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; -messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates; -messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool; -messages.getPaidReactionPrivacy#472455aa = Updates; -messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; -messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; -messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; -messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages; -messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; -messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; -messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; -messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; -messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; -messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; -messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; -messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; -messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates; -messages.getForumTopics#3ba47bff flags:# peer:InputPeer q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; -messages.getForumTopicsByID#af0a4a08 peer:InputPeer topics:Vector = messages.ForumTopics; -messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates; -messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates; -messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector = Updates; -messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; -messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory; -messages.getEmojiGameInfo#fb7e8ca7 = messages.EmojiGameInfo; -messages.summarizeText#abbbd346 flags:# peer:InputPeer id:int to_lang:flags.0?string tone:flags.2?string = TextWithEntities; -messages.editChatCreator#f743b857 peer:InputPeer user_id:InputUser password:InputCheckPasswordSRP = Updates; -messages.getFutureChatCreatorAfterLeave#3b7d0ea6 peer:InputPeer = User; -messages.editChatParticipantRank#a00f32b0 peer:InputPeer participant:InputPeer rank:string = Updates; -messages.declineUrlAuth#35436bbc url:string = Bool; -messages.checkUrlAuthMatchCode#c9a47b0b url:string match_code:string = Bool; -messages.composeMessageWithAI#fd426afe flags:# proofread:flags.0?true emojify:flags.3?true text:TextWithEntities translate_to_lang:flags.1?string change_tone:flags.2?string = messages.ComposedMessageWithAI; -messages.reportReadMetrics#4067c5e6 peer:InputPeer metrics:Vector = Bool; -messages.reportMusicListen#ddbcd819 id:InputDocument listened_duration:int = Bool; -messages.addPollAnswer#19bc4b6d peer:InputPeer msg_id:int answer:PollAnswer = Updates; -messages.deletePollAnswer#ac8505a5 peer:InputPeer msg_id:int option:bytes = Updates; -messages.getUnreadPollVotes#43286cf2 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readPollVotes#1720b4d8 flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; - -updates.getState#edd4882a = updates.State; -updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; -updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; - -photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo; -photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo; -photos.deletePhotos#87cf7f2f id:Vector = Vector; -photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; -photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo; - -upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; -upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File; -upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; -upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; -upload.getCdnFile#395f69da file_token:bytes offset:long limit:int = upload.CdnFile; -upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; -upload.getCdnFileHashes#91dc3f31 file_token:bytes offset:long = Vector; -upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector; - -help.getConfig#c4f9186b = Config; -help.getNearestDc#1fb33026 = NearestDc; -help.getAppUpdate#522d5a7d source:string = help.AppUpdate; -help.getInviteText#4d392343 = help.InviteText; -help.getSupport#9cdf08cd = help.Support; -help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; -help.getCdnConfig#52029342 = CdnConfig; -help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; -help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; -help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; -help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; -help.getAppConfig#61e3f854 hash:int = help.AppConfig; -help.saveAppLog#6f02f748 events:Vector = Bool; -help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; -help.getSupportName#d360e72c = help.SupportName; -help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; -help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; -help.getPromoData#c0977421 = help.PromoData; -help.hidePromoData#1e251c95 peer:InputPeer = Bool; -help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; -help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; -help.getPremiumPromo#b81b93d4 = help.PremiumPromo; -help.getPeerColors#da80f42f hash:int = help.PeerColors; -help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors; -help.getTimezonesList#49b30240 hash:int = help.TimezonesList; - -channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; -channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; -channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector = Bool; -channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; -channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; -channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; -channels.getChannels#a7f6bbb id:Vector = messages.Chats; -channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; -channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates; -channels.editAdmin#9a98ad68 flags:# channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:flags.0?string = Updates; -channels.editTitle#566decd0 channel:InputChannel title:string = Updates; -channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; -channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; -channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; -channels.joinChannel#24b524c5 channel:InputChannel = Updates; -channels.leaveChannel#f836aa95 channel:InputChannel = Updates; -channels.inviteToChannel#c9e33d54 channel:InputChannel users:Vector = messages.InvitedUsers; -channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; -channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; -channels.toggleSignatures#418d549c flags:# signatures_enabled:flags.0?true profiles_enabled:flags.1?true channel:InputChannel = Updates; -channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_personal:flags.2?true = messages.Chats; -channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; -channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; -channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; -channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates; -channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; -channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; -channels.getGroupsForDiscussion#f5dad378 = messages.Chats; -channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; -channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; -channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; -channels.getInactiveChannels#11e831ee = messages.InactiveChats; -channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; -channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true for_live_stories:flags.1?true peer:InputPeer = channels.SendAsPeers; -channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory; -channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates; -channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates; -channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector = Bool; -channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool; -channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool; -channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates; -channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates; -channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool; -channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; -channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates; -channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; -channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats; -channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates; -channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates; -channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; -channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; -channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; -channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; -channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; -channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood; -channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool; - -bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; -bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; -bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector = Bool; -bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool; -bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector; -bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool; -bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton; -bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool; -bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool; -bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool; -bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo; -bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector = Bool; -bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool; -bots.canSendMessage#1359f4e6 bot:InputUser = Bool; -bots.allowSendMessage#f132e3ef bot:InputUser = Updates; -bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; -bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; -bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia; -bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia; -bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector = Bool; -bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector = Bool; -bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo; -bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; -bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool; -bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; -bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; -bots.getAdminedBots#b0711d83 = Vector; -bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram; -bots.setCustomVerification#8b89dfbd flags:# enabled:flags.1?true bot:flags.0?InputUser peer:InputPeer custom_description:flags.2?string = Bool; -bots.getBotRecommendations#a1b70815 bot:InputUser = users.Users; -bots.checkUsername#87f2219b username:string = Bool; -bots.createBot#e5b17f2b flags:# via_deeplink:flags.0?true name:string username:string manager_id:InputUser = User; -bots.exportBotToken#bd0d99eb bot:InputUser revoke:Bool = bots.ExportedBotToken; -bots.requestWebViewButton#31a2a35e user_id:InputUser button:KeyboardButton = bots.RequestedButton; -bots.getRequestedWebViewButton#bf25b7f3 bot:InputUser webapp_req_id:string = KeyboardButton; - -payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; -payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; -payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; -payments.sendPaymentForm#2d03522f flags:# form_id:long invoice:InputInvoice requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; -payments.getSavedInfo#227d824b = payments.SavedInfo; -payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; -payments.getBankCardData#2e79d779 number:string = payments.BankCardData; -payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; -payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; -payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; -payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector; -payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; -payments.applyGiftCode#f6e26854 slug:string = Updates; -payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; -payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; -payments.getStarsTopupOptions#c00ec7d3 = Vector; -payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus; -payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; -payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult; -payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; -payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats; -payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; -payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; -payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector = payments.StarsStatus; -payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; -payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; -payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; -payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; -payments.getStarsGiveawayOptions#bd1efd3e = Vector; -payments.getStarGifts#c4563590 hash:int = payments.StarGifts; -payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool; -payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool; -payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; -payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; -payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots; -payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; -payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview; -payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates; -payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates; -payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift; -payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_unique:flags.4?true sort_by_value:flags.5?true exclude_upgradable:flags.7?true exclude_unupgradable:flags.8?true peer_color_available:flags.9?true exclude_hosted:flags.10?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts; -payments.getSavedStarGift#b455a106 stargift:Vector = payments.SavedStarGifts; -payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; -payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; -payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; -payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; -payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true for_craft:flags.4?true stars_only:flags.5?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; -payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; -payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; -payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; -payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector = Bool; -payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool; -payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections; -payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo; -payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult; -payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState; -payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts; -payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions; -payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates; -payments.sendStarGiftOffer#8fb86b41 flags:# peer:InputPeer slug:string price:StarsAmount duration:int random_id:long allow_paid_stars:flags.0?long = Updates; -payments.getStarGiftUpgradeAttributes#6d038b58 gift_id:long = payments.StarGiftUpgradeAttributes; -payments.getCraftStarGifts#fd05dd00 gift_id:long offset:string limit:int = payments.SavedStarGifts; -payments.craftStarGift#b0f9684f stargift:Vector = Updates; - -stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; -stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; -stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; -stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; -stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet; -stickers.checkShortName#284b3639 short_name:string = Bool; -stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName; -stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet; -stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet; -stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool; -stickers.replaceSticker#4696459a sticker:InputDocument new_sticker:InputStickerSetItem = messages.StickerSet; - -phone.getCallConfig#55451fa9 = DataJSON; -phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; -phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; -phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; -phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; -phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; -phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; -phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; -phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates; -phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; -phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; -phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; -phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates; -phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; -phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; -phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; -phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; -phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; -phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; -phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; -phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; -phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; -phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; -phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; -phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates; -phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates; -phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels; -phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl; -phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool; -phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates; -phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector block:bytes = Updates; -phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates; -phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates; -phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates; -phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates; -phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates; -phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool; -phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector = Updates; -phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates; -phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars; -phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool; - -langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; -langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; -langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; -langpack.getLanguages#42c6978f lang_pack:string = Vector; -langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; - -folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; - -stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats; -stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; -stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; -stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards; -stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; -stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; -stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards; - -chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; -chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; -chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector = ExportedChatlistInvite; -chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites; -chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite; -chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector = Updates; -chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates; -chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector = Updates; -chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool; -chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector; -chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector = Updates; - -stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount; -stories.sendStory#8f9e6898 flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector music:flags.9?InputDocument = Updates; -stories.editStory#2c63a72b flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector music:flags.4?InputDocument = Updates; -stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; -stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; -stories.getAllStories#eeb0d625 flags:# next:flags.1?true hidden:flags.2?true state:flags.0?string = stories.AllStories; -stories.getPinnedStories#5821a5dc peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector = stories.Stories; -stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool; -stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector; -stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector = Bool; -stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList; -stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector = stories.StoryViews; -stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; -stories.report#19d8eb45 peer:InputPeer id:Vector option:bytes message:string = ReportResult; -stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates; -stories.sendReaction#7fd736b2 flags:# add_to_recent:flags.0?true peer:InputPeer story_id:int reaction:Reaction = Updates; -stories.getPeerStories#2c4ada50 peer:InputPeer = stories.PeerStories; -stories.getAllReadPeerStories#9b5ae7f9 = Updates; -stories.getPeerMaxIDs#78499170 id:Vector = Vector; -stories.getChatsToSend#a56a8b60 = messages.Chats; -stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; -stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; -stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; -stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories; -stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector = StoryAlbum; -stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector add_stories:flags.2?Vector order:flags.3?Vector = StoryAlbum; -stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector = Bool; -stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool; -stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums; -stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories; -stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates; - -premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; -premium.getMyBoosts#be77b4a = premium.MyBoosts; -premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; -premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; -premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; - -smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin; -smsjobs.join#a74ece2d = Bool; -smsjobs.leave#9898ad73 = Bool; -smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool; -smsjobs.getStatus#10a698e8 = smsjobs.Status; -smsjobs.getSmsJob#778d902f job_id:string = SmsJob; -smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; - -fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; - -// LAYER 224 diff --git a/internal/compat/layerwire/_schema/layer-225.tl b/internal/compat/layerwire/_schema/layer-225.tl deleted file mode 100644 index 24720c36..00000000 --- a/internal/compat/layerwire/_schema/layer-225.tl +++ /dev/null @@ -1,2977 +0,0 @@ -boolFalse#bc799737 = Bool; -boolTrue#997275b5 = Bool; - -true#3fedd339 = True; - -vector#1cb5c415 {t:Type} # [ t ] = Vector t; - -error#c4b9f9bb code:int text:string = Error; - -null#56730bcc = Null; - -inputPeerEmpty#7f3b18ea = InputPeer; -inputPeerSelf#7da07ec9 = InputPeer; -inputPeerChat#35a95cb9 chat_id:long = InputPeer; -inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; -inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer; -inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer; -inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer; - -inputUserEmpty#b98886cf = InputUser; -inputUserSelf#f7c1b13f = InputUser; -inputUser#f21158c6 user_id:long access_hash:long = InputUser; -inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser; - -inputPhoneContact#6a1dc4be flags:# client_id:long phone:string first_name:string last_name:string note:flags.0?TextWithEntities = InputContact; - -inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; -inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; -inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile; - -inputMediaEmpty#9664f57f = InputMedia; -inputMediaUploadedPhoto#7d8375da flags:# spoiler:flags.2?true live_photo:flags.3?true file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int video:flags.3?InputDocument = InputMedia; -inputMediaPhoto#e3af4434 flags:# spoiler:flags.1?true live_photo:flags.2?true id:InputPhoto ttl_seconds:flags.0?int video:flags.2?InputDocument = InputMedia; -inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; -inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; -inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; -inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; -inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; -inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; -inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; -inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; -inputMediaPoll#883a4108 flags:# poll:Poll correct_answers:flags.0?Vector attached_media:flags.3?InputMedia solution:flags.1?string solution_entities:flags.1?Vector solution_media:flags.2?InputMedia = InputMedia; -inputMediaDice#e66fbf7b emoticon:string = InputMedia; -inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; -inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; -inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; -inputMediaTodo#9fc55fde todo:TodoList = InputMedia; -inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia; - -inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; -inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; -inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; - -inputGeoPointEmpty#e4c123d6 = InputGeoPoint; -inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint; - -inputPhotoEmpty#1cd7bf0d = InputPhoto; -inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; - -inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; -inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; -inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; -inputTakeoutFileLocation#29be5899 = InputFileLocation; -inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; -inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; -inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; -inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; - -peerUser#59511722 user_id:long = Peer; -peerChat#36c6019a chat_id:long = Peer; -peerChannel#a2a5371e channel_id:long = Peer; - -storage.fileUnknown#aa963b05 = storage.FileType; -storage.filePartial#40bc6f52 = storage.FileType; -storage.fileJpeg#7efe0e = storage.FileType; -storage.fileGif#cae1aadf = storage.FileType; -storage.filePng#a4f63c0 = storage.FileType; -storage.filePdf#ae1e508d = storage.FileType; -storage.fileMp3#528a0677 = storage.FileType; -storage.fileMov#4b09ebbc = storage.FileType; -storage.fileMp4#b3cea0e4 = storage.FileType; -storage.fileWebp#1081464c = storage.FileType; - -userEmpty#d3bc4b7a id:long = User; -user#31774388 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true bot_business:flags2.11?true bot_has_main_app:flags2.13?true bot_forum_view:flags2.16?true bot_forum_can_manage_topics:flags2.17?true bot_can_manage_bots:flags2.18?true bot_guestchat:flags2.19?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?RecentStory color:flags2.8?PeerColor profile_color:flags2.9?PeerColor bot_active_users:flags2.12?int bot_verification_icon:flags2.14?long send_paid_messages_stars:flags2.15?long = User; - -userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; - -userStatusEmpty#9d05049 = UserStatus; -userStatusOnline#edb93949 expires:int = UserStatus; -userStatusOffline#8c703f was_online:int = UserStatus; -userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus; -userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus; -userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; - -chatEmpty#29562865 id:long = Chat; -chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; -chatForbidden#6592a1a7 id:long title:string = Chat; -channel#1c32b11c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?RecentStory color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat; -channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true monoforum:flags.10?true id:long access_hash:long title:string until_date:flags.16?int = Chat; - -chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#e4e0b29d flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab = ChatFull; - -chatParticipant#38e79fde flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; -chatParticipantCreator#e1f867b8 flags:# user_id:long rank:flags.0?string = ChatParticipant; -chatParticipantAdmin#360d5d2 flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; - -chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants; -chatParticipants#3cbc93f8 chat_id:long participants:Vector version:int = ChatParticipants; - -chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; - -messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; -message#95ef6f2b flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int from_rank:flags2.12?string peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long guestchat_via_from:flags2.19?Peer reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string = Message; -messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; - -messageMediaEmpty#3ded6320 = MessageMedia; -messageMediaPhoto#e216eb63 flags:# spoiler:flags.3?true live_photo:flags.4?true photo:flags.0?Photo ttl_seconds:flags.2?int video:flags.4?Document = MessageMedia; -messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; -messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; -messageMediaUnsupported#9f84f49e = MessageMedia; -messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; -messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; -messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; -messageMediaGame#fdb19008 game:Game = MessageMedia; -messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia; -messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia; -messageMediaPoll#773f4e66 flags:# poll:Poll results:PollResults attached_media:flags.0?MessageMedia = MessageMedia; -messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia; -messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; -messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; -messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; -messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; -messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector = MessageMedia; -messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia; - -messageActionEmpty#b6aef7b0 = MessageAction; -messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; -messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; -messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; -messageActionChatDeletePhoto#95e3fbef = MessageAction; -messageActionChatAddUser#15cefd00 users:Vector = MessageAction; -messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction; -messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction; -messageActionChannelCreate#95d2ac92 title:string = MessageAction; -messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction; -messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction; -messageActionPinMessage#94bd38ed = MessageAction; -messageActionHistoryClear#9fbab604 = MessageAction; -messageActionGameScore#92a72876 game_id:long score:int = MessageAction; -messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction; -messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction; -messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; -messageActionScreenshotTaken#4792929b = MessageAction; -messageActionCustomAction#fae69f56 message:string = MessageAction; -messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction; -messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; -messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; -messageActionContactSignUp#f3f25f76 = MessageAction; -messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction; -messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; -messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector = MessageAction; -messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction; -messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; -messageActionSetChatTheme#b91bbd3a theme:ChatTheme = MessageAction; -messageActionChatJoinedByRequest#ebbca3cb = MessageAction; -messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction; -messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction; -messageActionGiftPremium#48e91302 flags:# currency:string amount:long days:int crypto_currency:flags.0?string crypto_amount:flags.0?long message:flags.1?TextWithEntities = MessageAction; -messageActionTopicCreate#d999256 flags:# title_missing:flags.1?true title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction; -messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction; -messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; -messageActionRequestedPeer#31518e9b button_id:int peers:Vector = MessageAction; -messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; -messageActionGiftCode#31c48347 flags:# via_giveaway:flags.0?true unclaimed:flags.5?true boost_peer:flags.1?Peer days:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long message:flags.4?TextWithEntities = MessageAction; -messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction; -messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction; -messageActionBoostApply#cc02aa6d boosts:int = MessageAction; -messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; -messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; -messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; -messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; -messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction; -messageActionStarGiftUnique#e6c31522 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true craft:flags.16?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long can_craft_at:flags.15?int = MessageAction; -messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; -messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; -messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; -messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; -messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; -messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction; -messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction; -messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction; -messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction; -messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction; -messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction; -messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction; -messageActionNewCreatorPending#b07ed085 new_creator_id:long = MessageAction; -messageActionChangeCreator#e188503b new_creator_id:long = MessageAction; -messageActionNoForwardsToggle#bf7d6572 prev_value:Bool new_value:Bool = MessageAction; -messageActionNoForwardsRequest#3e2793ba flags:# expired:flags.0?true prev_value:Bool new_value:Bool = MessageAction; -messageActionPollAppendAnswer#9da1cd6c answer:PollAnswer = MessageAction; -messageActionPollDeleteAnswer#399674dc answer:PollAnswer = MessageAction; -messageActionManagedBotCreated#16605e3e bot_id:long = MessageAction; - -dialog#fc89f7f3 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; -dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; - -photoEmpty#2331b22d id:long = Photo; -photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = Photo; - -photoSizeEmpty#e17e23c type:string = PhotoSize; -photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; -photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; -photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; -photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; -photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; - -geoPointEmpty#1117dd5f = GeoPoint; -geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; - -auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; -auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; -auth.sentCodePaymentRequired#e0955a3c store_product:string phone_code_hash:string support_email_address:string support_email_subject:string currency:string amount:long = auth.SentCode; - -auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; -auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; - -auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; - -inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; -inputNotifyUsers#193b4417 = InputNotifyPeer; -inputNotifyChats#4a95e84e = InputNotifyPeer; -inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; -inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer; - -inputPeerNotifySettings#cacb6ae2 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_sound:flags.8?NotificationSound = InputPeerNotifySettings; - -peerNotifySettings#99622c0c flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_ios_sound:flags.8?NotificationSound stories_android_sound:flags.9?NotificationSound stories_other_sound:flags.10?NotificationSound = PeerNotifySettings; - -peerSettings#f47741f7 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true business_bot_paused:flags.11?true business_bot_can_reply:flags.12?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int business_bot_id:flags.13?long business_bot_manage_url:flags.13?string charge_paid_message_stars:flags.14?long registration_month:flags.15?string phone_country:flags.16?string name_change_date:flags.17?int photo_change_date:flags.18?int = PeerSettings; - -wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; -wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; - -inputReportReasonSpam#58dbcab8 = ReportReason; -inputReportReasonViolence#1e22c78d = ReportReason; -inputReportReasonPornography#2e59d922 = ReportReason; -inputReportReasonChildAbuse#adf44ee3 = ReportReason; -inputReportReasonOther#c1e4a2b1 = ReportReason; -inputReportReasonCopyright#9b89f93a = ReportReason; -inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; -inputReportReasonFake#f5ddd6e7 = ReportReason; -inputReportReasonIllegalDrugs#a8eb2be = ReportReason; -inputReportReasonPersonalDetails#9ec7863d = ReportReason; - -userFull#6cbe645 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true noforwards_my_enabled:flags2.23?true noforwards_peer_enabled:flags2.24?true unofficial_security_risk:flags2.26?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme:flags.15?ChatTheme private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int main_tab:flags2.20?ProfileTab saved_music:flags2.21?Document note:flags2.22?TextWithEntities bot_manager_id:flags2.25?long = UserFull; - -contact#145ade0b user_id:long mutual:Bool = Contact; - -importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; - -contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; - -contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; -contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; - -contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; - -contacts.blocked#ade1591 blocked:Vector chats:Vector users:Vector = contacts.Blocked; -contacts.blockedSlice#e1664194 count:int blocked:Vector chats:Vector users:Vector = contacts.Blocked; - -messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; - -messages.messages#1d73e7ea messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#5f206716 flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesNotModified#74535f21 count:int = messages.Messages; - -messages.chats#64ff9fd5 chats:Vector = messages.Chats; -messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; - -messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; - -messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; - -inputMessagesFilterEmpty#57e2f66c = MessagesFilter; -inputMessagesFilterPhotos#9609a51c = MessagesFilter; -inputMessagesFilterVideo#9fc00e65 = MessagesFilter; -inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; -inputMessagesFilterDocument#9eddf188 = MessagesFilter; -inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; -inputMessagesFilterGif#ffc86587 = MessagesFilter; -inputMessagesFilterVoice#50f5c392 = MessagesFilter; -inputMessagesFilterMusic#3751b49e = MessagesFilter; -inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; -inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; -inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; -inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; -inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; -inputMessagesFilterGeo#e7026d0d = MessagesFilter; -inputMessagesFilterContacts#e062db83 = MessagesFilter; -inputMessagesFilterPinned#1bb00451 = MessagesFilter; -inputMessagesFilterPoll#fa2bc90a = MessagesFilter; - -updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; -updateMessageID#4e90bfd6 id:int random_id:long = Update; -updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; -updateUserTyping#2a17bf5c flags:# user_id:long top_msg_id:flags.0?int action:SendMessageAction = Update; -updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update; -updateChatParticipants#7761198 participants:ChatParticipants = Update; -updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; -updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector = Update; -updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update; -updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; -updateEncryptedChatTyping#1710f156 chat_id:int = Update; -updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; -updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; -updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update; -updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update; -updateDcOptions#8e5e9873 dc_options:Vector = Update; -updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; -updateServiceNotification#ebe46819 flags:# popup:flags.0?true invert_media:flags.2?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; -updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; -updateUserPhone#5492a13 user_id:long phone:string = Update; -updateReadHistoryInbox#9e84bc99 flags:# folder_id:flags.0?int peer:Peer top_msg_id:flags.1?int max_id:int still_unread_count:int pts:int pts_count:int = Update; -updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; -updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; -updateReadMessagesContents#f8227181 flags:# messages:Vector pts:int pts_count:int date:flags.0?int = Update; -updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; -updateChannel#635b4c09 channel_id:long = Update; -updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update; -updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; -updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; -updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; -updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Update; -updateStickerSets#31c24808 flags:# masks:flags.0?true emojis:flags.1?true = Update; -updateSavedGifs#9375341e = Update; -updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; -updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; -updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; -updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; -updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; -updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update; -updateReadFeaturedStickers#571d2742 = Update; -updateRecentStickers#9a422c20 = Update; -updateConfig#a229dd06 = Update; -updatePtsChanged#3354678f = Update; -updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update; -updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; -updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; -updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; -updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; -updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update; -updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; -updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; -updateLangPackTooLong#46560264 lang_code:string = Update; -updateLangPack#56022f4d difference:LangPackDifference = Update; -updateFavedStickers#e511996d = Update; -updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector = Update; -updateContactsReset#7084a7be = Update; -updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; -updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update; -updateMessagePoll#d64c522b flags:# peer:flags.1?Peer msg_id:flags.1?int top_msg_id:flags.2?int poll_id:long poll:flags.0?Poll results:PollResults = Update; -updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; -updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; -updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update; -updatePeerLocated#b4afcfb0 peers:Vector = Update; -updateNewScheduledMessage#39a51dfb message:Message = Update; -updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector sent_messages:flags.0?Vector = Update; -updateTheme#8216fba3 theme:Theme = Update; -updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update; -updateLoginToken#564fe691 = Update; -updateMessagePollVote#7699f014 poll_id:long peer:Peer options:Vector positions:Vector qts:int = Update; -updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update; -updateDialogFilterOrder#a5d72105 order:Vector = Update; -updateDialogFilters#3504914f = Update; -updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update; -updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update; -updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update; -updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update; -updatePeerBlocked#ebe07752 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer = Update; -updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; -updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; -updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChat#f89a6a4e chat_id:long = Update; -updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; -updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update; -updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; -updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update; -updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update; -updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; -updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; -updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update; -updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update; -updateAttachMenuBots#17b7a20b = Update; -updateWebViewResultSent#1592b79d query_id:long = Update; -updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update; -updateSavedRingtones#74d8be99 = Update; -updateTranscribedAudio#84cd5a flags:# pending:flags.0?true peer:Peer msg_id:int transcription_id:long text:string = Update; -updateReadFeaturedEmojiStickers#fb4c496c = Update; -updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update; -updateRecentEmojiStatuses#30f443db = Update; -updateRecentReactions#6f7863f4 = Update; -updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update; -updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector = Update; -updateUser#20529438 user_id:long = Update; -updateAutoSaveSettings#ec05b097 = Update; -updateStory#75b3b798 peer:Peer story:StoryItem = Update; -updateReadStories#f74e932b peer:Peer max_id:int = Update; -updateStoryID#1bf335b9 id:int random_id:long = Update; -updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update; -updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update; -updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update; -updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update; -updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update; -updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector new_reactions:Vector qts:int = Update; -updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector qts:int = Update; -updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; -updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector = Update; -updateSavedReactionTags#39c67432 = Update; -updateSmsJob#f16269d4 job_id:string = Update; -updateQuickReplies#f9470ab2 quick_replies:Vector = Update; -updateNewQuickReply#f53da717 quick_reply:QuickReply = Update; -updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update; -updateQuickReplyMessage#3e050d0f message:Message = Update; -updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector = Update; -updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Update; -updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; -updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; -updateStarsBalance#4e80a379 balance:StarsAmount = Update; -updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; -updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; -updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; -updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; -updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; -updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; -updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update; -updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = Update; -updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update; -updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update; -updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector = Update; -updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector = Update; -updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update; -updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update; -updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update; -updateStarGiftCraftFail#ac072444 = Update; -updateChatParticipantRank#bd8367b9 chat_id:long user_id:long rank:string version:int = Update; -updateManagedBot#4880ed9a user_id:long bot_id:long qts:int = Update; -updateBotGuestChatQuery#cdd4093d flags:# query_id:long message:Message reference_messages:flags.0?Vector qts:int = Update; -updateAiComposeTones#8c0f91fb = Update; - -updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; - -updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; -updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; -updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; -updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; - -updatesTooLong#e317af7e = Updates; -updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShort#78d4dec1 update:Update date:int = Updates; -updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; -updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; -updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; -photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; - -photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; - -upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; -upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; - -dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; - -config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config; - -nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; - -help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate; -help.noAppUpdate#c45a6536 = help.AppUpdate; - -help.inviteText#18cb9f78 message:string = help.InviteText; - -encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; -encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat; -encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; -encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; -encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat; - -inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; - -encryptedFileEmpty#c21f497e = EncryptedFile; -encryptedFile#a8008cd8 id:long access_hash:long size:long dc_id:int key_fingerprint:int = EncryptedFile; - -inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; -inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; -inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; -inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; - -encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; -encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; - -messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; -messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; - -messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; -messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; - -inputDocumentEmpty#72f0eaae = InputDocument; -inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; - -documentEmpty#36f8c871 id:long = Document; -document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector video_thumbs:flags.1?Vector dc_id:int attributes:Vector = Document; - -help.support#17c6b5f6 phone_number:string user:User = help.Support; - -notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; -notifyUsers#b4c83b4c = NotifyPeer; -notifyChats#c007cec3 = NotifyPeer; -notifyBroadcasts#d612e8ef = NotifyPeer; -notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer; - -sendMessageTypingAction#16bf744e = SendMessageAction; -sendMessageCancelAction#fd5ec8f5 = SendMessageAction; -sendMessageRecordVideoAction#a187d66f = SendMessageAction; -sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; -sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; -sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; -sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; -sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; -sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; -sendMessageChooseContactAction#628cbc6f = SendMessageAction; -sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; -sendMessageRecordRoundAction#88f27fbc = SendMessageAction; -sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; -speakingInGroupCallAction#d92c2285 = SendMessageAction; -sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; -sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; -sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction; -sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction; -sendMessageTextDraftAction#376d975c random_id:long text:TextWithEntities = SendMessageAction; - -contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; - -inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; -inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; -inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; -inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; -inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; -inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; -inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; -inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey; -inputPrivacyKeyVoiceMessages#aee69d68 = InputPrivacyKey; -inputPrivacyKeyAbout#3823cc40 = InputPrivacyKey; -inputPrivacyKeyBirthday#d65a11cc = InputPrivacyKey; -inputPrivacyKeyStarGiftsAutoSave#e1732341 = InputPrivacyKey; -inputPrivacyKeyNoPaidMessages#bdc597b4 = InputPrivacyKey; -inputPrivacyKeySavedMusic#4dbe9226 = InputPrivacyKey; - -privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; -privacyKeyChatInvite#500e6dfa = PrivacyKey; -privacyKeyPhoneCall#3d662b7b = PrivacyKey; -privacyKeyPhoneP2P#39491cc8 = PrivacyKey; -privacyKeyForwards#69ec56a3 = PrivacyKey; -privacyKeyProfilePhoto#96151fed = PrivacyKey; -privacyKeyPhoneNumber#d19ae46d = PrivacyKey; -privacyKeyAddedByPhone#42ffd42b = PrivacyKey; -privacyKeyVoiceMessages#697f414 = PrivacyKey; -privacyKeyAbout#a486b761 = PrivacyKey; -privacyKeyBirthday#2000a518 = PrivacyKey; -privacyKeyStarGiftsAutoSave#2ca4fdf8 = PrivacyKey; -privacyKeyNoPaidMessages#17d348d2 = PrivacyKey; -privacyKeySavedMusic#ff7a571b = PrivacyKey; - -inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; -inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; -inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; -inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; -inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; -inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; -inputPrivacyValueAllowChatParticipants#840649cf chats:Vector = InputPrivacyRule; -inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector = InputPrivacyRule; -inputPrivacyValueAllowCloseFriends#2f453e49 = InputPrivacyRule; -inputPrivacyValueAllowPremium#77cdc9f1 = InputPrivacyRule; -inputPrivacyValueAllowBots#5a4fcce5 = InputPrivacyRule; -inputPrivacyValueDisallowBots#c4e57915 = InputPrivacyRule; - -privacyValueAllowContacts#fffe1bac = PrivacyRule; -privacyValueAllowAll#65427b82 = PrivacyRule; -privacyValueAllowUsers#b8905fb2 users:Vector = PrivacyRule; -privacyValueDisallowContacts#f888fa1a = PrivacyRule; -privacyValueDisallowAll#8b73e763 = PrivacyRule; -privacyValueDisallowUsers#e4621141 users:Vector = PrivacyRule; -privacyValueAllowChatParticipants#6b134e8e chats:Vector = PrivacyRule; -privacyValueDisallowChatParticipants#41c87565 chats:Vector = PrivacyRule; -privacyValueAllowCloseFriends#f7e8d89b = PrivacyRule; -privacyValueAllowPremium#ece9814b = PrivacyRule; -privacyValueAllowBots#21461b5d = PrivacyRule; -privacyValueDisallowBots#f6a5f82f = PrivacyRule; - -account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; - -accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; - -documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; -documentAttributeAnimated#11b58939 = DocumentAttribute; -documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; -documentAttributeVideo#43c57c48 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double video_codec:flags.5?string = DocumentAttribute; -documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; -documentAttributeFilename#15590068 file_name:string = DocumentAttribute; -documentAttributeHasStickers#9801d2f7 = DocumentAttribute; -documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute; - -messages.stickersNotModified#f1749a22 = messages.Stickers; -messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; - -stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; - -messages.allStickersNotModified#e86602c3 = messages.AllStickers; -messages.allStickers#cdbbcebb hash:long sets:Vector = messages.AllStickers; - -messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; - -webPageEmpty#211a1788 flags:# id:long url:flags.0?string = WebPage; -webPagePending#b0d13e47 flags:# id:long url:flags.0?string date:int = WebPage; -webPage#e89c45b2 flags:# has_large_media:flags.13?true video_cover_photo:flags.14?true id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector = WebPage; -webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; - -authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; - -account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector = account.Authorizations; - -account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password; - -account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; - -account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; - -auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; - -receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; - -chatInviteExported#a22cbd96 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int subscription_expired:flags.10?int title:flags.8?string subscription_pricing:flags.9?StarsSubscriptionPricing = ExportedChatInvite; -chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite; - -chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#5c9d3702 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true can_refulfill_subscription:flags.11?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector color:int subscription_pricing:flags.10?StarsSubscriptionPricing subscription_form_id:flags.12?long bot_verification:flags.13?BotVerification = ChatInvite; -chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; - -inputStickerSetEmpty#ffb62b95 = InputStickerSet; -inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; -inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; -inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; -inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; -inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet; -inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet; -inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; -inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; -inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet; -inputStickerSetTonGifts#1cf671a0 = InputStickerSet; - -stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; - -messages.stickerSet#6e153f16 set:StickerSet packs:Vector keywords:Vector documents:Vector = messages.StickerSet; -messages.stickerSetNotModified#d3f924eb = messages.StickerSet; - -botCommand#c27ac8c7 command:string description:string = BotCommand; - -botInfo#4d8a0299 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton privacy_policy_url:flags.7?string app_settings:flags.8?BotAppSettings verifier_settings:flags.9?BotVerifierSettings = BotInfo; - -keyboardButton#7d170cff flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrl#d80c25ec flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonCallback#e62bc960 flags:# requires_password:flags.0?true style:flags.10?KeyboardButtonStyle text:string data:bytes = KeyboardButton; -keyboardButtonRequestPhone#417efd8f flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonRequestGeoLocation#aa40f94d flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonSwitchInline#991399fc flags:# same_peer:flags.0?true style:flags.10?KeyboardButtonStyle text:string query:string peer_types:flags.1?Vector = KeyboardButton; -keyboardButtonGame#89c590f9 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonBuy#3fa53905 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrlAuth#f51006f9 flags:# style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; -inputKeyboardButtonUrlAuth#68013e72 flags:# request_write_access:flags.0?true style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; -keyboardButtonRequestPoll#7a11d782 flags:# style:flags.10?KeyboardButtonStyle quiz:flags.0?Bool text:string = KeyboardButton; -inputKeyboardButtonUserProfile#7d5e07c7 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:InputUser = KeyboardButton; -keyboardButtonUserProfile#c0fd5d09 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:long = KeyboardButton; -keyboardButtonWebView#e846b1a0 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonSimpleWebView#e15c4370 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonRequestPeer#5b0f15f5 flags:# style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -inputKeyboardButtonRequestPeer#2b78156 flags:# name_requested:flags.0?true username_requested:flags.1?true photo_requested:flags.2?true style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -keyboardButtonCopy#bcc4af10 flags:# style:flags.10?KeyboardButtonStyle text:string copy_text:string = KeyboardButton; - -keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; - -replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; -replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup; -replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector placeholder:flags.3?string = ReplyMarkup; -replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; - -messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; -messageEntityMention#fa04579d offset:int length:int = MessageEntity; -messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; -messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; -messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; -messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; -messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; -messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; -messageEntityCode#28a20571 offset:int length:int = MessageEntity; -messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; -messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; -messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity; -inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; -messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; -messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; -messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity; -messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; -messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; -messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; -messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; -messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity; -messageEntityFormattedDate#904ac7c7 flags:# relative:flags.0?true short_time:flags.1?true long_time:flags.2?true short_date:flags.3?true long_date:flags.4?true day_of_week:flags.5?true offset:int length:int date:int = MessageEntity; -messageEntityDiffInsert#71777116 offset:int length:int = MessageEntity; -messageEntityDiffReplace#c6c1e5a7 offset:int length:int old_text:string = MessageEntity; -messageEntityDiffDelete#652c1c5 offset:int length:int = MessageEntity; - -inputChannelEmpty#ee8c1e86 = InputChannel; -inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; -inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel; - -contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; - -messageRange#ae30253 min_id:int max_id:int = MessageRange; - -updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; -updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; -updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; - -channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; -channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; - -channelParticipant#1bd54456 flags:# user_id:long date:int subscription_until_date:flags.0?int rank:flags.2?string = ChannelParticipant; -channelParticipantSelf#a9478a1a flags:# via_request:flags.0?true user_id:long inviter_id:long date:int subscription_until_date:flags.1?int rank:flags.2?string = ChannelParticipant; -channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; -channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; -channelParticipantBanned#d5f0ad91 flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights rank:flags.2?string = ChannelParticipant; -channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; - -channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; -channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; -channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; -channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; -channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; -channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; -channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; -channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; - -channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; -channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; - -channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; - -help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; - -messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; -messages.savedGifs#84a02a0d hash:long gifs:Vector = messages.SavedGifs; - -inputBotInlineMessageMediaAuto#3380c786 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaWebPage#bddcc510 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true optional:flags.6?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; - -botInlineMessageMediaAuto#764cf810 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; -botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; - -messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector cache_time:int users:Vector = messages.BotResults; - -exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; - -messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader; - -auth.codeTypeSms#72a3158c = auth.CodeType; -auth.codeTypeCall#741cd3e3 = auth.CodeType; -auth.codeTypeFlashCall#226ccefb = auth.CodeType; -auth.codeTypeMissedCall#d61ad6ee = auth.CodeType; -auth.codeTypeFragmentSms#6ed998c = auth.CodeType; - -auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; -auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; -auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; -auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType; -auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; -auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; -auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; -auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; -auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; -auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; - -messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; - -messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; - -inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; -inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID; - -inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; - -messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; - -topPeer#edcdc05b peer:Peer rating:double = TopPeer; - -topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; -topPeerCategoryBotsInline#148677e2 = TopPeerCategory; -topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; -topPeerCategoryGroups#bd17a14a = TopPeerCategory; -topPeerCategoryChannels#161d9628 = TopPeerCategory; -topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; -topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; -topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; -topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory; - -topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; - -contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; -contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; -contacts.topPeersDisabled#b52c939d = contacts.TopPeers; - -draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; -draftMessage#96eaa5eb flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost = DraftMessage; - -messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; -messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; - -messages.recentStickersNotModified#b17f890 = messages.RecentStickers; -messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; - -messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; - -messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; -messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; - -stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; -stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; -stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector keywords:Vector documents:Vector = StickerSetCovered; -stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered; - -maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; - -inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; -inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; - -game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; - -inputGameID#32c3e77 id:long access_hash:long = InputGame; -inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; - -highScore#73a379eb pos:int user_id:long score:int = HighScore; - -messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; - -textEmpty#dc3d824f = RichText; -textPlain#744694e0 text:string = RichText; -textBold#6724abc4 text:RichText = RichText; -textItalic#d912a59c text:RichText = RichText; -textUnderline#c12622c4 text:RichText = RichText; -textStrike#9bf8bb95 text:RichText = RichText; -textFixed#6c3f19b9 text:RichText = RichText; -textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; -textEmail#de5a0dd6 text:RichText email:string = RichText; -textConcat#7e6260d7 texts:Vector = RichText; -textSubscript#ed6a8504 text:RichText = RichText; -textSuperscript#c7fb5e01 text:RichText = RichText; -textMarked#34b8621 text:RichText = RichText; -textPhone#1ccb966a text:RichText phone:string = RichText; -textImage#81ccf4f document_id:long w:int h:int = RichText; -textAnchor#35553762 text:RichText name:string = RichText; - -pageBlockUnsupported#13567e8a = PageBlock; -pageBlockTitle#70abc3fd text:RichText = PageBlock; -pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; -pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; -pageBlockHeader#bfd064ec text:RichText = PageBlock; -pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; -pageBlockParagraph#467a0766 text:RichText = PageBlock; -pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; -pageBlockFooter#48870999 text:RichText = PageBlock; -pageBlockDivider#db20b188 = PageBlock; -pageBlockAnchor#ce0d37b0 name:string = PageBlock; -pageBlockList#e4e88011 items:Vector = PageBlock; -pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; -pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; -pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; -pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; -pageBlockCover#39f23300 cover:PageBlock = PageBlock; -pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; -pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; -pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; -pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; -pageBlockChannel#ef1751b5 channel:Chat = PageBlock; -pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; -pageBlockKicker#1e148390 text:RichText = PageBlock; -pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; -pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; -pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; -pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; -pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; - -phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; -phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; -phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; -phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; -phoneCallDiscardReasonMigrateConferenceCall#9fbbf1f7 slug:string = PhoneCallDiscardReason; - -dataJSON#7d748d04 data:string = DataJSON; - -labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; - -invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector terms_url:flags.10?string subscription_period:flags.11?int = Invoice; - -paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; - -postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; - -paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; - -paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; - -webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; -webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; - -inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; - -inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; -inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; -inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation; - -upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; - -payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector users:Vector = payments.PaymentForm; -payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector = payments.PaymentForm; -payments.paymentFormStarGift#b425cfe1 form_id:long invoice:Invoice = payments.PaymentForm; - -payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; - -payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; -payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; - -payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; -payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector = payments.PaymentReceipt; - -payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; - -inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; -inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials; - -account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; - -shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; - -inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem; - -inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; - -phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#30535af5 flags:# p2p_allowed:flags.5?true video:flags.6?true conference_supported:flags.8?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int custom_parameters:flags.7?DataJSON = PhoneCall; -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; - -phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; -phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection; - -phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector = PhoneCallProtocol; - -phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; - -upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; -upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; - -cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; - -cdnConfig#5725e40a public_keys:Vector = CdnConfig; - -langPackString#cad181f6 key:string value:string = LangPackString; -langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; -langPackStringDeleted#2979eeb2 key:string = LangPackString; - -langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; - -langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; - -channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; -channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector new_value:Vector = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAutotranslation#c517f77e new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantEditRank#5806b4ec user_id:long prev_rank:string new_rank:string = ChannelAdminLogEventAction; - -channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; - -channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; - -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true edit_rank:flags.19?true = ChannelAdminLogEventsFilter; - -popularContact#5ce14175 client_id:long importers:int = PopularContact; - -messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; -messages.favedStickers#2cb51097 hash:long packs:Vector stickers:Vector = messages.FavedStickers; - -recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; -recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl; -recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl; -recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; -recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; - -help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; - -inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; - -webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; - -account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; - -inputMessageID#a676a322 id:int = InputMessage; -inputMessageReplyTo#bad88395 id:int = InputMessage; -inputMessagePinned#86872538 = InputMessage; -inputMessageCallbackQuery#acfa1a7e id:int query_id:long = InputMessage; - -inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; -inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; - -dialogPeer#e56dbf05 peer:Peer = DialogPeer; -dialogPeerFolder#514519e2 folder_id:int = DialogPeer; - -messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; -messages.foundStickerSets#8af09dd2 hash:long sets:Vector = messages.FoundStickerSets; - -fileHash#f39b035c offset:long limit:int hash:bytes = FileHash; - -inputClientProxy#75588b3f address:string port:int = InputClientProxy; - -help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; -help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; - -inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; -inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; - -secureFileEmpty#64199744 = SecureFile; -secureFile#7d09c27e id:long access_hash:long size:long dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; - -secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; - -securePlainPhone#7d6099dd phone:string = SecurePlainData; -securePlainEmail#21ec5a5f email:string = SecurePlainData; - -secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; -secureValueTypePassport#3dac6a00 = SecureValueType; -secureValueTypeDriverLicense#6e425c4 = SecureValueType; -secureValueTypeIdentityCard#a0d0744b = SecureValueType; -secureValueTypeInternalPassport#99a48f23 = SecureValueType; -secureValueTypeAddress#cbe31e26 = SecureValueType; -secureValueTypeUtilityBill#fc36954e = SecureValueType; -secureValueTypeBankStatement#89137c0d = SecureValueType; -secureValueTypeRentalAgreement#8b883488 = SecureValueType; -secureValueTypePassportRegistration#99e3806a = SecureValueType; -secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; -secureValueTypePhone#b320aadb = SecureValueType; -secureValueTypeEmail#8e3ca7ee = SecureValueType; - -secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; - -inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; - -secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; - -secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; -secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; -secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; - -secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; - -account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; - -account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; - -help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; -help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; - -savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; - -account.takeout#4dba4501 id:long = account.Takeout; - -passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; -passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; - -securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; -securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; -securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; - -secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; - -inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; -inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; - -secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; -secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; - -help.passportConfigNotModified#bfb9f457 = help.PassportConfig; -help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; - -inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; - -jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; - -jsonNull#3f6d7b68 = JSONValue; -jsonBool#c7345e6a value:Bool = JSONValue; -jsonNumber#2be0dfa4 value:double = JSONValue; -jsonString#b71e767a value:string = JSONValue; -jsonArray#f7444763 value:Vector = JSONValue; -jsonObject#99c1d49d value:Vector = JSONValue; - -pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; - -pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; - -pageCaption#6f747657 text:RichText credit:RichText = PageCaption; - -pageListItemText#b92fb6cd text:RichText = PageListItem; -pageListItemBlocks#25e073fc blocks:Vector = PageListItem; - -pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; -pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; - -pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; - -page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector views:flags.3?int = Page; - -help.supportName#8c05f1c9 name:string = help.SupportName; - -help.userInfoEmpty#f3ae2eed = help.UserInfo; -help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; - -pollAnswer#4b7d786a flags:# text:TextWithEntities option:bytes media:flags.0?MessageMedia added_by:flags.1?Peer date:flags.1?int = PollAnswer; -inputPollAnswer#199fed96 flags:# text:TextWithEntities media:flags.0?InputMedia = PollAnswer; - -poll#966e2dbf id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true open_answers:flags.6?true revoting_disabled:flags.7?true shuffle_answers:flags.8?true hide_results_until_close:flags.9?true creator:flags.10?true subscribers_only:flags.11?true question:TextWithEntities answers:Vector close_period:flags.4?int close_date:flags.5?int countries_iso2:flags.12?Vector hash:long = Poll; - -pollAnswerVoters#3645230a flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:flags.2?int recent_voters:flags.2?Vector = PollAnswerVoters; - -pollResults#ba7bb15e flags:# min:flags.0?true has_unread_votes:flags.6?true can_view_stats:flags.7?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector solution_media:flags.5?MessageMedia = PollResults; - -chatOnlines#f041e250 onlines:int = ChatOnlines; - -statsURL#47a971e0 url:string = StatsURL; - -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true manage_ranks:flags.18?true = ChatAdminRights; - -chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true edit_rank:flags.26?true send_reactions:flags.27?true until_date:int = ChatBannedRights; - -inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; -inputWallPaperSlug#72091c80 slug:string = InputWallPaper; -inputWallPaperNoFile#967a462e id:long = InputWallPaper; - -account.wallPapersNotModified#1c199183 = account.WallPapers; -account.wallPapers#cdc3858c hash:long wallpapers:Vector = account.WallPapers; - -codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true unknown_number:flags.9?true logout_tokens:flags.6?Vector token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings; - -wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings; - -autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings; - -account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; - -emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector = EmojiKeyword; -emojiKeywordDeleted#236df622 keyword:string emoticons:Vector = EmojiKeyword; - -emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector = EmojiKeywordsDifference; - -emojiURL#a575739d url:string = EmojiURL; - -emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; - -folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; - -inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; - -folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; - -messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; - -urlAuthResultRequest#3cd623ec flags:# request_write_access:flags.0?true request_phone_number:flags.1?true match_codes_first:flags.5?true is_app:flags.6?true bot:User domain:string browser:flags.2?string platform:flags.2?string ip:flags.2?string region:flags.2?string match_codes:flags.3?Vector user_id_hint:flags.4?long verified_app_name:flags.7?string = UrlAuthResult; -urlAuthResultAccepted#623a8fa0 flags:# url:flags.0?string = UrlAuthResult; -urlAuthResultDefault#a9d6db1f = UrlAuthResult; - -channelLocationEmpty#bfb5ad8b = ChannelLocation; -channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation; - -peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated; -peerSelfLocated#f8ec284b expires:int = PeerLocated; - -restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason; - -inputTheme#3c5693e9 id:long access_hash:long = InputTheme; -inputThemeSlug#f5890df1 slug:string = InputTheme; - -theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector emoticon:flags.6?string installs_count:flags.4?int = Theme; - -account.themesNotModified#f41eb622 = account.Themes; -account.themes#9a3d8c6d hash:long themes:Vector = account.Themes; - -auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken; -auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken; -auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken; - -account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings; - -messages.inactiveChats#a927fec5 dates:Vector chats:Vector users:Vector = messages.InactiveChats; - -baseThemeClassic#c3a12462 = BaseTheme; -baseThemeDay#fbd81688 = BaseTheme; -baseThemeNight#b7b31ea8 = BaseTheme; -baseThemeTinted#6d5f77ee = BaseTheme; -baseThemeArctic#5b11125a = BaseTheme; - -inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; - -themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; - -webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; -webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; -webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; -webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; -webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; -webPageAttributeStarGiftAuction#1c641c2 gift:StarGift end_date:int = WebPageAttribute; -webPageAttributeAiComposeTone#7781fe18 emoji_id:long = WebPageAttribute; - -messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; - -bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl; - -payments.bankCardData#3e24e573 title:string open_urls:Vector = payments.BankCardData; - -dialogFilter#aa472651 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector exclude_peers:Vector = DialogFilter; -dialogFilterDefault#363293ae = DialogFilter; -dialogFilterChatlist#96537bd7 flags:# has_my_invites:flags.26?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector = DialogFilter; - -dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested; - -statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays; - -statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev; - -statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue; - -statsGraphAsync#4a27eb2d token:string = StatsGraph; -statsGraphError#bedc9822 error:string = StatsGraph; -statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph; - -stats.broadcastStats#396ca5fc period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev reactions_per_post:StatsAbsValueAndPrev views_per_story:StatsAbsValueAndPrev shares_per_story:StatsAbsValueAndPrev reactions_per_story:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_posts_interactions:Vector = stats.BroadcastStats; - -help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; -help.promoData#8a4d87a flags:# proxy:flags.0?true expires:int peer:flags.3?Peer psa_type:flags.1?string psa_message:flags.2?string pending_suggestions:Vector dismissed_suggestions:Vector custom_pending_suggestion:flags.4?PendingSuggestion chats:Vector users:Vector = help.PromoData; - -videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; -videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector = VideoSize; -videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector = VideoSize; - -statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster; - -statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; - -statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; - -stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; - -globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; - -help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; - -help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector = help.Country; - -help.countriesListNotModified#93cc1f32 = help.CountriesList; -help.countriesList#87d0759e countries:Vector hash:int = help.CountriesList; - -messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews; - -messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; - -messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; - -messageReplyHeader#1b97dd66 flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector quote_offset:flags.10?int todo_item_id:flags.11?int poll_option:flags.12?bytes = MessageReplyHeader; -messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader; - -messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; - -peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; - -stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; - -groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall; - -inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -inputGroupCallSlug#fe06823f slug:string = InputGroupCall; -inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall; - -groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant; - -phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; - -phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; - -inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; -inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; -inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType; -inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType; -inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType; -inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType; - -messages.historyImport#1662af0b id:long = messages.HistoryImport; - -messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed; - -messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector = messages.AffectedFoundMessages; - -chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter; - -messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; - -messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; -messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; - -messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; - -chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites; - -messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; - -messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; - -phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; - -phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; - -groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector = GroupCallParticipantVideoSourceGroup; - -groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector audio_source:flags.1?int = GroupCallParticipantVideo; - -stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName; - -botCommandScopeDefault#2f6cb2ab = BotCommandScope; -botCommandScopeUsers#3c4f04d8 = BotCommandScope; -botCommandScopeChats#6fe1a881 = BotCommandScope; -botCommandScopeChatAdmins#b9aa606a = BotCommandScope; -botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope; -botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope; -botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope; - -account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult; -account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; -account.resetPasswordOk#e926d63e = account.ResetPasswordResult; - -chatTheme#c3dffc04 emoticon:string = ChatTheme; -chatThemeUniqueGift#3458f9c8 gift:StarGift theme_settings:Vector = ChatTheme; - -account.chatThemesNotModified#e011e1c4 = account.ChatThemes; -account.chatThemes#be098173 flags:# hash:long themes:Vector chats:Vector users:Vector next_offset:flags.0?string = account.ChatThemes; - -sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage; - -messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; -messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; - -searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; - -messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector messages:Vector chats:Vector users:Vector = messages.SearchResultsCalendar; - -searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition; - -messages.searchResultsPositions#53b22baf count:int positions:Vector = messages.SearchResultsPositions; - -channels.sendAsPeers#f496b0c6 peers:Vector chats:Vector users:Vector = channels.SendAsPeers; - -users.userFull#3b6d152e full_user:UserFull chats:Vector users:Vector = users.UserFull; - -messages.peerSettings#6880b94d settings:PeerSettings chats:Vector users:Vector = messages.PeerSettings; - -auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut; - -reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; - -messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector recent_reactions:flags.1?Vector top_reactors:flags.4?Vector = MessageReactions; - -messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.MessageReactionsList; - -availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; - -messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions; -messages.availableReactions#768e3aad hash:int reactions:Vector = messages.AvailableReactions; - -messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true my:flags.2?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction; - -groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel; - -phone.groupCallStreamChannels#d0e482b2 channels:Vector = phone.GroupCallStreamChannels; - -phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl; - -attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; - -attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector = AttachMenuBotIcon; - -attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector icons:Vector = AttachMenuBot; - -attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; -attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector = AttachMenuBots; - -attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector = AttachMenuBotsBot; - -webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true fullscreen:flags.2?true query_id:flags.0?long url:string = WebViewResult; - -webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent; - -botMenuButtonDefault#7533a588 = BotMenuButton; -botMenuButtonCommands#4258c205 = BotMenuButton; -botMenuButton#c7b57ce6 text:string url:string = BotMenuButton; - -account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones; -account.savedRingtones#c1e92cc5 hash:long ringtones:Vector = account.SavedRingtones; - -notificationSoundDefault#97e8bebe = NotificationSound; -notificationSoundNone#6f0c34df = NotificationSound; -notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound; -notificationSoundRingtone#ff6c8049 id:long = NotificationSound; - -account.savedRingtone#b7263f6d = account.SavedRingtone; -account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone; - -attachMenuPeerTypeSameBotPM#7d6be90e = AttachMenuPeerType; -attachMenuPeerTypeBotPM#c32bfa1a = AttachMenuPeerType; -attachMenuPeerTypePM#f146d31f = AttachMenuPeerType; -attachMenuPeerTypeChat#509113f = AttachMenuPeerType; -attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; - -inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; -inputInvoiceSlug#c326caef slug:string = InputInvoice; -inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; -inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice; -inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice; -inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; -inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; -inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; -inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; -inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice; -inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice; - -payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; - -messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; - -help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; - -inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose; -inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentPremiumGiftCode#fb790393 flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long message:flags.1?TextWithEntities = InputStorePaymentPurpose; -inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsTopup#f9a2a6cb flags:# stars:long currency:string amount:long spend_purpose_peer:flags.0?InputPeer = InputStorePaymentPurpose; -inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; -inputStorePaymentAuthCode#9bb2636d flags:# restore:flags.0?true phone_number:string phone_code_hash:string currency:string amount:long = InputStorePaymentPurpose; - -paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; - -emojiStatusEmpty#2de11aae = EmojiStatus; -emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus; -emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus; -inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus; - -account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses; -account.emojiStatuses#90c467d1 hash:long statuses:Vector = account.EmojiStatuses; - -reactionEmpty#79f5d419 = Reaction; -reactionEmoji#1b2286b8 emoticon:string = Reaction; -reactionCustomEmoji#8935fc73 document_id:long = Reaction; -reactionPaid#523da4eb = Reaction; - -chatReactionsNone#eafc32bc = ChatReactions; -chatReactionsAll#52928bca flags:# allow_custom:flags.0?true = ChatReactions; -chatReactionsSome#661d4037 reactions:Vector = ChatReactions; - -messages.reactionsNotModified#b06fdbdf = messages.Reactions; -messages.reactions#eafdf716 hash:long reactions:Vector = messages.Reactions; - -emailVerifyPurposeLoginSetup#4345be73 phone_number:string phone_code_hash:string = EmailVerifyPurpose; -emailVerifyPurposeLoginChange#527d22eb = EmailVerifyPurpose; -emailVerifyPurposePassport#bbf51685 = EmailVerifyPurpose; - -emailVerificationCode#922e55a9 code:string = EmailVerification; -emailVerificationGoogle#db909ec2 token:string = EmailVerification; -emailVerificationApple#96d074fd token:string = EmailVerification; - -account.emailVerified#2b96cd1b email:string = account.EmailVerified; -account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified; - -premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption; - -sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer; - -messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia; -messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia; - -stickerKeyword#fcfeb29c document_id:long keyword:Vector = StickerKeyword; - -username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username; - -forumTopicDeleted#23f109b id:int = ForumTopic; -forumTopic#fcdad815 flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true title_missing:flags.7?true id:int date:int peer:Peer title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic; - -messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector messages:Vector chats:Vector users:Vector pts:int = messages.ForumTopics; - -defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL; - -exportedContactToken#41bf109b url:string expires:int = ExportedContactToken; - -requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType; -requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeCreateBot#3e81e078 flags:# bot_managed:flags.0?true suggested_name:flags.1?string suggested_username:flags.2?string = RequestPeerType; - -emojiListNotModified#481eadfa = EmojiList; -emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; - -emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; - -messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; -messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; - -textWithEntities#751f3146 text:string entities:Vector = TextWithEntities; - -messages.translateResult#33db32f8 result:Vector = messages.TranslatedText; - -autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings; - -autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException; - -account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector chats:Vector users:Vector = account.AutoSaveSettings; - -help.appConfigNotModified#7cde641d = help.AppConfig; -help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig; - -inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp; -inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp; - -botAppNotModified#5da674b7 = BotApp; -botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; - -messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp; - -inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; - -readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; - -inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist; - -exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector = ExportedChatlistInvite; - -chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite; - -chatlists.exportedInvites#10ab6dc7 invites:Vector chats:Vector users:Vector = chatlists.ExportedInvites; - -chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector already_peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; -chatlists.chatlistInvite#f10ece2f flags:# title_noanimate:flags.1?true title:TextWithEntities emoticon:flags.0?string peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; - -chatlists.chatlistUpdates#93bd878d missing_peers:Vector chats:Vector users:Vector = chatlists.ChatlistUpdates; - -bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo; - -messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote; -messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote; -messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector date:int = MessagePeerVote; - -storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector reactions_count:flags.4?int recent_viewers:flags.0?Vector = StoryViews; - -storyItemDeleted#51e6ee4f id:int = StoryItem; -storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true live:flags.9?true id:int date:int expire_date:int = StoryItem; -storyItem#16a4b93c flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector music:flags.20?Document = StoryItem; - -stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; -stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; - -stories.stories#63c3dd0a flags:# count:int stories:Vector pinned_to_top:flags.0?Vector chats:Vector users:Vector = stories.Stories; - -storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView; -storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView; -storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView; - -stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryViewsList; - -stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; - -inputReplyToMessage#3bd4b7c2 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int poll_option:flags.7?bytes = InputReplyTo; -inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; -inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; - -exportedStoryLink#3fc9053b link:string = ExportedStoryLink; - -storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; - -mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates; - -mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea; -inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea; -mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea; -mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea; -mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; -inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; -mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; -mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea; -mediaAreaStarGift#5787686d coordinates:MediaAreaCoordinates slug:string = MediaArea; - -peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; - -stories.peerStories#cae68768 stories:PeerStories chats:Vector users:Vector = stories.PeerStories; - -messages.webPage#fd5e12bd webpage:WebPage chats:Vector users:Vector = messages.WebPage; - -premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption; - -payments.checkedGiftCode#eb983f8f flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int days:int used_date:flags.1?int chats:Vector users:Vector = payments.CheckedGiftCode; - -payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; -payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo; - -prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; -prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway; - -boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost; - -premium.boostsList#86f8613c flags:# count:int boosts:Vector next_offset:flags.0?string users:Vector = premium.BoostsList; - -myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost; - -premium.myBoosts#9ae228e2 my_boosts:Vector chats:Vector users:Vector = premium.MyBoosts; - -premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector my_boost_slots:flags.2?Vector = premium.BoostsStatus; - -storyFwdHeader#b826e150 flags:# modified:flags.3?true from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader; - -postInteractionCountersMessage#e7058e7f msg_id:int views:int forwards:int reactions:int = PostInteractionCounters; -postInteractionCountersStory#8a480e27 story_id:int views:int forwards:int reactions:int = PostInteractionCounters; - -stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats; - -publicForwardMessage#1f2bf4a message:Message = PublicForward; -publicForwardStory#edf3add0 peer:Peer story:StoryItem = PublicForward; - -stats.publicForwards#93037e20 flags:# count:int forwards:Vector next_offset:flags.0?string chats:Vector users:Vector = stats.PublicForwards; - -peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor; -peerColorCollectible#b9c0639a flags:# collectible_id:long gift_emoji_id:long background_emoji_id:long accent_color:int colors:Vector dark_accent_color:flags.0?int dark_colors:flags.1?Vector = PeerColor; -inputPeerColorCollectible#b8ea86a9 collectible_id:long = PeerColor; - -help.peerColorSet#26219a58 colors:Vector = help.PeerColorSet; -help.peerColorProfileSet#767d61eb palette_colors:Vector bg_colors:Vector story_colors:Vector = help.PeerColorSet; - -help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption; - -help.peerColorsNotModified#2ba1f5ce = help.PeerColors; -help.peerColors#f8ed08 hash:int colors:Vector = help.PeerColors; - -storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction; -storyReactionPublicForward#bbab2643 message:Message = StoryReaction; -storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; - -stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; - -savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; -monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; - -messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; - -savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; - -messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; -messages.savedReactionTags#3259950a tags:Vector hash:long = messages.SavedReactionTags; - -outboxReadDate#3bb842ac date:int = OutboxReadDate; - -smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin; - -smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status; - -smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob; - -businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen; - -businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector = BusinessWorkHours; - -businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation; - -inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = InputBusinessRecipients; - -businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = BusinessRecipients; - -businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule; - -inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage; - -businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage; - -inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage; - -businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage; - -timezone#ff9289f5 id:string name:string utc_offset:int = Timezone; - -help.timezonesListNotModified#970708cc = help.TimezonesList; -help.timezonesList#7b74ed71 timezones:Vector hash:int = help.TimezonesList; - -quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply; - -inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut; -inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; - -messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; -messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; - -connectedBot#cd64636c flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights = ConnectedBot; - -account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; - -messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector = messages.DialogFilters; - -birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; - -botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; - -inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; - -businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro; - -messages.myStickers#faff629d count:int sets:Vector = messages.MyStickers; - -inputCollectibleUsername#e39460a9 username:string = InputCollectible; -inputCollectiblePhone#a2e214a4 phone:string = InputCollectible; - -fragment.collectibleInfo#6ebdff91 purchase_date:int currency:string amount:long crypto_currency:string crypto_amount:long url:string = fragment.CollectibleInfo; - -inputBusinessBotRecipients#c4e5921e flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = InputBusinessBotRecipients; - -businessBotRecipients#b88cf373 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = BusinessBotRecipients; - -contactBirthday#1d998733 contact_id:long birthday:Birthday = ContactBirthday; - -contacts.contactBirthdays#114ff30d contacts:Vector users:Vector = contacts.ContactBirthdays; - -missingInvitee#628c9224 flags:# premium_would_allow_invite:flags.0?true premium_required_for_pm:flags.1?true user_id:long = MissingInvitee; - -messages.invitedUsers#7f5defa6 updates:Updates missing_invitees:Vector = messages.InvitedUsers; - -inputBusinessChatLink#11679fa7 flags:# message:string entities:flags.0?Vector title:flags.1?string = InputBusinessChatLink; - -businessChatLink#b4ae666f flags:# link:string message:string entities:flags.0?Vector title:flags.1?string views:int = BusinessChatLink; - -account.businessChatLinks#ec43a2d1 links:Vector chats:Vector users:Vector = account.BusinessChatLinks; - -account.resolvedBusinessChatLinks#9a23af21 flags:# peer:Peer message:string entities:flags.0?Vector chats:Vector users:Vector = account.ResolvedBusinessChatLinks; - -requestedPeerUser#d62ff46a flags:# user_id:long first_name:flags.0?string last_name:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChat#7307544f flags:# chat_id:long title:flags.0?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChannel#8ba403e4 flags:# channel_id:long title:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; - -sponsoredMessageReportOption#430d3150 text:string option:bytes = SponsoredMessageReportOption; - -channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:Vector = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; - -reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; -reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; - -reactionsNotifySettings#71e4ea58 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom poll_votes_notify_from:flags.2?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; - -availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; - -messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; -messages.availableEffects#bddb616e hash:int effects:Vector documents:Vector = messages.AvailableEffects; - -factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck; - -starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer; -starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer; -starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; -starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; -starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; -starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; -starsTransactionPeerAds#60682812 = StarsTransactionPeer; -starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; - -starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; - -starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true posts_search:flags.24?true stargift_prepaid_upgrade:flags.25?true stargift_drop_original_details:flags.26?true phonegroup_message:flags.27?true stargift_auction_bid:flags.28?true offer:flags.29?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction; - -payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; - -foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; - -stories.foundStories#e2de7737 flags:# count:int stories:Vector next_offset:flags.0?string chats:Vector users:Vector = stories.FoundStories; - -geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; - -starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; - -payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; - -payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; - -payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl; - -inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; - -starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption; - -bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector = bots.PopularAppBots; - -botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia; - -bots.previewInfo#ca71d64 media:Vector lang_codes:Vector = bots.PreviewInfo; - -starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing; - -starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true bot_canceled:flags.7?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string title:flags.4?string photo:flags.5?WebDocument invoice_slug:flags.6?string = StarsSubscription; - -messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; - -starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; - -starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; - -starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift; -starGiftUnique#85f0a9cd flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true burned:flags.14?true crafted:flags.15?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int craft_chance_permille:flags.16?int = StarGift; - -payments.starGiftsNotModified#a388a368 = payments.StarGifts; -payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; - -messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; - -reportResultChooseOption#f0e4e0b6 title:string options:Vector = ReportResult; -reportResultAddComment#6f09ac31 flags:# optional:flags.0?true option:bytes = ReportResult; -reportResultReported#8db33c4b = ReportResult; - -messages.botPreparedInlineMessage#8ecf0511 id:string expire_date:int = messages.BotPreparedInlineMessage; - -messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult peer_types:Vector cache_time:int users:Vector = messages.PreparedInlineMessage; - -botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings; - -starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram; - -connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef; - -payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector = payments.ConnectedStarRefBots; - -payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; - -starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount; -starsTonAmount#74aee3e0 amount:long = StarsAmount; - -messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers; -messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector = messages.FoundStickers; - -botVerifierSettings#b0cd6617 flags:# can_modify_custom_description:flags.1?true icon:long company:string custom_description:flags.0?string = BotVerifierSettings; - -botVerification#f93cd45c bot_id:long icon:long description:string = BotVerification; - -starGiftAttributeModel#565251e2 flags:# crafted:flags.0?true name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributePattern#4e7085ea name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeBackdrop#9f2504e4 name:string backdrop_id:int center_color:int edge_color:int pattern_color:int text_color:int rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute; - -payments.starGiftUpgradePreview#3de1dfed sample_attributes:Vector prices:Vector next_prices:Vector = payments.StarGiftUpgradePreview; - -users.users#62d706b8 users:Vector = users.Users; -users.usersSlice#315a4974 count:int users:Vector = users.Users; - -payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector users:Vector = payments.UniqueStarGift; - -messages.webPagePreview#8c9a88ac media:MessageMedia chats:Vector users:Vector = messages.WebPagePreview; - -savedStarGift#41df43fc flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int can_craft_at:flags.20?int = SavedStarGift; - -payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; - -inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift; -inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift; -inputSavedStarGiftSlug#2085c238 slug:string = InputSavedStarGift; - -payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl; - -paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy; -paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy; -paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy; - -account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRevenue; - -requirementToContactEmpty#50a9839 = RequirementToContact; -requirementToContactPremium#e581e4e9 = RequirementToContact; -requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; - -businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; - -disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true disallow_stargifts_from_channels:flags.4?true = DisallowedGiftsSettings; - -sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; - -contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; -contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; - -starGiftAttributeIdModel#48aaae3c document_id:long = StarGiftAttributeId; -starGiftAttributeIdPattern#4a162433 document_id:long = StarGiftAttributeId; -starGiftAttributeIdBackdrop#1f01c757 backdrop_id:int = StarGiftAttributeId; - -starGiftAttributeCounter#2eb1b658 attribute:StarGiftAttributeId count:int = StarGiftAttributeCounter; - -payments.resaleStarGifts#947a12df flags:# count:int gifts:Vector next_offset:flags.0?string attributes:flags.1?Vector attributes_hash:flags.1?long chats:Vector counters:flags.2?Vector users:Vector = payments.ResaleStarGifts; - -stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount; - -pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion; - -todoItem#cba9a52f id:int title:TextWithEntities = TodoItem; - -todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector = TodoList; - -todoCompletion#221bb5e4 id:int completed_by:Peer date:int = TodoCompletion; - -suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost; - -starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating; - -starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection; - -payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; -payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; - -storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; - -stories.albumsNotModified#564edaeb = stories.Albums; -stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; - -searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; - -payments.uniqueStarGiftValueInfo#512fe446 flags:# last_sale_on_fragment:flags.1?true value_is_average:flags.6?true currency:string value:long initial_sale_date:int initial_sale_stars:long initial_sale_price:long last_sale_date:flags.0?int last_sale_price:flags.0?long floor_price:flags.2?long average_price:flags.3?long listed_count:flags.4?int fragment_listed_count:flags.5?int fragment_listed_url:flags.5?string = payments.UniqueStarGiftValueInfo; - -profileTabPosts#b98cd696 = ProfileTab; -profileTabGifts#4d4bd46a = ProfileTab; -profileTabMedia#72c64955 = ProfileTab; -profileTabFiles#ab339c00 = ProfileTab; -profileTabMusic#9f27d26e = ProfileTab; -profileTabVoice#e477092e = ProfileTab; -profileTabLinks#d3656499 = ProfileTab; -profileTabGifs#a2c0f695 = ProfileTab; - -users.savedMusicNotModified#e3878aa4 count:int = users.SavedMusic; -users.savedMusic#34a2f297 count:int documents:Vector = users.SavedMusic; - -account.savedMusicIdsNotModified#4fc81d6e = account.SavedMusicIds; -account.savedMusicIds#998d6636 ids:Vector = account.SavedMusicIds; - -payments.checkCanSendGiftResultOk#374fa7ad = payments.CheckCanSendGiftResult; -payments.checkCanSendGiftResultFail#d5e58274 reason:TextWithEntities = payments.CheckCanSendGiftResult; - -inputChatThemeEmpty#83268483 = InputChatTheme; -inputChatTheme#c93de95c emoticon:string = InputChatTheme; -inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme; - -starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice; - -groupCallMessage#1a8afc7e flags:# from_admin:flags.1?true id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage; - -groupCallDonor#ee430c85 flags:# top:flags.0?true my:flags.1?true peer_id:flags.3?Peer stars:long = GroupCallDonor; - -phone.groupCallStars#9d1dbd26 total_stars:long top_donors:Vector chats:Vector users:Vector = phone.GroupCallStars; - -recentStory#711d692d flags:# live:flags.0?true max_id:flags.1?int = RecentStory; - -auctionBidLevel#310240cc pos:int amount:long date:int = AuctionBidLevel; - -starGiftAuctionStateNotModified#fe333952 = StarGiftAuctionState; -starGiftAuctionState#771a4e66 version:int start_date:int end_date:int min_bid_amount:long bid_levels:Vector top_bidders:Vector next_round_at:int last_gift_num:int gifts_left:int current_round:int total_rounds:int rounds:Vector = StarGiftAuctionState; -starGiftAuctionStateFinished#972dabbf flags:# start_date:int end_date:int average_price:long listed_count:flags.0?int fragment_listed_count:flags.1?int fragment_listed_url:flags.1?string = StarGiftAuctionState; - -starGiftAuctionUserState#2eeed1c4 flags:# returned:flags.1?true bid_amount:flags.0?long bid_date:flags.0?int min_bid_amount:flags.0?long bid_peer:flags.0?Peer acquired_count:int = StarGiftAuctionUserState; - -payments.starGiftAuctionState#6b39f4ec gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState timeout:int users:Vector chats:Vector = payments.StarGiftAuctionState; - -starGiftAuctionAcquiredGift#42b00348 flags:# name_hidden:flags.0?true peer:Peer date:int bid_amount:long round:int pos:int message:flags.1?TextWithEntities gift_num:flags.2?int = StarGiftAuctionAcquiredGift; - -payments.starGiftAuctionAcquiredGifts#7d5bd1f0 gifts:Vector users:Vector chats:Vector = payments.StarGiftAuctionAcquiredGifts; - -starGiftActiveAuctionState#d31bc45d gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState = StarGiftActiveAuctionState; - -payments.starGiftActiveAuctionsNotModified#db33dad0 = payments.StarGiftActiveAuctions; -payments.starGiftActiveAuctions#aef6abbc auctions:Vector users:Vector chats:Vector = payments.StarGiftActiveAuctions; - -inputStarGiftAuction#2e16c98 gift_id:long = InputStarGiftAuction; -inputStarGiftAuctionSlug#7ab58308 slug:string = InputStarGiftAuction; - -passkey#98613ebf flags:# id:string name:string date:int software_emoji_id:flags.0?long last_usage_date:flags.1?int = Passkey; - -account.passkeys#f8e0aa1c passkeys:Vector = account.Passkeys; - -account.passkeyRegistrationOptions#e16b5ce1 options:DataJSON = account.PasskeyRegistrationOptions; - -auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions; - -inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse; -inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse; - -inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential; -inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential; - -starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground; - -starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound; -starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound; - -payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector = payments.StarGiftUpgradeAttributes; - -messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome; - -messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo; -messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector plays_left:flags.0?int = messages.EmojiGameInfo; - -starGiftAttributeRarity#36437737 permille:int = StarGiftAttributeRarity; -starGiftAttributeRarityUncommon#dbce6389 = StarGiftAttributeRarity; -starGiftAttributeRarityRare#f08d516b = StarGiftAttributeRarity; -starGiftAttributeRarityEpic#78fbf3a8 = StarGiftAttributeRarity; -starGiftAttributeRarityLegendary#cef7e7a8 = StarGiftAttributeRarity; - -keyboardButtonStyle#4fdd3430 flags:# bg_primary:flags.0?true bg_danger:flags.1?true bg_success:flags.2?true icon:flags.3?long = KeyboardButtonStyle; - -inputMessageReadMetric#402b4495 msg_id:int view_id:long time_in_view_ms:int active_time_in_view_ms:int height_to_viewport_ratio_permille:int seen_range_ratio_permille:int = InputMessageReadMetric; - -bots.exportedBotToken#3c60b621 token:string = bots.ExportedBotToken; - -bots.requestedButton#f13bbcd7 webapp_req_id:string = bots.RequestedButton; - -messages.composedMessageWithAI#90d7adfa flags:# result_text:TextWithEntities diff_text:flags.0?TextWithEntities = messages.ComposedMessageWithAI; - -stats.pollStats#2999beed votes_graph:StatsGraph = stats.PollStats; - -inputAiComposeToneDefault#1fe9a9bf tone:string = InputAiComposeTone; -inputAiComposeToneID#773c080 id:long access_hash:long = InputAiComposeTone; -inputAiComposeToneSlug#1fa01357 slug:string = InputAiComposeTone; - -aiComposeTone#cff63ea9 flags:# creator:flags.0?true id:long access_hash:long slug:string title:string emoji_id:flags.1?long prompt:flags.4?string installs_count:flags.2?int author_id:flags.3?long example_english:flags.5?AiComposeToneExample = AiComposeTone; -aiComposeToneDefault#9bad6414 tone:string emoji_id:long title:string = AiComposeTone; - -aicompose.tonesNotModified#c1f46103 = aicompose.Tones; -aicompose.tones#6c9d0efe hash:long tones:Vector users:Vector = aicompose.Tones; - -aiComposeToneExample#f1d628ec from:TextWithEntities to:TextWithEntities = AiComposeToneExample; - -bots.accessSettings#dd1fbf93 flags:# restricted:flags.0?true add_users:flags.1?Vector = bots.AccessSettings; - ----functions--- - -invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; -invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; -initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; -invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; -invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; -invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; -invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; -invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; -invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; -invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X; -invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X; - -auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; -auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; -auth.signIn#8d52a951 flags:# phone_number:string phone_code_hash:string phone_code:flags.0?string email_verification:flags.1?EmailVerification = auth.Authorization; -auth.logOut#3e72ba19 = auth.LoggedOut; -auth.resetAuthorizations#9fab0d1a = Bool; -auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; -auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; -auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; -auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; -auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; -auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; -auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; -auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode; -auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; -auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; -auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; -auth.acceptLoginToken#e894ad4d token:bytes = Authorization; -auth.checkRecoveryPassword#d36bf79 code:string = Bool; -auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; -auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool; -auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; -auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; -auth.checkPaidAuth#56e59f9c phone_number:string phone_code_hash:string form_id:long = auth.SentCode; -auth.initPasskeyLogin#518ad0b7 api_id:int api_hash:string = auth.PasskeyLoginOptions; -auth.finishPasskeyLogin#9857ad07 flags:# credential:InputPasskeyCredential from_dc_id:flags.0?int from_auth_key_id:flags.0?long = auth.Authorization; - -account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; -account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; -account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; -account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; -account.resetNotifySettings#db7e1747 = Bool; -account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; -account.updateStatus#6628562c offline:Bool = Bool; -account.getWallPapers#7967d36 hash:long = account.WallPapers; -account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool; -account.checkUsername#2714d86c username:string = Bool; -account.updateUsername#3e0bdd7c username:string = User; -account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; -account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; -account.deleteAccount#a2c0cf74 flags:# reason:string password:flags.0?InputCheckPasswordSRP = Bool; -account.getAccountTTL#8fc711d = AccountDaysTTL; -account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; -account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; -account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; -account.updateDeviceLocked#38df3532 period:int = Bool; -account.getAuthorizations#e320c158 = account.Authorizations; -account.resetAuthorization#df77f3bc hash:long = Bool; -account.getPassword#548a30f5 = account.Password; -account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; -account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; -account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; -account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; -account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; -account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; -account.resetWebAuthorization#2d01b9ef hash:long = Bool; -account.resetWebAuthorizations#682d2594 = Bool; -account.getAllSecureValues#b288bc7d = Vector; -account.getSecureValue#73665bc2 types:Vector = Vector; -account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; -account.deleteSecureValue#b880bc4b types:Vector = Bool; -account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm; -account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; -account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; -account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; -account.sendVerifyEmailCode#98e037bb purpose:EmailVerifyPurpose email:string = account.SentEmailCode; -account.verifyEmail#32da4cf purpose:EmailVerifyPurpose verification:EmailVerification = account.EmailVerified; -account.initTakeoutSession#8ef3eab0 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?long = account.Takeout; -account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; -account.confirmPasswordEmail#8fdf1920 code:string = Bool; -account.resendPasswordEmail#7a7f2a15 = Bool; -account.cancelPasswordEmail#c1cbd5b6 = Bool; -account.getContactSignUpNotification#9f07c728 = Bool; -account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; -account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true compare_stories:flags.2?true peer:flags.0?InputNotifyPeer = Updates; -account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; -account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; -account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; -account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; -account.resetWallPapers#bb3b9804 = Bool; -account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; -account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; -account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document; -account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool; -account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool; -account.getTheme#3a5869ec format:string theme:InputTheme = Theme; -account.getThemes#7206e458 format:string hash:long = account.Themes; -account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool; -account.getContentSettings#8b9b4dae = account.ContentSettings; -account.getMultiWallPapers#65ad71dc wallpapers:Vector = Vector; -account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings; -account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; -account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; -account.resetPassword#9308ce1b = account.ResetPasswordResult; -account.declinePasswordReset#4c9409f6 = Bool; -account.getChatThemes#d638de89 hash:long = account.Themes; -account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; -account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; -account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones; -account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone; -account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document; -account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool; -account.getDefaultEmojiStatuses#d6753386 hash:long = account.EmojiStatuses; -account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; -account.clearRecentEmojiStatuses#18201aae = Bool; -account.reorderUsernames#ef500eab order:Vector = Bool; -account.toggleUsername#58d6b376 username:string active:Bool = Bool; -account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList; -account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList; -account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings; -account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool; -account.deleteAutoSaveExceptions#53bc0020 = Bool; -account.invalidateSignInCodes#ca8ae8ba codes:Vector = Bool; -account.updateColor#684d214e flags:# for_profile:flags.1?true color:flags.2?PeerColor = Bool; -account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList; -account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses; -account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList; -account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool; -account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool; -account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool; -account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool; -account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates; -account.getConnectedBots#4ea4c80f = account.ConnectedBots; -account.getBotBusinessConnection#76a86270 connection_id:string = Updates; -account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool; -account.toggleConnectedBotPaused#646e1097 peer:InputPeer paused:Bool = Bool; -account.disablePeerConnectedBot#5e437ed9 peer:InputPeer = Bool; -account.updateBirthday#cc6e0c11 flags:# birthday:flags.0?Birthday = Bool; -account.createBusinessChatLink#8851e68e link:InputBusinessChatLink = BusinessChatLink; -account.editBusinessChatLink#8c3410af slug:string link:InputBusinessChatLink = BusinessChatLink; -account.deleteBusinessChatLink#60073674 slug:string = Bool; -account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks; -account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks; -account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool; -account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool; -account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings; -account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings; -account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses; -account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue; -account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool; -account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool; -account.saveMusic#b26732a9 flags:# unsave:flags.0?true id:InputDocument after_id:flags.1?InputDocument = Bool; -account.getSavedMusicIds#e09d5faf hash:long = account.SavedMusicIds; -account.getUniqueGiftChatThemes#e42ce9c9 offset:string limit:int hash:long = account.ChatThemes; -account.initPasskeyRegistration#429547e8 = account.PasskeyRegistrationOptions; -account.registerPasskey#55b41fd6 credential:InputPasskeyCredential = Passkey; -account.getPasskeys#ea1f0c52 = account.Passkeys; -account.deletePasskey#f5b5563f id:string = Bool; - -users.getUsers#d91a548 id:Vector = Vector; -users.getFullUser#b60f5918 id:InputUser = users.UserFull; -users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; -users.getRequirementsToContact#d89a83a3 id:Vector = Vector; -users.getSavedMusic#788d7fe3 id:InputUser offset:int limit:int hash:long = users.SavedMusic; -users.getSavedMusicByID#7573a4e9 id:InputUser documents:Vector = users.SavedMusic; -users.suggestBirthday#fc533372 id:InputUser birthday:Birthday = Updates; - -contacts.getContactIDs#7adc669d hash:long = Vector; -contacts.getStatuses#c4a353ee = Vector; -contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; -contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; -contacts.deleteContacts#96a0e00 id:Vector = Updates; -contacts.deleteByPhones#1013fd9e phones:Vector = Bool; -contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; -contacts.search#11f812d8 q:string limit:int = contacts.Found; -contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer; -contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true offset:int limit:int hash:long = contacts.TopPeers; -contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; -contacts.resetSaved#879537f1 = Bool; -contacts.getSaved#82f1e39f = Vector; -contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; -contacts.addContact#d9ba2e54 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string note:flags.1?TextWithEntities = Updates; -contacts.acceptContact#f831a20f id:InputUser = Updates; -contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates; -contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates; -contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer; -contacts.exportContactToken#f8654027 = ExportedContactToken; -contacts.importContactToken#13005788 token:string = User; -contacts.editCloseFriends#ba6705f0 id:Vector = Bool; -contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector limit:int = Bool; -contacts.getBirthdays#daeda864 = contacts.ContactBirthdays; -contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers; -contacts.updateContactNote#139f63fb id:InputUser note:TextWithEntities = Bool; - -messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; -messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; -messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; -messages.receivedMessages#5a954c0 max_id:int = Vector; -messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; -messages.sendMessage#545cd15a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.sendMedia#330e77f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.forwardMessages#13704a7c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; -messages.reportSpam#cf1592db peer:InputPeer = Bool; -messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; -messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; -messages.getChats#49e9528f id:Vector = messages.Chats; -messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; -messages.editChatTitle#73783ffd chat_id:long title:string = Updates; -messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates; -messages.addChatUser#cbc6d107 chat_id:long user_id:InputUser fwd_limit:int = messages.InvitedUsers; -messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates; -messages.createChat#92ceddd4 flags:# users:Vector title:string ttl_period:flags.0?int = messages.InvitedUsers; -messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; -messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; -messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; -messages.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool; -messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; -messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; -messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; -messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.receivedQueue#55a5bb66 max_qts:int = Vector; -messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; -messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; -messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers; -messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers; -messages.getWebPagePreview#570d6f6f flags:# message:string entities:flags.3?Vector = messages.WebPagePreview; -messages.exportChatInvite#a455de90 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string subscription_pricing:flags.5?StarsSubscriptionPricing = ExportedChatInvite; -messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; -messages.importChatInvite#6c50051c hash:string = Updates; -messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet; -messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; -messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; -messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; -messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool = messages.MessageViews; -messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; -messages.migrateChat#a2875319 chat_id:long = Updates; -messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true groups_only:flags.2?true users_only:flags.3?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; -messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Bool; -messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document; -messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; -messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; -messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; -messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool; -messages.sendInlineBotResult#c0cf7646 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut allow_paid_stars:flags.21?long = Updates; -messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; -messages.editMessage#51e842e1 flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.15?int schedule_repeat_period:flags.18?int quick_reply_shortcut_id:flags.17?int = Updates; -messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; -messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; -messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; -messages.saveDraft#54ae308e flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost = Bool; -messages.getAllDrafts#6a3f8d65 = Updates; -messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; -messages.readFeaturedStickers#5b118126 id:Vector = Bool; -messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; -messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; -messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; -messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers; -messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; -messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; -messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; -messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; -messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; -messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; -messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats; -messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage; -messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; -messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; -messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; -messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; -messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia; -messages.sendScreenshotNotification#a1405817 peer:InputPeer reply_to:InputReplyTo random_id:long = Updates; -messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers; -messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; -messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; -messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; -messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSplitRanges#1cff7e08 = Vector; -messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool; -messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector; -messages.clearAllDrafts#7e58ee9c = Bool; -messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates; -messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; -messages.getPollResults#eda3e33b peer:InputPeer msg_id:int poll_hash:long = Updates; -messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; -messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; -messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; -messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; -messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; -messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; -messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; -messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector = Vector; -messages.requestUrlAuth#894cc99c flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string in_app_origin:flags.3?string = UrlAuthResult; -messages.acceptUrlAuth#67a3f0de flags:# write_allowed:flags.0?true share_phone_number:flags.3?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string match_code:flags.4?string = UrlAuthResult; -messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; -messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages; -messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; -messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector = Updates; -messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector = Updates; -messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList; -messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector = Bool; -messages.getDialogFilters#efd48c89 = messages.DialogFilters; -messages.getSuggestedDialogFilters#a29cd42c = Vector; -messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool; -messages.updateDialogFiltersOrder#c563c1e4 order:Vector = Bool; -messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers; -messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; -messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; -messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.deleteChat#5bd0ee50 chat_id:long = Bool; -messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; -messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; -messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport; -messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; -messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; -messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; -messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; -messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite; -messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; -messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; -messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; -messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true subscription_expired:flags.3?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; -messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; -messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; -messages.setChatTheme#81202c9 peer:InputPeer theme:InputChatTheme = Updates; -messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector; -messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; -messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; -messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; -messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; -messages.toggleNoForwards#b2081a35 flags:# peer:InputPeer enabled:Bool request_msg_id:flags.0?int = Updates; -messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; -messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector = Updates; -messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector = Updates; -messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList; -messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int paid_enabled:flags.1?Bool = Updates; -messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; -messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool; -messages.translateText#a5eec345 flags:# peer:flags.0?InputPeer id:flags.0?Vector text:flags.1?Vector to_lang:string tone:flags.2?string = messages.TranslatedText; -messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages; -messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; -messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; -messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; -messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; -messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; -messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true fullscreen:flags.8?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; -messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; -messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; -messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool; -messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector = Vector; -messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers; -messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers; -messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer = Bool; -messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions; -messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions; -messages.clearRecentReactions#9dfeefb4 = Bool; -messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector = Updates; -messages.setDefaultHistoryTTL#9eb51445 period:int = Bool; -messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL; -messages.sendBotRequestedPeer#6c5cf2a7 flags:# peer:InputPeer msg_id:flags.0?int webapp_req_id:flags.1?string button_id:int requested_peers:Vector = Updates; -messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups; -messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups; -messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups; -messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; -messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; -messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; -messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; -messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; -messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; -messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; -messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; -messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags; -messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; -messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; -messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate; -messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies; -messages.reorderQuickReplies#60331907 order:Vector = Bool; -messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool; -messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool; -messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool; -messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector hash:long = messages.Messages; -messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vector random_id:Vector = Updates; -messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; -messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; -messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; -messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; -messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; -messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; -messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; -messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; -messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates; -messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool; -messages.getPaidReactionPrivacy#472455aa = Updates; -messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; -messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; -messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; -messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages; -messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; -messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; -messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; -messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; -messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; -messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; -messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; -messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; -messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates; -messages.getForumTopics#3ba47bff flags:# peer:InputPeer q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; -messages.getForumTopicsByID#af0a4a08 peer:InputPeer topics:Vector = messages.ForumTopics; -messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates; -messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates; -messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector = Updates; -messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; -messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory; -messages.getEmojiGameInfo#fb7e8ca7 = messages.EmojiGameInfo; -messages.summarizeText#abbbd346 flags:# peer:InputPeer id:int to_lang:flags.0?string tone:flags.2?string = TextWithEntities; -messages.editChatCreator#f743b857 peer:InputPeer user_id:InputUser password:InputCheckPasswordSRP = Updates; -messages.getFutureChatCreatorAfterLeave#3b7d0ea6 peer:InputPeer = User; -messages.editChatParticipantRank#a00f32b0 peer:InputPeer participant:InputPeer rank:string = Updates; -messages.declineUrlAuth#35436bbc url:string = Bool; -messages.checkUrlAuthMatchCode#c9a47b0b url:string match_code:string = Bool; -messages.composeMessageWithAI#daecc589 flags:# proofread:flags.0?true emojify:flags.3?true text:TextWithEntities translate_to_lang:flags.1?string tone:flags.2?InputAiComposeTone = messages.ComposedMessageWithAI; -messages.reportReadMetrics#4067c5e6 peer:InputPeer metrics:Vector = Bool; -messages.reportMusicListen#ddbcd819 id:InputDocument listened_duration:int = Bool; -messages.addPollAnswer#19bc4b6d peer:InputPeer msg_id:int answer:PollAnswer = Updates; -messages.deletePollAnswer#ac8505a5 peer:InputPeer msg_id:int option:bytes = Updates; -messages.getUnreadPollVotes#43286cf2 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readPollVotes#1720b4d8 flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.setBotGuestChatResult#52b08db query_id:long result:InputBotInlineResult = Bool; -messages.deleteParticipantReactions#a0b80cf8 peer:InputPeer participant:InputPeer = Bool; -messages.deleteParticipantReaction#e3b7f82c peer:InputPeer msg_id:int participant:InputPeer = Updates; - -updates.getState#edd4882a = updates.State; -updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; -updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; - -photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo; -photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo; -photos.deletePhotos#87cf7f2f id:Vector = Vector; -photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; -photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo; - -upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; -upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File; -upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; -upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; -upload.getCdnFile#395f69da file_token:bytes offset:long limit:int = upload.CdnFile; -upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; -upload.getCdnFileHashes#91dc3f31 file_token:bytes offset:long = Vector; -upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector; - -help.getConfig#c4f9186b = Config; -help.getNearestDc#1fb33026 = NearestDc; -help.getAppUpdate#522d5a7d source:string = help.AppUpdate; -help.getInviteText#4d392343 = help.InviteText; -help.getSupport#9cdf08cd = help.Support; -help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; -help.getCdnConfig#52029342 = CdnConfig; -help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; -help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; -help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; -help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; -help.getAppConfig#61e3f854 hash:int = help.AppConfig; -help.saveAppLog#6f02f748 events:Vector = Bool; -help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; -help.getSupportName#d360e72c = help.SupportName; -help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; -help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; -help.getPromoData#c0977421 = help.PromoData; -help.hidePromoData#1e251c95 peer:InputPeer = Bool; -help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; -help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; -help.getPremiumPromo#b81b93d4 = help.PremiumPromo; -help.getPeerColors#da80f42f hash:int = help.PeerColors; -help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors; -help.getTimezonesList#49b30240 hash:int = help.TimezonesList; - -channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; -channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; -channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector = Bool; -channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; -channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; -channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; -channels.getChannels#a7f6bbb id:Vector = messages.Chats; -channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; -channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates; -channels.editAdmin#9a98ad68 flags:# channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:flags.0?string = Updates; -channels.editTitle#566decd0 channel:InputChannel title:string = Updates; -channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; -channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; -channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; -channels.joinChannel#24b524c5 channel:InputChannel = Updates; -channels.leaveChannel#f836aa95 channel:InputChannel = Updates; -channels.inviteToChannel#c9e33d54 channel:InputChannel users:Vector = messages.InvitedUsers; -channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; -channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; -channels.toggleSignatures#418d549c flags:# signatures_enabled:flags.0?true profiles_enabled:flags.1?true channel:InputChannel = Updates; -channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_personal:flags.2?true = messages.Chats; -channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; -channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; -channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; -channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates; -channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; -channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; -channels.getGroupsForDiscussion#f5dad378 = messages.Chats; -channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; -channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; -channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; -channels.getInactiveChannels#11e831ee = messages.InactiveChats; -channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; -channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true for_live_stories:flags.1?true peer:InputPeer = channels.SendAsPeers; -channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory; -channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates; -channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates; -channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector = Bool; -channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool; -channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool; -channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates; -channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates; -channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool; -channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; -channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates; -channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; -channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats; -channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates; -channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates; -channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; -channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; -channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; -channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; -channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; -channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood; -channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool; - -bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; -bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; -bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector = Bool; -bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool; -bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector; -bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool; -bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton; -bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool; -bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool; -bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool; -bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo; -bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector = Bool; -bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool; -bots.canSendMessage#1359f4e6 bot:InputUser = Bool; -bots.allowSendMessage#f132e3ef bot:InputUser = Updates; -bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; -bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; -bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia; -bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia; -bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector = Bool; -bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector = Bool; -bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo; -bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; -bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool; -bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; -bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; -bots.getAdminedBots#b0711d83 = Vector; -bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram; -bots.setCustomVerification#8b89dfbd flags:# enabled:flags.1?true bot:flags.0?InputUser peer:InputPeer custom_description:flags.2?string = Bool; -bots.getBotRecommendations#a1b70815 bot:InputUser = users.Users; -bots.checkUsername#87f2219b username:string = Bool; -bots.createBot#e5b17f2b flags:# via_deeplink:flags.0?true name:string username:string manager_id:InputUser = User; -bots.exportBotToken#bd0d99eb bot:InputUser revoke:Bool = bots.ExportedBotToken; -bots.requestWebViewButton#31a2a35e user_id:InputUser button:KeyboardButton = bots.RequestedButton; -bots.getRequestedWebViewButton#bf25b7f3 bot:InputUser webapp_req_id:string = KeyboardButton; -bots.getAccessSettings#213853a3 bot:InputUser = bots.AccessSettings; -bots.editAccessSettings#31813cd8 flags:# restricted:flags.0?true bot:InputUser add_users:flags.1?Vector = Bool; - -payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; -payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; -payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; -payments.sendPaymentForm#2d03522f flags:# form_id:long invoice:InputInvoice requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; -payments.getSavedInfo#227d824b = payments.SavedInfo; -payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; -payments.getBankCardData#2e79d779 number:string = payments.BankCardData; -payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; -payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; -payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; -payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector; -payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; -payments.applyGiftCode#f6e26854 slug:string = Updates; -payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; -payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; -payments.getStarsTopupOptions#c00ec7d3 = Vector; -payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus; -payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; -payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult; -payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; -payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats; -payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; -payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; -payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector = payments.StarsStatus; -payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; -payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; -payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; -payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; -payments.getStarsGiveawayOptions#bd1efd3e = Vector; -payments.getStarGifts#c4563590 hash:int = payments.StarGifts; -payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool; -payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool; -payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; -payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; -payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots; -payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; -payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview; -payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates; -payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates; -payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift; -payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_unique:flags.4?true sort_by_value:flags.5?true exclude_upgradable:flags.7?true exclude_unupgradable:flags.8?true peer_color_available:flags.9?true exclude_hosted:flags.10?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts; -payments.getSavedStarGift#b455a106 stargift:Vector = payments.SavedStarGifts; -payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; -payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; -payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; -payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; -payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true for_craft:flags.4?true stars_only:flags.5?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; -payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; -payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; -payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; -payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector = Bool; -payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool; -payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections; -payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo; -payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult; -payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState; -payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts; -payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions; -payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates; -payments.sendStarGiftOffer#8fb86b41 flags:# peer:InputPeer slug:string price:StarsAmount duration:int random_id:long allow_paid_stars:flags.0?long = Updates; -payments.getStarGiftUpgradeAttributes#6d038b58 gift_id:long = payments.StarGiftUpgradeAttributes; -payments.getCraftStarGifts#fd05dd00 gift_id:long offset:string limit:int = payments.SavedStarGifts; -payments.craftStarGift#b0f9684f stargift:Vector = Updates; - -stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; -stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; -stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; -stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; -stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet; -stickers.checkShortName#284b3639 short_name:string = Bool; -stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName; -stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet; -stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet; -stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool; -stickers.replaceSticker#4696459a sticker:InputDocument new_sticker:InputStickerSetItem = messages.StickerSet; - -phone.getCallConfig#55451fa9 = DataJSON; -phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; -phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; -phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; -phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; -phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; -phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; -phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; -phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates; -phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; -phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; -phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; -phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates; -phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; -phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; -phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; -phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; -phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; -phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; -phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; -phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; -phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; -phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; -phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; -phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates; -phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates; -phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels; -phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl; -phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool; -phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates; -phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector block:bytes = Updates; -phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates; -phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates; -phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates; -phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates; -phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates; -phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool; -phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector = Updates; -phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates; -phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars; -phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool; - -langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; -langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; -langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; -langpack.getLanguages#42c6978f lang_pack:string = Vector; -langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; - -folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; - -stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats; -stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; -stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; -stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards; -stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; -stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; -stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards; -stats.getPollStats#c27dfa68 flags:# dark:flags.0?true peer:InputPeer msg_id:int = stats.PollStats; - -chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; -chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; -chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector = ExportedChatlistInvite; -chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites; -chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite; -chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector = Updates; -chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates; -chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector = Updates; -chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool; -chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector; -chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector = Updates; - -stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount; -stories.sendStory#8f9e6898 flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector music:flags.9?InputDocument = Updates; -stories.editStory#2c63a72b flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector music:flags.4?InputDocument = Updates; -stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; -stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; -stories.getAllStories#eeb0d625 flags:# next:flags.1?true hidden:flags.2?true state:flags.0?string = stories.AllStories; -stories.getPinnedStories#5821a5dc peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector = stories.Stories; -stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool; -stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector; -stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector = Bool; -stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList; -stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector = stories.StoryViews; -stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; -stories.report#19d8eb45 peer:InputPeer id:Vector option:bytes message:string = ReportResult; -stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates; -stories.sendReaction#7fd736b2 flags:# add_to_recent:flags.0?true peer:InputPeer story_id:int reaction:Reaction = Updates; -stories.getPeerStories#2c4ada50 peer:InputPeer = stories.PeerStories; -stories.getAllReadPeerStories#9b5ae7f9 = Updates; -stories.getPeerMaxIDs#78499170 id:Vector = Vector; -stories.getChatsToSend#a56a8b60 = messages.Chats; -stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; -stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; -stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; -stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories; -stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector = StoryAlbum; -stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector add_stories:flags.2?Vector order:flags.3?Vector = StoryAlbum; -stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector = Bool; -stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool; -stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums; -stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories; -stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates; - -premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; -premium.getMyBoosts#be77b4a = premium.MyBoosts; -premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; -premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; -premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; - -smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin; -smsjobs.join#a74ece2d = Bool; -smsjobs.leave#9898ad73 = Bool; -smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool; -smsjobs.getStatus#10a698e8 = smsjobs.Status; -smsjobs.getSmsJob#778d902f job_id:string = SmsJob; -smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; - -fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; - -aicompose.createTone#4aa83913 flags:# display_author:flags.0?true emoji_id:long title:string prompt:string = AiComposeTone; -aicompose.updateTone#903bcf59 flags:# tone:InputAiComposeTone display_author:flags.0?Bool emoji_id:flags.1?long title:flags.2?string prompt:flags.3?string = AiComposeTone; -aicompose.saveTone#1782cbb1 tone:InputAiComposeTone unsave:Bool = Bool; -aicompose.deleteTone#dd39316a tone:InputAiComposeTone = Bool; -aicompose.getTone#b2e8ba03 tone:InputAiComposeTone = aicompose.Tones; -aicompose.getTones#abd59201 hash:long = aicompose.Tones; -aicompose.getToneExample#d1b4ab14 tone:InputAiComposeTone num:int = AiComposeToneExample; - -// LAYER 225 diff --git a/internal/compat/layerwire/_schema/layer-226.tl b/internal/compat/layerwire/_schema/layer-226.tl deleted file mode 100644 index f2f907c7..00000000 --- a/internal/compat/layerwire/_schema/layer-226.tl +++ /dev/null @@ -1,3002 +0,0 @@ -boolFalse#bc799737 = Bool; -boolTrue#997275b5 = Bool; - -true#3fedd339 = True; - -vector#1cb5c415 {t:Type} # [ t ] = Vector t; - -error#c4b9f9bb code:int text:string = Error; - -null#56730bcc = Null; - -inputPeerEmpty#7f3b18ea = InputPeer; -inputPeerSelf#7da07ec9 = InputPeer; -inputPeerChat#35a95cb9 chat_id:long = InputPeer; -inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; -inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer; -inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer; -inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer; - -inputUserEmpty#b98886cf = InputUser; -inputUserSelf#f7c1b13f = InputUser; -inputUser#f21158c6 user_id:long access_hash:long = InputUser; -inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser; - -inputPhoneContact#6a1dc4be flags:# client_id:long phone:string first_name:string last_name:string note:flags.0?TextWithEntities = InputContact; - -inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; -inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; -inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile; - -inputMediaEmpty#9664f57f = InputMedia; -inputMediaUploadedPhoto#7d8375da flags:# spoiler:flags.2?true live_photo:flags.3?true file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int video:flags.3?InputDocument = InputMedia; -inputMediaPhoto#e3af4434 flags:# spoiler:flags.1?true live_photo:flags.2?true id:InputPhoto ttl_seconds:flags.0?int video:flags.2?InputDocument = InputMedia; -inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; -inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; -inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; -inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; -inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; -inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; -inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; -inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; -inputMediaPoll#883a4108 flags:# poll:Poll correct_answers:flags.0?Vector attached_media:flags.3?InputMedia solution:flags.1?string solution_entities:flags.1?Vector solution_media:flags.2?InputMedia = InputMedia; -inputMediaDice#e66fbf7b emoticon:string = InputMedia; -inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; -inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; -inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; -inputMediaTodo#9fc55fde todo:TodoList = InputMedia; -inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia; - -inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; -inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; -inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; - -inputGeoPointEmpty#e4c123d6 = InputGeoPoint; -inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint; - -inputPhotoEmpty#1cd7bf0d = InputPhoto; -inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; - -inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; -inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; -inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; -inputTakeoutFileLocation#29be5899 = InputFileLocation; -inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; -inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; -inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; -inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; - -peerUser#59511722 user_id:long = Peer; -peerChat#36c6019a chat_id:long = Peer; -peerChannel#a2a5371e channel_id:long = Peer; - -storage.fileUnknown#aa963b05 = storage.FileType; -storage.filePartial#40bc6f52 = storage.FileType; -storage.fileJpeg#7efe0e = storage.FileType; -storage.fileGif#cae1aadf = storage.FileType; -storage.filePng#a4f63c0 = storage.FileType; -storage.filePdf#ae1e508d = storage.FileType; -storage.fileMp3#528a0677 = storage.FileType; -storage.fileMov#4b09ebbc = storage.FileType; -storage.fileMp4#b3cea0e4 = storage.FileType; -storage.fileWebp#1081464c = storage.FileType; - -userEmpty#d3bc4b7a id:long = User; -user#31774388 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true bot_business:flags2.11?true bot_has_main_app:flags2.13?true bot_forum_view:flags2.16?true bot_forum_can_manage_topics:flags2.17?true bot_can_manage_bots:flags2.18?true bot_guestchat:flags2.19?true bot_guard:flags2.20?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?RecentStory color:flags2.8?PeerColor profile_color:flags2.9?PeerColor bot_active_users:flags2.12?int bot_verification_icon:flags2.14?long send_paid_messages_stars:flags2.15?long = User; - -userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; - -userStatusEmpty#9d05049 = UserStatus; -userStatusOnline#edb93949 expires:int = UserStatus; -userStatusOffline#8c703f was_online:int = UserStatus; -userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus; -userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus; -userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; - -chatEmpty#29562865 id:long = Chat; -chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; -chatForbidden#6592a1a7 id:long title:string = Chat; -channel#1c32b11c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?RecentStory color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat; -channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true monoforum:flags.10?true id:long access_hash:long title:string until_date:flags.16?int = Chat; - -chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#a04e8d3a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab guard_bot_id:flags2.23?long = ChatFull; - -chatParticipant#38e79fde flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; -chatParticipantCreator#e1f867b8 flags:# user_id:long rank:flags.0?string = ChatParticipant; -chatParticipantAdmin#360d5d2 flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; - -chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants; -chatParticipants#3cbc93f8 chat_id:long participants:Vector version:int = ChatParticipants; - -chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; - -messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; -message#95ef6f2b flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int from_rank:flags2.12?string peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long guestchat_via_from:flags2.19?Peer reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string = Message; -messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; - -messageMediaEmpty#3ded6320 = MessageMedia; -messageMediaPhoto#e216eb63 flags:# spoiler:flags.3?true live_photo:flags.4?true photo:flags.0?Photo ttl_seconds:flags.2?int video:flags.4?Document = MessageMedia; -messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; -messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; -messageMediaUnsupported#9f84f49e = MessageMedia; -messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; -messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; -messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; -messageMediaGame#fdb19008 game:Game = MessageMedia; -messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia; -messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia; -messageMediaPoll#773f4e66 flags:# poll:Poll results:PollResults attached_media:flags.0?MessageMedia = MessageMedia; -messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia; -messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; -messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; -messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; -messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; -messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector = MessageMedia; -messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia; - -messageActionEmpty#b6aef7b0 = MessageAction; -messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; -messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; -messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; -messageActionChatDeletePhoto#95e3fbef = MessageAction; -messageActionChatAddUser#15cefd00 users:Vector = MessageAction; -messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction; -messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction; -messageActionChannelCreate#95d2ac92 title:string = MessageAction; -messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction; -messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction; -messageActionPinMessage#94bd38ed = MessageAction; -messageActionHistoryClear#9fbab604 = MessageAction; -messageActionGameScore#92a72876 game_id:long score:int = MessageAction; -messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction; -messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction; -messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; -messageActionScreenshotTaken#4792929b = MessageAction; -messageActionCustomAction#fae69f56 message:string = MessageAction; -messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction; -messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; -messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; -messageActionContactSignUp#f3f25f76 = MessageAction; -messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction; -messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; -messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector = MessageAction; -messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction; -messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; -messageActionSetChatTheme#b91bbd3a theme:ChatTheme = MessageAction; -messageActionChatJoinedByRequest#ebbca3cb = MessageAction; -messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction; -messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction; -messageActionGiftPremium#48e91302 flags:# currency:string amount:long days:int crypto_currency:flags.0?string crypto_amount:flags.0?long message:flags.1?TextWithEntities = MessageAction; -messageActionTopicCreate#d999256 flags:# title_missing:flags.1?true title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction; -messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction; -messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; -messageActionRequestedPeer#31518e9b button_id:int peers:Vector = MessageAction; -messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; -messageActionGiftCode#31c48347 flags:# via_giveaway:flags.0?true unclaimed:flags.5?true boost_peer:flags.1?Peer days:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long message:flags.4?TextWithEntities = MessageAction; -messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction; -messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction; -messageActionBoostApply#cc02aa6d boosts:int = MessageAction; -messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; -messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; -messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; -messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; -messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction; -messageActionStarGiftUnique#e6c31522 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true craft:flags.16?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long can_craft_at:flags.15?int = MessageAction; -messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; -messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; -messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; -messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; -messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; -messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction; -messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction; -messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction; -messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction; -messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction; -messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction; -messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction; -messageActionNewCreatorPending#b07ed085 new_creator_id:long = MessageAction; -messageActionChangeCreator#e188503b new_creator_id:long = MessageAction; -messageActionNoForwardsToggle#bf7d6572 prev_value:Bool new_value:Bool = MessageAction; -messageActionNoForwardsRequest#3e2793ba flags:# expired:flags.0?true prev_value:Bool new_value:Bool = MessageAction; -messageActionPollAppendAnswer#9da1cd6c answer:PollAnswer = MessageAction; -messageActionPollDeleteAnswer#399674dc answer:PollAnswer = MessageAction; -messageActionManagedBotCreated#16605e3e bot_id:long = MessageAction; - -dialog#fc89f7f3 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; -dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; - -photoEmpty#2331b22d id:long = Photo; -photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = Photo; - -photoSizeEmpty#e17e23c type:string = PhotoSize; -photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; -photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; -photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; -photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; -photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; - -geoPointEmpty#1117dd5f = GeoPoint; -geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; - -auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; -auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; -auth.sentCodePaymentRequired#f8827ebf store_product:string phone_code_hash:string support_email_address:string support_email_subject:string premium_days:int currency:string amount:long = auth.SentCode; - -auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; -auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; - -auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; - -inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; -inputNotifyUsers#193b4417 = InputNotifyPeer; -inputNotifyChats#4a95e84e = InputNotifyPeer; -inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; -inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer; - -inputPeerNotifySettings#cacb6ae2 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_sound:flags.8?NotificationSound = InputPeerNotifySettings; - -peerNotifySettings#99622c0c flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_ios_sound:flags.8?NotificationSound stories_android_sound:flags.9?NotificationSound stories_other_sound:flags.10?NotificationSound = PeerNotifySettings; - -peerSettings#f47741f7 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true business_bot_paused:flags.11?true business_bot_can_reply:flags.12?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int business_bot_id:flags.13?long business_bot_manage_url:flags.13?string charge_paid_message_stars:flags.14?long registration_month:flags.15?string phone_country:flags.16?string name_change_date:flags.17?int photo_change_date:flags.18?int = PeerSettings; - -wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; -wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; - -inputReportReasonSpam#58dbcab8 = ReportReason; -inputReportReasonViolence#1e22c78d = ReportReason; -inputReportReasonPornography#2e59d922 = ReportReason; -inputReportReasonChildAbuse#adf44ee3 = ReportReason; -inputReportReasonOther#c1e4a2b1 = ReportReason; -inputReportReasonCopyright#9b89f93a = ReportReason; -inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; -inputReportReasonFake#f5ddd6e7 = ReportReason; -inputReportReasonIllegalDrugs#a8eb2be = ReportReason; -inputReportReasonPersonalDetails#9ec7863d = ReportReason; - -userFull#6cbe645 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true noforwards_my_enabled:flags2.23?true noforwards_peer_enabled:flags2.24?true unofficial_security_risk:flags2.26?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme:flags.15?ChatTheme private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int main_tab:flags2.20?ProfileTab saved_music:flags2.21?Document note:flags2.22?TextWithEntities bot_manager_id:flags2.25?long = UserFull; - -contact#145ade0b user_id:long mutual:Bool = Contact; - -importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; - -contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; - -contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; -contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; - -contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; - -contacts.blocked#ade1591 blocked:Vector chats:Vector users:Vector = contacts.Blocked; -contacts.blockedSlice#e1664194 count:int blocked:Vector chats:Vector users:Vector = contacts.Blocked; - -messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; - -messages.messages#1d73e7ea messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#5f206716 flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesNotModified#74535f21 count:int = messages.Messages; - -messages.chats#64ff9fd5 chats:Vector = messages.Chats; -messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; - -messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; - -messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; - -inputMessagesFilterEmpty#57e2f66c = MessagesFilter; -inputMessagesFilterPhotos#9609a51c = MessagesFilter; -inputMessagesFilterVideo#9fc00e65 = MessagesFilter; -inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; -inputMessagesFilterDocument#9eddf188 = MessagesFilter; -inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; -inputMessagesFilterGif#ffc86587 = MessagesFilter; -inputMessagesFilterVoice#50f5c392 = MessagesFilter; -inputMessagesFilterMusic#3751b49e = MessagesFilter; -inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; -inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; -inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; -inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; -inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; -inputMessagesFilterGeo#e7026d0d = MessagesFilter; -inputMessagesFilterContacts#e062db83 = MessagesFilter; -inputMessagesFilterPinned#1bb00451 = MessagesFilter; -inputMessagesFilterPoll#fa2bc90a = MessagesFilter; - -updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; -updateMessageID#4e90bfd6 id:int random_id:long = Update; -updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; -updateUserTyping#2a17bf5c flags:# user_id:long top_msg_id:flags.0?int action:SendMessageAction = Update; -updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update; -updateChatParticipants#7761198 participants:ChatParticipants = Update; -updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; -updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector = Update; -updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update; -updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; -updateEncryptedChatTyping#1710f156 chat_id:int = Update; -updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; -updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; -updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update; -updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update; -updateDcOptions#8e5e9873 dc_options:Vector = Update; -updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; -updateServiceNotification#ebe46819 flags:# popup:flags.0?true invert_media:flags.2?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; -updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; -updateUserPhone#5492a13 user_id:long phone:string = Update; -updateReadHistoryInbox#9e84bc99 flags:# folder_id:flags.0?int peer:Peer top_msg_id:flags.1?int max_id:int still_unread_count:int pts:int pts_count:int = Update; -updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; -updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; -updateReadMessagesContents#f8227181 flags:# messages:Vector pts:int pts_count:int date:flags.0?int = Update; -updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; -updateChannel#635b4c09 channel_id:long = Update; -updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update; -updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; -updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; -updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; -updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Update; -updateStickerSets#31c24808 flags:# masks:flags.0?true emojis:flags.1?true = Update; -updateSavedGifs#9375341e = Update; -updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; -updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; -updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; -updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; -updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; -updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update; -updateReadFeaturedStickers#571d2742 = Update; -updateRecentStickers#9a422c20 = Update; -updateConfig#a229dd06 = Update; -updatePtsChanged#3354678f = Update; -updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update; -updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; -updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; -updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; -updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; -updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update; -updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; -updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; -updateLangPackTooLong#46560264 lang_code:string = Update; -updateLangPack#56022f4d difference:LangPackDifference = Update; -updateFavedStickers#e511996d = Update; -updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector = Update; -updateContactsReset#7084a7be = Update; -updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; -updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update; -updateMessagePoll#d64c522b flags:# peer:flags.1?Peer msg_id:flags.1?int top_msg_id:flags.2?int poll_id:long poll:flags.0?Poll results:PollResults = Update; -updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; -updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; -updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update; -updatePeerLocated#b4afcfb0 peers:Vector = Update; -updateNewScheduledMessage#39a51dfb message:Message = Update; -updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector sent_messages:flags.0?Vector = Update; -updateTheme#8216fba3 theme:Theme = Update; -updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update; -updateLoginToken#564fe691 = Update; -updateMessagePollVote#7699f014 poll_id:long peer:Peer options:Vector positions:Vector qts:int = Update; -updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update; -updateDialogFilterOrder#a5d72105 order:Vector = Update; -updateDialogFilters#3504914f = Update; -updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update; -updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update; -updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update; -updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update; -updatePeerBlocked#ebe07752 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer = Update; -updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; -updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; -updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChat#f89a6a4e chat_id:long = Update; -updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; -updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update; -updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; -updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update; -updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update; -updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; -updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; -updateBotChatInviteRequester#7cb34d79 flags:# peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int query_id:flags.0?long = Update; -updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update; -updateAttachMenuBots#17b7a20b = Update; -updateWebViewResultSent#1592b79d query_id:long = Update; -updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update; -updateSavedRingtones#74d8be99 = Update; -updateTranscribedAudio#84cd5a flags:# pending:flags.0?true peer:Peer msg_id:int transcription_id:long text:string = Update; -updateReadFeaturedEmojiStickers#fb4c496c = Update; -updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update; -updateRecentEmojiStatuses#30f443db = Update; -updateRecentReactions#6f7863f4 = Update; -updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update; -updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector = Update; -updateUser#20529438 user_id:long = Update; -updateAutoSaveSettings#ec05b097 = Update; -updateStory#75b3b798 peer:Peer story:StoryItem = Update; -updateReadStories#f74e932b peer:Peer max_id:int = Update; -updateStoryID#1bf335b9 id:int random_id:long = Update; -updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update; -updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update; -updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update; -updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update; -updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update; -updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector new_reactions:Vector qts:int = Update; -updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector qts:int = Update; -updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; -updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector = Update; -updateSavedReactionTags#39c67432 = Update; -updateSmsJob#f16269d4 job_id:string = Update; -updateQuickReplies#f9470ab2 quick_replies:Vector = Update; -updateNewQuickReply#f53da717 quick_reply:QuickReply = Update; -updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update; -updateQuickReplyMessage#3e050d0f message:Message = Update; -updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector = Update; -updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Update; -updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; -updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; -updateStarsBalance#4e80a379 balance:StarsAmount = Update; -updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; -updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; -updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; -updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; -updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; -updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; -updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update; -updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = Update; -updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update; -updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update; -updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector = Update; -updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector = Update; -updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update; -updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update; -updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update; -updateStarGiftCraftFail#ac072444 = Update; -updateChatParticipantRank#bd8367b9 chat_id:long user_id:long rank:string version:int = Update; -updateManagedBot#4880ed9a user_id:long bot_id:long qts:int = Update; -updateBotGuestChatQuery#cdd4093d flags:# query_id:long message:Message reference_messages:flags.0?Vector qts:int = Update; -updateAiComposeTones#8c0f91fb = Update; -updateJoinChatWebViewDecision#bdac7e70 peer:Peer query_id:long result:JoinChatBotResult = Update; -updateNewBotConnection#b22083a6 flags:# confirmed:flags.0?true bot_id:long date:flags.1?int device:flags.1?string location:flags.1?string = Update; -updateWebBrowserSettings#c39a2ade flags:# open_external_browser:flags.0?true display_close_button:flags.1?true = Update; -updateWebBrowserException#140502d1 flags:# delete:flags.1?true open_external_browser:flags.0?Bool exception:WebDomainException = Update; - -updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; - -updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; -updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; -updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; -updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; - -updatesTooLong#e317af7e = Updates; -updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShort#78d4dec1 update:Update date:int = Updates; -updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; -updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; -updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; -photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; - -photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; - -upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; -upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; - -dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; - -config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config; - -nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; - -help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate; -help.noAppUpdate#c45a6536 = help.AppUpdate; - -help.inviteText#18cb9f78 message:string = help.InviteText; - -encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; -encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat; -encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; -encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; -encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat; - -inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; - -encryptedFileEmpty#c21f497e = EncryptedFile; -encryptedFile#a8008cd8 id:long access_hash:long size:long dc_id:int key_fingerprint:int = EncryptedFile; - -inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; -inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; -inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; -inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; - -encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; -encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; - -messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; -messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; - -messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; -messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; - -inputDocumentEmpty#72f0eaae = InputDocument; -inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; - -documentEmpty#36f8c871 id:long = Document; -document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector video_thumbs:flags.1?Vector dc_id:int attributes:Vector = Document; - -help.support#17c6b5f6 phone_number:string user:User = help.Support; - -notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; -notifyUsers#b4c83b4c = NotifyPeer; -notifyChats#c007cec3 = NotifyPeer; -notifyBroadcasts#d612e8ef = NotifyPeer; -notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer; - -sendMessageTypingAction#16bf744e = SendMessageAction; -sendMessageCancelAction#fd5ec8f5 = SendMessageAction; -sendMessageRecordVideoAction#a187d66f = SendMessageAction; -sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; -sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; -sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; -sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; -sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; -sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; -sendMessageChooseContactAction#628cbc6f = SendMessageAction; -sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; -sendMessageRecordRoundAction#88f27fbc = SendMessageAction; -sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; -speakingInGroupCallAction#d92c2285 = SendMessageAction; -sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; -sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; -sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction; -sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction; -sendMessageTextDraftAction#376d975c random_id:long text:TextWithEntities = SendMessageAction; - -contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; - -inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; -inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; -inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; -inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; -inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; -inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; -inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; -inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey; -inputPrivacyKeyVoiceMessages#aee69d68 = InputPrivacyKey; -inputPrivacyKeyAbout#3823cc40 = InputPrivacyKey; -inputPrivacyKeyBirthday#d65a11cc = InputPrivacyKey; -inputPrivacyKeyStarGiftsAutoSave#e1732341 = InputPrivacyKey; -inputPrivacyKeyNoPaidMessages#bdc597b4 = InputPrivacyKey; -inputPrivacyKeySavedMusic#4dbe9226 = InputPrivacyKey; - -privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; -privacyKeyChatInvite#500e6dfa = PrivacyKey; -privacyKeyPhoneCall#3d662b7b = PrivacyKey; -privacyKeyPhoneP2P#39491cc8 = PrivacyKey; -privacyKeyForwards#69ec56a3 = PrivacyKey; -privacyKeyProfilePhoto#96151fed = PrivacyKey; -privacyKeyPhoneNumber#d19ae46d = PrivacyKey; -privacyKeyAddedByPhone#42ffd42b = PrivacyKey; -privacyKeyVoiceMessages#697f414 = PrivacyKey; -privacyKeyAbout#a486b761 = PrivacyKey; -privacyKeyBirthday#2000a518 = PrivacyKey; -privacyKeyStarGiftsAutoSave#2ca4fdf8 = PrivacyKey; -privacyKeyNoPaidMessages#17d348d2 = PrivacyKey; -privacyKeySavedMusic#ff7a571b = PrivacyKey; - -inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; -inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; -inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; -inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; -inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; -inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; -inputPrivacyValueAllowChatParticipants#840649cf chats:Vector = InputPrivacyRule; -inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector = InputPrivacyRule; -inputPrivacyValueAllowCloseFriends#2f453e49 = InputPrivacyRule; -inputPrivacyValueAllowPremium#77cdc9f1 = InputPrivacyRule; -inputPrivacyValueAllowBots#5a4fcce5 = InputPrivacyRule; -inputPrivacyValueDisallowBots#c4e57915 = InputPrivacyRule; - -privacyValueAllowContacts#fffe1bac = PrivacyRule; -privacyValueAllowAll#65427b82 = PrivacyRule; -privacyValueAllowUsers#b8905fb2 users:Vector = PrivacyRule; -privacyValueDisallowContacts#f888fa1a = PrivacyRule; -privacyValueDisallowAll#8b73e763 = PrivacyRule; -privacyValueDisallowUsers#e4621141 users:Vector = PrivacyRule; -privacyValueAllowChatParticipants#6b134e8e chats:Vector = PrivacyRule; -privacyValueDisallowChatParticipants#41c87565 chats:Vector = PrivacyRule; -privacyValueAllowCloseFriends#f7e8d89b = PrivacyRule; -privacyValueAllowPremium#ece9814b = PrivacyRule; -privacyValueAllowBots#21461b5d = PrivacyRule; -privacyValueDisallowBots#f6a5f82f = PrivacyRule; - -account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; - -accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; - -documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; -documentAttributeAnimated#11b58939 = DocumentAttribute; -documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; -documentAttributeVideo#43c57c48 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double video_codec:flags.5?string = DocumentAttribute; -documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; -documentAttributeFilename#15590068 file_name:string = DocumentAttribute; -documentAttributeHasStickers#9801d2f7 = DocumentAttribute; -documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute; - -messages.stickersNotModified#f1749a22 = messages.Stickers; -messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; - -stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; - -messages.allStickersNotModified#e86602c3 = messages.AllStickers; -messages.allStickers#cdbbcebb hash:long sets:Vector = messages.AllStickers; - -messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; - -webPageEmpty#211a1788 flags:# id:long url:flags.0?string = WebPage; -webPagePending#b0d13e47 flags:# id:long url:flags.0?string date:int = WebPage; -webPage#e89c45b2 flags:# has_large_media:flags.13?true video_cover_photo:flags.14?true id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector = WebPage; -webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; - -authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; - -account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector = account.Authorizations; - -account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password; - -account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; - -account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; - -auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; - -receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; - -chatInviteExported#a22cbd96 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int subscription_expired:flags.10?int title:flags.8?string subscription_pricing:flags.9?StarsSubscriptionPricing = ExportedChatInvite; -chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite; - -chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#5c9d3702 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true can_refulfill_subscription:flags.11?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector color:int subscription_pricing:flags.10?StarsSubscriptionPricing subscription_form_id:flags.12?long bot_verification:flags.13?BotVerification = ChatInvite; -chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; - -inputStickerSetEmpty#ffb62b95 = InputStickerSet; -inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; -inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; -inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; -inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; -inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet; -inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet; -inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; -inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; -inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet; -inputStickerSetTonGifts#1cf671a0 = InputStickerSet; - -stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; - -messages.stickerSet#6e153f16 set:StickerSet packs:Vector keywords:Vector documents:Vector = messages.StickerSet; -messages.stickerSetNotModified#d3f924eb = messages.StickerSet; - -botCommand#c27ac8c7 command:string description:string = BotCommand; - -botInfo#4d8a0299 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton privacy_policy_url:flags.7?string app_settings:flags.8?BotAppSettings verifier_settings:flags.9?BotVerifierSettings = BotInfo; - -keyboardButton#7d170cff flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrl#d80c25ec flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonCallback#e62bc960 flags:# requires_password:flags.0?true style:flags.10?KeyboardButtonStyle text:string data:bytes = KeyboardButton; -keyboardButtonRequestPhone#417efd8f flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonRequestGeoLocation#aa40f94d flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonSwitchInline#991399fc flags:# same_peer:flags.0?true style:flags.10?KeyboardButtonStyle text:string query:string peer_types:flags.1?Vector = KeyboardButton; -keyboardButtonGame#89c590f9 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonBuy#3fa53905 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrlAuth#f51006f9 flags:# style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; -inputKeyboardButtonUrlAuth#68013e72 flags:# request_write_access:flags.0?true style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; -keyboardButtonRequestPoll#7a11d782 flags:# style:flags.10?KeyboardButtonStyle quiz:flags.0?Bool text:string = KeyboardButton; -inputKeyboardButtonUserProfile#7d5e07c7 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:InputUser = KeyboardButton; -keyboardButtonUserProfile#c0fd5d09 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:long = KeyboardButton; -keyboardButtonWebView#e846b1a0 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonSimpleWebView#e15c4370 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonRequestPeer#5b0f15f5 flags:# style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -inputKeyboardButtonRequestPeer#2b78156 flags:# name_requested:flags.0?true username_requested:flags.1?true photo_requested:flags.2?true style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -keyboardButtonCopy#bcc4af10 flags:# style:flags.10?KeyboardButtonStyle text:string copy_text:string = KeyboardButton; - -keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; - -replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; -replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup; -replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector placeholder:flags.3?string = ReplyMarkup; -replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; - -messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; -messageEntityMention#fa04579d offset:int length:int = MessageEntity; -messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; -messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; -messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; -messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; -messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; -messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; -messageEntityCode#28a20571 offset:int length:int = MessageEntity; -messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; -messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; -messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity; -inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; -messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; -messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; -messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity; -messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; -messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; -messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; -messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; -messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity; -messageEntityFormattedDate#904ac7c7 flags:# relative:flags.0?true short_time:flags.1?true long_time:flags.2?true short_date:flags.3?true long_date:flags.4?true day_of_week:flags.5?true offset:int length:int date:int = MessageEntity; -messageEntityDiffInsert#71777116 offset:int length:int = MessageEntity; -messageEntityDiffReplace#c6c1e5a7 offset:int length:int old_text:string = MessageEntity; -messageEntityDiffDelete#652c1c5 offset:int length:int = MessageEntity; - -inputChannelEmpty#ee8c1e86 = InputChannel; -inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; -inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel; - -contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; - -messageRange#ae30253 min_id:int max_id:int = MessageRange; - -updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; -updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; -updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; - -channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; -channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; - -channelParticipant#1bd54456 flags:# user_id:long date:int subscription_until_date:flags.0?int rank:flags.2?string = ChannelParticipant; -channelParticipantSelf#a9478a1a flags:# via_request:flags.0?true user_id:long inviter_id:long date:int subscription_until_date:flags.1?int rank:flags.2?string = ChannelParticipant; -channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; -channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; -channelParticipantBanned#d5f0ad91 flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights rank:flags.2?string = ChannelParticipant; -channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; - -channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; -channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; -channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; -channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; -channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; -channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; -channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; -channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; - -channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; -channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; - -channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; - -help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; - -messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; -messages.savedGifs#84a02a0d hash:long gifs:Vector = messages.SavedGifs; - -inputBotInlineMessageMediaAuto#3380c786 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaWebPage#bddcc510 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true optional:flags.6?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; - -botInlineMessageMediaAuto#764cf810 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; -botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; - -messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector cache_time:int users:Vector = messages.BotResults; - -exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; - -messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader; - -auth.codeTypeSms#72a3158c = auth.CodeType; -auth.codeTypeCall#741cd3e3 = auth.CodeType; -auth.codeTypeFlashCall#226ccefb = auth.CodeType; -auth.codeTypeMissedCall#d61ad6ee = auth.CodeType; -auth.codeTypeFragmentSms#6ed998c = auth.CodeType; - -auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; -auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; -auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; -auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType; -auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; -auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; -auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; -auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; -auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; -auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; - -messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; - -messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; - -inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; -inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID; - -inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; - -messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; - -topPeer#edcdc05b peer:Peer rating:double = TopPeer; - -topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; -topPeerCategoryBotsInline#148677e2 = TopPeerCategory; -topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; -topPeerCategoryGroups#bd17a14a = TopPeerCategory; -topPeerCategoryChannels#161d9628 = TopPeerCategory; -topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; -topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; -topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; -topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory; -topPeerCategoryBotsGuestChat#6c24f3dd = TopPeerCategory; - -topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; - -contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; -contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; -contacts.topPeersDisabled#b52c939d = contacts.TopPeers; - -draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; -draftMessage#96eaa5eb flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost = DraftMessage; - -messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; -messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; - -messages.recentStickersNotModified#b17f890 = messages.RecentStickers; -messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; - -messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; - -messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; -messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; - -stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; -stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; -stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector keywords:Vector documents:Vector = StickerSetCovered; -stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered; - -maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; - -inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; -inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; - -game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; - -inputGameID#32c3e77 id:long access_hash:long = InputGame; -inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; - -highScore#73a379eb pos:int user_id:long score:int = HighScore; - -messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; - -textEmpty#dc3d824f = RichText; -textPlain#744694e0 text:string = RichText; -textBold#6724abc4 text:RichText = RichText; -textItalic#d912a59c text:RichText = RichText; -textUnderline#c12622c4 text:RichText = RichText; -textStrike#9bf8bb95 text:RichText = RichText; -textFixed#6c3f19b9 text:RichText = RichText; -textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; -textEmail#de5a0dd6 text:RichText email:string = RichText; -textConcat#7e6260d7 texts:Vector = RichText; -textSubscript#ed6a8504 text:RichText = RichText; -textSuperscript#c7fb5e01 text:RichText = RichText; -textMarked#34b8621 text:RichText = RichText; -textPhone#1ccb966a text:RichText phone:string = RichText; -textImage#81ccf4f document_id:long w:int h:int = RichText; -textAnchor#35553762 text:RichText name:string = RichText; - -pageBlockUnsupported#13567e8a = PageBlock; -pageBlockTitle#70abc3fd text:RichText = PageBlock; -pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; -pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; -pageBlockHeader#bfd064ec text:RichText = PageBlock; -pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; -pageBlockParagraph#467a0766 text:RichText = PageBlock; -pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; -pageBlockFooter#48870999 text:RichText = PageBlock; -pageBlockDivider#db20b188 = PageBlock; -pageBlockAnchor#ce0d37b0 name:string = PageBlock; -pageBlockList#e4e88011 items:Vector = PageBlock; -pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; -pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; -pageBlockPhoto#1759c560 flags:# photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; -pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true video_id:long caption:PageCaption = PageBlock; -pageBlockCover#39f23300 cover:PageBlock = PageBlock; -pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; -pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; -pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; -pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; -pageBlockChannel#ef1751b5 channel:Chat = PageBlock; -pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; -pageBlockKicker#1e148390 text:RichText = PageBlock; -pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; -pageBlockOrderedList#9a8ae1e1 items:Vector = PageBlock; -pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; -pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; -pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; - -phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; -phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; -phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; -phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; -phoneCallDiscardReasonMigrateConferenceCall#9fbbf1f7 slug:string = PhoneCallDiscardReason; - -dataJSON#7d748d04 data:string = DataJSON; - -labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; - -invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector terms_url:flags.10?string subscription_period:flags.11?int = Invoice; - -paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; - -postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; - -paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; - -paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; - -webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; -webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; - -inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; - -inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; -inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; -inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation; - -upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; - -payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector users:Vector = payments.PaymentForm; -payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector = payments.PaymentForm; -payments.paymentFormStarGift#b425cfe1 form_id:long invoice:Invoice = payments.PaymentForm; - -payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; - -payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; -payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; - -payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; -payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector = payments.PaymentReceipt; - -payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; - -inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; -inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials; - -account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; - -shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; - -inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem; - -inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; - -phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#30535af5 flags:# p2p_allowed:flags.5?true video:flags.6?true conference_supported:flags.8?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int custom_parameters:flags.7?DataJSON = PhoneCall; -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; - -phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; -phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection; - -phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector = PhoneCallProtocol; - -phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; - -upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; -upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; - -cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; - -cdnConfig#5725e40a public_keys:Vector = CdnConfig; - -langPackString#cad181f6 key:string value:string = LangPackString; -langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; -langPackStringDeleted#2979eeb2 key:string = LangPackString; - -langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; - -langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; - -channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; -channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector new_value:Vector = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAutotranslation#c517f77e new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantEditRank#5806b4ec user_id:long prev_rank:string new_rank:string = ChannelAdminLogEventAction; - -channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; - -channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; - -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true edit_rank:flags.19?true = ChannelAdminLogEventsFilter; - -popularContact#5ce14175 client_id:long importers:int = PopularContact; - -messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; -messages.favedStickers#2cb51097 hash:long packs:Vector stickers:Vector = messages.FavedStickers; - -recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; -recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl; -recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl; -recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; -recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; - -help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; - -inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; - -webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; - -account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; - -inputMessageID#a676a322 id:int = InputMessage; -inputMessageReplyTo#bad88395 id:int = InputMessage; -inputMessagePinned#86872538 = InputMessage; -inputMessageCallbackQuery#acfa1a7e id:int query_id:long = InputMessage; - -inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; -inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; - -dialogPeer#e56dbf05 peer:Peer = DialogPeer; -dialogPeerFolder#514519e2 folder_id:int = DialogPeer; - -messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; -messages.foundStickerSets#8af09dd2 hash:long sets:Vector = messages.FoundStickerSets; - -fileHash#f39b035c offset:long limit:int hash:bytes = FileHash; - -inputClientProxy#75588b3f address:string port:int = InputClientProxy; - -help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; -help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; - -inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; -inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; - -secureFileEmpty#64199744 = SecureFile; -secureFile#7d09c27e id:long access_hash:long size:long dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; - -secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; - -securePlainPhone#7d6099dd phone:string = SecurePlainData; -securePlainEmail#21ec5a5f email:string = SecurePlainData; - -secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; -secureValueTypePassport#3dac6a00 = SecureValueType; -secureValueTypeDriverLicense#6e425c4 = SecureValueType; -secureValueTypeIdentityCard#a0d0744b = SecureValueType; -secureValueTypeInternalPassport#99a48f23 = SecureValueType; -secureValueTypeAddress#cbe31e26 = SecureValueType; -secureValueTypeUtilityBill#fc36954e = SecureValueType; -secureValueTypeBankStatement#89137c0d = SecureValueType; -secureValueTypeRentalAgreement#8b883488 = SecureValueType; -secureValueTypePassportRegistration#99e3806a = SecureValueType; -secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; -secureValueTypePhone#b320aadb = SecureValueType; -secureValueTypeEmail#8e3ca7ee = SecureValueType; - -secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; - -inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; - -secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; - -secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; -secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; -secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; - -secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; - -account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; - -account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; - -help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; -help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; - -savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; - -account.takeout#4dba4501 id:long = account.Takeout; - -passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; -passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; - -securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; -securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; -securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; - -secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; - -inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; -inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; - -secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; -secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; - -help.passportConfigNotModified#bfb9f457 = help.PassportConfig; -help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; - -inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; - -jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; - -jsonNull#3f6d7b68 = JSONValue; -jsonBool#c7345e6a value:Bool = JSONValue; -jsonNumber#2be0dfa4 value:double = JSONValue; -jsonString#b71e767a value:string = JSONValue; -jsonArray#f7444763 value:Vector = JSONValue; -jsonObject#99c1d49d value:Vector = JSONValue; - -pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; - -pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; - -pageCaption#6f747657 text:RichText credit:RichText = PageCaption; - -pageListItemText#b92fb6cd text:RichText = PageListItem; -pageListItemBlocks#25e073fc blocks:Vector = PageListItem; - -pageListOrderedItemText#5e068047 num:string text:RichText = PageListOrderedItem; -pageListOrderedItemBlocks#98dd8936 num:string blocks:Vector = PageListOrderedItem; - -pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; - -page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector views:flags.3?int = Page; - -help.supportName#8c05f1c9 name:string = help.SupportName; - -help.userInfoEmpty#f3ae2eed = help.UserInfo; -help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; - -pollAnswer#4b7d786a flags:# text:TextWithEntities option:bytes media:flags.0?MessageMedia added_by:flags.1?Peer date:flags.1?int = PollAnswer; -inputPollAnswer#199fed96 flags:# text:TextWithEntities media:flags.0?InputMedia = PollAnswer; - -poll#966e2dbf id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true open_answers:flags.6?true revoting_disabled:flags.7?true shuffle_answers:flags.8?true hide_results_until_close:flags.9?true creator:flags.10?true subscribers_only:flags.11?true question:TextWithEntities answers:Vector close_period:flags.4?int close_date:flags.5?int countries_iso2:flags.12?Vector hash:long = Poll; - -pollAnswerVoters#3645230a flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:flags.2?int recent_voters:flags.2?Vector = PollAnswerVoters; - -pollResults#ba7bb15e flags:# min:flags.0?true has_unread_votes:flags.6?true can_view_stats:flags.7?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector solution_media:flags.5?MessageMedia = PollResults; - -chatOnlines#f041e250 onlines:int = ChatOnlines; - -statsURL#47a971e0 url:string = StatsURL; - -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true manage_ranks:flags.18?true = ChatAdminRights; - -chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true edit_rank:flags.26?true send_reactions:flags.27?true until_date:int = ChatBannedRights; - -inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; -inputWallPaperSlug#72091c80 slug:string = InputWallPaper; -inputWallPaperNoFile#967a462e id:long = InputWallPaper; - -account.wallPapersNotModified#1c199183 = account.WallPapers; -account.wallPapers#cdc3858c hash:long wallpapers:Vector = account.WallPapers; - -codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true unknown_number:flags.9?true logout_tokens:flags.6?Vector token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings; - -wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings; - -autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings; - -account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; - -emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector = EmojiKeyword; -emojiKeywordDeleted#236df622 keyword:string emoticons:Vector = EmojiKeyword; - -emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector = EmojiKeywordsDifference; - -emojiURL#a575739d url:string = EmojiURL; - -emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; - -folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; - -inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; - -folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; - -messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; - -urlAuthResultRequest#3cd623ec flags:# request_write_access:flags.0?true request_phone_number:flags.1?true match_codes_first:flags.5?true is_app:flags.6?true bot:User domain:string browser:flags.2?string platform:flags.2?string ip:flags.2?string region:flags.2?string match_codes:flags.3?Vector user_id_hint:flags.4?long verified_app_name:flags.7?string = UrlAuthResult; -urlAuthResultAccepted#623a8fa0 flags:# url:flags.0?string = UrlAuthResult; -urlAuthResultDefault#a9d6db1f = UrlAuthResult; - -channelLocationEmpty#bfb5ad8b = ChannelLocation; -channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation; - -peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated; -peerSelfLocated#f8ec284b expires:int = PeerLocated; - -restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason; - -inputTheme#3c5693e9 id:long access_hash:long = InputTheme; -inputThemeSlug#f5890df1 slug:string = InputTheme; - -theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector emoticon:flags.6?string installs_count:flags.4?int = Theme; - -account.themesNotModified#f41eb622 = account.Themes; -account.themes#9a3d8c6d hash:long themes:Vector = account.Themes; - -auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken; -auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken; -auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken; - -account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings; - -messages.inactiveChats#a927fec5 dates:Vector chats:Vector users:Vector = messages.InactiveChats; - -baseThemeClassic#c3a12462 = BaseTheme; -baseThemeDay#fbd81688 = BaseTheme; -baseThemeNight#b7b31ea8 = BaseTheme; -baseThemeTinted#6d5f77ee = BaseTheme; -baseThemeArctic#5b11125a = BaseTheme; - -inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; - -themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; - -webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; -webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; -webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; -webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; -webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; -webPageAttributeStarGiftAuction#1c641c2 gift:StarGift end_date:int = WebPageAttribute; -webPageAttributeAiComposeTone#7781fe18 emoji_id:long = WebPageAttribute; - -messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; - -bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl; - -payments.bankCardData#3e24e573 title:string open_urls:Vector = payments.BankCardData; - -dialogFilter#aa472651 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector exclude_peers:Vector = DialogFilter; -dialogFilterDefault#363293ae = DialogFilter; -dialogFilterChatlist#96537bd7 flags:# has_my_invites:flags.26?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector = DialogFilter; - -dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested; - -statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays; - -statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev; - -statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue; - -statsGraphAsync#4a27eb2d token:string = StatsGraph; -statsGraphError#bedc9822 error:string = StatsGraph; -statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph; - -stats.broadcastStats#396ca5fc period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev reactions_per_post:StatsAbsValueAndPrev views_per_story:StatsAbsValueAndPrev shares_per_story:StatsAbsValueAndPrev reactions_per_story:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_posts_interactions:Vector = stats.BroadcastStats; - -help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; -help.promoData#8a4d87a flags:# proxy:flags.0?true expires:int peer:flags.3?Peer psa_type:flags.1?string psa_message:flags.2?string pending_suggestions:Vector dismissed_suggestions:Vector custom_pending_suggestion:flags.4?PendingSuggestion chats:Vector users:Vector = help.PromoData; - -videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; -videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector = VideoSize; -videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector = VideoSize; - -statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster; - -statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; - -statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; - -stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; - -globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; - -help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; - -help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector = help.Country; - -help.countriesListNotModified#93cc1f32 = help.CountriesList; -help.countriesList#87d0759e countries:Vector hash:int = help.CountriesList; - -messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews; - -messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; - -messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; - -messageReplyHeader#1b97dd66 flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector quote_offset:flags.10?int todo_item_id:flags.11?int poll_option:flags.12?bytes = MessageReplyHeader; -messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader; - -messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; - -peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; - -stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; - -groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall; - -inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -inputGroupCallSlug#fe06823f slug:string = InputGroupCall; -inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall; - -groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant; - -phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; - -phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; - -inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; -inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; -inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType; -inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType; -inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType; -inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType; - -messages.historyImport#1662af0b id:long = messages.HistoryImport; - -messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed; - -messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector = messages.AffectedFoundMessages; - -chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter; - -messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; - -messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; -messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; - -messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; - -chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites; - -messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; - -messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; - -phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; - -phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; - -groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector = GroupCallParticipantVideoSourceGroup; - -groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector audio_source:flags.1?int = GroupCallParticipantVideo; - -stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName; - -botCommandScopeDefault#2f6cb2ab = BotCommandScope; -botCommandScopeUsers#3c4f04d8 = BotCommandScope; -botCommandScopeChats#6fe1a881 = BotCommandScope; -botCommandScopeChatAdmins#b9aa606a = BotCommandScope; -botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope; -botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope; -botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope; - -account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult; -account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; -account.resetPasswordOk#e926d63e = account.ResetPasswordResult; - -chatTheme#c3dffc04 emoticon:string = ChatTheme; -chatThemeUniqueGift#3458f9c8 gift:StarGift theme_settings:Vector = ChatTheme; - -account.chatThemesNotModified#e011e1c4 = account.ChatThemes; -account.chatThemes#be098173 flags:# hash:long themes:Vector chats:Vector users:Vector next_offset:flags.0?string = account.ChatThemes; - -sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage; - -messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; -messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; - -searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; - -messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector messages:Vector chats:Vector users:Vector = messages.SearchResultsCalendar; - -searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition; - -messages.searchResultsPositions#53b22baf count:int positions:Vector = messages.SearchResultsPositions; - -channels.sendAsPeers#f496b0c6 peers:Vector chats:Vector users:Vector = channels.SendAsPeers; - -users.userFull#3b6d152e full_user:UserFull chats:Vector users:Vector = users.UserFull; - -messages.peerSettings#6880b94d settings:PeerSettings chats:Vector users:Vector = messages.PeerSettings; - -auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut; - -reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; - -messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector recent_reactions:flags.1?Vector top_reactors:flags.4?Vector = MessageReactions; - -messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.MessageReactionsList; - -availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; - -messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions; -messages.availableReactions#768e3aad hash:int reactions:Vector = messages.AvailableReactions; - -messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true my:flags.2?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction; - -groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel; - -phone.groupCallStreamChannels#d0e482b2 channels:Vector = phone.GroupCallStreamChannels; - -phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl; - -attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; - -attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector = AttachMenuBotIcon; - -attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector icons:Vector = AttachMenuBot; - -attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; -attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector = AttachMenuBots; - -attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector = AttachMenuBotsBot; - -webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true fullscreen:flags.2?true query_id:flags.0?long url:string = WebViewResult; - -webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent; - -botMenuButtonDefault#7533a588 = BotMenuButton; -botMenuButtonCommands#4258c205 = BotMenuButton; -botMenuButton#c7b57ce6 text:string url:string = BotMenuButton; - -account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones; -account.savedRingtones#c1e92cc5 hash:long ringtones:Vector = account.SavedRingtones; - -notificationSoundDefault#97e8bebe = NotificationSound; -notificationSoundNone#6f0c34df = NotificationSound; -notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound; -notificationSoundRingtone#ff6c8049 id:long = NotificationSound; - -account.savedRingtone#b7263f6d = account.SavedRingtone; -account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone; - -attachMenuPeerTypeSameBotPM#7d6be90e = AttachMenuPeerType; -attachMenuPeerTypeBotPM#c32bfa1a = AttachMenuPeerType; -attachMenuPeerTypePM#f146d31f = AttachMenuPeerType; -attachMenuPeerTypeChat#509113f = AttachMenuPeerType; -attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; - -inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; -inputInvoiceSlug#c326caef slug:string = InputInvoice; -inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; -inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice; -inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice; -inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; -inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; -inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; -inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; -inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice; -inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice; - -payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; - -messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; - -help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; - -inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose; -inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentPremiumGiftCode#fb790393 flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long message:flags.1?TextWithEntities = InputStorePaymentPurpose; -inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsTopup#f9a2a6cb flags:# stars:long currency:string amount:long spend_purpose_peer:flags.0?InputPeer = InputStorePaymentPurpose; -inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; -inputStorePaymentAuthCode#3fc18057 flags:# restore:flags.0?true phone_number:string phone_code_hash:string premium_days:int currency:string amount:long = InputStorePaymentPurpose; - -paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; - -emojiStatusEmpty#2de11aae = EmojiStatus; -emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus; -emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus; -inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus; - -account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses; -account.emojiStatuses#90c467d1 hash:long statuses:Vector = account.EmojiStatuses; - -reactionEmpty#79f5d419 = Reaction; -reactionEmoji#1b2286b8 emoticon:string = Reaction; -reactionCustomEmoji#8935fc73 document_id:long = Reaction; -reactionPaid#523da4eb = Reaction; - -chatReactionsNone#eafc32bc = ChatReactions; -chatReactionsAll#52928bca flags:# allow_custom:flags.0?true = ChatReactions; -chatReactionsSome#661d4037 reactions:Vector = ChatReactions; - -messages.reactionsNotModified#b06fdbdf = messages.Reactions; -messages.reactions#eafdf716 hash:long reactions:Vector = messages.Reactions; - -emailVerifyPurposeLoginSetup#4345be73 phone_number:string phone_code_hash:string = EmailVerifyPurpose; -emailVerifyPurposeLoginChange#527d22eb = EmailVerifyPurpose; -emailVerifyPurposePassport#bbf51685 = EmailVerifyPurpose; - -emailVerificationCode#922e55a9 code:string = EmailVerification; -emailVerificationGoogle#db909ec2 token:string = EmailVerification; -emailVerificationApple#96d074fd token:string = EmailVerification; - -account.emailVerified#2b96cd1b email:string = account.EmailVerified; -account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified; - -premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption; - -sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer; - -messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia; -messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia; - -stickerKeyword#fcfeb29c document_id:long keyword:Vector = StickerKeyword; - -username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username; - -forumTopicDeleted#23f109b id:int = ForumTopic; -forumTopic#fcdad815 flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true title_missing:flags.7?true id:int date:int peer:Peer title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic; - -messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector messages:Vector chats:Vector users:Vector pts:int = messages.ForumTopics; - -defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL; - -exportedContactToken#41bf109b url:string expires:int = ExportedContactToken; - -requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType; -requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeCreateBot#3e81e078 flags:# bot_managed:flags.0?true suggested_name:flags.1?string suggested_username:flags.2?string = RequestPeerType; - -emojiListNotModified#481eadfa = EmojiList; -emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; - -emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; - -messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; -messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; - -textWithEntities#751f3146 text:string entities:Vector = TextWithEntities; - -messages.translateResult#33db32f8 result:Vector = messages.TranslatedText; - -autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings; - -autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException; - -account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector chats:Vector users:Vector = account.AutoSaveSettings; - -help.appConfigNotModified#7cde641d = help.AppConfig; -help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig; - -inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp; -inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp; - -botAppNotModified#5da674b7 = BotApp; -botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; - -messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp; - -inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; - -readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; - -inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist; - -exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector = ExportedChatlistInvite; - -chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite; - -chatlists.exportedInvites#10ab6dc7 invites:Vector chats:Vector users:Vector = chatlists.ExportedInvites; - -chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector already_peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; -chatlists.chatlistInvite#f10ece2f flags:# title_noanimate:flags.1?true title:TextWithEntities emoticon:flags.0?string peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; - -chatlists.chatlistUpdates#93bd878d missing_peers:Vector chats:Vector users:Vector = chatlists.ChatlistUpdates; - -bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo; - -messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote; -messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote; -messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector date:int = MessagePeerVote; - -storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector reactions_count:flags.4?int recent_viewers:flags.0?Vector = StoryViews; - -storyItemDeleted#51e6ee4f id:int = StoryItem; -storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true live:flags.9?true id:int date:int expire_date:int = StoryItem; -storyItem#16a4b93c flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector music:flags.20?Document = StoryItem; - -stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; -stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; - -stories.stories#63c3dd0a flags:# count:int stories:Vector pinned_to_top:flags.0?Vector chats:Vector users:Vector = stories.Stories; - -storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView; -storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView; -storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView; - -stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryViewsList; - -stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; - -inputReplyToMessage#3bd4b7c2 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int poll_option:flags.7?bytes = InputReplyTo; -inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; -inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; - -exportedStoryLink#3fc9053b link:string = ExportedStoryLink; - -storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; - -mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates; - -mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea; -inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea; -mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea; -mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea; -mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; -inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; -mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; -mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea; -mediaAreaStarGift#5787686d coordinates:MediaAreaCoordinates slug:string = MediaArea; - -peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; - -stories.peerStories#cae68768 stories:PeerStories chats:Vector users:Vector = stories.PeerStories; - -messages.webPage#fd5e12bd webpage:WebPage chats:Vector users:Vector = messages.WebPage; - -premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption; - -payments.checkedGiftCode#eb983f8f flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int days:int used_date:flags.1?int chats:Vector users:Vector = payments.CheckedGiftCode; - -payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; -payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo; - -prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; -prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway; - -boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost; - -premium.boostsList#86f8613c flags:# count:int boosts:Vector next_offset:flags.0?string users:Vector = premium.BoostsList; - -myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost; - -premium.myBoosts#9ae228e2 my_boosts:Vector chats:Vector users:Vector = premium.MyBoosts; - -premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector my_boost_slots:flags.2?Vector = premium.BoostsStatus; - -storyFwdHeader#b826e150 flags:# modified:flags.3?true from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader; - -postInteractionCountersMessage#e7058e7f msg_id:int views:int forwards:int reactions:int = PostInteractionCounters; -postInteractionCountersStory#8a480e27 story_id:int views:int forwards:int reactions:int = PostInteractionCounters; - -stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats; - -publicForwardMessage#1f2bf4a message:Message = PublicForward; -publicForwardStory#edf3add0 peer:Peer story:StoryItem = PublicForward; - -stats.publicForwards#93037e20 flags:# count:int forwards:Vector next_offset:flags.0?string chats:Vector users:Vector = stats.PublicForwards; - -peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor; -peerColorCollectible#b9c0639a flags:# collectible_id:long gift_emoji_id:long background_emoji_id:long accent_color:int colors:Vector dark_accent_color:flags.0?int dark_colors:flags.1?Vector = PeerColor; -inputPeerColorCollectible#b8ea86a9 collectible_id:long = PeerColor; - -help.peerColorSet#26219a58 colors:Vector = help.PeerColorSet; -help.peerColorProfileSet#767d61eb palette_colors:Vector bg_colors:Vector story_colors:Vector = help.PeerColorSet; - -help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption; - -help.peerColorsNotModified#2ba1f5ce = help.PeerColors; -help.peerColors#f8ed08 hash:int colors:Vector = help.PeerColors; - -storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction; -storyReactionPublicForward#bbab2643 message:Message = StoryReaction; -storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; - -stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; - -savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; -monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; - -messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; - -savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; - -messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; -messages.savedReactionTags#3259950a tags:Vector hash:long = messages.SavedReactionTags; - -outboxReadDate#3bb842ac date:int = OutboxReadDate; - -smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin; - -smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status; - -smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob; - -businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen; - -businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector = BusinessWorkHours; - -businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation; - -inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = InputBusinessRecipients; - -businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = BusinessRecipients; - -businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule; - -inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage; - -businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage; - -inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage; - -businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage; - -timezone#ff9289f5 id:string name:string utc_offset:int = Timezone; - -help.timezonesListNotModified#970708cc = help.TimezonesList; -help.timezonesList#7b74ed71 timezones:Vector hash:int = help.TimezonesList; - -quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply; - -inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut; -inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; - -messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; -messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; - -connectedBot#33ed001 flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights device:flags.0?string date:flags.1?int location:flags.2?string = ConnectedBot; - -account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; - -messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector = messages.DialogFilters; - -birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; - -botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; - -inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; - -businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro; - -messages.myStickers#faff629d count:int sets:Vector = messages.MyStickers; - -inputCollectibleUsername#e39460a9 username:string = InputCollectible; -inputCollectiblePhone#a2e214a4 phone:string = InputCollectible; - -fragment.collectibleInfo#6ebdff91 purchase_date:int currency:string amount:long crypto_currency:string crypto_amount:long url:string = fragment.CollectibleInfo; - -inputBusinessBotRecipients#c4e5921e flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = InputBusinessBotRecipients; - -businessBotRecipients#b88cf373 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = BusinessBotRecipients; - -contactBirthday#1d998733 contact_id:long birthday:Birthday = ContactBirthday; - -contacts.contactBirthdays#114ff30d contacts:Vector users:Vector = contacts.ContactBirthdays; - -missingInvitee#628c9224 flags:# premium_would_allow_invite:flags.0?true premium_required_for_pm:flags.1?true user_id:long = MissingInvitee; - -messages.invitedUsers#7f5defa6 updates:Updates missing_invitees:Vector = messages.InvitedUsers; - -inputBusinessChatLink#11679fa7 flags:# message:string entities:flags.0?Vector title:flags.1?string = InputBusinessChatLink; - -businessChatLink#b4ae666f flags:# link:string message:string entities:flags.0?Vector title:flags.1?string views:int = BusinessChatLink; - -account.businessChatLinks#ec43a2d1 links:Vector chats:Vector users:Vector = account.BusinessChatLinks; - -account.resolvedBusinessChatLinks#9a23af21 flags:# peer:Peer message:string entities:flags.0?Vector chats:Vector users:Vector = account.ResolvedBusinessChatLinks; - -requestedPeerUser#d62ff46a flags:# user_id:long first_name:flags.0?string last_name:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChat#7307544f flags:# chat_id:long title:flags.0?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChannel#8ba403e4 flags:# channel_id:long title:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; - -sponsoredMessageReportOption#430d3150 text:string option:bytes = SponsoredMessageReportOption; - -channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:Vector = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; - -reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; -reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; - -reactionsNotifySettings#71e4ea58 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom poll_votes_notify_from:flags.2?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; - -availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; - -messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; -messages.availableEffects#bddb616e hash:int effects:Vector documents:Vector = messages.AvailableEffects; - -factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck; - -starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer; -starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer; -starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; -starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; -starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; -starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; -starsTransactionPeerAds#60682812 = StarsTransactionPeer; -starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; - -starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; - -starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true posts_search:flags.24?true stargift_prepaid_upgrade:flags.25?true stargift_drop_original_details:flags.26?true phonegroup_message:flags.27?true stargift_auction_bid:flags.28?true offer:flags.29?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction; - -payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; - -foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; - -stories.foundStories#e2de7737 flags:# count:int stories:Vector next_offset:flags.0?string chats:Vector users:Vector = stories.FoundStories; - -geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; - -starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; - -payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; - -payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; - -payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl; - -inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; - -starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption; - -bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector = bots.PopularAppBots; - -botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia; - -bots.previewInfo#ca71d64 media:Vector lang_codes:Vector = bots.PreviewInfo; - -starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing; - -starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true bot_canceled:flags.7?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string title:flags.4?string photo:flags.5?WebDocument invoice_slug:flags.6?string = StarsSubscription; - -messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; - -starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; - -starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; - -starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift; -starGiftUnique#85f0a9cd flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true burned:flags.14?true crafted:flags.15?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int craft_chance_permille:flags.16?int = StarGift; - -payments.starGiftsNotModified#a388a368 = payments.StarGifts; -payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; - -messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; - -reportResultChooseOption#f0e4e0b6 title:string options:Vector = ReportResult; -reportResultAddComment#6f09ac31 flags:# optional:flags.0?true option:bytes = ReportResult; -reportResultReported#8db33c4b = ReportResult; - -messages.botPreparedInlineMessage#8ecf0511 id:string expire_date:int = messages.BotPreparedInlineMessage; - -messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult peer_types:Vector cache_time:int users:Vector = messages.PreparedInlineMessage; - -botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings; - -starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram; - -connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef; - -payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector = payments.ConnectedStarRefBots; - -payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; - -starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount; -starsTonAmount#74aee3e0 amount:long = StarsAmount; - -messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers; -messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector = messages.FoundStickers; - -botVerifierSettings#b0cd6617 flags:# can_modify_custom_description:flags.1?true icon:long company:string custom_description:flags.0?string = BotVerifierSettings; - -botVerification#f93cd45c bot_id:long icon:long description:string = BotVerification; - -starGiftAttributeModel#565251e2 flags:# crafted:flags.0?true name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributePattern#4e7085ea name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeBackdrop#9f2504e4 name:string backdrop_id:int center_color:int edge_color:int pattern_color:int text_color:int rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute; - -payments.starGiftUpgradePreview#3de1dfed sample_attributes:Vector prices:Vector next_prices:Vector = payments.StarGiftUpgradePreview; - -users.users#62d706b8 users:Vector = users.Users; -users.usersSlice#315a4974 count:int users:Vector = users.Users; - -payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector users:Vector = payments.UniqueStarGift; - -messages.webPagePreview#8c9a88ac media:MessageMedia chats:Vector users:Vector = messages.WebPagePreview; - -savedStarGift#41df43fc flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int can_craft_at:flags.20?int = SavedStarGift; - -payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; - -inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift; -inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift; -inputSavedStarGiftSlug#2085c238 slug:string = InputSavedStarGift; - -payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl; - -paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy; -paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy; -paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy; - -account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRevenue; - -requirementToContactEmpty#50a9839 = RequirementToContact; -requirementToContactPremium#e581e4e9 = RequirementToContact; -requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; - -businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; - -disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true disallow_stargifts_from_channels:flags.4?true = DisallowedGiftsSettings; - -sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; - -contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; -contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; - -starGiftAttributeIdModel#48aaae3c document_id:long = StarGiftAttributeId; -starGiftAttributeIdPattern#4a162433 document_id:long = StarGiftAttributeId; -starGiftAttributeIdBackdrop#1f01c757 backdrop_id:int = StarGiftAttributeId; - -starGiftAttributeCounter#2eb1b658 attribute:StarGiftAttributeId count:int = StarGiftAttributeCounter; - -payments.resaleStarGifts#947a12df flags:# count:int gifts:Vector next_offset:flags.0?string attributes:flags.1?Vector attributes_hash:flags.1?long chats:Vector counters:flags.2?Vector users:Vector = payments.ResaleStarGifts; - -stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount; - -pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion; - -todoItem#cba9a52f id:int title:TextWithEntities = TodoItem; - -todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector = TodoList; - -todoCompletion#221bb5e4 id:int completed_by:Peer date:int = TodoCompletion; - -suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost; - -starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating; - -starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection; - -payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; -payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; - -storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; - -stories.albumsNotModified#564edaeb = stories.Albums; -stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; - -searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; - -payments.uniqueStarGiftValueInfo#512fe446 flags:# last_sale_on_fragment:flags.1?true value_is_average:flags.6?true currency:string value:long initial_sale_date:int initial_sale_stars:long initial_sale_price:long last_sale_date:flags.0?int last_sale_price:flags.0?long floor_price:flags.2?long average_price:flags.3?long listed_count:flags.4?int fragment_listed_count:flags.5?int fragment_listed_url:flags.5?string = payments.UniqueStarGiftValueInfo; - -profileTabPosts#b98cd696 = ProfileTab; -profileTabGifts#4d4bd46a = ProfileTab; -profileTabMedia#72c64955 = ProfileTab; -profileTabFiles#ab339c00 = ProfileTab; -profileTabMusic#9f27d26e = ProfileTab; -profileTabVoice#e477092e = ProfileTab; -profileTabLinks#d3656499 = ProfileTab; -profileTabGifs#a2c0f695 = ProfileTab; - -users.savedMusicNotModified#e3878aa4 count:int = users.SavedMusic; -users.savedMusic#34a2f297 count:int documents:Vector = users.SavedMusic; - -account.savedMusicIdsNotModified#4fc81d6e = account.SavedMusicIds; -account.savedMusicIds#998d6636 ids:Vector = account.SavedMusicIds; - -payments.checkCanSendGiftResultOk#374fa7ad = payments.CheckCanSendGiftResult; -payments.checkCanSendGiftResultFail#d5e58274 reason:TextWithEntities = payments.CheckCanSendGiftResult; - -inputChatThemeEmpty#83268483 = InputChatTheme; -inputChatTheme#c93de95c emoticon:string = InputChatTheme; -inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme; - -starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice; - -groupCallMessage#1a8afc7e flags:# from_admin:flags.1?true id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage; - -groupCallDonor#ee430c85 flags:# top:flags.0?true my:flags.1?true peer_id:flags.3?Peer stars:long = GroupCallDonor; - -phone.groupCallStars#9d1dbd26 total_stars:long top_donors:Vector chats:Vector users:Vector = phone.GroupCallStars; - -recentStory#711d692d flags:# live:flags.0?true max_id:flags.1?int = RecentStory; - -auctionBidLevel#310240cc pos:int amount:long date:int = AuctionBidLevel; - -starGiftAuctionStateNotModified#fe333952 = StarGiftAuctionState; -starGiftAuctionState#771a4e66 version:int start_date:int end_date:int min_bid_amount:long bid_levels:Vector top_bidders:Vector next_round_at:int last_gift_num:int gifts_left:int current_round:int total_rounds:int rounds:Vector = StarGiftAuctionState; -starGiftAuctionStateFinished#972dabbf flags:# start_date:int end_date:int average_price:long listed_count:flags.0?int fragment_listed_count:flags.1?int fragment_listed_url:flags.1?string = StarGiftAuctionState; - -starGiftAuctionUserState#2eeed1c4 flags:# returned:flags.1?true bid_amount:flags.0?long bid_date:flags.0?int min_bid_amount:flags.0?long bid_peer:flags.0?Peer acquired_count:int = StarGiftAuctionUserState; - -payments.starGiftAuctionState#6b39f4ec gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState timeout:int users:Vector chats:Vector = payments.StarGiftAuctionState; - -starGiftAuctionAcquiredGift#42b00348 flags:# name_hidden:flags.0?true peer:Peer date:int bid_amount:long round:int pos:int message:flags.1?TextWithEntities gift_num:flags.2?int = StarGiftAuctionAcquiredGift; - -payments.starGiftAuctionAcquiredGifts#7d5bd1f0 gifts:Vector users:Vector chats:Vector = payments.StarGiftAuctionAcquiredGifts; - -starGiftActiveAuctionState#d31bc45d gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState = StarGiftActiveAuctionState; - -payments.starGiftActiveAuctionsNotModified#db33dad0 = payments.StarGiftActiveAuctions; -payments.starGiftActiveAuctions#aef6abbc auctions:Vector users:Vector chats:Vector = payments.StarGiftActiveAuctions; - -inputStarGiftAuction#2e16c98 gift_id:long = InputStarGiftAuction; -inputStarGiftAuctionSlug#7ab58308 slug:string = InputStarGiftAuction; - -passkey#98613ebf flags:# id:string name:string date:int software_emoji_id:flags.0?long last_usage_date:flags.1?int = Passkey; - -account.passkeys#f8e0aa1c passkeys:Vector = account.Passkeys; - -account.passkeyRegistrationOptions#e16b5ce1 options:DataJSON = account.PasskeyRegistrationOptions; - -auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions; - -inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse; -inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse; - -inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential; -inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential; - -starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground; - -starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound; -starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound; - -payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector = payments.StarGiftUpgradeAttributes; - -messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome; - -messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo; -messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector plays_left:flags.0?int = messages.EmojiGameInfo; - -starGiftAttributeRarity#36437737 permille:int = StarGiftAttributeRarity; -starGiftAttributeRarityUncommon#dbce6389 = StarGiftAttributeRarity; -starGiftAttributeRarityRare#f08d516b = StarGiftAttributeRarity; -starGiftAttributeRarityEpic#78fbf3a8 = StarGiftAttributeRarity; -starGiftAttributeRarityLegendary#cef7e7a8 = StarGiftAttributeRarity; - -keyboardButtonStyle#4fdd3430 flags:# bg_primary:flags.0?true bg_danger:flags.1?true bg_success:flags.2?true icon:flags.3?long = KeyboardButtonStyle; - -inputMessageReadMetric#402b4495 msg_id:int view_id:long time_in_view_ms:int active_time_in_view_ms:int height_to_viewport_ratio_permille:int seen_range_ratio_permille:int = InputMessageReadMetric; - -bots.exportedBotToken#3c60b621 token:string = bots.ExportedBotToken; - -bots.requestedButton#f13bbcd7 webapp_req_id:string = bots.RequestedButton; - -messages.composedMessageWithAI#90d7adfa flags:# result_text:TextWithEntities diff_text:flags.0?TextWithEntities = messages.ComposedMessageWithAI; - -stats.pollStats#2999beed votes_graph:StatsGraph = stats.PollStats; - -inputAiComposeToneDefault#1fe9a9bf tone:string = InputAiComposeTone; -inputAiComposeToneID#773c080 id:long access_hash:long = InputAiComposeTone; -inputAiComposeToneSlug#1fa01357 slug:string = InputAiComposeTone; - -aiComposeTone#cff63ea9 flags:# creator:flags.0?true id:long access_hash:long slug:string title:string emoji_id:flags.1?long prompt:flags.4?string installs_count:flags.2?int author_id:flags.3?long example_english:flags.5?AiComposeToneExample = AiComposeTone; -aiComposeToneDefault#9bad6414 tone:string emoji_id:long title:string = AiComposeTone; - -aicompose.tonesNotModified#c1f46103 = aicompose.Tones; -aicompose.tones#6c9d0efe hash:long tones:Vector users:Vector = aicompose.Tones; - -aiComposeToneExample#f1d628ec from:TextWithEntities to:TextWithEntities = AiComposeToneExample; - -bots.accessSettings#dd1fbf93 flags:# restricted:flags.0?true add_users:flags.1?Vector = bots.AccessSettings; - -messages.chatInviteJoinResultOk#445663a7 updates:Updates = messages.ChatInviteJoinResult; -messages.chatInviteJoinResultWebView#774bbdf4 bot_id:long url:string query_id:long users:Vector = messages.ChatInviteJoinResult; - -joinChatBotResultApproved#ae152a69 = JoinChatBotResult; -joinChatBotResultDeclined#efa0194 = JoinChatBotResult; -joinChatBotResultQueued#98a3a840 = JoinChatBotResult; -joinChatBotResultWebView#d6e3b813 url:string = JoinChatBotResult; - -webDomainException#933ca597 flags:# domain:string url:string title:string favicon:flags.0?long = WebDomainException; - -account.webBrowserSettingsNotModified#c31c8f4e = account.WebBrowserSettings; -account.webBrowserSettings#79eb8cb3 flags:# open_external_browser:flags.0?true display_close_button:flags.1?true external_exceptions:Vector inapp_exceptions:Vector hash:long = account.WebBrowserSettings; - ----functions--- - -invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; -invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; -initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; -invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; -invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; -invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; -invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; -invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; -invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; -invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X; -invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X; - -auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; -auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; -auth.signIn#8d52a951 flags:# phone_number:string phone_code_hash:string phone_code:flags.0?string email_verification:flags.1?EmailVerification = auth.Authorization; -auth.logOut#3e72ba19 = auth.LoggedOut; -auth.resetAuthorizations#9fab0d1a = Bool; -auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; -auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; -auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; -auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; -auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; -auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; -auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; -auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode; -auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; -auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; -auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; -auth.acceptLoginToken#e894ad4d token:bytes = Authorization; -auth.checkRecoveryPassword#d36bf79 code:string = Bool; -auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; -auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool; -auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; -auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; -auth.checkPaidAuth#56e59f9c phone_number:string phone_code_hash:string form_id:long = auth.SentCode; -auth.initPasskeyLogin#518ad0b7 api_id:int api_hash:string = auth.PasskeyLoginOptions; -auth.finishPasskeyLogin#9857ad07 flags:# credential:InputPasskeyCredential from_dc_id:flags.0?int from_auth_key_id:flags.0?long = auth.Authorization; - -account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; -account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; -account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; -account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; -account.resetNotifySettings#db7e1747 = Bool; -account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; -account.updateStatus#6628562c offline:Bool = Bool; -account.getWallPapers#7967d36 hash:long = account.WallPapers; -account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool; -account.checkUsername#2714d86c username:string = Bool; -account.updateUsername#3e0bdd7c username:string = User; -account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; -account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; -account.deleteAccount#a2c0cf74 flags:# reason:string password:flags.0?InputCheckPasswordSRP = Bool; -account.getAccountTTL#8fc711d = AccountDaysTTL; -account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; -account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; -account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; -account.updateDeviceLocked#38df3532 period:int = Bool; -account.getAuthorizations#e320c158 = account.Authorizations; -account.resetAuthorization#df77f3bc hash:long = Bool; -account.getPassword#548a30f5 = account.Password; -account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; -account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; -account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; -account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; -account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; -account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; -account.resetWebAuthorization#2d01b9ef hash:long = Bool; -account.resetWebAuthorizations#682d2594 = Bool; -account.getAllSecureValues#b288bc7d = Vector; -account.getSecureValue#73665bc2 types:Vector = Vector; -account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; -account.deleteSecureValue#b880bc4b types:Vector = Bool; -account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm; -account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; -account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; -account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; -account.sendVerifyEmailCode#98e037bb purpose:EmailVerifyPurpose email:string = account.SentEmailCode; -account.verifyEmail#32da4cf purpose:EmailVerifyPurpose verification:EmailVerification = account.EmailVerified; -account.initTakeoutSession#8ef3eab0 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?long = account.Takeout; -account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; -account.confirmPasswordEmail#8fdf1920 code:string = Bool; -account.resendPasswordEmail#7a7f2a15 = Bool; -account.cancelPasswordEmail#c1cbd5b6 = Bool; -account.getContactSignUpNotification#9f07c728 = Bool; -account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; -account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true compare_stories:flags.2?true peer:flags.0?InputNotifyPeer = Updates; -account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; -account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; -account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; -account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; -account.resetWallPapers#bb3b9804 = Bool; -account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; -account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; -account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document; -account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool; -account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool; -account.getTheme#3a5869ec format:string theme:InputTheme = Theme; -account.getThemes#7206e458 format:string hash:long = account.Themes; -account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool; -account.getContentSettings#8b9b4dae = account.ContentSettings; -account.getMultiWallPapers#65ad71dc wallpapers:Vector = Vector; -account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings; -account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; -account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; -account.resetPassword#9308ce1b = account.ResetPasswordResult; -account.declinePasswordReset#4c9409f6 = Bool; -account.getChatThemes#d638de89 hash:long = account.Themes; -account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; -account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; -account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones; -account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone; -account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document; -account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool; -account.getDefaultEmojiStatuses#d6753386 hash:long = account.EmojiStatuses; -account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; -account.clearRecentEmojiStatuses#18201aae = Bool; -account.reorderUsernames#ef500eab order:Vector = Bool; -account.toggleUsername#58d6b376 username:string active:Bool = Bool; -account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList; -account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList; -account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings; -account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool; -account.deleteAutoSaveExceptions#53bc0020 = Bool; -account.invalidateSignInCodes#ca8ae8ba codes:Vector = Bool; -account.updateColor#684d214e flags:# for_profile:flags.1?true color:flags.2?PeerColor = Bool; -account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList; -account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses; -account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList; -account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool; -account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool; -account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool; -account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool; -account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates; -account.getConnectedBots#4ea4c80f = account.ConnectedBots; -account.getBotBusinessConnection#76a86270 connection_id:string = Updates; -account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool; -account.toggleConnectedBotPaused#646e1097 peer:InputPeer paused:Bool = Bool; -account.disablePeerConnectedBot#5e437ed9 peer:InputPeer = Bool; -account.updateBirthday#cc6e0c11 flags:# birthday:flags.0?Birthday = Bool; -account.createBusinessChatLink#8851e68e link:InputBusinessChatLink = BusinessChatLink; -account.editBusinessChatLink#8c3410af slug:string link:InputBusinessChatLink = BusinessChatLink; -account.deleteBusinessChatLink#60073674 slug:string = Bool; -account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks; -account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks; -account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool; -account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool; -account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings; -account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings; -account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses; -account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue; -account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool; -account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool; -account.saveMusic#b26732a9 flags:# unsave:flags.0?true id:InputDocument after_id:flags.1?InputDocument = Bool; -account.getSavedMusicIds#e09d5faf hash:long = account.SavedMusicIds; -account.getUniqueGiftChatThemes#e42ce9c9 offset:string limit:int hash:long = account.ChatThemes; -account.initPasskeyRegistration#429547e8 = account.PasskeyRegistrationOptions; -account.registerPasskey#55b41fd6 credential:InputPasskeyCredential = Passkey; -account.getPasskeys#ea1f0c52 = account.Passkeys; -account.deletePasskey#f5b5563f id:string = Bool; -account.confirmBotConnection#67ed1f68 bot_id:InputUser = Bool; -account.getWebBrowserSettings#56655768 hash:long = account.WebBrowserSettings; -account.updateWebBrowserSettings#9adf82fe flags:# open_external_browser:flags.0?true display_close_button:flags.1?true = account.WebBrowserSettings; -account.toggleWebBrowserSettingsException#2d0a0571 flags:# delete:flags.1?true open_external_browser:flags.0?Bool url:string = Bool; -account.deleteWebBrowserSettingsExceptions#86a0765d = account.WebBrowserSettings; - -users.getUsers#d91a548 id:Vector = Vector; -users.getFullUser#b60f5918 id:InputUser = users.UserFull; -users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; -users.getRequirementsToContact#d89a83a3 id:Vector = Vector; -users.getSavedMusic#788d7fe3 id:InputUser offset:int limit:int hash:long = users.SavedMusic; -users.getSavedMusicByID#7573a4e9 id:InputUser documents:Vector = users.SavedMusic; -users.suggestBirthday#fc533372 id:InputUser birthday:Birthday = Updates; - -contacts.getContactIDs#7adc669d hash:long = Vector; -contacts.getStatuses#c4a353ee = Vector; -contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; -contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; -contacts.deleteContacts#96a0e00 id:Vector = Updates; -contacts.deleteByPhones#1013fd9e phones:Vector = Bool; -contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; -contacts.search#11f812d8 q:string limit:int = contacts.Found; -contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer; -contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true bots_guestchat:flags.17?true offset:int limit:int hash:long = contacts.TopPeers; -contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; -contacts.resetSaved#879537f1 = Bool; -contacts.getSaved#82f1e39f = Vector; -contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; -contacts.addContact#d9ba2e54 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string note:flags.1?TextWithEntities = Updates; -contacts.acceptContact#f831a20f id:InputUser = Updates; -contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates; -contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates; -contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer; -contacts.exportContactToken#f8654027 = ExportedContactToken; -contacts.importContactToken#13005788 token:string = User; -contacts.editCloseFriends#ba6705f0 id:Vector = Bool; -contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector limit:int = Bool; -contacts.getBirthdays#daeda864 = contacts.ContactBirthdays; -contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers; -contacts.updateContactNote#139f63fb id:InputUser note:TextWithEntities = Bool; - -messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; -messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; -messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; -messages.receivedMessages#5a954c0 max_id:int = Vector; -messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; -messages.sendMessage#545cd15a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.sendMedia#330e77f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.forwardMessages#13704a7c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; -messages.reportSpam#cf1592db peer:InputPeer = Bool; -messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; -messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; -messages.getChats#49e9528f id:Vector = messages.Chats; -messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; -messages.editChatTitle#73783ffd chat_id:long title:string = Updates; -messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates; -messages.addChatUser#cbc6d107 chat_id:long user_id:InputUser fwd_limit:int = messages.InvitedUsers; -messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates; -messages.createChat#92ceddd4 flags:# users:Vector title:string ttl_period:flags.0?int = messages.InvitedUsers; -messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; -messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; -messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; -messages.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool; -messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; -messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; -messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; -messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.receivedQueue#55a5bb66 max_qts:int = Vector; -messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; -messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; -messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers; -messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers; -messages.getWebPagePreview#570d6f6f flags:# message:string entities:flags.3?Vector = messages.WebPagePreview; -messages.exportChatInvite#a455de90 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string subscription_pricing:flags.5?StarsSubscriptionPricing = ExportedChatInvite; -messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; -messages.importChatInvite#de91436e hash:string = messages.ChatInviteJoinResult; -messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet; -messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; -messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; -messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; -messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool = messages.MessageViews; -messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; -messages.migrateChat#a2875319 chat_id:long = Updates; -messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true groups_only:flags.2?true users_only:flags.3?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; -messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Bool; -messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document; -messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; -messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; -messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; -messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool; -messages.sendInlineBotResult#c0cf7646 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut allow_paid_stars:flags.21?long = Updates; -messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; -messages.editMessage#51e842e1 flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.15?int schedule_repeat_period:flags.18?int quick_reply_shortcut_id:flags.17?int = Updates; -messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector = Bool; -messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; -messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; -messages.saveDraft#54ae308e flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost = Bool; -messages.getAllDrafts#6a3f8d65 = Updates; -messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; -messages.readFeaturedStickers#5b118126 id:Vector = Bool; -messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; -messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; -messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; -messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers; -messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; -messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; -messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; -messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; -messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; -messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; -messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats; -messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage; -messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; -messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; -messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; -messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; -messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia; -messages.sendScreenshotNotification#a1405817 peer:InputPeer reply_to:InputReplyTo random_id:long = Updates; -messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers; -messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; -messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; -messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; -messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSplitRanges#1cff7e08 = Vector; -messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool; -messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector; -messages.clearAllDrafts#7e58ee9c = Bool; -messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates; -messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; -messages.getPollResults#eda3e33b peer:InputPeer msg_id:int poll_hash:long = Updates; -messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; -messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; -messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; -messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; -messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; -messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; -messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; -messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector = Vector; -messages.requestUrlAuth#894cc99c flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string in_app_origin:flags.3?string = UrlAuthResult; -messages.acceptUrlAuth#67a3f0de flags:# write_allowed:flags.0?true share_phone_number:flags.3?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string match_code:flags.4?string = UrlAuthResult; -messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; -messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages; -messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; -messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector = Updates; -messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector = Updates; -messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList; -messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector = Bool; -messages.getDialogFilters#efd48c89 = messages.DialogFilters; -messages.getSuggestedDialogFilters#a29cd42c = Vector; -messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool; -messages.updateDialogFiltersOrder#c563c1e4 order:Vector = Bool; -messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers; -messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; -messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; -messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.deleteChat#5bd0ee50 chat_id:long = Bool; -messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; -messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; -messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport; -messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; -messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; -messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; -messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; -messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite; -messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; -messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; -messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; -messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true subscription_expired:flags.3?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; -messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; -messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; -messages.setChatTheme#81202c9 peer:InputPeer theme:InputChatTheme = Updates; -messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector; -messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; -messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; -messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; -messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; -messages.toggleNoForwards#b2081a35 flags:# peer:InputPeer enabled:Bool request_msg_id:flags.0?int = Updates; -messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; -messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector = Updates; -messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector = Updates; -messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList; -messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int paid_enabled:flags.1?Bool = Updates; -messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; -messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool; -messages.translateText#a5eec345 flags:# peer:flags.0?InputPeer id:flags.0?Vector text:flags.1?Vector to_lang:string tone:flags.2?string = messages.TranslatedText; -messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages; -messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; -messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; -messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; -messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; -messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; -messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true fullscreen:flags.8?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; -messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; -messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; -messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool; -messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector = Vector; -messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers; -messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers; -messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer = Bool; -messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions; -messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions; -messages.clearRecentReactions#9dfeefb4 = Bool; -messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector = Updates; -messages.setDefaultHistoryTTL#9eb51445 period:int = Bool; -messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL; -messages.sendBotRequestedPeer#6c5cf2a7 flags:# peer:InputPeer msg_id:flags.0?int webapp_req_id:flags.1?string button_id:int requested_peers:Vector = Updates; -messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups; -messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups; -messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups; -messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; -messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; -messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; -messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; -messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; -messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; -messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; -messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; -messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags; -messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; -messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; -messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate; -messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies; -messages.reorderQuickReplies#60331907 order:Vector = Bool; -messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool; -messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool; -messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool; -messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector hash:long = messages.Messages; -messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vector random_id:Vector = Updates; -messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; -messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; -messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; -messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; -messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; -messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; -messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; -messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; -messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates; -messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool; -messages.getPaidReactionPrivacy#472455aa = Updates; -messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; -messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; -messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; -messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages; -messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; -messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; -messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; -messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; -messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; -messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; -messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; -messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; -messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates; -messages.getForumTopics#3ba47bff flags:# peer:InputPeer q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; -messages.getForumTopicsByID#af0a4a08 peer:InputPeer topics:Vector = messages.ForumTopics; -messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates; -messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates; -messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector = Updates; -messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; -messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory; -messages.getEmojiGameInfo#fb7e8ca7 = messages.EmojiGameInfo; -messages.summarizeText#abbbd346 flags:# peer:InputPeer id:int to_lang:flags.0?string tone:flags.2?string = TextWithEntities; -messages.editChatCreator#f743b857 peer:InputPeer user_id:InputUser password:InputCheckPasswordSRP = Updates; -messages.getFutureChatCreatorAfterLeave#3b7d0ea6 peer:InputPeer = User; -messages.editChatParticipantRank#a00f32b0 peer:InputPeer participant:InputPeer rank:string = Updates; -messages.declineUrlAuth#35436bbc url:string = Bool; -messages.checkUrlAuthMatchCode#c9a47b0b url:string match_code:string = Bool; -messages.composeMessageWithAI#daecc589 flags:# proofread:flags.0?true emojify:flags.3?true text:TextWithEntities translate_to_lang:flags.1?string tone:flags.2?InputAiComposeTone = messages.ComposedMessageWithAI; -messages.reportReadMetrics#4067c5e6 peer:InputPeer metrics:Vector = Bool; -messages.reportMusicListen#ddbcd819 id:InputDocument listened_duration:int = Bool; -messages.addPollAnswer#19bc4b6d peer:InputPeer msg_id:int answer:PollAnswer = Updates; -messages.deletePollAnswer#ac8505a5 peer:InputPeer msg_id:int option:bytes = Updates; -messages.getUnreadPollVotes#43286cf2 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readPollVotes#1720b4d8 flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.setBotGuestChatResult#b8f106e3 query_id:long result:InputBotInlineResult = InputBotInlineMessageID; -messages.deleteParticipantReactions#a0b80cf8 peer:InputPeer participant:InputPeer = Bool; -messages.deleteParticipantReaction#e3b7f82c peer:InputPeer msg_id:int participant:InputPeer = Updates; -messages.getPersonalChannelHistory#55fb0996 user_id:InputUser limit:int max_id:int min_id:int hash:long = messages.Messages; - -updates.getState#edd4882a = updates.State; -updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; -updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; - -photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo; -photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo; -photos.deletePhotos#87cf7f2f id:Vector = Vector; -photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; -photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo; - -upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; -upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File; -upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; -upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; -upload.getCdnFile#395f69da file_token:bytes offset:long limit:int = upload.CdnFile; -upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; -upload.getCdnFileHashes#91dc3f31 file_token:bytes offset:long = Vector; -upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector; - -help.getConfig#c4f9186b = Config; -help.getNearestDc#1fb33026 = NearestDc; -help.getAppUpdate#522d5a7d source:string = help.AppUpdate; -help.getInviteText#4d392343 = help.InviteText; -help.getSupport#9cdf08cd = help.Support; -help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; -help.getCdnConfig#52029342 = CdnConfig; -help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; -help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; -help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; -help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; -help.getAppConfig#61e3f854 hash:int = help.AppConfig; -help.saveAppLog#6f02f748 events:Vector = Bool; -help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; -help.getSupportName#d360e72c = help.SupportName; -help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; -help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; -help.getPromoData#c0977421 = help.PromoData; -help.hidePromoData#1e251c95 peer:InputPeer = Bool; -help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; -help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; -help.getPremiumPromo#b81b93d4 = help.PremiumPromo; -help.getPeerColors#da80f42f hash:int = help.PeerColors; -help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors; -help.getTimezonesList#49b30240 hash:int = help.TimezonesList; - -channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; -channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; -channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector = Bool; -channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; -channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; -channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; -channels.getChannels#a7f6bbb id:Vector = messages.Chats; -channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; -channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates; -channels.editAdmin#9a98ad68 flags:# channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:flags.0?string = Updates; -channels.editTitle#566decd0 channel:InputChannel title:string = Updates; -channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; -channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; -channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; -channels.joinChannel#7f6a1e22 channel:InputChannel = messages.ChatInviteJoinResult; -channels.leaveChannel#f836aa95 channel:InputChannel = Updates; -channels.inviteToChannel#c9e33d54 channel:InputChannel users:Vector = messages.InvitedUsers; -channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; -channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; -channels.toggleSignatures#418d549c flags:# signatures_enabled:flags.0?true profiles_enabled:flags.1?true channel:InputChannel = Updates; -channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_personal:flags.2?true = messages.Chats; -channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; -channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; -channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; -channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates; -channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; -channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; -channels.getGroupsForDiscussion#f5dad378 = messages.Chats; -channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; -channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; -channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; -channels.getInactiveChannels#11e831ee = messages.InactiveChats; -channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; -channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true for_live_stories:flags.1?true peer:InputPeer = channels.SendAsPeers; -channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory; -channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates; -channels.toggleJoinRequest#ecc2618 flags:# apply_to_invites:flags.1?true channel:InputChannel enabled:Bool guard_bot:flags.0?InputUser = Updates; -channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector = Bool; -channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool; -channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool; -channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates; -channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates; -channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool; -channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; -channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates; -channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; -channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats; -channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates; -channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates; -channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; -channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; -channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; -channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; -channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; -channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood; -channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool; - -bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; -bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; -bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector = Bool; -bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool; -bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector; -bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool; -bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton; -bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool; -bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool; -bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool; -bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo; -bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector = Bool; -bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool; -bots.canSendMessage#1359f4e6 bot:InputUser = Bool; -bots.allowSendMessage#f132e3ef bot:InputUser = Updates; -bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; -bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; -bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia; -bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia; -bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector = Bool; -bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector = Bool; -bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo; -bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; -bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool; -bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; -bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; -bots.getAdminedBots#b0711d83 = Vector; -bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram; -bots.setCustomVerification#8b89dfbd flags:# enabled:flags.1?true bot:flags.0?InputUser peer:InputPeer custom_description:flags.2?string = Bool; -bots.getBotRecommendations#a1b70815 bot:InputUser = users.Users; -bots.checkUsername#87f2219b username:string = Bool; -bots.createBot#e5b17f2b flags:# via_deeplink:flags.0?true name:string username:string manager_id:InputUser = User; -bots.exportBotToken#bd0d99eb bot:InputUser revoke:Bool = bots.ExportedBotToken; -bots.requestWebViewButton#31a2a35e user_id:InputUser button:KeyboardButton = bots.RequestedButton; -bots.getRequestedWebViewButton#bf25b7f3 bot:InputUser webapp_req_id:string = KeyboardButton; -bots.getAccessSettings#213853a3 bot:InputUser = bots.AccessSettings; -bots.editAccessSettings#31813cd8 flags:# restricted:flags.0?true bot:InputUser add_users:flags.1?Vector = Bool; -bots.setJoinChatResults#e71a4810 query_id:long result:JoinChatBotResult = Bool; - -payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; -payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; -payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; -payments.sendPaymentForm#2d03522f flags:# form_id:long invoice:InputInvoice requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; -payments.getSavedInfo#227d824b = payments.SavedInfo; -payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; -payments.getBankCardData#2e79d779 number:string = payments.BankCardData; -payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; -payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; -payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; -payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector; -payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; -payments.applyGiftCode#f6e26854 slug:string = Updates; -payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; -payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; -payments.getStarsTopupOptions#c00ec7d3 = Vector; -payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus; -payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; -payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult; -payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; -payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats; -payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; -payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; -payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector = payments.StarsStatus; -payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; -payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; -payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; -payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; -payments.getStarsGiveawayOptions#bd1efd3e = Vector; -payments.getStarGifts#c4563590 hash:int = payments.StarGifts; -payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool; -payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool; -payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; -payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; -payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots; -payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; -payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview; -payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates; -payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates; -payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift; -payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_unique:flags.4?true sort_by_value:flags.5?true exclude_upgradable:flags.7?true exclude_unupgradable:flags.8?true peer_color_available:flags.9?true exclude_hosted:flags.10?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts; -payments.getSavedStarGift#b455a106 stargift:Vector = payments.SavedStarGifts; -payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; -payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; -payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; -payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; -payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true for_craft:flags.4?true stars_only:flags.5?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; -payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; -payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; -payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; -payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector = Bool; -payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool; -payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections; -payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo; -payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult; -payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState; -payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts; -payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions; -payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates; -payments.sendStarGiftOffer#8fb86b41 flags:# peer:InputPeer slug:string price:StarsAmount duration:int random_id:long allow_paid_stars:flags.0?long = Updates; -payments.getStarGiftUpgradeAttributes#6d038b58 gift_id:long = payments.StarGiftUpgradeAttributes; -payments.getCraftStarGifts#fd05dd00 gift_id:long offset:string limit:int = payments.SavedStarGifts; -payments.craftStarGift#b0f9684f stargift:Vector = Updates; - -stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; -stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; -stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; -stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; -stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet; -stickers.checkShortName#284b3639 short_name:string = Bool; -stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName; -stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet; -stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet; -stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool; -stickers.replaceSticker#4696459a sticker:InputDocument new_sticker:InputStickerSetItem = messages.StickerSet; - -phone.getCallConfig#55451fa9 = DataJSON; -phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; -phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; -phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; -phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; -phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; -phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; -phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; -phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates; -phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; -phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; -phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; -phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates; -phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; -phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; -phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; -phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; -phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; -phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; -phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; -phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; -phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; -phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; -phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; -phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates; -phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates; -phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels; -phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl; -phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool; -phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates; -phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector block:bytes = Updates; -phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates; -phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates; -phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates; -phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates; -phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates; -phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool; -phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector = Updates; -phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates; -phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars; -phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool; - -langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; -langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; -langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; -langpack.getLanguages#42c6978f lang_pack:string = Vector; -langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; - -folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; - -stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats; -stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; -stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; -stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards; -stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; -stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; -stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards; -stats.getPollStats#c27dfa68 flags:# dark:flags.0?true peer:InputPeer msg_id:int = stats.PollStats; - -chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; -chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; -chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector = ExportedChatlistInvite; -chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites; -chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite; -chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector = Updates; -chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates; -chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector = Updates; -chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool; -chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector; -chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector = Updates; - -stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount; -stories.sendStory#8f9e6898 flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector music:flags.9?InputDocument = Updates; -stories.editStory#2c63a72b flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector music:flags.4?InputDocument = Updates; -stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; -stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; -stories.getAllStories#eeb0d625 flags:# next:flags.1?true hidden:flags.2?true state:flags.0?string = stories.AllStories; -stories.getPinnedStories#5821a5dc peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector = stories.Stories; -stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool; -stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector; -stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector = Bool; -stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList; -stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector = stories.StoryViews; -stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; -stories.report#19d8eb45 peer:InputPeer id:Vector option:bytes message:string = ReportResult; -stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates; -stories.sendReaction#7fd736b2 flags:# add_to_recent:flags.0?true peer:InputPeer story_id:int reaction:Reaction = Updates; -stories.getPeerStories#2c4ada50 peer:InputPeer = stories.PeerStories; -stories.getAllReadPeerStories#9b5ae7f9 = Updates; -stories.getPeerMaxIDs#78499170 id:Vector = Vector; -stories.getChatsToSend#a56a8b60 = messages.Chats; -stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; -stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; -stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; -stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories; -stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector = StoryAlbum; -stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector add_stories:flags.2?Vector order:flags.3?Vector = StoryAlbum; -stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector = Bool; -stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool; -stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums; -stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories; -stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates; - -premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; -premium.getMyBoosts#be77b4a = premium.MyBoosts; -premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; -premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; -premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; - -smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin; -smsjobs.join#a74ece2d = Bool; -smsjobs.leave#9898ad73 = Bool; -smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool; -smsjobs.getStatus#10a698e8 = smsjobs.Status; -smsjobs.getSmsJob#778d902f job_id:string = SmsJob; -smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; - -fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; - -aicompose.createTone#4aa83913 flags:# display_author:flags.0?true emoji_id:long title:string prompt:string = AiComposeTone; -aicompose.updateTone#903bcf59 flags:# tone:InputAiComposeTone display_author:flags.0?Bool emoji_id:flags.1?long title:flags.2?string prompt:flags.3?string = AiComposeTone; -aicompose.saveTone#1782cbb1 tone:InputAiComposeTone unsave:Bool = Bool; -aicompose.deleteTone#dd39316a tone:InputAiComposeTone = Bool; -aicompose.getTone#b2e8ba03 tone:InputAiComposeTone = aicompose.Tones; -aicompose.getTones#abd59201 hash:long = aicompose.Tones; -aicompose.getToneExample#d1b4ab14 tone:InputAiComposeTone num:int = AiComposeToneExample; - -// LAYER 226 diff --git a/internal/compat/layerwire/_schema/layer-227.tl b/internal/compat/layerwire/_schema/layer-227.tl deleted file mode 100644 index 2784293c..00000000 --- a/internal/compat/layerwire/_schema/layer-227.tl +++ /dev/null @@ -1,3039 +0,0 @@ -boolFalse#bc799737 = Bool; -boolTrue#997275b5 = Bool; - -true#3fedd339 = True; - -vector#1cb5c415 {t:Type} # [ t ] = Vector t; - -error#c4b9f9bb code:int text:string = Error; - -null#56730bcc = Null; - -inputPeerEmpty#7f3b18ea = InputPeer; -inputPeerSelf#7da07ec9 = InputPeer; -inputPeerChat#35a95cb9 chat_id:long = InputPeer; -inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; -inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer; -inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer; -inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer; - -inputUserEmpty#b98886cf = InputUser; -inputUserSelf#f7c1b13f = InputUser; -inputUser#f21158c6 user_id:long access_hash:long = InputUser; -inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser; - -inputPhoneContact#6a1dc4be flags:# client_id:long phone:string first_name:string last_name:string note:flags.0?TextWithEntities = InputContact; - -inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; -inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; -inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile; - -inputMediaEmpty#9664f57f = InputMedia; -inputMediaUploadedPhoto#7d8375da flags:# spoiler:flags.2?true live_photo:flags.3?true file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int video:flags.3?InputDocument = InputMedia; -inputMediaPhoto#e3af4434 flags:# spoiler:flags.1?true live_photo:flags.2?true id:InputPhoto ttl_seconds:flags.0?int video:flags.2?InputDocument = InputMedia; -inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; -inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; -inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; -inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; -inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; -inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; -inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; -inputMediaGame#d33f43f3 id:InputGame = InputMedia; -inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; -inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; -inputMediaPoll#883a4108 flags:# poll:Poll correct_answers:flags.0?Vector attached_media:flags.3?InputMedia solution:flags.1?string solution_entities:flags.1?Vector solution_media:flags.2?InputMedia = InputMedia; -inputMediaDice#e66fbf7b emoticon:string = InputMedia; -inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; -inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; -inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; -inputMediaTodo#9fc55fde todo:TodoList = InputMedia; -inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia; - -inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; -inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; -inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; - -inputGeoPointEmpty#e4c123d6 = InputGeoPoint; -inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint; - -inputPhotoEmpty#1cd7bf0d = InputPhoto; -inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; - -inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; -inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; -inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; -inputTakeoutFileLocation#29be5899 = InputFileLocation; -inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; -inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; -inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; -inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; -inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; - -peerUser#59511722 user_id:long = Peer; -peerChat#36c6019a chat_id:long = Peer; -peerChannel#a2a5371e channel_id:long = Peer; - -storage.fileUnknown#aa963b05 = storage.FileType; -storage.filePartial#40bc6f52 = storage.FileType; -storage.fileJpeg#7efe0e = storage.FileType; -storage.fileGif#cae1aadf = storage.FileType; -storage.filePng#a4f63c0 = storage.FileType; -storage.filePdf#ae1e508d = storage.FileType; -storage.fileMp3#528a0677 = storage.FileType; -storage.fileMov#4b09ebbc = storage.FileType; -storage.fileMp4#b3cea0e4 = storage.FileType; -storage.fileWebp#1081464c = storage.FileType; - -userEmpty#d3bc4b7a id:long = User; -user#31774388 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true bot_business:flags2.11?true bot_has_main_app:flags2.13?true bot_forum_view:flags2.16?true bot_forum_can_manage_topics:flags2.17?true bot_can_manage_bots:flags2.18?true bot_guestchat:flags2.19?true bot_guard:flags2.20?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?RecentStory color:flags2.8?PeerColor profile_color:flags2.9?PeerColor bot_active_users:flags2.12?int bot_verification_icon:flags2.14?long send_paid_messages_stars:flags2.15?long = User; - -userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; -userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; - -userStatusEmpty#9d05049 = UserStatus; -userStatusOnline#edb93949 expires:int = UserStatus; -userStatusOffline#8c703f was_online:int = UserStatus; -userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus; -userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus; -userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; - -chatEmpty#29562865 id:long = Chat; -chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; -chatForbidden#6592a1a7 id:long title:string = Chat; -channel#1c32b11c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?RecentStory color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat; -channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true monoforum:flags.10?true id:long access_hash:long title:string until_date:flags.16?int = Chat; - -chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#a04e8d3a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab guard_bot_id:flags2.23?long = ChatFull; - -chatParticipant#38e79fde flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; -chatParticipantCreator#e1f867b8 flags:# user_id:long rank:flags.0?string = ChatParticipant; -chatParticipantAdmin#360d5d2 flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; - -chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants; -chatParticipants#3cbc93f8 chat_id:long participants:Vector version:int = ChatParticipants; - -chatPhotoEmpty#37c1011c = ChatPhoto; -chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; - -messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; -message#7600b9d3 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int from_rank:flags2.12?string peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long guestchat_via_from:flags2.19?Peer reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string rich_message:flags2.13?RichMessage = Message; -messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; - -messageMediaEmpty#3ded6320 = MessageMedia; -messageMediaPhoto#e216eb63 flags:# spoiler:flags.3?true live_photo:flags.4?true photo:flags.0?Photo ttl_seconds:flags.2?int video:flags.4?Document = MessageMedia; -messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; -messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; -messageMediaUnsupported#9f84f49e = MessageMedia; -messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; -messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; -messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; -messageMediaGame#fdb19008 game:Game = MessageMedia; -messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia; -messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia; -messageMediaPoll#773f4e66 flags:# poll:Poll results:PollResults attached_media:flags.0?MessageMedia = MessageMedia; -messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia; -messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; -messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; -messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; -messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; -messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector = MessageMedia; -messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia; - -messageActionEmpty#b6aef7b0 = MessageAction; -messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; -messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; -messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; -messageActionChatDeletePhoto#95e3fbef = MessageAction; -messageActionChatAddUser#15cefd00 users:Vector = MessageAction; -messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction; -messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction; -messageActionChannelCreate#95d2ac92 title:string = MessageAction; -messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction; -messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction; -messageActionPinMessage#94bd38ed = MessageAction; -messageActionHistoryClear#9fbab604 = MessageAction; -messageActionGameScore#92a72876 game_id:long score:int = MessageAction; -messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction; -messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction; -messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; -messageActionScreenshotTaken#4792929b = MessageAction; -messageActionCustomAction#fae69f56 message:string = MessageAction; -messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction; -messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; -messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; -messageActionContactSignUp#f3f25f76 = MessageAction; -messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction; -messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; -messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector = MessageAction; -messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction; -messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; -messageActionSetChatTheme#b91bbd3a theme:ChatTheme = MessageAction; -messageActionChatJoinedByRequest#ebbca3cb = MessageAction; -messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction; -messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction; -messageActionGiftPremium#48e91302 flags:# currency:string amount:long days:int crypto_currency:flags.0?string crypto_amount:flags.0?long message:flags.1?TextWithEntities = MessageAction; -messageActionTopicCreate#d999256 flags:# title_missing:flags.1?true title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction; -messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction; -messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; -messageActionRequestedPeer#31518e9b button_id:int peers:Vector = MessageAction; -messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; -messageActionGiftCode#31c48347 flags:# via_giveaway:flags.0?true unclaimed:flags.5?true boost_peer:flags.1?Peer days:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long message:flags.4?TextWithEntities = MessageAction; -messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction; -messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction; -messageActionBoostApply#cc02aa6d boosts:int = MessageAction; -messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; -messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; -messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; -messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; -messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction; -messageActionStarGiftUnique#e6c31522 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true craft:flags.16?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long can_craft_at:flags.15?int = MessageAction; -messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; -messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; -messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; -messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; -messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; -messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction; -messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction; -messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction; -messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction; -messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction; -messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction; -messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction; -messageActionNewCreatorPending#b07ed085 new_creator_id:long = MessageAction; -messageActionChangeCreator#e188503b new_creator_id:long = MessageAction; -messageActionNoForwardsToggle#bf7d6572 prev_value:Bool new_value:Bool = MessageAction; -messageActionNoForwardsRequest#3e2793ba flags:# expired:flags.0?true prev_value:Bool new_value:Bool = MessageAction; -messageActionPollAppendAnswer#9da1cd6c answer:PollAnswer = MessageAction; -messageActionPollDeleteAnswer#399674dc answer:PollAnswer = MessageAction; -messageActionManagedBotCreated#16605e3e bot_id:long = MessageAction; - -dialog#fc89f7f3 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; -dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; - -photoEmpty#2331b22d id:long = Photo; -photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = Photo; - -photoSizeEmpty#e17e23c type:string = PhotoSize; -photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; -photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; -photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; -photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; -photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; - -geoPointEmpty#1117dd5f = GeoPoint; -geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; - -auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; -auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; -auth.sentCodePaymentRequired#f8827ebf store_product:string phone_code_hash:string support_email_address:string support_email_subject:string premium_days:int currency:string amount:long = auth.SentCode; - -auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; -auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; - -auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; - -inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; -inputNotifyUsers#193b4417 = InputNotifyPeer; -inputNotifyChats#4a95e84e = InputNotifyPeer; -inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; -inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer; - -inputPeerNotifySettings#cacb6ae2 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_sound:flags.8?NotificationSound = InputPeerNotifySettings; - -peerNotifySettings#99622c0c flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_ios_sound:flags.8?NotificationSound stories_android_sound:flags.9?NotificationSound stories_other_sound:flags.10?NotificationSound = PeerNotifySettings; - -peerSettings#f47741f7 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true business_bot_paused:flags.11?true business_bot_can_reply:flags.12?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int business_bot_id:flags.13?long business_bot_manage_url:flags.13?string charge_paid_message_stars:flags.14?long registration_month:flags.15?string phone_country:flags.16?string name_change_date:flags.17?int photo_change_date:flags.18?int = PeerSettings; - -wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; -wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; - -inputReportReasonSpam#58dbcab8 = ReportReason; -inputReportReasonViolence#1e22c78d = ReportReason; -inputReportReasonPornography#2e59d922 = ReportReason; -inputReportReasonChildAbuse#adf44ee3 = ReportReason; -inputReportReasonOther#c1e4a2b1 = ReportReason; -inputReportReasonCopyright#9b89f93a = ReportReason; -inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; -inputReportReasonFake#f5ddd6e7 = ReportReason; -inputReportReasonIllegalDrugs#a8eb2be = ReportReason; -inputReportReasonPersonalDetails#9ec7863d = ReportReason; - -userFull#6cbe645 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true noforwards_my_enabled:flags2.23?true noforwards_peer_enabled:flags2.24?true unofficial_security_risk:flags2.26?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme:flags.15?ChatTheme private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int main_tab:flags2.20?ProfileTab saved_music:flags2.21?Document note:flags2.22?TextWithEntities bot_manager_id:flags2.25?long = UserFull; - -contact#145ade0b user_id:long mutual:Bool = Contact; - -importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; - -contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; - -contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; -contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; - -contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; - -contacts.blocked#ade1591 blocked:Vector chats:Vector users:Vector = contacts.Blocked; -contacts.blockedSlice#e1664194 count:int blocked:Vector chats:Vector users:Vector = contacts.Blocked; - -messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; -messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; - -messages.messages#1d73e7ea messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesSlice#5f206716 flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; -messages.messagesNotModified#74535f21 count:int = messages.Messages; - -messages.chats#64ff9fd5 chats:Vector = messages.Chats; -messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; - -messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; - -messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; - -inputMessagesFilterEmpty#57e2f66c = MessagesFilter; -inputMessagesFilterPhotos#9609a51c = MessagesFilter; -inputMessagesFilterVideo#9fc00e65 = MessagesFilter; -inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; -inputMessagesFilterDocument#9eddf188 = MessagesFilter; -inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; -inputMessagesFilterGif#ffc86587 = MessagesFilter; -inputMessagesFilterVoice#50f5c392 = MessagesFilter; -inputMessagesFilterMusic#3751b49e = MessagesFilter; -inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; -inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; -inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; -inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; -inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; -inputMessagesFilterGeo#e7026d0d = MessagesFilter; -inputMessagesFilterContacts#e062db83 = MessagesFilter; -inputMessagesFilterPinned#1bb00451 = MessagesFilter; -inputMessagesFilterPoll#fa2bc90a = MessagesFilter; - -updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; -updateMessageID#4e90bfd6 id:int random_id:long = Update; -updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; -updateUserTyping#2a17bf5c flags:# user_id:long top_msg_id:flags.0?int action:SendMessageAction = Update; -updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update; -updateChatParticipants#7761198 participants:ChatParticipants = Update; -updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; -updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector = Update; -updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update; -updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; -updateEncryptedChatTyping#1710f156 chat_id:int = Update; -updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; -updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; -updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update; -updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update; -updateDcOptions#8e5e9873 dc_options:Vector = Update; -updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; -updateServiceNotification#ebe46819 flags:# popup:flags.0?true invert_media:flags.2?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; -updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; -updateUserPhone#5492a13 user_id:long phone:string = Update; -updateReadHistoryInbox#9e84bc99 flags:# folder_id:flags.0?int peer:Peer top_msg_id:flags.1?int max_id:int still_unread_count:int pts:int pts_count:int = Update; -updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; -updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; -updateReadMessagesContents#f8227181 flags:# messages:Vector pts:int pts_count:int date:flags.0?int = Update; -updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; -updateChannel#635b4c09 channel_id:long = Update; -updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; -updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update; -updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; -updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; -updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; -updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Update; -updateStickerSets#31c24808 flags:# masks:flags.0?true emojis:flags.1?true = Update; -updateSavedGifs#9375341e = Update; -updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; -updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; -updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; -updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; -updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; -updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; -updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update; -updateReadFeaturedStickers#571d2742 = Update; -updateRecentStickers#9a422c20 = Update; -updateConfig#a229dd06 = Update; -updatePtsChanged#3354678f = Update; -updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update; -updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; -updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; -updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; -updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; -updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update; -updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; -updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; -updateLangPackTooLong#46560264 lang_code:string = Update; -updateLangPack#56022f4d difference:LangPackDifference = Update; -updateFavedStickers#e511996d = Update; -updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector = Update; -updateContactsReset#7084a7be = Update; -updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; -updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update; -updateMessagePoll#d64c522b flags:# peer:flags.1?Peer msg_id:flags.1?int top_msg_id:flags.2?int poll_id:long poll:flags.0?Poll results:PollResults = Update; -updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; -updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; -updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update; -updatePeerLocated#b4afcfb0 peers:Vector = Update; -updateNewScheduledMessage#39a51dfb message:Message = Update; -updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector sent_messages:flags.0?Vector = Update; -updateTheme#8216fba3 theme:Theme = Update; -updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update; -updateLoginToken#564fe691 = Update; -updateMessagePollVote#7699f014 poll_id:long peer:Peer options:Vector positions:Vector qts:int = Update; -updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update; -updateDialogFilterOrder#a5d72105 order:Vector = Update; -updateDialogFilters#3504914f = Update; -updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update; -updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update; -updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update; -updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update; -updatePeerBlocked#ebe07752 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer = Update; -updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; -updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; -updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector pts:int pts_count:int = Update; -updateChat#f89a6a4e chat_id:long = Update; -updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; -updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update; -updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; -updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; -updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update; -updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update; -updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; -updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; -updateBotChatInviteRequester#7cb34d79 flags:# peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int query_id:flags.0?long = Update; -updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update; -updateAttachMenuBots#17b7a20b = Update; -updateWebViewResultSent#1592b79d query_id:long = Update; -updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update; -updateSavedRingtones#74d8be99 = Update; -updateTranscribedAudio#84cd5a flags:# pending:flags.0?true peer:Peer msg_id:int transcription_id:long text:string = Update; -updateReadFeaturedEmojiStickers#fb4c496c = Update; -updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update; -updateRecentEmojiStatuses#30f443db = Update; -updateRecentReactions#6f7863f4 = Update; -updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update; -updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector = Update; -updateUser#20529438 user_id:long = Update; -updateAutoSaveSettings#ec05b097 = Update; -updateStory#75b3b798 peer:Peer story:StoryItem = Update; -updateReadStories#f74e932b peer:Peer max_id:int = Update; -updateStoryID#1bf335b9 id:int random_id:long = Update; -updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update; -updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update; -updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update; -updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update; -updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update; -updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector new_reactions:Vector qts:int = Update; -updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector qts:int = Update; -updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; -updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector = Update; -updateSavedReactionTags#39c67432 = Update; -updateSmsJob#f16269d4 job_id:string = Update; -updateQuickReplies#f9470ab2 quick_replies:Vector = Update; -updateNewQuickReply#f53da717 quick_reply:QuickReply = Update; -updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update; -updateQuickReplyMessage#3e050d0f message:Message = Update; -updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector = Update; -updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Update; -updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; -updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; -updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; -updateStarsBalance#4e80a379 balance:StarsAmount = Update; -updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; -updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; -updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; -updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; -updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; -updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; -updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; -updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update; -updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = Update; -updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update; -updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update; -updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector = Update; -updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector = Update; -updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update; -updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update; -updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update; -updateStarGiftCraftFail#ac072444 = Update; -updateChatParticipantRank#bd8367b9 chat_id:long user_id:long rank:string version:int = Update; -updateManagedBot#4880ed9a user_id:long bot_id:long qts:int = Update; -updateBotGuestChatQuery#cdd4093d flags:# query_id:long message:Message reference_messages:flags.0?Vector qts:int = Update; -updateAiComposeTones#8c0f91fb = Update; -updateJoinChatWebViewDecision#bdac7e70 peer:Peer query_id:long result:JoinChatBotResult = Update; -updateNewBotConnection#b22083a6 flags:# confirmed:flags.0?true bot_id:long date:flags.1?int device:flags.1?string location:flags.1?string = Update; -updateWebBrowserSettings#c39a2ade flags:# open_external_browser:flags.0?true display_close_button:flags.1?true = Update; -updateWebBrowserException#140502d1 flags:# delete:flags.1?true open_external_browser:flags.0?Bool exception:WebDomainException = Update; - -updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; - -updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; -updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; -updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; -updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; - -updatesTooLong#e317af7e = Updates; -updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; -updateShort#78d4dec1 update:Update date:int = Updates; -updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; -updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; -updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; -photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; - -photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; - -upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; -upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; - -dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; - -config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config; - -nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; - -help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate; -help.noAppUpdate#c45a6536 = help.AppUpdate; - -help.inviteText#18cb9f78 message:string = help.InviteText; - -encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; -encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat; -encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; -encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; -encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat; - -inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; - -encryptedFileEmpty#c21f497e = EncryptedFile; -encryptedFile#a8008cd8 id:long access_hash:long size:long dc_id:int key_fingerprint:int = EncryptedFile; - -inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; -inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; -inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; -inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; - -encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; -encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; - -messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; -messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; - -messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; -messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; - -inputDocumentEmpty#72f0eaae = InputDocument; -inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; - -documentEmpty#36f8c871 id:long = Document; -document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector video_thumbs:flags.1?Vector dc_id:int attributes:Vector = Document; - -help.support#17c6b5f6 phone_number:string user:User = help.Support; - -notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; -notifyUsers#b4c83b4c = NotifyPeer; -notifyChats#c007cec3 = NotifyPeer; -notifyBroadcasts#d612e8ef = NotifyPeer; -notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer; - -sendMessageTypingAction#16bf744e = SendMessageAction; -sendMessageCancelAction#fd5ec8f5 = SendMessageAction; -sendMessageRecordVideoAction#a187d66f = SendMessageAction; -sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; -sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; -sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; -sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; -sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; -sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; -sendMessageChooseContactAction#628cbc6f = SendMessageAction; -sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; -sendMessageRecordRoundAction#88f27fbc = SendMessageAction; -sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; -speakingInGroupCallAction#d92c2285 = SendMessageAction; -sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; -sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; -sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction; -sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction; -sendMessageTextDraftAction#376d975c random_id:long text:TextWithEntities = SendMessageAction; -inputSendMessageRichMessageDraftAction#e2b23b51 random_id:long rich_message:InputRichMessage = SendMessageAction; -sendMessageRichMessageDraftAction#a2cb24f9 random_id:long rich_message:RichMessage = SendMessageAction; - -contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; - -inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; -inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; -inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; -inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; -inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; -inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; -inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; -inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey; -inputPrivacyKeyVoiceMessages#aee69d68 = InputPrivacyKey; -inputPrivacyKeyAbout#3823cc40 = InputPrivacyKey; -inputPrivacyKeyBirthday#d65a11cc = InputPrivacyKey; -inputPrivacyKeyStarGiftsAutoSave#e1732341 = InputPrivacyKey; -inputPrivacyKeyNoPaidMessages#bdc597b4 = InputPrivacyKey; -inputPrivacyKeySavedMusic#4dbe9226 = InputPrivacyKey; - -privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; -privacyKeyChatInvite#500e6dfa = PrivacyKey; -privacyKeyPhoneCall#3d662b7b = PrivacyKey; -privacyKeyPhoneP2P#39491cc8 = PrivacyKey; -privacyKeyForwards#69ec56a3 = PrivacyKey; -privacyKeyProfilePhoto#96151fed = PrivacyKey; -privacyKeyPhoneNumber#d19ae46d = PrivacyKey; -privacyKeyAddedByPhone#42ffd42b = PrivacyKey; -privacyKeyVoiceMessages#697f414 = PrivacyKey; -privacyKeyAbout#a486b761 = PrivacyKey; -privacyKeyBirthday#2000a518 = PrivacyKey; -privacyKeyStarGiftsAutoSave#2ca4fdf8 = PrivacyKey; -privacyKeyNoPaidMessages#17d348d2 = PrivacyKey; -privacyKeySavedMusic#ff7a571b = PrivacyKey; - -inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; -inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; -inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; -inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; -inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; -inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; -inputPrivacyValueAllowChatParticipants#840649cf chats:Vector = InputPrivacyRule; -inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector = InputPrivacyRule; -inputPrivacyValueAllowCloseFriends#2f453e49 = InputPrivacyRule; -inputPrivacyValueAllowPremium#77cdc9f1 = InputPrivacyRule; -inputPrivacyValueAllowBots#5a4fcce5 = InputPrivacyRule; -inputPrivacyValueDisallowBots#c4e57915 = InputPrivacyRule; - -privacyValueAllowContacts#fffe1bac = PrivacyRule; -privacyValueAllowAll#65427b82 = PrivacyRule; -privacyValueAllowUsers#b8905fb2 users:Vector = PrivacyRule; -privacyValueDisallowContacts#f888fa1a = PrivacyRule; -privacyValueDisallowAll#8b73e763 = PrivacyRule; -privacyValueDisallowUsers#e4621141 users:Vector = PrivacyRule; -privacyValueAllowChatParticipants#6b134e8e chats:Vector = PrivacyRule; -privacyValueDisallowChatParticipants#41c87565 chats:Vector = PrivacyRule; -privacyValueAllowCloseFriends#f7e8d89b = PrivacyRule; -privacyValueAllowPremium#ece9814b = PrivacyRule; -privacyValueAllowBots#21461b5d = PrivacyRule; -privacyValueDisallowBots#f6a5f82f = PrivacyRule; - -account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; - -accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; - -documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; -documentAttributeAnimated#11b58939 = DocumentAttribute; -documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; -documentAttributeVideo#43c57c48 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double video_codec:flags.5?string = DocumentAttribute; -documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; -documentAttributeFilename#15590068 file_name:string = DocumentAttribute; -documentAttributeHasStickers#9801d2f7 = DocumentAttribute; -documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute; - -messages.stickersNotModified#f1749a22 = messages.Stickers; -messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; - -stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; - -messages.allStickersNotModified#e86602c3 = messages.AllStickers; -messages.allStickers#cdbbcebb hash:long sets:Vector = messages.AllStickers; - -messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; - -webPageEmpty#211a1788 flags:# id:long url:flags.0?string = WebPage; -webPagePending#b0d13e47 flags:# id:long url:flags.0?string date:int = WebPage; -webPage#e89c45b2 flags:# has_large_media:flags.13?true video_cover_photo:flags.14?true id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector = WebPage; -webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; - -authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; - -account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector = account.Authorizations; - -account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password; - -account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; - -account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; - -auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; - -receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; - -chatInviteExported#a22cbd96 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int subscription_expired:flags.10?int title:flags.8?string subscription_pricing:flags.9?StarsSubscriptionPricing = ExportedChatInvite; -chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite; - -chatInviteAlready#5a686d7c chat:Chat = ChatInvite; -chatInvite#5c9d3702 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true can_refulfill_subscription:flags.11?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector color:int subscription_pricing:flags.10?StarsSubscriptionPricing subscription_form_id:flags.12?long bot_verification:flags.13?BotVerification = ChatInvite; -chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; - -inputStickerSetEmpty#ffb62b95 = InputStickerSet; -inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; -inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; -inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; -inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; -inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; -inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet; -inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet; -inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; -inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; -inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet; -inputStickerSetTonGifts#1cf671a0 = InputStickerSet; - -stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; - -messages.stickerSet#6e153f16 set:StickerSet packs:Vector keywords:Vector documents:Vector = messages.StickerSet; -messages.stickerSetNotModified#d3f924eb = messages.StickerSet; - -botCommand#c27ac8c7 command:string description:string = BotCommand; - -botInfo#4d8a0299 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton privacy_policy_url:flags.7?string app_settings:flags.8?BotAppSettings verifier_settings:flags.9?BotVerifierSettings = BotInfo; - -keyboardButton#7d170cff flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrl#d80c25ec flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonCallback#e62bc960 flags:# requires_password:flags.0?true style:flags.10?KeyboardButtonStyle text:string data:bytes = KeyboardButton; -keyboardButtonRequestPhone#417efd8f flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonRequestGeoLocation#aa40f94d flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonSwitchInline#991399fc flags:# same_peer:flags.0?true style:flags.10?KeyboardButtonStyle text:string query:string peer_types:flags.1?Vector = KeyboardButton; -keyboardButtonGame#89c590f9 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonBuy#3fa53905 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; -keyboardButtonUrlAuth#f51006f9 flags:# style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; -inputKeyboardButtonUrlAuth#68013e72 flags:# request_write_access:flags.0?true style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; -keyboardButtonRequestPoll#7a11d782 flags:# style:flags.10?KeyboardButtonStyle quiz:flags.0?Bool text:string = KeyboardButton; -inputKeyboardButtonUserProfile#7d5e07c7 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:InputUser = KeyboardButton; -keyboardButtonUserProfile#c0fd5d09 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:long = KeyboardButton; -keyboardButtonWebView#e846b1a0 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonSimpleWebView#e15c4370 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; -keyboardButtonRequestPeer#5b0f15f5 flags:# style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -inputKeyboardButtonRequestPeer#2b78156 flags:# name_requested:flags.0?true username_requested:flags.1?true photo_requested:flags.2?true style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; -keyboardButtonCopy#bcc4af10 flags:# style:flags.10?KeyboardButtonStyle text:string copy_text:string = KeyboardButton; - -keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; - -replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; -replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup; -replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector placeholder:flags.3?string = ReplyMarkup; -replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; - -messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; -messageEntityMention#fa04579d offset:int length:int = MessageEntity; -messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; -messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; -messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; -messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; -messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; -messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; -messageEntityCode#28a20571 offset:int length:int = MessageEntity; -messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; -messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; -messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity; -inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; -messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; -messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; -messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity; -messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; -messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; -messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; -messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; -messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity; -messageEntityFormattedDate#904ac7c7 flags:# relative:flags.0?true short_time:flags.1?true long_time:flags.2?true short_date:flags.3?true long_date:flags.4?true day_of_week:flags.5?true offset:int length:int date:int = MessageEntity; -messageEntityDiffInsert#71777116 offset:int length:int = MessageEntity; -messageEntityDiffReplace#c6c1e5a7 offset:int length:int old_text:string = MessageEntity; -messageEntityDiffDelete#652c1c5 offset:int length:int = MessageEntity; - -inputChannelEmpty#ee8c1e86 = InputChannel; -inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; -inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel; - -contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; - -messageRange#ae30253 min_id:int max_id:int = MessageRange; - -updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; -updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; -updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; - -channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; -channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; - -channelParticipant#1bd54456 flags:# user_id:long date:int subscription_until_date:flags.0?int rank:flags.2?string = ChannelParticipant; -channelParticipantSelf#a9478a1a flags:# via_request:flags.0?true user_id:long inviter_id:long date:int subscription_until_date:flags.1?int rank:flags.2?string = ChannelParticipant; -channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; -channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; -channelParticipantBanned#d5f0ad91 flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights rank:flags.2?string = ChannelParticipant; -channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; - -channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; -channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; -channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; -channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; -channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; -channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; -channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; -channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; - -channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; -channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; - -channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; - -help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; - -messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; -messages.savedGifs#84a02a0d hash:long gifs:Vector = messages.SavedGifs; - -inputBotInlineMessageMediaAuto#3380c786 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageMediaWebPage#bddcc510 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true optional:flags.6?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; -inputBotInlineMessageRichMessage#b43df56c flags:# reply_markup:flags.2?ReplyMarkup rich_message:InputRichMessage = InputBotInlineMessage; - -inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; -inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; - -botInlineMessageMediaAuto#764cf810 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; -botInlineMessageRichMessage#a617e7b flags:# reply_markup:flags.2?ReplyMarkup rich_message:RichMessage = BotInlineMessage; - -botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; -botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; - -messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector cache_time:int users:Vector = messages.BotResults; - -exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; - -messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader; - -auth.codeTypeSms#72a3158c = auth.CodeType; -auth.codeTypeCall#741cd3e3 = auth.CodeType; -auth.codeTypeFlashCall#226ccefb = auth.CodeType; -auth.codeTypeMissedCall#d61ad6ee = auth.CodeType; -auth.codeTypeFragmentSms#6ed998c = auth.CodeType; - -auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; -auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; -auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; -auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; -auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType; -auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; -auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; -auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; -auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; -auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; -auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; - -messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; - -messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; - -inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; -inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID; - -inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; - -messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; - -topPeer#edcdc05b peer:Peer rating:double = TopPeer; - -topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; -topPeerCategoryBotsInline#148677e2 = TopPeerCategory; -topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; -topPeerCategoryGroups#bd17a14a = TopPeerCategory; -topPeerCategoryChannels#161d9628 = TopPeerCategory; -topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; -topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; -topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; -topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory; -topPeerCategoryBotsGuestChat#6c24f3dd = TopPeerCategory; - -topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; - -contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; -contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; -contacts.topPeersDisabled#b52c939d = contacts.TopPeers; - -draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; -draftMessage#60fe3294 flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost rich_message:flags.9?RichMessage = DraftMessage; - -messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; -messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; - -messages.recentStickersNotModified#b17f890 = messages.RecentStickers; -messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; - -messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; - -messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; -messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; - -stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; -stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; -stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector keywords:Vector documents:Vector = StickerSetCovered; -stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered; - -maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; - -inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; -inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; - -game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; - -inputGameID#32c3e77 id:long access_hash:long = InputGame; -inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; - -highScore#73a379eb pos:int user_id:long score:int = HighScore; - -messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; - -textEmpty#dc3d824f = RichText; -textPlain#744694e0 text:string = RichText; -textBold#6724abc4 text:RichText = RichText; -textItalic#d912a59c text:RichText = RichText; -textUnderline#c12622c4 text:RichText = RichText; -textStrike#9bf8bb95 text:RichText = RichText; -textFixed#6c3f19b9 text:RichText = RichText; -textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; -textEmail#de5a0dd6 text:RichText email:string = RichText; -textConcat#7e6260d7 texts:Vector = RichText; -textSubscript#ed6a8504 text:RichText = RichText; -textSuperscript#c7fb5e01 text:RichText = RichText; -textMarked#34b8621 text:RichText = RichText; -textPhone#1ccb966a text:RichText phone:string = RichText; -textImage#81ccf4f document_id:long w:int h:int = RichText; -textAnchor#35553762 text:RichText name:string = RichText; -textMath#9d2eac97 source:string = RichText; -textCustomEmoji#a26156c0 document_id:long alt:string = RichText; -textSpoiler#4c2a5d62 text:RichText = RichText; -textMention#cd24cf44 text:RichText = RichText; -textHashtag#519524ea text:RichText = RichText; -textBotCommand#2ff29d3 text:RichText = RichText; -textCashtag#7b9e1801 text:RichText = RichText; -textAutoUrl#ac6a83aa text:RichText = RichText; -textAutoEmail#c556a45d text:RichText = RichText; -textAutoPhone#24c26789 text:RichText = RichText; -textBankCard#b956812d text:RichText = RichText; -textMentionName#1a9fbfc text:RichText user_id:long = RichText; -textDate#a5b45e2b flags:# relative:flags.0?true short_time:flags.1?true long_time:flags.2?true short_date:flags.3?true long_date:flags.4?true day_of_week:flags.5?true text:RichText date:int = RichText; - -pageBlockUnsupported#13567e8a = PageBlock; -pageBlockTitle#70abc3fd text:RichText = PageBlock; -pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; -pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; -pageBlockHeader#bfd064ec text:RichText = PageBlock; -pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; -pageBlockParagraph#467a0766 text:RichText = PageBlock; -pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; -pageBlockFooter#48870999 text:RichText = PageBlock; -pageBlockDivider#db20b188 = PageBlock; -pageBlockAnchor#ce0d37b0 name:string = PageBlock; -pageBlockList#e4e88011 items:Vector = PageBlock; -pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; -pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; -pageBlockPhoto#1759c560 flags:# spoiler:flags.1?true photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; -pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true spoiler:flags.2?true video_id:long caption:PageCaption = PageBlock; -pageBlockCover#39f23300 cover:PageBlock = PageBlock; -pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; -pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; -pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; -pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; -pageBlockChannel#ef1751b5 channel:Chat = PageBlock; -pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; -pageBlockKicker#1e148390 text:RichText = PageBlock; -pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; -pageBlockOrderedList#1fd6f6c1 flags:# reversed:flags.2?true items:Vector start:flags.0?int type:flags.1?string = PageBlock; -pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; -pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; -pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; -pageBlockHeading1#baff072f text:RichText = PageBlock; -pageBlockHeading2#96b2aec text:RichText = PageBlock; -pageBlockHeading3#67e731ad text:RichText = PageBlock; -pageBlockHeading4#b532772b text:RichText = PageBlock; -pageBlockHeading5#dbbe6c6a text:RichText = PageBlock; -pageBlockHeading6#682a41a9 text:RichText = PageBlock; -pageBlockMath#59080c20 source:string = PageBlock; -pageBlockThinking#3c29a3e2 text:RichText = PageBlock; -inputPageBlockMap#574b617f geo:InputGeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; -pageBlockBlockquoteBlocks#e6e47c4 blocks:Vector caption:RichText = PageBlock; - -phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; -phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; -phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; -phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; -phoneCallDiscardReasonMigrateConferenceCall#9fbbf1f7 slug:string = PhoneCallDiscardReason; - -dataJSON#7d748d04 data:string = DataJSON; - -labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; - -invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector terms_url:flags.10?string subscription_period:flags.11?int = Invoice; - -paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; - -postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; - -paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; - -paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; - -webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; -webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; - -inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; - -inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; -inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; -inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation; - -upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; - -payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector users:Vector = payments.PaymentForm; -payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector = payments.PaymentForm; -payments.paymentFormStarGift#b425cfe1 form_id:long invoice:Invoice = payments.PaymentForm; - -payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; - -payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; -payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; - -payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; -payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector = payments.PaymentReceipt; - -payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; - -inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; -inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; -inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials; - -account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; - -shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; - -inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem; - -inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; - -phoneCallEmpty#5366c915 id:long = PhoneCall; -phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; -phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall; -phoneCall#30535af5 flags:# p2p_allowed:flags.5?true video:flags.6?true conference_supported:flags.8?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int custom_parameters:flags.7?DataJSON = PhoneCall; -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; - -phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; -phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection; - -phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector = PhoneCallProtocol; - -phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; - -upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; -upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; - -cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; - -cdnConfig#5725e40a public_keys:Vector = CdnConfig; - -langPackString#cad181f6 key:string value:string = LangPackString; -langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; -langPackStringDeleted#2979eeb2 key:string = LangPackString; - -langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; - -langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; - -channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; -channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector new_value:Vector = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; -channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; -channelAdminLogEventActionToggleAutotranslation#c517f77e new_value:Bool = ChannelAdminLogEventAction; -channelAdminLogEventActionParticipantEditRank#5806b4ec user_id:long prev_rank:string new_rank:string = ChannelAdminLogEventAction; - -channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; - -channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; - -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true edit_rank:flags.19?true = ChannelAdminLogEventsFilter; - -popularContact#5ce14175 client_id:long importers:int = PopularContact; - -messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; -messages.favedStickers#2cb51097 hash:long packs:Vector stickers:Vector = messages.FavedStickers; - -recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; -recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl; -recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl; -recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; -recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; - -help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; - -inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; - -webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; - -account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; - -inputMessageID#a676a322 id:int = InputMessage; -inputMessageReplyTo#bad88395 id:int = InputMessage; -inputMessagePinned#86872538 = InputMessage; -inputMessageCallbackQuery#acfa1a7e id:int query_id:long = InputMessage; - -inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; -inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; - -dialogPeer#e56dbf05 peer:Peer = DialogPeer; -dialogPeerFolder#514519e2 folder_id:int = DialogPeer; - -messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; -messages.foundStickerSets#8af09dd2 hash:long sets:Vector = messages.FoundStickerSets; - -fileHash#f39b035c offset:long limit:int hash:bytes = FileHash; - -inputClientProxy#75588b3f address:string port:int = InputClientProxy; - -help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; -help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; - -inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; -inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; - -secureFileEmpty#64199744 = SecureFile; -secureFile#7d09c27e id:long access_hash:long size:long dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; - -secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; - -securePlainPhone#7d6099dd phone:string = SecurePlainData; -securePlainEmail#21ec5a5f email:string = SecurePlainData; - -secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; -secureValueTypePassport#3dac6a00 = SecureValueType; -secureValueTypeDriverLicense#6e425c4 = SecureValueType; -secureValueTypeIdentityCard#a0d0744b = SecureValueType; -secureValueTypeInternalPassport#99a48f23 = SecureValueType; -secureValueTypeAddress#cbe31e26 = SecureValueType; -secureValueTypeUtilityBill#fc36954e = SecureValueType; -secureValueTypeBankStatement#89137c0d = SecureValueType; -secureValueTypeRentalAgreement#8b883488 = SecureValueType; -secureValueTypePassportRegistration#99e3806a = SecureValueType; -secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; -secureValueTypePhone#b320aadb = SecureValueType; -secureValueTypeEmail#8e3ca7ee = SecureValueType; - -secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; - -inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; - -secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; - -secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; -secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; -secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; -secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; - -secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; - -account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; - -account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; - -help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; -help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; - -savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; - -account.takeout#4dba4501 id:long = account.Takeout; - -passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; -passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; - -securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; -securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; -securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; - -secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; - -inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; -inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; - -secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; -secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; - -help.passportConfigNotModified#bfb9f457 = help.PassportConfig; -help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; - -inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; - -jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; - -jsonNull#3f6d7b68 = JSONValue; -jsonBool#c7345e6a value:Bool = JSONValue; -jsonNumber#2be0dfa4 value:double = JSONValue; -jsonString#b71e767a value:string = JSONValue; -jsonArray#f7444763 value:Vector = JSONValue; -jsonObject#99c1d49d value:Vector = JSONValue; - -pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; - -pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; - -pageCaption#6f747657 text:RichText credit:RichText = PageCaption; - -pageListItemText#2f58683c flags:# checkbox:flags.0?true checked:flags.1?true text:RichText = PageListItem; -pageListItemBlocks#63ca67aa flags:# checkbox:flags.0?true checked:flags.1?true blocks:Vector = PageListItem; - -pageListOrderedItemText#15031189 flags:# checkbox:flags.0?true checked:flags.1?true num:flags.2?string text:RichText value:flags.3?int type:flags.4?string = PageListOrderedItem; -pageListOrderedItemBlocks#8ff2d5f0 flags:# checkbox:flags.0?true checked:flags.1?true num:flags.2?string blocks:Vector value:flags.3?int type:flags.4?string = PageListOrderedItem; - -pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; - -page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector views:flags.3?int = Page; - -help.supportName#8c05f1c9 name:string = help.SupportName; - -help.userInfoEmpty#f3ae2eed = help.UserInfo; -help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; - -pollAnswer#4b7d786a flags:# text:TextWithEntities option:bytes media:flags.0?MessageMedia added_by:flags.1?Peer date:flags.1?int = PollAnswer; -inputPollAnswer#199fed96 flags:# text:TextWithEntities media:flags.0?InputMedia = PollAnswer; - -poll#966e2dbf id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true open_answers:flags.6?true revoting_disabled:flags.7?true shuffle_answers:flags.8?true hide_results_until_close:flags.9?true creator:flags.10?true subscribers_only:flags.11?true question:TextWithEntities answers:Vector close_period:flags.4?int close_date:flags.5?int countries_iso2:flags.12?Vector hash:long = Poll; - -pollAnswerVoters#3645230a flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:flags.2?int recent_voters:flags.2?Vector = PollAnswerVoters; - -pollResults#ba7bb15e flags:# min:flags.0?true has_unread_votes:flags.6?true can_view_stats:flags.7?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector solution_media:flags.5?MessageMedia = PollResults; - -chatOnlines#f041e250 onlines:int = ChatOnlines; - -statsURL#47a971e0 url:string = StatsURL; - -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true manage_ranks:flags.18?true = ChatAdminRights; - -chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true edit_rank:flags.26?true send_reactions:flags.27?true until_date:int = ChatBannedRights; - -inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; -inputWallPaperSlug#72091c80 slug:string = InputWallPaper; -inputWallPaperNoFile#967a462e id:long = InputWallPaper; - -account.wallPapersNotModified#1c199183 = account.WallPapers; -account.wallPapers#cdc3858c hash:long wallpapers:Vector = account.WallPapers; - -codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true unknown_number:flags.9?true logout_tokens:flags.6?Vector token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings; - -wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings; - -autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings; - -account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; - -emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector = EmojiKeyword; -emojiKeywordDeleted#236df622 keyword:string emoticons:Vector = EmojiKeyword; - -emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector = EmojiKeywordsDifference; - -emojiURL#a575739d url:string = EmojiURL; - -emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; - -folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; - -inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; - -folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; - -messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; - -urlAuthResultRequest#3cd623ec flags:# request_write_access:flags.0?true request_phone_number:flags.1?true match_codes_first:flags.5?true is_app:flags.6?true bot:User domain:string browser:flags.2?string platform:flags.2?string ip:flags.2?string region:flags.2?string match_codes:flags.3?Vector user_id_hint:flags.4?long verified_app_name:flags.7?string = UrlAuthResult; -urlAuthResultAccepted#623a8fa0 flags:# url:flags.0?string = UrlAuthResult; -urlAuthResultDefault#a9d6db1f = UrlAuthResult; - -channelLocationEmpty#bfb5ad8b = ChannelLocation; -channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation; - -peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated; -peerSelfLocated#f8ec284b expires:int = PeerLocated; - -restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason; - -inputTheme#3c5693e9 id:long access_hash:long = InputTheme; -inputThemeSlug#f5890df1 slug:string = InputTheme; - -theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector emoticon:flags.6?string installs_count:flags.4?int = Theme; - -account.themesNotModified#f41eb622 = account.Themes; -account.themes#9a3d8c6d hash:long themes:Vector = account.Themes; - -auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken; -auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken; -auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken; - -account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings; - -messages.inactiveChats#a927fec5 dates:Vector chats:Vector users:Vector = messages.InactiveChats; - -baseThemeClassic#c3a12462 = BaseTheme; -baseThemeDay#fbd81688 = BaseTheme; -baseThemeNight#b7b31ea8 = BaseTheme; -baseThemeTinted#6d5f77ee = BaseTheme; -baseThemeArctic#5b11125a = BaseTheme; - -inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; - -themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; - -webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; -webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; -webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; -webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; -webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; -webPageAttributeStarGiftAuction#1c641c2 gift:StarGift end_date:int = WebPageAttribute; -webPageAttributeAiComposeTone#7781fe18 emoji_id:long = WebPageAttribute; - -messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; - -bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl; - -payments.bankCardData#3e24e573 title:string open_urls:Vector = payments.BankCardData; - -dialogFilter#aa472651 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector exclude_peers:Vector = DialogFilter; -dialogFilterDefault#363293ae = DialogFilter; -dialogFilterChatlist#96537bd7 flags:# has_my_invites:flags.26?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector = DialogFilter; - -dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested; - -statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays; - -statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev; - -statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue; - -statsGraphAsync#4a27eb2d token:string = StatsGraph; -statsGraphError#bedc9822 error:string = StatsGraph; -statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph; - -stats.broadcastStats#396ca5fc period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev reactions_per_post:StatsAbsValueAndPrev views_per_story:StatsAbsValueAndPrev shares_per_story:StatsAbsValueAndPrev reactions_per_story:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_posts_interactions:Vector = stats.BroadcastStats; - -help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; -help.promoData#8a4d87a flags:# proxy:flags.0?true expires:int peer:flags.3?Peer psa_type:flags.1?string psa_message:flags.2?string pending_suggestions:Vector dismissed_suggestions:Vector custom_pending_suggestion:flags.4?PendingSuggestion chats:Vector users:Vector = help.PromoData; - -videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; -videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector = VideoSize; -videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector = VideoSize; - -statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster; - -statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; - -statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; - -stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; - -globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; - -help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; - -help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector = help.Country; - -help.countriesListNotModified#93cc1f32 = help.CountriesList; -help.countriesList#87d0759e countries:Vector hash:int = help.CountriesList; - -messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews; - -messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; - -messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; - -messageReplyHeader#1b97dd66 flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_ephemeral:flags.13?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector quote_offset:flags.10?int todo_item_id:flags.11?int poll_option:flags.12?bytes = MessageReplyHeader; -messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader; - -messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; - -peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; - -stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; - -groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; -groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall; - -inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; -inputGroupCallSlug#fe06823f slug:string = InputGroupCall; -inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall; - -groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant; - -phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; - -phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; - -inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; -inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; -inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType; -inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType; -inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType; -inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType; - -messages.historyImport#1662af0b id:long = messages.HistoryImport; - -messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed; - -messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector = messages.AffectedFoundMessages; - -chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter; - -messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; - -messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; -messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; - -messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; - -chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites; - -messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; - -messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; - -phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; - -phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; - -groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector = GroupCallParticipantVideoSourceGroup; - -groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector audio_source:flags.1?int = GroupCallParticipantVideo; - -stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName; - -botCommandScopeDefault#2f6cb2ab = BotCommandScope; -botCommandScopeUsers#3c4f04d8 = BotCommandScope; -botCommandScopeChats#6fe1a881 = BotCommandScope; -botCommandScopeChatAdmins#b9aa606a = BotCommandScope; -botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope; -botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope; -botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope; - -account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult; -account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; -account.resetPasswordOk#e926d63e = account.ResetPasswordResult; - -chatTheme#c3dffc04 emoticon:string = ChatTheme; -chatThemeUniqueGift#3458f9c8 gift:StarGift theme_settings:Vector = ChatTheme; - -account.chatThemesNotModified#e011e1c4 = account.ChatThemes; -account.chatThemes#be098173 flags:# hash:long themes:Vector chats:Vector users:Vector next_offset:flags.0?string = account.ChatThemes; - -sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage; - -messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; -messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; - -searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; - -messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector messages:Vector chats:Vector users:Vector = messages.SearchResultsCalendar; - -searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition; - -messages.searchResultsPositions#53b22baf count:int positions:Vector = messages.SearchResultsPositions; - -channels.sendAsPeers#f496b0c6 peers:Vector chats:Vector users:Vector = channels.SendAsPeers; - -users.userFull#3b6d152e full_user:UserFull chats:Vector users:Vector = users.UserFull; - -messages.peerSettings#6880b94d settings:PeerSettings chats:Vector users:Vector = messages.PeerSettings; - -auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut; - -reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; - -messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector recent_reactions:flags.1?Vector top_reactors:flags.4?Vector = MessageReactions; - -messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.MessageReactionsList; - -availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; - -messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions; -messages.availableReactions#768e3aad hash:int reactions:Vector = messages.AvailableReactions; - -messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true my:flags.2?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction; - -groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel; - -phone.groupCallStreamChannels#d0e482b2 channels:Vector = phone.GroupCallStreamChannels; - -phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl; - -attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; - -attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector = AttachMenuBotIcon; - -attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector icons:Vector = AttachMenuBot; - -attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; -attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector = AttachMenuBots; - -attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector = AttachMenuBotsBot; - -webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true fullscreen:flags.2?true same_origin:flags.3?true query_id:flags.0?long url:string = WebViewResult; - -webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent; - -botMenuButtonDefault#7533a588 = BotMenuButton; -botMenuButtonCommands#4258c205 = BotMenuButton; -botMenuButton#c7b57ce6 text:string url:string = BotMenuButton; - -account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones; -account.savedRingtones#c1e92cc5 hash:long ringtones:Vector = account.SavedRingtones; - -notificationSoundDefault#97e8bebe = NotificationSound; -notificationSoundNone#6f0c34df = NotificationSound; -notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound; -notificationSoundRingtone#ff6c8049 id:long = NotificationSound; - -account.savedRingtone#b7263f6d = account.SavedRingtone; -account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone; - -attachMenuPeerTypeSameBotPM#7d6be90e = AttachMenuPeerType; -attachMenuPeerTypeBotPM#c32bfa1a = AttachMenuPeerType; -attachMenuPeerTypePM#f146d31f = AttachMenuPeerType; -attachMenuPeerTypeChat#509113f = AttachMenuPeerType; -attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; - -inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; -inputInvoiceSlug#c326caef slug:string = InputInvoice; -inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; -inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice; -inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice; -inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; -inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; -inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; -inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; -inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice; -inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice; -inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice; -inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice; - -payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; - -messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; - -help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; - -inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose; -inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentPremiumGiftCode#fb790393 flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long message:flags.1?TextWithEntities = InputStorePaymentPurpose; -inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsTopup#f9a2a6cb flags:# stars:long currency:string amount:long spend_purpose_peer:flags.0?InputPeer = InputStorePaymentPurpose; -inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; -inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; -inputStorePaymentAuthCode#3fc18057 flags:# restore:flags.0?true phone_number:string phone_code_hash:string premium_days:int currency:string amount:long = InputStorePaymentPurpose; - -paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; - -emojiStatusEmpty#2de11aae = EmojiStatus; -emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus; -emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus; -inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus; - -account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses; -account.emojiStatuses#90c467d1 hash:long statuses:Vector = account.EmojiStatuses; - -reactionEmpty#79f5d419 = Reaction; -reactionEmoji#1b2286b8 emoticon:string = Reaction; -reactionCustomEmoji#8935fc73 document_id:long = Reaction; -reactionPaid#523da4eb = Reaction; - -chatReactionsNone#eafc32bc = ChatReactions; -chatReactionsAll#52928bca flags:# allow_custom:flags.0?true = ChatReactions; -chatReactionsSome#661d4037 reactions:Vector = ChatReactions; - -messages.reactionsNotModified#b06fdbdf = messages.Reactions; -messages.reactions#eafdf716 hash:long reactions:Vector = messages.Reactions; - -emailVerifyPurposeLoginSetup#4345be73 phone_number:string phone_code_hash:string = EmailVerifyPurpose; -emailVerifyPurposeLoginChange#527d22eb = EmailVerifyPurpose; -emailVerifyPurposePassport#bbf51685 = EmailVerifyPurpose; - -emailVerificationCode#922e55a9 code:string = EmailVerification; -emailVerificationGoogle#db909ec2 token:string = EmailVerification; -emailVerificationApple#96d074fd token:string = EmailVerification; - -account.emailVerified#2b96cd1b email:string = account.EmailVerified; -account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified; - -premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption; - -sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer; - -messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia; -messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia; - -stickerKeyword#fcfeb29c document_id:long keyword:Vector = StickerKeyword; - -username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username; - -forumTopicDeleted#23f109b id:int = ForumTopic; -forumTopic#fcdad815 flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true title_missing:flags.7?true id:int date:int peer:Peer title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic; - -messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector messages:Vector chats:Vector users:Vector pts:int = messages.ForumTopics; - -defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL; - -exportedContactToken#41bf109b url:string expires:int = ExportedContactToken; - -requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType; -requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; -requestPeerTypeCreateBot#3e81e078 flags:# bot_managed:flags.0?true suggested_name:flags.1?string suggested_username:flags.2?string = RequestPeerType; - -emojiListNotModified#481eadfa = EmojiList; -emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; - -emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; -emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; - -messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; -messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; - -textWithEntities#751f3146 text:string entities:Vector = TextWithEntities; - -messages.translateResult#33db32f8 result:Vector = messages.TranslatedText; - -autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings; - -autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException; - -account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector chats:Vector users:Vector = account.AutoSaveSettings; - -help.appConfigNotModified#7cde641d = help.AppConfig; -help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig; - -inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp; -inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp; - -botAppNotModified#5da674b7 = BotApp; -botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; - -messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp; - -inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; - -readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; - -inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist; - -exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector = ExportedChatlistInvite; - -chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite; - -chatlists.exportedInvites#10ab6dc7 invites:Vector chats:Vector users:Vector = chatlists.ExportedInvites; - -chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector already_peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; -chatlists.chatlistInvite#f10ece2f flags:# title_noanimate:flags.1?true title:TextWithEntities emoticon:flags.0?string peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; - -chatlists.chatlistUpdates#93bd878d missing_peers:Vector chats:Vector users:Vector = chatlists.ChatlistUpdates; - -bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo; - -messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote; -messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote; -messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector date:int = MessagePeerVote; - -storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector reactions_count:flags.4?int recent_viewers:flags.0?Vector = StoryViews; - -storyItemDeleted#51e6ee4f id:int = StoryItem; -storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true live:flags.9?true id:int date:int expire_date:int = StoryItem; -storyItem#16a4b93c flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector music:flags.20?Document = StoryItem; - -stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; -stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; - -stories.stories#63c3dd0a flags:# count:int stories:Vector pinned_to_top:flags.0?Vector chats:Vector users:Vector = stories.Stories; - -storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView; -storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView; -storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView; - -stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryViewsList; - -stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; - -inputReplyToMessage#3bd4b7c2 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int poll_option:flags.7?bytes = InputReplyTo; -inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; -inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; - -exportedStoryLink#3fc9053b link:string = ExportedStoryLink; - -storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; - -mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates; - -mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea; -inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea; -mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea; -mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea; -mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; -inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; -mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; -mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea; -mediaAreaStarGift#5787686d coordinates:MediaAreaCoordinates slug:string = MediaArea; - -peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; - -stories.peerStories#cae68768 stories:PeerStories chats:Vector users:Vector = stories.PeerStories; - -messages.webPage#fd5e12bd webpage:WebPage chats:Vector users:Vector = messages.WebPage; - -premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption; - -payments.checkedGiftCode#eb983f8f flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int days:int used_date:flags.1?int chats:Vector users:Vector = payments.CheckedGiftCode; - -payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; -payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo; - -prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; -prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway; - -boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost; - -premium.boostsList#86f8613c flags:# count:int boosts:Vector next_offset:flags.0?string users:Vector = premium.BoostsList; - -myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost; - -premium.myBoosts#9ae228e2 my_boosts:Vector chats:Vector users:Vector = premium.MyBoosts; - -premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector my_boost_slots:flags.2?Vector = premium.BoostsStatus; - -storyFwdHeader#b826e150 flags:# modified:flags.3?true from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader; - -postInteractionCountersMessage#e7058e7f msg_id:int views:int forwards:int reactions:int = PostInteractionCounters; -postInteractionCountersStory#8a480e27 story_id:int views:int forwards:int reactions:int = PostInteractionCounters; - -stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats; - -publicForwardMessage#1f2bf4a message:Message = PublicForward; -publicForwardStory#edf3add0 peer:Peer story:StoryItem = PublicForward; - -stats.publicForwards#93037e20 flags:# count:int forwards:Vector next_offset:flags.0?string chats:Vector users:Vector = stats.PublicForwards; - -peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor; -peerColorCollectible#b9c0639a flags:# collectible_id:long gift_emoji_id:long background_emoji_id:long accent_color:int colors:Vector dark_accent_color:flags.0?int dark_colors:flags.1?Vector = PeerColor; -inputPeerColorCollectible#b8ea86a9 collectible_id:long = PeerColor; - -help.peerColorSet#26219a58 colors:Vector = help.PeerColorSet; -help.peerColorProfileSet#767d61eb palette_colors:Vector bg_colors:Vector story_colors:Vector = help.PeerColorSet; - -help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption; - -help.peerColorsNotModified#2ba1f5ce = help.PeerColors; -help.peerColors#f8ed08 hash:int colors:Vector = help.PeerColors; - -storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction; -storyReactionPublicForward#bbab2643 message:Message = StoryReaction; -storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; - -stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; - -savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; -monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; - -messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; -messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; - -savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; - -messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; -messages.savedReactionTags#3259950a tags:Vector hash:long = messages.SavedReactionTags; - -outboxReadDate#3bb842ac date:int = OutboxReadDate; - -smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin; - -smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status; - -smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob; - -businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen; - -businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector = BusinessWorkHours; - -businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation; - -inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = InputBusinessRecipients; - -businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = BusinessRecipients; - -businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule; -businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule; - -inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage; - -businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage; - -inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage; - -businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage; - -timezone#ff9289f5 id:string name:string utc_offset:int = Timezone; - -help.timezonesListNotModified#970708cc = help.TimezonesList; -help.timezonesList#7b74ed71 timezones:Vector hash:int = help.TimezonesList; - -quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply; - -inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut; -inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; - -messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; -messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; - -connectedBot#33ed001 flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights device:flags.0?string date:flags.1?int location:flags.2?string = ConnectedBot; - -account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; - -messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector = messages.DialogFilters; - -birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; - -botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; - -inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; - -businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro; - -messages.myStickers#faff629d count:int sets:Vector = messages.MyStickers; - -inputCollectibleUsername#e39460a9 username:string = InputCollectible; -inputCollectiblePhone#a2e214a4 phone:string = InputCollectible; - -fragment.collectibleInfo#6ebdff91 purchase_date:int currency:string amount:long crypto_currency:string crypto_amount:long url:string = fragment.CollectibleInfo; - -inputBusinessBotRecipients#c4e5921e flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = InputBusinessBotRecipients; - -businessBotRecipients#b88cf373 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = BusinessBotRecipients; - -contactBirthday#1d998733 contact_id:long birthday:Birthday = ContactBirthday; - -contacts.contactBirthdays#114ff30d contacts:Vector users:Vector = contacts.ContactBirthdays; - -missingInvitee#628c9224 flags:# premium_would_allow_invite:flags.0?true premium_required_for_pm:flags.1?true user_id:long = MissingInvitee; - -messages.invitedUsers#7f5defa6 updates:Updates missing_invitees:Vector = messages.InvitedUsers; - -inputBusinessChatLink#11679fa7 flags:# message:string entities:flags.0?Vector title:flags.1?string = InputBusinessChatLink; - -businessChatLink#b4ae666f flags:# link:string message:string entities:flags.0?Vector title:flags.1?string views:int = BusinessChatLink; - -account.businessChatLinks#ec43a2d1 links:Vector chats:Vector users:Vector = account.BusinessChatLinks; - -account.resolvedBusinessChatLinks#9a23af21 flags:# peer:Peer message:string entities:flags.0?Vector chats:Vector users:Vector = account.ResolvedBusinessChatLinks; - -requestedPeerUser#d62ff46a flags:# user_id:long first_name:flags.0?string last_name:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChat#7307544f flags:# chat_id:long title:flags.0?string photo:flags.2?Photo = RequestedPeer; -requestedPeerChannel#8ba403e4 flags:# channel_id:long title:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; - -sponsoredMessageReportOption#430d3150 text:string option:bytes = SponsoredMessageReportOption; - -channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:Vector = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; -channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; - -reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; -reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; - -reactionsNotifySettings#71e4ea58 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom poll_votes_notify_from:flags.2?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; - -availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; - -messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; -messages.availableEffects#bddb616e hash:int effects:Vector documents:Vector = messages.AvailableEffects; - -factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck; - -starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer; -starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer; -starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; -starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; -starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; -starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; -starsTransactionPeerAds#60682812 = StarsTransactionPeer; -starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; - -starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; - -starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true posts_search:flags.24?true stargift_prepaid_upgrade:flags.25?true stargift_drop_original_details:flags.26?true phonegroup_message:flags.27?true stargift_auction_bid:flags.28?true offer:flags.29?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction; - -payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; - -foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; - -stories.foundStories#e2de7737 flags:# count:int stories:Vector next_offset:flags.0?string chats:Vector users:Vector = stories.FoundStories; - -geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; - -starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; - -payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; - -payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; - -payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl; - -inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; - -starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption; - -bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector = bots.PopularAppBots; - -botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia; - -bots.previewInfo#ca71d64 media:Vector lang_codes:Vector = bots.PreviewInfo; - -starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing; - -starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true bot_canceled:flags.7?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string title:flags.4?string photo:flags.5?WebDocument invoice_slug:flags.6?string = StarsSubscription; - -messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; - -starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; - -starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; - -starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift; -starGiftUnique#85f0a9cd flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true burned:flags.14?true crafted:flags.15?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int craft_chance_permille:flags.16?int = StarGift; - -payments.starGiftsNotModified#a388a368 = payments.StarGifts; -payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; - -messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; - -reportResultChooseOption#f0e4e0b6 title:string options:Vector = ReportResult; -reportResultAddComment#6f09ac31 flags:# optional:flags.0?true option:bytes = ReportResult; -reportResultReported#8db33c4b = ReportResult; - -messages.botPreparedInlineMessage#8ecf0511 id:string expire_date:int = messages.BotPreparedInlineMessage; - -messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult peer_types:Vector cache_time:int users:Vector = messages.PreparedInlineMessage; - -botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings; - -starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram; - -connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef; - -payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector = payments.ConnectedStarRefBots; - -payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; - -starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount; -starsTonAmount#74aee3e0 amount:long = StarsAmount; - -messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers; -messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector = messages.FoundStickers; - -botVerifierSettings#b0cd6617 flags:# can_modify_custom_description:flags.1?true icon:long company:string custom_description:flags.0?string = BotVerifierSettings; - -botVerification#f93cd45c bot_id:long icon:long description:string = BotVerification; - -starGiftAttributeModel#565251e2 flags:# crafted:flags.0?true name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributePattern#4e7085ea name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeBackdrop#9f2504e4 name:string backdrop_id:int center_color:int edge_color:int pattern_color:int text_color:int rarity:StarGiftAttributeRarity = StarGiftAttribute; -starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute; - -payments.starGiftUpgradePreview#3de1dfed sample_attributes:Vector prices:Vector next_prices:Vector = payments.StarGiftUpgradePreview; - -users.users#62d706b8 users:Vector = users.Users; -users.usersSlice#315a4974 count:int users:Vector = users.Users; - -payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector users:Vector = payments.UniqueStarGift; - -messages.webPagePreview#8c9a88ac media:MessageMedia chats:Vector users:Vector = messages.WebPagePreview; - -savedStarGift#41df43fc flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int can_craft_at:flags.20?int = SavedStarGift; - -payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; - -inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift; -inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift; -inputSavedStarGiftSlug#2085c238 slug:string = InputSavedStarGift; - -payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl; - -paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy; -paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy; -paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy; - -account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRevenue; - -requirementToContactEmpty#50a9839 = RequirementToContact; -requirementToContactPremium#e581e4e9 = RequirementToContact; -requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; - -businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; - -disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true disallow_stargifts_from_channels:flags.4?true = DisallowedGiftsSettings; - -sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; - -contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; -contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; - -starGiftAttributeIdModel#48aaae3c document_id:long = StarGiftAttributeId; -starGiftAttributeIdPattern#4a162433 document_id:long = StarGiftAttributeId; -starGiftAttributeIdBackdrop#1f01c757 backdrop_id:int = StarGiftAttributeId; - -starGiftAttributeCounter#2eb1b658 attribute:StarGiftAttributeId count:int = StarGiftAttributeCounter; - -payments.resaleStarGifts#947a12df flags:# count:int gifts:Vector next_offset:flags.0?string attributes:flags.1?Vector attributes_hash:flags.1?long chats:Vector counters:flags.2?Vector users:Vector = payments.ResaleStarGifts; - -stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount; - -pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion; - -todoItem#cba9a52f id:int title:TextWithEntities = TodoItem; - -todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector = TodoList; - -todoCompletion#221bb5e4 id:int completed_by:Peer date:int = TodoCompletion; - -suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost; - -starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating; - -starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection; - -payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; -payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; - -storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; - -stories.albumsNotModified#564edaeb = stories.Albums; -stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; - -searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; - -payments.uniqueStarGiftValueInfo#512fe446 flags:# last_sale_on_fragment:flags.1?true value_is_average:flags.6?true currency:string value:long initial_sale_date:int initial_sale_stars:long initial_sale_price:long last_sale_date:flags.0?int last_sale_price:flags.0?long floor_price:flags.2?long average_price:flags.3?long listed_count:flags.4?int fragment_listed_count:flags.5?int fragment_listed_url:flags.5?string = payments.UniqueStarGiftValueInfo; - -profileTabPosts#b98cd696 = ProfileTab; -profileTabGifts#4d4bd46a = ProfileTab; -profileTabMedia#72c64955 = ProfileTab; -profileTabFiles#ab339c00 = ProfileTab; -profileTabMusic#9f27d26e = ProfileTab; -profileTabVoice#e477092e = ProfileTab; -profileTabLinks#d3656499 = ProfileTab; -profileTabGifs#a2c0f695 = ProfileTab; - -users.savedMusicNotModified#e3878aa4 count:int = users.SavedMusic; -users.savedMusic#34a2f297 count:int documents:Vector = users.SavedMusic; - -account.savedMusicIdsNotModified#4fc81d6e = account.SavedMusicIds; -account.savedMusicIds#998d6636 ids:Vector = account.SavedMusicIds; - -payments.checkCanSendGiftResultOk#374fa7ad = payments.CheckCanSendGiftResult; -payments.checkCanSendGiftResultFail#d5e58274 reason:TextWithEntities = payments.CheckCanSendGiftResult; - -inputChatThemeEmpty#83268483 = InputChatTheme; -inputChatTheme#c93de95c emoticon:string = InputChatTheme; -inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme; - -starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice; - -groupCallMessage#1a8afc7e flags:# from_admin:flags.1?true id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage; - -groupCallDonor#ee430c85 flags:# top:flags.0?true my:flags.1?true peer_id:flags.3?Peer stars:long = GroupCallDonor; - -phone.groupCallStars#9d1dbd26 total_stars:long top_donors:Vector chats:Vector users:Vector = phone.GroupCallStars; - -recentStory#711d692d flags:# live:flags.0?true max_id:flags.1?int = RecentStory; - -auctionBidLevel#310240cc pos:int amount:long date:int = AuctionBidLevel; - -starGiftAuctionStateNotModified#fe333952 = StarGiftAuctionState; -starGiftAuctionState#771a4e66 version:int start_date:int end_date:int min_bid_amount:long bid_levels:Vector top_bidders:Vector next_round_at:int last_gift_num:int gifts_left:int current_round:int total_rounds:int rounds:Vector = StarGiftAuctionState; -starGiftAuctionStateFinished#972dabbf flags:# start_date:int end_date:int average_price:long listed_count:flags.0?int fragment_listed_count:flags.1?int fragment_listed_url:flags.1?string = StarGiftAuctionState; - -starGiftAuctionUserState#2eeed1c4 flags:# returned:flags.1?true bid_amount:flags.0?long bid_date:flags.0?int min_bid_amount:flags.0?long bid_peer:flags.0?Peer acquired_count:int = StarGiftAuctionUserState; - -payments.starGiftAuctionState#6b39f4ec gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState timeout:int users:Vector chats:Vector = payments.StarGiftAuctionState; - -starGiftAuctionAcquiredGift#42b00348 flags:# name_hidden:flags.0?true peer:Peer date:int bid_amount:long round:int pos:int message:flags.1?TextWithEntities gift_num:flags.2?int = StarGiftAuctionAcquiredGift; - -payments.starGiftAuctionAcquiredGifts#7d5bd1f0 gifts:Vector users:Vector chats:Vector = payments.StarGiftAuctionAcquiredGifts; - -starGiftActiveAuctionState#d31bc45d gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState = StarGiftActiveAuctionState; - -payments.starGiftActiveAuctionsNotModified#db33dad0 = payments.StarGiftActiveAuctions; -payments.starGiftActiveAuctions#aef6abbc auctions:Vector users:Vector chats:Vector = payments.StarGiftActiveAuctions; - -inputStarGiftAuction#2e16c98 gift_id:long = InputStarGiftAuction; -inputStarGiftAuctionSlug#7ab58308 slug:string = InputStarGiftAuction; - -passkey#98613ebf flags:# id:string name:string date:int software_emoji_id:flags.0?long last_usage_date:flags.1?int = Passkey; - -account.passkeys#f8e0aa1c passkeys:Vector = account.Passkeys; - -account.passkeyRegistrationOptions#e16b5ce1 options:DataJSON = account.PasskeyRegistrationOptions; - -auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions; - -inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse; -inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse; - -inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential; -inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential; - -starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground; - -starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound; -starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound; - -payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector = payments.StarGiftUpgradeAttributes; - -messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome; - -messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo; -messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector plays_left:flags.0?int = messages.EmojiGameInfo; - -starGiftAttributeRarity#36437737 permille:int = StarGiftAttributeRarity; -starGiftAttributeRarityUncommon#dbce6389 = StarGiftAttributeRarity; -starGiftAttributeRarityRare#f08d516b = StarGiftAttributeRarity; -starGiftAttributeRarityEpic#78fbf3a8 = StarGiftAttributeRarity; -starGiftAttributeRarityLegendary#cef7e7a8 = StarGiftAttributeRarity; - -keyboardButtonStyle#4fdd3430 flags:# bg_primary:flags.0?true bg_danger:flags.1?true bg_success:flags.2?true icon:flags.3?long = KeyboardButtonStyle; - -inputMessageReadMetric#402b4495 msg_id:int view_id:long time_in_view_ms:int active_time_in_view_ms:int height_to_viewport_ratio_permille:int seen_range_ratio_permille:int = InputMessageReadMetric; - -bots.exportedBotToken#3c60b621 token:string = bots.ExportedBotToken; - -bots.requestedButton#f13bbcd7 webapp_req_id:string = bots.RequestedButton; - -messages.composedMessageWithAI#90d7adfa flags:# result_text:TextWithEntities diff_text:flags.0?TextWithEntities = messages.ComposedMessageWithAI; - -stats.pollStats#2999beed votes_graph:StatsGraph = stats.PollStats; - -inputAiComposeToneDefault#1fe9a9bf tone:string = InputAiComposeTone; -inputAiComposeToneID#773c080 id:long access_hash:long = InputAiComposeTone; -inputAiComposeToneSlug#1fa01357 slug:string = InputAiComposeTone; - -aiComposeTone#cff63ea9 flags:# creator:flags.0?true id:long access_hash:long slug:string title:string emoji_id:flags.1?long prompt:flags.4?string installs_count:flags.2?int author_id:flags.3?long example_english:flags.5?AiComposeToneExample = AiComposeTone; -aiComposeToneDefault#9bad6414 tone:string emoji_id:long title:string = AiComposeTone; - -aicompose.tonesNotModified#c1f46103 = aicompose.Tones; -aicompose.tones#6c9d0efe hash:long tones:Vector users:Vector = aicompose.Tones; - -aiComposeToneExample#f1d628ec from:TextWithEntities to:TextWithEntities = AiComposeToneExample; - -bots.accessSettings#dd1fbf93 flags:# restricted:flags.0?true add_users:flags.1?Vector = bots.AccessSettings; - -messages.chatInviteJoinResultOk#445663a7 updates:Updates = messages.ChatInviteJoinResult; -messages.chatInviteJoinResultWebView#2f51c337 bot_id:long webview:WebViewResult users:Vector = messages.ChatInviteJoinResult; - -joinChatBotResultApproved#ae152a69 = JoinChatBotResult; -joinChatBotResultDeclined#efa0194 = JoinChatBotResult; -joinChatBotResultQueued#98a3a840 = JoinChatBotResult; -joinChatBotResultWebView#d6e3b813 url:string = JoinChatBotResult; - -webDomainException#933ca597 flags:# domain:string url:string title:string favicon:flags.0?long = WebDomainException; - -account.webBrowserSettingsNotModified#c31c8f4e = account.WebBrowserSettings; -account.webBrowserSettings#79eb8cb3 flags:# open_external_browser:flags.0?true display_close_button:flags.1?true external_exceptions:Vector inapp_exceptions:Vector hash:long = account.WebBrowserSettings; - -inputRichFilePhoto#9b00622b id:string photo:InputPhoto = InputRichFile; -inputRichFileDocument#83281dbd id:string document:InputDocument = InputRichFile; - -inputRichMessage#e4c449fc flags:# rtl:flags.0?true noautolink:flags.1?true blocks:Vector photos:flags.2?Vector documents:flags.3?Vector users:flags.4?Vector = InputRichMessage; -inputRichMessageHTML#dacb836a flags:# rtl:flags.0?true noautolink:flags.1?true html:string files:flags.2?Vector = InputRichMessage; -inputRichMessageMarkdown#4b572c flags:# rtl:flags.0?true noautolink:flags.1?true markdown:string files:flags.2?Vector = InputRichMessage; - -richMessage#baf39d8b flags:# rtl:flags.0?true part:flags.1?true blocks:Vector photos:Vector documents:Vector = RichMessage; - ----functions--- - -invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; -invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; -initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; -invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; -invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; -invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; -invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; -invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; -invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; -invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X; -invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X; - -auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; -auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; -auth.signIn#8d52a951 flags:# phone_number:string phone_code_hash:string phone_code:flags.0?string email_verification:flags.1?EmailVerification = auth.Authorization; -auth.logOut#3e72ba19 = auth.LoggedOut; -auth.resetAuthorizations#9fab0d1a = Bool; -auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; -auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; -auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; -auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; -auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; -auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; -auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; -auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode; -auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; -auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; -auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; -auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; -auth.acceptLoginToken#e894ad4d token:bytes = Authorization; -auth.checkRecoveryPassword#d36bf79 code:string = Bool; -auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; -auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool; -auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; -auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; -auth.checkPaidAuth#56e59f9c phone_number:string phone_code_hash:string form_id:long = auth.SentCode; -auth.initPasskeyLogin#518ad0b7 api_id:int api_hash:string = auth.PasskeyLoginOptions; -auth.finishPasskeyLogin#9857ad07 flags:# credential:InputPasskeyCredential from_dc_id:flags.0?int from_auth_key_id:flags.0?long = auth.Authorization; - -account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; -account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; -account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; -account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; -account.resetNotifySettings#db7e1747 = Bool; -account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; -account.updateStatus#6628562c offline:Bool = Bool; -account.getWallPapers#7967d36 hash:long = account.WallPapers; -account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool; -account.checkUsername#2714d86c username:string = Bool; -account.updateUsername#3e0bdd7c username:string = User; -account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; -account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; -account.deleteAccount#a2c0cf74 flags:# reason:string password:flags.0?InputCheckPasswordSRP = Bool; -account.getAccountTTL#8fc711d = AccountDaysTTL; -account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; -account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; -account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; -account.updateDeviceLocked#38df3532 period:int = Bool; -account.getAuthorizations#e320c158 = account.Authorizations; -account.resetAuthorization#df77f3bc hash:long = Bool; -account.getPassword#548a30f5 = account.Password; -account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; -account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; -account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; -account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; -account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; -account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; -account.resetWebAuthorization#2d01b9ef hash:long = Bool; -account.resetWebAuthorizations#682d2594 = Bool; -account.getAllSecureValues#b288bc7d = Vector; -account.getSecureValue#73665bc2 types:Vector = Vector; -account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; -account.deleteSecureValue#b880bc4b types:Vector = Bool; -account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm; -account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; -account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; -account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; -account.sendVerifyEmailCode#98e037bb purpose:EmailVerifyPurpose email:string = account.SentEmailCode; -account.verifyEmail#32da4cf purpose:EmailVerifyPurpose verification:EmailVerification = account.EmailVerified; -account.initTakeoutSession#8ef3eab0 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?long = account.Takeout; -account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; -account.confirmPasswordEmail#8fdf1920 code:string = Bool; -account.resendPasswordEmail#7a7f2a15 = Bool; -account.cancelPasswordEmail#c1cbd5b6 = Bool; -account.getContactSignUpNotification#9f07c728 = Bool; -account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; -account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true compare_stories:flags.2?true peer:flags.0?InputNotifyPeer = Updates; -account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; -account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; -account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; -account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; -account.resetWallPapers#bb3b9804 = Bool; -account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; -account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; -account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document; -account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector = Theme; -account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool; -account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool; -account.getTheme#3a5869ec format:string theme:InputTheme = Theme; -account.getThemes#7206e458 format:string hash:long = account.Themes; -account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool; -account.getContentSettings#8b9b4dae = account.ContentSettings; -account.getMultiWallPapers#65ad71dc wallpapers:Vector = Vector; -account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings; -account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; -account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; -account.resetPassword#9308ce1b = account.ResetPasswordResult; -account.declinePasswordReset#4c9409f6 = Bool; -account.getChatThemes#d638de89 hash:long = account.Themes; -account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; -account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; -account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones; -account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone; -account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document; -account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool; -account.getDefaultEmojiStatuses#d6753386 hash:long = account.EmojiStatuses; -account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; -account.clearRecentEmojiStatuses#18201aae = Bool; -account.reorderUsernames#ef500eab order:Vector = Bool; -account.toggleUsername#58d6b376 username:string active:Bool = Bool; -account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList; -account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList; -account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings; -account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool; -account.deleteAutoSaveExceptions#53bc0020 = Bool; -account.invalidateSignInCodes#ca8ae8ba codes:Vector = Bool; -account.updateColor#684d214e flags:# for_profile:flags.1?true color:flags.2?PeerColor = Bool; -account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList; -account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses; -account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList; -account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool; -account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool; -account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool; -account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool; -account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates; -account.getConnectedBots#4ea4c80f = account.ConnectedBots; -account.getBotBusinessConnection#76a86270 connection_id:string = Updates; -account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool; -account.toggleConnectedBotPaused#646e1097 peer:InputPeer paused:Bool = Bool; -account.disablePeerConnectedBot#5e437ed9 peer:InputPeer = Bool; -account.updateBirthday#cc6e0c11 flags:# birthday:flags.0?Birthday = Bool; -account.createBusinessChatLink#8851e68e link:InputBusinessChatLink = BusinessChatLink; -account.editBusinessChatLink#8c3410af slug:string link:InputBusinessChatLink = BusinessChatLink; -account.deleteBusinessChatLink#60073674 slug:string = Bool; -account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks; -account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks; -account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool; -account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool; -account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings; -account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings; -account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses; -account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue; -account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool; -account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool; -account.saveMusic#b26732a9 flags:# unsave:flags.0?true id:InputDocument after_id:flags.1?InputDocument = Bool; -account.getSavedMusicIds#e09d5faf hash:long = account.SavedMusicIds; -account.getUniqueGiftChatThemes#e42ce9c9 offset:string limit:int hash:long = account.ChatThemes; -account.initPasskeyRegistration#429547e8 = account.PasskeyRegistrationOptions; -account.registerPasskey#55b41fd6 credential:InputPasskeyCredential = Passkey; -account.getPasskeys#ea1f0c52 = account.Passkeys; -account.deletePasskey#f5b5563f id:string = Bool; -account.confirmBotConnection#67ed1f68 bot_id:InputUser = Bool; -account.getWebBrowserSettings#56655768 hash:long = account.WebBrowserSettings; -account.updateWebBrowserSettings#9adf82fe flags:# open_external_browser:flags.0?true display_close_button:flags.1?true = account.WebBrowserSettings; -account.toggleWebBrowserSettingsException#60ed4229 flags:# delete:flags.1?true open_external_browser:flags.0?Bool url:string = Updates; -account.deleteWebBrowserSettingsExceptions#86a0765d = account.WebBrowserSettings; - -users.getUsers#d91a548 id:Vector = Vector; -users.getFullUser#b60f5918 id:InputUser = users.UserFull; -users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; -users.getRequirementsToContact#d89a83a3 id:Vector = Vector; -users.getSavedMusic#788d7fe3 id:InputUser offset:int limit:int hash:long = users.SavedMusic; -users.getSavedMusicByID#7573a4e9 id:InputUser documents:Vector = users.SavedMusic; -users.suggestBirthday#fc533372 id:InputUser birthday:Birthday = Updates; - -contacts.getContactIDs#7adc669d hash:long = Vector; -contacts.getStatuses#c4a353ee = Vector; -contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; -contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; -contacts.deleteContacts#96a0e00 id:Vector = Updates; -contacts.deleteByPhones#1013fd9e phones:Vector = Bool; -contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; -contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; -contacts.search#5f58d0f flags:# broadcasts:flags.0?true bots:flags.1?true q:string limit:int = contacts.Found; -contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer; -contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true bots_guestchat:flags.17?true offset:int limit:int hash:long = contacts.TopPeers; -contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; -contacts.resetSaved#879537f1 = Bool; -contacts.getSaved#82f1e39f = Vector; -contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; -contacts.addContact#d9ba2e54 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string note:flags.1?TextWithEntities = Updates; -contacts.acceptContact#f831a20f id:InputUser = Updates; -contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates; -contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates; -contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer; -contacts.exportContactToken#f8654027 = ExportedContactToken; -contacts.importContactToken#13005788 token:string = User; -contacts.editCloseFriends#ba6705f0 id:Vector = Bool; -contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector limit:int = Bool; -contacts.getBirthdays#daeda864 = contacts.ContactBirthdays; -contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers; -contacts.updateContactNote#139f63fb id:InputUser note:TextWithEntities = Bool; - -messages.getMessages#63c66506 id:Vector = messages.Messages; -messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; -messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; -messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; -messages.receivedMessages#5a954c0 max_id:int = Vector; -messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; -messages.sendMessage#fef48f62 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost rich_message:flags.23?InputRichMessage = Updates; -messages.sendMedia#330e77f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; -messages.forwardMessages#13704a7c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; -messages.reportSpam#cf1592db peer:InputPeer = Bool; -messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; -messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; -messages.getChats#49e9528f id:Vector = messages.Chats; -messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; -messages.editChatTitle#73783ffd chat_id:long title:string = Updates; -messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates; -messages.addChatUser#cbc6d107 chat_id:long user_id:InputUser fwd_limit:int = messages.InvitedUsers; -messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates; -messages.createChat#92ceddd4 flags:# users:Vector title:string ttl_period:flags.0?int = messages.InvitedUsers; -messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; -messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; -messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; -messages.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool; -messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; -messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; -messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; -messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; -messages.receivedQueue#55a5bb66 max_qts:int = Vector; -messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; -messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; -messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers; -messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers; -messages.getWebPagePreview#570d6f6f flags:# message:string entities:flags.3?Vector = messages.WebPagePreview; -messages.exportChatInvite#a455de90 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string subscription_pricing:flags.5?StarsSubscriptionPricing = ExportedChatInvite; -messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; -messages.importChatInvite#de91436e hash:string = messages.ChatInviteJoinResult; -messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet; -messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; -messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; -messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; -messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool = messages.MessageViews; -messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; -messages.migrateChat#a2875319 chat_id:long = Updates; -messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true groups_only:flags.2?true users_only:flags.3?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; -messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Bool; -messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document; -messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; -messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; -messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; -messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool; -messages.sendInlineBotResult#c0cf7646 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut allow_paid_stars:flags.21?long = Updates; -messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; -messages.editMessage#b106e66c flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.15?int schedule_repeat_period:flags.18?int quick_reply_shortcut_id:flags.17?int rich_message:flags.23?InputRichMessage = Updates; -messages.editInlineBotMessage#a423bb51 flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector rich_message:flags.23?InputRichMessage = Bool; -messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; -messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; -messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; -messages.saveDraft#ad0fa15c flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost rich_message:flags.9?InputRichMessage = Bool; -messages.getAllDrafts#6a3f8d65 = Updates; -messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; -messages.readFeaturedStickers#5b118126 id:Vector = Bool; -messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; -messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; -messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; -messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers; -messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; -messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; -messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; -messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; -messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; -messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; -messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats; -messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage; -messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; -messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; -messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; -messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; -messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia; -messages.sendScreenshotNotification#a1405817 peer:InputPeer reply_to:InputReplyTo random_id:long = Updates; -messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers; -messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; -messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; -messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; -messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSplitRanges#1cff7e08 = Vector; -messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool; -messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector; -messages.clearAllDrafts#7e58ee9c = Bool; -messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates; -messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; -messages.getPollResults#eda3e33b peer:InputPeer msg_id:int poll_hash:long = Updates; -messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; -messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; -messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; -messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; -messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; -messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; -messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; -messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector = Vector; -messages.requestUrlAuth#894cc99c flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string in_app_origin:flags.3?string = UrlAuthResult; -messages.acceptUrlAuth#67a3f0de flags:# write_allowed:flags.0?true share_phone_number:flags.3?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string match_code:flags.4?string = UrlAuthResult; -messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; -messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages; -messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; -messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector = Updates; -messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector = Updates; -messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList; -messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector = Bool; -messages.getDialogFilters#efd48c89 = messages.DialogFilters; -messages.getSuggestedDialogFilters#a29cd42c = Vector; -messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool; -messages.updateDialogFiltersOrder#c563c1e4 order:Vector = Bool; -messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers; -messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; -messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; -messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.deleteChat#5bd0ee50 chat_id:long = Bool; -messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; -messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; -messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport; -messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; -messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; -messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; -messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; -messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite; -messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; -messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; -messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; -messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true subscription_expired:flags.3?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; -messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; -messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; -messages.setChatTheme#81202c9 peer:InputPeer theme:InputChatTheme = Updates; -messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector; -messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; -messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; -messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; -messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; -messages.toggleNoForwards#b2081a35 flags:# peer:InputPeer enabled:Bool request_msg_id:flags.0?int = Updates; -messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; -messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector = Updates; -messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector = Updates; -messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList; -messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int paid_enabled:flags.1?Bool = Updates; -messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; -messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool; -messages.translateText#a5eec345 flags:# peer:flags.0?InputPeer id:flags.0?Vector text:flags.1?Vector to_lang:string tone:flags.2?string = messages.TranslatedText; -messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; -messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages; -messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; -messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; -messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; -messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; -messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; -messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true fullscreen:flags.8?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; -messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; -messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; -messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool; -messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector = Vector; -messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers; -messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers; -messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer = Bool; -messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions; -messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions; -messages.clearRecentReactions#9dfeefb4 = Bool; -messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector = Updates; -messages.setDefaultHistoryTTL#9eb51445 period:int = Bool; -messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL; -messages.sendBotRequestedPeer#6c5cf2a7 flags:# peer:InputPeer msg_id:flags.0?int webapp_req_id:flags.1?string button_id:int requested_peers:Vector = Updates; -messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups; -messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups; -messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups; -messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; -messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; -messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; -messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; -messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; -messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; -messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; -messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; -messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; -messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; -messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags; -messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; -messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; -messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate; -messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies; -messages.reorderQuickReplies#60331907 order:Vector = Bool; -messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool; -messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool; -messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool; -messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector hash:long = messages.Messages; -messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vector random_id:Vector = Updates; -messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; -messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; -messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; -messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; -messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; -messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; -messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; -messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; -messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; -messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates; -messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool; -messages.getPaidReactionPrivacy#472455aa = Updates; -messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; -messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; -messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; -messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages; -messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; -messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; -messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; -messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; -messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; -messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; -messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; -messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; -messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates; -messages.getForumTopics#3ba47bff flags:# peer:InputPeer q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; -messages.getForumTopicsByID#af0a4a08 peer:InputPeer topics:Vector = messages.ForumTopics; -messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates; -messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates; -messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector = Updates; -messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; -messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory; -messages.getEmojiGameInfo#fb7e8ca7 = messages.EmojiGameInfo; -messages.summarizeText#abbbd346 flags:# peer:InputPeer id:int to_lang:flags.0?string tone:flags.2?string = TextWithEntities; -messages.editChatCreator#f743b857 peer:InputPeer user_id:InputUser password:InputCheckPasswordSRP = Updates; -messages.getFutureChatCreatorAfterLeave#3b7d0ea6 peer:InputPeer = User; -messages.editChatParticipantRank#a00f32b0 peer:InputPeer participant:InputPeer rank:string = Updates; -messages.declineUrlAuth#35436bbc url:string = Bool; -messages.checkUrlAuthMatchCode#c9a47b0b url:string match_code:string = Bool; -messages.composeMessageWithAI#daecc589 flags:# proofread:flags.0?true emojify:flags.3?true text:TextWithEntities translate_to_lang:flags.1?string tone:flags.2?InputAiComposeTone = messages.ComposedMessageWithAI; -messages.reportReadMetrics#4067c5e6 peer:InputPeer metrics:Vector = Bool; -messages.reportMusicListen#ddbcd819 id:InputDocument listened_duration:int = Bool; -messages.addPollAnswer#19bc4b6d peer:InputPeer msg_id:int answer:PollAnswer = Updates; -messages.deletePollAnswer#ac8505a5 peer:InputPeer msg_id:int option:bytes = Updates; -messages.getUnreadPollVotes#43286cf2 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readPollVotes#1720b4d8 flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; -messages.setBotGuestChatResult#b8f106e3 query_id:long result:InputBotInlineResult = InputBotInlineMessageID; -messages.deleteParticipantReactions#a0b80cf8 peer:InputPeer participant:InputPeer = Bool; -messages.deleteParticipantReaction#e3b7f82c peer:InputPeer msg_id:int participant:InputPeer = Updates; -messages.getPersonalChannelHistory#55fb0996 user_id:InputUser limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.getRichMessage#501569cf peer:InputPeer id:int = messages.Messages; - -updates.getState#edd4882a = updates.State; -updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; -updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; - -photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo; -photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo; -photos.deletePhotos#87cf7f2f id:Vector = Vector; -photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; -photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo; - -upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; -upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File; -upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; -upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; -upload.getCdnFile#395f69da file_token:bytes offset:long limit:int = upload.CdnFile; -upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; -upload.getCdnFileHashes#91dc3f31 file_token:bytes offset:long = Vector; -upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector; - -help.getConfig#c4f9186b = Config; -help.getNearestDc#1fb33026 = NearestDc; -help.getAppUpdate#522d5a7d source:string = help.AppUpdate; -help.getInviteText#4d392343 = help.InviteText; -help.getSupport#9cdf08cd = help.Support; -help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; -help.getCdnConfig#52029342 = CdnConfig; -help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; -help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; -help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; -help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; -help.getAppConfig#61e3f854 hash:int = help.AppConfig; -help.saveAppLog#6f02f748 events:Vector = Bool; -help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; -help.getSupportName#d360e72c = help.SupportName; -help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; -help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; -help.getPromoData#c0977421 = help.PromoData; -help.hidePromoData#1e251c95 peer:InputPeer = Bool; -help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; -help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; -help.getPremiumPromo#b81b93d4 = help.PremiumPromo; -help.getPeerColors#da80f42f hash:int = help.PeerColors; -help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors; -help.getTimezonesList#49b30240 hash:int = help.TimezonesList; - -channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; -channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; -channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector = Bool; -channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; -channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; -channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; -channels.getChannels#a7f6bbb id:Vector = messages.Chats; -channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; -channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates; -channels.editAdmin#9a98ad68 flags:# channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:flags.0?string = Updates; -channels.editTitle#566decd0 channel:InputChannel title:string = Updates; -channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; -channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; -channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; -channels.joinChannel#7f6a1e22 channel:InputChannel = messages.ChatInviteJoinResult; -channels.leaveChannel#f836aa95 channel:InputChannel = Updates; -channels.inviteToChannel#c9e33d54 channel:InputChannel users:Vector = messages.InvitedUsers; -channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; -channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; -channels.toggleSignatures#418d549c flags:# signatures_enabled:flags.0?true profiles_enabled:flags.1?true channel:InputChannel = Updates; -channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_personal:flags.2?true = messages.Chats; -channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; -channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; -channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; -channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates; -channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; -channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; -channels.getGroupsForDiscussion#f5dad378 = messages.Chats; -channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; -channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; -channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; -channels.getInactiveChannels#11e831ee = messages.InactiveChats; -channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; -channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true for_live_stories:flags.1?true peer:InputPeer = channels.SendAsPeers; -channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory; -channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates; -channels.toggleJoinRequest#ecc2618 flags:# apply_to_invites:flags.1?true channel:InputChannel enabled:Bool guard_bot:flags.0?InputUser = Updates; -channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector = Bool; -channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool; -channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool; -channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates; -channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates; -channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool; -channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; -channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates; -channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; -channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats; -channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates; -channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates; -channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; -channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; -channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; -channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; -channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; -channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; -channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood; -channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool; - -bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; -bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; -bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector = Bool; -bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool; -bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector; -bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool; -bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton; -bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool; -bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool; -bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool; -bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo; -bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector = Bool; -bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool; -bots.canSendMessage#1359f4e6 bot:InputUser = Bool; -bots.allowSendMessage#f132e3ef bot:InputUser = Updates; -bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; -bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; -bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia; -bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia; -bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector = Bool; -bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector = Bool; -bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo; -bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; -bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool; -bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; -bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; -bots.getAdminedBots#b0711d83 = Vector; -bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram; -bots.setCustomVerification#8b89dfbd flags:# enabled:flags.1?true bot:flags.0?InputUser peer:InputPeer custom_description:flags.2?string = Bool; -bots.getBotRecommendations#a1b70815 bot:InputUser = users.Users; -bots.checkUsername#87f2219b username:string = Bool; -bots.createBot#e5b17f2b flags:# via_deeplink:flags.0?true name:string username:string manager_id:InputUser = User; -bots.exportBotToken#bd0d99eb bot:InputUser revoke:Bool = bots.ExportedBotToken; -bots.requestWebViewButton#31a2a35e user_id:InputUser button:KeyboardButton = bots.RequestedButton; -bots.getRequestedWebViewButton#bf25b7f3 bot:InputUser webapp_req_id:string = KeyboardButton; -bots.getAccessSettings#213853a3 bot:InputUser = bots.AccessSettings; -bots.editAccessSettings#31813cd8 flags:# restricted:flags.0?true bot:InputUser add_users:flags.1?Vector = Bool; -bots.setJoinChatResults#e71a4810 query_id:long result:JoinChatBotResult = Bool; - -payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; -payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; -payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; -payments.sendPaymentForm#2d03522f flags:# form_id:long invoice:InputInvoice requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; -payments.getSavedInfo#227d824b = payments.SavedInfo; -payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; -payments.getBankCardData#2e79d779 number:string = payments.BankCardData; -payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; -payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; -payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; -payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector; -payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; -payments.applyGiftCode#f6e26854 slug:string = Updates; -payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; -payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; -payments.getStarsTopupOptions#c00ec7d3 = Vector; -payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus; -payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; -payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult; -payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; -payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats; -payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; -payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; -payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector = payments.StarsStatus; -payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; -payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; -payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; -payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; -payments.getStarsGiveawayOptions#bd1efd3e = Vector; -payments.getStarGifts#c4563590 hash:int = payments.StarGifts; -payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool; -payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool; -payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; -payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; -payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots; -payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; -payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; -payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview; -payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates; -payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates; -payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift; -payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_unique:flags.4?true sort_by_value:flags.5?true exclude_upgradable:flags.7?true exclude_unupgradable:flags.8?true peer_color_available:flags.9?true exclude_hosted:flags.10?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts; -payments.getSavedStarGift#b455a106 stargift:Vector = payments.SavedStarGifts; -payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; -payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; -payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; -payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; -payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true for_craft:flags.4?true stars_only:flags.5?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; -payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; -payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; -payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; -payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector = Bool; -payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool; -payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections; -payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo; -payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult; -payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState; -payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts; -payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions; -payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates; -payments.sendStarGiftOffer#8fb86b41 flags:# peer:InputPeer slug:string price:StarsAmount duration:int random_id:long allow_paid_stars:flags.0?long = Updates; -payments.getStarGiftUpgradeAttributes#6d038b58 gift_id:long = payments.StarGiftUpgradeAttributes; -payments.getCraftStarGifts#fd05dd00 gift_id:long offset:string limit:int = payments.SavedStarGifts; -payments.craftStarGift#b0f9684f stargift:Vector = Updates; - -stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; -stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; -stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; -stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; -stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet; -stickers.checkShortName#284b3639 short_name:string = Bool; -stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName; -stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet; -stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet; -stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool; -stickers.replaceSticker#4696459a sticker:InputDocument new_sticker:InputStickerSetItem = messages.StickerSet; - -phone.getCallConfig#55451fa9 = DataJSON; -phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; -phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; -phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; -phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; -phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; -phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; -phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; -phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; -phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates; -phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; -phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; -phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; -phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates; -phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; -phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; -phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; -phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; -phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; -phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; -phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; -phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; -phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; -phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; -phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; -phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates; -phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates; -phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels; -phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl; -phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool; -phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates; -phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector block:bytes = Updates; -phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates; -phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates; -phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates; -phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates; -phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates; -phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool; -phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector = Updates; -phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates; -phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars; -phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool; - -langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; -langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; -langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; -langpack.getLanguages#42c6978f lang_pack:string = Vector; -langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; - -folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; - -stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats; -stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; -stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; -stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards; -stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; -stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; -stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards; -stats.getPollStats#c27dfa68 flags:# dark:flags.0?true peer:InputPeer msg_id:int = stats.PollStats; - -chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; -chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; -chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector = ExportedChatlistInvite; -chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites; -chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite; -chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector = Updates; -chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates; -chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector = Updates; -chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool; -chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector; -chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector = Updates; - -stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount; -stories.sendStory#8f9e6898 flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector music:flags.9?InputDocument = Updates; -stories.editStory#2c63a72b flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector music:flags.4?InputDocument = Updates; -stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; -stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; -stories.getAllStories#eeb0d625 flags:# next:flags.1?true hidden:flags.2?true state:flags.0?string = stories.AllStories; -stories.getPinnedStories#5821a5dc peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stories.Stories; -stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector = stories.Stories; -stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool; -stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector; -stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector = Bool; -stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList; -stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector = stories.StoryViews; -stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; -stories.report#19d8eb45 peer:InputPeer id:Vector option:bytes message:string = ReportResult; -stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates; -stories.sendReaction#7fd736b2 flags:# add_to_recent:flags.0?true peer:InputPeer story_id:int reaction:Reaction = Updates; -stories.getPeerStories#2c4ada50 peer:InputPeer = stories.PeerStories; -stories.getAllReadPeerStories#9b5ae7f9 = Updates; -stories.getPeerMaxIDs#78499170 id:Vector = Vector; -stories.getChatsToSend#a56a8b60 = messages.Chats; -stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; -stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; -stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; -stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories; -stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector = StoryAlbum; -stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector add_stories:flags.2?Vector order:flags.3?Vector = StoryAlbum; -stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector = Bool; -stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool; -stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums; -stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories; -stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates; - -premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; -premium.getMyBoosts#be77b4a = premium.MyBoosts; -premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; -premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; -premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; - -smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin; -smsjobs.join#a74ece2d = Bool; -smsjobs.leave#9898ad73 = Bool; -smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool; -smsjobs.getStatus#10a698e8 = smsjobs.Status; -smsjobs.getSmsJob#778d902f job_id:string = SmsJob; -smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; - -fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; - -aicompose.createTone#4aa83913 flags:# display_author:flags.0?true emoji_id:long title:string prompt:string = AiComposeTone; -aicompose.updateTone#903bcf59 flags:# tone:InputAiComposeTone display_author:flags.0?Bool emoji_id:flags.1?long title:flags.2?string prompt:flags.3?string = AiComposeTone; -aicompose.saveTone#1782cbb1 tone:InputAiComposeTone unsave:Bool = Bool; -aicompose.deleteTone#dd39316a tone:InputAiComposeTone = Bool; -aicompose.getTone#b2e8ba03 tone:InputAiComposeTone = aicompose.Tones; -aicompose.getTones#abd59201 hash:long = aicompose.Tones; -aicompose.getToneExample#d1b4ab14 tone:InputAiComposeTone num:int = AiComposeToneExample; - -// LAYER 227 diff --git a/internal/compat/layerwire/bench_test.go b/internal/compat/layerwire/bench_test.go deleted file mode 100644 index b2a92b63..00000000 --- a/internal/compat/layerwire/bench_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package layerwire - -import ( - "testing" - - "github.com/gotd/td/bin" - "github.com/gotd/td/tg" -) - -func benchEncode(o bin.Encoder) []byte { - var b bin.Buffer - if err := o.Encode(&b); err != nil { - panic(err) - } - return b.Copy() -} - -// BenchmarkTranscodeOutbound measures the outbound seam: the 227 passthrough -// (the overwhelmingly common case) vs a real message downgrade to 220. -func BenchmarkTranscodeOutbound(b *testing.B) { - richMessage := canonicalCorpus()[1] - raw := benchEncode(richMessage) - - b.Run("identity_227", func(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - if _, err := Transcode(raw, 227); err != nil { - b.Fatal(err) - } - } - }) - b.Run("downgrade_220_message", func(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - if _, err := Transcode(raw, 220); err != nil { - b.Fatal(err) - } - } - }) - - dialogs := benchEncode(canonicalCorpus()[11]) // messages.dialogs - b.Run("downgrade_220_dialogs", func(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - if _, err := Transcode(dialogs, 220); err != nil { - b.Fatal(err) - } - } - }) -} - -// BenchmarkUpgradeInbound measures the inbound seam: a 227 client (miss, the -// common case), a CRC-swap drift, and a body-transform drift. -func BenchmarkUpgradeInbound(b *testing.B) { - b.Run("miss_227", func(b *testing.B) { - // A canonical method id that needs no upgrade. - body := benchEncode(&tg.HelpGetConfigRequest{}) - b.ReportAllocs() - for i := 0; i < b.N; i++ { - in := &bin.Buffer{Buf: body} - id, _ := in.PeekID() - if _, ok, _ := UpgradeInbound(id, in); ok { - b.Fatal("unexpected upgrade") - } - } - }) - - // uploadMedia body transform (peer+media -> flags+peer+media). - var um bin.Buffer - um.PutID(0x519bc2b1) - _ = (&tg.InputPeerSelf{}).Encode(&um) - _ = (&tg.InputMediaUploadedPhoto{File: &tg.InputFile{ID: 10, Parts: 1, Name: "a.jpg"}}).Encode(&um) - umRaw := um.Copy() - b.Run("drift_uploadMedia", func(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - in := &bin.Buffer{Buf: append([]byte(nil), umRaw...)} - if _, ok, err := UpgradeInbound(0x519bc2b1, in); !ok || err != nil { - b.Fatal(ok, err) - } - } - }) -} diff --git a/internal/compat/layerwire/client_aliases.go b/internal/compat/layerwire/client_aliases.go deleted file mode 100644 index 23b81820..00000000 --- a/internal/compat/layerwire/client_aliases.go +++ /dev/null @@ -1,36 +0,0 @@ -package layerwire - -// clientMethodAliases maps method constructor ids emitted by a specific client's -// hand-maintained TL (constructor *drift*, NOT official api.tl layer drift) to -// the canonical (227) id — for the subset whose request body is byte-identical -// to canonical so a 4-byte id swap suffices. -// -// This is the second, hand-maintained half of the inbound compat table; the -// generated inboundMethodUpgrades (tables_gen.go) covers official layer drift -// derived from TDesktop api.tl, which by construction never contains these -// client-private ids. Entries here are sourced from client source (e.g. DrKLO -// TLRPC.java), each verified body-compatible against the canonical layout. -// -// Client-drift constructors whose body differs structurally (a missing flags -// integer, a different field type, or that need business logic such as -// access_hash resolution or a legacy-shaped response) are NOT here — they remain -// dedicated decode handlers in internal/rpc (dispatchCompat), because the body -// cannot be reused as-is and the transform needs more than an id swap. -var clientMethodAliases = map[uint32]uint32{ - // DrKLO Android (post-Layer225) messages.forwardMessages. Wire layout is - // identical to canonical #13704a7c for every flag bit the client can set - // (the only schema delta is flags it never sets), so the body decodes as-is. - 0x41d41ade: 0x13704a7c, - // DrKLO Android channels.inviteToChannel. Body is still - // channel:InputChannel users:Vector = canonical #c9e33d54. - 0x199f3a6c: 0xc9e33d54, - // DrKLO Android updates.getDifference. Old layout only uses flags.0 - // (pts_total_limit); canonical #19c2f763 adds pts_limit(flags.1)/ - // qts_limit(flags.2) which the client leaves clear ⇒ zero wire bytes, so the - // old body decodes byte-for-byte as canonical. - 0x25939651: 0x19c2f763, - // DrKLO Android messages.createChat. Body is byte-identical to canonical - // #92ceddd4; the legacy-shaped response is produced by ClientType==Android - // (createChatNeedsLegacyChat), so no dedicated handler is needed. - 0x0034a818: 0x92ceddd4, -} diff --git a/internal/compat/layerwire/corpus_test.go b/internal/compat/layerwire/corpus_test.go deleted file mode 100644 index c9105c44..00000000 --- a/internal/compat/layerwire/corpus_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package layerwire - -import ( - "github.com/gotd/td/bin" - "github.com/gotd/td/tg" -) - -// canonicalCorpus is a diverse set of canonical (gotd, Layer 227) objects shared -// by the walker and transcoder tests. It deliberately exercises changed types -// (message, messageMediaPhoto, keyboardButton*, dialog, channelFull, userFull, -// pollResults/pollAnswerVoters), nested containers, vectors, and multi-flags. -func canonicalCorpus() []bin.Encoder { - photo := &tg.Photo{ - ID: 10, - AccessHash: 11, - FileReference: []byte{1, 2, 3}, - Date: 100, - Sizes: []tg.PhotoSizeClass{ - &tg.PhotoSize{Type: "x", W: 100, H: 100, Size: 2048}, - &tg.PhotoStrippedSize{Type: "i", Bytes: []byte{9, 8, 7}}, - }, - DCID: 2, - } - return []bin.Encoder{ - &tg.Message{ID: 1, PeerID: &tg.PeerUser{UserID: 2}, Date: 100, Message: "hi"}, - &tg.Message{ - Out: true, - ID: 2, - FromID: &tg.PeerUser{UserID: 3}, - PeerID: &tg.PeerChannel{ChannelID: 4}, - Date: 101, - Message: "rich", - Media: &tg.MessageMediaPhoto{Photo: photo, TTLSeconds: 5}, - Entities: []tg.MessageEntityClass{ - &tg.MessageEntityBold{Offset: 0, Length: 2}, - &tg.MessageEntityTextURL{Offset: 0, Length: 2, URL: "https://x"}, - }, - ReplyMarkup: &tg.ReplyInlineMarkup{Rows: []tg.KeyboardButtonRow{ - {Buttons: []tg.KeyboardButtonClass{ - &tg.KeyboardButtonCallback{Text: "ok", Data: []byte("d")}, - &tg.KeyboardButtonURL{Text: "go", URL: "https://y"}, - }}, - }}, - ReplyTo: &tg.MessageReplyHeader{ReplyToMsgID: 1}, - FwdFrom: tg.MessageFwdHeader{FromName: "n", Date: 99}, - Views: 7, - Forwards: 2, - Reactions: tg.MessageReactions{Results: []tg.ReactionCount{{Reaction: &tg.ReactionEmoji{Emoticon: "👍"}, Count: 3}}}, - GroupedID: 555, - }, - &tg.MessageService{ - ID: 3, - PeerID: &tg.PeerUser{UserID: 2}, - Date: 102, - Action: &tg.MessageActionChatEditTitle{Title: "t"}, - }, - &tg.Updates{ - Updates: []tg.UpdateClass{ - &tg.UpdateNewMessage{Message: &tg.Message{ID: 9, PeerID: &tg.PeerUser{UserID: 2}, Date: 1, Message: "u"}, Pts: 1, PtsCount: 1}, - &tg.UpdateMessageID{ID: 9, RandomID: 123}, - }, - Users: []tg.UserClass{&tg.User{ID: 2, AccessHash: 5, FirstName: "A"}}, - Chats: []tg.ChatClass{&tg.Channel{ID: 4, AccessHash: 6, Title: "C", Photo: &tg.ChatPhotoEmpty{}}}, - Date: 100, - Seq: 1, - }, - &tg.User{ - ID: 2, - AccessHash: 5, - FirstName: "A", - Username: "a", - Photo: &tg.UserProfilePhoto{PhotoID: 7, DCID: 2}, - Status: &tg.UserStatusOnline{Expires: 999}, - }, - &tg.UserFull{ - ID: 2, - About: "hi", - Settings: tg.PeerSettings{}, - NotifySettings: tg.PeerNotifySettings{}, - CommonChatsCount: 0, - }, - &tg.Channel{ID: 4, AccessHash: 6, Title: "C", Megagroup: true, Photo: &tg.ChatPhotoEmpty{}}, - &tg.ChannelFull{ - ID: 4, - About: "about", - ReadInboxMaxID: 1, - ReadOutboxMaxID: 1, - UnreadCount: 0, - ChatPhoto: &tg.PhotoEmpty{ID: 0}, - NotifySettings: tg.PeerNotifySettings{}, - Pts: 1, - }, - &tg.Dialog{ - Peer: &tg.PeerUser{UserID: 2}, - TopMessage: 2, - ReadInboxMaxID: 1, - NotifySettings: tg.PeerNotifySettings{}, - }, - &tg.Poll{ - ID: 1, - Question: tg.TextWithEntities{Text: "q?"}, - Answers: []tg.PollAnswerClass{ - &tg.PollAnswer{Text: tg.TextWithEntities{Text: "a"}, Option: []byte{0}}, - &tg.PollAnswer{Text: tg.TextWithEntities{Text: "b"}, Option: []byte{1}}, - }, - }, - &tg.PollResults{ - Results: []tg.PollAnswerVoters{ - {Option: []byte{0}, Voters: 3, Chosen: true}, - {Option: []byte{1}, Voters: 1}, - }, - TotalVoters: 4, - }, - &tg.MessagesDialogs{ - Dialogs: []tg.DialogClass{&tg.Dialog{Peer: &tg.PeerUser{UserID: 2}, TopMessage: 2, NotifySettings: tg.PeerNotifySettings{}}}, - Messages: []tg.MessageClass{&tg.Message{ID: 2, PeerID: &tg.PeerUser{UserID: 2}, Date: 1, Message: "x"}}, - Chats: []tg.ChatClass{}, - Users: []tg.UserClass{&tg.User{ID: 2, AccessHash: 5, FirstName: "A"}}, - }, - &tg.MessagesMessages{ - Messages: []tg.MessageClass{&tg.Message{ID: 2, PeerID: &tg.PeerUser{UserID: 2}, Date: 1, Message: "x"}}, - Chats: []tg.ChatClass{}, - Users: []tg.UserClass{&tg.User{ID: 2, AccessHash: 5, FirstName: "A"}}, - }, - } -} diff --git a/internal/compat/layerwire/fallback.go b/internal/compat/layerwire/fallback.go deleted file mode 100644 index b9bb043e..00000000 --- a/internal/compat/layerwire/fallback.go +++ /dev/null @@ -1,144 +0,0 @@ -package layerwire - -import "github.com/gotd/td/bin" - -// Hand-written transforms for the message subtree: structural changes that are -// not pure field drops, and 227-only constructors that older clients cannot -// decode. By-abstract-type fallbacks auto-cover future variants of the same -// class (e.g. a new MessageAction added in a later layer still degrades to -// messageActionEmpty). See docs/layer-compat-220-227-design.md §5.2. - -const ( - messageActionEmptyID = 0xb6aef7b0 // messageActionEmpty = MessageAction - messageEntityUnknownID = 0xbb92ba95 // messageEntityUnknown offset:int length:int = MessageEntity - pageBlockUnsupportedID = 0x13567e8a // pageBlockUnsupported = PageBlock - textEmptyID = 0xdc3d824f // textEmpty = RichText -) - -func init() { - structuralTransforms["pollAnswerVoters"] = transcodePollAnswerVoters - - // 227-only constructors degrade to a class member every supported layer has. - // Each target carries no body, so the replacement is a bare id (a new - // variant inside a Vector keeps its slot — no element drop needed). - newTypeFallbacksByType["MessageAction"] = replaceWithBare(messageActionEmptyID) - newTypeFallbacksByType["PageBlock"] = replaceWithBare(pageBlockUnsupportedID) - newTypeFallbacksByType["RichText"] = replaceWithBare(textEmptyID) - newTypeFallbacksByType["MessageEntity"] = fallbackMessageEntity -} - -// replaceWithBare consumes the canonical (227-only) object and emits a -// bodyless constructor id the target layer understands. -func replaceWithBare(id uint32) fallbackFunc { - return func(cl *ctorLayout, in, out *bin.Buffer, layer, depth int, walk *walkState) error { - if err := in.ConsumeID(cl.crc); err != nil { - return err - } - if err := walk.skipCtorBody(canonical, in, cl, depth); err != nil { - return err - } - out.PutID(id) - return nil - } -} - -// peerVectorField is a synthetic Vector layout used to consume the -// canonical recent_voters field. -var peerVectorField = fieldLayout{ - kind: kindVector, - flagBit: -1, - elem: &fieldLayout{kind: kindObject, typeName: "Peer", flagBit: -1}, -} - -var pollOptionBytesField = fieldLayout{kind: kindBytes, flagBit: -1} - -// transcodePollAnswerVoters downgrades pollAnswerVoters: canonical (227) made -// voters conditional (flags.2?int) and added recent_voters (flags.2?Vector); -// older layers carry voters as a plain int. The leading CRC is already consumed. -// -// 227: flags:# chosen:flags.0?true correct:flags.1?true option:bytes -// voters:flags.2?int recent_voters:flags.2?Vector -// <=226: flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:int -func transcodePollAnswerVoters(cl *ctorLayout, target uint32, in, out *bin.Buffer, layer, depth int, walk *walkState) error { - flags, err := in.Uint32() - if err != nil { - return err - } - optionStart := in.Buf - if err := walk.skipValue(canonical, in, &pollOptionBytesField, cl, depth); err != nil { - return err - } - optionRaw := optionStart[:len(optionStart)-len(in.Buf)] - var voters int - if flags&(1<<2) != 0 { - if voters, err = in.Int(); err != nil { - return err - } - if err := walk.skipValue(canonical, in, &peerVectorField, cl, depth); err != nil { - return err - } - } - out.PutID(target) - out.PutUint32(flags & 0b11) // retain chosen/correct, clear the moved bit 2 - out.Put(optionRaw) - out.PutInt(voters) - return nil -} - -// fallbackMessageEntity replaces any 227-only MessageEntity with -// messageEntityUnknown, preserving offset/length so text positions stay valid. -func fallbackMessageEntity(cl *ctorLayout, in, out *bin.Buffer, layer, depth int, walk *walkState) error { - id, err := in.PeekID() - if err != nil { - return err - } - if err := in.ConsumeID(id); err != nil { - return err - } - offset, length, err := canonical.decodeOffsetLength(in, cl, depth, walk) - if err != nil { - return err - } - out.PutID(messageEntityUnknownID) - out.PutInt(offset) - out.PutInt(length) - return nil -} - -// decodeOffsetLength walks a constructor body (no leading CRC) per the canonical -// layout, returning its offset/length int fields and discarding the rest. -func (m *schemaModel) decodeOffsetLength(in *bin.Buffer, cl *ctorLayout, depth int, walk *walkState) (offset, length int, err error) { - var flags map[string]uint32 - for i := range cl.fields { - f := &cl.fields[i] - if f.isFlags { - v, e := in.Uint32() - if e != nil { - return 0, 0, e - } - if flags == nil { - flags = make(map[string]uint32, 2) - } - flags[f.name] = v - continue - } - if f.conditional() && flags[f.flagName]&(1<server (Input*) type the -// server never emits, so it cannot appear in downgraded output. -func isInbound(cl *ctorLayout) bool { - return strings.HasPrefix(cl.result, "Input") || strings.HasPrefix(cl.name, "input") -} - -// collectReachableTypes returns abstract/bare type names that can appear in -// downgraded output at a layer: those referenced by a *retained* field of a -// constructor that is itself emittable (not a function, not a 227-only type that -// is replaced wholesale, not an inbound Input* type). -func collectReachableTypes(lt *layerTables) map[string]bool { - refs := map[string]bool{} - var addField func(f *fieldLayout) - addField = func(f *fieldLayout) { - switch f.kind { - case kindObject, kindBareObject: - refs[f.typeName] = true - case kindVector, kindVectorBare: - addField(f.elem) - } - } - for crc, cl := range canonical.byCRC { - if cl.isFunc || isInbound(cl) || lt.newTypes[crc] { - continue - } - var keep map[string]bool - if r := lt.rules[crc]; r != nil && r.structural == "" { - keep = r.keep - } - for i := range cl.fields { - f := &cl.fields[i] - if f.isFlags { - continue - } - if keep != nil && !keep[f.name] { - continue // dropped by a mechanical rule - } - addField(f) - } - } - return refs -} - -// unemittedAllowlist is the curated set of reachable-but-unhandled 227-only -// constructors that telesrv does not actually emit (confirmed against the -// outbound-constructor scoping audit, 2026-06-25). They live behind features the -// server lacks (instant-view rich pages, AI compose, managed bots, web-browser -// settings, guest chat, star-gift rarity/craft, join-chat bot results). The gate -// fails if a NEW reachable type appears that is neither handled nor listed here, -// forcing a human to triage on every gotd bump / client upgrade. -var unemittedAllowlist = map[string]bool{ - "aiComposeTone": true, - "aiComposeToneDefault": true, - "aiComposeToneExample": true, - "botInlineMessageRichMessage": true, - "channelAdminLogEventActionParticipantEditRank": true, - "joinChatBotResultApproved": true, - "joinChatBotResultDeclined": true, - "joinChatBotResultQueued": true, - "joinChatBotResultWebView": true, - "messages.chatInviteJoinResultWebView": true, - "messages.emojiGameDiceInfo": true, - "messages.emojiGameUnavailable": true, - "requestPeerTypeCreateBot": true, - "richMessage": true, - "sendMessageRichMessageDraftAction": true, - "starGiftAttributeRarity": true, - "starGiftAttributeRarityEpic": true, - "starGiftAttributeRarityLegendary": true, - "starGiftAttributeRarityRare": true, - "starGiftAttributeRarityUncommon": true, - "topPeerCategoryBotsGuestChat": true, - "updateAiComposeTones": true, - "updateBotGuestChatQuery": true, - "updateChatParticipantRank": true, - "updateEmojiGameInfo": true, - "updateJoinChatWebViewDecision": true, - "updateManagedBot": true, - "updateNewBotConnection": true, - "updateStarGiftCraftFail": true, - "updateWebBrowserException": true, - "updateWebBrowserSettings": true, - "webDomainException": true, - "webPageAttributeAiComposeTone": true, - // Structural changed-types telesrv does not emit (see design Appendix C and - // the scoping audit); their hand transforms are deferred to CI-todo. - "pageListOrderedItemText": true, - "pageListOrderedItemBlocks": true, - "starGiftAttributeModel": true, - "starGiftAttributeBackdrop": true, - "starGiftAttributePattern": true, - "urlAuthResultAccepted": true, - "inputMediaPoll": true, // inbound only -} - -func newTypeHandled(crc uint32, result string) bool { - if newTypeFallbacks[crc] != nil { - return true - } - return newTypeFallbacksByType[result] != nil -} - -// TestCoverageGate is the drift gate. For every supported layer, each 227-only -// or structural constructor that can appear in downgraded output must be either -// handled (fallback / structural transform) or explicitly allowlisted as not -// emitted. A bare failure means new wire shape slipped in unhandled. -func TestCoverageGate(t *testing.T) { - for layer := SupportedFloor; layer < CanonicalLayer; layer++ { - lt := tables[layer] - if lt == nil { - t.Fatalf("no tables for layer %d", layer) - } - reach := collectReachableTypes(lt) - - // Structural rules that are reachable need a registered transform. - for crc, r := range lt.rules { - if r.structural == "" { - continue - } - cl := canonical.byCRC[crc] - reachable := cl != nil && reach[cl.result] && !isInbound(cl) - handled := structuralTransforms[r.structural] != nil - if reachable && !handled && !unemittedAllowlist[nameOf(crc)] { - t.Errorf("layer %d: reachable structural %s (%#08x) has no transform", layer, nameOf(crc), crc) - } - } - - // New constructors reachable through a retained field need a fallback. - var gaps []string - for crc := range lt.newTypes { - cl := canonical.byCRC[crc] - if cl == nil || cl.isFunc || isInbound(cl) { - continue - } - if !reach[cl.result] { - continue - } - if newTypeHandled(crc, cl.result) || unemittedAllowlist[cl.name] { - continue - } - gaps = append(gaps, cl.name) - } - if len(gaps) > 0 { - sort.Strings(gaps) - t.Errorf("layer %d: %d reachable 227-only types lack a fallback or allowlist entry:\n %v", layer, len(gaps), gaps) - } - } -} - -func nameOf(crc uint32) string { - if cl := canonical.byCRC[crc]; cl != nil { - return cl.name - } - return "?" -} diff --git a/internal/compat/layerwire/gen/main.go b/internal/compat/layerwire/gen/main.go deleted file mode 100644 index 12817bd7..00000000 --- a/internal/compat/layerwire/gen/main.go +++ /dev/null @@ -1,450 +0,0 @@ -// Command layerwire-gen diffs the canonical gotd schema (Layer 227, the bytes -// telesrv actually emits) against historical TDesktop api.tl layers (220..226) -// and classifies every per-constructor change as either MECHANICAL (a pure -// append-only delta that can be downgraded by dropping trailing/optional fields -// and masking flag bits) or STRUCTURAL (field reorder / reinterpretation that -// needs a hand-written transform). -// -// It is the generate-time half of the layer-compat design -// (docs/layer-compat-220-227-design.md). Run from the telesrv module root: -// -// go run ./internal/compat/layerwire/gen -report -// -// This first iteration only prints a report so the numbers can be validated -// against the design doc before any table is emitted. -package main - -import ( - "flag" - "fmt" - "go/format" - "os" - "path/filepath" - "sort" - "strconv" - "strings" - - "github.com/gotd/tl" -) - -// canonicalLayer is the layer telesrv's gotd is pinned to. -const canonicalLayer = 227 - -// supportedFloor is the oldest client layer telesrv aims to serve. -const supportedFloor = 220 - -// spec is a single TL constructor or method with field-level metadata. -type spec struct { - qname string // qualified name, e.g. "messages.dialogs" or "message" - crc uint32 - params []tl.Parameter - isFunc bool -} - -// schema indexes one parsed .tl file by qualified name and by CRC. -type schema struct { - layer int - byName map[string]*spec - byCRC map[uint32]*spec - ordered []*spec -} - -func qualify(d tl.Definition) string { - if len(d.Namespace) == 0 { - return d.Name - } - return strings.Join(d.Namespace, ".") + "." + d.Name -} - -func load(path string) (*schema, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - parsed, err := tl.Parse(f) - if err != nil { - return nil, fmt.Errorf("parse %s: %w", path, err) - } - s := &schema{ - layer: parsed.Layer, - byName: make(map[string]*spec), - byCRC: make(map[uint32]*spec), - } - for i := range parsed.Definitions { - sd := parsed.Definitions[i] - d := sd.Definition - sp := &spec{ - qname: qualify(d), - crc: d.ID, - params: d.Params, - isFunc: sd.Category == tl.CategoryFunction, - } - // Skip the implicit vector pseudo-definition if present. - if sp.qname == "vector" { - continue - } - s.byName[sp.qname] = sp - s.byCRC[sp.crc] = sp - s.ordered = append(s.ordered, sp) - } - return s, nil -} - -// classifyResult describes how a changed constructor downgrades from canonical -// (227) to a target layer. -type classifyResult struct { - mechanical bool - drops []string // canonical fields absent at the target layer - reason string // populated when !mechanical -} - -// classifyDowngrade aligns the target params as a subsequence (by name) of the -// canonical params. Success ⇒ mechanical drop of the unmatched canonical fields. -// Any name mismatch, type change, or flag-condition change ⇒ structural. -func classifyDowngrade(from, to *spec) classifyResult { - var drops []string - i, j := 0, 0 - fp, tp := from.params, to.params - for j < len(tp) { - // Advance over canonical fields until we reach the target field name. - for i < len(fp) && fp[i].Name != tp[j].Name { - drops = append(drops, fp[i].Name) - i++ - } - if i == len(fp) { - return classifyResult{reason: fmt.Sprintf("target field %q not found in canonical (reorder/insert)", tp[j].Name)} - } - if reason := compatible(fp[i], tp[j]); reason != "" { - return classifyResult{reason: fmt.Sprintf("field %q: %s", tp[j].Name, reason)} - } - i++ - j++ - } - for ; i < len(fp); i++ { - drops = append(drops, fp[i].Name) - } - return classifyResult{mechanical: true, drops: drops} -} - -// compatible reports "" if a kept field is wire-compatible between canonical and -// target, or a reason string otherwise. -func compatible(f, t tl.Parameter) string { - if f.Flags != t.Flags { - return "flags-int vs field mismatch" - } - if f.Flags { - // Both are `#` flag integers; the name must match because conditional - // fields reference it by name. - if f.Name != t.Name { - return fmt.Sprintf("flags int renamed %q->%q", t.Name, f.Name) - } - return "" - } - // Conditional-ness must match exactly (no flag-bit remap supported yet). - fc, tc := f.Flag != nil, t.Flag != nil - if fc != tc { - return "conditional-ness changed" - } - if fc { - if f.Flag.Name != t.Flag.Name || f.Flag.Index != t.Flag.Index { - return fmt.Sprintf("flag moved %s.%d->%s.%d", t.Flag.Name, t.Flag.Index, f.Flag.Name, f.Flag.Index) - } - } - if f.Type.String() != t.Type.String() { - return fmt.Sprintf("type changed %s->%s", t.Type.String(), f.Type.String()) - } - return "" -} - -type changed struct { - qname string - fromCRC, toCRC uint32 - res classifyResult -} - -// diff compares canonical (from) against a single target layer (to). -type diffResult struct { - layer int - changedTypes []changed - changedMethods []changed - newTypes []string // exist in canonical, absent at target - newMethods []string - removedTypes []string // exist at target, absent in canonical -} - -func diff(from, to *schema) diffResult { - r := diffResult{layer: to.layer} - for _, sp := range from.ordered { - other, ok := to.byName[sp.qname] - if !ok { - if sp.isFunc { - r.newMethods = append(r.newMethods, sp.qname) - } else { - r.newTypes = append(r.newTypes, sp.qname) - } - continue - } - if other.crc == sp.crc { - continue - } - c := changed{qname: sp.qname, fromCRC: sp.crc, toCRC: other.crc, res: classifyDowngrade(sp, other)} - if sp.isFunc { - r.changedMethods = append(r.changedMethods, c) - } else { - r.changedTypes = append(r.changedTypes, c) - } - } - for _, sp := range to.ordered { - if _, ok := from.byName[sp.qname]; !ok { - r.removedTypes = append(r.removedTypes, sp.qname) - } - } - return r -} - -func main() { - var ( - schemaDir = flag.String("schema", "internal/compat/layerwire/_schema", "dir with layer-NNN.tl") - canonical = flag.String("canonical", "internal/compat/layerwire/schema/canonical-227.tl", "gotd canonical 227 schema") - emit = flag.String("emit", "", "write generated tables_gen.go to this path") - _ = flag.Bool("report", true, "print report") - ) - flag.Parse() - - canon, err := load(*canonical) - if err != nil { - fmt.Fprintln(os.Stderr, "load canonical:", err) - os.Exit(1) - } - - if *emit != "" { - if err := emitTables(canon, *schemaDir, *emit); err != nil { - fmt.Fprintln(os.Stderr, "emit:", err) - os.Exit(1) - } - fmt.Printf("wrote %s\n", *emit) - return - } - fmt.Printf("canonical (gotd) layer=%d defs=%d\n", canon.layer, len(canon.ordered)) - - // Per-layer diff + union across the supported range. - unionChangedTypes := map[string]bool{} - unionChangedMethods := map[string]bool{} - unionNewTypes := map[string]bool{} - unionNewMethods := map[string]bool{} - structuralTypes := map[string]string{} // qname -> reason (worst case seen) - - for L := supportedFloor; L < canonicalLayer; L++ { - path := filepath.Join(*schemaDir, fmt.Sprintf("layer-%d.tl", L)) - tgt, err := load(path) - if err != nil { - fmt.Fprintln(os.Stderr, "load", path, ":", err) - os.Exit(1) - } - r := diff(canon, tgt) - mech, struc := 0, 0 - for _, c := range r.changedTypes { - unionChangedTypes[c.qname] = true - if c.res.mechanical { - mech++ - } else { - struc++ - structuralTypes[c.qname] = c.res.reason - } - } - for _, c := range r.changedMethods { - unionChangedMethods[c.qname] = true - } - for _, n := range r.newTypes { - unionNewTypes[n] = true - } - for _, n := range r.newMethods { - unionNewMethods[n] = true - } - fmt.Printf("layer %d: defs=%d changedTypes=%d (mech=%d struc=%d) changedMethods=%d newTypes=%d newMethods=%d removed=%d\n", - L, len(tgt.ordered), len(r.changedTypes), mech, struc, len(r.changedMethods), len(r.newTypes), len(r.newMethods), len(r.removedTypes)) - } - - fmt.Printf("\n=== UNION %d..%d vs %d ===\n", supportedFloor, canonicalLayer-1, canonicalLayer) - fmt.Printf("changed types: %d\n", len(unionChangedTypes)) - fmt.Printf("changed methods: %d\n", len(unionChangedMethods)) - fmt.Printf("new types: %d\n", len(unionNewTypes)) - fmt.Printf("new methods: %d\n", len(unionNewMethods)) - fmt.Printf("structural types (need hand transform): %d\n", len(structuralTypes)) - for _, q := range sortedKeys(structuralTypes) { - fmt.Printf(" - %s : %s\n", q, structuralTypes[q]) - } - - // Detailed 220-vs-227 drop table (matches design doc Appendix A). - fmt.Printf("\n=== 220 vs 227 changed-type drop table ===\n") - tgt220, _ := load(filepath.Join(*schemaDir, "layer-220.tl")) - r := diff(canon, tgt220) - sort.Slice(r.changedTypes, func(a, b int) bool { return r.changedTypes[a].qname < r.changedTypes[b].qname }) - for _, c := range r.changedTypes { - tag := "MECH" - detail := "drop: " + strings.Join(c.res.drops, ", ") - if !c.res.mechanical { - tag = "STRUCT" - detail = c.res.reason - } - fmt.Printf(" [%-6s] %-34s %#08x->%#08x %s\n", tag, c.qname, c.toCRC, c.fromCRC, detail) - } -} - -// emitTables writes the runtime downgrade tables (tables_gen.go) for every -// supported layer: per changed constructor a mechanical keep-list or a -// structural marker, plus the set of canonical CRCs absent at that layer. -func emitTables(canon *schema, schemaDir, outPath string) error { - var b strings.Builder - b.WriteString("// Code generated by ./internal/compat/layerwire/gen; DO NOT EDIT.\n") - b.WriteString("// Source: gotd canonical schema (Layer 227) diffed against TDesktop api.tl@N.\n\n") - b.WriteString("package layerwire\n\n") - b.WriteString("// generatedTables maps a supported client layer to its canonical(227)->layer\n") - b.WriteString("// downgrade table. See docs/layer-compat-220-227-design.md.\n") - b.WriteString("var generatedTables = map[int]layerRaw{\n") - - // inbound 方法升级(扁平:老方法 CRC -> 227 CRC)。老 CRC 本身编码了格式,故无需 layer 维度。 - // 仅收"升级安全"的方法:227 新增字段全为 flag-gated 条件字段(老客户端清零位=零字节, - // 其 body 本就是合法 227 body,换 4 字节 CRC 即可交给 227 handler)。 - inboundUpgrades := map[uint32]uint32{} // oldCRC -> 227CRC - inboundUnsafe := map[string]string{} // qname -> reason - - for L := supportedFloor; L < canonicalLayer; L++ { - tgt, err := load(filepath.Join(schemaDir, fmt.Sprintf("layer-%d.tl", L))) - if err != nil { - return err - } - r := diff(canon, tgt) - for _, c := range r.changedMethods { - canonSpec := canon.byName[c.qname] - if reason := methodUpgradeSafe(canonSpec, c.res); reason == "" { - inboundUpgrades[c.toCRC] = c.fromCRC // client(old) -> canonical(227) - } else if _, done := inboundUpgrades[c.toCRC]; !done { - inboundUnsafe[c.qname] = reason - } - } - fmt.Fprintf(&b, "\t%d: {\n", L) - - sort.Slice(r.changedTypes, func(i, j int) bool { return r.changedTypes[i].fromCRC < r.changedTypes[j].fromCRC }) - b.WriteString("\t\trules: map[uint32]ruleRaw{\n") - for _, c := range r.changedTypes { - canonSpec := canon.byName[c.qname] - if c.res.mechanical { - dropSet := map[string]bool{} - for _, d := range c.res.drops { - dropSet[d] = true - } - var keep []string - for _, p := range canonSpec.params { - if !dropSet[p.Name] { - keep = append(keep, p.Name) - } - } - fmt.Fprintf(&b, "\t\t\t0x%08x: {target: 0x%08x, keep: %s}, // %s\n", c.fromCRC, c.toCRC, goStrSlice(keep), c.qname) - } else { - fmt.Fprintf(&b, "\t\t\t0x%08x: {target: 0x%08x, structural: %q}, // %s\n", c.fromCRC, c.toCRC, c.qname, c.res.reason) - } - } - b.WriteString("\t\t},\n") - - var newCRC []uint32 - for _, q := range r.newTypes { - if sp := canon.byName[q]; sp != nil { - newCRC = append(newCRC, sp.crc) - } - } - sort.Slice(newCRC, func(i, j int) bool { return newCRC[i] < newCRC[j] }) - b.WriteString("\t\tnewTypes: []uint32{") - for i, c := range newCRC { - if i%6 == 0 { - b.WriteString("\n\t\t\t") - } - fmt.Fprintf(&b, "0x%08x, ", c) - } - if len(newCRC) > 0 { - b.WriteString("\n\t\t") - } - b.WriteString("},\n") - b.WriteString("\t},\n") - } - b.WriteString("}\n\n") - - // Flat inbound method CRC upgrade table. - b.WriteString("// inboundMethodUpgrades maps an old client method constructor id to the\n") - b.WriteString("// canonical (227) id. Only upgrade-safe changes (all 227 additions flag-gated)\n") - b.WriteString("// are listed: rewriting the 4-byte id yields a valid 227 request body.\n") - if len(inboundUnsafe) > 0 { - b.WriteString("// NOT upgrade-safe as a pure id swap (declare a body transform in client-drift.tl when needed):\n") - for _, q := range sortedKeys(inboundUnsafe) { - fmt.Fprintf(&b, "// %s: %s\n", q, inboundUnsafe[q]) - } - } - b.WriteString("var inboundMethodUpgrades = map[uint32]uint32{\n") - oldCRCs := make([]uint32, 0, len(inboundUpgrades)) - for old := range inboundUpgrades { - oldCRCs = append(oldCRCs, old) - } - sort.Slice(oldCRCs, func(i, j int) bool { return oldCRCs[i] < oldCRCs[j] }) - for _, old := range oldCRCs { - fmt.Fprintf(&b, "\t0x%08x: 0x%08x, // %s\n", old, inboundUpgrades[old], canon.byCRC[inboundUpgrades[old]].qname) - } - b.WriteString("}\n") - - formatted, err := format.Source([]byte(b.String())) - if err != nil { - _ = os.WriteFile(outPath, []byte(b.String()), 0o644) - return fmt.Errorf("gofmt: %w", err) - } - return os.WriteFile(outPath, formatted, 0o644) -} - -// methodUpgradeSafe reports "" if a layer-N request body for a changed method -// is also a valid 227 body after only swapping the constructor id — i.e. the -// downgrade is mechanical and every 227-only field is flag-gated (a conditional -// field the old client leaves clear ⇒ zero wire bytes). A 227-only non-conditional -// field or an inserted flags integer breaks the byte alignment ⇒ unsafe. -func methodUpgradeSafe(canonSpec *spec, res classifyResult) string { - if !res.mechanical { - return res.reason - } - byName := map[string]tl.Parameter{} - for _, p := range canonSpec.params { - byName[p.Name] = p - } - for _, d := range res.drops { - p, ok := byName[d] - if !ok { - return fmt.Sprintf("dropped field %q not in canonical", d) - } - if p.Flags { - return fmt.Sprintf("227 inserts flags integer %q", d) - } - if p.Flag == nil { - return fmt.Sprintf("227-only field %q is non-conditional", d) - } - } - return "" -} - -func goStrSlice(ss []string) string { - var b strings.Builder - b.WriteString("[]string{") - for i, s := range ss { - if i > 0 { - b.WriteString(", ") - } - b.WriteString(strconv.Quote(s)) - } - b.WriteString("}") - return b.String() -} - -func sortedKeys[V any](m map[string]V) []string { - ks := make([]string, 0, len(m)) - for k := range m { - ks = append(ks, k) - } - sort.Strings(ks) - return ks -} diff --git a/internal/compat/layerwire/inbound.go b/internal/compat/layerwire/inbound.go deleted file mode 100644 index 2cc7bd5f..00000000 --- a/internal/compat/layerwire/inbound.go +++ /dev/null @@ -1,326 +0,0 @@ -package layerwire - -import ( - _ "embed" - "encoding/binary" - "fmt" - - "github.com/gotd/td/bin" -) - -// Canonical ids used to synthesize converted/defaulted values. -const ( - inputUserID = 0xf21158c6 // inputUser user_id:long access_hash:long - inputMessageID = 0xa676a322 // inputMessageID id:int - inputChannelEmptyID = 0xee8c1e86 // inputChannelEmpty - inputChannelID = 0xf35aec28 // inputChannel channel_id:long access_hash:long - inputChannelFromMessageID = 0x5b934f9d // inputChannelFromMessage peer:InputPeer msg_id:int channel_id:long - inputPeerEmptyID = 0x7f3b18ea // inputPeerEmpty - inputPeerChannelID = 0x27bcbbfc // inputPeerChannel channel_id:long access_hash:long - inputPeerChannelFromMessageID = 0xbd2a0840 // inputPeerChannelFromMessage peer:InputPeer msg_id:int channel_id:long - boolFalseID = 0xbc799737 // boolFalse -) - -//go:embed schema/client-drift.tl -var clientDriftSchema string - -// driftModel holds the declared old-layout of each client-drift constructor. -var driftModel = mustLoadDrift() - -func mustLoadDrift() *schemaModel { - m, err := parseSchemaModel(clientDriftSchema) - if err != nil { - panic("layerwire: parse client-drift schema: " + err.Error()) - } - return m -} - -// driftFieldRenames maps a canonical field that was renamed from the client's -// old constructor: key "\x00" -> old field. -// Pure schema diff cannot recover a rename, so it is declared here (data, not a -// transform). It is the only thing a structural rename needs. -var driftFieldRenames = map[string]string{ - "bots.exportBotToken\x00bot": "bot_id", - "messages.editChatCreator\x00peer": "channel", -} - -// fieldConverter rewrites one field whose wire type changed between the old and -// canonical layout. Keyed by "->"; raw is the old field's -// encoded bytes. Reusable across any method with the same type change. -type fieldConverter func(raw []byte, out *bin.Buffer, walk *walkState, owner *ctorLayout, field *fieldLayout) error - -var fieldConverters = map[string]fieldConverter{ - // id:Vector -> id:Vector (wrap each int in inputMessageID). - "Vector->Vector": func(raw []byte, out *bin.Buffer, walk *walkState, owner *ctorLayout, field *fieldLayout) error { - in := &bin.Buffer{Buf: raw} - n, err := in.VectorHeader() - if err != nil { - return err - } - if max := walk.vectorLimit(owner, field); n > max { - return limitf("vector %s.%s length %d exceeds limit %d", ownerName(owner), fieldName(field), n, max) - } - out.PutVectorHeader(n) - for i := 0; i < n; i++ { - v, err := in.Int() - if err != nil { - return err - } - out.PutID(inputMessageID) - out.PutInt(v) - } - if in.Len() != 0 { - return malformedf("%d trailing bytes in Vector converter", in.Len()) - } - return nil - }, - // bot_id:long -> bot:InputUser{user_id, access_hash=0}. - "long->InputUser": func(raw []byte, out *bin.Buffer, walk *walkState, owner *ctorLayout, field *fieldLayout) error { - in := &bin.Buffer{Buf: raw} - id, err := in.Long() - if err != nil { - return err - } - out.PutID(inputUserID) - out.PutLong(id) - out.PutLong(0) - if in.Len() != 0 { - return malformedf("%d trailing bytes in long converter", in.Len()) - } - return nil - }, - // channel:InputChannel -> peer:InputPeer for the old channels.editCreator - // Android constructor. Concrete layouts are otherwise byte-compatible. - "InputChannel->InputPeer": func(raw []byte, out *bin.Buffer, walk *walkState, owner *ctorLayout, field *fieldLayout) error { - in := &bin.Buffer{Buf: raw} - id, err := in.ID() - if err != nil { - return err - } - switch id { - case inputChannelEmptyID: - out.PutID(inputPeerEmptyID) - case inputChannelID: - out.PutID(inputPeerChannelID) - out.Put(in.Buf) - case inputChannelFromMessageID: - out.PutID(inputPeerChannelFromMessageID) - out.Put(in.Buf) - default: - return bin.NewUnexpectedID(id) - } - return nil - }, -} - -// UpgradeInbound converts an old client's inbound request to canonical (227) -// form so the normal gotd dispatcher can handle it. It unifies three data-driven -// sources, all of which require no per-method handler code: -// - inboundMethodUpgrades (generated from api.tl diff): official layer drift. -// - clientMethodAliases (client_aliases.go): body-identical client drift. -// - driftModel (client-drift.tl): body-different client drift, upgraded by the -// generic engine below. -// -// ok=false means no upgrade applies. On ok=true the returned buffer (canonical -// id + body) is what to dispatch. -func UpgradeInbound(id uint32, in *bin.Buffer) (*bin.Buffer, bool, error) { - if newID, ok := UpgradeMethodCRC(id); ok { - target := canonical.byCRC[newID] - if target == nil || !target.isFunc { - return nil, true, malformedf("alias %#08x targets unknown canonical method %#08x", id, newID) - } - if err := validateAliasedMethod(id, target, in.Buf); err != nil { - return nil, true, err - } - // Copy rather than rewrite in place: never mutate the caller's buffer - // (matches the body-transform path, which also returns a fresh buffer). - out := &bin.Buffer{Buf: append([]byte(nil), in.Buf...)} - binary.LittleEndian.PutUint32(out.Buf[:4], newID) - return out, true, nil - } - if old := driftModel.byCRC[id]; old != nil { - out, err := upgradeFromDrift(old, in, newWalkState()) - if err != nil { - return nil, true, classifyWalkError(fmt.Errorf("layerwire: upgrade %s (%#08x): %w", old.name, id, err)) - } - return out, true, nil - } - return nil, false, nil -} - -// validateAliasedMethod validates the old-id/canonical-body shape before -// allocating the replacement buffer. The body is walked against the canonical -// target layout while the original constructor id remains untouched. -func validateAliasedMethod(oldID uint32, target *ctorLayout, raw []byte) error { - walk := newWalkState() - if err := walk.enter(1, "constructor"); err != nil { - return err - } - b := &bin.Buffer{Buf: raw} - if err := b.ConsumeID(oldID); err != nil { - return classifyWalkError(err) - } - if err := walk.skipCtorBody(canonical, b, target, 1); err != nil { - return classifyWalkError(err) - } - if b.Len() != 0 { - return malformedf("%d trailing bytes after aliased method %s", b.Len(), target.name) - } - return nil -} - -// IsClientDrift reports whether id is a client-private constructor (DrKLO -// constructor drift), as opposed to official layer drift from api.tl. -func IsClientDrift(id uint32) bool { - if _, ok := clientMethodAliases[id]; ok { - return true - } - return driftModel.byCRC[id] != nil -} - -// upgradeFromDrift rebuilds a canonical (227) request from an old client-drift -// body, comparing the declared old layout to the canonical layout field by field. -func upgradeFromDrift(old *ctorLayout, in *bin.Buffer, walk *walkState) (*bin.Buffer, error) { - target := canonical.byName[old.name] - if target == nil { - return nil, fmt.Errorf("no canonical method %q", old.name) - } - if err := walk.enter(1, "constructor"); err != nil { - return nil, err - } - if err := in.ConsumeID(old.crc); err != nil { - return nil, err - } - - // Decode the old body: capture each present field's raw bytes + flag ints. - vals := make(map[string][]byte, len(old.fields)) - present := make(map[string]bool, len(old.fields)) - oldFlags := make(map[string]uint32, 2) - oldByName := make(map[string]*fieldLayout, len(old.fields)) - for i := range old.fields { - f := &old.fields[i] - oldByName[f.name] = f - if f.isFlags { - v, err := in.Uint32() - if err != nil { - return nil, err - } - oldFlags[f.name] = v - continue - } - if f.conditional() && oldFlags[f.flagName]&(1<"+typeSig(nf)] - if conv == nil { - return nil, fmt.Errorf("field %q: no converter %s->%s", nf.name, typeSig(of), typeSig(nf)) - } - if err := conv(vals[oldName], out, walk, old, of); err != nil { - return nil, fmt.Errorf("field %q convert: %w", nf.name, err) - } - } else { - out.Put(vals[oldName]) // shared field, identical wire (kindTrue => no bytes) - } - continue - } - // Canonical-only field absent in old. - if nf.conditional() || nf.kind == kindTrue { - continue // optional: leave absent (its flag bit is clear) - } - if err := writeDefault(nf, out); err != nil { - return nil, fmt.Errorf("field %q default: %w", nf.name, err) - } - } - return out, nil -} - -// writeDefault writes the zero value of a required canonical-only field. -func writeDefault(f *fieldLayout, out *bin.Buffer) error { - switch f.kind { - case kindInt: - out.PutInt(0) - case kindLong: - out.PutLong(0) - case kindDouble: - out.PutDouble(0) - case kindInt128: - out.PutInt128(bin.Int128{}) - case kindInt256: - out.PutInt256(bin.Int256{}) - case kindBytes: - out.PutBytes(nil) - case kindString: - out.PutString("") - case kindBool: - out.PutID(boolFalseID) - case kindVector: - out.PutVectorHeader(0) - case kindVectorBare: - out.PutInt(0) - default: - return fmt.Errorf("cannot default kind %d (boxed object needs a transform)", f.kind) - } - return nil -} - -// typeSig is a stable wire-type signature for matching/converter lookup. -func typeSig(f *fieldLayout) string { - switch f.kind { - case kindInt: - return "int" - case kindLong: - return "long" - case kindDouble: - return "double" - case kindInt128: - return "int128" - case kindInt256: - return "int256" - case kindBytes: - return "bytes" - case kindString: - return "string" - case kindBool: - return "Bool" - case kindTrue: - return "true" - case kindVector: - return "Vector<" + typeSig(f.elem) + ">" - case kindVectorBare: - return "vector<" + typeSig(f.elem) + ">" - case kindObject, kindBareObject: - return f.typeName - default: - return fmt.Sprintf("kind%d", f.kind) - } -} diff --git a/internal/compat/layerwire/inbound_test.go b/internal/compat/layerwire/inbound_test.go deleted file mode 100644 index 1d4028b2..00000000 --- a/internal/compat/layerwire/inbound_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package layerwire - -import "testing" - -// TestInboundUpgradeTableWellFormed checks every inbound upgrade maps an old id -// to a real canonical method id, and that the old id is genuinely historical -// (not already a canonical constructor). -func TestInboundUpgradeTableWellFormed(t *testing.T) { - if len(inboundMethodUpgrades) == 0 { - t.Fatal("inboundMethodUpgrades is empty") - } - for oldID, newID := range inboundMethodUpgrades { - cl := canonical.byCRC[newID] - if cl == nil { - t.Errorf("upgrade target %#08x is not a canonical constructor", newID) - continue - } - if !cl.isFunc { - t.Errorf("upgrade target %s (%#08x) is not a method", cl.name, newID) - } - if oldID == newID { - t.Errorf("%s: old id equals canonical id %#08x", cl.name, oldID) - } - if prev := canonical.byCRC[oldID]; prev != nil { - t.Errorf("old id %#08x collides with canonical %s", oldID, prev.name) - } - } -} - -// TestClientMethodAliasesWellFormed checks every hand-maintained client-drift -// alias maps to a real canonical method, and is reachable via UpgradeMethodCRC. -func TestClientMethodAliasesWellFormed(t *testing.T) { - for oldID, newID := range clientMethodAliases { - cl := canonical.byCRC[newID] - if cl == nil || !cl.isFunc { - t.Errorf("alias target %#08x is not a canonical method", newID) - } - if _, ok := inboundMethodUpgrades[oldID]; ok { - t.Errorf("alias %#08x duplicates a generated upgrade entry", oldID) - } - if got, ok := UpgradeMethodCRC(oldID); !ok || got != newID { - t.Errorf("UpgradeMethodCRC(%#08x) = (%#08x,%v), want (%#08x,true)", oldID, got, ok, newID) - } - } -} - -// TestInboundDriftCoverage is the inbound drift gate: it statically proves every -// client-drift constructor in client-drift.tl can be upgraded to its canonical -// method — shared fields match (or have a converter), canonical-only required -// fields are defaultable, and renamed fields are mapped. Adding a TL line that -// isn't auto-upgradable fails here, telling the author exactly what converter or -// rename to declare (instead of discovering it at runtime). -func TestInboundDriftCoverage(t *testing.T) { - defaultable := map[wireKind]bool{ - kindInt: true, kindLong: true, kindDouble: true, kindInt128: true, kindInt256: true, - kindBytes: true, kindString: true, kindBool: true, kindVector: true, kindVectorBare: true, - } - for crc, old := range driftModel.byCRC { - target := canonical.byName[old.name] - if target == nil { - t.Errorf("drift %s (%#08x): no canonical method of that name", old.name, crc) - continue - } - oldHas := map[string]*fieldLayout{} - for i := range old.fields { - oldHas[old.fields[i].name] = &old.fields[i] - } - for i := range target.fields { - nf := &target.fields[i] - if nf.isFlags { - continue - } - oldName := nf.name - if m, ok := driftFieldRenames[old.name+"\x00"+nf.name]; ok { - oldName = m - } - if of, ok := oldHas[oldName]; ok { - if typeSig(of) != typeSig(nf) && fieldConverters[typeSig(of)+"->"+typeSig(nf)] == nil { - t.Errorf("drift %s: field %q needs converter %s->%s", old.name, nf.name, typeSig(of), typeSig(nf)) - } - continue - } - if nf.conditional() || nf.kind == kindTrue { - continue // optional canonical-only field — left absent - } - if !defaultable[nf.kind] { - t.Errorf("drift %s: canonical-only required field %q (kind %d) is not defaultable; declare a transform", old.name, nf.name, nf.kind) - } - } - } -} - -// TestInboundUpgradeSendMessage validates the full chain for the highest-value -// method: a layer-220 client's messages.sendMessage id upgrades to the 227 id. -func TestInboundUpgradeSendMessage(t *testing.T) { - m220 := loadLayerModel(t, 220) - old, ok := m220.byName["messages.sendMessage"] - if !ok { - t.Fatal("messages.sendMessage missing from layer-220 schema") - } - canon, ok := canonical.byName["messages.sendMessage"] - if !ok { - t.Fatal("messages.sendMessage missing from canonical schema") - } - if old.crc == canon.crc { - t.Skip("sendMessage unchanged 220->227; nothing to upgrade") - } - newID, ok := UpgradeMethodCRC(old.crc) - if !ok { - t.Fatalf("sendMessage@220 (%#08x) not in upgrade table", old.crc) - } - if newID != canon.crc { - t.Fatalf("sendMessage upgrade = %#08x, want canonical %#08x", newID, canon.crc) - } -} diff --git a/internal/compat/layerwire/inbound_transform_test.go b/internal/compat/layerwire/inbound_transform_test.go deleted file mode 100644 index e1db366d..00000000 --- a/internal/compat/layerwire/inbound_transform_test.go +++ /dev/null @@ -1,236 +0,0 @@ -package layerwire - -import ( - "testing" - - "github.com/gotd/td/bin" - "github.com/gotd/td/tg" -) - -// validateMethodRequest asserts that buf holds a single canonical (227) method -// request: its leading id equals wantCRC and the canonical walker consumes every -// byte (proving the rebuilt body matches the 227 layout). -func validateMethodRequest(t *testing.T, buf *bin.Buffer, wantCRC uint32, label string) { - t.Helper() - id, err := (&bin.Buffer{Buf: buf.Buf}).PeekID() - if err != nil { - t.Fatalf("%s: peek id: %v", label, err) - } - if id != wantCRC { - t.Fatalf("%s: id = %#08x, want %#08x", label, id, wantCRC) - } - probe := &bin.Buffer{Buf: append([]byte(nil), buf.Buf...)} - if err := canonical.skipObject(probe); err != nil { - t.Fatalf("%s: result not a valid 227 request: %v", label, err) - } - if probe.Len() != 0 { - t.Fatalf("%s: %d trailing bytes in rebuilt request", label, probe.Len()) - } -} - -func TestInboundBodyTransforms(t *testing.T) { - // uploadMedia: peer + media -> flags + peer + media. - t.Run("uploadMedia", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x519bc2b1) - _ = (&tg.InputPeerSelf{}).Encode(&in) - _ = (&tg.InputMediaUploadedPhoto{File: &tg.InputFile{ID: 10, Parts: 1, Name: "a.jpg"}}).Encode(&in) - out, ok, err := UpgradeInbound(0x519bc2b1, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0x14967978, "uploadMedia") - }) - - t.Run("authSignUp", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x80eee427) - in.PutString("+15550000000") - in.PutString("hash") - in.PutString("First") - in.PutString("Last") - out, ok, err := UpgradeInbound(0x80eee427, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0xaac7b717, "authSignUp") - }) - - t.Run("channelsGetMessages", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x93d7b347) - _ = (&tg.InputChannel{ChannelID: 4, AccessHash: 5}).Encode(&in) - in.PutVectorHeader(2) - in.PutInt(11) - in.PutInt(12) - out, ok, err := UpgradeInbound(0x93d7b347, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0xad8c9a23, "channelsGetMessages") - }) - - t.Run("messagesGetMessages", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x4222fa74) - in.PutVectorHeader(2) - in.PutInt(21) - in.PutInt(22) - out, ok, err := UpgradeInbound(0x4222fa74, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, tg.MessagesGetMessagesRequestTypeID, "messagesGetMessages") - var req tg.MessagesGetMessagesRequest - if err := req.Decode(&bin.Buffer{Buf: append([]byte(nil), out.Buf...)}); err != nil { - t.Fatalf("decode upgraded messages.getMessages: %v", err) - } - if len(req.ID) != 2 { - t.Fatalf("upgraded ids = %d, want 2", len(req.ID)) - } - first, ok := req.ID[0].(*tg.InputMessageID) - if !ok || first.ID != 21 { - t.Fatalf("upgraded id[0] = %T %+v, want inputMessageID(21)", req.ID[0], req.ID[0]) - } - }) - - t.Run("botsExportBotToken", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x0063b089) - in.PutLong(777) - in.PutID(0x997275b5) // boolTrue (revoke) - out, ok, err := UpgradeInbound(0x0063b089, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0xbd0d99eb, "botsExportBotToken") - }) - - t.Run("accountRegisterDevice", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x637ea878) - in.PutInt(2) - in.PutString("token-blob") - out, ok, err := UpgradeInbound(0x637ea878, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0xec86017a, "accountRegisterDevice") - }) - - t.Run("contactsSearch", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x11f812d8) - in.PutString("ngame") - in.PutInt(20) - out, ok, err := UpgradeInbound(0x11f812d8, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, tg.ContactsSearchRequestTypeID, "contactsSearch") - var req tg.ContactsSearchRequest - if err := req.Decode(&bin.Buffer{Buf: append([]byte(nil), out.Buf...)}); err != nil { - t.Fatalf("decode upgraded contacts.search: %v", err) - } - if req.Flags != 0 || req.Q != "ngame" || req.Limit != 20 { - t.Fatalf("upgraded contacts.search = flags:%#x q:%q limit:%d", req.Flags, req.Q, req.Limit) - } - }) - - t.Run("langpackGetLangPack", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x9ab5c58e) - in.PutString("en") - out, ok, err := UpgradeInbound(0x9ab5c58e, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0xf2f2330a, "langpackGetLangPack") - }) - - t.Run("langpackGetStrings", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x2e1ee318) - in.PutString("en") - in.PutVectorHeader(2) - in.PutString("key1") - in.PutString("key2") - out, ok, err := UpgradeInbound(0x2e1ee318, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0xefea3803, "langpackGetStrings") - }) - - t.Run("langpackGetLanguages", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x800fd57d) - out, ok, err := UpgradeInbound(0x800fd57d, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0x42c6978f, "langpackGetLanguages") - }) - - t.Run("channelsEditCreatorToMessagesEditChatCreator", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x8f38cd1f) - _ = (&tg.InputChannel{ChannelID: 132, AccessHash: 8956724956393200600}).Encode(&in) - _ = (&tg.InputUser{UserID: 1780243211, AccessHash: 42}).Encode(&in) - _ = (&tg.InputCheckPasswordEmpty{}).Encode(&in) - out, ok, err := UpgradeInbound(0x8f38cd1f, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0xf743b857, "messagesEditChatCreator") - var req tg.MessagesEditChatCreatorRequest - if err := req.Decode(&bin.Buffer{Buf: append([]byte(nil), out.Buf...)}); err != nil { - t.Fatalf("decode upgraded editChatCreator: %v", err) - } - peer, ok := req.Peer.(*tg.InputPeerChannel) - if !ok || peer.ChannelID != 132 || peer.AccessHash != 8956724956393200600 { - t.Fatalf("upgraded peer = %T %+v, want inputPeerChannel", req.Peer, req.Peer) - } - user, ok := req.UserID.(*tg.InputUser) - if !ok || user.UserID != 1780243211 || user.AccessHash != 42 { - t.Fatalf("upgraded user = %T %+v, want inputUser", req.UserID, req.UserID) - } - if _, ok := req.Password.(*tg.InputCheckPasswordEmpty); !ok { - t.Fatalf("upgraded password = %T, want inputCheckPasswordEmpty", req.Password) - } - }) -} - -// TestInboundCRCSwaps covers the body-compatible client-drift methods that only -// need a 4-byte id swap. -func TestInboundCRCSwaps(t *testing.T) { - t.Run("updatesGetDifference", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x25939651) - in.PutUint32(0) // flags (no pts_total_limit) - in.PutInt(100) // pts - in.PutInt(200) // date - in.PutInt(0) // qts - out, ok, err := UpgradeInbound(0x25939651, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0x19c2f763, "updatesGetDifference") - }) - - t.Run("createChat", func(t *testing.T) { - var in bin.Buffer - in.PutID(0x0034a818) - if err := (&tg.MessagesCreateChatRequest{ - Users: []tg.InputUserClass{&tg.InputUser{UserID: 2, AccessHash: 3}}, - Title: "Group", - }).EncodeBare(&in); err != nil { - t.Fatalf("encode createChat body: %v", err) - } - out, ok, err := UpgradeInbound(0x0034a818, &in) - if !ok || err != nil { - t.Fatalf("upgrade: ok=%v err=%v", ok, err) - } - validateMethodRequest(t, out, 0x92ceddd4, "createChat") - }) -} diff --git a/internal/compat/layerwire/layout.go b/internal/compat/layerwire/layout.go deleted file mode 100644 index 803e2dbc..00000000 --- a/internal/compat/layerwire/layout.go +++ /dev/null @@ -1,204 +0,0 @@ -// Package layerwire downgrades canonical (Layer 227, the bytes gotd actually -// emits) TL objects to the wire shape expected by older clients (down to -// Layer 220), and is the runtime half of docs/layer-compat-220-227-design.md. -// -// The package is schema-driven: at init it parses the embedded canonical-227 -// schema into a per-constructor field layout used by a generic walker; the -// generate-time tables (tables_gen.go, produced by ./gen) describe the -// per-layer downgrade rules. Business handlers and gotd are never touched — -// they always produce Layer 227, and transcoding happens only at the edge and -// only when the negotiated client layer is below 227. -package layerwire - -import ( - _ "embed" - "fmt" - "strings" - - "github.com/gotd/tl" -) - -// CanonicalLayer is the layer telesrv's pinned gotd emits. -const CanonicalLayer = 227 - -// SupportedFloor is the oldest client layer the transcoder targets. -const SupportedFloor = 220 - -// vectorTypeID is the boxed Vector constructor id. -const vectorTypeID = 0x1cb5c415 - -//go:embed schema/canonical-227.tl -var canonicalSchema string - -// wireKind is the on-wire representation of a single TL value. -type wireKind uint8 - -const ( - kindInt wireKind = iota // 4 bytes - kindLong // 8 bytes - kindDouble // 8 bytes - kindInt128 // 16 bytes - kindInt256 // 32 bytes - kindBytes // TL bytes (length-prefixed, padded) - kindString // TL string (same wire as bytes) - kindBool // boxed Bool (4-byte CRC) - kindTrue // flag-only pseudo value, 0 bytes - kindVector // boxed Vector (0x1cb5c415 + n + elems) - kindVectorBare // bare vector (n + elems, no id) - kindObject // boxed object (4-byte CRC + body) - kindBareObject // bare object (body only, resolved by typeName) -) - -// fieldLayout is one parameter of a constructor with its decoded wire shape. -type fieldLayout struct { - name string - kind wireKind - isFlags bool // this is a `#` flags integer - flagName string // when conditional: which flags integer gates it - flagBit int // when conditional: bit index; -1 otherwise - elem *fieldLayout // vector element layout - typeName string // object/bareObject: (qualified) referenced type name -} - -func (f fieldLayout) conditional() bool { return f.flagBit >= 0 } - -// ctorLayout is the decoded field layout of a single constructor. -type ctorLayout struct { - crc uint32 - name string // qualified TL name, e.g. "messages.dialogs" / "message" - result string // qualified result (abstract) type name - fields []fieldLayout - isFunc bool -} - -// schemaModel is the parsed canonical schema indexed for the walker. -type schemaModel struct { - byCRC map[uint32]*ctorLayout - byName map[string]*ctorLayout // qualified ctor name -> layout - bareByT map[string]*ctorLayout // bare type name -> its single constructor - ctorsOfT map[string][]*ctorLayout // abstract result type -> constructors -} - -// canonical is the parsed Layer 227 model, built once at init. -var canonical = mustLoadCanonical() - -func mustLoadCanonical() *schemaModel { - m, err := parseSchemaModel(canonicalSchema) - if err != nil { - panic("layerwire: parse canonical schema: " + err.Error()) - } - return m -} - -func qualifyName(ns []string, name string) string { - if len(ns) == 0 { - return name - } - return strings.Join(ns, ".") + "." + name -} - -func qualifyType(t tl.Type) string { - return qualifyName(t.Namespace, t.Name) -} - -func parseSchemaModel(src string) (*schemaModel, error) { - parsed, err := tl.Parse(strings.NewReader(src)) - if err != nil { - return nil, err - } - m := &schemaModel{ - byCRC: make(map[uint32]*ctorLayout), - byName: make(map[string]*ctorLayout), - bareByT: make(map[string]*ctorLayout), - ctorsOfT: make(map[string][]*ctorLayout), - } - for i := range parsed.Definitions { - sd := parsed.Definitions[i] - d := sd.Definition - name := qualifyName(d.Namespace, d.Name) - if name == "vector" { - continue // implicit Vector pseudo-definition - } - cl := &ctorLayout{ - crc: d.ID, - name: name, - result: qualifyType(d.Type), - isFunc: sd.Category == tl.CategoryFunction, - } - for _, p := range d.Params { - fl, err := toFieldLayout(p) - if err != nil { - return nil, fmt.Errorf("%s field %q: %w", name, p.Name, err) - } - cl.fields = append(cl.fields, fl) - } - if prev, ok := m.byCRC[cl.crc]; ok && prev.name != cl.name { - return nil, fmt.Errorf("crc collision %#08x: %s vs %s", cl.crc, prev.name, cl.name) - } - m.byCRC[cl.crc] = cl - m.byName[cl.name] = cl - if !cl.isFunc { - m.ctorsOfT[cl.result] = append(m.ctorsOfT[cl.result], cl) - // A bare type name is the lowercase constructor name itself. - m.bareByT[cl.name] = cl - } - } - return m, nil -} - -func toFieldLayout(p tl.Parameter) (fieldLayout, error) { - if p.Flags { - return fieldLayout{name: p.Name, kind: kindInt, isFlags: true, flagBit: -1}, nil - } - fl := fieldLayout{name: p.Name, flagBit: -1} - if p.Flag != nil { - fl.flagName = p.Flag.Name - fl.flagBit = p.Flag.Index - } - kind, typeName, elem, err := resolveType(p.Type) - if err != nil { - return fieldLayout{}, err - } - fl.kind = kind - fl.typeName = typeName - fl.elem = elem - return fl, nil -} - -func resolveType(t tl.Type) (kind wireKind, typeName string, elem *fieldLayout, err error) { - if t.GenericArg != nil { - ek, etn, eel, eerr := resolveType(*t.GenericArg) - if eerr != nil { - return 0, "", nil, eerr - } - el := &fieldLayout{kind: ek, typeName: etn, elem: eel, flagBit: -1} - if t.Name == "vector" { // bare vector - return kindVectorBare, "", el, nil - } - return kindVector, "", el, nil - } - switch t.Name { - case "int": - return kindInt, "", nil, nil - case "long": - return kindLong, "", nil, nil - case "double": - return kindDouble, "", nil, nil - case "int128": - return kindInt128, "", nil, nil - case "int256": - return kindInt256, "", nil, nil - case "bytes": - return kindBytes, "", nil, nil - case "string": - return kindString, "", nil, nil - case "Bool": - return kindBool, "", nil, nil - case "true": - return kindTrue, "", nil, nil - } - if t.Bare { - return kindBareObject, qualifyType(t), nil, nil - } - return kindObject, qualifyType(t), nil, nil -} diff --git a/internal/compat/layerwire/routable.go b/internal/compat/layerwire/routable.go deleted file mode 100644 index 3f17984e..00000000 --- a/internal/compat/layerwire/routable.go +++ /dev/null @@ -1,80 +0,0 @@ -package layerwire - -import ( - _ "embed" - "fmt" - - "github.com/gotd/td/bin" -) - -const maxOpaqueRequestBytes = 16 << 20 - -//go:embed schema/routable-compat.tl -var routableCompatSchema string - -// routable combines the canonical Layer 227 model with the small set of -// explicitly declared compatibility-only methods. Nested objects in those -// methods are canonical Input* constructors, so one combined graph is needed -// for the same depth/vector/bytes walker to validate the complete request. -var routable = mustLoadRoutable() - -func mustLoadRoutable() *schemaModel { - compat, err := parseSchemaModel(routableCompatSchema) - if err != nil { - panic("layerwire: parse routable compat schema: " + err.Error()) - } - m := &schemaModel{ - byCRC: make(map[uint32]*ctorLayout, len(canonical.byCRC)+len(compat.byCRC)), - byName: make(map[string]*ctorLayout, len(canonical.byName)+len(compat.byName)), - bareByT: make(map[string]*ctorLayout, len(canonical.bareByT)), - ctorsOfT: make(map[string][]*ctorLayout, len(canonical.ctorsOfT)), - } - for id, cl := range canonical.byCRC { - m.byCRC[id] = cl - } - for name, cl := range canonical.byName { - m.byName[name] = cl - } - for name, cl := range canonical.bareByT { - m.bareByT[name] = cl - } - for name, ctors := range canonical.ctorsOfT { - m.ctorsOfT[name] = ctors - } - for id, cl := range compat.byCRC { - if existing := m.byCRC[id]; existing != nil { - panic(fmt.Sprintf("layerwire: routable compat crc %#08x collides with %s", id, existing.name)) - } - m.byCRC[id] = cl - m.byName[cl.name] = cl - } - return m -} - -// ValidateRoutableRequest validates every request shape the router knows how to -// decode, including compatibility-only fallback methods. known=false denotes -// a genuinely unknown top-level constructor. Such a request is never decoded: -// it is treated as opaque, word-aligned TL data, bounded by both this total-size -// cap and mtprotoedge's transport/RPC budgets, and must continue to the router's -// compatibility trace rather than being mislabeled as malformed input. -func ValidateRoutableRequest(body []byte) (known bool, err error) { - b := &bin.Buffer{Buf: body} - id, err := b.PeekID() - if err != nil { - return false, classifyWalkError(err) - } - cl := routable.byCRC[id] - if cl == nil { - if len(body) > maxOpaqueRequestBytes { - return false, limitf("opaque request length %d exceeds limit %d", len(body), maxOpaqueRequestBytes) - } - if len(body)%bin.Word != 0 { - return false, malformedf("opaque request length %d is not word aligned", len(body)) - } - return false, nil - } - if !cl.isFunc { - return true, malformedf("constructor %s (%#08x) is not a method", cl.name, id) - } - return true, validateRequestLayout(routable, cl, body) -} diff --git a/internal/compat/layerwire/routable_test.go b/internal/compat/layerwire/routable_test.go deleted file mode 100644 index 5c4e8010..00000000 --- a/internal/compat/layerwire/routable_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package layerwire - -import ( - "errors" - "testing" - - "github.com/gotd/td/bin" - "github.com/gotd/td/tg" -) - -func TestValidateRoutableRequestCompatibilityAndUnknown(t *testing.T) { - t.Run("legacy theme is fully walked", func(t *testing.T) { - var b bin.Buffer - b.PutID(0x8d9d742b) - b.PutString("android") - (&tg.InputThemeSlug{Slug: "night"}).Encode(&b) - b.PutLong(42) - known, err := ValidateRoutableRequest(b.Buf) - if err != nil || !known { - t.Fatalf("legacy theme known=%v err=%v, want true/nil", known, err) - } - - b.Buf = b.Buf[:len(b.Buf)-4] - known, err = ValidateRoutableRequest(b.Buf) - if !known || !errors.Is(err, ErrMalformed) { - t.Fatalf("truncated legacy theme known=%v err=%v, want true/malformed", known, err) - } - }) - - t.Run("unknown stays opaque and bounded", func(t *testing.T) { - var b bin.Buffer - b.PutID(0x12345678) - b.PutUint32(0xffffffff) - known, err := ValidateRoutableRequest(b.Buf) - if err != nil || known { - t.Fatalf("opaque unknown known=%v err=%v, want false/nil", known, err) - } - known, err = ValidateRoutableRequest(append(b.Buf, 1)) - if known || !errors.Is(err, ErrMalformed) { - t.Fatalf("unaligned unknown known=%v err=%v, want false/malformed", known, err) - } - }) -} diff --git a/internal/compat/layerwire/schema/canonical-227.tl b/internal/compat/layerwire/schema/canonical-227.tl deleted file mode 100644 index a79d0991..00000000 --- a/internal/compat/layerwire/schema/canonical-227.tl +++ /dev/null @@ -1,4828 +0,0 @@ -// Code generated by ./cmd/dltl, DO NOT EDIT. -// -// Source: https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/Telegram/SourceFiles/mtproto/scheme/api.tl -// Layer: 227 -// SHA256: f8fe06d2279657cc36f7d5280a28fa00a176ca6c99b5208038850b40e9aa5518 - -boolFalse#bc799737 = Bool; - -boolTrue#997275b5 = Bool; - -true#3fedd339 = True; - -error#c4b9f9bb code:int text:string = Error; - -null#56730bcc = Null; - -inputPeerEmpty#7f3b18ea = InputPeer; - -inputPeerSelf#7da07ec9 = InputPeer; - -inputPeerChat#35a95cb9 chat_id:long = InputPeer; - -inputPeerUser#dde8a54c user_id:long access_hash:long = InputPeer; - -inputPeerChannel#27bcbbfc channel_id:long access_hash:long = InputPeer; - -inputPeerUserFromMessage#a87b0a1c peer:InputPeer msg_id:int user_id:long = InputPeer; - -inputPeerChannelFromMessage#bd2a0840 peer:InputPeer msg_id:int channel_id:long = InputPeer; - -inputUserEmpty#b98886cf = InputUser; - -inputUserSelf#f7c1b13f = InputUser; - -inputUser#f21158c6 user_id:long access_hash:long = InputUser; - -inputUserFromMessage#1da448e2 peer:InputPeer msg_id:int user_id:long = InputUser; - -inputPhoneContact#6a1dc4be flags:# client_id:long phone:string first_name:string last_name:string note:flags.0?TextWithEntities = InputContact; - -inputFile#f52ff27f id:long parts:int name:string md5_checksum:string = InputFile; - -inputFileBig#fa4f0bb5 id:long parts:int name:string = InputFile; - -inputFileStoryDocument#62dc8b48 id:InputDocument = InputFile; - -inputMediaEmpty#9664f57f = InputMedia; - -inputMediaUploadedPhoto#7d8375da flags:# spoiler:flags.2?true live_photo:flags.3?true file:InputFile stickers:flags.0?Vector ttl_seconds:flags.1?int video:flags.3?InputDocument = InputMedia; - -inputMediaPhoto#e3af4434 flags:# spoiler:flags.1?true live_photo:flags.2?true id:InputPhoto ttl_seconds:flags.0?int video:flags.2?InputDocument = InputMedia; - -inputMediaGeoPoint#f9c44144 geo_point:InputGeoPoint = InputMedia; - -inputMediaContact#f8ab7dfb phone_number:string first_name:string last_name:string vcard:string = InputMedia; - -inputMediaUploadedDocument#37c9330 flags:# nosound_video:flags.3?true force_file:flags.4?true spoiler:flags.5?true file:InputFile thumb:flags.2?InputFile mime_type:string attributes:Vector stickers:flags.0?Vector video_cover:flags.6?InputPhoto video_timestamp:flags.7?int ttl_seconds:flags.1?int = InputMedia; - -inputMediaDocument#a8763ab5 flags:# spoiler:flags.2?true id:InputDocument video_cover:flags.3?InputPhoto video_timestamp:flags.4?int ttl_seconds:flags.0?int query:flags.1?string = InputMedia; - -inputMediaVenue#c13d1c11 geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string = InputMedia; - -inputMediaPhotoExternal#e5bbfe1a flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int = InputMedia; - -inputMediaDocumentExternal#779600f9 flags:# spoiler:flags.1?true url:string ttl_seconds:flags.0?int video_cover:flags.2?InputPhoto video_timestamp:flags.3?int = InputMedia; - -inputMediaGame#d33f43f3 id:InputGame = InputMedia; - -inputMediaInvoice#405fef0d flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:flags.3?string provider_data:DataJSON start_param:flags.1?string extended_media:flags.2?InputMedia = InputMedia; - -inputMediaGeoLive#971fa843 flags:# stopped:flags.0?true geo_point:InputGeoPoint heading:flags.2?int period:flags.1?int proximity_notification_radius:flags.3?int = InputMedia; - -inputMediaPoll#883a4108 flags:# poll:Poll correct_answers:flags.0?Vector attached_media:flags.3?InputMedia solution:flags.1?string solution_entities:flags.1?Vector solution_media:flags.2?InputMedia = InputMedia; - -inputMediaDice#e66fbf7b emoticon:string = InputMedia; - -inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; - -inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; - -inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; - -inputMediaTodo#9fc55fde todo:TodoList = InputMedia; - -inputMediaStakeDice#f3a9244a game_hash:string ton_amount:long client_seed:bytes = InputMedia; - -inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; - -inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; - -inputChatPhoto#8953ad37 id:InputPhoto = InputChatPhoto; - -inputGeoPointEmpty#e4c123d6 = InputGeoPoint; - -inputGeoPoint#48222faf flags:# lat:double long:double accuracy_radius:flags.0?int = InputGeoPoint; - -inputPhotoEmpty#1cd7bf0d = InputPhoto; - -inputPhoto#3bb3b94a id:long access_hash:long file_reference:bytes = InputPhoto; - -inputFileLocation#dfdaabe1 volume_id:long local_id:int secret:long file_reference:bytes = InputFileLocation; - -inputEncryptedFileLocation#f5235d55 id:long access_hash:long = InputFileLocation; - -inputDocumentFileLocation#bad07584 id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; - -inputSecureFileLocation#cbc7ee28 id:long access_hash:long = InputFileLocation; - -inputTakeoutFileLocation#29be5899 = InputFileLocation; - -inputPhotoFileLocation#40181ffe id:long access_hash:long file_reference:bytes thumb_size:string = InputFileLocation; - -inputPhotoLegacyFileLocation#d83466f3 id:long access_hash:long file_reference:bytes volume_id:long local_id:int secret:long = InputFileLocation; - -inputPeerPhotoFileLocation#37257e99 flags:# big:flags.0?true peer:InputPeer photo_id:long = InputFileLocation; - -inputStickerSetThumb#9d84f3db stickerset:InputStickerSet thumb_version:int = InputFileLocation; - -inputGroupCallStream#598a92a flags:# call:InputGroupCall time_ms:long scale:int video_channel:flags.0?int video_quality:flags.0?int = InputFileLocation; - -peerUser#59511722 user_id:long = Peer; - -peerChat#36c6019a chat_id:long = Peer; - -peerChannel#a2a5371e channel_id:long = Peer; - -storage.fileUnknown#aa963b05 = storage.FileType; - -storage.filePartial#40bc6f52 = storage.FileType; - -storage.fileJpeg#7efe0e = storage.FileType; - -storage.fileGif#cae1aadf = storage.FileType; - -storage.filePng#a4f63c0 = storage.FileType; - -storage.filePdf#ae1e508d = storage.FileType; - -storage.fileMp3#528a0677 = storage.FileType; - -storage.fileMov#4b09ebbc = storage.FileType; - -storage.fileMp4#b3cea0e4 = storage.FileType; - -storage.fileWebp#1081464c = storage.FileType; - -userEmpty#d3bc4b7a id:long = User; - -user#31774388 flags:# self:flags.10?true contact:flags.11?true mutual_contact:flags.12?true deleted:flags.13?true bot:flags.14?true bot_chat_history:flags.15?true bot_nochats:flags.16?true verified:flags.17?true restricted:flags.18?true min:flags.20?true bot_inline_geo:flags.21?true support:flags.23?true scam:flags.24?true apply_min_photo:flags.25?true fake:flags.26?true bot_attach_menu:flags.27?true premium:flags.28?true attach_menu_enabled:flags.29?true flags2:# bot_can_edit:flags2.1?true close_friend:flags2.2?true stories_hidden:flags2.3?true stories_unavailable:flags2.4?true contact_require_premium:flags2.10?true bot_business:flags2.11?true bot_has_main_app:flags2.13?true bot_forum_view:flags2.16?true bot_forum_can_manage_topics:flags2.17?true bot_can_manage_bots:flags2.18?true bot_guestchat:flags2.19?true bot_guard:flags2.20?true id:long access_hash:flags.0?long first_name:flags.1?string last_name:flags.2?string username:flags.3?string phone:flags.4?string photo:flags.5?UserProfilePhoto status:flags.6?UserStatus bot_info_version:flags.14?int restriction_reason:flags.18?Vector bot_inline_placeholder:flags.19?string lang_code:flags.22?string emoji_status:flags.30?EmojiStatus usernames:flags2.0?Vector stories_max_id:flags2.5?RecentStory color:flags2.8?PeerColor profile_color:flags2.9?PeerColor bot_active_users:flags2.12?int bot_verification_icon:flags2.14?long send_paid_messages_stars:flags2.15?long = User; - -userProfilePhotoEmpty#4f11bae1 = UserProfilePhoto; - -userProfilePhoto#82d1f706 flags:# has_video:flags.0?true personal:flags.2?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = UserProfilePhoto; - -userStatusEmpty#9d05049 = UserStatus; - -userStatusOnline#edb93949 expires:int = UserStatus; - -userStatusOffline#8c703f was_online:int = UserStatus; - -userStatusRecently#7b197dc8 flags:# by_me:flags.0?true = UserStatus; - -userStatusLastWeek#541a1d1a flags:# by_me:flags.0?true = UserStatus; - -userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; - -chatEmpty#29562865 id:long = Chat; - -chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; - -chatForbidden#6592a1a7 id:long title:string = Chat; - -channel#1c32b11c flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?RecentStory color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat; - -channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true monoforum:flags.10?true id:long access_hash:long title:string until_date:flags.16?int = Chat; - -chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; - -channelFull#a04e8d3a flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long main_tab:flags2.22?ProfileTab guard_bot_id:flags2.23?long = ChatFull; - -chatParticipant#38e79fde flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; - -chatParticipantCreator#e1f867b8 flags:# user_id:long rank:flags.0?string = ChatParticipant; - -chatParticipantAdmin#360d5d2 flags:# user_id:long inviter_id:long date:int rank:flags.0?string = ChatParticipant; - -chatParticipantsForbidden#8763d3e1 flags:# chat_id:long self_participant:flags.0?ChatParticipant = ChatParticipants; - -chatParticipants#3cbc93f8 chat_id:long participants:Vector version:int = ChatParticipants; - -chatPhotoEmpty#37c1011c = ChatPhoto; - -chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; - -messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; - -message#7600b9d3 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int from_rank:flags2.12?string peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long guestchat_via_from:flags2.19?Peer reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost schedule_repeat_period:flags2.10?int summary_from_language:flags2.11?string rich_message:flags2.13?RichMessage = Message; - -messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; - -messageMediaEmpty#3ded6320 = MessageMedia; - -messageMediaPhoto#e216eb63 flags:# spoiler:flags.3?true live_photo:flags.4?true photo:flags.0?Photo ttl_seconds:flags.2?int video:flags.4?Document = MessageMedia; - -messageMediaGeo#56e0d474 geo:GeoPoint = MessageMedia; - -messageMediaContact#70322949 phone_number:string first_name:string last_name:string vcard:string user_id:long = MessageMedia; - -messageMediaUnsupported#9f84f49e = MessageMedia; - -messageMediaDocument#52d8ccd9 flags:# nopremium:flags.3?true spoiler:flags.4?true video:flags.6?true round:flags.7?true voice:flags.8?true document:flags.0?Document alt_documents:flags.5?Vector video_cover:flags.9?Photo video_timestamp:flags.10?int ttl_seconds:flags.2?int = MessageMedia; - -messageMediaWebPage#ddf10c3b flags:# force_large_media:flags.0?true force_small_media:flags.1?true manual:flags.3?true safe:flags.4?true webpage:WebPage = MessageMedia; - -messageMediaVenue#2ec0533f geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MessageMedia; - -messageMediaGame#fdb19008 game:Game = MessageMedia; - -messageMediaInvoice#f6a548d3 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument receipt_msg_id:flags.2?int currency:string total_amount:long start_param:string extended_media:flags.4?MessageExtendedMedia = MessageMedia; - -messageMediaGeoLive#b940c666 flags:# geo:GeoPoint heading:flags.0?int period:int proximity_notification_radius:flags.1?int = MessageMedia; - -messageMediaPoll#773f4e66 flags:# poll:Poll results:PollResults attached_media:flags.0?MessageMedia = MessageMedia; - -messageMediaDice#8cbec07 flags:# value:int emoticon:string game_outcome:flags.0?messages.EmojiGameOutcome = MessageMedia; - -messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int story:flags.0?StoryItem = MessageMedia; - -messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; - -messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; - -messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; - -messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector = MessageMedia; - -messageMediaVideoStream#ca5cab89 flags:# rtmp_stream:flags.0?true call:InputGroupCall = MessageMedia; - -messageActionEmpty#b6aef7b0 = MessageAction; - -messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; - -messageActionChatEditTitle#b5a1ce5a title:string = MessageAction; - -messageActionChatEditPhoto#7fcb13a8 photo:Photo = MessageAction; - -messageActionChatDeletePhoto#95e3fbef = MessageAction; - -messageActionChatAddUser#15cefd00 users:Vector = MessageAction; - -messageActionChatDeleteUser#a43f30cc user_id:long = MessageAction; - -messageActionChatJoinedByLink#31224c3 inviter_id:long = MessageAction; - -messageActionChannelCreate#95d2ac92 title:string = MessageAction; - -messageActionChatMigrateTo#e1037f92 channel_id:long = MessageAction; - -messageActionChannelMigrateFrom#ea3948e9 title:string chat_id:long = MessageAction; - -messageActionPinMessage#94bd38ed = MessageAction; - -messageActionHistoryClear#9fbab604 = MessageAction; - -messageActionGameScore#92a72876 game_id:long score:int = MessageAction; - -messageActionPaymentSentMe#ffa00ccc flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string charge:PaymentCharge subscription_until_date:flags.4?int = MessageAction; - -messageActionPaymentSent#c624b16e flags:# recurring_init:flags.2?true recurring_used:flags.3?true currency:string total_amount:long invoice_slug:flags.0?string subscription_until_date:flags.4?int = MessageAction; - -messageActionPhoneCall#80e11a7f flags:# video:flags.2?true call_id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = MessageAction; - -messageActionScreenshotTaken#4792929b = MessageAction; - -messageActionCustomAction#fae69f56 message:string = MessageAction; - -messageActionBotAllowed#c516d679 flags:# attach_menu:flags.1?true from_request:flags.3?true domain:flags.0?string app:flags.2?BotApp = MessageAction; - -messageActionSecureValuesSentMe#1b287353 values:Vector credentials:SecureCredentialsEncrypted = MessageAction; - -messageActionSecureValuesSent#d95c6154 types:Vector = MessageAction; - -messageActionContactSignUp#f3f25f76 = MessageAction; - -messageActionGeoProximityReached#98e0d697 from_id:Peer to_id:Peer distance:int = MessageAction; - -messageActionGroupCall#7a0d7f42 flags:# call:InputGroupCall duration:flags.0?int = MessageAction; - -messageActionInviteToGroupCall#502f92f7 call:InputGroupCall users:Vector = MessageAction; - -messageActionSetMessagesTTL#3c134d7b flags:# period:int auto_setting_from:flags.0?long = MessageAction; - -messageActionGroupCallScheduled#b3a07661 call:InputGroupCall schedule_date:int = MessageAction; - -messageActionSetChatTheme#b91bbd3a theme:ChatTheme = MessageAction; - -messageActionChatJoinedByRequest#ebbca3cb = MessageAction; - -messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction; - -messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction; - -messageActionGiftPremium#48e91302 flags:# currency:string amount:long days:int crypto_currency:flags.0?string crypto_amount:flags.0?long message:flags.1?TextWithEntities = MessageAction; - -messageActionTopicCreate#d999256 flags:# title_missing:flags.1?true title:string icon_color:int icon_emoji_id:flags.0?long = MessageAction; - -messageActionTopicEdit#c0944820 flags:# title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = MessageAction; - -messageActionSuggestProfilePhoto#57de635e photo:Photo = MessageAction; - -messageActionRequestedPeer#31518e9b button_id:int peers:Vector = MessageAction; - -messageActionSetChatWallPaper#5060a3f4 flags:# same:flags.0?true for_both:flags.1?true wallpaper:WallPaper = MessageAction; - -messageActionGiftCode#31c48347 flags:# via_giveaway:flags.0?true unclaimed:flags.5?true boost_peer:flags.1?Peer days:int slug:string currency:flags.2?string amount:flags.2?long crypto_currency:flags.3?string crypto_amount:flags.3?long message:flags.4?TextWithEntities = MessageAction; - -messageActionGiveawayLaunch#a80f51e4 flags:# stars:flags.0?long = MessageAction; - -messageActionGiveawayResults#87e2f155 flags:# stars:flags.0?true winners_count:int unclaimed_count:int = MessageAction; - -messageActionBoostApply#cc02aa6d boosts:int = MessageAction; - -messageActionRequestedPeerSentMe#93b31848 button_id:int peers:Vector = MessageAction; - -messageActionPaymentRefunded#41b3e202 flags:# peer:Peer currency:string total_amount:long payload:flags.0?bytes charge:PaymentCharge = MessageAction; - -messageActionGiftStars#45d5b021 flags:# currency:string amount:long stars:long crypto_currency:flags.0?string crypto_amount:flags.0?long transaction_id:flags.1?string = MessageAction; - -messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long transaction_id:string boost_peer:Peer giveaway_msg_id:int = MessageAction; - -messageActionStarGift#ea2c31d3 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true prepaid_upgrade:flags.13?true upgrade_separate:flags.16?true auction_acquired:flags.17?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long prepaid_upgrade_hash:flags.14?string gift_msg_id:flags.15?int to_id:flags.18?Peer gift_num:flags.19?int = MessageAction; - -messageActionStarGiftUnique#e6c31522 flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true prepaid_upgrade:flags.11?true assigned:flags.13?true from_offer:flags.14?true craft:flags.16?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_amount:flags.8?StarsAmount can_transfer_at:flags.9?int can_resell_at:flags.10?int drop_original_details_stars:flags.12?long can_craft_at:flags.15?int = MessageAction; - -messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; - -messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; - -messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; - -messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; - -messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; - -messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction; - -messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction; - -messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction; - -messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction; - -messageActionSuggestBirthday#2c8f2a25 birthday:Birthday = MessageAction; - -messageActionStarGiftPurchaseOffer#774278d4 flags:# accepted:flags.0?true declined:flags.1?true gift:StarGift price:StarsAmount expires_at:int = MessageAction; - -messageActionStarGiftPurchaseOfferDeclined#73ada76b flags:# expired:flags.0?true gift:StarGift price:StarsAmount = MessageAction; - -messageActionNewCreatorPending#b07ed085 new_creator_id:long = MessageAction; - -messageActionChangeCreator#e188503b new_creator_id:long = MessageAction; - -messageActionNoForwardsToggle#bf7d6572 prev_value:Bool new_value:Bool = MessageAction; - -messageActionNoForwardsRequest#3e2793ba flags:# expired:flags.0?true prev_value:Bool new_value:Bool = MessageAction; - -messageActionPollAppendAnswer#9da1cd6c answer:PollAnswer = MessageAction; - -messageActionPollDeleteAnswer#399674dc answer:PollAnswer = MessageAction; - -messageActionManagedBotCreated#16605e3e bot_id:long = MessageAction; - -dialog#fc89f7f3 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; - -dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; - -photoEmpty#2331b22d id:long = Photo; - -photo#fb197a65 flags:# has_stickers:flags.0?true id:long access_hash:long file_reference:bytes date:int sizes:Vector video_sizes:flags.1?Vector dc_id:int = Photo; - -photoSizeEmpty#e17e23c type:string = PhotoSize; - -photoSize#75c78e60 type:string w:int h:int size:int = PhotoSize; - -photoCachedSize#21e1ad6 type:string w:int h:int bytes:bytes = PhotoSize; - -photoStrippedSize#e0b0bc2e type:string bytes:bytes = PhotoSize; - -photoSizeProgressive#fa3efb95 type:string w:int h:int sizes:Vector = PhotoSize; - -photoPathSize#d8214d41 type:string bytes:bytes = PhotoSize; - -geoPointEmpty#1117dd5f = GeoPoint; - -geoPoint#b2a2f663 flags:# long:double lat:double access_hash:long accuracy_radius:flags.0?int = GeoPoint; - -auth.sentCode#5e002502 flags:# type:auth.SentCodeType phone_code_hash:string next_type:flags.1?auth.CodeType timeout:flags.2?int = auth.SentCode; - -auth.sentCodeSuccess#2390fe44 authorization:auth.Authorization = auth.SentCode; - -auth.sentCodePaymentRequired#f8827ebf store_product:string phone_code_hash:string support_email_address:string support_email_subject:string premium_days:int currency:string amount:long = auth.SentCode; - -auth.authorization#2ea2c0d4 flags:# setup_password_required:flags.1?true otherwise_relogin_days:flags.1?int tmp_sessions:flags.0?int future_auth_token:flags.2?bytes user:User = auth.Authorization; - -auth.authorizationSignUpRequired#44747e9a flags:# terms_of_service:flags.0?help.TermsOfService = auth.Authorization; - -auth.exportedAuthorization#b434e2b8 id:long bytes:bytes = auth.ExportedAuthorization; - -inputNotifyPeer#b8bc5b0c peer:InputPeer = InputNotifyPeer; - -inputNotifyUsers#193b4417 = InputNotifyPeer; - -inputNotifyChats#4a95e84e = InputNotifyPeer; - -inputNotifyBroadcasts#b1db7c7e = InputNotifyPeer; - -inputNotifyForumTopic#5c467992 peer:InputPeer top_msg_id:int = InputNotifyPeer; - -inputPeerNotifySettings#cacb6ae2 flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int sound:flags.3?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_sound:flags.8?NotificationSound = InputPeerNotifySettings; - -peerNotifySettings#99622c0c flags:# show_previews:flags.0?Bool silent:flags.1?Bool mute_until:flags.2?int ios_sound:flags.3?NotificationSound android_sound:flags.4?NotificationSound other_sound:flags.5?NotificationSound stories_muted:flags.6?Bool stories_hide_sender:flags.7?Bool stories_ios_sound:flags.8?NotificationSound stories_android_sound:flags.9?NotificationSound stories_other_sound:flags.10?NotificationSound = PeerNotifySettings; - -peerSettings#f47741f7 flags:# report_spam:flags.0?true add_contact:flags.1?true block_contact:flags.2?true share_contact:flags.3?true need_contacts_exception:flags.4?true report_geo:flags.5?true autoarchived:flags.7?true invite_members:flags.8?true request_chat_broadcast:flags.10?true business_bot_paused:flags.11?true business_bot_can_reply:flags.12?true geo_distance:flags.6?int request_chat_title:flags.9?string request_chat_date:flags.9?int business_bot_id:flags.13?long business_bot_manage_url:flags.13?string charge_paid_message_stars:flags.14?long registration_month:flags.15?string phone_country:flags.16?string name_change_date:flags.17?int photo_change_date:flags.18?int = PeerSettings; - -wallPaper#a437c3ed id:long flags:# creator:flags.0?true default:flags.1?true pattern:flags.3?true dark:flags.4?true access_hash:long slug:string document:Document settings:flags.2?WallPaperSettings = WallPaper; - -wallPaperNoFile#e0804116 id:long flags:# default:flags.1?true dark:flags.4?true settings:flags.2?WallPaperSettings = WallPaper; - -inputReportReasonSpam#58dbcab8 = ReportReason; - -inputReportReasonViolence#1e22c78d = ReportReason; - -inputReportReasonPornography#2e59d922 = ReportReason; - -inputReportReasonChildAbuse#adf44ee3 = ReportReason; - -inputReportReasonOther#c1e4a2b1 = ReportReason; - -inputReportReasonCopyright#9b89f93a = ReportReason; - -inputReportReasonGeoIrrelevant#dbd4feed = ReportReason; - -inputReportReasonFake#f5ddd6e7 = ReportReason; - -inputReportReasonIllegalDrugs#a8eb2be = ReportReason; - -inputReportReasonPersonalDetails#9ec7863d = ReportReason; - -userFull#6cbe645 flags:# blocked:flags.0?true phone_calls_available:flags.4?true phone_calls_private:flags.5?true can_pin_message:flags.7?true has_scheduled:flags.12?true video_calls_available:flags.13?true voice_messages_forbidden:flags.20?true translations_disabled:flags.23?true stories_pinned_available:flags.26?true blocked_my_stories_from:flags.27?true wallpaper_overridden:flags.28?true contact_require_premium:flags.29?true read_dates_private:flags.30?true flags2:# sponsored_enabled:flags2.7?true can_view_revenue:flags2.9?true bot_can_manage_emoji_status:flags2.10?true display_gifts_button:flags2.16?true noforwards_my_enabled:flags2.23?true noforwards_peer_enabled:flags2.24?true unofficial_security_risk:flags2.26?true id:long about:flags.1?string settings:PeerSettings personal_photo:flags.21?Photo profile_photo:flags.2?Photo fallback_photo:flags.22?Photo notify_settings:PeerNotifySettings bot_info:flags.3?BotInfo pinned_msg_id:flags.6?int common_chats_count:int folder_id:flags.11?int ttl_period:flags.14?int theme:flags.15?ChatTheme private_forward_name:flags.16?string bot_group_admin_rights:flags.17?ChatAdminRights bot_broadcast_admin_rights:flags.18?ChatAdminRights wallpaper:flags.24?WallPaper stories:flags.25?PeerStories business_work_hours:flags2.0?BusinessWorkHours business_location:flags2.1?BusinessLocation business_greeting_message:flags2.2?BusinessGreetingMessage business_away_message:flags2.3?BusinessAwayMessage business_intro:flags2.4?BusinessIntro birthday:flags2.5?Birthday personal_channel_id:flags2.6?long personal_channel_message:flags2.6?int stargifts_count:flags2.8?int starref_program:flags2.11?StarRefProgram bot_verification:flags2.12?BotVerification send_paid_messages_stars:flags2.14?long disallowed_gifts:flags2.15?DisallowedGiftsSettings stars_rating:flags2.17?StarsRating stars_my_pending_rating:flags2.18?StarsRating stars_my_pending_rating_date:flags2.18?int main_tab:flags2.20?ProfileTab saved_music:flags2.21?Document note:flags2.22?TextWithEntities bot_manager_id:flags2.25?long = UserFull; - -contact#145ade0b user_id:long mutual:Bool = Contact; - -importedContact#c13e3c50 user_id:long client_id:long = ImportedContact; - -contactStatus#16d9703b user_id:long status:UserStatus = ContactStatus; - -contacts.contactsNotModified#b74ba9d2 = contacts.Contacts; - -contacts.contacts#eae87e42 contacts:Vector saved_count:int users:Vector = contacts.Contacts; - -contacts.importedContacts#77d01c3b imported:Vector popular_invites:Vector retry_contacts:Vector users:Vector = contacts.ImportedContacts; - -contacts.blocked#ade1591 blocked:Vector chats:Vector users:Vector = contacts.Blocked; - -contacts.blockedSlice#e1664194 count:int blocked:Vector chats:Vector users:Vector = contacts.Blocked; - -messages.dialogs#15ba6c40 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; - -messages.dialogsSlice#71e094f3 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.Dialogs; - -messages.dialogsNotModified#f0e3e596 count:int = messages.Dialogs; - -messages.messages#1d73e7ea messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; - -messages.messagesSlice#5f206716 flags:# inexact:flags.1?true count:int next_rate:flags.0?int offset_id_offset:flags.2?int search_flood:flags.3?SearchPostsFlood messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; - -messages.channelMessages#c776ba4e flags:# inexact:flags.1?true pts:int count:int offset_id_offset:flags.2?int messages:Vector topics:Vector chats:Vector users:Vector = messages.Messages; - -messages.messagesNotModified#74535f21 count:int = messages.Messages; - -messages.chats#64ff9fd5 chats:Vector = messages.Chats; - -messages.chatsSlice#9cd81144 count:int chats:Vector = messages.Chats; - -messages.chatFull#e5d7d19c full_chat:ChatFull chats:Vector users:Vector = messages.ChatFull; - -messages.affectedHistory#b45c69d1 pts:int pts_count:int offset:int = messages.AffectedHistory; - -inputMessagesFilterEmpty#57e2f66c = MessagesFilter; - -inputMessagesFilterPhotos#9609a51c = MessagesFilter; - -inputMessagesFilterVideo#9fc00e65 = MessagesFilter; - -inputMessagesFilterPhotoVideo#56e9f0e4 = MessagesFilter; - -inputMessagesFilterDocument#9eddf188 = MessagesFilter; - -inputMessagesFilterUrl#7ef0dd87 = MessagesFilter; - -inputMessagesFilterGif#ffc86587 = MessagesFilter; - -inputMessagesFilterVoice#50f5c392 = MessagesFilter; - -inputMessagesFilterMusic#3751b49e = MessagesFilter; - -inputMessagesFilterChatPhotos#3a20ecb8 = MessagesFilter; - -inputMessagesFilterPhoneCalls#80c99768 flags:# missed:flags.0?true = MessagesFilter; - -inputMessagesFilterRoundVoice#7a7c17a4 = MessagesFilter; - -inputMessagesFilterRoundVideo#b549da53 = MessagesFilter; - -inputMessagesFilterMyMentions#c1f8e69a = MessagesFilter; - -inputMessagesFilterGeo#e7026d0d = MessagesFilter; - -inputMessagesFilterContacts#e062db83 = MessagesFilter; - -inputMessagesFilterPinned#1bb00451 = MessagesFilter; - -inputMessagesFilterPoll#fa2bc90a = MessagesFilter; - -updateNewMessage#1f2b0afd message:Message pts:int pts_count:int = Update; - -updateMessageID#4e90bfd6 id:int random_id:long = Update; - -updateDeleteMessages#a20db0e5 messages:Vector pts:int pts_count:int = Update; - -updateUserTyping#2a17bf5c flags:# user_id:long top_msg_id:flags.0?int action:SendMessageAction = Update; - -updateChatUserTyping#83487af0 chat_id:long from_id:Peer action:SendMessageAction = Update; - -updateChatParticipants#7761198 participants:ChatParticipants = Update; - -updateUserStatus#e5bdf8de user_id:long status:UserStatus = Update; - -updateUserName#a7848924 user_id:long first_name:string last_name:string usernames:Vector = Update; - -updateNewAuthorization#8951abef flags:# unconfirmed:flags.0?true hash:long date:flags.0?int device:flags.0?string location:flags.0?string = Update; - -updateNewEncryptedMessage#12bcbd9a message:EncryptedMessage qts:int = Update; - -updateEncryptedChatTyping#1710f156 chat_id:int = Update; - -updateEncryption#b4a2e88d chat:EncryptedChat date:int = Update; - -updateEncryptedMessagesRead#38fe25b7 chat_id:int max_date:int date:int = Update; - -updateChatParticipantAdd#3dda5451 chat_id:long user_id:long inviter_id:long date:int version:int = Update; - -updateChatParticipantDelete#e32f3d77 chat_id:long user_id:long version:int = Update; - -updateDcOptions#8e5e9873 dc_options:Vector = Update; - -updateNotifySettings#bec268ef peer:NotifyPeer notify_settings:PeerNotifySettings = Update; - -updateServiceNotification#ebe46819 flags:# popup:flags.0?true invert_media:flags.2?true inbox_date:flags.1?int type:string message:string media:MessageMedia entities:Vector = Update; - -updatePrivacy#ee3b272a key:PrivacyKey rules:Vector = Update; - -updateUserPhone#5492a13 user_id:long phone:string = Update; - -updateReadHistoryInbox#9e84bc99 flags:# folder_id:flags.0?int peer:Peer top_msg_id:flags.1?int max_id:int still_unread_count:int pts:int pts_count:int = Update; - -updateReadHistoryOutbox#2f2f21bf peer:Peer max_id:int pts:int pts_count:int = Update; - -updateWebPage#7f891213 webpage:WebPage pts:int pts_count:int = Update; - -updateReadMessagesContents#f8227181 flags:# messages:Vector pts:int pts_count:int date:flags.0?int = Update; - -updateChannelTooLong#108d941f flags:# channel_id:long pts:flags.0?int = Update; - -updateChannel#635b4c09 channel_id:long = Update; - -updateNewChannelMessage#62ba04d9 message:Message pts:int pts_count:int = Update; - -updateReadChannelInbox#922e6e10 flags:# folder_id:flags.0?int channel_id:long max_id:int still_unread_count:int pts:int = Update; - -updateDeleteChannelMessages#c32d5b12 channel_id:long messages:Vector pts:int pts_count:int = Update; - -updateChannelMessageViews#f226ac08 channel_id:long id:int views:int = Update; - -updateChatParticipantAdmin#d7ca61a2 chat_id:long user_id:long is_admin:Bool version:int = Update; - -updateNewStickerSet#688a30aa stickerset:messages.StickerSet = Update; - -updateStickerSetsOrder#bb2d201 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Update; - -updateStickerSets#31c24808 flags:# masks:flags.0?true emojis:flags.1?true = Update; - -updateSavedGifs#9375341e = Update; - -updateBotInlineQuery#496f379c flags:# query_id:long user_id:long query:string geo:flags.0?GeoPoint peer_type:flags.1?InlineQueryPeerType offset:string = Update; - -updateBotInlineSend#12f12a07 flags:# user_id:long query:string geo:flags.0?GeoPoint id:string msg_id:flags.1?InputBotInlineMessageID = Update; - -updateEditChannelMessage#1b3f4df7 message:Message pts:int pts_count:int = Update; - -updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg_id:int chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; - -updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; - -updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; - -updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; - -updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update; - -updateReadFeaturedStickers#571d2742 = Update; - -updateRecentStickers#9a422c20 = Update; - -updateConfig#a229dd06 = Update; - -updatePtsChanged#3354678f = Update; - -updateChannelWebPage#2f2ba99f channel_id:long webpage:WebPage pts:int pts_count:int = Update; - -updateDialogPinned#6e6fe51c flags:# pinned:flags.0?true folder_id:flags.1?int peer:DialogPeer = Update; - -updatePinnedDialogs#fa0f3ca2 flags:# folder_id:flags.1?int order:flags.0?Vector = Update; - -updateBotWebhookJSON#8317c0c3 data:DataJSON = Update; - -updateBotWebhookJSONQuery#9b9240a6 query_id:long data:DataJSON timeout:int = Update; - -updateBotShippingQuery#b5aefd7d query_id:long user_id:long payload:bytes shipping_address:PostAddress = Update; - -updateBotPrecheckoutQuery#8caa9a96 flags:# query_id:long user_id:long payload:bytes info:flags.0?PaymentRequestedInfo shipping_option_id:flags.1?string currency:string total_amount:long = Update; - -updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; - -updateLangPackTooLong#46560264 lang_code:string = Update; - -updateLangPack#56022f4d difference:LangPackDifference = Update; - -updateFavedStickers#e511996d = Update; - -updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector = Update; - -updateContactsReset#7084a7be = Update; - -updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; - -updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update; - -updateMessagePoll#d64c522b flags:# peer:flags.1?Peer msg_id:flags.1?int top_msg_id:flags.2?int poll_id:long poll:flags.0?Poll results:PollResults = Update; - -updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; - -updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; - -updatePeerSettings#6a7e7366 peer:Peer settings:PeerSettings = Update; - -updatePeerLocated#b4afcfb0 peers:Vector = Update; - -updateNewScheduledMessage#39a51dfb message:Message = Update; - -updateDeleteScheduledMessages#f2a71983 flags:# peer:Peer messages:Vector sent_messages:flags.0?Vector = Update; - -updateTheme#8216fba3 theme:Theme = Update; - -updateGeoLiveViewed#871fb939 peer:Peer msg_id:int = Update; - -updateLoginToken#564fe691 = Update; - -updateMessagePollVote#7699f014 poll_id:long peer:Peer options:Vector positions:Vector qts:int = Update; - -updateDialogFilter#26ffde7d flags:# id:int filter:flags.0?DialogFilter = Update; - -updateDialogFilterOrder#a5d72105 order:Vector = Update; - -updateDialogFilters#3504914f = Update; - -updatePhoneCallSignalingData#2661bf09 phone_call_id:long data:bytes = Update; - -updateChannelMessageForwards#d29a27f4 channel_id:long id:int forwards:int = Update; - -updateReadChannelDiscussionInbox#d6b19546 flags:# channel_id:long top_msg_id:int read_max_id:int broadcast_id:flags.0?long broadcast_post:flags.0?int = Update; - -updateReadChannelDiscussionOutbox#695c9e7c channel_id:long top_msg_id:int read_max_id:int = Update; - -updatePeerBlocked#ebe07752 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer = Update; - -updateChannelUserTyping#8c88c923 flags:# channel_id:long top_msg_id:flags.0?int from_id:Peer action:SendMessageAction = Update; - -updatePinnedMessages#ed85eab5 flags:# pinned:flags.0?true peer:Peer messages:Vector pts:int pts_count:int = Update; - -updatePinnedChannelMessages#5bb98608 flags:# pinned:flags.0?true channel_id:long messages:Vector pts:int pts_count:int = Update; - -updateChat#f89a6a4e chat_id:long = Update; - -updateGroupCallParticipants#f2ebdb4e call:InputGroupCall participants:Vector version:int = Update; - -updateGroupCall#9d2216e0 flags:# live_story:flags.2?true peer:flags.1?Peer call:GroupCall = Update; - -updatePeerHistoryTTL#bb9bb9a5 flags:# peer:Peer ttl_period:flags.0?int = Update; - -updateChatParticipant#d087663a flags:# chat_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChatParticipant new_participant:flags.1?ChatParticipant invite:flags.2?ExportedChatInvite qts:int = Update; - -updateChannelParticipant#985d3abb flags:# via_chatlist:flags.3?true channel_id:long date:int actor_id:long user_id:long prev_participant:flags.0?ChannelParticipant new_participant:flags.1?ChannelParticipant invite:flags.2?ExportedChatInvite qts:int = Update; - -updateBotStopped#c4870a49 user_id:long date:int stopped:Bool qts:int = Update; - -updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJSON = Update; - -updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; - -updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; - -updateBotChatInviteRequester#7cb34d79 flags:# peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int query_id:flags.0?long = Update; - -updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update; - -updateAttachMenuBots#17b7a20b = Update; - -updateWebViewResultSent#1592b79d query_id:long = Update; - -updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update; - -updateSavedRingtones#74d8be99 = Update; - -updateTranscribedAudio#84cd5a flags:# pending:flags.0?true peer:Peer msg_id:int transcription_id:long text:string = Update; - -updateReadFeaturedEmojiStickers#fb4c496c = Update; - -updateUserEmojiStatus#28373599 user_id:long emoji_status:EmojiStatus = Update; - -updateRecentEmojiStatuses#30f443db = Update; - -updateRecentReactions#6f7863f4 = Update; - -updateMoveStickerSetToTop#86fccf85 flags:# masks:flags.0?true emojis:flags.1?true stickerset:long = Update; - -updateMessageExtendedMedia#d5a41724 peer:Peer msg_id:int extended_media:Vector = Update; - -updateUser#20529438 user_id:long = Update; - -updateAutoSaveSettings#ec05b097 = Update; - -updateStory#75b3b798 peer:Peer story:StoryItem = Update; - -updateReadStories#f74e932b peer:Peer max_id:int = Update; - -updateStoryID#1bf335b9 id:int random_id:long = Update; - -updateStoriesStealthMode#2c084dc1 stealth_mode:StoriesStealthMode = Update; - -updateSentStoryReaction#7d627683 peer:Peer story_id:int reaction:Reaction = Update; - -updateBotChatBoost#904dd49c peer:Peer boost:Boost qts:int = Update; - -updateChannelViewForumAsMessages#7b68920 channel_id:long enabled:Bool = Update; - -updatePeerWallpaper#ae3f101d flags:# wallpaper_overridden:flags.1?true peer:Peer wallpaper:flags.0?WallPaper = Update; - -updateBotMessageReaction#ac21d3ce peer:Peer msg_id:int date:int actor:Peer old_reactions:Vector new_reactions:Vector qts:int = Update; - -updateBotMessageReactions#9cb7759 peer:Peer msg_id:int date:int reactions:Vector qts:int = Update; - -updateSavedDialogPinned#aeaf9e74 flags:# pinned:flags.0?true peer:DialogPeer = Update; - -updatePinnedSavedDialogs#686c85a6 flags:# order:flags.0?Vector = Update; - -updateSavedReactionTags#39c67432 = Update; - -updateSmsJob#f16269d4 job_id:string = Update; - -updateQuickReplies#f9470ab2 quick_replies:Vector = Update; - -updateNewQuickReply#f53da717 quick_reply:QuickReply = Update; - -updateDeleteQuickReply#53e6f1ec shortcut_id:int = Update; - -updateQuickReplyMessage#3e050d0f message:Message = Update; - -updateDeleteQuickReplyMessages#566fe7cd shortcut_id:int messages:Vector = Update; - -updateBotBusinessConnect#8ae5c97a connection:BotBusinessConnection qts:int = Update; - -updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; - -updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; - -updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; - -updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; - -updateStarsBalance#4e80a379 balance:StarsAmount = Update; - -updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update; - -updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; - -updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update; - -updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; - -updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; - -updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; - -updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; - -updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; - -updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update; - -updateGroupCallMessage#d8326f0d call:InputGroupCall message:GroupCallMessage = Update; - -updateGroupCallEncryptedMessage#c957a766 call:InputGroupCall from_id:Peer encrypted_message:bytes = Update; - -updatePinnedForumTopic#683b2c52 flags:# pinned:flags.0?true peer:Peer topic_id:int = Update; - -updatePinnedForumTopics#def143d0 flags:# peer:Peer order:flags.0?Vector = Update; - -updateDeleteGroupCallMessages#3e85e92c call:InputGroupCall messages:Vector = Update; - -updateStarGiftAuctionState#48e246c2 gift_id:long state:StarGiftAuctionState = Update; - -updateStarGiftAuctionUserState#dc58f31e gift_id:long user_state:StarGiftAuctionUserState = Update; - -updateEmojiGameInfo#fb9c547a info:messages.EmojiGameInfo = Update; - -updateStarGiftCraftFail#ac072444 = Update; - -updateChatParticipantRank#bd8367b9 chat_id:long user_id:long rank:string version:int = Update; - -updateManagedBot#4880ed9a user_id:long bot_id:long qts:int = Update; - -updateBotGuestChatQuery#cdd4093d flags:# query_id:long message:Message reference_messages:flags.0?Vector qts:int = Update; - -updateAiComposeTones#8c0f91fb = Update; - -updateJoinChatWebViewDecision#bdac7e70 peer:Peer query_id:long result:JoinChatBotResult = Update; - -updateNewBotConnection#b22083a6 flags:# confirmed:flags.0?true bot_id:long date:flags.1?int device:flags.1?string location:flags.1?string = Update; - -updateWebBrowserSettings#c39a2ade flags:# open_external_browser:flags.0?true display_close_button:flags.1?true = Update; - -updateWebBrowserException#140502d1 flags:# delete:flags.1?true open_external_browser:flags.0?Bool exception:WebDomainException = Update; - -updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; - -updates.differenceEmpty#5d75a138 date:int seq:int = updates.Difference; - -updates.difference#f49ca0 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector state:updates.State = updates.Difference; - -updates.differenceSlice#a8fb1981 new_messages:Vector new_encrypted_messages:Vector other_updates:Vector chats:Vector users:Vector intermediate_state:updates.State = updates.Difference; - -updates.differenceTooLong#4afe8f6d pts:int = updates.Difference; - -updatesTooLong#e317af7e = Updates; - -updateShortMessage#313bc7f8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int user_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -updateShortChatMessage#4d6deea5 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true id:int from_id:long chat_id:long message:string pts:int pts_count:int date:int fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long reply_to:flags.3?MessageReplyHeader entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -updateShort#78d4dec1 update:Update date:int = Updates; - -updatesCombined#725b04c3 updates:Vector users:Vector chats:Vector date:int seq_start:int seq:int = Updates; - -updates#74ae4240 updates:Vector users:Vector chats:Vector date:int seq:int = Updates; - -updateShortSentMessage#9015e101 flags:# out:flags.1?true id:int pts:int pts_count:int date:int media:flags.9?MessageMedia entities:flags.7?Vector ttl_period:flags.25?int = Updates; - -photos.photos#8dca6aa5 photos:Vector users:Vector = photos.Photos; - -photos.photosSlice#15051f54 count:int photos:Vector users:Vector = photos.Photos; - -photos.photo#20212ca8 photo:Photo users:Vector = photos.Photo; - -upload.file#96a18d5 type:storage.FileType mtime:int bytes:bytes = upload.File; - -upload.fileCdnRedirect#f18cda44 dc_id:int file_token:bytes encryption_key:bytes encryption_iv:bytes file_hashes:Vector = upload.File; - -dcOption#18b7a10d flags:# ipv6:flags.0?true media_only:flags.1?true tcpo_only:flags.2?true cdn:flags.3?true static:flags.4?true this_port_only:flags.5?true id:int ip_address:string port:int secret:flags.10?bytes = DcOption; - -config#cc1a241e flags:# default_p2p_contacts:flags.3?true preload_featured_stickers:flags.4?true revoke_pm_inbox:flags.6?true blocked_mode:flags.8?true force_try_ipv6:flags.14?true date:int expires:int test_mode:Bool this_dc:int dc_options:Vector dc_txt_domain_name:string chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int push_chat_period_ms:int push_chat_limit:int edit_time_limit:int revoke_time_limit:int revoke_pm_time_limit:int rating_e_decay:int stickers_recent_limit:int channels_read_media_period:int tmp_sessions:flags.0?int call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string autoupdate_url_prefix:flags.7?string gif_search_username:flags.9?string venue_search_username:flags.10?string img_search_username:flags.11?string static_maps_provider:flags.12?string caption_length_max:int message_length_max:int webfile_dc_id:int suggested_lang_code:flags.2?string lang_pack_version:flags.2?int base_lang_pack_version:flags.2?int reactions_default:flags.15?Reaction autologin_token:flags.16?string = Config; - -nearestDc#8e1a1775 country:string this_dc:int nearest_dc:int = NearestDc; - -help.appUpdate#ccbbce30 flags:# can_not_skip:flags.0?true id:int version:string text:string entities:Vector document:flags.1?Document url:flags.2?string sticker:flags.3?Document = help.AppUpdate; - -help.noAppUpdate#c45a6536 = help.AppUpdate; - -help.inviteText#18cb9f78 message:string = help.InviteText; - -encryptedChatEmpty#ab7ec0a0 id:int = EncryptedChat; - -encryptedChatWaiting#66b25953 id:int access_hash:long date:int admin_id:long participant_id:long = EncryptedChat; - -encryptedChatRequested#48f1d94c flags:# folder_id:flags.0?int id:int access_hash:long date:int admin_id:long participant_id:long g_a:bytes = EncryptedChat; - -encryptedChat#61f0d4c7 id:int access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long = EncryptedChat; - -encryptedChatDiscarded#1e1c7c45 flags:# history_deleted:flags.0?true id:int = EncryptedChat; - -inputEncryptedChat#f141b5e1 chat_id:int access_hash:long = InputEncryptedChat; - -encryptedFileEmpty#c21f497e = EncryptedFile; - -encryptedFile#a8008cd8 id:long access_hash:long size:long dc_id:int key_fingerprint:int = EncryptedFile; - -inputEncryptedFileEmpty#1837c364 = InputEncryptedFile; - -inputEncryptedFileUploaded#64bd0306 id:long parts:int md5_checksum:string key_fingerprint:int = InputEncryptedFile; - -inputEncryptedFile#5a17b5e5 id:long access_hash:long = InputEncryptedFile; - -inputEncryptedFileBigUploaded#2dc173c8 id:long parts:int key_fingerprint:int = InputEncryptedFile; - -encryptedMessage#ed18c118 random_id:long chat_id:int date:int bytes:bytes file:EncryptedFile = EncryptedMessage; - -encryptedMessageService#23734b06 random_id:long chat_id:int date:int bytes:bytes = EncryptedMessage; - -messages.dhConfigNotModified#c0e24635 random:bytes = messages.DhConfig; - -messages.dhConfig#2c221edd g:int p:bytes version:int random:bytes = messages.DhConfig; - -messages.sentEncryptedMessage#560f8935 date:int = messages.SentEncryptedMessage; - -messages.sentEncryptedFile#9493ff32 date:int file:EncryptedFile = messages.SentEncryptedMessage; - -inputDocumentEmpty#72f0eaae = InputDocument; - -inputDocument#1abfb575 id:long access_hash:long file_reference:bytes = InputDocument; - -documentEmpty#36f8c871 id:long = Document; - -document#8fd4c4d8 flags:# id:long access_hash:long file_reference:bytes date:int mime_type:string size:long thumbs:flags.0?Vector video_thumbs:flags.1?Vector dc_id:int attributes:Vector = Document; - -help.support#17c6b5f6 phone_number:string user:User = help.Support; - -notifyPeer#9fd40bd8 peer:Peer = NotifyPeer; - -notifyUsers#b4c83b4c = NotifyPeer; - -notifyChats#c007cec3 = NotifyPeer; - -notifyBroadcasts#d612e8ef = NotifyPeer; - -notifyForumTopic#226e6308 peer:Peer top_msg_id:int = NotifyPeer; - -sendMessageTypingAction#16bf744e = SendMessageAction; - -sendMessageCancelAction#fd5ec8f5 = SendMessageAction; - -sendMessageRecordVideoAction#a187d66f = SendMessageAction; - -sendMessageUploadVideoAction#e9763aec progress:int = SendMessageAction; - -sendMessageRecordAudioAction#d52f73f7 = SendMessageAction; - -sendMessageUploadAudioAction#f351d7ab progress:int = SendMessageAction; - -sendMessageUploadPhotoAction#d1d34a26 progress:int = SendMessageAction; - -sendMessageUploadDocumentAction#aa0cd9e4 progress:int = SendMessageAction; - -sendMessageGeoLocationAction#176f8ba1 = SendMessageAction; - -sendMessageChooseContactAction#628cbc6f = SendMessageAction; - -sendMessageGamePlayAction#dd6a8f48 = SendMessageAction; - -sendMessageRecordRoundAction#88f27fbc = SendMessageAction; - -sendMessageUploadRoundAction#243e1c66 progress:int = SendMessageAction; - -speakingInGroupCallAction#d92c2285 = SendMessageAction; - -sendMessageHistoryImportAction#dbda9246 progress:int = SendMessageAction; - -sendMessageChooseStickerAction#b05ac6b1 = SendMessageAction; - -sendMessageEmojiInteraction#25972bcb emoticon:string msg_id:int interaction:DataJSON = SendMessageAction; - -sendMessageEmojiInteractionSeen#b665902e emoticon:string = SendMessageAction; - -sendMessageTextDraftAction#376d975c random_id:long text:TextWithEntities = SendMessageAction; - -inputSendMessageRichMessageDraftAction#e2b23b51 random_id:long rich_message:InputRichMessage = SendMessageAction; - -sendMessageRichMessageDraftAction#a2cb24f9 random_id:long rich_message:RichMessage = SendMessageAction; - -contacts.found#b3134d9d my_results:Vector results:Vector chats:Vector users:Vector = contacts.Found; - -inputPrivacyKeyStatusTimestamp#4f96cb18 = InputPrivacyKey; - -inputPrivacyKeyChatInvite#bdfb0426 = InputPrivacyKey; - -inputPrivacyKeyPhoneCall#fabadc5f = InputPrivacyKey; - -inputPrivacyKeyPhoneP2P#db9e70d2 = InputPrivacyKey; - -inputPrivacyKeyForwards#a4dd4c08 = InputPrivacyKey; - -inputPrivacyKeyProfilePhoto#5719bacc = InputPrivacyKey; - -inputPrivacyKeyPhoneNumber#352dafa = InputPrivacyKey; - -inputPrivacyKeyAddedByPhone#d1219bdd = InputPrivacyKey; - -inputPrivacyKeyVoiceMessages#aee69d68 = InputPrivacyKey; - -inputPrivacyKeyAbout#3823cc40 = InputPrivacyKey; - -inputPrivacyKeyBirthday#d65a11cc = InputPrivacyKey; - -inputPrivacyKeyStarGiftsAutoSave#e1732341 = InputPrivacyKey; - -inputPrivacyKeyNoPaidMessages#bdc597b4 = InputPrivacyKey; - -inputPrivacyKeySavedMusic#4dbe9226 = InputPrivacyKey; - -privacyKeyStatusTimestamp#bc2eab30 = PrivacyKey; - -privacyKeyChatInvite#500e6dfa = PrivacyKey; - -privacyKeyPhoneCall#3d662b7b = PrivacyKey; - -privacyKeyPhoneP2P#39491cc8 = PrivacyKey; - -privacyKeyForwards#69ec56a3 = PrivacyKey; - -privacyKeyProfilePhoto#96151fed = PrivacyKey; - -privacyKeyPhoneNumber#d19ae46d = PrivacyKey; - -privacyKeyAddedByPhone#42ffd42b = PrivacyKey; - -privacyKeyVoiceMessages#697f414 = PrivacyKey; - -privacyKeyAbout#a486b761 = PrivacyKey; - -privacyKeyBirthday#2000a518 = PrivacyKey; - -privacyKeyStarGiftsAutoSave#2ca4fdf8 = PrivacyKey; - -privacyKeyNoPaidMessages#17d348d2 = PrivacyKey; - -privacyKeySavedMusic#ff7a571b = PrivacyKey; - -inputPrivacyValueAllowContacts#d09e07b = InputPrivacyRule; - -inputPrivacyValueAllowAll#184b35ce = InputPrivacyRule; - -inputPrivacyValueAllowUsers#131cc67f users:Vector = InputPrivacyRule; - -inputPrivacyValueDisallowContacts#ba52007 = InputPrivacyRule; - -inputPrivacyValueDisallowAll#d66b66c9 = InputPrivacyRule; - -inputPrivacyValueDisallowUsers#90110467 users:Vector = InputPrivacyRule; - -inputPrivacyValueAllowChatParticipants#840649cf chats:Vector = InputPrivacyRule; - -inputPrivacyValueDisallowChatParticipants#e94f0f86 chats:Vector = InputPrivacyRule; - -inputPrivacyValueAllowCloseFriends#2f453e49 = InputPrivacyRule; - -inputPrivacyValueAllowPremium#77cdc9f1 = InputPrivacyRule; - -inputPrivacyValueAllowBots#5a4fcce5 = InputPrivacyRule; - -inputPrivacyValueDisallowBots#c4e57915 = InputPrivacyRule; - -privacyValueAllowContacts#fffe1bac = PrivacyRule; - -privacyValueAllowAll#65427b82 = PrivacyRule; - -privacyValueAllowUsers#b8905fb2 users:Vector = PrivacyRule; - -privacyValueDisallowContacts#f888fa1a = PrivacyRule; - -privacyValueDisallowAll#8b73e763 = PrivacyRule; - -privacyValueDisallowUsers#e4621141 users:Vector = PrivacyRule; - -privacyValueAllowChatParticipants#6b134e8e chats:Vector = PrivacyRule; - -privacyValueDisallowChatParticipants#41c87565 chats:Vector = PrivacyRule; - -privacyValueAllowCloseFriends#f7e8d89b = PrivacyRule; - -privacyValueAllowPremium#ece9814b = PrivacyRule; - -privacyValueAllowBots#21461b5d = PrivacyRule; - -privacyValueDisallowBots#f6a5f82f = PrivacyRule; - -account.privacyRules#50a04e45 rules:Vector chats:Vector users:Vector = account.PrivacyRules; - -accountDaysTTL#b8d0afdf days:int = AccountDaysTTL; - -documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute; - -documentAttributeAnimated#11b58939 = DocumentAttribute; - -documentAttributeSticker#6319d612 flags:# mask:flags.1?true alt:string stickerset:InputStickerSet mask_coords:flags.0?MaskCoords = DocumentAttribute; - -documentAttributeVideo#43c57c48 flags:# round_message:flags.0?true supports_streaming:flags.1?true nosound:flags.3?true duration:double w:int h:int preload_prefix_size:flags.2?int video_start_ts:flags.4?double video_codec:flags.5?string = DocumentAttribute; - -documentAttributeAudio#9852f9c6 flags:# voice:flags.10?true duration:int title:flags.0?string performer:flags.1?string waveform:flags.2?bytes = DocumentAttribute; - -documentAttributeFilename#15590068 file_name:string = DocumentAttribute; - -documentAttributeHasStickers#9801d2f7 = DocumentAttribute; - -documentAttributeCustomEmoji#fd149899 flags:# free:flags.0?true text_color:flags.1?true alt:string stickerset:InputStickerSet = DocumentAttribute; - -messages.stickersNotModified#f1749a22 = messages.Stickers; - -messages.stickers#30a6ec7e hash:long stickers:Vector = messages.Stickers; - -stickerPack#12b299d4 emoticon:string documents:Vector = StickerPack; - -messages.allStickersNotModified#e86602c3 = messages.AllStickers; - -messages.allStickers#cdbbcebb hash:long sets:Vector = messages.AllStickers; - -messages.affectedMessages#84d19185 pts:int pts_count:int = messages.AffectedMessages; - -webPageEmpty#211a1788 flags:# id:long url:flags.0?string = WebPage; - -webPagePending#b0d13e47 flags:# id:long url:flags.0?string date:int = WebPage; - -webPage#e89c45b2 flags:# has_large_media:flags.13?true video_cover_photo:flags.14?true id:long url:string display_url:string hash:int type:flags.0?string site_name:flags.1?string title:flags.2?string description:flags.3?string photo:flags.4?Photo embed_url:flags.5?string embed_type:flags.5?string embed_width:flags.6?int embed_height:flags.6?int duration:flags.7?int author:flags.8?string document:flags.9?Document cached_page:flags.10?Page attributes:flags.12?Vector = WebPage; - -webPageNotModified#7311ca11 flags:# cached_page_views:flags.0?int = WebPage; - -authorization#ad01d61d flags:# current:flags.0?true official_app:flags.1?true password_pending:flags.2?true encrypted_requests_disabled:flags.3?true call_requests_disabled:flags.4?true unconfirmed:flags.5?true hash:long device_model:string platform:string system_version:string api_id:int app_name:string app_version:string date_created:int date_active:int ip:string country:string region:string = Authorization; - -account.authorizations#4bff8ea0 authorization_ttl_days:int authorizations:Vector = account.Authorizations; - -account.password#957b50fb flags:# has_recovery:flags.0?true has_secure_values:flags.1?true has_password:flags.2?true current_algo:flags.2?PasswordKdfAlgo srp_B:flags.2?bytes srp_id:flags.2?long hint:flags.3?string email_unconfirmed_pattern:flags.4?string new_algo:PasswordKdfAlgo new_secure_algo:SecurePasswordKdfAlgo secure_random:bytes pending_reset_date:flags.5?int login_email_pattern:flags.6?string = account.Password; - -account.passwordSettings#9a5c33e5 flags:# email:flags.0?string secure_settings:flags.1?SecureSecretSettings = account.PasswordSettings; - -account.passwordInputSettings#c23727c9 flags:# new_algo:flags.0?PasswordKdfAlgo new_password_hash:flags.0?bytes hint:flags.0?string email:flags.1?string new_secure_settings:flags.2?SecureSecretSettings = account.PasswordInputSettings; - -auth.passwordRecovery#137948a5 email_pattern:string = auth.PasswordRecovery; - -receivedNotifyMessage#a384b779 id:int flags:int = ReceivedNotifyMessage; - -chatInviteExported#a22cbd96 flags:# revoked:flags.0?true permanent:flags.5?true request_needed:flags.6?true link:string admin_id:long date:int start_date:flags.4?int expire_date:flags.1?int usage_limit:flags.2?int usage:flags.3?int requested:flags.7?int subscription_expired:flags.10?int title:flags.8?string subscription_pricing:flags.9?StarsSubscriptionPricing = ExportedChatInvite; - -chatInvitePublicJoinRequests#ed107ab7 = ExportedChatInvite; - -chatInviteAlready#5a686d7c chat:Chat = ChatInvite; - -chatInvite#5c9d3702 flags:# channel:flags.0?true broadcast:flags.1?true public:flags.2?true megagroup:flags.3?true request_needed:flags.6?true verified:flags.7?true scam:flags.8?true fake:flags.9?true can_refulfill_subscription:flags.11?true title:string about:flags.5?string photo:Photo participants_count:int participants:flags.4?Vector color:int subscription_pricing:flags.10?StarsSubscriptionPricing subscription_form_id:flags.12?long bot_verification:flags.13?BotVerification = ChatInvite; - -chatInvitePeek#61695cb0 chat:Chat expires:int = ChatInvite; - -inputStickerSetEmpty#ffb62b95 = InputStickerSet; - -inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet; - -inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet; - -inputStickerSetAnimatedEmoji#28703c8 = InputStickerSet; - -inputStickerSetDice#e67f520e emoticon:string = InputStickerSet; - -inputStickerSetAnimatedEmojiAnimations#cde3739 = InputStickerSet; - -inputStickerSetPremiumGifts#c88b3b02 = InputStickerSet; - -inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet; - -inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; - -inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; - -inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet; - -inputStickerSetTonGifts#1cf671a0 = InputStickerSet; - -stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; - -messages.stickerSet#6e153f16 set:StickerSet packs:Vector keywords:Vector documents:Vector = messages.StickerSet; - -messages.stickerSetNotModified#d3f924eb = messages.StickerSet; - -botCommand#c27ac8c7 command:string description:string = BotCommand; - -botInfo#4d8a0299 flags:# has_preview_medias:flags.6?true user_id:flags.0?long description:flags.1?string description_photo:flags.4?Photo description_document:flags.5?Document commands:flags.2?Vector menu_button:flags.3?BotMenuButton privacy_policy_url:flags.7?string app_settings:flags.8?BotAppSettings verifier_settings:flags.9?BotVerifierSettings = BotInfo; - -keyboardButton#7d170cff flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; - -keyboardButtonUrl#d80c25ec flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; - -keyboardButtonCallback#e62bc960 flags:# requires_password:flags.0?true style:flags.10?KeyboardButtonStyle text:string data:bytes = KeyboardButton; - -keyboardButtonRequestPhone#417efd8f flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; - -keyboardButtonRequestGeoLocation#aa40f94d flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; - -keyboardButtonSwitchInline#991399fc flags:# same_peer:flags.0?true style:flags.10?KeyboardButtonStyle text:string query:string peer_types:flags.1?Vector = KeyboardButton; - -keyboardButtonGame#89c590f9 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; - -keyboardButtonBuy#3fa53905 flags:# style:flags.10?KeyboardButtonStyle text:string = KeyboardButton; - -keyboardButtonUrlAuth#f51006f9 flags:# style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.0?string url:string button_id:int = KeyboardButton; - -inputKeyboardButtonUrlAuth#68013e72 flags:# request_write_access:flags.0?true style:flags.10?KeyboardButtonStyle text:string fwd_text:flags.1?string url:string bot:InputUser = KeyboardButton; - -keyboardButtonRequestPoll#7a11d782 flags:# style:flags.10?KeyboardButtonStyle quiz:flags.0?Bool text:string = KeyboardButton; - -inputKeyboardButtonUserProfile#7d5e07c7 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:InputUser = KeyboardButton; - -keyboardButtonUserProfile#c0fd5d09 flags:# style:flags.10?KeyboardButtonStyle text:string user_id:long = KeyboardButton; - -keyboardButtonWebView#e846b1a0 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; - -keyboardButtonSimpleWebView#e15c4370 flags:# style:flags.10?KeyboardButtonStyle text:string url:string = KeyboardButton; - -keyboardButtonRequestPeer#5b0f15f5 flags:# style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; - -inputKeyboardButtonRequestPeer#2b78156 flags:# name_requested:flags.0?true username_requested:flags.1?true photo_requested:flags.2?true style:flags.10?KeyboardButtonStyle text:string button_id:int peer_type:RequestPeerType max_quantity:int = KeyboardButton; - -keyboardButtonCopy#bcc4af10 flags:# style:flags.10?KeyboardButtonStyle text:string copy_text:string = KeyboardButton; - -keyboardButtonRow#77608b83 buttons:Vector = KeyboardButtonRow; - -replyKeyboardHide#a03e5b85 flags:# selective:flags.2?true = ReplyMarkup; - -replyKeyboardForceReply#86b40b08 flags:# single_use:flags.1?true selective:flags.2?true placeholder:flags.3?string = ReplyMarkup; - -replyKeyboardMarkup#85dd99d1 flags:# resize:flags.0?true single_use:flags.1?true selective:flags.2?true persistent:flags.4?true rows:Vector placeholder:flags.3?string = ReplyMarkup; - -replyInlineMarkup#48a30254 rows:Vector = ReplyMarkup; - -messageEntityUnknown#bb92ba95 offset:int length:int = MessageEntity; - -messageEntityMention#fa04579d offset:int length:int = MessageEntity; - -messageEntityHashtag#6f635b0d offset:int length:int = MessageEntity; - -messageEntityBotCommand#6cef8ac7 offset:int length:int = MessageEntity; - -messageEntityUrl#6ed02538 offset:int length:int = MessageEntity; - -messageEntityEmail#64e475c2 offset:int length:int = MessageEntity; - -messageEntityBold#bd610bc9 offset:int length:int = MessageEntity; - -messageEntityItalic#826f8b60 offset:int length:int = MessageEntity; - -messageEntityCode#28a20571 offset:int length:int = MessageEntity; - -messageEntityPre#73924be0 offset:int length:int language:string = MessageEntity; - -messageEntityTextUrl#76a6d327 offset:int length:int url:string = MessageEntity; - -messageEntityMentionName#dc7b1140 offset:int length:int user_id:long = MessageEntity; - -inputMessageEntityMentionName#208e68c9 offset:int length:int user_id:InputUser = MessageEntity; - -messageEntityPhone#9b69e34b offset:int length:int = MessageEntity; - -messageEntityCashtag#4c4e743f offset:int length:int = MessageEntity; - -messageEntityUnderline#9c4e7e8b offset:int length:int = MessageEntity; - -messageEntityStrike#bf0693d4 offset:int length:int = MessageEntity; - -messageEntityBankCard#761e6af4 offset:int length:int = MessageEntity; - -messageEntitySpoiler#32ca960f offset:int length:int = MessageEntity; - -messageEntityCustomEmoji#c8cf05f8 offset:int length:int document_id:long = MessageEntity; - -messageEntityBlockquote#f1ccaaac flags:# collapsed:flags.0?true offset:int length:int = MessageEntity; - -messageEntityFormattedDate#904ac7c7 flags:# relative:flags.0?true short_time:flags.1?true long_time:flags.2?true short_date:flags.3?true long_date:flags.4?true day_of_week:flags.5?true offset:int length:int date:int = MessageEntity; - -messageEntityDiffInsert#71777116 offset:int length:int = MessageEntity; - -messageEntityDiffReplace#c6c1e5a7 offset:int length:int old_text:string = MessageEntity; - -messageEntityDiffDelete#652c1c5 offset:int length:int = MessageEntity; - -inputChannelEmpty#ee8c1e86 = InputChannel; - -inputChannel#f35aec28 channel_id:long access_hash:long = InputChannel; - -inputChannelFromMessage#5b934f9d peer:InputPeer msg_id:int channel_id:long = InputChannel; - -contacts.resolvedPeer#7f077ad9 peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; - -messageRange#ae30253 min_id:int max_id:int = MessageRange; - -updates.channelDifferenceEmpty#3e11affb flags:# final:flags.0?true pts:int timeout:flags.1?int = updates.ChannelDifference; - -updates.channelDifferenceTooLong#a4bcc6fe flags:# final:flags.0?true timeout:flags.1?int dialog:Dialog messages:Vector chats:Vector users:Vector = updates.ChannelDifference; - -updates.channelDifference#2064674e flags:# final:flags.0?true pts:int timeout:flags.1?int new_messages:Vector other_updates:Vector chats:Vector users:Vector = updates.ChannelDifference; - -channelMessagesFilterEmpty#94d42ee7 = ChannelMessagesFilter; - -channelMessagesFilter#cd77d957 flags:# exclude_new_messages:flags.1?true ranges:Vector = ChannelMessagesFilter; - -channelParticipant#1bd54456 flags:# user_id:long date:int subscription_until_date:flags.0?int rank:flags.2?string = ChannelParticipant; - -channelParticipantSelf#a9478a1a flags:# via_request:flags.0?true user_id:long inviter_id:long date:int subscription_until_date:flags.1?int rank:flags.2?string = ChannelParticipant; - -channelParticipantCreator#2fe601d3 flags:# user_id:long admin_rights:ChatAdminRights rank:flags.0?string = ChannelParticipant; - -channelParticipantAdmin#34c3bb53 flags:# can_edit:flags.0?true self:flags.1?true user_id:long inviter_id:flags.1?long promoted_by:long date:int admin_rights:ChatAdminRights rank:flags.2?string = ChannelParticipant; - -channelParticipantBanned#d5f0ad91 flags:# left:flags.0?true peer:Peer kicked_by:long date:int banned_rights:ChatBannedRights rank:flags.2?string = ChannelParticipant; - -channelParticipantLeft#1b03f006 peer:Peer = ChannelParticipant; - -channelParticipantsRecent#de3f3c79 = ChannelParticipantsFilter; - -channelParticipantsAdmins#b4608969 = ChannelParticipantsFilter; - -channelParticipantsKicked#a3b54985 q:string = ChannelParticipantsFilter; - -channelParticipantsBots#b0d1865b = ChannelParticipantsFilter; - -channelParticipantsBanned#1427a5e1 q:string = ChannelParticipantsFilter; - -channelParticipantsSearch#656ac4b q:string = ChannelParticipantsFilter; - -channelParticipantsContacts#bb6ae88d q:string = ChannelParticipantsFilter; - -channelParticipantsMentions#e04b5ceb flags:# q:flags.0?string top_msg_id:flags.1?int = ChannelParticipantsFilter; - -channels.channelParticipants#9ab0feaf count:int participants:Vector chats:Vector users:Vector = channels.ChannelParticipants; - -channels.channelParticipantsNotModified#f0173fe9 = channels.ChannelParticipants; - -channels.channelParticipant#dfb80317 participant:ChannelParticipant chats:Vector users:Vector = channels.ChannelParticipant; - -help.termsOfService#780a0310 flags:# popup:flags.0?true id:DataJSON text:string entities:Vector min_age_confirm:flags.1?int = help.TermsOfService; - -messages.savedGifsNotModified#e8025ca2 = messages.SavedGifs; - -messages.savedGifs#84a02a0d hash:long gifs:Vector = messages.SavedGifs; - -inputBotInlineMessageMediaAuto#3380c786 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineMessageText#3dcd7a87 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineMessageMediaGeo#96929a85 flags:# geo_point:InputGeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineMessageMediaVenue#417bbf11 flags:# geo_point:InputGeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineMessageMediaContact#a6edbffd flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineMessageGame#4b425864 flags:# reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineMessageMediaInvoice#d7e78225 flags:# title:string description:string photo:flags.0?InputWebDocument invoice:Invoice payload:bytes provider:string provider_data:DataJSON reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineMessageMediaWebPage#bddcc510 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true optional:flags.6?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = InputBotInlineMessage; - -inputBotInlineMessageRichMessage#b43df56c flags:# reply_markup:flags.2?ReplyMarkup rich_message:InputRichMessage = InputBotInlineMessage; - -inputBotInlineResult#88bf9319 flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?InputWebDocument content:flags.5?InputWebDocument send_message:InputBotInlineMessage = InputBotInlineResult; - -inputBotInlineResultPhoto#a8d864a7 id:string type:string photo:InputPhoto send_message:InputBotInlineMessage = InputBotInlineResult; - -inputBotInlineResultDocument#fff8fdc4 flags:# id:string type:string title:flags.1?string description:flags.2?string document:InputDocument send_message:InputBotInlineMessage = InputBotInlineResult; - -inputBotInlineResultGame#4fa417f2 id:string short_name:string send_message:InputBotInlineMessage = InputBotInlineResult; - -botInlineMessageMediaAuto#764cf810 flags:# invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineMessageText#8c7f65e2 flags:# no_webpage:flags.0?true invert_media:flags.3?true message:string entities:flags.1?Vector reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineMessageMediaGeo#51846fd flags:# geo:GeoPoint heading:flags.0?int period:flags.1?int proximity_notification_radius:flags.3?int reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineMessageMediaVenue#8a86659c flags:# geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineMessageMediaContact#18d1cdc2 flags:# phone_number:string first_name:string last_name:string vcard:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineMessageMediaInvoice#354a9b09 flags:# shipping_address_requested:flags.1?true test:flags.3?true title:string description:string photo:flags.0?WebDocument currency:string total_amount:long reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineMessageMediaWebPage#809ad9a6 flags:# invert_media:flags.3?true force_large_media:flags.4?true force_small_media:flags.5?true manual:flags.7?true safe:flags.8?true message:string entities:flags.1?Vector url:string reply_markup:flags.2?ReplyMarkup = BotInlineMessage; - -botInlineMessageRichMessage#a617e7b flags:# reply_markup:flags.2?ReplyMarkup rich_message:RichMessage = BotInlineMessage; - -botInlineResult#11965f3a flags:# id:string type:string title:flags.1?string description:flags.2?string url:flags.3?string thumb:flags.4?WebDocument content:flags.5?WebDocument send_message:BotInlineMessage = BotInlineResult; - -botInlineMediaResult#17db940b flags:# id:string type:string photo:flags.0?Photo document:flags.1?Document title:flags.2?string description:flags.3?string send_message:BotInlineMessage = BotInlineResult; - -messages.botResults#e021f2f6 flags:# gallery:flags.0?true query_id:long next_offset:flags.1?string switch_pm:flags.2?InlineBotSwitchPM switch_webview:flags.3?InlineBotWebView results:Vector cache_time:int users:Vector = messages.BotResults; - -exportedMessageLink#5dab1af4 link:string html:string = ExportedMessageLink; - -messageFwdHeader#4e4df4bb flags:# imported:flags.7?true saved_out:flags.11?true from_id:flags.0?Peer from_name:flags.5?string date:int channel_post:flags.2?int post_author:flags.3?string saved_from_peer:flags.4?Peer saved_from_msg_id:flags.4?int saved_from_id:flags.8?Peer saved_from_name:flags.9?string saved_date:flags.10?int psa_type:flags.6?string = MessageFwdHeader; - -auth.codeTypeSms#72a3158c = auth.CodeType; - -auth.codeTypeCall#741cd3e3 = auth.CodeType; - -auth.codeTypeFlashCall#226ccefb = auth.CodeType; - -auth.codeTypeMissedCall#d61ad6ee = auth.CodeType; - -auth.codeTypeFragmentSms#6ed998c = auth.CodeType; - -auth.sentCodeTypeApp#3dbb5986 length:int = auth.SentCodeType; - -auth.sentCodeTypeSms#c000bba2 length:int = auth.SentCodeType; - -auth.sentCodeTypeCall#5353e5a7 length:int = auth.SentCodeType; - -auth.sentCodeTypeFlashCall#ab03c6d9 pattern:string = auth.SentCodeType; - -auth.sentCodeTypeMissedCall#82006484 prefix:string length:int = auth.SentCodeType; - -auth.sentCodeTypeEmailCode#f450f59b flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true email_pattern:string length:int reset_available_period:flags.3?int reset_pending_date:flags.4?int = auth.SentCodeType; - -auth.sentCodeTypeSetUpEmailRequired#a5491dea flags:# apple_signin_allowed:flags.0?true google_signin_allowed:flags.1?true = auth.SentCodeType; - -auth.sentCodeTypeFragmentSms#d9565c39 url:string length:int = auth.SentCodeType; - -auth.sentCodeTypeFirebaseSms#9fd736 flags:# nonce:flags.0?bytes play_integrity_project_id:flags.2?long play_integrity_nonce:flags.2?bytes receipt:flags.1?string push_timeout:flags.1?int length:int = auth.SentCodeType; - -auth.sentCodeTypeSmsWord#a416ac81 flags:# beginning:flags.0?string = auth.SentCodeType; - -auth.sentCodeTypeSmsPhrase#b37794af flags:# beginning:flags.0?string = auth.SentCodeType; - -messages.botCallbackAnswer#36585ea4 flags:# alert:flags.1?true has_url:flags.3?true native_ui:flags.4?true message:flags.0?string url:flags.2?string cache_time:int = messages.BotCallbackAnswer; - -messages.messageEditData#26b5dde6 flags:# caption:flags.0?true = messages.MessageEditData; - -inputBotInlineMessageID#890c3d89 dc_id:int id:long access_hash:long = InputBotInlineMessageID; - -inputBotInlineMessageID64#b6d915d7 dc_id:int owner_id:long id:int access_hash:long = InputBotInlineMessageID; - -inlineBotSwitchPM#3c20629f text:string start_param:string = InlineBotSwitchPM; - -messages.peerDialogs#3371c354 dialogs:Vector messages:Vector chats:Vector users:Vector state:updates.State = messages.PeerDialogs; - -topPeer#edcdc05b peer:Peer rating:double = TopPeer; - -topPeerCategoryBotsPM#ab661b5b = TopPeerCategory; - -topPeerCategoryBotsInline#148677e2 = TopPeerCategory; - -topPeerCategoryCorrespondents#637b7ed = TopPeerCategory; - -topPeerCategoryGroups#bd17a14a = TopPeerCategory; - -topPeerCategoryChannels#161d9628 = TopPeerCategory; - -topPeerCategoryPhoneCalls#1e76a78c = TopPeerCategory; - -topPeerCategoryForwardUsers#a8406ca9 = TopPeerCategory; - -topPeerCategoryForwardChats#fbeec0f0 = TopPeerCategory; - -topPeerCategoryBotsApp#fd9e7bec = TopPeerCategory; - -topPeerCategoryBotsGuestChat#6c24f3dd = TopPeerCategory; - -topPeerCategoryPeers#fb834291 category:TopPeerCategory count:int peers:Vector = TopPeerCategoryPeers; - -contacts.topPeersNotModified#de266ef5 = contacts.TopPeers; - -contacts.topPeers#70b772a8 categories:Vector chats:Vector users:Vector = contacts.TopPeers; - -contacts.topPeersDisabled#b52c939d = contacts.TopPeers; - -draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; - -draftMessage#60fe3294 flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost rich_message:flags.9?RichMessage = DraftMessage; - -messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; - -messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; - -messages.recentStickersNotModified#b17f890 = messages.RecentStickers; - -messages.recentStickers#88d37c56 hash:long packs:Vector stickers:Vector dates:Vector = messages.RecentStickers; - -messages.archivedStickers#4fcba9c8 count:int sets:Vector = messages.ArchivedStickers; - -messages.stickerSetInstallResultSuccess#38641628 = messages.StickerSetInstallResult; - -messages.stickerSetInstallResultArchive#35e410a8 sets:Vector = messages.StickerSetInstallResult; - -stickerSetCovered#6410a5d2 set:StickerSet cover:Document = StickerSetCovered; - -stickerSetMultiCovered#3407e51b set:StickerSet covers:Vector = StickerSetCovered; - -stickerSetFullCovered#40d13c0e set:StickerSet packs:Vector keywords:Vector documents:Vector = StickerSetCovered; - -stickerSetNoCovered#77b15d1c set:StickerSet = StickerSetCovered; - -maskCoords#aed6dbb2 n:int x:double y:double zoom:double = MaskCoords; - -inputStickeredMediaPhoto#4a992157 id:InputPhoto = InputStickeredMedia; - -inputStickeredMediaDocument#438865b id:InputDocument = InputStickeredMedia; - -game#bdf9653b flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document = Game; - -inputGameID#32c3e77 id:long access_hash:long = InputGame; - -inputGameShortName#c331e80a bot_id:InputUser short_name:string = InputGame; - -highScore#73a379eb pos:int user_id:long score:int = HighScore; - -messages.highScores#9a3bfd99 scores:Vector users:Vector = messages.HighScores; - -textEmpty#dc3d824f = RichText; - -textPlain#744694e0 text:string = RichText; - -textBold#6724abc4 text:RichText = RichText; - -textItalic#d912a59c text:RichText = RichText; - -textUnderline#c12622c4 text:RichText = RichText; - -textStrike#9bf8bb95 text:RichText = RichText; - -textFixed#6c3f19b9 text:RichText = RichText; - -textUrl#3c2884c1 text:RichText url:string webpage_id:long = RichText; - -textEmail#de5a0dd6 text:RichText email:string = RichText; - -textConcat#7e6260d7 texts:Vector = RichText; - -textSubscript#ed6a8504 text:RichText = RichText; - -textSuperscript#c7fb5e01 text:RichText = RichText; - -textMarked#34b8621 text:RichText = RichText; - -textPhone#1ccb966a text:RichText phone:string = RichText; - -textImage#81ccf4f document_id:long w:int h:int = RichText; - -textAnchor#35553762 text:RichText name:string = RichText; - -textMath#9d2eac97 source:string = RichText; - -textCustomEmoji#a26156c0 document_id:long alt:string = RichText; - -textSpoiler#4c2a5d62 text:RichText = RichText; - -textMention#cd24cf44 text:RichText = RichText; - -textHashtag#519524ea text:RichText = RichText; - -textBotCommand#2ff29d3 text:RichText = RichText; - -textCashtag#7b9e1801 text:RichText = RichText; - -textAutoUrl#ac6a83aa text:RichText = RichText; - -textAutoEmail#c556a45d text:RichText = RichText; - -textAutoPhone#24c26789 text:RichText = RichText; - -textBankCard#b956812d text:RichText = RichText; - -textMentionName#1a9fbfc text:RichText user_id:long = RichText; - -textDate#a5b45e2b flags:# relative:flags.0?true short_time:flags.1?true long_time:flags.2?true short_date:flags.3?true long_date:flags.4?true day_of_week:flags.5?true text:RichText date:int = RichText; - -pageBlockUnsupported#13567e8a = PageBlock; - -pageBlockTitle#70abc3fd text:RichText = PageBlock; - -pageBlockSubtitle#8ffa9a1f text:RichText = PageBlock; - -pageBlockAuthorDate#baafe5e0 author:RichText published_date:int = PageBlock; - -pageBlockHeader#bfd064ec text:RichText = PageBlock; - -pageBlockSubheader#f12bb6e1 text:RichText = PageBlock; - -pageBlockParagraph#467a0766 text:RichText = PageBlock; - -pageBlockPreformatted#c070d93e text:RichText language:string = PageBlock; - -pageBlockFooter#48870999 text:RichText = PageBlock; - -pageBlockDivider#db20b188 = PageBlock; - -pageBlockAnchor#ce0d37b0 name:string = PageBlock; - -pageBlockList#e4e88011 items:Vector = PageBlock; - -pageBlockBlockquote#263d7c26 text:RichText caption:RichText = PageBlock; - -pageBlockPullquote#4f4456d3 text:RichText caption:RichText = PageBlock; - -pageBlockPhoto#1759c560 flags:# spoiler:flags.1?true photo_id:long caption:PageCaption url:flags.0?string webpage_id:flags.0?long = PageBlock; - -pageBlockVideo#7c8fe7b6 flags:# autoplay:flags.0?true loop:flags.1?true spoiler:flags.2?true video_id:long caption:PageCaption = PageBlock; - -pageBlockCover#39f23300 cover:PageBlock = PageBlock; - -pageBlockEmbed#a8718dc5 flags:# full_width:flags.0?true allow_scrolling:flags.3?true url:flags.1?string html:flags.2?string poster_photo_id:flags.4?long w:flags.5?int h:flags.5?int caption:PageCaption = PageBlock; - -pageBlockEmbedPost#f259a80b url:string webpage_id:long author_photo_id:long author:string date:int blocks:Vector caption:PageCaption = PageBlock; - -pageBlockCollage#65a0fa4d items:Vector caption:PageCaption = PageBlock; - -pageBlockSlideshow#31f9590 items:Vector caption:PageCaption = PageBlock; - -pageBlockChannel#ef1751b5 channel:Chat = PageBlock; - -pageBlockAudio#804361ea audio_id:long caption:PageCaption = PageBlock; - -pageBlockKicker#1e148390 text:RichText = PageBlock; - -pageBlockTable#bf4dea82 flags:# bordered:flags.0?true striped:flags.1?true title:RichText rows:Vector = PageBlock; - -pageBlockOrderedList#1fd6f6c1 flags:# reversed:flags.2?true items:Vector start:flags.0?int type:flags.1?string = PageBlock; - -pageBlockDetails#76768bed flags:# open:flags.0?true blocks:Vector title:RichText = PageBlock; - -pageBlockRelatedArticles#16115a96 title:RichText articles:Vector = PageBlock; - -pageBlockMap#a44f3ef6 geo:GeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; - -pageBlockHeading1#baff072f text:RichText = PageBlock; - -pageBlockHeading2#96b2aec text:RichText = PageBlock; - -pageBlockHeading3#67e731ad text:RichText = PageBlock; - -pageBlockHeading4#b532772b text:RichText = PageBlock; - -pageBlockHeading5#dbbe6c6a text:RichText = PageBlock; - -pageBlockHeading6#682a41a9 text:RichText = PageBlock; - -pageBlockMath#59080c20 source:string = PageBlock; - -pageBlockThinking#3c29a3e2 text:RichText = PageBlock; - -inputPageBlockMap#574b617f geo:InputGeoPoint zoom:int w:int h:int caption:PageCaption = PageBlock; - -pageBlockBlockquoteBlocks#e6e47c4 blocks:Vector caption:RichText = PageBlock; - -phoneCallDiscardReasonMissed#85e42301 = PhoneCallDiscardReason; - -phoneCallDiscardReasonDisconnect#e095c1a0 = PhoneCallDiscardReason; - -phoneCallDiscardReasonHangup#57adc690 = PhoneCallDiscardReason; - -phoneCallDiscardReasonBusy#faf7e8c9 = PhoneCallDiscardReason; - -phoneCallDiscardReasonMigrateConferenceCall#9fbbf1f7 slug:string = PhoneCallDiscardReason; - -dataJSON#7d748d04 data:string = DataJSON; - -labeledPrice#cb296bf8 label:string amount:long = LabeledPrice; - -invoice#49ee584 flags:# test:flags.0?true name_requested:flags.1?true phone_requested:flags.2?true email_requested:flags.3?true shipping_address_requested:flags.4?true flexible:flags.5?true phone_to_provider:flags.6?true email_to_provider:flags.7?true recurring:flags.9?true currency:string prices:Vector max_tip_amount:flags.8?long suggested_tip_amounts:flags.8?Vector terms_url:flags.10?string subscription_period:flags.11?int = Invoice; - -paymentCharge#ea02c27e id:string provider_charge_id:string = PaymentCharge; - -postAddress#1e8caaeb street_line1:string street_line2:string city:string state:string country_iso2:string post_code:string = PostAddress; - -paymentRequestedInfo#909c3f94 flags:# name:flags.0?string phone:flags.1?string email:flags.2?string shipping_address:flags.3?PostAddress = PaymentRequestedInfo; - -paymentSavedCredentialsCard#cdc27a1f id:string title:string = PaymentSavedCredentials; - -webDocument#1c570ed1 url:string access_hash:long size:int mime_type:string attributes:Vector = WebDocument; - -webDocumentNoProxy#f9c8bcc6 url:string size:int mime_type:string attributes:Vector = WebDocument; - -inputWebDocument#9bed434d url:string size:int mime_type:string attributes:Vector = InputWebDocument; - -inputWebFileLocation#c239d686 url:string access_hash:long = InputWebFileLocation; - -inputWebFileGeoPointLocation#9f2221c9 geo_point:InputGeoPoint access_hash:long w:int h:int zoom:int scale:int = InputWebFileLocation; - -inputWebFileAudioAlbumThumbLocation#f46fe924 flags:# small:flags.2?true document:flags.0?InputDocument title:flags.1?string performer:flags.1?string = InputWebFileLocation; - -upload.webFile#21e753bc size:int mime_type:string file_type:storage.FileType mtime:int bytes:bytes = upload.WebFile; - -payments.paymentForm#a0058751 flags:# can_save_credentials:flags.2?true password_missing:flags.3?true form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice provider_id:long url:string native_provider:flags.4?string native_params:flags.4?DataJSON additional_methods:flags.6?Vector saved_info:flags.0?PaymentRequestedInfo saved_credentials:flags.1?Vector users:Vector = payments.PaymentForm; - -payments.paymentFormStars#7bf6b15c flags:# form_id:long bot_id:long title:string description:string photo:flags.5?WebDocument invoice:Invoice users:Vector = payments.PaymentForm; - -payments.paymentFormStarGift#b425cfe1 form_id:long invoice:Invoice = payments.PaymentForm; - -payments.validatedRequestedInfo#d1451883 flags:# id:flags.0?string shipping_options:flags.1?Vector = payments.ValidatedRequestedInfo; - -payments.paymentResult#4e5f810d updates:Updates = payments.PaymentResult; - -payments.paymentVerificationNeeded#d8411139 url:string = payments.PaymentResult; - -payments.paymentReceipt#70c4fe03 flags:# date:int bot_id:long provider_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice info:flags.0?PaymentRequestedInfo shipping:flags.1?ShippingOption tip_amount:flags.3?long currency:string total_amount:long credentials_title:string users:Vector = payments.PaymentReceipt; - -payments.paymentReceiptStars#dabbf83a flags:# date:int bot_id:long title:string description:string photo:flags.2?WebDocument invoice:Invoice currency:string total_amount:long transaction_id:string users:Vector = payments.PaymentReceipt; - -payments.savedInfo#fb8fe43c flags:# has_saved_credentials:flags.1?true saved_info:flags.0?PaymentRequestedInfo = payments.SavedInfo; - -inputPaymentCredentialsSaved#c10eb2cf id:string tmp_password:bytes = InputPaymentCredentials; - -inputPaymentCredentials#3417d728 flags:# save:flags.0?true data:DataJSON = InputPaymentCredentials; - -inputPaymentCredentialsApplePay#aa1c39f payment_data:DataJSON = InputPaymentCredentials; - -inputPaymentCredentialsGooglePay#8ac32801 payment_token:DataJSON = InputPaymentCredentials; - -account.tmpPassword#db64fd34 tmp_password:bytes valid_until:int = account.TmpPassword; - -shippingOption#b6213cdf id:string title:string prices:Vector = ShippingOption; - -inputStickerSetItem#32da9e9c flags:# document:InputDocument emoji:string mask_coords:flags.0?MaskCoords keywords:flags.1?string = InputStickerSetItem; - -inputPhoneCall#1e36fded id:long access_hash:long = InputPhoneCall; - -phoneCallEmpty#5366c915 id:long = PhoneCall; - -phoneCallWaiting#c5226f17 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long protocol:PhoneCallProtocol receive_date:flags.0?int = PhoneCall; - -phoneCallRequested#14b0ed0c flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_hash:bytes protocol:PhoneCallProtocol = PhoneCall; - -phoneCallAccepted#3660c311 flags:# video:flags.6?true id:long access_hash:long date:int admin_id:long participant_id:long g_b:bytes protocol:PhoneCallProtocol = PhoneCall; - -phoneCall#30535af5 flags:# p2p_allowed:flags.5?true video:flags.6?true conference_supported:flags.8?true id:long access_hash:long date:int admin_id:long participant_id:long g_a_or_b:bytes key_fingerprint:long protocol:PhoneCallProtocol connections:Vector start_date:int custom_parameters:flags.7?DataJSON = PhoneCall; - -phoneCallDiscarded#50ca4de1 flags:# need_rating:flags.2?true need_debug:flags.3?true video:flags.6?true id:long reason:flags.0?PhoneCallDiscardReason duration:flags.1?int = PhoneCall; - -phoneConnection#9cc123c7 flags:# tcp:flags.0?true id:long ip:string ipv6:string port:int peer_tag:bytes = PhoneConnection; - -phoneConnectionWebrtc#635fe375 flags:# turn:flags.0?true stun:flags.1?true id:long ip:string ipv6:string port:int username:string password:string = PhoneConnection; - -phoneCallProtocol#fc878fc8 flags:# udp_p2p:flags.0?true udp_reflector:flags.1?true min_layer:int max_layer:int library_versions:Vector = PhoneCallProtocol; - -phone.phoneCall#ec82e140 phone_call:PhoneCall users:Vector = phone.PhoneCall; - -upload.cdnFileReuploadNeeded#eea8e46e request_token:bytes = upload.CdnFile; - -upload.cdnFile#a99fca4f bytes:bytes = upload.CdnFile; - -cdnPublicKey#c982eaba dc_id:int public_key:string = CdnPublicKey; - -cdnConfig#5725e40a public_keys:Vector = CdnConfig; - -langPackString#cad181f6 key:string value:string = LangPackString; - -langPackStringPluralized#6c47ac9f flags:# key:string zero_value:flags.0?string one_value:flags.1?string two_value:flags.2?string few_value:flags.3?string many_value:flags.4?string other_value:string = LangPackString; - -langPackStringDeleted#2979eeb2 key:string = LangPackString; - -langPackDifference#f385c1f6 lang_code:string from_version:int version:int strings:Vector = LangPackDifference; - -langPackLanguage#eeca5ce3 flags:# official:flags.0?true rtl:flags.2?true beta:flags.3?true name:string native_name:string lang_code:string base_lang_code:flags.1?string plural_code:string strings_count:int translated_count:int translations_url:string = LangPackLanguage; - -channelAdminLogEventActionChangeTitle#e6dfb825 prev_value:string new_value:string = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeAbout#55188a2e prev_value:string new_value:string = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeUsername#6a4afc38 prev_value:string new_value:string = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangePhoto#434bd2af prev_photo:Photo new_photo:Photo = ChannelAdminLogEventAction; - -channelAdminLogEventActionToggleInvites#1b7907ae new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEventActionToggleSignatures#26ae0971 new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEventActionUpdatePinned#e9e82c18 message:Message = ChannelAdminLogEventAction; - -channelAdminLogEventActionEditMessage#709b2405 prev_message:Message new_message:Message = ChannelAdminLogEventAction; - -channelAdminLogEventActionDeleteMessage#42e047bb message:Message = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantJoin#183040d3 = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantLeave#f89777f2 = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantInvite#e31c34d8 participant:ChannelParticipant = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantToggleBan#e6d83d7e prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantToggleAdmin#d5676710 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeStickerSet#b1c3caa7 prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; - -channelAdminLogEventActionTogglePreHistoryHidden#5f5c95f1 new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEventActionDefaultBannedRights#2df5fc0a prev_banned_rights:ChatBannedRights new_banned_rights:ChatBannedRights = ChannelAdminLogEventAction; - -channelAdminLogEventActionStopPoll#8f079643 message:Message = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeLinkedChat#50c7ac8 prev_value:long new_value:long = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeLocation#e6b76ae prev_value:ChannelLocation new_value:ChannelLocation = ChannelAdminLogEventAction; - -channelAdminLogEventActionToggleSlowMode#53909779 prev_value:int new_value:int = ChannelAdminLogEventAction; - -channelAdminLogEventActionStartGroupCall#23209745 call:InputGroupCall = ChannelAdminLogEventAction; - -channelAdminLogEventActionDiscardGroupCall#db9f9140 call:InputGroupCall = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantMute#f92424d2 participant:GroupCallParticipant = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantUnmute#e64429c0 participant:GroupCallParticipant = ChannelAdminLogEventAction; - -channelAdminLogEventActionToggleGroupCallSetting#56d6a247 join_muted:Bool = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantJoinByInvite#fe9fc158 flags:# via_chatlist:flags.0?true invite:ExportedChatInvite = ChannelAdminLogEventAction; - -channelAdminLogEventActionExportedInviteDelete#5a50fca4 invite:ExportedChatInvite = ChannelAdminLogEventAction; - -channelAdminLogEventActionExportedInviteRevoke#410a134e invite:ExportedChatInvite = ChannelAdminLogEventAction; - -channelAdminLogEventActionExportedInviteEdit#e90ebb59 prev_invite:ExportedChatInvite new_invite:ExportedChatInvite = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantVolume#3e7f6847 participant:GroupCallParticipant = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeHistoryTTL#6e941a38 prev_value:int new_value:int = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantJoinByRequest#afb6144a invite:ExportedChatInvite approved_by:long = ChannelAdminLogEventAction; - -channelAdminLogEventActionToggleNoForwards#cb2ac766 new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEventActionSendMessage#278f2868 message:Message = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeAvailableReactions#be4e0ef8 prev_value:ChatReactions new_value:ChatReactions = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeUsernames#f04fb3a9 prev_value:Vector new_value:Vector = ChannelAdminLogEventAction; - -channelAdminLogEventActionToggleForum#2cc6383 new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEventActionCreateTopic#58707d28 topic:ForumTopic = ChannelAdminLogEventAction; - -channelAdminLogEventActionEditTopic#f06fe208 prev_topic:ForumTopic new_topic:ForumTopic = ChannelAdminLogEventAction; - -channelAdminLogEventActionDeleteTopic#ae168909 topic:ForumTopic = ChannelAdminLogEventAction; - -channelAdminLogEventActionPinTopic#5d8d353b flags:# prev_topic:flags.0?ForumTopic new_topic:flags.1?ForumTopic = ChannelAdminLogEventAction; - -channelAdminLogEventActionToggleAntiSpam#64f36dfc new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangePeerColor#5796e780 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeProfilePeerColor#5e477b25 prev_value:PeerColor new_value:PeerColor = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeWallpaper#31bb5d52 prev_value:WallPaper new_value:WallPaper = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeEmojiStatus#3ea9feb1 prev_value:EmojiStatus new_value:EmojiStatus = ChannelAdminLogEventAction; - -channelAdminLogEventActionChangeEmojiStickerSet#46d840ab prev_stickerset:InputStickerSet new_stickerset:InputStickerSet = ChannelAdminLogEventAction; - -channelAdminLogEventActionToggleSignatureProfiles#60a79c79 new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantSubExtend#64642db3 prev_participant:ChannelParticipant new_participant:ChannelParticipant = ChannelAdminLogEventAction; - -channelAdminLogEventActionToggleAutotranslation#c517f77e new_value:Bool = ChannelAdminLogEventAction; - -channelAdminLogEventActionParticipantEditRank#5806b4ec user_id:long prev_rank:string new_rank:string = ChannelAdminLogEventAction; - -channelAdminLogEvent#1fad68cd id:long date:int user_id:long action:ChannelAdminLogEventAction = ChannelAdminLogEvent; - -channels.adminLogResults#ed8af74d events:Vector chats:Vector users:Vector = channels.AdminLogResults; - -channelAdminLogEventsFilter#ea107ae4 flags:# join:flags.0?true leave:flags.1?true invite:flags.2?true ban:flags.3?true unban:flags.4?true kick:flags.5?true unkick:flags.6?true promote:flags.7?true demote:flags.8?true info:flags.9?true settings:flags.10?true pinned:flags.11?true edit:flags.12?true delete:flags.13?true group_call:flags.14?true invites:flags.15?true send:flags.16?true forums:flags.17?true sub_extend:flags.18?true edit_rank:flags.19?true = ChannelAdminLogEventsFilter; - -popularContact#5ce14175 client_id:long importers:int = PopularContact; - -messages.favedStickersNotModified#9e8fa6d3 = messages.FavedStickers; - -messages.favedStickers#2cb51097 hash:long packs:Vector stickers:Vector = messages.FavedStickers; - -recentMeUrlUnknown#46e1d13d url:string = RecentMeUrl; - -recentMeUrlUser#b92c09e2 url:string user_id:long = RecentMeUrl; - -recentMeUrlChat#b2da71d2 url:string chat_id:long = RecentMeUrl; - -recentMeUrlChatInvite#eb49081d url:string chat_invite:ChatInvite = RecentMeUrl; - -recentMeUrlStickerSet#bc0a57dc url:string set:StickerSetCovered = RecentMeUrl; - -help.recentMeUrls#e0310d7 urls:Vector chats:Vector users:Vector = help.RecentMeUrls; - -inputSingleMedia#1cc6e91f flags:# media:InputMedia random_id:long message:string entities:flags.0?Vector = InputSingleMedia; - -webAuthorization#a6f8f452 hash:long bot_id:long domain:string browser:string platform:string date_created:int date_active:int ip:string region:string = WebAuthorization; - -account.webAuthorizations#ed56c9fc authorizations:Vector users:Vector = account.WebAuthorizations; - -inputMessageID#a676a322 id:int = InputMessage; - -inputMessageReplyTo#bad88395 id:int = InputMessage; - -inputMessagePinned#86872538 = InputMessage; - -inputMessageCallbackQuery#acfa1a7e id:int query_id:long = InputMessage; - -inputDialogPeer#fcaafeb7 peer:InputPeer = InputDialogPeer; - -inputDialogPeerFolder#64600527 folder_id:int = InputDialogPeer; - -dialogPeer#e56dbf05 peer:Peer = DialogPeer; - -dialogPeerFolder#514519e2 folder_id:int = DialogPeer; - -messages.foundStickerSetsNotModified#d54b65d = messages.FoundStickerSets; - -messages.foundStickerSets#8af09dd2 hash:long sets:Vector = messages.FoundStickerSets; - -fileHash#f39b035c offset:long limit:int hash:bytes = FileHash; - -inputClientProxy#75588b3f address:string port:int = InputClientProxy; - -help.termsOfServiceUpdateEmpty#e3309f7f expires:int = help.TermsOfServiceUpdate; - -help.termsOfServiceUpdate#28ecf961 expires:int terms_of_service:help.TermsOfService = help.TermsOfServiceUpdate; - -inputSecureFileUploaded#3334b0f0 id:long parts:int md5_checksum:string file_hash:bytes secret:bytes = InputSecureFile; - -inputSecureFile#5367e5be id:long access_hash:long = InputSecureFile; - -secureFileEmpty#64199744 = SecureFile; - -secureFile#7d09c27e id:long access_hash:long size:long dc_id:int date:int file_hash:bytes secret:bytes = SecureFile; - -secureData#8aeabec3 data:bytes data_hash:bytes secret:bytes = SecureData; - -securePlainPhone#7d6099dd phone:string = SecurePlainData; - -securePlainEmail#21ec5a5f email:string = SecurePlainData; - -secureValueTypePersonalDetails#9d2a81e3 = SecureValueType; - -secureValueTypePassport#3dac6a00 = SecureValueType; - -secureValueTypeDriverLicense#6e425c4 = SecureValueType; - -secureValueTypeIdentityCard#a0d0744b = SecureValueType; - -secureValueTypeInternalPassport#99a48f23 = SecureValueType; - -secureValueTypeAddress#cbe31e26 = SecureValueType; - -secureValueTypeUtilityBill#fc36954e = SecureValueType; - -secureValueTypeBankStatement#89137c0d = SecureValueType; - -secureValueTypeRentalAgreement#8b883488 = SecureValueType; - -secureValueTypePassportRegistration#99e3806a = SecureValueType; - -secureValueTypeTemporaryRegistration#ea02ec33 = SecureValueType; - -secureValueTypePhone#b320aadb = SecureValueType; - -secureValueTypeEmail#8e3ca7ee = SecureValueType; - -secureValue#187fa0ca flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?SecureFile reverse_side:flags.2?SecureFile selfie:flags.3?SecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData hash:bytes = SecureValue; - -inputSecureValue#db21d0a7 flags:# type:SecureValueType data:flags.0?SecureData front_side:flags.1?InputSecureFile reverse_side:flags.2?InputSecureFile selfie:flags.3?InputSecureFile translation:flags.6?Vector files:flags.4?Vector plain_data:flags.5?SecurePlainData = InputSecureValue; - -secureValueHash#ed1ecdb0 type:SecureValueType hash:bytes = SecureValueHash; - -secureValueErrorData#e8a40bd9 type:SecureValueType data_hash:bytes field:string text:string = SecureValueError; - -secureValueErrorFrontSide#be3dfa type:SecureValueType file_hash:bytes text:string = SecureValueError; - -secureValueErrorReverseSide#868a2aa5 type:SecureValueType file_hash:bytes text:string = SecureValueError; - -secureValueErrorSelfie#e537ced6 type:SecureValueType file_hash:bytes text:string = SecureValueError; - -secureValueErrorFile#7a700873 type:SecureValueType file_hash:bytes text:string = SecureValueError; - -secureValueErrorFiles#666220e9 type:SecureValueType file_hash:Vector text:string = SecureValueError; - -secureValueError#869d758f type:SecureValueType hash:bytes text:string = SecureValueError; - -secureValueErrorTranslationFile#a1144770 type:SecureValueType file_hash:bytes text:string = SecureValueError; - -secureValueErrorTranslationFiles#34636dd8 type:SecureValueType file_hash:Vector text:string = SecureValueError; - -secureCredentialsEncrypted#33f0ea47 data:bytes hash:bytes secret:bytes = SecureCredentialsEncrypted; - -account.authorizationForm#ad2e1cd8 flags:# required_types:Vector values:Vector errors:Vector users:Vector privacy_policy_url:flags.0?string = account.AuthorizationForm; - -account.sentEmailCode#811f854f email_pattern:string length:int = account.SentEmailCode; - -help.deepLinkInfoEmpty#66afa166 = help.DeepLinkInfo; - -help.deepLinkInfo#6a4ee832 flags:# update_app:flags.0?true message:string entities:flags.1?Vector = help.DeepLinkInfo; - -savedPhoneContact#1142bd56 phone:string first_name:string last_name:string date:int = SavedContact; - -account.takeout#4dba4501 id:long = account.Takeout; - -passwordKdfAlgoUnknown#d45ab096 = PasswordKdfAlgo; - -passwordKdfAlgoSHA256SHA256PBKDF2HMACSHA512iter100000SHA256ModPow#3a912d4a salt1:bytes salt2:bytes g:int p:bytes = PasswordKdfAlgo; - -securePasswordKdfAlgoUnknown#4a8537 = SecurePasswordKdfAlgo; - -securePasswordKdfAlgoPBKDF2HMACSHA512iter100000#bbf2dda0 salt:bytes = SecurePasswordKdfAlgo; - -securePasswordKdfAlgoSHA512#86471d92 salt:bytes = SecurePasswordKdfAlgo; - -secureSecretSettings#1527bcac secure_algo:SecurePasswordKdfAlgo secure_secret:bytes secure_secret_id:long = SecureSecretSettings; - -inputCheckPasswordEmpty#9880f658 = InputCheckPasswordSRP; - -inputCheckPasswordSRP#d27ff082 srp_id:long A:bytes M1:bytes = InputCheckPasswordSRP; - -secureRequiredType#829d99da flags:# native_names:flags.0?true selfie_required:flags.1?true translation_required:flags.2?true type:SecureValueType = SecureRequiredType; - -secureRequiredTypeOneOf#27477b4 types:Vector = SecureRequiredType; - -help.passportConfigNotModified#bfb9f457 = help.PassportConfig; - -help.passportConfig#a098d6af hash:int countries_langs:DataJSON = help.PassportConfig; - -inputAppEvent#1d1b1245 time:double type:string peer:long data:JSONValue = InputAppEvent; - -jsonObjectValue#c0de1bd9 key:string value:JSONValue = JSONObjectValue; - -jsonNull#3f6d7b68 = JSONValue; - -jsonBool#c7345e6a value:Bool = JSONValue; - -jsonNumber#2be0dfa4 value:double = JSONValue; - -jsonString#b71e767a value:string = JSONValue; - -jsonArray#f7444763 value:Vector = JSONValue; - -jsonObject#99c1d49d value:Vector = JSONValue; - -pageTableCell#34566b6a flags:# header:flags.0?true align_center:flags.3?true align_right:flags.4?true valign_middle:flags.5?true valign_bottom:flags.6?true text:flags.7?RichText colspan:flags.1?int rowspan:flags.2?int = PageTableCell; - -pageTableRow#e0c0c5e5 cells:Vector = PageTableRow; - -pageCaption#6f747657 text:RichText credit:RichText = PageCaption; - -pageListItemText#2f58683c flags:# checkbox:flags.0?true checked:flags.1?true text:RichText = PageListItem; - -pageListItemBlocks#63ca67aa flags:# checkbox:flags.0?true checked:flags.1?true blocks:Vector = PageListItem; - -pageListOrderedItemText#15031189 flags:# checkbox:flags.0?true checked:flags.1?true num:flags.2?string text:RichText value:flags.3?int type:flags.4?string = PageListOrderedItem; - -pageListOrderedItemBlocks#8ff2d5f0 flags:# checkbox:flags.0?true checked:flags.1?true num:flags.2?string blocks:Vector value:flags.3?int type:flags.4?string = PageListOrderedItem; - -pageRelatedArticle#b390dc08 flags:# url:string webpage_id:long title:flags.0?string description:flags.1?string photo_id:flags.2?long author:flags.3?string published_date:flags.4?int = PageRelatedArticle; - -page#98657f0d flags:# part:flags.0?true rtl:flags.1?true v2:flags.2?true url:string blocks:Vector photos:Vector documents:Vector views:flags.3?int = Page; - -help.supportName#8c05f1c9 name:string = help.SupportName; - -help.userInfoEmpty#f3ae2eed = help.UserInfo; - -help.userInfo#1eb3758 message:string entities:Vector author:string date:int = help.UserInfo; - -pollAnswer#4b7d786a flags:# text:TextWithEntities option:bytes media:flags.0?MessageMedia added_by:flags.1?Peer date:flags.1?int = PollAnswer; - -inputPollAnswer#199fed96 flags:# text:TextWithEntities media:flags.0?InputMedia = PollAnswer; - -poll#966e2dbf id:long flags:# closed:flags.0?true public_voters:flags.1?true multiple_choice:flags.2?true quiz:flags.3?true open_answers:flags.6?true revoting_disabled:flags.7?true shuffle_answers:flags.8?true hide_results_until_close:flags.9?true creator:flags.10?true subscribers_only:flags.11?true question:TextWithEntities answers:Vector close_period:flags.4?int close_date:flags.5?int countries_iso2:flags.12?Vector hash:long = Poll; - -pollAnswerVoters#3645230a flags:# chosen:flags.0?true correct:flags.1?true option:bytes voters:flags.2?int recent_voters:flags.2?Vector = PollAnswerVoters; - -pollResults#ba7bb15e flags:# min:flags.0?true has_unread_votes:flags.6?true can_view_stats:flags.7?true results:flags.1?Vector total_voters:flags.2?int recent_voters:flags.3?Vector solution:flags.4?string solution_entities:flags.4?Vector solution_media:flags.5?MessageMedia = PollResults; - -chatOnlines#f041e250 onlines:int = ChatOnlines; - -statsURL#47a971e0 url:string = StatsURL; - -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true manage_ranks:flags.18?true = ChatAdminRights; - -chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true edit_rank:flags.26?true send_reactions:flags.27?true until_date:int = ChatBannedRights; - -inputWallPaper#e630b979 id:long access_hash:long = InputWallPaper; - -inputWallPaperSlug#72091c80 slug:string = InputWallPaper; - -inputWallPaperNoFile#967a462e id:long = InputWallPaper; - -account.wallPapersNotModified#1c199183 = account.WallPapers; - -account.wallPapers#cdc3858c hash:long wallpapers:Vector = account.WallPapers; - -codeSettings#ad253d78 flags:# allow_flashcall:flags.0?true current_number:flags.1?true allow_app_hash:flags.4?true allow_missed_call:flags.5?true allow_firebase:flags.7?true unknown_number:flags.9?true logout_tokens:flags.6?Vector token:flags.8?string app_sandbox:flags.8?Bool = CodeSettings; - -wallPaperSettings#372efcd0 flags:# blur:flags.1?true motion:flags.2?true background_color:flags.0?int second_background_color:flags.4?int third_background_color:flags.5?int fourth_background_color:flags.6?int intensity:flags.3?int rotation:flags.4?int emoticon:flags.7?string = WallPaperSettings; - -autoDownloadSettings#baa57628 flags:# disabled:flags.0?true video_preload_large:flags.1?true audio_preload_next:flags.2?true phonecalls_less_data:flags.3?true stories_preload:flags.4?true photo_size_max:int video_size_max:long file_size_max:long video_upload_maxbitrate:int small_queue_active_operations_max:int large_queue_active_operations_max:int = AutoDownloadSettings; - -account.autoDownloadSettings#63cacf26 low:AutoDownloadSettings medium:AutoDownloadSettings high:AutoDownloadSettings = account.AutoDownloadSettings; - -emojiKeyword#d5b3b9f9 keyword:string emoticons:Vector = EmojiKeyword; - -emojiKeywordDeleted#236df622 keyword:string emoticons:Vector = EmojiKeyword; - -emojiKeywordsDifference#5cc761bd lang_code:string from_version:int version:int keywords:Vector = EmojiKeywordsDifference; - -emojiURL#a575739d url:string = EmojiURL; - -emojiLanguage#b3fb5361 lang_code:string = EmojiLanguage; - -folder#ff544e65 flags:# autofill_new_broadcasts:flags.0?true autofill_public_groups:flags.1?true autofill_new_correspondents:flags.2?true id:int title:string photo:flags.3?ChatPhoto = Folder; - -inputFolderPeer#fbd2c296 peer:InputPeer folder_id:int = InputFolderPeer; - -folderPeer#e9baa668 peer:Peer folder_id:int = FolderPeer; - -messages.searchCounter#e844ebff flags:# inexact:flags.1?true filter:MessagesFilter count:int = messages.SearchCounter; - -urlAuthResultRequest#3cd623ec flags:# request_write_access:flags.0?true request_phone_number:flags.1?true match_codes_first:flags.5?true is_app:flags.6?true bot:User domain:string browser:flags.2?string platform:flags.2?string ip:flags.2?string region:flags.2?string match_codes:flags.3?Vector user_id_hint:flags.4?long verified_app_name:flags.7?string = UrlAuthResult; - -urlAuthResultAccepted#623a8fa0 flags:# url:flags.0?string = UrlAuthResult; - -urlAuthResultDefault#a9d6db1f = UrlAuthResult; - -channelLocationEmpty#bfb5ad8b = ChannelLocation; - -channelLocation#209b82db geo_point:GeoPoint address:string = ChannelLocation; - -peerLocated#ca461b5d peer:Peer expires:int distance:int = PeerLocated; - -peerSelfLocated#f8ec284b expires:int = PeerLocated; - -restrictionReason#d072acb4 platform:string reason:string text:string = RestrictionReason; - -inputTheme#3c5693e9 id:long access_hash:long = InputTheme; - -inputThemeSlug#f5890df1 slug:string = InputTheme; - -theme#a00e67d6 flags:# creator:flags.0?true default:flags.1?true for_chat:flags.5?true id:long access_hash:long slug:string title:string document:flags.2?Document settings:flags.3?Vector emoticon:flags.6?string installs_count:flags.4?int = Theme; - -account.themesNotModified#f41eb622 = account.Themes; - -account.themes#9a3d8c6d hash:long themes:Vector = account.Themes; - -auth.loginToken#629f1980 expires:int token:bytes = auth.LoginToken; - -auth.loginTokenMigrateTo#68e9916 dc_id:int token:bytes = auth.LoginToken; - -auth.loginTokenSuccess#390d5c5e authorization:auth.Authorization = auth.LoginToken; - -account.contentSettings#57e28221 flags:# sensitive_enabled:flags.0?true sensitive_can_change:flags.1?true = account.ContentSettings; - -messages.inactiveChats#a927fec5 dates:Vector chats:Vector users:Vector = messages.InactiveChats; - -baseThemeClassic#c3a12462 = BaseTheme; - -baseThemeDay#fbd81688 = BaseTheme; - -baseThemeNight#b7b31ea8 = BaseTheme; - -baseThemeTinted#6d5f77ee = BaseTheme; - -baseThemeArctic#5b11125a = BaseTheme; - -inputThemeSettings#8fde504f flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?InputWallPaper wallpaper_settings:flags.1?WallPaperSettings = InputThemeSettings; - -themeSettings#fa58b6d4 flags:# message_colors_animated:flags.2?true base_theme:BaseTheme accent_color:int outbox_accent_color:flags.3?int message_colors:flags.0?Vector wallpaper:flags.1?WallPaper = ThemeSettings; - -webPageAttributeTheme#54b56617 flags:# documents:flags.0?Vector settings:flags.1?ThemeSettings = WebPageAttribute; - -webPageAttributeStory#2e94c3e7 flags:# peer:Peer id:int story:flags.0?StoryItem = WebPageAttribute; - -webPageAttributeStickerSet#50cc03d3 flags:# emojis:flags.0?true text_color:flags.1?true stickers:Vector = WebPageAttribute; - -webPageAttributeUniqueStarGift#cf6f6db8 gift:StarGift = WebPageAttribute; - -webPageAttributeStarGiftCollection#31cad303 icons:Vector = WebPageAttribute; - -webPageAttributeStarGiftAuction#1c641c2 gift:StarGift end_date:int = WebPageAttribute; - -webPageAttributeAiComposeTone#7781fe18 emoji_id:long = WebPageAttribute; - -messages.votesList#4899484e flags:# count:int votes:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.VotesList; - -bankCardOpenUrl#f568028a url:string name:string = BankCardOpenUrl; - -payments.bankCardData#3e24e573 title:string open_urls:Vector = payments.BankCardData; - -dialogFilter#aa472651 flags:# contacts:flags.0?true non_contacts:flags.1?true groups:flags.2?true broadcasts:flags.3?true bots:flags.4?true exclude_muted:flags.11?true exclude_read:flags.12?true exclude_archived:flags.13?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector exclude_peers:Vector = DialogFilter; - -dialogFilterDefault#363293ae = DialogFilter; - -dialogFilterChatlist#96537bd7 flags:# has_my_invites:flags.26?true title_noanimate:flags.28?true id:int title:TextWithEntities emoticon:flags.25?string color:flags.27?int pinned_peers:Vector include_peers:Vector = DialogFilter; - -dialogFilterSuggested#77744d4a filter:DialogFilter description:string = DialogFilterSuggested; - -statsDateRangeDays#b637edaf min_date:int max_date:int = StatsDateRangeDays; - -statsAbsValueAndPrev#cb43acde current:double previous:double = StatsAbsValueAndPrev; - -statsPercentValue#cbce2fe0 part:double total:double = StatsPercentValue; - -statsGraphAsync#4a27eb2d token:string = StatsGraph; - -statsGraphError#bedc9822 error:string = StatsGraph; - -statsGraph#8ea464b6 flags:# json:DataJSON zoom_token:flags.0?string = StatsGraph; - -stats.broadcastStats#396ca5fc period:StatsDateRangeDays followers:StatsAbsValueAndPrev views_per_post:StatsAbsValueAndPrev shares_per_post:StatsAbsValueAndPrev reactions_per_post:StatsAbsValueAndPrev views_per_story:StatsAbsValueAndPrev shares_per_story:StatsAbsValueAndPrev reactions_per_story:StatsAbsValueAndPrev enabled_notifications:StatsPercentValue growth_graph:StatsGraph followers_graph:StatsGraph mute_graph:StatsGraph top_hours_graph:StatsGraph interactions_graph:StatsGraph iv_interactions_graph:StatsGraph views_by_source_graph:StatsGraph new_followers_by_source_graph:StatsGraph languages_graph:StatsGraph reactions_by_emotion_graph:StatsGraph story_interactions_graph:StatsGraph story_reactions_by_emotion_graph:StatsGraph recent_posts_interactions:Vector = stats.BroadcastStats; - -help.promoDataEmpty#98f6ac75 expires:int = help.PromoData; - -help.promoData#8a4d87a flags:# proxy:flags.0?true expires:int peer:flags.3?Peer psa_type:flags.1?string psa_message:flags.2?string pending_suggestions:Vector dismissed_suggestions:Vector custom_pending_suggestion:flags.4?PendingSuggestion chats:Vector users:Vector = help.PromoData; - -videoSize#de33b094 flags:# type:string w:int h:int size:int video_start_ts:flags.0?double = VideoSize; - -videoSizeEmojiMarkup#f85c413c emoji_id:long background_colors:Vector = VideoSize; - -videoSizeStickerMarkup#da082fe stickerset:InputStickerSet sticker_id:long background_colors:Vector = VideoSize; - -statsGroupTopPoster#9d04af9b user_id:long messages:int avg_chars:int = StatsGroupTopPoster; - -statsGroupTopAdmin#d7584c87 user_id:long deleted:int kicked:int banned:int = StatsGroupTopAdmin; - -statsGroupTopInviter#535f779d user_id:long invitations:int = StatsGroupTopInviter; - -stats.megagroupStats#ef7ff916 period:StatsDateRangeDays members:StatsAbsValueAndPrev messages:StatsAbsValueAndPrev viewers:StatsAbsValueAndPrev posters:StatsAbsValueAndPrev growth_graph:StatsGraph members_graph:StatsGraph new_members_by_source_graph:StatsGraph languages_graph:StatsGraph messages_graph:StatsGraph actions_graph:StatsGraph top_hours_graph:StatsGraph weekdays_graph:StatsGraph top_posters:Vector top_admins:Vector top_inviters:Vector users:Vector = stats.MegagroupStats; - -globalPrivacySettings#fe41b34f flags:# archive_and_mute_new_noncontact_peers:flags.0?true keep_archived_unmuted:flags.1?true keep_archived_folders:flags.2?true hide_read_marks:flags.3?true new_noncontact_peers_require_premium:flags.4?true display_gifts_button:flags.7?true noncontact_peers_paid_stars:flags.5?long disallowed_gifts:flags.6?DisallowedGiftsSettings = GlobalPrivacySettings; - -help.countryCode#4203c5ef flags:# country_code:string prefixes:flags.0?Vector patterns:flags.1?Vector = help.CountryCode; - -help.country#c3878e23 flags:# hidden:flags.0?true iso2:string default_name:string name:flags.1?string country_codes:Vector = help.Country; - -help.countriesListNotModified#93cc1f32 = help.CountriesList; - -help.countriesList#87d0759e countries:Vector hash:int = help.CountriesList; - -messageViews#455b853d flags:# views:flags.0?int forwards:flags.1?int replies:flags.2?MessageReplies = MessageViews; - -messages.messageViews#b6c4f543 views:Vector chats:Vector users:Vector = messages.MessageViews; - -messages.discussionMessage#a6341782 flags:# messages:Vector max_id:flags.0?int read_inbox_max_id:flags.1?int read_outbox_max_id:flags.2?int unread_count:int chats:Vector users:Vector = messages.DiscussionMessage; - -messageReplyHeader#1b97dd66 flags:# reply_to_scheduled:flags.2?true forum_topic:flags.3?true quote:flags.9?true reply_to_ephemeral:flags.13?true reply_to_msg_id:flags.4?int reply_to_peer_id:flags.0?Peer reply_from:flags.5?MessageFwdHeader reply_media:flags.8?MessageMedia reply_to_top_id:flags.1?int quote_text:flags.6?string quote_entities:flags.7?Vector quote_offset:flags.10?int todo_item_id:flags.11?int poll_option:flags.12?bytes = MessageReplyHeader; - -messageReplyStoryHeader#e5af939 peer:Peer story_id:int = MessageReplyHeader; - -messageReplies#83d60fc2 flags:# comments:flags.0?true replies:int replies_pts:int recent_repliers:flags.1?Vector channel_id:flags.0?long max_id:flags.2?int read_max_id:flags.3?int = MessageReplies; - -peerBlocked#e8fd8014 peer_id:Peer date:int = PeerBlocked; - -stats.messageStats#7fe91c14 views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.MessageStats; - -groupCallDiscarded#7780bcb4 id:long access_hash:long duration:int = GroupCall; - -groupCall#efb2b617 flags:# join_muted:flags.1?true can_change_join_muted:flags.2?true join_date_asc:flags.6?true schedule_start_subscribed:flags.8?true can_start_video:flags.9?true record_video_active:flags.11?true rtmp_stream:flags.12?true listeners_hidden:flags.13?true conference:flags.14?true creator:flags.15?true messages_enabled:flags.17?true can_change_messages_enabled:flags.18?true min:flags.19?true id:long access_hash:long participants_count:int title:flags.3?string stream_dc_id:flags.4?int record_start_date:flags.5?int schedule_date:flags.7?int unmuted_video_count:flags.10?int unmuted_video_limit:int version:int invite_link:flags.16?string send_paid_messages_stars:flags.20?long default_send_as:flags.21?Peer = GroupCall; - -inputGroupCall#d8aa840f id:long access_hash:long = InputGroupCall; - -inputGroupCallSlug#fe06823f slug:string = InputGroupCall; - -inputGroupCallInviteMessage#8c10603f msg_id:int = InputGroupCall; - -groupCallParticipant#2a3dc7ac flags:# muted:flags.0?true left:flags.1?true can_self_unmute:flags.2?true just_joined:flags.4?true versioned:flags.5?true min:flags.8?true muted_by_you:flags.9?true volume_by_admin:flags.10?true self:flags.12?true video_joined:flags.15?true peer:Peer date:int active_date:flags.3?int source:int volume:flags.7?int about:flags.11?string raise_hand_rating:flags.13?long video:flags.6?GroupCallParticipantVideo presentation:flags.14?GroupCallParticipantVideo paid_stars_total:flags.16?long = GroupCallParticipant; - -phone.groupCall#9e727aad call:GroupCall participants:Vector participants_next_offset:string chats:Vector users:Vector = phone.GroupCall; - -phone.groupParticipants#f47751b6 count:int participants:Vector next_offset:string chats:Vector users:Vector version:int = phone.GroupParticipants; - -inlineQueryPeerTypeSameBotPM#3081ed9d = InlineQueryPeerType; - -inlineQueryPeerTypePM#833c0fac = InlineQueryPeerType; - -inlineQueryPeerTypeChat#d766c50a = InlineQueryPeerType; - -inlineQueryPeerTypeMegagroup#5ec4be43 = InlineQueryPeerType; - -inlineQueryPeerTypeBroadcast#6334ee9a = InlineQueryPeerType; - -inlineQueryPeerTypeBotPM#e3b2d0c = InlineQueryPeerType; - -messages.historyImport#1662af0b id:long = messages.HistoryImport; - -messages.historyImportParsed#5e0fb7b9 flags:# pm:flags.0?true group:flags.1?true title:flags.2?string = messages.HistoryImportParsed; - -messages.affectedFoundMessages#ef8d3e6c pts:int pts_count:int offset:int messages:Vector = messages.AffectedFoundMessages; - -chatInviteImporter#8c5adfd9 flags:# requested:flags.0?true via_chatlist:flags.3?true user_id:long date:int about:flags.2?string approved_by:flags.1?long = ChatInviteImporter; - -messages.exportedChatInvites#bdc62dcc count:int invites:Vector users:Vector = messages.ExportedChatInvites; - -messages.exportedChatInvite#1871be50 invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; - -messages.exportedChatInviteReplaced#222600ef invite:ExportedChatInvite new_invite:ExportedChatInvite users:Vector = messages.ExportedChatInvite; - -messages.chatInviteImporters#81b6b00a count:int importers:Vector users:Vector = messages.ChatInviteImporters; - -chatAdminWithInvites#f2ecef23 admin_id:long invites_count:int revoked_invites_count:int = ChatAdminWithInvites; - -messages.chatAdminsWithInvites#b69b72d7 admins:Vector users:Vector = messages.ChatAdminsWithInvites; - -messages.checkedHistoryImportPeer#a24de717 confirm_text:string = messages.CheckedHistoryImportPeer; - -phone.joinAsPeers#afe5623f peers:Vector chats:Vector users:Vector = phone.JoinAsPeers; - -phone.exportedGroupCallInvite#204bd158 link:string = phone.ExportedGroupCallInvite; - -groupCallParticipantVideoSourceGroup#dcb118b7 semantics:string sources:Vector = GroupCallParticipantVideoSourceGroup; - -groupCallParticipantVideo#67753ac8 flags:# paused:flags.0?true endpoint:string source_groups:Vector audio_source:flags.1?int = GroupCallParticipantVideo; - -stickers.suggestedShortName#85fea03f short_name:string = stickers.SuggestedShortName; - -botCommandScopeDefault#2f6cb2ab = BotCommandScope; - -botCommandScopeUsers#3c4f04d8 = BotCommandScope; - -botCommandScopeChats#6fe1a881 = BotCommandScope; - -botCommandScopeChatAdmins#b9aa606a = BotCommandScope; - -botCommandScopePeer#db9d897d peer:InputPeer = BotCommandScope; - -botCommandScopePeerAdmins#3fd863d1 peer:InputPeer = BotCommandScope; - -botCommandScopePeerUser#a1321f3 peer:InputPeer user_id:InputUser = BotCommandScope; - -account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordResult; - -account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; - -account.resetPasswordOk#e926d63e = account.ResetPasswordResult; - -chatTheme#c3dffc04 emoticon:string = ChatTheme; - -chatThemeUniqueGift#3458f9c8 gift:StarGift theme_settings:Vector = ChatTheme; - -account.chatThemesNotModified#e011e1c4 = account.ChatThemes; - -account.chatThemes#be098173 flags:# hash:long themes:Vector chats:Vector users:Vector next_offset:flags.0?string = account.ChatThemes; - -sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage; - -messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; - -messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; - -searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; - -messages.searchResultsCalendar#147ee23c flags:# inexact:flags.0?true count:int min_date:int min_msg_id:int offset_id_offset:flags.1?int periods:Vector messages:Vector chats:Vector users:Vector = messages.SearchResultsCalendar; - -searchResultPosition#7f648b67 msg_id:int date:int offset:int = SearchResultsPosition; - -messages.searchResultsPositions#53b22baf count:int positions:Vector = messages.SearchResultsPositions; - -channels.sendAsPeers#f496b0c6 peers:Vector chats:Vector users:Vector = channels.SendAsPeers; - -users.userFull#3b6d152e full_user:UserFull chats:Vector users:Vector = users.UserFull; - -messages.peerSettings#6880b94d settings:PeerSettings chats:Vector users:Vector = messages.PeerSettings; - -auth.loggedOut#c3a2835f flags:# future_auth_token:flags.0?bytes = auth.LoggedOut; - -reactionCount#a3d1cb80 flags:# chosen_order:flags.0?int reaction:Reaction count:int = ReactionCount; - -messageReactions#a339f0b flags:# min:flags.0?true can_see_list:flags.2?true reactions_as_tags:flags.3?true results:Vector recent_reactions:flags.1?Vector top_reactors:flags.4?Vector = MessageReactions; - -messages.messageReactionsList#31bd492d flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = messages.MessageReactionsList; - -availableReaction#c077ec01 flags:# inactive:flags.0?true premium:flags.2?true reaction:string title:string static_icon:Document appear_animation:Document select_animation:Document activate_animation:Document effect_animation:Document around_animation:flags.1?Document center_icon:flags.1?Document = AvailableReaction; - -messages.availableReactionsNotModified#9f071957 = messages.AvailableReactions; - -messages.availableReactions#768e3aad hash:int reactions:Vector = messages.AvailableReactions; - -messagePeerReaction#8c79b63c flags:# big:flags.0?true unread:flags.1?true my:flags.2?true peer_id:Peer date:int reaction:Reaction = MessagePeerReaction; - -groupCallStreamChannel#80eb48af channel:int scale:int last_timestamp_ms:long = GroupCallStreamChannel; - -phone.groupCallStreamChannels#d0e482b2 channels:Vector = phone.GroupCallStreamChannels; - -phone.groupCallStreamRtmpUrl#2dbf3432 url:string key:string = phone.GroupCallStreamRtmpUrl; - -attachMenuBotIconColor#4576f3f0 name:string color:int = AttachMenuBotIconColor; - -attachMenuBotIcon#b2a7386b flags:# name:string icon:Document colors:flags.0?Vector = AttachMenuBotIcon; - -attachMenuBot#d90d8dfe flags:# inactive:flags.0?true has_settings:flags.1?true request_write_access:flags.2?true show_in_attach_menu:flags.3?true show_in_side_menu:flags.4?true side_menu_disclaimer_needed:flags.5?true bot_id:long short_name:string peer_types:flags.3?Vector icons:Vector = AttachMenuBot; - -attachMenuBotsNotModified#f1d88a5c = AttachMenuBots; - -attachMenuBots#3c4301c0 hash:long bots:Vector users:Vector = AttachMenuBots; - -attachMenuBotsBot#93bf667f bot:AttachMenuBot users:Vector = AttachMenuBotsBot; - -webViewResultUrl#4d22ff98 flags:# fullsize:flags.1?true fullscreen:flags.2?true same_origin:flags.3?true query_id:flags.0?long url:string = WebViewResult; - -webViewMessageSent#c94511c flags:# msg_id:flags.0?InputBotInlineMessageID = WebViewMessageSent; - -botMenuButtonDefault#7533a588 = BotMenuButton; - -botMenuButtonCommands#4258c205 = BotMenuButton; - -botMenuButton#c7b57ce6 text:string url:string = BotMenuButton; - -account.savedRingtonesNotModified#fbf6e8b1 = account.SavedRingtones; - -account.savedRingtones#c1e92cc5 hash:long ringtones:Vector = account.SavedRingtones; - -notificationSoundDefault#97e8bebe = NotificationSound; - -notificationSoundNone#6f0c34df = NotificationSound; - -notificationSoundLocal#830b9ae4 title:string data:string = NotificationSound; - -notificationSoundRingtone#ff6c8049 id:long = NotificationSound; - -account.savedRingtone#b7263f6d = account.SavedRingtone; - -account.savedRingtoneConverted#1f307eb7 document:Document = account.SavedRingtone; - -attachMenuPeerTypeSameBotPM#7d6be90e = AttachMenuPeerType; - -attachMenuPeerTypeBotPM#c32bfa1a = AttachMenuPeerType; - -attachMenuPeerTypePM#f146d31f = AttachMenuPeerType; - -attachMenuPeerTypeChat#509113f = AttachMenuPeerType; - -attachMenuPeerTypeBroadcast#7bfbdefc = AttachMenuPeerType; - -inputInvoiceMessage#c5b56859 peer:InputPeer msg_id:int = InputInvoice; - -inputInvoiceSlug#c326caef slug:string = InputInvoice; - -inputInvoicePremiumGiftCode#98986c0d purpose:InputStorePaymentPurpose option:PremiumGiftCodeOption = InputInvoice; - -inputInvoiceStars#65f00ce3 purpose:InputStorePaymentPurpose = InputInvoice; - -inputInvoiceChatInviteSubscription#34e793f1 hash:string = InputInvoice; - -inputInvoiceStarGift#e8625e92 flags:# hide_name:flags.0?true include_upgrade:flags.2?true peer:InputPeer gift_id:long message:flags.1?TextWithEntities = InputInvoice; - -inputInvoiceStarGiftUpgrade#4d818d5d flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = InputInvoice; - -inputInvoiceStarGiftTransfer#4a5f5bd9 stargift:InputSavedStarGift to_id:InputPeer = InputInvoice; - -inputInvoicePremiumGiftStars#dabab2ef flags:# user_id:InputUser months:int message:flags.0?TextWithEntities = InputInvoice; - -inputInvoiceBusinessBotTransferStars#f4997e42 bot:InputUser stars:long = InputInvoice; - -inputInvoiceStarGiftResale#c39f5324 flags:# ton:flags.0?true slug:string to_id:InputPeer = InputInvoice; - -inputInvoiceStarGiftPrepaidUpgrade#9a0b48b8 peer:InputPeer hash:string = InputInvoice; - -inputInvoicePremiumAuthCode#3e77f614 purpose:InputStorePaymentPurpose = InputInvoice; - -inputInvoiceStarGiftDropOriginalDetails#923d8d1 stargift:InputSavedStarGift = InputInvoice; - -inputInvoiceStarGiftAuctionBid#1ecafa10 flags:# hide_name:flags.0?true update_bid:flags.2?true peer:flags.3?InputPeer gift_id:long bid_amount:long message:flags.1?TextWithEntities = InputInvoice; - -payments.exportedInvoice#aed0cbd9 url:string = payments.ExportedInvoice; - -messages.transcribedAudio#cfb9d957 flags:# pending:flags.0?true transcription_id:long text:string trial_remains_num:flags.1?int trial_remains_until_date:flags.1?int = messages.TranscribedAudio; - -help.premiumPromo#5334759c status_text:string status_entities:Vector video_sections:Vector videos:Vector period_options:Vector users:Vector = help.PremiumPromo; - -inputStorePaymentPremiumSubscription#a6751e66 flags:# restore:flags.0?true upgrade:flags.1?true = InputStorePaymentPurpose; - -inputStorePaymentGiftPremium#616f7fe8 user_id:InputUser currency:string amount:long = InputStorePaymentPurpose; - -inputStorePaymentPremiumGiftCode#fb790393 flags:# users:Vector boost_peer:flags.0?InputPeer currency:string amount:long message:flags.1?TextWithEntities = InputStorePaymentPurpose; - -inputStorePaymentPremiumGiveaway#160544ca flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long = InputStorePaymentPurpose; - -inputStorePaymentStarsTopup#f9a2a6cb flags:# stars:long currency:string amount:long spend_purpose_peer:flags.0?InputPeer = InputStorePaymentPurpose; - -inputStorePaymentStarsGift#1d741ef7 user_id:InputUser stars:long currency:string amount:long = InputStorePaymentPurpose; - -inputStorePaymentStarsGiveaway#751f08fa flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.3?true stars:long boost_peer:InputPeer additional_peers:flags.1?Vector countries_iso2:flags.2?Vector prize_description:flags.4?string random_id:long until_date:int currency:string amount:long users:int = InputStorePaymentPurpose; - -inputStorePaymentAuthCode#3fc18057 flags:# restore:flags.0?true phone_number:string phone_code_hash:string premium_days:int currency:string amount:long = InputStorePaymentPurpose; - -paymentFormMethod#88f8f21b url:string title:string = PaymentFormMethod; - -emojiStatusEmpty#2de11aae = EmojiStatus; - -emojiStatus#e7ff068a flags:# document_id:long until:flags.0?int = EmojiStatus; - -emojiStatusCollectible#7184603b flags:# collectible_id:long document_id:long title:string slug:string pattern_document_id:long center_color:int edge_color:int pattern_color:int text_color:int until:flags.0?int = EmojiStatus; - -inputEmojiStatusCollectible#7141dbf flags:# collectible_id:long until:flags.0?int = EmojiStatus; - -account.emojiStatusesNotModified#d08ce645 = account.EmojiStatuses; - -account.emojiStatuses#90c467d1 hash:long statuses:Vector = account.EmojiStatuses; - -reactionEmpty#79f5d419 = Reaction; - -reactionEmoji#1b2286b8 emoticon:string = Reaction; - -reactionCustomEmoji#8935fc73 document_id:long = Reaction; - -reactionPaid#523da4eb = Reaction; - -chatReactionsNone#eafc32bc = ChatReactions; - -chatReactionsAll#52928bca flags:# allow_custom:flags.0?true = ChatReactions; - -chatReactionsSome#661d4037 reactions:Vector = ChatReactions; - -messages.reactionsNotModified#b06fdbdf = messages.Reactions; - -messages.reactions#eafdf716 hash:long reactions:Vector = messages.Reactions; - -emailVerifyPurposeLoginSetup#4345be73 phone_number:string phone_code_hash:string = EmailVerifyPurpose; - -emailVerifyPurposeLoginChange#527d22eb = EmailVerifyPurpose; - -emailVerifyPurposePassport#bbf51685 = EmailVerifyPurpose; - -emailVerificationCode#922e55a9 code:string = EmailVerification; - -emailVerificationGoogle#db909ec2 token:string = EmailVerification; - -emailVerificationApple#96d074fd token:string = EmailVerification; - -account.emailVerified#2b96cd1b email:string = account.EmailVerified; - -account.emailVerifiedLogin#e1bb0d61 email:string sent_code:auth.SentCode = account.EmailVerified; - -premiumSubscriptionOption#5f2d1df2 flags:# current:flags.1?true can_purchase_upgrade:flags.2?true transaction:flags.3?string months:int currency:string amount:long bot_url:string store_product:flags.0?string = PremiumSubscriptionOption; - -sendAsPeer#b81c7034 flags:# premium_required:flags.0?true peer:Peer = SendAsPeer; - -messageExtendedMediaPreview#ad628cc8 flags:# w:flags.0?int h:flags.0?int thumb:flags.1?PhotoSize video_duration:flags.2?int = MessageExtendedMedia; - -messageExtendedMedia#ee479c64 media:MessageMedia = MessageExtendedMedia; - -stickerKeyword#fcfeb29c document_id:long keyword:Vector = StickerKeyword; - -username#b4073647 flags:# editable:flags.0?true active:flags.1?true username:string = Username; - -forumTopicDeleted#23f109b id:int = ForumTopic; - -forumTopic#fcdad815 flags:# my:flags.1?true closed:flags.2?true pinned:flags.3?true short:flags.5?true hidden:flags.6?true title_missing:flags.7?true id:int date:int peer:Peer title:string icon_color:int icon_emoji_id:flags.0?long top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int unread_poll_votes_count:int from_id:Peer notify_settings:PeerNotifySettings draft:flags.4?DraftMessage = ForumTopic; - -messages.forumTopics#367617d3 flags:# order_by_create_date:flags.0?true count:int topics:Vector messages:Vector chats:Vector users:Vector pts:int = messages.ForumTopics; - -defaultHistoryTTL#43b46b20 period:int = DefaultHistoryTTL; - -exportedContactToken#41bf109b url:string expires:int = ExportedContactToken; - -requestPeerTypeUser#5f3b8a00 flags:# bot:flags.0?Bool premium:flags.1?Bool = RequestPeerType; - -requestPeerTypeChat#c9f06e1b flags:# creator:flags.0?true bot_participant:flags.5?true has_username:flags.3?Bool forum:flags.4?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; - -requestPeerTypeBroadcast#339bef6c flags:# creator:flags.0?true has_username:flags.3?Bool user_admin_rights:flags.1?ChatAdminRights bot_admin_rights:flags.2?ChatAdminRights = RequestPeerType; - -requestPeerTypeCreateBot#3e81e078 flags:# bot_managed:flags.0?true suggested_name:flags.1?string suggested_username:flags.2?string = RequestPeerType; - -emojiListNotModified#481eadfa = EmojiList; - -emojiList#7a1e11d1 hash:long document_id:Vector = EmojiList; - -emojiGroup#7a9abda9 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; - -emojiGroupGreeting#80d26cc7 title:string icon_emoji_id:long emoticons:Vector = EmojiGroup; - -emojiGroupPremium#93bcf34 title:string icon_emoji_id:long = EmojiGroup; - -messages.emojiGroupsNotModified#6fb4ad87 = messages.EmojiGroups; - -messages.emojiGroups#881fb94b hash:int groups:Vector = messages.EmojiGroups; - -textWithEntities#751f3146 text:string entities:Vector = TextWithEntities; - -messages.translateResult#33db32f8 result:Vector = messages.TranslatedText; - -autoSaveSettings#c84834ce flags:# photos:flags.0?true videos:flags.1?true video_max_size:flags.2?long = AutoSaveSettings; - -autoSaveException#81602d47 peer:Peer settings:AutoSaveSettings = AutoSaveException; - -account.autoSaveSettings#4c3e069d users_settings:AutoSaveSettings chats_settings:AutoSaveSettings broadcasts_settings:AutoSaveSettings exceptions:Vector chats:Vector users:Vector = account.AutoSaveSettings; - -help.appConfigNotModified#7cde641d = help.AppConfig; - -help.appConfig#dd18782e hash:int config:JSONValue = help.AppConfig; - -inputBotAppID#a920bd7a id:long access_hash:long = InputBotApp; - -inputBotAppShortName#908c0407 bot_id:InputUser short_name:string = InputBotApp; - -botAppNotModified#5da674b7 = BotApp; - -botApp#95fcd1d6 flags:# id:long access_hash:long short_name:string title:string description:string photo:Photo document:flags.0?Document hash:long = BotApp; - -messages.botApp#eb50adf5 flags:# inactive:flags.0?true request_write_access:flags.1?true has_settings:flags.2?true app:BotApp = messages.BotApp; - -inlineBotWebView#b57295d5 text:string url:string = InlineBotWebView; - -readParticipantDate#4a4ff172 user_id:long date:int = ReadParticipantDate; - -inputChatlistDialogFilter#f3e0da33 filter_id:int = InputChatlist; - -exportedChatlistInvite#c5181ac flags:# title:string url:string peers:Vector = ExportedChatlistInvite; - -chatlists.exportedChatlistInvite#10e6e3a6 filter:DialogFilter invite:ExportedChatlistInvite = chatlists.ExportedChatlistInvite; - -chatlists.exportedInvites#10ab6dc7 invites:Vector chats:Vector users:Vector = chatlists.ExportedInvites; - -chatlists.chatlistInviteAlready#fa87f659 filter_id:int missing_peers:Vector already_peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; - -chatlists.chatlistInvite#f10ece2f flags:# title_noanimate:flags.1?true title:TextWithEntities emoticon:flags.0?string peers:Vector chats:Vector users:Vector = chatlists.ChatlistInvite; - -chatlists.chatlistUpdates#93bd878d missing_peers:Vector chats:Vector users:Vector = chatlists.ChatlistUpdates; - -bots.botInfo#e8a775b0 name:string about:string description:string = bots.BotInfo; - -messagePeerVote#b6cc2d5c peer:Peer option:bytes date:int = MessagePeerVote; - -messagePeerVoteInputOption#74cda504 peer:Peer date:int = MessagePeerVote; - -messagePeerVoteMultiple#4628f6e6 peer:Peer options:Vector date:int = MessagePeerVote; - -storyViews#8d595cd6 flags:# has_viewers:flags.1?true views_count:int forwards_count:flags.2?int reactions:flags.3?Vector reactions_count:flags.4?int recent_viewers:flags.0?Vector = StoryViews; - -storyItemDeleted#51e6ee4f id:int = StoryItem; - -storyItemSkipped#ffadc913 flags:# close_friends:flags.8?true live:flags.9?true id:int date:int expire_date:int = StoryItem; - -storyItem#16a4b93c flags:# pinned:flags.5?true public:flags.7?true close_friends:flags.8?true min:flags.9?true noforwards:flags.10?true edited:flags.11?true contacts:flags.12?true selected_contacts:flags.13?true out:flags.16?true id:int date:int from_id:flags.18?Peer fwd_from:flags.17?StoryFwdHeader expire_date:int caption:flags.0?string entities:flags.1?Vector media:MessageMedia media_areas:flags.14?Vector privacy:flags.2?Vector views:flags.3?StoryViews sent_reaction:flags.15?Reaction albums:flags.19?Vector music:flags.20?Document = StoryItem; - -stories.allStoriesNotModified#1158fe3e flags:# state:string stealth_mode:StoriesStealthMode = stories.AllStories; - -stories.allStories#6efc5e81 flags:# has_more:flags.0?true count:int state:string peer_stories:Vector chats:Vector users:Vector stealth_mode:StoriesStealthMode = stories.AllStories; - -stories.stories#63c3dd0a flags:# count:int stories:Vector pinned_to_top:flags.0?Vector chats:Vector users:Vector = stories.Stories; - -storyView#b0bdeac5 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true user_id:long date:int reaction:flags.2?Reaction = StoryView; - -storyViewPublicForward#9083670b flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true message:Message = StoryView; - -storyViewPublicRepost#bd74cf49 flags:# blocked:flags.0?true blocked_my_stories_from:flags.1?true peer_id:Peer story:StoryItem = StoryView; - -stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count:int reactions_count:int views:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryViewsList; - -stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; - -inputReplyToMessage#3bd4b7c2 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer todo_item_id:flags.6?int poll_option:flags.7?bytes = InputReplyTo; - -inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; - -inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; - -exportedStoryLink#3fc9053b link:string = ExportedStoryLink; - -storiesStealthMode#712e27fd flags:# active_until_date:flags.0?int cooldown_until_date:flags.1?int = StoriesStealthMode; - -mediaAreaCoordinates#cfc9e002 flags:# x:double y:double w:double h:double rotation:double radius:flags.0?double = MediaAreaCoordinates; - -mediaAreaVenue#be82db9c coordinates:MediaAreaCoordinates geo:GeoPoint title:string address:string provider:string venue_id:string venue_type:string = MediaArea; - -inputMediaAreaVenue#b282217f coordinates:MediaAreaCoordinates query_id:long result_id:string = MediaArea; - -mediaAreaGeoPoint#cad5452d flags:# coordinates:MediaAreaCoordinates geo:GeoPoint address:flags.0?GeoPointAddress = MediaArea; - -mediaAreaSuggestedReaction#14455871 flags:# dark:flags.0?true flipped:flags.1?true coordinates:MediaAreaCoordinates reaction:Reaction = MediaArea; - -mediaAreaChannelPost#770416af coordinates:MediaAreaCoordinates channel_id:long msg_id:int = MediaArea; - -inputMediaAreaChannelPost#2271f2bf coordinates:MediaAreaCoordinates channel:InputChannel msg_id:int = MediaArea; - -mediaAreaUrl#37381085 coordinates:MediaAreaCoordinates url:string = MediaArea; - -mediaAreaWeather#49a6549c coordinates:MediaAreaCoordinates emoji:string temperature_c:double color:int = MediaArea; - -mediaAreaStarGift#5787686d coordinates:MediaAreaCoordinates slug:string = MediaArea; - -peerStories#9a35e999 flags:# peer:Peer max_read_id:flags.0?int stories:Vector = PeerStories; - -stories.peerStories#cae68768 stories:PeerStories chats:Vector users:Vector = stories.PeerStories; - -messages.webPage#fd5e12bd webpage:WebPage chats:Vector users:Vector = messages.WebPage; - -premiumGiftCodeOption#257e962b flags:# users:int months:int store_product:flags.0?string store_quantity:flags.1?int currency:string amount:long = PremiumGiftCodeOption; - -payments.checkedGiftCode#eb983f8f flags:# via_giveaway:flags.2?true from_id:flags.4?Peer giveaway_msg_id:flags.3?int to_id:flags.0?long date:int days:int used_date:flags.1?int chats:Vector users:Vector = payments.CheckedGiftCode; - -payments.giveawayInfo#4367daa0 flags:# participating:flags.0?true preparing_results:flags.3?true start_date:int joined_too_early_date:flags.1?int admin_disallowed_chat_id:flags.2?long disallowed_country:flags.4?string = payments.GiveawayInfo; - -payments.giveawayInfoResults#e175e66f flags:# winner:flags.0?true refunded:flags.1?true start_date:int gift_code_slug:flags.3?string stars_prize:flags.4?long finish_date:int winners_count:int activated_count:flags.2?int = payments.GiveawayInfo; - -prepaidGiveaway#b2539d54 id:long months:int quantity:int date:int = PrepaidGiveaway; - -prepaidStarsGiveaway#9a9d77e0 id:long stars:long quantity:int boosts:int date:int = PrepaidGiveaway; - -boost#4b3e14d6 flags:# gift:flags.1?true giveaway:flags.2?true unclaimed:flags.3?true id:string user_id:flags.0?long giveaway_msg_id:flags.2?int date:int expires:int used_gift_slug:flags.4?string multiplier:flags.5?int stars:flags.6?long = Boost; - -premium.boostsList#86f8613c flags:# count:int boosts:Vector next_offset:flags.0?string users:Vector = premium.BoostsList; - -myBoost#c448415c flags:# slot:int peer:flags.0?Peer date:int expires:int cooldown_until_date:flags.1?int = MyBoost; - -premium.myBoosts#9ae228e2 my_boosts:Vector chats:Vector users:Vector = premium.MyBoosts; - -premium.boostsStatus#4959427a flags:# my_boost:flags.2?true level:int current_level_boosts:int boosts:int gift_boosts:flags.4?int next_level_boosts:flags.0?int premium_audience:flags.1?StatsPercentValue boost_url:string prepaid_giveaways:flags.3?Vector my_boost_slots:flags.2?Vector = premium.BoostsStatus; - -storyFwdHeader#b826e150 flags:# modified:flags.3?true from:flags.0?Peer from_name:flags.1?string story_id:flags.2?int = StoryFwdHeader; - -postInteractionCountersMessage#e7058e7f msg_id:int views:int forwards:int reactions:int = PostInteractionCounters; - -postInteractionCountersStory#8a480e27 story_id:int views:int forwards:int reactions:int = PostInteractionCounters; - -stats.storyStats#50cd067c views_graph:StatsGraph reactions_by_emotion_graph:StatsGraph = stats.StoryStats; - -publicForwardMessage#1f2bf4a message:Message = PublicForward; - -publicForwardStory#edf3add0 peer:Peer story:StoryItem = PublicForward; - -stats.publicForwards#93037e20 flags:# count:int forwards:Vector next_offset:flags.0?string chats:Vector users:Vector = stats.PublicForwards; - -peerColor#b54b5acf flags:# color:flags.0?int background_emoji_id:flags.1?long = PeerColor; - -peerColorCollectible#b9c0639a flags:# collectible_id:long gift_emoji_id:long background_emoji_id:long accent_color:int colors:Vector dark_accent_color:flags.0?int dark_colors:flags.1?Vector = PeerColor; - -inputPeerColorCollectible#b8ea86a9 collectible_id:long = PeerColor; - -help.peerColorSet#26219a58 colors:Vector = help.PeerColorSet; - -help.peerColorProfileSet#767d61eb palette_colors:Vector bg_colors:Vector story_colors:Vector = help.PeerColorSet; - -help.peerColorOption#adec6ebe flags:# hidden:flags.0?true color_id:int colors:flags.1?help.PeerColorSet dark_colors:flags.2?help.PeerColorSet channel_min_level:flags.3?int group_min_level:flags.4?int = help.PeerColorOption; - -help.peerColorsNotModified#2ba1f5ce = help.PeerColors; - -help.peerColors#f8ed08 hash:int colors:Vector = help.PeerColors; - -storyReaction#6090d6d5 peer_id:Peer date:int reaction:Reaction = StoryReaction; - -storyReactionPublicForward#bbab2643 message:Message = StoryReaction; - -storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; - -stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; - -savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; - -monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; - -messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; - -messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; - -messages.savedDialogsNotModified#c01f6fe8 count:int = messages.SavedDialogs; - -savedReactionTag#cb6ff828 flags:# reaction:Reaction title:flags.0?string count:int = SavedReactionTag; - -messages.savedReactionTagsNotModified#889b59ef = messages.SavedReactionTags; - -messages.savedReactionTags#3259950a tags:Vector hash:long = messages.SavedReactionTags; - -outboxReadDate#3bb842ac date:int = OutboxReadDate; - -smsjobs.eligibleToJoin#dc8b44cf terms_url:string monthly_sent_sms:int = smsjobs.EligibilityToJoin; - -smsjobs.status#2aee9191 flags:# allow_international:flags.0?true recent_sent:int recent_since:int recent_remains:int total_sent:int total_since:int last_gift_slug:flags.1?string terms_url:string = smsjobs.Status; - -smsJob#e6a1eeb8 job_id:string phone_number:string text:string = SmsJob; - -businessWeeklyOpen#120b1ab9 start_minute:int end_minute:int = BusinessWeeklyOpen; - -businessWorkHours#8c92b098 flags:# open_now:flags.0?true timezone_id:string weekly_open:Vector = BusinessWorkHours; - -businessLocation#ac5c1af7 flags:# geo_point:flags.0?GeoPoint address:string = BusinessLocation; - -inputBusinessRecipients#6f8b32aa flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = InputBusinessRecipients; - -businessRecipients#21108ff7 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector = BusinessRecipients; - -businessAwayMessageScheduleAlways#c9b9e2b9 = BusinessAwayMessageSchedule; - -businessAwayMessageScheduleOutsideWorkHours#c3f2f501 = BusinessAwayMessageSchedule; - -businessAwayMessageScheduleCustom#cc4d9ecc start_date:int end_date:int = BusinessAwayMessageSchedule; - -inputBusinessGreetingMessage#194cb3b shortcut_id:int recipients:InputBusinessRecipients no_activity_days:int = InputBusinessGreetingMessage; - -businessGreetingMessage#e519abab shortcut_id:int recipients:BusinessRecipients no_activity_days:int = BusinessGreetingMessage; - -inputBusinessAwayMessage#832175e0 flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:InputBusinessRecipients = InputBusinessAwayMessage; - -businessAwayMessage#ef156a5c flags:# offline_only:flags.0?true shortcut_id:int schedule:BusinessAwayMessageSchedule recipients:BusinessRecipients = BusinessAwayMessage; - -timezone#ff9289f5 id:string name:string utc_offset:int = Timezone; - -help.timezonesListNotModified#970708cc = help.TimezonesList; - -help.timezonesList#7b74ed71 timezones:Vector hash:int = help.TimezonesList; - -quickReply#697102b shortcut_id:int shortcut:string top_message:int count:int = QuickReply; - -inputQuickReplyShortcut#24596d41 shortcut:string = InputQuickReplyShortcut; - -inputQuickReplyShortcutId#1190cf1 shortcut_id:int = InputQuickReplyShortcut; - -messages.quickReplies#c68d6695 quick_replies:Vector messages:Vector chats:Vector users:Vector = messages.QuickReplies; - -messages.quickRepliesNotModified#5f91eb5b = messages.QuickReplies; - -connectedBot#33ed001 flags:# bot_id:long recipients:BusinessBotRecipients rights:BusinessBotRights device:flags.0?string date:flags.1?int location:flags.2?string = ConnectedBot; - -account.connectedBots#17d7f87b connected_bots:Vector users:Vector = account.ConnectedBots; - -messages.dialogFilters#2ad93719 flags:# tags_enabled:flags.0?true filters:Vector = messages.DialogFilters; - -birthday#6c8e1e06 flags:# day:int month:int year:flags.0?int = Birthday; - -botBusinessConnection#8f34b2f5 flags:# disabled:flags.1?true connection_id:string user_id:long dc_id:int date:int rights:flags.2?BusinessBotRights = BotBusinessConnection; - -inputBusinessIntro#9c469cd flags:# title:string description:string sticker:flags.0?InputDocument = InputBusinessIntro; - -businessIntro#5a0a066d flags:# title:string description:string sticker:flags.0?Document = BusinessIntro; - -messages.myStickers#faff629d count:int sets:Vector = messages.MyStickers; - -inputCollectibleUsername#e39460a9 username:string = InputCollectible; - -inputCollectiblePhone#a2e214a4 phone:string = InputCollectible; - -fragment.collectibleInfo#6ebdff91 purchase_date:int currency:string amount:long crypto_currency:string crypto_amount:long url:string = fragment.CollectibleInfo; - -inputBusinessBotRecipients#c4e5921e flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = InputBusinessBotRecipients; - -businessBotRecipients#b88cf373 flags:# existing_chats:flags.0?true new_chats:flags.1?true contacts:flags.2?true non_contacts:flags.3?true exclude_selected:flags.5?true users:flags.4?Vector exclude_users:flags.6?Vector = BusinessBotRecipients; - -contactBirthday#1d998733 contact_id:long birthday:Birthday = ContactBirthday; - -contacts.contactBirthdays#114ff30d contacts:Vector users:Vector = contacts.ContactBirthdays; - -missingInvitee#628c9224 flags:# premium_would_allow_invite:flags.0?true premium_required_for_pm:flags.1?true user_id:long = MissingInvitee; - -messages.invitedUsers#7f5defa6 updates:Updates missing_invitees:Vector = messages.InvitedUsers; - -inputBusinessChatLink#11679fa7 flags:# message:string entities:flags.0?Vector title:flags.1?string = InputBusinessChatLink; - -businessChatLink#b4ae666f flags:# link:string message:string entities:flags.0?Vector title:flags.1?string views:int = BusinessChatLink; - -account.businessChatLinks#ec43a2d1 links:Vector chats:Vector users:Vector = account.BusinessChatLinks; - -account.resolvedBusinessChatLinks#9a23af21 flags:# peer:Peer message:string entities:flags.0?Vector chats:Vector users:Vector = account.ResolvedBusinessChatLinks; - -requestedPeerUser#d62ff46a flags:# user_id:long first_name:flags.0?string last_name:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; - -requestedPeerChat#7307544f flags:# chat_id:long title:flags.0?string photo:flags.2?Photo = RequestedPeer; - -requestedPeerChannel#8ba403e4 flags:# channel_id:long title:flags.0?string username:flags.1?string photo:flags.2?Photo = RequestedPeer; - -sponsoredMessageReportOption#430d3150 text:string option:bytes = SponsoredMessageReportOption; - -channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options:Vector = channels.SponsoredMessageReportResult; - -channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; - -channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; - -reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; - -reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; - -reactionsNotifySettings#71e4ea58 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom poll_votes_notify_from:flags.2?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; - -availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; - -messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; - -messages.availableEffects#bddb616e hash:int effects:Vector documents:Vector = messages.AvailableEffects; - -factCheck#b89bfccf flags:# need_check:flags.0?true country:flags.1?string text:flags.1?TextWithEntities hash:long = FactCheck; - -starsTransactionPeerUnsupported#95f2bfe4 = StarsTransactionPeer; - -starsTransactionPeerAppStore#b457b375 = StarsTransactionPeer; - -starsTransactionPeerPlayMarket#7b560a0b = StarsTransactionPeer; - -starsTransactionPeerPremiumBot#250dbaf8 = StarsTransactionPeer; - -starsTransactionPeerFragment#e92fd902 = StarsTransactionPeer; - -starsTransactionPeer#d80da15d peer:Peer = StarsTransactionPeer; - -starsTransactionPeerAds#60682812 = StarsTransactionPeer; - -starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; - -starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; - -starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true posts_search:flags.24?true stargift_prepaid_upgrade:flags.25?true stargift_drop_original_details:flags.26?true phonegroup_message:flags.27?true stargift_auction_bid:flags.28?true offer:flags.29?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction; - -payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; - -foundStory#e87acbc0 peer:Peer story:StoryItem = FoundStory; - -stories.foundStories#e2de7737 flags:# count:int stories:Vector next_offset:flags.0?string chats:Vector users:Vector = stories.FoundStories; - -geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:flags.1?string street:flags.2?string = GeoPointAddress; - -starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; - -payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; - -payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; - -payments.starsRevenueAdsAccountUrl#394e7f21 url:string = payments.StarsRevenueAdsAccountUrl; - -inputStarsTransaction#206ae6d1 flags:# refund:flags.0?true id:string = InputStarsTransaction; - -starsGiftOption#5e0589f1 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsGiftOption; - -bots.popularAppBots#1991b13b flags:# next_offset:flags.0?string users:Vector = bots.PopularAppBots; - -botPreviewMedia#23e91ba3 date:int media:MessageMedia = BotPreviewMedia; - -bots.previewInfo#ca71d64 media:Vector lang_codes:Vector = bots.PreviewInfo; - -starsSubscriptionPricing#5416d58 period:int amount:long = StarsSubscriptionPricing; - -starsSubscription#2e6eab1a flags:# canceled:flags.0?true can_refulfill:flags.1?true missing_balance:flags.2?true bot_canceled:flags.7?true id:string peer:Peer until_date:int pricing:StarsSubscriptionPricing chat_invite_hash:flags.3?string title:flags.4?string photo:flags.5?WebDocument invoice_slug:flags.6?string = StarsSubscription; - -messageReactor#4ba3a95a flags:# top:flags.0?true my:flags.1?true anonymous:flags.2?true peer_id:flags.3?Peer count:int = MessageReactor; - -starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true stars:long yearly_boosts:int store_product:flags.2?string currency:string amount:long winners:Vector = StarsGiveawayOption; - -starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption; - -starGift#313a9547 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true require_premium:flags.7?true limited_per_user:flags.8?true peer_color_available:flags.10?true auction:flags.11?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer per_user_total:flags.8?int per_user_remains:flags.8?int locked_until_date:flags.9?int auction_slug:flags.11?string gifts_per_round:flags.11?int auction_start_date:flags.11?int upgrade_variants:flags.12?int background:flags.13?StarGiftBackground = StarGift; - -starGiftUnique#85f0a9cd flags:# require_premium:flags.6?true resale_ton_only:flags.7?true theme_available:flags.9?true burned:flags.14?true crafted:flags.15?true id:long gift_id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector availability_issued:int availability_total:int gift_address:flags.3?string resell_amount:flags.4?Vector released_by:flags.5?Peer value_amount:flags.8?long value_currency:flags.8?string value_usd_amount:flags.8?long theme_peer:flags.10?Peer peer_color:flags.11?PeerColor host_id:flags.12?Peer offer_min_stars:flags.13?int craft_chance_permille:flags.16?int = StarGift; - -payments.starGiftsNotModified#a388a368 = payments.StarGifts; - -payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; - -messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; - -reportResultChooseOption#f0e4e0b6 title:string options:Vector = ReportResult; - -reportResultAddComment#6f09ac31 flags:# optional:flags.0?true option:bytes = ReportResult; - -reportResultReported#8db33c4b = ReportResult; - -messages.botPreparedInlineMessage#8ecf0511 id:string expire_date:int = messages.BotPreparedInlineMessage; - -messages.preparedInlineMessage#ff57708d query_id:long result:BotInlineResult peer_types:Vector cache_time:int users:Vector = messages.PreparedInlineMessage; - -botAppSettings#c99b1950 flags:# placeholder_path:flags.0?bytes background_color:flags.1?int background_dark_color:flags.2?int header_color:flags.3?int header_dark_color:flags.4?int = BotAppSettings; - -starRefProgram#dd0c66f2 flags:# bot_id:long commission_permille:int duration_months:flags.0?int end_date:flags.1?int daily_revenue_per_user:flags.2?StarsAmount = StarRefProgram; - -connectedBotStarRef#19a13f71 flags:# revoked:flags.1?true url:string date:int bot_id:long commission_permille:int duration_months:flags.0?int participants:long revenue:long = ConnectedBotStarRef; - -payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector = payments.ConnectedStarRefBots; - -payments.suggestedStarRefBots#b4d5d859 flags:# count:int suggested_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; - -starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount; - -starsTonAmount#74aee3e0 amount:long = StarsAmount; - -messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers; - -messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector = messages.FoundStickers; - -botVerifierSettings#b0cd6617 flags:# can_modify_custom_description:flags.1?true icon:long company:string custom_description:flags.0?string = BotVerifierSettings; - -botVerification#f93cd45c bot_id:long icon:long description:string = BotVerification; - -starGiftAttributeModel#565251e2 flags:# crafted:flags.0?true name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; - -starGiftAttributePattern#4e7085ea name:string document:Document rarity:StarGiftAttributeRarity = StarGiftAttribute; - -starGiftAttributeBackdrop#9f2504e4 name:string backdrop_id:int center_color:int edge_color:int pattern_color:int text_color:int rarity:StarGiftAttributeRarity = StarGiftAttribute; - -starGiftAttributeOriginalDetails#e0bff26c flags:# sender_id:flags.0?Peer recipient_id:Peer date:int message:flags.1?TextWithEntities = StarGiftAttribute; - -payments.starGiftUpgradePreview#3de1dfed sample_attributes:Vector prices:Vector next_prices:Vector = payments.StarGiftUpgradePreview; - -users.users#62d706b8 users:Vector = users.Users; - -users.usersSlice#315a4974 count:int users:Vector = users.Users; - -payments.uniqueStarGift#416c56e8 gift:StarGift chats:Vector users:Vector = payments.UniqueStarGift; - -messages.webPagePreview#8c9a88ac media:MessageMedia chats:Vector users:Vector = messages.WebPagePreview; - -savedStarGift#41df43fc flags:# name_hidden:flags.0?true unsaved:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true pinned_to_top:flags.12?true upgrade_separate:flags.17?true from_id:flags.1?Peer date:int gift:StarGift message:flags.2?TextWithEntities msg_id:flags.3?int saved_id:flags.11?long convert_stars:flags.4?long upgrade_stars:flags.6?long can_export_at:flags.7?int transfer_stars:flags.8?long can_transfer_at:flags.13?int can_resell_at:flags.14?int collection_id:flags.15?Vector prepaid_upgrade_hash:flags.16?string drop_original_details_stars:flags.18?long gift_num:flags.19?int can_craft_at:flags.20?int = SavedStarGift; - -payments.savedStarGifts#95f389b1 flags:# count:int chat_notifications_enabled:flags.1?Bool gifts:Vector next_offset:flags.0?string chats:Vector users:Vector = payments.SavedStarGifts; - -inputSavedStarGiftUser#69279795 msg_id:int = InputSavedStarGift; - -inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGift; - -inputSavedStarGiftSlug#2085c238 slug:string = InputSavedStarGift; - -payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl; - -paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy; - -paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy; - -paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy; - -account.paidMessagesRevenue#1e109708 stars_amount:long = account.PaidMessagesRevenue; - -requirementToContactEmpty#50a9839 = RequirementToContact; - -requirementToContactPremium#e581e4e9 = RequirementToContact; - -requirementToContactPaidMessages#b4f67e93 stars_amount:long = RequirementToContact; - -businessBotRights#a0624cf7 flags:# reply:flags.0?true read_messages:flags.1?true delete_sent_messages:flags.2?true delete_received_messages:flags.3?true edit_name:flags.4?true edit_bio:flags.5?true edit_profile_photo:flags.6?true edit_username:flags.7?true view_gifts:flags.8?true sell_gifts:flags.9?true change_gift_settings:flags.10?true transfer_and_upgrade_gifts:flags.11?true transfer_stars:flags.12?true manage_stories:flags.13?true = BusinessBotRights; - -disallowedGiftsSettings#71f276c4 flags:# disallow_unlimited_stargifts:flags.0?true disallow_limited_stargifts:flags.1?true disallow_unique_stargifts:flags.2?true disallow_premium_gifts:flags.3?true disallow_stargifts_from_channels:flags.4?true = DisallowedGiftsSettings; - -sponsoredPeer#c69708d3 flags:# random_id:bytes peer:Peer sponsor_info:flags.0?string additional_info:flags.1?string = SponsoredPeer; - -contacts.sponsoredPeersEmpty#ea32b4b1 = contacts.SponsoredPeers; - -contacts.sponsoredPeers#eb032884 peers:Vector chats:Vector users:Vector = contacts.SponsoredPeers; - -starGiftAttributeIdModel#48aaae3c document_id:long = StarGiftAttributeId; - -starGiftAttributeIdPattern#4a162433 document_id:long = StarGiftAttributeId; - -starGiftAttributeIdBackdrop#1f01c757 backdrop_id:int = StarGiftAttributeId; - -starGiftAttributeCounter#2eb1b658 attribute:StarGiftAttributeId count:int = StarGiftAttributeCounter; - -payments.resaleStarGifts#947a12df flags:# count:int gifts:Vector next_offset:flags.0?string attributes:flags.1?Vector attributes_hash:flags.1?long chats:Vector counters:flags.2?Vector users:Vector = payments.ResaleStarGifts; - -stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount; - -pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion; - -todoItem#cba9a52f id:int title:TextWithEntities = TodoItem; - -todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector = TodoList; - -todoCompletion#221bb5e4 id:int completed_by:Peer date:int = TodoCompletion; - -suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost; - -starsRating#1b0e4f07 flags:# level:int current_level_stars:long stars:long next_level_stars:flags.0?long = StarsRating; - -starGiftCollection#9d6b13b0 flags:# collection_id:int title:string icon:flags.0?Document gifts_count:int hash:long = StarGiftCollection; - -payments.starGiftCollectionsNotModified#a0ba4f17 = payments.StarGiftCollections; - -payments.starGiftCollections#8a2932f3 collections:Vector = payments.StarGiftCollections; - -storyAlbum#9325705a flags:# album_id:int title:string icon_photo:flags.0?Photo icon_video:flags.1?Document = StoryAlbum; - -stories.albumsNotModified#564edaeb = stories.Albums; - -stories.albums#c3987a3a hash:long albums:Vector = stories.Albums; - -searchPostsFlood#3e0b5b6a flags:# query_is_free:flags.0?true total_daily:int remains:int wait_till:flags.1?int stars_amount:long = SearchPostsFlood; - -payments.uniqueStarGiftValueInfo#512fe446 flags:# last_sale_on_fragment:flags.1?true value_is_average:flags.6?true currency:string value:long initial_sale_date:int initial_sale_stars:long initial_sale_price:long last_sale_date:flags.0?int last_sale_price:flags.0?long floor_price:flags.2?long average_price:flags.3?long listed_count:flags.4?int fragment_listed_count:flags.5?int fragment_listed_url:flags.5?string = payments.UniqueStarGiftValueInfo; - -profileTabPosts#b98cd696 = ProfileTab; - -profileTabGifts#4d4bd46a = ProfileTab; - -profileTabMedia#72c64955 = ProfileTab; - -profileTabFiles#ab339c00 = ProfileTab; - -profileTabMusic#9f27d26e = ProfileTab; - -profileTabVoice#e477092e = ProfileTab; - -profileTabLinks#d3656499 = ProfileTab; - -profileTabGifs#a2c0f695 = ProfileTab; - -users.savedMusicNotModified#e3878aa4 count:int = users.SavedMusic; - -users.savedMusic#34a2f297 count:int documents:Vector = users.SavedMusic; - -account.savedMusicIdsNotModified#4fc81d6e = account.SavedMusicIds; - -account.savedMusicIds#998d6636 ids:Vector = account.SavedMusicIds; - -payments.checkCanSendGiftResultOk#374fa7ad = payments.CheckCanSendGiftResult; - -payments.checkCanSendGiftResultFail#d5e58274 reason:TextWithEntities = payments.CheckCanSendGiftResult; - -inputChatThemeEmpty#83268483 = InputChatTheme; - -inputChatTheme#c93de95c emoticon:string = InputChatTheme; - -inputChatThemeUniqueGift#87e5dfe4 slug:string = InputChatTheme; - -starGiftUpgradePrice#99ea331d date:int upgrade_stars:long = StarGiftUpgradePrice; - -groupCallMessage#1a8afc7e flags:# from_admin:flags.1?true id:int from_id:Peer date:int message:TextWithEntities paid_message_stars:flags.0?long = GroupCallMessage; - -groupCallDonor#ee430c85 flags:# top:flags.0?true my:flags.1?true peer_id:flags.3?Peer stars:long = GroupCallDonor; - -phone.groupCallStars#9d1dbd26 total_stars:long top_donors:Vector chats:Vector users:Vector = phone.GroupCallStars; - -recentStory#711d692d flags:# live:flags.0?true max_id:flags.1?int = RecentStory; - -auctionBidLevel#310240cc pos:int amount:long date:int = AuctionBidLevel; - -starGiftAuctionStateNotModified#fe333952 = StarGiftAuctionState; - -starGiftAuctionState#771a4e66 version:int start_date:int end_date:int min_bid_amount:long bid_levels:Vector top_bidders:Vector next_round_at:int last_gift_num:int gifts_left:int current_round:int total_rounds:int rounds:Vector = StarGiftAuctionState; - -starGiftAuctionStateFinished#972dabbf flags:# start_date:int end_date:int average_price:long listed_count:flags.0?int fragment_listed_count:flags.1?int fragment_listed_url:flags.1?string = StarGiftAuctionState; - -starGiftAuctionUserState#2eeed1c4 flags:# returned:flags.1?true bid_amount:flags.0?long bid_date:flags.0?int min_bid_amount:flags.0?long bid_peer:flags.0?Peer acquired_count:int = StarGiftAuctionUserState; - -payments.starGiftAuctionState#6b39f4ec gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState timeout:int users:Vector chats:Vector = payments.StarGiftAuctionState; - -starGiftAuctionAcquiredGift#42b00348 flags:# name_hidden:flags.0?true peer:Peer date:int bid_amount:long round:int pos:int message:flags.1?TextWithEntities gift_num:flags.2?int = StarGiftAuctionAcquiredGift; - -payments.starGiftAuctionAcquiredGifts#7d5bd1f0 gifts:Vector users:Vector chats:Vector = payments.StarGiftAuctionAcquiredGifts; - -starGiftActiveAuctionState#d31bc45d gift:StarGift state:StarGiftAuctionState user_state:StarGiftAuctionUserState = StarGiftActiveAuctionState; - -payments.starGiftActiveAuctionsNotModified#db33dad0 = payments.StarGiftActiveAuctions; - -payments.starGiftActiveAuctions#aef6abbc auctions:Vector users:Vector chats:Vector = payments.StarGiftActiveAuctions; - -inputStarGiftAuction#2e16c98 gift_id:long = InputStarGiftAuction; - -inputStarGiftAuctionSlug#7ab58308 slug:string = InputStarGiftAuction; - -passkey#98613ebf flags:# id:string name:string date:int software_emoji_id:flags.0?long last_usage_date:flags.1?int = Passkey; - -account.passkeys#f8e0aa1c passkeys:Vector = account.Passkeys; - -account.passkeyRegistrationOptions#e16b5ce1 options:DataJSON = account.PasskeyRegistrationOptions; - -auth.passkeyLoginOptions#e2037789 options:DataJSON = auth.PasskeyLoginOptions; - -inputPasskeyResponseRegister#3e63935c client_data:DataJSON attestation_data:bytes = InputPasskeyResponse; - -inputPasskeyResponseLogin#c31fc14a client_data:DataJSON authenticator_data:bytes signature:bytes user_handle:string = InputPasskeyResponse; - -inputPasskeyCredentialPublicKey#3c27b78f id:string raw_id:string response:InputPasskeyResponse = InputPasskeyCredential; - -inputPasskeyCredentialFirebasePNV#5b1ccb28 pnv_token:string = InputPasskeyCredential; - -starGiftBackground#aff56398 center_color:int edge_color:int text_color:int = StarGiftBackground; - -starGiftAuctionRound#3aae0528 num:int duration:int = StarGiftAuctionRound; - -starGiftAuctionRoundExtendable#aa021e5 num:int duration:int extend_top:int extend_window:int = StarGiftAuctionRound; - -payments.starGiftUpgradeAttributes#46c6e36f attributes:Vector = payments.StarGiftUpgradeAttributes; - -messages.emojiGameOutcome#da2ad647 seed:bytes stake_ton_amount:long ton_amount:long = messages.EmojiGameOutcome; - -messages.emojiGameUnavailable#59e65335 = messages.EmojiGameInfo; - -messages.emojiGameDiceInfo#44e56023 flags:# game_hash:string prev_stake:long current_streak:int params:Vector plays_left:flags.0?int = messages.EmojiGameInfo; - -starGiftAttributeRarity#36437737 permille:int = StarGiftAttributeRarity; - -starGiftAttributeRarityUncommon#dbce6389 = StarGiftAttributeRarity; - -starGiftAttributeRarityRare#f08d516b = StarGiftAttributeRarity; - -starGiftAttributeRarityEpic#78fbf3a8 = StarGiftAttributeRarity; - -starGiftAttributeRarityLegendary#cef7e7a8 = StarGiftAttributeRarity; - -keyboardButtonStyle#4fdd3430 flags:# bg_primary:flags.0?true bg_danger:flags.1?true bg_success:flags.2?true icon:flags.3?long = KeyboardButtonStyle; - -inputMessageReadMetric#402b4495 msg_id:int view_id:long time_in_view_ms:int active_time_in_view_ms:int height_to_viewport_ratio_permille:int seen_range_ratio_permille:int = InputMessageReadMetric; - -bots.exportedBotToken#3c60b621 token:string = bots.ExportedBotToken; - -bots.requestedButton#f13bbcd7 webapp_req_id:string = bots.RequestedButton; - -messages.composedMessageWithAI#90d7adfa flags:# result_text:TextWithEntities diff_text:flags.0?TextWithEntities = messages.ComposedMessageWithAI; - -stats.pollStats#2999beed votes_graph:StatsGraph = stats.PollStats; - -inputAiComposeToneDefault#1fe9a9bf tone:string = InputAiComposeTone; - -inputAiComposeToneID#773c080 id:long access_hash:long = InputAiComposeTone; - -inputAiComposeToneSlug#1fa01357 slug:string = InputAiComposeTone; - -aiComposeTone#cff63ea9 flags:# creator:flags.0?true id:long access_hash:long slug:string title:string emoji_id:flags.1?long prompt:flags.4?string installs_count:flags.2?int author_id:flags.3?long example_english:flags.5?AiComposeToneExample = AiComposeTone; - -aiComposeToneDefault#9bad6414 tone:string emoji_id:long title:string = AiComposeTone; - -aicompose.tonesNotModified#c1f46103 = aicompose.Tones; - -aicompose.tones#6c9d0efe hash:long tones:Vector users:Vector = aicompose.Tones; - -aiComposeToneExample#f1d628ec from:TextWithEntities to:TextWithEntities = AiComposeToneExample; - -bots.accessSettings#dd1fbf93 flags:# restricted:flags.0?true add_users:flags.1?Vector = bots.AccessSettings; - -messages.chatInviteJoinResultOk#445663a7 updates:Updates = messages.ChatInviteJoinResult; - -messages.chatInviteJoinResultWebView#2f51c337 bot_id:long webview:WebViewResult users:Vector = messages.ChatInviteJoinResult; - -joinChatBotResultApproved#ae152a69 = JoinChatBotResult; - -joinChatBotResultDeclined#efa0194 = JoinChatBotResult; - -joinChatBotResultQueued#98a3a840 = JoinChatBotResult; - -joinChatBotResultWebView#d6e3b813 url:string = JoinChatBotResult; - -webDomainException#933ca597 flags:# domain:string url:string title:string favicon:flags.0?long = WebDomainException; - -account.webBrowserSettingsNotModified#c31c8f4e = account.WebBrowserSettings; - -account.webBrowserSettings#79eb8cb3 flags:# open_external_browser:flags.0?true display_close_button:flags.1?true external_exceptions:Vector inapp_exceptions:Vector hash:long = account.WebBrowserSettings; - -inputRichFilePhoto#9b00622b id:string photo:InputPhoto = InputRichFile; - -inputRichFileDocument#83281dbd id:string document:InputDocument = InputRichFile; - -inputRichMessage#e4c449fc flags:# rtl:flags.0?true noautolink:flags.1?true blocks:Vector photos:flags.2?Vector documents:flags.3?Vector users:flags.4?Vector = InputRichMessage; - -inputRichMessageHTML#dacb836a flags:# rtl:flags.0?true noautolink:flags.1?true html:string files:flags.2?Vector = InputRichMessage; - -inputRichMessageMarkdown#4b572c flags:# rtl:flags.0?true noautolink:flags.1?true markdown:string files:flags.2?Vector = InputRichMessage; - -richMessage#baf39d8b flags:# rtl:flags.0?true part:flags.1?true blocks:Vector photos:Vector documents:Vector = RichMessage; - - ----functions--- - -invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; - -invokeAfterMsgs#3dc4b4f0 {X:Type} msg_ids:Vector query:!X = X; - -initConnection#c1cd5ea9 {X:Type} flags:# api_id:int device_model:string system_version:string app_version:string system_lang_code:string lang_pack:string lang_code:string proxy:flags.0?InputClientProxy params:flags.1?JSONValue query:!X = X; - -invokeWithLayer#da9b0d0d {X:Type} layer:int query:!X = X; - -invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X; - -invokeWithMessagesRange#365275f2 {X:Type} range:MessageRange query:!X = X; - -invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X; - -invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X; - -invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X; - -invokeWithApnsSecret#dae54f8 {X:Type} nonce:string secret:string query:!X = X; - -invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X; - -auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode; - -auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; - -auth.signIn#8d52a951 flags:# phone_number:string phone_code_hash:string phone_code:flags.0?string email_verification:flags.1?EmailVerification = auth.Authorization; - -auth.logOut#3e72ba19 = auth.LoggedOut; - -auth.resetAuthorizations#9fab0d1a = Bool; - -auth.exportAuthorization#e5bfffcd dc_id:int = auth.ExportedAuthorization; - -auth.importAuthorization#a57a7dad id:long bytes:bytes = auth.Authorization; - -auth.bindTempAuthKey#cdd42a05 perm_auth_key_id:long nonce:long expires_at:int encrypted_message:bytes = Bool; - -auth.importBotAuthorization#67a3ff2c flags:int api_id:int api_hash:string bot_auth_token:string = auth.Authorization; - -auth.checkPassword#d18b4d16 password:InputCheckPasswordSRP = auth.Authorization; - -auth.requestPasswordRecovery#d897bc66 = auth.PasswordRecovery; - -auth.recoverPassword#37096c70 flags:# code:string new_settings:flags.0?account.PasswordInputSettings = auth.Authorization; - -auth.resendCode#cae47523 flags:# phone_number:string phone_code_hash:string reason:flags.0?string = auth.SentCode; - -auth.cancelCode#1f040578 phone_number:string phone_code_hash:string = Bool; - -auth.dropTempAuthKeys#8e48a188 except_auth_keys:Vector = Bool; - -auth.exportLoginToken#b7e085fe api_id:int api_hash:string except_ids:Vector = auth.LoginToken; - -auth.importLoginToken#95ac5ce4 token:bytes = auth.LoginToken; - -auth.acceptLoginToken#e894ad4d token:bytes = Authorization; - -auth.checkRecoveryPassword#d36bf79 code:string = Bool; - -auth.importWebTokenAuthorization#2db873a9 api_id:int api_hash:string web_auth_token:string = auth.Authorization; - -auth.requestFirebaseSms#8e39261e flags:# phone_number:string phone_code_hash:string safety_net_token:flags.0?string play_integrity_token:flags.2?string ios_push_secret:flags.1?string = Bool; - -auth.resetLoginEmail#7e960193 phone_number:string phone_code_hash:string = auth.SentCode; - -auth.reportMissingCode#cb9deff6 phone_number:string phone_code_hash:string mnc:string = Bool; - -auth.checkPaidAuth#56e59f9c phone_number:string phone_code_hash:string form_id:long = auth.SentCode; - -auth.initPasskeyLogin#518ad0b7 api_id:int api_hash:string = auth.PasskeyLoginOptions; - -auth.finishPasskeyLogin#9857ad07 flags:# credential:InputPasskeyCredential from_dc_id:flags.0?int from_auth_key_id:flags.0?long = auth.Authorization; - -account.registerDevice#ec86017a flags:# no_muted:flags.0?true token_type:int token:string app_sandbox:Bool secret:bytes other_uids:Vector = Bool; - -account.unregisterDevice#6a0d3206 token_type:int token:string other_uids:Vector = Bool; - -account.updateNotifySettings#84be5b93 peer:InputNotifyPeer settings:InputPeerNotifySettings = Bool; - -account.getNotifySettings#12b3ad31 peer:InputNotifyPeer = PeerNotifySettings; - -account.resetNotifySettings#db7e1747 = Bool; - -account.updateProfile#78515775 flags:# first_name:flags.0?string last_name:flags.1?string about:flags.2?string = User; - -account.updateStatus#6628562c offline:Bool = Bool; - -account.getWallPapers#7967d36 hash:long = account.WallPapers; - -account.reportPeer#c5ba3d86 peer:InputPeer reason:ReportReason message:string = Bool; - -account.checkUsername#2714d86c username:string = Bool; - -account.updateUsername#3e0bdd7c username:string = User; - -account.getPrivacy#dadbc950 key:InputPrivacyKey = account.PrivacyRules; - -account.setPrivacy#c9f81ce8 key:InputPrivacyKey rules:Vector = account.PrivacyRules; - -account.deleteAccount#a2c0cf74 flags:# reason:string password:flags.0?InputCheckPasswordSRP = Bool; - -account.getAccountTTL#8fc711d = AccountDaysTTL; - -account.setAccountTTL#2442485e ttl:AccountDaysTTL = Bool; - -account.sendChangePhoneCode#82574ae5 phone_number:string settings:CodeSettings = auth.SentCode; - -account.changePhone#70c32edb phone_number:string phone_code_hash:string phone_code:string = User; - -account.updateDeviceLocked#38df3532 period:int = Bool; - -account.getAuthorizations#e320c158 = account.Authorizations; - -account.resetAuthorization#df77f3bc hash:long = Bool; - -account.getPassword#548a30f5 = account.Password; - -account.getPasswordSettings#9cd4eaf9 password:InputCheckPasswordSRP = account.PasswordSettings; - -account.updatePasswordSettings#a59b102f password:InputCheckPasswordSRP new_settings:account.PasswordInputSettings = Bool; - -account.sendConfirmPhoneCode#1b3faa88 hash:string settings:CodeSettings = auth.SentCode; - -account.confirmPhone#5f2178c3 phone_code_hash:string phone_code:string = Bool; - -account.getTmpPassword#449e0b51 password:InputCheckPasswordSRP period:int = account.TmpPassword; - -account.getWebAuthorizations#182e6d6f = account.WebAuthorizations; - -account.resetWebAuthorization#2d01b9ef hash:long = Bool; - -account.resetWebAuthorizations#682d2594 = Bool; - -account.getAllSecureValues#b288bc7d = Vector; - -account.getSecureValue#73665bc2 types:Vector = Vector; - -account.saveSecureValue#899fe31d value:InputSecureValue secure_secret_id:long = SecureValue; - -account.deleteSecureValue#b880bc4b types:Vector = Bool; - -account.getAuthorizationForm#a929597a bot_id:long scope:string public_key:string = account.AuthorizationForm; - -account.acceptAuthorization#f3ed4c73 bot_id:long scope:string public_key:string value_hashes:Vector credentials:SecureCredentialsEncrypted = Bool; - -account.sendVerifyPhoneCode#a5a356f9 phone_number:string settings:CodeSettings = auth.SentCode; - -account.verifyPhone#4dd3a7f6 phone_number:string phone_code_hash:string phone_code:string = Bool; - -account.sendVerifyEmailCode#98e037bb purpose:EmailVerifyPurpose email:string = account.SentEmailCode; - -account.verifyEmail#32da4cf purpose:EmailVerifyPurpose verification:EmailVerification = account.EmailVerified; - -account.initTakeoutSession#8ef3eab0 flags:# contacts:flags.0?true message_users:flags.1?true message_chats:flags.2?true message_megagroups:flags.3?true message_channels:flags.4?true files:flags.5?true file_max_size:flags.5?long = account.Takeout; - -account.finishTakeoutSession#1d2652ee flags:# success:flags.0?true = Bool; - -account.confirmPasswordEmail#8fdf1920 code:string = Bool; - -account.resendPasswordEmail#7a7f2a15 = Bool; - -account.cancelPasswordEmail#c1cbd5b6 = Bool; - -account.getContactSignUpNotification#9f07c728 = Bool; - -account.setContactSignUpNotification#cff43f61 silent:Bool = Bool; - -account.getNotifyExceptions#53577479 flags:# compare_sound:flags.1?true compare_stories:flags.2?true peer:flags.0?InputNotifyPeer = Updates; - -account.getWallPaper#fc8ddbea wallpaper:InputWallPaper = WallPaper; - -account.uploadWallPaper#e39a8f03 flags:# for_chat:flags.0?true file:InputFile mime_type:string settings:WallPaperSettings = WallPaper; - -account.saveWallPaper#6c5a5b37 wallpaper:InputWallPaper unsave:Bool settings:WallPaperSettings = Bool; - -account.installWallPaper#feed5769 wallpaper:InputWallPaper settings:WallPaperSettings = Bool; - -account.resetWallPapers#bb3b9804 = Bool; - -account.getAutoDownloadSettings#56da0b3f = account.AutoDownloadSettings; - -account.saveAutoDownloadSettings#76f36233 flags:# low:flags.0?true high:flags.1?true settings:AutoDownloadSettings = Bool; - -account.uploadTheme#1c3db333 flags:# file:InputFile thumb:flags.0?InputFile file_name:string mime_type:string = Document; - -account.createTheme#652e4400 flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?Vector = Theme; - -account.updateTheme#2bf40ccc flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?Vector = Theme; - -account.saveTheme#f257106c theme:InputTheme unsave:Bool = Bool; - -account.installTheme#c727bb3b flags:# dark:flags.0?true theme:flags.1?InputTheme format:flags.2?string base_theme:flags.3?BaseTheme = Bool; - -account.getTheme#3a5869ec format:string theme:InputTheme = Theme; - -account.getThemes#7206e458 format:string hash:long = account.Themes; - -account.setContentSettings#b574b16b flags:# sensitive_enabled:flags.0?true = Bool; - -account.getContentSettings#8b9b4dae = account.ContentSettings; - -account.getMultiWallPapers#65ad71dc wallpapers:Vector = Vector; - -account.getGlobalPrivacySettings#eb2b4cf6 = GlobalPrivacySettings; - -account.setGlobalPrivacySettings#1edaaac2 settings:GlobalPrivacySettings = GlobalPrivacySettings; - -account.reportProfilePhoto#fa8cc6f5 peer:InputPeer photo_id:InputPhoto reason:ReportReason message:string = Bool; - -account.resetPassword#9308ce1b = account.ResetPasswordResult; - -account.declinePasswordReset#4c9409f6 = Bool; - -account.getChatThemes#d638de89 hash:long = account.Themes; - -account.setAuthorizationTTL#bf899aa0 authorization_ttl_days:int = Bool; - -account.changeAuthorizationSettings#40f48462 flags:# confirmed:flags.3?true hash:long encrypted_requests_disabled:flags.0?Bool call_requests_disabled:flags.1?Bool = Bool; - -account.getSavedRingtones#e1902288 hash:long = account.SavedRingtones; - -account.saveRingtone#3dea5b03 id:InputDocument unsave:Bool = account.SavedRingtone; - -account.uploadRingtone#831a83a2 file:InputFile file_name:string mime_type:string = Document; - -account.updateEmojiStatus#fbd3de6b emoji_status:EmojiStatus = Bool; - -account.getDefaultEmojiStatuses#d6753386 hash:long = account.EmojiStatuses; - -account.getRecentEmojiStatuses#f578105 hash:long = account.EmojiStatuses; - -account.clearRecentEmojiStatuses#18201aae = Bool; - -account.reorderUsernames#ef500eab order:Vector = Bool; - -account.toggleUsername#58d6b376 username:string active:Bool = Bool; - -account.getDefaultProfilePhotoEmojis#e2750328 hash:long = EmojiList; - -account.getDefaultGroupPhotoEmojis#915860ae hash:long = EmojiList; - -account.getAutoSaveSettings#adcbbcda = account.AutoSaveSettings; - -account.saveAutoSaveSettings#d69b8361 flags:# users:flags.0?true chats:flags.1?true broadcasts:flags.2?true peer:flags.3?InputPeer settings:AutoSaveSettings = Bool; - -account.deleteAutoSaveExceptions#53bc0020 = Bool; - -account.invalidateSignInCodes#ca8ae8ba codes:Vector = Bool; - -account.updateColor#684d214e flags:# for_profile:flags.1?true color:flags.2?PeerColor = Bool; - -account.getDefaultBackgroundEmojis#a60ab9ce hash:long = EmojiList; - -account.getChannelDefaultEmojiStatuses#7727a7d5 hash:long = account.EmojiStatuses; - -account.getChannelRestrictedStatusEmojis#35a9e0d5 hash:long = EmojiList; - -account.updateBusinessWorkHours#4b00e066 flags:# business_work_hours:flags.0?BusinessWorkHours = Bool; - -account.updateBusinessLocation#9e6b131a flags:# geo_point:flags.1?InputGeoPoint address:flags.0?string = Bool; - -account.updateBusinessGreetingMessage#66cdafc4 flags:# message:flags.0?InputBusinessGreetingMessage = Bool; - -account.updateBusinessAwayMessage#a26a7fa5 flags:# message:flags.0?InputBusinessAwayMessage = Bool; - -account.updateConnectedBot#66a08c7e flags:# deleted:flags.1?true rights:flags.0?BusinessBotRights bot:InputUser recipients:InputBusinessBotRecipients = Updates; - -account.getConnectedBots#4ea4c80f = account.ConnectedBots; - -account.getBotBusinessConnection#76a86270 connection_id:string = Updates; - -account.updateBusinessIntro#a614d034 flags:# intro:flags.0?InputBusinessIntro = Bool; - -account.toggleConnectedBotPaused#646e1097 peer:InputPeer paused:Bool = Bool; - -account.disablePeerConnectedBot#5e437ed9 peer:InputPeer = Bool; - -account.updateBirthday#cc6e0c11 flags:# birthday:flags.0?Birthday = Bool; - -account.createBusinessChatLink#8851e68e link:InputBusinessChatLink = BusinessChatLink; - -account.editBusinessChatLink#8c3410af slug:string link:InputBusinessChatLink = BusinessChatLink; - -account.deleteBusinessChatLink#60073674 slug:string = Bool; - -account.getBusinessChatLinks#6f70dde1 = account.BusinessChatLinks; - -account.resolveBusinessChatLink#5492e5ee slug:string = account.ResolvedBusinessChatLinks; - -account.updatePersonalChannel#d94305e0 channel:InputChannel = Bool; - -account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool; - -account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings; - -account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings; - -account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses; - -account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue; - -account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool; - -account.setMainProfileTab#5dee78b0 tab:ProfileTab = Bool; - -account.saveMusic#b26732a9 flags:# unsave:flags.0?true id:InputDocument after_id:flags.1?InputDocument = Bool; - -account.getSavedMusicIds#e09d5faf hash:long = account.SavedMusicIds; - -account.getUniqueGiftChatThemes#e42ce9c9 offset:string limit:int hash:long = account.ChatThemes; - -account.initPasskeyRegistration#429547e8 = account.PasskeyRegistrationOptions; - -account.registerPasskey#55b41fd6 credential:InputPasskeyCredential = Passkey; - -account.getPasskeys#ea1f0c52 = account.Passkeys; - -account.deletePasskey#f5b5563f id:string = Bool; - -account.confirmBotConnection#67ed1f68 bot_id:InputUser = Bool; - -account.getWebBrowserSettings#56655768 hash:long = account.WebBrowserSettings; - -account.updateWebBrowserSettings#9adf82fe flags:# open_external_browser:flags.0?true display_close_button:flags.1?true = account.WebBrowserSettings; - -account.toggleWebBrowserSettingsException#60ed4229 flags:# delete:flags.1?true open_external_browser:flags.0?Bool url:string = Updates; - -account.deleteWebBrowserSettingsExceptions#86a0765d = account.WebBrowserSettings; - -users.getUsers#d91a548 id:Vector = Vector; - -users.getFullUser#b60f5918 id:InputUser = users.UserFull; - -users.setSecureValueErrors#90c894b5 id:InputUser errors:Vector = Bool; - -users.getRequirementsToContact#d89a83a3 id:Vector = Vector; - -users.getSavedMusic#788d7fe3 id:InputUser offset:int limit:int hash:long = users.SavedMusic; - -users.getSavedMusicByID#7573a4e9 id:InputUser documents:Vector = users.SavedMusic; - -users.suggestBirthday#fc533372 id:InputUser birthday:Birthday = Updates; - -contacts.getContactIDs#7adc669d hash:long = Vector; - -contacts.getStatuses#c4a353ee = Vector; - -contacts.getContacts#5dd69e12 hash:long = contacts.Contacts; - -contacts.importContacts#2c800be5 contacts:Vector = contacts.ImportedContacts; - -contacts.deleteContacts#96a0e00 id:Vector = Updates; - -contacts.deleteByPhones#1013fd9e phones:Vector = Bool; - -contacts.block#2e2e8734 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; - -contacts.unblock#b550d328 flags:# my_stories_from:flags.0?true id:InputPeer = Bool; - -contacts.getBlocked#9a868f80 flags:# my_stories_from:flags.0?true offset:int limit:int = contacts.Blocked; - -contacts.search#5f58d0f flags:# broadcasts:flags.0?true bots:flags.1?true q:string limit:int = contacts.Found; - -contacts.resolveUsername#725afbbc flags:# username:string referer:flags.0?string = contacts.ResolvedPeer; - -contacts.getTopPeers#973478b6 flags:# correspondents:flags.0?true bots_pm:flags.1?true bots_inline:flags.2?true phone_calls:flags.3?true forward_users:flags.4?true forward_chats:flags.5?true groups:flags.10?true channels:flags.15?true bots_app:flags.16?true bots_guestchat:flags.17?true offset:int limit:int hash:long = contacts.TopPeers; - -contacts.resetTopPeerRating#1ae373ac category:TopPeerCategory peer:InputPeer = Bool; - -contacts.resetSaved#879537f1 = Bool; - -contacts.getSaved#82f1e39f = Vector; - -contacts.toggleTopPeers#8514bdda enabled:Bool = Bool; - -contacts.addContact#d9ba2e54 flags:# add_phone_privacy_exception:flags.0?true id:InputUser first_name:string last_name:string phone:string note:flags.1?TextWithEntities = Updates; - -contacts.acceptContact#f831a20f id:InputUser = Updates; - -contacts.getLocated#d348bc44 flags:# background:flags.1?true geo_point:InputGeoPoint self_expires:flags.0?int = Updates; - -contacts.blockFromReplies#29a8962c flags:# delete_message:flags.0?true delete_history:flags.1?true report_spam:flags.2?true msg_id:int = Updates; - -contacts.resolvePhone#8af94344 phone:string = contacts.ResolvedPeer; - -contacts.exportContactToken#f8654027 = ExportedContactToken; - -contacts.importContactToken#13005788 token:string = User; - -contacts.editCloseFriends#ba6705f0 id:Vector = Bool; - -contacts.setBlocked#94c65c76 flags:# my_stories_from:flags.0?true id:Vector limit:int = Bool; - -contacts.getBirthdays#daeda864 = contacts.ContactBirthdays; - -contacts.getSponsoredPeers#b6c8c393 q:string = contacts.SponsoredPeers; - -contacts.updateContactNote#139f63fb id:InputUser note:TextWithEntities = Bool; - -messages.getMessages#63c66506 id:Vector = messages.Messages; - -messages.getDialogs#a0f4cb4f flags:# exclude_pinned:flags.0?true folder_id:flags.1?int offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.Dialogs; - -messages.getHistory#4423e6c5 peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; - -messages.search#29ee847a flags:# peer:InputPeer q:string from_id:flags.0?InputPeer saved_peer_id:flags.2?InputPeer saved_reaction:flags.3?Vector top_msg_id:flags.1?int filter:MessagesFilter min_date:int max_date:int offset_id:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; - -messages.readHistory#e306d3a peer:InputPeer max_id:int = messages.AffectedMessages; - -messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?true peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; - -messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; - -messages.receivedMessages#5a954c0 max_id:int = Vector; - -messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; - -messages.sendMessage#fef48f62 flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost rich_message:flags.23?InputRichMessage = Updates; - -messages.sendMedia#330e77f flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; - -messages.forwardMessages#13704a7c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int schedule_repeat_period:flags.24?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; - -messages.reportSpam#cf1592db peer:InputPeer = Bool; - -messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; - -messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; - -messages.getChats#49e9528f id:Vector = messages.Chats; - -messages.getFullChat#aeb00b34 chat_id:long = messages.ChatFull; - -messages.editChatTitle#73783ffd chat_id:long title:string = Updates; - -messages.editChatPhoto#35ddd674 chat_id:long photo:InputChatPhoto = Updates; - -messages.addChatUser#cbc6d107 chat_id:long user_id:InputUser fwd_limit:int = messages.InvitedUsers; - -messages.deleteChatUser#a2185cab flags:# revoke_history:flags.0?true chat_id:long user_id:InputUser = Updates; - -messages.createChat#92ceddd4 flags:# users:Vector title:string ttl_period:flags.0?int = messages.InvitedUsers; - -messages.getDhConfig#26cf8950 version:int random_length:int = messages.DhConfig; - -messages.requestEncryption#f64daf43 user_id:InputUser random_id:int g_a:bytes = EncryptedChat; - -messages.acceptEncryption#3dbc0415 peer:InputEncryptedChat g_b:bytes key_fingerprint:long = EncryptedChat; - -messages.discardEncryption#f393aea0 flags:# delete_history:flags.0?true chat_id:int = Bool; - -messages.setEncryptedTyping#791451ed peer:InputEncryptedChat typing:Bool = Bool; - -messages.readEncryptedHistory#7f4b690a peer:InputEncryptedChat max_date:int = Bool; - -messages.sendEncrypted#44fa7a15 flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; - -messages.sendEncryptedFile#5559481d flags:# silent:flags.0?true peer:InputEncryptedChat random_id:long data:bytes file:InputEncryptedFile = messages.SentEncryptedMessage; - -messages.sendEncryptedService#32d439a4 peer:InputEncryptedChat random_id:long data:bytes = messages.SentEncryptedMessage; - -messages.receivedQueue#55a5bb66 max_qts:int = Vector; - -messages.reportEncryptedSpam#4b0c8c0f peer:InputEncryptedChat = Bool; - -messages.readMessageContents#36a73f77 id:Vector = messages.AffectedMessages; - -messages.getStickers#d5a5d3a1 emoticon:string hash:long = messages.Stickers; - -messages.getAllStickers#b8a0a1a8 hash:long = messages.AllStickers; - -messages.getWebPagePreview#570d6f6f flags:# message:string entities:flags.3?Vector = messages.WebPagePreview; - -messages.exportChatInvite#a455de90 flags:# legacy_revoke_permanent:flags.2?true request_needed:flags.3?true peer:InputPeer expire_date:flags.0?int usage_limit:flags.1?int title:flags.4?string subscription_pricing:flags.5?StarsSubscriptionPricing = ExportedChatInvite; - -messages.checkChatInvite#3eadb1bb hash:string = ChatInvite; - -messages.importChatInvite#de91436e hash:string = messages.ChatInviteJoinResult; - -messages.getStickerSet#c8a0ec74 stickerset:InputStickerSet hash:int = messages.StickerSet; - -messages.installStickerSet#c78fe460 stickerset:InputStickerSet archived:Bool = messages.StickerSetInstallResult; - -messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool; - -messages.startBot#e6df7378 bot:InputUser peer:InputPeer random_id:long start_param:string = Updates; - -messages.getMessagesViews#5784d3e1 peer:InputPeer id:Vector increment:Bool = messages.MessageViews; - -messages.editChatAdmin#a85bd1c2 chat_id:long user_id:InputUser is_admin:Bool = Bool; - -messages.migrateChat#a2875319 chat_id:long = Updates; - -messages.searchGlobal#4bc6589a flags:# broadcasts_only:flags.1?true groups_only:flags.2?true users_only:flags.3?true folder_id:flags.0?int q:string filter:MessagesFilter min_date:int max_date:int offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; - -messages.reorderStickerSets#78337739 flags:# masks:flags.0?true emojis:flags.1?true order:Vector = Bool; - -messages.getDocumentByHash#b1f2061f sha256:bytes size:long mime_type:string = Document; - -messages.getSavedGifs#5cf09635 hash:long = messages.SavedGifs; - -messages.saveGif#327a30cb id:InputDocument unsave:Bool = Bool; - -messages.getInlineBotResults#514e999d flags:# bot:InputUser peer:InputPeer geo_point:flags.0?InputGeoPoint query:string offset:string = messages.BotResults; - -messages.setInlineBotResults#bb12a419 flags:# gallery:flags.0?true private:flags.1?true query_id:long results:Vector cache_time:int next_offset:flags.2?string switch_pm:flags.3?InlineBotSwitchPM switch_webview:flags.4?InlineBotWebView = Bool; - -messages.sendInlineBotResult#c0cf7646 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true hide_via:flags.11?true peer:InputPeer reply_to:flags.0?InputReplyTo random_id:long query_id:long id:string schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut allow_paid_stars:flags.21?long = Updates; - -messages.getMessageEditData#fda68d36 peer:InputPeer id:int = messages.MessageEditData; - -messages.editMessage#b106e66c flags:# no_webpage:flags.1?true invert_media:flags.16?true peer:InputPeer id:int message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.15?int schedule_repeat_period:flags.18?int quick_reply_shortcut_id:flags.17?int rich_message:flags.23?InputRichMessage = Updates; - -messages.editInlineBotMessage#a423bb51 flags:# no_webpage:flags.1?true invert_media:flags.16?true id:InputBotInlineMessageID message:flags.11?string media:flags.14?InputMedia reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector rich_message:flags.23?InputRichMessage = Bool; - -messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; - -messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; - -messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; - -messages.saveDraft#ad0fa15c flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost rich_message:flags.9?InputRichMessage = Bool; - -messages.getAllDrafts#6a3f8d65 = Updates; - -messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; - -messages.readFeaturedStickers#5b118126 id:Vector = Bool; - -messages.getRecentStickers#9da9403b flags:# attached:flags.0?true hash:long = messages.RecentStickers; - -messages.saveRecentSticker#392718f8 flags:# attached:flags.0?true id:InputDocument unsave:Bool = Bool; - -messages.clearRecentStickers#8999602d flags:# attached:flags.0?true = Bool; - -messages.getArchivedStickers#57f17692 flags:# masks:flags.0?true emojis:flags.1?true offset_id:long limit:int = messages.ArchivedStickers; - -messages.getMaskStickers#640f82b8 hash:long = messages.AllStickers; - -messages.getAttachedStickers#cc5b67cc media:InputStickeredMedia = Vector; - -messages.setGameScore#8ef8ecc0 flags:# edit_message:flags.0?true force:flags.1?true peer:InputPeer id:int user_id:InputUser score:int = Updates; - -messages.setInlineGameScore#15ad9f64 flags:# edit_message:flags.0?true force:flags.1?true id:InputBotInlineMessageID user_id:InputUser score:int = Bool; - -messages.getGameHighScores#e822649d peer:InputPeer id:int user_id:InputUser = messages.HighScores; - -messages.getInlineGameHighScores#f635e1b id:InputBotInlineMessageID user_id:InputUser = messages.HighScores; - -messages.getCommonChats#e40ca104 user_id:InputUser max_id:long limit:int = messages.Chats; - -messages.getWebPage#8d9692a3 url:string hash:int = messages.WebPage; - -messages.toggleDialogPin#a731e257 flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; - -messages.reorderPinnedDialogs#3b1adf37 flags:# force:flags.0?true folder_id:int order:Vector = Bool; - -messages.getPinnedDialogs#d6b94df2 folder_id:int = messages.PeerDialogs; - -messages.setBotShippingResults#e5f672fa flags:# query_id:long error:flags.0?string shipping_options:flags.1?Vector = Bool; - -messages.setBotPrecheckoutResults#9c2dd95 flags:# success:flags.1?true query_id:long error:flags.0?string = Bool; - -messages.uploadMedia#14967978 flags:# business_connection_id:flags.0?string peer:InputPeer media:InputMedia = MessageMedia; - -messages.sendScreenshotNotification#a1405817 peer:InputPeer reply_to:InputReplyTo random_id:long = Updates; - -messages.getFavedStickers#4f1aaa9 hash:long = messages.FavedStickers; - -messages.faveSticker#b9ffc55b id:InputDocument unfave:Bool = Bool; - -messages.getUnreadMentions#f107e790 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; - -messages.readMentions#36e5bf4d flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; - -messages.getRecentLocations#702a40e0 peer:InputPeer limit:int hash:long = messages.Messages; - -messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo multi_media:Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; - -messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; - -messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; - -messages.getSplitRanges#1cff7e08 = Vector; - -messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool; - -messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector; - -messages.clearAllDrafts#7e58ee9c = Bool; - -messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates; - -messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; - -messages.getPollResults#eda3e33b peer:InputPeer msg_id:int poll_hash:long = Updates; - -messages.getOnlines#6e2be050 peer:InputPeer = ChatOnlines; - -messages.editChatAbout#def60797 peer:InputPeer about:string = Bool; - -messages.editChatDefaultBannedRights#a5866b41 peer:InputPeer banned_rights:ChatBannedRights = Updates; - -messages.getEmojiKeywords#35a0e062 lang_code:string = EmojiKeywordsDifference; - -messages.getEmojiKeywordsDifference#1508b6af lang_code:string from_version:int = EmojiKeywordsDifference; - -messages.getEmojiKeywordsLanguages#4e9963b2 lang_codes:Vector = Vector; - -messages.getEmojiURL#d5b10c26 lang_code:string = EmojiURL; - -messages.getSearchCounters#1bbcf300 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer top_msg_id:flags.0?int filters:Vector = Vector; - -messages.requestUrlAuth#894cc99c flags:# peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string in_app_origin:flags.3?string = UrlAuthResult; - -messages.acceptUrlAuth#67a3f0de flags:# write_allowed:flags.0?true share_phone_number:flags.3?true peer:flags.1?InputPeer msg_id:flags.1?int button_id:flags.1?int url:flags.2?string match_code:flags.4?string = UrlAuthResult; - -messages.hidePeerSettingsBar#4facb138 peer:InputPeer = Bool; - -messages.getScheduledHistory#f516760b peer:InputPeer hash:long = messages.Messages; - -messages.getScheduledMessages#bdbb0464 peer:InputPeer id:Vector = messages.Messages; - -messages.sendScheduledMessages#bd38850a peer:InputPeer id:Vector = Updates; - -messages.deleteScheduledMessages#59ae2b16 peer:InputPeer id:Vector = Updates; - -messages.getPollVotes#b86e380e flags:# peer:InputPeer id:int option:flags.0?bytes offset:flags.1?string limit:int = messages.VotesList; - -messages.toggleStickerSets#b5052fea flags:# uninstall:flags.0?true archive:flags.1?true unarchive:flags.2?true stickersets:Vector = Bool; - -messages.getDialogFilters#efd48c89 = messages.DialogFilters; - -messages.getSuggestedDialogFilters#a29cd42c = Vector; - -messages.updateDialogFilter#1ad4a04a flags:# id:int filter:flags.0?DialogFilter = Bool; - -messages.updateDialogFiltersOrder#c563c1e4 order:Vector = Bool; - -messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messages.FeaturedStickers; - -messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; - -messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; - -messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; - -messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; - -messages.deleteChat#5bd0ee50 chat_id:long = Bool; - -messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; - -messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; - -messages.initHistoryImport#34090c3b peer:InputPeer file:InputFile media_count:int = messages.HistoryImport; - -messages.uploadImportedMedia#2a862092 peer:InputPeer import_id:long file_name:string media:InputMedia = MessageMedia; - -messages.startHistoryImport#b43df344 peer:InputPeer import_id:long = Bool; - -messages.getExportedChatInvites#a2b5a3f6 flags:# revoked:flags.3?true peer:InputPeer admin_id:InputUser offset_date:flags.2?int offset_link:flags.2?string limit:int = messages.ExportedChatInvites; - -messages.getExportedChatInvite#73746f5c peer:InputPeer link:string = messages.ExportedChatInvite; - -messages.editExportedChatInvite#bdca2f75 flags:# revoked:flags.2?true peer:InputPeer link:string expire_date:flags.0?int usage_limit:flags.1?int request_needed:flags.3?Bool title:flags.4?string = messages.ExportedChatInvite; - -messages.deleteRevokedExportedChatInvites#56987bd5 peer:InputPeer admin_id:InputUser = Bool; - -messages.deleteExportedChatInvite#d464a42b peer:InputPeer link:string = Bool; - -messages.getAdminsWithInvites#3920e6ef peer:InputPeer = messages.ChatAdminsWithInvites; - -messages.getChatInviteImporters#df04dd4e flags:# requested:flags.0?true subscription_expired:flags.3?true peer:InputPeer link:flags.1?string q:flags.2?string offset_date:int offset_user:InputUser limit:int = messages.ChatInviteImporters; - -messages.setHistoryTTL#b80e5fe4 peer:InputPeer period:int = Updates; - -messages.checkHistoryImportPeer#5dc60f03 peer:InputPeer = messages.CheckedHistoryImportPeer; - -messages.setChatTheme#81202c9 peer:InputPeer theme:InputChatTheme = Updates; - -messages.getMessageReadParticipants#31c1c44f peer:InputPeer msg_id:int = Vector; - -messages.getSearchResultsCalendar#6aa3f6bd flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int offset_date:int = messages.SearchResultsCalendar; - -messages.getSearchResultsPositions#9c7f2f10 flags:# peer:InputPeer saved_peer_id:flags.2?InputPeer filter:MessagesFilter offset_id:int limit:int = messages.SearchResultsPositions; - -messages.hideChatJoinRequest#7fe7e815 flags:# approved:flags.0?true peer:InputPeer user_id:InputUser = Updates; - -messages.hideAllChatJoinRequests#e085f4ea flags:# approved:flags.0?true peer:InputPeer link:flags.1?string = Updates; - -messages.toggleNoForwards#b2081a35 flags:# peer:InputPeer enabled:Bool request_msg_id:flags.0?int = Updates; - -messages.saveDefaultSendAs#ccfddf96 peer:InputPeer send_as:InputPeer = Bool; - -messages.sendReaction#d30d78d4 flags:# big:flags.1?true add_to_recent:flags.2?true peer:InputPeer msg_id:int reaction:flags.0?Vector = Updates; - -messages.getMessagesReactions#8bba90e6 peer:InputPeer id:Vector = Updates; - -messages.getMessageReactionsList#461b3f48 flags:# peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = messages.MessageReactionsList; - -messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_reactions:ChatReactions reactions_limit:flags.0?int paid_enabled:flags.1?Bool = Updates; - -messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; - -messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool; - -messages.translateText#a5eec345 flags:# peer:flags.0?InputPeer id:flags.0?Vector text:flags.1?Vector to_lang:string tone:flags.2?string = messages.TranslatedText; - -messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; - -messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; - -messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages; - -messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; - -messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; - -messages.toggleBotInAttachMenu#69f59d69 flags:# write_allowed:flags.0?true bot:InputUser enabled:Bool = Bool; - -messages.requestWebView#269dc2c1 flags:# from_bot_menu:flags.4?true silent:flags.5?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser url:flags.1?string start_param:flags.3?string theme_params:flags.2?DataJSON platform:string reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = WebViewResult; - -messages.prolongWebView#b0d81a83 flags:# silent:flags.5?true peer:InputPeer bot:InputUser query_id:long reply_to:flags.0?InputReplyTo send_as:flags.13?InputPeer = Bool; - -messages.requestSimpleWebView#413a3e73 flags:# from_switch_webview:flags.1?true from_side_menu:flags.2?true compact:flags.7?true fullscreen:flags.8?true bot:InputUser url:flags.3?string start_param:flags.4?string theme_params:flags.0?DataJSON platform:string = WebViewResult; - -messages.sendWebViewResultMessage#a4314f5 bot_query_id:string result:InputBotInlineResult = WebViewMessageSent; - -messages.sendWebViewData#dc0242c8 bot:InputUser random_id:long button_text:string data:string = Updates; - -messages.transcribeAudio#269e9a49 peer:InputPeer msg_id:int = messages.TranscribedAudio; - -messages.rateTranscribedAudio#7f1d072f peer:InputPeer msg_id:int transcription_id:long good:Bool = Bool; - -messages.getCustomEmojiDocuments#d9ab0f54 document_id:Vector = Vector; - -messages.getEmojiStickers#fbfca18f hash:long = messages.AllStickers; - -messages.getFeaturedEmojiStickers#ecf6736 hash:long = messages.FeaturedStickers; - -messages.reportReaction#3f64c076 peer:InputPeer id:int reaction_peer:InputPeer = Bool; - -messages.getTopReactions#bb8125ba limit:int hash:long = messages.Reactions; - -messages.getRecentReactions#39461db2 limit:int hash:long = messages.Reactions; - -messages.clearRecentReactions#9dfeefb4 = Bool; - -messages.getExtendedMedia#84f80814 peer:InputPeer id:Vector = Updates; - -messages.setDefaultHistoryTTL#9eb51445 period:int = Bool; - -messages.getDefaultHistoryTTL#658b7188 = DefaultHistoryTTL; - -messages.sendBotRequestedPeer#6c5cf2a7 flags:# peer:InputPeer msg_id:flags.0?int webapp_req_id:flags.1?string button_id:int requested_peers:Vector = Updates; - -messages.getEmojiGroups#7488ce5b hash:int = messages.EmojiGroups; - -messages.getEmojiStatusGroups#2ecd56cd hash:int = messages.EmojiGroups; - -messages.getEmojiProfilePhotoGroups#21a548f3 hash:int = messages.EmojiGroups; - -messages.searchCustomEmoji#2c11c0d7 emoticon:string hash:long = EmojiList; - -messages.togglePeerTranslations#e47cb579 flags:# disabled:flags.0?true peer:InputPeer = Bool; - -messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; - -messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; - -messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; - -messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; - -messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; - -messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; - -messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; - -messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; - -messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; - -messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; - -messages.getSavedReactionTags#3637e05b flags:# peer:flags.0?InputPeer hash:long = messages.SavedReactionTags; - -messages.updateSavedReactionTag#60297dec flags:# reaction:Reaction title:flags.0?string = Bool; - -messages.getDefaultTagReactions#bdf93428 hash:long = messages.Reactions; - -messages.getOutboxReadDate#8c4bfe5d peer:InputPeer msg_id:int = OutboxReadDate; - -messages.getQuickReplies#d483f2a8 hash:long = messages.QuickReplies; - -messages.reorderQuickReplies#60331907 order:Vector = Bool; - -messages.checkQuickReplyShortcut#f1d0fbd3 shortcut:string = Bool; - -messages.editQuickReplyShortcut#5c003cef shortcut_id:int shortcut:string = Bool; - -messages.deleteQuickReplyShortcut#3cc04740 shortcut_id:int = Bool; - -messages.getQuickReplyMessages#94a495c3 flags:# shortcut_id:int id:flags.0?Vector hash:long = messages.Messages; - -messages.sendQuickReplyMessages#6c750de1 peer:InputPeer shortcut_id:int id:Vector random_id:Vector = Updates; - -messages.deleteQuickReplyMessages#e105e910 shortcut_id:int id:Vector = Updates; - -messages.toggleDialogFilterTags#fd2dda49 enabled:Bool = Bool; - -messages.getMyStickers#d0b5e1fc offset_id:long limit:int = messages.MyStickers; - -messages.getEmojiStickerGroups#1dd840f5 hash:int = messages.EmojiGroups; - -messages.getAvailableEffects#dea20a39 hash:int = messages.AvailableEffects; - -messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities = Updates; - -messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates; - -messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector = Vector; - -messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult; - -messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates; - -messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool; - -messages.getPaidReactionPrivacy#472455aa = Updates; - -messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; - -messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; - -messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; - -messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages; - -messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; - -messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; - -messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; - -messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; - -messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; - -messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; - -messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; - -messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; - -messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates; - -messages.getForumTopics#3ba47bff flags:# peer:InputPeer q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; - -messages.getForumTopicsByID#af0a4a08 peer:InputPeer topics:Vector = messages.ForumTopics; - -messages.editForumTopic#cecc1134 flags:# peer:InputPeer topic_id:int title:flags.0?string icon_emoji_id:flags.1?long closed:flags.2?Bool hidden:flags.3?Bool = Updates; - -messages.updatePinnedForumTopic#175df251 peer:InputPeer topic_id:int pinned:Bool = Updates; - -messages.reorderPinnedForumTopics#e7841f0 flags:# force:flags.0?true peer:InputPeer order:Vector = Updates; - -messages.createForumTopic#2f98c3d5 flags:# title_missing:flags.4?true peer:InputPeer title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; - -messages.deleteTopicHistory#d2816f10 peer:InputPeer top_msg_id:int = messages.AffectedHistory; - -messages.getEmojiGameInfo#fb7e8ca7 = messages.EmojiGameInfo; - -messages.summarizeText#abbbd346 flags:# peer:InputPeer id:int to_lang:flags.0?string tone:flags.2?string = TextWithEntities; - -messages.editChatCreator#f743b857 peer:InputPeer user_id:InputUser password:InputCheckPasswordSRP = Updates; - -messages.getFutureChatCreatorAfterLeave#3b7d0ea6 peer:InputPeer = User; - -messages.editChatParticipantRank#a00f32b0 peer:InputPeer participant:InputPeer rank:string = Updates; - -messages.declineUrlAuth#35436bbc url:string = Bool; - -messages.checkUrlAuthMatchCode#c9a47b0b url:string match_code:string = Bool; - -messages.composeMessageWithAI#daecc589 flags:# proofread:flags.0?true emojify:flags.3?true text:TextWithEntities translate_to_lang:flags.1?string tone:flags.2?InputAiComposeTone = messages.ComposedMessageWithAI; - -messages.reportReadMetrics#4067c5e6 peer:InputPeer metrics:Vector = Bool; - -messages.reportMusicListen#ddbcd819 id:InputDocument listened_duration:int = Bool; - -messages.addPollAnswer#19bc4b6d peer:InputPeer msg_id:int answer:PollAnswer = Updates; - -messages.deletePollAnswer#ac8505a5 peer:InputPeer msg_id:int option:bytes = Updates; - -messages.getUnreadPollVotes#43286cf2 flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; - -messages.readPollVotes#1720b4d8 flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; - -messages.setBotGuestChatResult#b8f106e3 query_id:long result:InputBotInlineResult = InputBotInlineMessageID; - -messages.deleteParticipantReactions#a0b80cf8 peer:InputPeer participant:InputPeer = Bool; - -messages.deleteParticipantReaction#e3b7f82c peer:InputPeer msg_id:int participant:InputPeer = Updates; - -messages.getPersonalChannelHistory#55fb0996 user_id:InputUser limit:int max_id:int min_id:int hash:long = messages.Messages; - -messages.getRichMessage#501569cf peer:InputPeer id:int = messages.Messages; - -updates.getState#edd4882a = updates.State; - -updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; - -updates.getChannelDifference#3173d78 flags:# force:flags.0?true channel:InputChannel filter:ChannelMessagesFilter pts:int limit:int = updates.ChannelDifference; - -photos.updateProfilePhoto#9e82039 flags:# fallback:flags.0?true bot:flags.1?InputUser id:InputPhoto = photos.Photo; - -photos.uploadProfilePhoto#388a3b5 flags:# fallback:flags.3?true bot:flags.5?InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.4?VideoSize = photos.Photo; - -photos.deletePhotos#87cf7f2f id:Vector = Vector; - -photos.getUserPhotos#91cd32a8 user_id:InputUser offset:int max_id:long limit:int = photos.Photos; - -photos.uploadContactProfilePhoto#e14c4a71 flags:# suggest:flags.3?true save:flags.4?true user_id:InputUser file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.5?VideoSize = photos.Photo; - -upload.saveFilePart#b304a621 file_id:long file_part:int bytes:bytes = Bool; - -upload.getFile#be5335be flags:# precise:flags.0?true cdn_supported:flags.1?true location:InputFileLocation offset:long limit:int = upload.File; - -upload.saveBigFilePart#de7b673d file_id:long file_part:int file_total_parts:int bytes:bytes = Bool; - -upload.getWebFile#24e6818d location:InputWebFileLocation offset:int limit:int = upload.WebFile; - -upload.getCdnFile#395f69da file_token:bytes offset:long limit:int = upload.CdnFile; - -upload.reuploadCdnFile#9b2754a8 file_token:bytes request_token:bytes = Vector; - -upload.getCdnFileHashes#91dc3f31 file_token:bytes offset:long = Vector; - -upload.getFileHashes#9156982a location:InputFileLocation offset:long = Vector; - -help.getConfig#c4f9186b = Config; - -help.getNearestDc#1fb33026 = NearestDc; - -help.getAppUpdate#522d5a7d source:string = help.AppUpdate; - -help.getInviteText#4d392343 = help.InviteText; - -help.getSupport#9cdf08cd = help.Support; - -help.setBotUpdatesStatus#ec22cfcd pending_updates_count:int message:string = Bool; - -help.getCdnConfig#52029342 = CdnConfig; - -help.getRecentMeUrls#3dc0f114 referer:string = help.RecentMeUrls; - -help.getTermsOfServiceUpdate#2ca51fd1 = help.TermsOfServiceUpdate; - -help.acceptTermsOfService#ee72f79a id:DataJSON = Bool; - -help.getDeepLinkInfo#3fedc75f path:string = help.DeepLinkInfo; - -help.getAppConfig#61e3f854 hash:int = help.AppConfig; - -help.saveAppLog#6f02f748 events:Vector = Bool; - -help.getPassportConfig#c661ad08 hash:int = help.PassportConfig; - -help.getSupportName#d360e72c = help.SupportName; - -help.getUserInfo#38a08d3 user_id:InputUser = help.UserInfo; - -help.editUserInfo#66b91b70 user_id:InputUser message:string entities:Vector = help.UserInfo; - -help.getPromoData#c0977421 = help.PromoData; - -help.hidePromoData#1e251c95 peer:InputPeer = Bool; - -help.dismissSuggestion#f50dbaa1 peer:InputPeer suggestion:string = Bool; - -help.getCountriesList#735787a8 lang_code:string hash:int = help.CountriesList; - -help.getPremiumPromo#b81b93d4 = help.PremiumPromo; - -help.getPeerColors#da80f42f hash:int = help.PeerColors; - -help.getPeerProfileColors#abcfa9fd hash:int = help.PeerColors; - -help.getTimezonesList#49b30240 hash:int = help.TimezonesList; - -channels.readHistory#cc104937 channel:InputChannel max_id:int = Bool; - -channels.deleteMessages#84c1fd4e channel:InputChannel id:Vector = messages.AffectedMessages; - -channels.reportSpam#f44a8315 channel:InputChannel participant:InputPeer id:Vector = Bool; - -channels.getMessages#ad8c9a23 channel:InputChannel id:Vector = messages.Messages; - -channels.getParticipants#77ced9d0 channel:InputChannel filter:ChannelParticipantsFilter offset:int limit:int hash:long = channels.ChannelParticipants; - -channels.getParticipant#a0ab6cc6 channel:InputChannel participant:InputPeer = channels.ChannelParticipant; - -channels.getChannels#a7f6bbb id:Vector = messages.Chats; - -channels.getFullChannel#8736a09 channel:InputChannel = messages.ChatFull; - -channels.createChannel#91006707 flags:# broadcast:flags.0?true megagroup:flags.1?true for_import:flags.3?true forum:flags.5?true title:string about:string geo_point:flags.2?InputGeoPoint address:flags.2?string ttl_period:flags.4?int = Updates; - -channels.editAdmin#9a98ad68 flags:# channel:InputChannel user_id:InputUser admin_rights:ChatAdminRights rank:flags.0?string = Updates; - -channels.editTitle#566decd0 channel:InputChannel title:string = Updates; - -channels.editPhoto#f12e57c9 channel:InputChannel photo:InputChatPhoto = Updates; - -channels.checkUsername#10e6bd2c channel:InputChannel username:string = Bool; - -channels.updateUsername#3514b3de channel:InputChannel username:string = Bool; - -channels.joinChannel#7f6a1e22 channel:InputChannel = messages.ChatInviteJoinResult; - -channels.leaveChannel#f836aa95 channel:InputChannel = Updates; - -channels.inviteToChannel#c9e33d54 channel:InputChannel users:Vector = messages.InvitedUsers; - -channels.deleteChannel#c0111fe3 channel:InputChannel = Updates; - -channels.exportMessageLink#e63fadeb flags:# grouped:flags.0?true thread:flags.1?true channel:InputChannel id:int = ExportedMessageLink; - -channels.toggleSignatures#418d549c flags:# signatures_enabled:flags.0?true profiles_enabled:flags.1?true channel:InputChannel = Updates; - -channels.getAdminedPublicChannels#f8b036af flags:# by_location:flags.0?true check_limit:flags.1?true for_personal:flags.2?true = messages.Chats; - -channels.editBanned#96e6cd81 channel:InputChannel participant:InputPeer banned_rights:ChatBannedRights = Updates; - -channels.getAdminLog#33ddf480 flags:# channel:InputChannel q:string events_filter:flags.0?ChannelAdminLogEventsFilter admins:flags.1?Vector max_id:long min_id:long limit:int = channels.AdminLogResults; - -channels.setStickers#ea8ca4f9 channel:InputChannel stickerset:InputStickerSet = Bool; - -channels.readMessageContents#eab5dc38 channel:InputChannel id:Vector = Bool; - -channels.deleteHistory#9baa9647 flags:# for_everyone:flags.0?true channel:InputChannel max_id:int = Updates; - -channels.togglePreHistoryHidden#eabbb94c channel:InputChannel enabled:Bool = Updates; - -channels.getLeftChannels#8341ecc0 offset:int = messages.Chats; - -channels.getGroupsForDiscussion#f5dad378 = messages.Chats; - -channels.setDiscussionGroup#40582bb2 broadcast:InputChannel group:InputChannel = Bool; - -channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint address:string = Bool; - -channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates; - -channels.getInactiveChannels#11e831ee = messages.InactiveChats; - -channels.convertToGigagroup#b290c69 channel:InputChannel = Updates; - -channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true for_live_stories:flags.1?true peer:InputPeer = channels.SendAsPeers; - -channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory; - -channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates; - -channels.toggleJoinRequest#ecc2618 flags:# apply_to_invites:flags.1?true channel:InputChannel enabled:Bool guard_bot:flags.0?InputUser = Updates; - -channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector = Bool; - -channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool; - -channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool; - -channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates; - -channels.toggleAntiSpam#68f3e4eb channel:InputChannel enabled:Bool = Updates; - -channels.reportAntiSpamFalsePositive#a850a693 channel:InputChannel msg_id:int = Bool; - -channels.toggleParticipantsHidden#6a6e7854 channel:InputChannel enabled:Bool = Updates; - -channels.updateColor#d8aa3671 flags:# for_profile:flags.1?true channel:InputChannel color:flags.2?int background_emoji_id:flags.0?long = Updates; - -channels.toggleViewForumAsMessages#9738bb15 channel:InputChannel enabled:Bool = Updates; - -channels.getChannelRecommendations#25a71742 flags:# channel:flags.0?InputChannel = messages.Chats; - -channels.updateEmojiStatus#f0d3e6a8 channel:InputChannel emoji_status:EmojiStatus = Updates; - -channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int = Updates; - -channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; - -channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; - -channels.searchPosts#f2c4f24d flags:# hashtag:flags.0?string query:flags.1?string offset_rate:int offset_peer:InputPeer offset_id:int limit:int allow_paid_stars:flags.2?long = messages.Messages; - -channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; - -channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; - -channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; - -channels.checkSearchPostsFlood#22567115 flags:# query:flags.0?string = SearchPostsFlood; - -channels.setMainProfileTab#3583fcb1 channel:InputChannel tab:ProfileTab = Bool; - -bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; - -bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; - -bots.setBotCommands#517165a scope:BotCommandScope lang_code:string commands:Vector = Bool; - -bots.resetBotCommands#3d8de0f9 scope:BotCommandScope lang_code:string = Bool; - -bots.getBotCommands#e34c0dd6 scope:BotCommandScope lang_code:string = Vector; - -bots.setBotMenuButton#4504d54f user_id:InputUser button:BotMenuButton = Bool; - -bots.getBotMenuButton#9c60eb28 user_id:InputUser = BotMenuButton; - -bots.setBotBroadcastDefaultAdminRights#788464e1 admin_rights:ChatAdminRights = Bool; - -bots.setBotGroupDefaultAdminRights#925ec9ea admin_rights:ChatAdminRights = Bool; - -bots.setBotInfo#10cf3123 flags:# bot:flags.2?InputUser lang_code:string name:flags.3?string about:flags.0?string description:flags.1?string = Bool; - -bots.getBotInfo#dcd914fd flags:# bot:flags.0?InputUser lang_code:string = bots.BotInfo; - -bots.reorderUsernames#9709b1c2 bot:InputUser order:Vector = Bool; - -bots.toggleUsername#53ca973 bot:InputUser username:string active:Bool = Bool; - -bots.canSendMessage#1359f4e6 bot:InputUser = Bool; - -bots.allowSendMessage#f132e3ef bot:InputUser = Updates; - -bots.invokeWebViewCustomMethod#87fc5e7 bot:InputUser custom_method:string params:DataJSON = DataJSON; - -bots.getPopularAppBots#c2510192 offset:string limit:int = bots.PopularAppBots; - -bots.addPreviewMedia#17aeb75a bot:InputUser lang_code:string media:InputMedia = BotPreviewMedia; - -bots.editPreviewMedia#8525606f bot:InputUser lang_code:string media:InputMedia new_media:InputMedia = BotPreviewMedia; - -bots.deletePreviewMedia#2d0135b3 bot:InputUser lang_code:string media:Vector = Bool; - -bots.reorderPreviewMedias#b627f3aa bot:InputUser lang_code:string order:Vector = Bool; - -bots.getPreviewInfo#423ab3ad bot:InputUser lang_code:string = bots.PreviewInfo; - -bots.getPreviewMedias#a2a5594d bot:InputUser = Vector; - -bots.updateUserEmojiStatus#ed9f30c5 user_id:InputUser emoji_status:EmojiStatus = Bool; - -bots.toggleUserEmojiStatusPermission#6de6392 bot:InputUser enabled:Bool = Bool; - -bots.checkDownloadFileParams#50077589 bot:InputUser file_name:string url:string = Bool; - -bots.getAdminedBots#b0711d83 = Vector; - -bots.updateStarRefProgram#778b5ab3 flags:# bot:InputUser commission_permille:int duration_months:flags.0?int = StarRefProgram; - -bots.setCustomVerification#8b89dfbd flags:# enabled:flags.1?true bot:flags.0?InputUser peer:InputPeer custom_description:flags.2?string = Bool; - -bots.getBotRecommendations#a1b70815 bot:InputUser = users.Users; - -bots.checkUsername#87f2219b username:string = Bool; - -bots.createBot#e5b17f2b flags:# via_deeplink:flags.0?true name:string username:string manager_id:InputUser = User; - -bots.exportBotToken#bd0d99eb bot:InputUser revoke:Bool = bots.ExportedBotToken; - -bots.requestWebViewButton#31a2a35e user_id:InputUser button:KeyboardButton = bots.RequestedButton; - -bots.getRequestedWebViewButton#bf25b7f3 bot:InputUser webapp_req_id:string = KeyboardButton; - -bots.getAccessSettings#213853a3 bot:InputUser = bots.AccessSettings; - -bots.editAccessSettings#31813cd8 flags:# restricted:flags.0?true bot:InputUser add_users:flags.1?Vector = Bool; - -bots.setJoinChatResults#e71a4810 query_id:long result:JoinChatBotResult = Bool; - -payments.getPaymentForm#37148dbb flags:# invoice:InputInvoice theme_params:flags.0?DataJSON = payments.PaymentForm; - -payments.getPaymentReceipt#2478d1cc peer:InputPeer msg_id:int = payments.PaymentReceipt; - -payments.validateRequestedInfo#b6c8f12b flags:# save:flags.0?true invoice:InputInvoice info:PaymentRequestedInfo = payments.ValidatedRequestedInfo; - -payments.sendPaymentForm#2d03522f flags:# form_id:long invoice:InputInvoice requested_info_id:flags.0?string shipping_option_id:flags.1?string credentials:InputPaymentCredentials tip_amount:flags.2?long = payments.PaymentResult; - -payments.getSavedInfo#227d824b = payments.SavedInfo; - -payments.clearSavedInfo#d83d70c1 flags:# credentials:flags.0?true info:flags.1?true = Bool; - -payments.getBankCardData#2e79d779 number:string = payments.BankCardData; - -payments.exportInvoice#f91b065 invoice_media:InputMedia = payments.ExportedInvoice; - -payments.assignAppStoreTransaction#80ed747d receipt:bytes purpose:InputStorePaymentPurpose = Updates; - -payments.assignPlayMarketTransaction#dffd50d3 receipt:DataJSON purpose:InputStorePaymentPurpose = Updates; - -payments.getPremiumGiftCodeOptions#2757ba54 flags:# boost_peer:flags.0?InputPeer = Vector; - -payments.checkGiftCode#8e51b4c1 slug:string = payments.CheckedGiftCode; - -payments.applyGiftCode#f6e26854 slug:string = Updates; - -payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; - -payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; - -payments.getStarsTopupOptions#c00ec7d3 = Vector; - -payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus; - -payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; - -payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult; - -payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; - -payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats; - -payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; - -payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; - -payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector = payments.StarsStatus; - -payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; - -payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; - -payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; - -payments.fulfillStarsSubscription#cc5bebb3 peer:InputPeer subscription_id:string = Bool; - -payments.getStarsGiveawayOptions#bd1efd3e = Vector; - -payments.getStarGifts#c4563590 hash:int = payments.StarGifts; - -payments.saveStarGift#2a2a697c flags:# unsave:flags.0?true stargift:InputSavedStarGift = Bool; - -payments.convertStarGift#74bf076b stargift:InputSavedStarGift = Bool; - -payments.botCancelStarsSubscription#6dfa0622 flags:# restore:flags.0?true user_id:InputUser charge_id:string = Bool; - -payments.getConnectedStarRefBots#5869a553 flags:# peer:InputPeer offset_date:flags.2?int offset_link:flags.2?string limit:int = payments.ConnectedStarRefBots; - -payments.getConnectedStarRefBot#b7d998f0 peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; - -payments.getSuggestedStarRefBots#d6b48f7 flags:# order_by_revenue:flags.0?true order_by_date:flags.1?true peer:InputPeer offset:string limit:int = payments.SuggestedStarRefBots; - -payments.connectStarRefBot#7ed5348a peer:InputPeer bot:InputUser = payments.ConnectedStarRefBots; - -payments.editConnectedStarRefBot#e4fca4a3 flags:# revoked:flags.0?true peer:InputPeer link:string = payments.ConnectedStarRefBots; - -payments.getStarGiftUpgradePreview#9c9abcb1 gift_id:long = payments.StarGiftUpgradePreview; - -payments.upgradeStarGift#aed6e4f5 flags:# keep_original_details:flags.0?true stargift:InputSavedStarGift = Updates; - -payments.transferStarGift#7f18176a stargift:InputSavedStarGift to_id:InputPeer = Updates; - -payments.getUniqueStarGift#a1974d72 slug:string = payments.UniqueStarGift; - -payments.getSavedStarGifts#a319e569 flags:# exclude_unsaved:flags.0?true exclude_saved:flags.1?true exclude_unlimited:flags.2?true exclude_unique:flags.4?true sort_by_value:flags.5?true exclude_upgradable:flags.7?true exclude_unupgradable:flags.8?true peer_color_available:flags.9?true exclude_hosted:flags.10?true peer:InputPeer collection_id:flags.6?int offset:string limit:int = payments.SavedStarGifts; - -payments.getSavedStarGift#b455a106 stargift:Vector = payments.SavedStarGifts; - -payments.getStarGiftWithdrawalUrl#d06e93a8 stargift:InputSavedStarGift password:InputCheckPasswordSRP = payments.StarGiftWithdrawalUrl; - -payments.toggleChatStarGiftNotifications#60eaefa1 flags:# enabled:flags.0?true peer:InputPeer = Bool; - -payments.toggleStarGiftsPinnedToTop#1513e7b0 peer:InputPeer stargift:Vector = Bool; - -payments.canPurchaseStore#4fdc5ea7 purpose:InputStorePaymentPurpose = Bool; - -payments.getResaleStarGifts#7a5fa236 flags:# sort_by_price:flags.1?true sort_by_num:flags.2?true for_craft:flags.4?true stars_only:flags.5?true attributes_hash:flags.0?long gift_id:long attributes:flags.3?Vector offset:string limit:int = payments.ResaleStarGifts; - -payments.updateStarGiftPrice#edbe6ccb stargift:InputSavedStarGift resell_amount:StarsAmount = Updates; - -payments.createStarGiftCollection#1f4a0e87 peer:InputPeer title:string stargift:Vector = StarGiftCollection; - -payments.updateStarGiftCollection#4fddbee7 flags:# peer:InputPeer collection_id:int title:flags.0?string delete_stargift:flags.1?Vector add_stargift:flags.2?Vector order:flags.3?Vector = StarGiftCollection; - -payments.reorderStarGiftCollections#c32af4cc peer:InputPeer order:Vector = Bool; - -payments.deleteStarGiftCollection#ad5648e8 peer:InputPeer collection_id:int = Bool; - -payments.getStarGiftCollections#981b91dd peer:InputPeer hash:long = payments.StarGiftCollections; - -payments.getUniqueStarGiftValueInfo#4365af6b slug:string = payments.UniqueStarGiftValueInfo; - -payments.checkCanSendGift#c0c4edc9 gift_id:long = payments.CheckCanSendGiftResult; - -payments.getStarGiftAuctionState#5c9ff4d6 auction:InputStarGiftAuction version:int = payments.StarGiftAuctionState; - -payments.getStarGiftAuctionAcquiredGifts#6ba2cbec gift_id:long = payments.StarGiftAuctionAcquiredGifts; - -payments.getStarGiftActiveAuctions#a5d0514d hash:long = payments.StarGiftActiveAuctions; - -payments.resolveStarGiftOffer#e9ce781c flags:# decline:flags.0?true offer_msg_id:int = Updates; - -payments.sendStarGiftOffer#8fb86b41 flags:# peer:InputPeer slug:string price:StarsAmount duration:int random_id:long allow_paid_stars:flags.0?long = Updates; - -payments.getStarGiftUpgradeAttributes#6d038b58 gift_id:long = payments.StarGiftUpgradeAttributes; - -payments.getCraftStarGifts#fd05dd00 gift_id:long offset:string limit:int = payments.SavedStarGifts; - -payments.craftStarGift#b0f9684f stargift:Vector = Updates; - -stickers.createStickerSet#9021ab67 flags:# masks:flags.0?true emojis:flags.5?true text_color:flags.6?true user_id:InputUser title:string short_name:string thumb:flags.2?InputDocument stickers:Vector software:flags.3?string = messages.StickerSet; - -stickers.removeStickerFromSet#f7760f51 sticker:InputDocument = messages.StickerSet; - -stickers.changeStickerPosition#ffb6d4ca sticker:InputDocument position:int = messages.StickerSet; - -stickers.addStickerToSet#8653febe stickerset:InputStickerSet sticker:InputStickerSetItem = messages.StickerSet; - -stickers.setStickerSetThumb#a76a5392 flags:# stickerset:InputStickerSet thumb:flags.0?InputDocument thumb_document_id:flags.1?long = messages.StickerSet; - -stickers.checkShortName#284b3639 short_name:string = Bool; - -stickers.suggestShortName#4dafc503 title:string = stickers.SuggestedShortName; - -stickers.changeSticker#f5537ebc flags:# sticker:InputDocument emoji:flags.0?string mask_coords:flags.1?MaskCoords keywords:flags.2?string = messages.StickerSet; - -stickers.renameStickerSet#124b1c00 stickerset:InputStickerSet title:string = messages.StickerSet; - -stickers.deleteStickerSet#87704394 stickerset:InputStickerSet = Bool; - -stickers.replaceSticker#4696459a sticker:InputDocument new_sticker:InputStickerSetItem = messages.StickerSet; - -phone.getCallConfig#55451fa9 = DataJSON; - -phone.requestCall#42ff96ed flags:# video:flags.0?true user_id:InputUser random_id:int g_a_hash:bytes protocol:PhoneCallProtocol = phone.PhoneCall; - -phone.acceptCall#3bd2b4a0 peer:InputPhoneCall g_b:bytes protocol:PhoneCallProtocol = phone.PhoneCall; - -phone.confirmCall#2efe1722 peer:InputPhoneCall g_a:bytes key_fingerprint:long protocol:PhoneCallProtocol = phone.PhoneCall; - -phone.receivedCall#17d54f61 peer:InputPhoneCall = Bool; - -phone.discardCall#b2cbc1c0 flags:# video:flags.0?true peer:InputPhoneCall duration:int reason:PhoneCallDiscardReason connection_id:long = Updates; - -phone.setCallRating#59ead627 flags:# user_initiative:flags.0?true peer:InputPhoneCall rating:int comment:string = Updates; - -phone.saveCallDebug#277add7e peer:InputPhoneCall debug:DataJSON = Bool; - -phone.sendSignalingData#ff7a9383 peer:InputPhoneCall data:bytes = Bool; - -phone.createGroupCall#48cdc6d8 flags:# rtmp_stream:flags.2?true peer:InputPeer random_id:int title:flags.0?string schedule_date:flags.1?int = Updates; - -phone.joinGroupCall#8fb53057 flags:# muted:flags.0?true video_stopped:flags.2?true call:InputGroupCall join_as:InputPeer invite_hash:flags.1?string public_key:flags.3?int256 block:flags.3?bytes params:DataJSON = Updates; - -phone.leaveGroupCall#500377f9 call:InputGroupCall source:int = Updates; - -phone.inviteToGroupCall#7b393160 call:InputGroupCall users:Vector = Updates; - -phone.discardGroupCall#7a777135 call:InputGroupCall = Updates; - -phone.toggleGroupCallSettings#974392f2 flags:# reset_invite_hash:flags.1?true call:InputGroupCall join_muted:flags.0?Bool messages_enabled:flags.2?Bool send_paid_messages_stars:flags.3?long = Updates; - -phone.getGroupCall#41845db call:InputGroupCall limit:int = phone.GroupCall; - -phone.getGroupParticipants#c558d8ab call:InputGroupCall ids:Vector sources:Vector offset:string limit:int = phone.GroupParticipants; - -phone.checkGroupCall#b59cf977 call:InputGroupCall sources:Vector = Vector; - -phone.toggleGroupCallRecord#f128c708 flags:# start:flags.0?true video:flags.2?true call:InputGroupCall title:flags.1?string video_portrait:flags.2?Bool = Updates; - -phone.editGroupCallParticipant#a5273abf flags:# call:InputGroupCall participant:InputPeer muted:flags.0?Bool volume:flags.1?int raise_hand:flags.2?Bool video_stopped:flags.3?Bool video_paused:flags.4?Bool presentation_paused:flags.5?Bool = Updates; - -phone.editGroupCallTitle#1ca6ac0a call:InputGroupCall title:string = Updates; - -phone.getGroupCallJoinAs#ef7c213a peer:InputPeer = phone.JoinAsPeers; - -phone.exportGroupCallInvite#e6aa647f flags:# can_self_unmute:flags.0?true call:InputGroupCall = phone.ExportedGroupCallInvite; - -phone.toggleGroupCallStartSubscription#219c34e6 call:InputGroupCall subscribed:Bool = Updates; - -phone.startScheduledGroupCall#5680e342 call:InputGroupCall = Updates; - -phone.saveDefaultGroupCallJoinAs#575e1f8c peer:InputPeer join_as:InputPeer = Bool; - -phone.joinGroupCallPresentation#cbea6bc4 call:InputGroupCall params:DataJSON = Updates; - -phone.leaveGroupCallPresentation#1c50d144 call:InputGroupCall = Updates; - -phone.getGroupCallStreamChannels#1ab21940 call:InputGroupCall = phone.GroupCallStreamChannels; - -phone.getGroupCallStreamRtmpUrl#5af4c73a flags:# live_story:flags.0?true peer:InputPeer revoke:Bool = phone.GroupCallStreamRtmpUrl; - -phone.saveCallLog#41248786 peer:InputPhoneCall file:InputFile = Bool; - -phone.createConferenceCall#7d0444bb flags:# muted:flags.0?true video_stopped:flags.2?true join:flags.3?true random_id:int public_key:flags.3?int256 block:flags.3?bytes params:flags.3?DataJSON = Updates; - -phone.deleteConferenceCallParticipants#8ca60525 flags:# only_left:flags.0?true kick:flags.1?true call:InputGroupCall ids:Vector block:bytes = Updates; - -phone.sendConferenceCallBroadcast#c6701900 call:InputGroupCall block:bytes = Updates; - -phone.inviteConferenceCallParticipant#bcf22685 flags:# video:flags.0?true call:InputGroupCall user_id:InputUser = Updates; - -phone.declineConferenceCallInvite#3c479971 msg_id:int = Updates; - -phone.getGroupCallChainBlocks#ee9f88a6 call:InputGroupCall sub_chain_id:int offset:int limit:int = Updates; - -phone.sendGroupCallMessage#b1d11410 flags:# call:InputGroupCall random_id:long message:TextWithEntities allow_paid_stars:flags.0?long send_as:flags.1?InputPeer = Updates; - -phone.sendGroupCallEncryptedMessage#e5afa56d call:InputGroupCall encrypted_message:bytes = Bool; - -phone.deleteGroupCallMessages#f64f54f7 flags:# report_spam:flags.0?true call:InputGroupCall messages:Vector = Updates; - -phone.deleteGroupCallParticipantMessages#1dbfeca0 flags:# report_spam:flags.0?true call:InputGroupCall participant:InputPeer = Updates; - -phone.getGroupCallStars#6f636302 call:InputGroupCall = phone.GroupCallStars; - -phone.saveDefaultSendAs#4167add1 call:InputGroupCall send_as:InputPeer = Bool; - -langpack.getLangPack#f2f2330a lang_pack:string lang_code:string = LangPackDifference; - -langpack.getStrings#efea3803 lang_pack:string lang_code:string keys:Vector = Vector; - -langpack.getDifference#cd984aa5 lang_pack:string lang_code:string from_version:int = LangPackDifference; - -langpack.getLanguages#42c6978f lang_pack:string = Vector; - -langpack.getLanguage#6a596502 lang_pack:string lang_code:string = LangPackLanguage; - -folders.editPeerFolders#6847d0ab folder_peers:Vector = Updates; - -stats.getBroadcastStats#ab42441a flags:# dark:flags.0?true channel:InputChannel = stats.BroadcastStats; - -stats.loadAsyncGraph#621d5fa0 flags:# token:string x:flags.0?long = StatsGraph; - -stats.getMegagroupStats#dcdf8607 flags:# dark:flags.0?true channel:InputChannel = stats.MegagroupStats; - -stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:string limit:int = stats.PublicForwards; - -stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; - -stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; - -stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards; - -stats.getPollStats#c27dfa68 flags:# dark:flags.0?true peer:InputPeer msg_id:int = stats.PollStats; - -chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; - -chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; - -chatlists.editExportedInvite#653db63d flags:# chatlist:InputChatlist slug:string title:flags.1?string peers:flags.2?Vector = ExportedChatlistInvite; - -chatlists.getExportedInvites#ce03da83 chatlist:InputChatlist = chatlists.ExportedInvites; - -chatlists.checkChatlistInvite#41c10fff slug:string = chatlists.ChatlistInvite; - -chatlists.joinChatlistInvite#a6b1e39a slug:string peers:Vector = Updates; - -chatlists.getChatlistUpdates#89419521 chatlist:InputChatlist = chatlists.ChatlistUpdates; - -chatlists.joinChatlistUpdates#e089f8f5 chatlist:InputChatlist peers:Vector = Updates; - -chatlists.hideChatlistUpdates#66e486fb chatlist:InputChatlist = Bool; - -chatlists.getLeaveChatlistSuggestions#fdbcd714 chatlist:InputChatlist = Vector; - -chatlists.leaveChatlist#74fae13a chatlist:InputChatlist peers:Vector = Updates; - -stories.canSendStory#30eb63f0 peer:InputPeer = stories.CanSendStoryCount; - -stories.sendStory#8f9e6898 flags:# pinned:flags.2?true noforwards:flags.4?true fwd_modified:flags.7?true peer:InputPeer media:InputMedia media_areas:flags.5?Vector caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long period:flags.3?int fwd_from_id:flags.6?InputPeer fwd_from_story:flags.6?int albums:flags.8?Vector music:flags.9?InputDocument = Updates; - -stories.editStory#2c63a72b flags:# peer:InputPeer id:int media:flags.0?InputMedia media_areas:flags.3?Vector caption:flags.1?string entities:flags.1?Vector privacy_rules:flags.2?Vector music:flags.4?InputDocument = Updates; - -stories.deleteStories#ae59db5f peer:InputPeer id:Vector = Vector; - -stories.togglePinned#9a75a1ef peer:InputPeer id:Vector pinned:Bool = Vector; - -stories.getAllStories#eeb0d625 flags:# next:flags.1?true hidden:flags.2?true state:flags.0?string = stories.AllStories; - -stories.getPinnedStories#5821a5dc peer:InputPeer offset_id:int limit:int = stories.Stories; - -stories.getStoriesArchive#b4352016 peer:InputPeer offset_id:int limit:int = stories.Stories; - -stories.getStoriesByID#5774ca74 peer:InputPeer id:Vector = stories.Stories; - -stories.toggleAllStoriesHidden#7c2557c4 hidden:Bool = Bool; - -stories.readStories#a556dac8 peer:InputPeer max_id:int = Vector; - -stories.incrementStoryViews#b2028afb peer:InputPeer id:Vector = Bool; - -stories.getStoryViewsList#7ed23c57 flags:# just_contacts:flags.0?true reactions_first:flags.2?true forwards_first:flags.3?true peer:InputPeer q:flags.1?string id:int offset:string limit:int = stories.StoryViewsList; - -stories.getStoriesViews#28e16cc8 peer:InputPeer id:Vector = stories.StoryViews; - -stories.exportStoryLink#7b8def20 peer:InputPeer id:int = ExportedStoryLink; - -stories.report#19d8eb45 peer:InputPeer id:Vector option:bytes message:string = ReportResult; - -stories.activateStealthMode#57bbd166 flags:# past:flags.0?true future:flags.1?true = Updates; - -stories.sendReaction#7fd736b2 flags:# add_to_recent:flags.0?true peer:InputPeer story_id:int reaction:Reaction = Updates; - -stories.getPeerStories#2c4ada50 peer:InputPeer = stories.PeerStories; - -stories.getAllReadPeerStories#9b5ae7f9 = Updates; - -stories.getPeerMaxIDs#78499170 id:Vector = Vector; - -stories.getChatsToSend#a56a8b60 = messages.Chats; - -stories.togglePeerStoriesHidden#bd0415c4 peer:InputPeer hidden:Bool = Bool; - -stories.getStoryReactionsList#b9b2881f flags:# forwards_first:flags.2?true peer:InputPeer id:int reaction:flags.0?Reaction offset:flags.1?string limit:int = stories.StoryReactionsList; - -stories.togglePinnedToTop#b297e9b peer:InputPeer id:Vector = Bool; - -stories.searchPosts#d1810907 flags:# hashtag:flags.0?string area:flags.1?MediaArea peer:flags.2?InputPeer offset:string limit:int = stories.FoundStories; - -stories.createAlbum#a36396e5 peer:InputPeer title:string stories:Vector = StoryAlbum; - -stories.updateAlbum#5e5259b6 flags:# peer:InputPeer album_id:int title:flags.0?string delete_stories:flags.1?Vector add_stories:flags.2?Vector order:flags.3?Vector = StoryAlbum; - -stories.reorderAlbums#8535fbd9 peer:InputPeer order:Vector = Bool; - -stories.deleteAlbum#8d3456d0 peer:InputPeer album_id:int = Bool; - -stories.getAlbums#25b3eac7 peer:InputPeer hash:long = stories.Albums; - -stories.getAlbumStories#ac806d61 peer:InputPeer album_id:int offset:int limit:int = stories.Stories; - -stories.startLive#d069ccde flags:# pinned:flags.2?true noforwards:flags.4?true rtmp_stream:flags.5?true peer:InputPeer caption:flags.0?string entities:flags.1?Vector privacy_rules:Vector random_id:long messages_enabled:flags.6?Bool send_paid_messages_stars:flags.7?long = Updates; - -premium.getBoostsList#60f67660 flags:# gifts:flags.0?true peer:InputPeer offset:string limit:int = premium.BoostsList; - -premium.getMyBoosts#be77b4a = premium.MyBoosts; - -premium.applyBoost#6b7da746 flags:# slots:flags.0?Vector peer:InputPeer = premium.MyBoosts; - -premium.getBoostsStatus#42f1f61 peer:InputPeer = premium.BoostsStatus; - -premium.getUserBoosts#39854d1f peer:InputPeer user_id:InputUser = premium.BoostsList; - -smsjobs.isEligibleToJoin#edc39d0 = smsjobs.EligibilityToJoin; - -smsjobs.join#a74ece2d = Bool; - -smsjobs.leave#9898ad73 = Bool; - -smsjobs.updateSettings#93fa0bf flags:# allow_international:flags.0?true = Bool; - -smsjobs.getStatus#10a698e8 = smsjobs.Status; - -smsjobs.getSmsJob#778d902f job_id:string = SmsJob; - -smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; - -fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; - -aicompose.createTone#4aa83913 flags:# display_author:flags.0?true emoji_id:long title:string prompt:string = AiComposeTone; - -aicompose.updateTone#903bcf59 flags:# tone:InputAiComposeTone display_author:flags.0?Bool emoji_id:flags.1?long title:flags.2?string prompt:flags.3?string = AiComposeTone; - -aicompose.saveTone#1782cbb1 tone:InputAiComposeTone unsave:Bool = Bool; - -aicompose.deleteTone#dd39316a tone:InputAiComposeTone = Bool; - -aicompose.getTone#b2e8ba03 tone:InputAiComposeTone = aicompose.Tones; - -aicompose.getTones#abd59201 hash:long = aicompose.Tones; - -aicompose.getToneExample#d1b4ab14 tone:InputAiComposeTone num:int = AiComposeToneExample; - -// LAYER 227 diff --git a/internal/compat/layerwire/schema/client-drift.tl b/internal/compat/layerwire/schema/client-drift.tl deleted file mode 100644 index 91e3a1c6..00000000 --- a/internal/compat/layerwire/schema/client-drift.tl +++ /dev/null @@ -1,33 +0,0 @@ -// Client constructor drift — method constructors emitted by a specific client's -// hand-maintained TL (DrKLO Android, TLRPC.java) that are absent from the -// canonical (227) schema. They are old-layer API versions the client never -// updated; from the server's view they request the SAME api method, only with an -// older wire shape. -// -// The generic inbound upgrader (inbound.go) matches each by qualified name to -// the canonical method and rebuilds a canonical request: copy shared fields, -// write 0 for inserted flags integers, synthesize defaults for new required -// fields, and convert changed field types via the converter registry. So adding -// support for a newly-observed drifted constructor is one line here + a `gen` -// run — never a runtime-discovered hand patch. -// -// Only bodies that differ structurally belong here. Body-identical drift (only -// the constructor id differs) is a plain id swap in clientMethodAliases -// (client_aliases.go). - ----functions--- - -messages.uploadMedia#519bc2b1 peer:InputPeer media:InputMedia = MessageMedia; -auth.signUp#80eee427 phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization; -messages.getMessages#4222fa74 id:Vector = messages.Messages; -channels.getMessages#93d7b347 channel:InputChannel id:Vector = messages.Messages; -bots.exportBotToken#0063b089 bot_id:long revoke:Bool = bots.ExportedBotToken; -account.registerDevice#637ea878 token_type:int token:string = Bool; -contacts.search#11f812d8 q:string limit:int = contacts.Found; -langpack.getLangPack#9ab5c58e lang_code:string = LangPackDifference; -langpack.getStrings#2e1ee318 lang_code:string keys:Vector = Vector; -langpack.getLanguages#800fd57d = Vector; -// DrKLO still emits old channels.editCreator#8f38cd1f; canonical 227 replaced -// that flow with messages.editChatCreator(peer:InputPeer,...). Keep the old -// constructor id here but target the canonical method name for generic upgrade. -messages.editChatCreator#8f38cd1f channel:InputChannel user_id:InputUser password:InputCheckPasswordSRP = Updates; diff --git a/internal/compat/layerwire/schema/routable-compat.tl b/internal/compat/layerwire/schema/routable-compat.tl deleted file mode 100644 index dd5aaee4..00000000 --- a/internal/compat/layerwire/schema/routable-compat.tl +++ /dev/null @@ -1,11 +0,0 @@ -// Hand-maintained request layouts that are intentionally handled by the RPC -// fallback instead of gotd's canonical ServerDispatcher. They still belong in -// the structural preflight model: fallback handlers must never become a way to -// bypass the canonical vector/depth/bytes budgets. - ----functions--- - -compat.legacyCreateTheme#8432c21f flags:# slug:string title:string document:flags.2?InputDocument settings:flags.3?InputThemeSettings = Object; -compat.legacyUpdateTheme#5cb367d5 flags:# format:string theme:InputTheme slug:flags.0?string title:flags.1?string document:flags.2?InputDocument settings:flags.3?InputThemeSettings = Object; -compat.legacyInstallTheme#7ae43737 flags:# dark:flags.0?true format:flags.1?string theme:flags.1?InputTheme = Object; -compat.legacyGetTheme#8d9d742b format:string theme:InputTheme document_id:long = Object; diff --git a/internal/compat/layerwire/tables.go b/internal/compat/layerwire/tables.go deleted file mode 100644 index 4290d04a..00000000 --- a/internal/compat/layerwire/tables.go +++ /dev/null @@ -1,374 +0,0 @@ -package layerwire - -import ( - "fmt" - - "github.com/gotd/td/bin" -) - -// ruleRaw is the generated, compact form of a single changed-constructor -// downgrade (see tables_gen.go). Mechanical rules carry the target CRC plus the -// canonical field names retained at the target layer; structural rules name a -// hand-written transform registered in fallback.go. -type ruleRaw struct { - target uint32 - keep []string - structural string -} - -// layerRaw is the generated downgrade table for one target layer. -type layerRaw struct { - rules map[uint32]ruleRaw - newTypes []uint32 // canonical CRCs that do not exist at this layer -} - -// downgradeRule is the runtime form of ruleRaw with keep as a set. -type downgradeRule struct { - target uint32 - keep map[string]bool - structural string -} - -// layerTables is the runtime downgrade model for one target layer. -type layerTables struct { - rules map[uint32]*downgradeRule - newTypes map[uint32]bool - dirty map[uint32]bool // ctor CRC needs a deep walk - dirtyT map[string]bool // abstract/bare type name reaches a dirty ctor -} - -// tables holds the runtime model per supported layer, built lazily. -var tables = func() map[int]*layerTables { - out := make(map[int]*layerTables, len(generatedTables)) - for layer, raw := range generatedTables { - out[layer] = buildLayerTables(raw) - } - return out -}() - -func buildLayerTables(raw layerRaw) *layerTables { - lt := &layerTables{ - rules: make(map[uint32]*downgradeRule, len(raw.rules)), - newTypes: make(map[uint32]bool, len(raw.newTypes)), - } - for crc, r := range raw.rules { - dr := &downgradeRule{target: r.target, structural: r.structural} - if r.structural == "" { - dr.keep = make(map[string]bool, len(r.keep)) - for _, n := range r.keep { - dr.keep[n] = true - } - } - lt.rules[crc] = dr - } - for _, crc := range raw.newTypes { - lt.newTypes[crc] = true - } - lt.computeDirty() - return lt -} - -// computeDirty marks every constructor (and abstract/bare type) that can -// transitively contain a changed, structural, or layer-absent constructor, so -// the transcoder can byte-copy the ~86% of the type graph that is unaffected. -func (lt *layerTables) computeDirty() { - lt.dirty = make(map[uint32]bool) - lt.dirtyT = make(map[string]bool) - // Seed: rules + new types are themselves dirty. - for crc := range lt.rules { - lt.dirty[crc] = true - } - for crc := range lt.newTypes { - lt.dirty[crc] = true - } - markType := func(name string) { - if name != "" && !lt.dirtyT[name] { - lt.dirtyT[name] = true - } - } - // Seed dirty types from seeded dirty ctors. - for crc := range lt.dirty { - if cl := canonical.byCRC[crc]; cl != nil { - markType(cl.result) - markType(cl.name) // bare reference - } - } - // Fixpoint: a ctor is dirty if any field's type is dirty; a type is dirty - // if any of its constructors is dirty. - for changed := true; changed; { - changed = false - for crc, cl := range canonical.byCRC { - if lt.dirty[crc] { - continue - } - if lt.ctorHasDirtyField(cl) { - lt.dirty[crc] = true - if !lt.dirtyT[cl.result] { - lt.dirtyT[cl.result] = true - } - if !lt.dirtyT[cl.name] { - lt.dirtyT[cl.name] = true - } - changed = true - } - } - } -} - -func (lt *layerTables) ctorHasDirtyField(cl *ctorLayout) bool { - for i := range cl.fields { - if lt.fieldDirty(&cl.fields[i]) { - return true - } - } - return false -} - -func (lt *layerTables) fieldDirty(f *fieldLayout) bool { - switch f.kind { - case kindObject, kindBareObject: - return lt.dirtyT[f.typeName] - case kindVector, kindVectorBare: - return lt.fieldDirty(f.elem) - default: - return false - } -} - -// structuralFunc transforms a changed constructor whose downgrade is not a pure -// field drop. The leading CRC has already been consumed from in; the transform -// reads the canonical body from in and writes the target-layer object (whose -// constructor id is target) to out. -type structuralFunc func(cl *ctorLayout, target uint32, in, out *bin.Buffer, layer, depth int, walk *walkState) error - -// fallbackFunc replaces a layer-absent (227-only) constructor with an -// equivalent the target layer understands. The leading CRC is NOT yet consumed. -type fallbackFunc func(cl *ctorLayout, in, out *bin.Buffer, layer, depth int, walk *walkState) error - -// structuralTransforms and the newType fallback registries are populated in -// fallback.go. newTypeFallbacks is keyed by canonical CRC (specific override); -// newTypeFallbacksByType is keyed by the canonical abstract result type and -// covers every 227-only constructor of that class (e.g. any new MessageAction). -var ( - structuralTransforms = map[string]structuralFunc{} - newTypeFallbacks = map[uint32]fallbackFunc{} - newTypeFallbacksByType = map[string]fallbackFunc{} -) - -// Transcode downgrades a single canonical (Layer 227) boxed object to the wire -// shape of layer. layer >= CanonicalLayer (or unsupported) returns in verbatim. -// On any transform gap it returns an error so the edge can fall back to sending -// the canonical bytes rather than corrupting the stream. -func Transcode(canonicalBytes []byte, layer int) ([]byte, error) { - if layer >= CanonicalLayer { - return canonicalBytes, nil - } - lt := tables[layer] - if lt == nil { - return canonicalBytes, nil // unsupported floor: best-effort passthrough - } - // Top-level constructors that are not in the canonical tg schema are MTProto - // control/error objects (mt.*, e.g. rpc_error) — layer-invariant, so pass - // them through. A nested unknown id is still a hard error (real gap). - if id, err := (&bin.Buffer{Buf: canonicalBytes}).PeekID(); err != nil || canonical.byCRC[id] == nil { - return canonicalBytes, nil - } - in := &bin.Buffer{Buf: canonicalBytes} - out := &bin.Buffer{} - walk := newWalkState() - if err := lt.transcodeObject(in, out, layer, 1, walk); err != nil { - return nil, classifyWalkError(err) - } - if in.Len() != 0 { - return nil, malformedf("%d trailing bytes after transcode to layer %d", in.Len(), layer) - } - return out.Buf, nil -} - -// UpgradeMethodCRC maps an old client's method constructor id to the canonical -// (227) id when the request body is byte-compatible — i.e. swapping the leading -// 4-byte id yields a valid 227 request. It unifies two sources: generated -// official layer drift (inboundMethodUpgrades) and hand-maintained client -// constructor drift (clientMethodAliases). Returns ok=false for unchanged -// methods and for changes that need a real decode (those stay as rpc handlers). -func UpgradeMethodCRC(oldID uint32) (uint32, bool) { - if newID, ok := inboundMethodUpgrades[oldID]; ok { - return newID, true - } - newID, ok := clientMethodAliases[oldID] - return newID, ok -} - -func (lt *layerTables) transcodeObject(in, out *bin.Buffer, layer, depth int, walk *walkState) error { - if err := walk.enter(depth, "constructor"); err != nil { - return err - } - id, err := in.PeekID() - if err != nil { - return err - } - cl, ok := canonical.byCRC[id] - if !ok { - return fmt.Errorf("layerwire: unknown constructor %#08x", id) - } - if rule := lt.rules[id]; rule != nil { - if err := in.ConsumeID(id); err != nil { - return err - } - if rule.structural != "" { - fn := structuralTransforms[rule.structural] - if fn == nil { - return fmt.Errorf("layerwire: no structural transform %q for %s@%d", rule.structural, cl.name, layer) - } - return fn(cl, rule.target, in, out, layer, depth, walk) - } - out.PutID(rule.target) - return lt.transcodeBody(in, out, cl, rule.keep, layer, depth, walk) - } - if lt.newTypes[id] { - fn := newTypeFallbacks[id] - if fn == nil { - fn = newTypeFallbacksByType[cl.result] - } - if fn == nil { - return fmt.Errorf("layerwire: %s (%#08x) absent at layer %d and no fallback", cl.name, id, layer) - } - return fn(cl, in, out, layer, depth, walk) - } - if !lt.dirty[id] { - // Unaffected subtree: byte-for-byte copy. - pre := in.Buf - if err := in.ConsumeID(id); err != nil { - return err - } - if err := walk.skipCtorBody(canonical, in, cl, depth); err != nil { - return err - } - out.Put(pre[:len(pre)-len(in.Buf)]) - return nil - } - // Unchanged at this level but a descendant is dirty: keep CRC, recurse. - if err := in.ConsumeID(id); err != nil { - return err - } - out.PutID(id) - return lt.transcodeBody(in, out, cl, nil, layer, depth, walk) -} - -// transcodeBody re-encodes a constructor body. keep==nil means retain every -// field (recursing into dirty descendants); otherwise only the named canonical -// fields are written, flag integers are remasked to the retained bits, and -// dropped fields are read-and-discarded. -func (lt *layerTables) transcodeBody(in, out *bin.Buffer, cl *ctorLayout, keep map[string]bool, layer, depth int, walk *walkState) error { - kept := func(name string) bool { return keep == nil || keep[name] } - var flags map[string]uint32 - for i := range cl.fields { - f := &cl.fields[i] - if f.isFlags { - v, err := in.Uint32() - if err != nil { - return fmt.Errorf("%s.%s: %w", cl.name, f.name, err) - } - if flags == nil { - flags = make(map[string]uint32, 2) - } - flags[f.name] = v - if kept(f.name) { - out.PutUint32(v & lt.keptMask(cl, f.name, kept)) - } - continue - } - present := !f.conditional() || flags[f.flagName]&(1< walk.limits.maxDepth { - return limitf("vector nesting depth %d exceeds limit %d", vectorDepth, walk.limits.maxDepth) - } - if f.kind == kindVector { - id, err := in.Uint32() - if err != nil { - return err - } - if id != vectorTypeID { - return fmt.Errorf("expected vector id, got %#08x", id) - } - out.PutUint32(vectorTypeID) - } - n, err := in.Int() - if err != nil { - return err - } - if n < 0 { - return malformedf("negative vector length %d", n) - } - if max := walk.vectorLimit(owner, f); n > max { - return limitf("vector %s.%s length %d exceeds limit %d", ownerName(owner), fieldName(f), n, max) - } - if err := walk.addUnits(n, "vector "+ownerName(owner)+"."+fieldName(f)); err != nil { - return err - } - out.PutInt(n) - for i := 0; i < n; i++ { - if err := lt.transcodeValue(in, out, f.elem, nil, layer, vectorDepth, walk); err != nil { - return err - } - } - return nil - case kindObject: - return lt.transcodeObject(in, out, layer, depth+1, walk) - case kindBareObject: - bareDepth := depth + 1 - if err := walk.enter(bareDepth, "bare constructor"); err != nil { - return err - } - cl, ok := canonical.bareByT[f.typeName] - if !ok { - return fmt.Errorf("unknown bare type %q", f.typeName) - } - // Bare objects have no CRC and (within 220..227) no changed bare ctor; - // recurse all-kept to reach any dirty descendants. - return lt.transcodeBody(in, out, cl, nil, layer, bareDepth, walk) - default: - // Primitive marked dirty should be impossible. - return fmt.Errorf("unexpected dirty primitive kind %d", f.kind) - } -} diff --git a/internal/compat/layerwire/tables_gen.go b/internal/compat/layerwire/tables_gen.go deleted file mode 100644 index 2f271e73..00000000 --- a/internal/compat/layerwire/tables_gen.go +++ /dev/null @@ -1,388 +0,0 @@ -// Code generated by ./internal/compat/layerwire/gen; DO NOT EDIT. -// Source: gotd canonical schema (Layer 227) diffed against TDesktop api.tl@N. - -package layerwire - -// generatedTables maps a supported client layer to its canonical(227)->layer -// downgrade table. See docs/layer-compat-220-227-design.md. -var generatedTables = map[int]layerRaw{ - 220: { - rules: map[uint32]ruleRaw{ - 0x02b78156: {target: 0xc9662d05, keep: []string{"flags", "name_requested", "username_requested", "photo_requested", "text", "button_id", "peer_type", "max_quantity"}}, // inputKeyboardButtonRequestPeer - 0x033ed001: {target: 0xcd64636c, keep: []string{"flags", "bot_id", "recipients", "rights"}}, // connectedBot - 0x0360d5d2: {target: 0xa0933f5b, keep: []string{"user_id", "inviter_id", "date"}}, // chatParticipantAdmin - 0x06cbe645: {target: 0xa02bc13e, keep: []string{"flags", "blocked", "phone_calls_available", "phone_calls_private", "can_pin_message", "has_scheduled", "video_calls_available", "voice_messages_forbidden", "translations_disabled", "stories_pinned_available", "blocked_my_stories_from", "wallpaper_overridden", "contact_require_premium", "read_dates_private", "flags2", "sponsored_enabled", "can_view_revenue", "bot_can_manage_emoji_status", "display_gifts_button", "id", "about", "settings", "personal_photo", "profile_photo", "fallback_photo", "notify_settings", "bot_info", "pinned_msg_id", "common_chats_count", "folder_id", "ttl_period", "theme", "private_forward_name", "bot_group_admin_rights", "bot_broadcast_admin_rights", "wallpaper", "stories", "business_work_hours", "business_location", "business_greeting_message", "business_away_message", "business_intro", "birthday", "personal_channel_id", "personal_channel_message", "stargifts_count", "starref_program", "bot_verification", "send_paid_messages_stars", "disallowed_gifts", "stars_rating", "stars_my_pending_rating", "stars_my_pending_rating_date", "main_tab", "saved_music", "note"}}, // userFull - 0x08cbec07: {target: 0x3f7ee58b, keep: []string{"value", "emoticon"}}, // messageMediaDice - 0x15031189: {target: 0x5e068047, structural: "pageListOrderedItemText"}, // field "num": conditional-ness changed - 0x16a4b93c: {target: 0xedf164f1, keep: []string{"flags", "pinned", "public", "close_friends", "min", "noforwards", "edited", "contacts", "selected_contacts", "out", "id", "date", "from_id", "fwd_from", "expire_date", "caption", "entities", "media", "media_areas", "privacy", "views", "sent_reaction", "albums"}}, // storyItem - 0x1b97dd66: {target: 0x6917560b, keep: []string{"flags", "reply_to_scheduled", "forum_topic", "quote", "reply_to_msg_id", "reply_to_peer_id", "reply_from", "reply_media", "reply_to_top_id", "quote_text", "quote_entities", "quote_offset", "todo_item_id"}}, // messageReplyHeader - 0x1bd54456: {target: 0xcb397619, keep: []string{"flags", "user_id", "date", "subscription_until_date"}}, // channelParticipant - 0x1fd6f6c1: {target: 0x9a8ae1e1, keep: []string{"items"}}, // pageBlockOrderedList - 0x2f58683c: {target: 0xb92fb6cd, keep: []string{"text"}}, // pageListItemText - 0x3645230a: {target: 0x3b6ddad2, structural: "pollAnswerVoters"}, // field "voters": conditional-ness changed - 0x38e79fde: {target: 0xc02d4007, keep: []string{"user_id", "inviter_id", "date"}}, // chatParticipant - 0x3bd4b7c2: {target: 0x869fbe10, keep: []string{"flags", "reply_to_msg_id", "top_msg_id", "reply_to_peer_id", "quote_text", "quote_entities", "quote_offset", "monoforum_peer_id", "todo_item_id"}}, // inputReplyToMessage - 0x3cd623ec: {target: 0x92d33a0e, keep: []string{"flags", "request_write_access", "bot", "domain"}}, // urlAuthResultRequest - 0x3fa53905: {target: 0xafd93fbb, keep: []string{"text"}}, // keyboardButtonBuy - 0x3fc18057: {target: 0x9bb2636d, keep: []string{"flags", "restore", "phone_number", "phone_code_hash", "currency", "amount"}}, // inputStorePaymentAuthCode - 0x417efd8f: {target: 0xb16a6c29, keep: []string{"text"}}, // keyboardButtonRequestPhone - 0x41df43fc: {target: 0xead6805e, keep: []string{"flags", "name_hidden", "unsaved", "refunded", "can_upgrade", "pinned_to_top", "upgrade_separate", "from_id", "date", "gift", "message", "msg_id", "saved_id", "convert_stars", "upgrade_stars", "can_export_at", "transfer_stars", "can_transfer_at", "can_resell_at", "collection_id", "prepaid_upgrade_hash", "drop_original_details_stars", "gift_num"}}, // savedStarGift - 0x4b7d786a: {target: 0xff16e2ca, keep: []string{"text", "option"}}, // pollAnswer - 0x4e7085ea: {target: 0x13acff19, structural: "starGiftAttributePattern"}, // target field "rarity_permille" not found in canonical (reorder/insert) - 0x565251e2: {target: 0x39d99013, structural: "starGiftAttributeModel"}, // target field "rarity_permille" not found in canonical (reorder/insert) - 0x5b0f15f5: {target: 0x53d7bfd8, keep: []string{"text", "button_id", "peer_type", "max_quantity"}}, // keyboardButtonRequestPeer - 0x60fe3294: {target: 0x96eaa5eb, keep: []string{"flags", "no_webpage", "invert_media", "reply_to", "message", "entities", "media", "date", "effect", "suggested_post"}}, // draftMessage - 0x623a8fa0: {target: 0x8f8c0e4e, structural: "urlAuthResultAccepted"}, // field "url": conditional-ness changed - 0x63ca67aa: {target: 0x25e073fc, keep: []string{"blocks"}}, // pageListItemBlocks - 0x68013e72: {target: 0xd02e7fd4, keep: []string{"flags", "request_write_access", "text", "fwd_text", "url", "bot"}}, // inputKeyboardButtonUrlAuth - 0x71e4ea58: {target: 0x56e34970, keep: []string{"flags", "messages_notify_from", "stories_notify_from", "sound", "show_previews"}}, // reactionsNotifySettings - 0x7600b9d3: {target: 0xb92f76cf, keep: []string{"flags", "out", "mentioned", "media_unread", "silent", "post", "from_scheduled", "legacy", "edit_hide", "pinned", "noforwards", "invert_media", "flags2", "offline", "video_processing_pending", "paid_suggested_post_stars", "paid_suggested_post_ton", "id", "from_id", "from_boosts_applied", "peer_id", "saved_peer_id", "fwd_from", "via_bot_id", "via_business_bot_id", "reply_to", "date", "message", "media", "reply_markup", "entities", "views", "forwards", "replies", "edit_date", "post_author", "grouped_id", "reactions", "restriction_reason", "ttl_period", "quick_reply_shortcut_id", "effect", "factcheck", "report_delivery_until_date", "paid_message_stars", "suggested_post", "schedule_repeat_period"}}, // message - 0x7699f014: {target: 0x24f40e77, keep: []string{"poll_id", "peer", "options", "qts"}}, // updateMessagePollVote - 0x773f4e66: {target: 0x4bd6e798, keep: []string{"poll", "results"}}, // messageMediaPoll - 0x7a11d782: {target: 0xbbc7515d, keep: []string{"flags", "quiz", "text"}}, // keyboardButtonRequestPoll - 0x7cb34d79: {target: 0x11dfa986, keep: []string{"peer", "date", "user_id", "about", "invite", "qts"}}, // updateBotChatInviteRequester - 0x7d170cff: {target: 0xa2fa4880, keep: []string{"text"}}, // keyboardButton - 0x7d5e07c7: {target: 0xe988037b, keep: []string{"text", "user_id"}}, // inputKeyboardButtonUserProfile - 0x7d8375da: {target: 0x1e287d04, keep: []string{"flags", "spoiler", "file", "stickers", "ttl_seconds"}}, // inputMediaUploadedPhoto - 0x85f0a9cd: {target: 0x569d64c9, keep: []string{"flags", "require_premium", "resale_ton_only", "theme_available", "id", "gift_id", "title", "slug", "num", "owner_id", "owner_name", "owner_address", "attributes", "availability_issued", "availability_total", "gift_address", "resell_amount", "released_by", "value_amount", "value_currency", "value_usd_amount", "theme_peer", "peer_color", "host_id", "offer_min_stars"}}, // starGiftUnique - 0x883a4108: {target: 0x0f94e5f1, structural: "inputMediaPoll"}, // field "correct_answers": type changed Vector->Vector - 0x89c590f9: {target: 0x50f41ccf, keep: []string{"text"}}, // keyboardButtonGame - 0x8ff2d5f0: {target: 0x98dd8936, structural: "pageListOrderedItemBlocks"}, // field "num": conditional-ness changed - 0x966e2dbf: {target: 0x58747131, keep: []string{"id", "flags", "closed", "public_voters", "multiple_choice", "quiz", "question", "answers", "close_period", "close_date"}}, // poll - 0x991399fc: {target: 0x93b9fbb5, keep: []string{"flags", "same_peer", "text", "query", "peer_types"}}, // keyboardButtonSwitchInline - 0x9f2504e4: {target: 0xd93d859c, structural: "starGiftAttributeBackdrop"}, // target field "rarity_permille" not found in canonical (reorder/insert) - 0xa04e8d3a: {target: 0xe4e0b29d, keep: []string{"flags", "can_view_participants", "can_set_username", "can_set_stickers", "hidden_prehistory", "can_set_location", "has_scheduled", "can_view_stats", "blocked", "flags2", "can_delete_channel", "antispam", "participants_hidden", "translations_disabled", "stories_pinned_available", "view_forum_as_messages", "restricted_sponsored", "can_view_revenue", "paid_media_allowed", "can_view_stars_revenue", "paid_reactions_available", "stargifts_available", "paid_messages_available", "id", "about", "participants_count", "admins_count", "kicked_count", "banned_count", "online_count", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "chat_photo", "notify_settings", "exported_invite", "bot_info", "migrated_from_chat_id", "migrated_from_max_id", "pinned_msg_id", "stickerset", "available_min_id", "folder_id", "linked_chat_id", "location", "slowmode_seconds", "slowmode_next_send_date", "stats_dc", "pts", "call", "ttl_period", "pending_suggestions", "groupcall_default_join_as", "theme_emoticon", "requests_pending", "recent_requesters", "default_send_as", "available_reactions", "reactions_limit", "stories", "wallpaper", "boosts_applied", "boosts_unrestrict", "emojiset", "bot_verification", "stargifts_count", "send_paid_messages_stars", "main_tab"}}, // channelFull - 0xa9478a1a: {target: 0x4f607bef, keep: []string{"flags", "via_request", "user_id", "inviter_id", "date", "subscription_until_date"}}, // channelParticipantSelf - 0xaa40f94d: {target: 0xfc796b3f, keep: []string{"text"}}, // keyboardButtonRequestGeoLocation - 0xba7bb15e: {target: 0x7adf2420, keep: []string{"flags", "min", "results", "total_voters", "recent_voters", "solution", "solution_entities"}}, // pollResults - 0xbcc4af10: {target: 0x75d2698e, keep: []string{"text", "copy_text"}}, // keyboardButtonCopy - 0xc0fd5d09: {target: 0x308660c1, keep: []string{"text", "user_id"}}, // keyboardButtonUserProfile - 0xd5f0ad91: {target: 0x6df8014e, keep: []string{"flags", "left", "peer", "kicked_by", "date", "banned_rights"}}, // channelParticipantBanned - 0xd64c522b: {target: 0xaca1657b, keep: []string{"flags", "poll_id", "poll", "results"}}, // updateMessagePoll - 0xd80c25ec: {target: 0x258aff05, keep: []string{"text", "url"}}, // keyboardButtonUrl - 0xe15c4370: {target: 0xa0c0505c, keep: []string{"text", "url"}}, // keyboardButtonSimpleWebView - 0xe1f867b8: {target: 0xe46bcee4, keep: []string{"user_id"}}, // chatParticipantCreator - 0xe216eb63: {target: 0x695150d7, keep: []string{"flags", "spoiler", "photo", "ttl_seconds"}}, // messageMediaPhoto - 0xe3af4434: {target: 0xb3ba0635, keep: []string{"flags", "spoiler", "id", "ttl_seconds"}}, // inputMediaPhoto - 0xe62bc960: {target: 0x35bbdb6b, keep: []string{"flags", "requires_password", "text", "data"}}, // keyboardButtonCallback - 0xe6c31522: {target: 0x95728543, keep: []string{"flags", "upgrade", "transferred", "saved", "refunded", "prepaid_upgrade", "assigned", "from_offer", "gift", "can_export_at", "transfer_stars", "from_id", "peer", "saved_id", "resale_amount", "can_transfer_at", "can_resell_at", "drop_original_details_stars"}}, // messageActionStarGiftUnique - 0xe846b1a0: {target: 0x13767230, keep: []string{"text", "url"}}, // keyboardButtonWebView - 0xf51006f9: {target: 0x10b78d29, keep: []string{"flags", "text", "fwd_text", "url", "button_id"}}, // keyboardButtonUrlAuth - 0xf8827ebf: {target: 0xe0955a3c, keep: []string{"store_product", "phone_code_hash", "support_email_address", "support_email_subject", "currency", "amount"}}, // auth.sentCodePaymentRequired - 0xfc89f7f3: {target: 0xd58a08c6, keep: []string{"flags", "pinned", "unread_mark", "view_forum_as_messages", "peer", "top_message", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "unread_mentions_count", "unread_reactions_count", "notify_settings", "pts", "draft", "folder_id", "ttl_period"}}, // dialog - 0xfcdad815: {target: 0xcdff0eca, keep: []string{"flags", "my", "closed", "pinned", "short", "hidden", "title_missing", "id", "date", "peer", "title", "icon_color", "icon_emoji_id", "top_message", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "unread_mentions_count", "unread_reactions_count", "from_id", "notify_settings", "draft"}}, // forumTopic - }, - newTypes: []uint32{ - 0x004b572c, 0x01a9fbfc, 0x02ff29d3, 0x0652c1c5, 0x0773c080, 0x096b2aec, - 0x0a617e7b, 0x0e6e47c4, 0x0efa0194, 0x140502d1, 0x16605e3e, 0x199fed96, - 0x1fa01357, 0x1fe9a9bf, 0x24c26789, 0x2999beed, 0x2f51c337, 0x36437737, - 0x399674dc, 0x3c29a3e2, 0x3c60b621, 0x3e2793ba, 0x3e81e078, 0x402b4495, - 0x445663a7, 0x44e56023, 0x4880ed9a, 0x4c2a5d62, 0x4fdd3430, 0x519524ea, - 0x574b617f, 0x5806b4ec, 0x59080c20, 0x59e65335, 0x5b1ccb28, 0x67e731ad, - 0x682a41a9, 0x6c24f3dd, 0x6c9d0efe, 0x71777116, 0x7781fe18, 0x78fbf3a8, - 0x79eb8cb3, 0x7b9e1801, 0x83281dbd, 0x8c0f91fb, 0x904ac7c7, 0x90d7adfa, - 0x933ca597, 0x98a3a840, 0x9b00622b, 0x9bad6414, 0x9d2eac97, 0x9da1cd6c, - 0xa26156c0, 0xa2cb24f9, 0xa5b45e2b, 0xac072444, 0xac6a83aa, 0xae152a69, - 0xb07ed085, 0xb22083a6, 0xb43df56c, 0xb532772b, 0xb956812d, 0xbaf39d8b, - 0xbaff072f, 0xbd8367b9, 0xbdac7e70, 0xbf7d6572, 0xc1f46103, 0xc31c8f4e, - 0xc39a2ade, 0xc556a45d, 0xc6c1e5a7, 0xcd24cf44, 0xcdd4093d, 0xcef7e7a8, - 0xcff63ea9, 0xd6e3b813, 0xda2ad647, 0xdacb836a, 0xdbbe6c6a, 0xdbce6389, - 0xdd1fbf93, 0xe188503b, 0xe2b23b51, 0xe4c449fc, 0xf08d516b, 0xf13bbcd7, - 0xf1d628ec, 0xf3a9244a, 0xfa2bc90a, 0xfb9c547a, - }, - }, - 221: { - rules: map[uint32]ruleRaw{ - 0x02b78156: {target: 0xc9662d05, keep: []string{"flags", "name_requested", "username_requested", "photo_requested", "text", "button_id", "peer_type", "max_quantity"}}, // inputKeyboardButtonRequestPeer - 0x033ed001: {target: 0xcd64636c, keep: []string{"flags", "bot_id", "recipients", "rights"}}, // connectedBot - 0x0360d5d2: {target: 0xa0933f5b, keep: []string{"user_id", "inviter_id", "date"}}, // chatParticipantAdmin - 0x06cbe645: {target: 0xa02bc13e, keep: []string{"flags", "blocked", "phone_calls_available", "phone_calls_private", "can_pin_message", "has_scheduled", "video_calls_available", "voice_messages_forbidden", "translations_disabled", "stories_pinned_available", "blocked_my_stories_from", "wallpaper_overridden", "contact_require_premium", "read_dates_private", "flags2", "sponsored_enabled", "can_view_revenue", "bot_can_manage_emoji_status", "display_gifts_button", "id", "about", "settings", "personal_photo", "profile_photo", "fallback_photo", "notify_settings", "bot_info", "pinned_msg_id", "common_chats_count", "folder_id", "ttl_period", "theme", "private_forward_name", "bot_group_admin_rights", "bot_broadcast_admin_rights", "wallpaper", "stories", "business_work_hours", "business_location", "business_greeting_message", "business_away_message", "business_intro", "birthday", "personal_channel_id", "personal_channel_message", "stargifts_count", "starref_program", "bot_verification", "send_paid_messages_stars", "disallowed_gifts", "stars_rating", "stars_my_pending_rating", "stars_my_pending_rating_date", "main_tab", "saved_music", "note"}}, // userFull - 0x15031189: {target: 0x5e068047, structural: "pageListOrderedItemText"}, // field "num": conditional-ness changed - 0x16a4b93c: {target: 0xedf164f1, keep: []string{"flags", "pinned", "public", "close_friends", "min", "noforwards", "edited", "contacts", "selected_contacts", "out", "id", "date", "from_id", "fwd_from", "expire_date", "caption", "entities", "media", "media_areas", "privacy", "views", "sent_reaction", "albums"}}, // storyItem - 0x1b97dd66: {target: 0x6917560b, keep: []string{"flags", "reply_to_scheduled", "forum_topic", "quote", "reply_to_msg_id", "reply_to_peer_id", "reply_from", "reply_media", "reply_to_top_id", "quote_text", "quote_entities", "quote_offset", "todo_item_id"}}, // messageReplyHeader - 0x1bd54456: {target: 0xcb397619, keep: []string{"flags", "user_id", "date", "subscription_until_date"}}, // channelParticipant - 0x1fd6f6c1: {target: 0x9a8ae1e1, keep: []string{"items"}}, // pageBlockOrderedList - 0x2f58683c: {target: 0xb92fb6cd, keep: []string{"text"}}, // pageListItemText - 0x3645230a: {target: 0x3b6ddad2, structural: "pollAnswerVoters"}, // field "voters": conditional-ness changed - 0x38e79fde: {target: 0xc02d4007, keep: []string{"user_id", "inviter_id", "date"}}, // chatParticipant - 0x3bd4b7c2: {target: 0x869fbe10, keep: []string{"flags", "reply_to_msg_id", "top_msg_id", "reply_to_peer_id", "quote_text", "quote_entities", "quote_offset", "monoforum_peer_id", "todo_item_id"}}, // inputReplyToMessage - 0x3cd623ec: {target: 0x92d33a0e, keep: []string{"flags", "request_write_access", "bot", "domain"}}, // urlAuthResultRequest - 0x3fa53905: {target: 0xafd93fbb, keep: []string{"text"}}, // keyboardButtonBuy - 0x3fc18057: {target: 0x9bb2636d, keep: []string{"flags", "restore", "phone_number", "phone_code_hash", "currency", "amount"}}, // inputStorePaymentAuthCode - 0x417efd8f: {target: 0xb16a6c29, keep: []string{"text"}}, // keyboardButtonRequestPhone - 0x41df43fc: {target: 0xead6805e, keep: []string{"flags", "name_hidden", "unsaved", "refunded", "can_upgrade", "pinned_to_top", "upgrade_separate", "from_id", "date", "gift", "message", "msg_id", "saved_id", "convert_stars", "upgrade_stars", "can_export_at", "transfer_stars", "can_transfer_at", "can_resell_at", "collection_id", "prepaid_upgrade_hash", "drop_original_details_stars", "gift_num"}}, // savedStarGift - 0x4b7d786a: {target: 0xff16e2ca, keep: []string{"text", "option"}}, // pollAnswer - 0x4e7085ea: {target: 0x13acff19, structural: "starGiftAttributePattern"}, // target field "rarity_permille" not found in canonical (reorder/insert) - 0x565251e2: {target: 0x39d99013, structural: "starGiftAttributeModel"}, // target field "rarity_permille" not found in canonical (reorder/insert) - 0x5b0f15f5: {target: 0x53d7bfd8, keep: []string{"text", "button_id", "peer_type", "max_quantity"}}, // keyboardButtonRequestPeer - 0x60fe3294: {target: 0x96eaa5eb, keep: []string{"flags", "no_webpage", "invert_media", "reply_to", "message", "entities", "media", "date", "effect", "suggested_post"}}, // draftMessage - 0x623a8fa0: {target: 0x8f8c0e4e, structural: "urlAuthResultAccepted"}, // field "url": conditional-ness changed - 0x63ca67aa: {target: 0x25e073fc, keep: []string{"blocks"}}, // pageListItemBlocks - 0x68013e72: {target: 0xd02e7fd4, keep: []string{"flags", "request_write_access", "text", "fwd_text", "url", "bot"}}, // inputKeyboardButtonUrlAuth - 0x71e4ea58: {target: 0x56e34970, keep: []string{"flags", "messages_notify_from", "stories_notify_from", "sound", "show_previews"}}, // reactionsNotifySettings - 0x7600b9d3: {target: 0x9cb490e9, keep: []string{"flags", "out", "mentioned", "media_unread", "silent", "post", "from_scheduled", "legacy", "edit_hide", "pinned", "noforwards", "invert_media", "flags2", "offline", "video_processing_pending", "paid_suggested_post_stars", "paid_suggested_post_ton", "id", "from_id", "from_boosts_applied", "peer_id", "saved_peer_id", "fwd_from", "via_bot_id", "via_business_bot_id", "reply_to", "date", "message", "media", "reply_markup", "entities", "views", "forwards", "replies", "edit_date", "post_author", "grouped_id", "reactions", "restriction_reason", "ttl_period", "quick_reply_shortcut_id", "effect", "factcheck", "report_delivery_until_date", "paid_message_stars", "suggested_post", "schedule_repeat_period", "summary_from_language"}}, // message - 0x7699f014: {target: 0x24f40e77, keep: []string{"poll_id", "peer", "options", "qts"}}, // updateMessagePollVote - 0x773f4e66: {target: 0x4bd6e798, keep: []string{"poll", "results"}}, // messageMediaPoll - 0x7a11d782: {target: 0xbbc7515d, keep: []string{"flags", "quiz", "text"}}, // keyboardButtonRequestPoll - 0x7cb34d79: {target: 0x11dfa986, keep: []string{"peer", "date", "user_id", "about", "invite", "qts"}}, // updateBotChatInviteRequester - 0x7d170cff: {target: 0xa2fa4880, keep: []string{"text"}}, // keyboardButton - 0x7d5e07c7: {target: 0xe988037b, keep: []string{"text", "user_id"}}, // inputKeyboardButtonUserProfile - 0x7d8375da: {target: 0x1e287d04, keep: []string{"flags", "spoiler", "file", "stickers", "ttl_seconds"}}, // inputMediaUploadedPhoto - 0x85f0a9cd: {target: 0x569d64c9, keep: []string{"flags", "require_premium", "resale_ton_only", "theme_available", "id", "gift_id", "title", "slug", "num", "owner_id", "owner_name", "owner_address", "attributes", "availability_issued", "availability_total", "gift_address", "resell_amount", "released_by", "value_amount", "value_currency", "value_usd_amount", "theme_peer", "peer_color", "host_id", "offer_min_stars"}}, // starGiftUnique - 0x883a4108: {target: 0x0f94e5f1, structural: "inputMediaPoll"}, // field "correct_answers": type changed Vector->Vector - 0x89c590f9: {target: 0x50f41ccf, keep: []string{"text"}}, // keyboardButtonGame - 0x8ff2d5f0: {target: 0x98dd8936, structural: "pageListOrderedItemBlocks"}, // field "num": conditional-ness changed - 0x966e2dbf: {target: 0x58747131, keep: []string{"id", "flags", "closed", "public_voters", "multiple_choice", "quiz", "question", "answers", "close_period", "close_date"}}, // poll - 0x991399fc: {target: 0x93b9fbb5, keep: []string{"flags", "same_peer", "text", "query", "peer_types"}}, // keyboardButtonSwitchInline - 0x9f2504e4: {target: 0xd93d859c, structural: "starGiftAttributeBackdrop"}, // target field "rarity_permille" not found in canonical (reorder/insert) - 0xa04e8d3a: {target: 0xe4e0b29d, keep: []string{"flags", "can_view_participants", "can_set_username", "can_set_stickers", "hidden_prehistory", "can_set_location", "has_scheduled", "can_view_stats", "blocked", "flags2", "can_delete_channel", "antispam", "participants_hidden", "translations_disabled", "stories_pinned_available", "view_forum_as_messages", "restricted_sponsored", "can_view_revenue", "paid_media_allowed", "can_view_stars_revenue", "paid_reactions_available", "stargifts_available", "paid_messages_available", "id", "about", "participants_count", "admins_count", "kicked_count", "banned_count", "online_count", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "chat_photo", "notify_settings", "exported_invite", "bot_info", "migrated_from_chat_id", "migrated_from_max_id", "pinned_msg_id", "stickerset", "available_min_id", "folder_id", "linked_chat_id", "location", "slowmode_seconds", "slowmode_next_send_date", "stats_dc", "pts", "call", "ttl_period", "pending_suggestions", "groupcall_default_join_as", "theme_emoticon", "requests_pending", "recent_requesters", "default_send_as", "available_reactions", "reactions_limit", "stories", "wallpaper", "boosts_applied", "boosts_unrestrict", "emojiset", "bot_verification", "stargifts_count", "send_paid_messages_stars", "main_tab"}}, // channelFull - 0xa9478a1a: {target: 0x4f607bef, keep: []string{"flags", "via_request", "user_id", "inviter_id", "date", "subscription_until_date"}}, // channelParticipantSelf - 0xaa40f94d: {target: 0xfc796b3f, keep: []string{"text"}}, // keyboardButtonRequestGeoLocation - 0xba7bb15e: {target: 0x7adf2420, keep: []string{"flags", "min", "results", "total_voters", "recent_voters", "solution", "solution_entities"}}, // pollResults - 0xbcc4af10: {target: 0x75d2698e, keep: []string{"text", "copy_text"}}, // keyboardButtonCopy - 0xc0fd5d09: {target: 0x308660c1, keep: []string{"text", "user_id"}}, // keyboardButtonUserProfile - 0xd5f0ad91: {target: 0x6df8014e, keep: []string{"flags", "left", "peer", "kicked_by", "date", "banned_rights"}}, // channelParticipantBanned - 0xd64c522b: {target: 0xaca1657b, keep: []string{"flags", "poll_id", "poll", "results"}}, // updateMessagePoll - 0xd80c25ec: {target: 0x258aff05, keep: []string{"text", "url"}}, // keyboardButtonUrl - 0xe15c4370: {target: 0xa0c0505c, keep: []string{"text", "url"}}, // keyboardButtonSimpleWebView - 0xe1f867b8: {target: 0xe46bcee4, keep: []string{"user_id"}}, // chatParticipantCreator - 0xe216eb63: {target: 0x695150d7, keep: []string{"flags", "spoiler", "photo", "ttl_seconds"}}, // messageMediaPhoto - 0xe3af4434: {target: 0xb3ba0635, keep: []string{"flags", "spoiler", "id", "ttl_seconds"}}, // inputMediaPhoto - 0xe62bc960: {target: 0x35bbdb6b, keep: []string{"flags", "requires_password", "text", "data"}}, // keyboardButtonCallback - 0xe6c31522: {target: 0x95728543, keep: []string{"flags", "upgrade", "transferred", "saved", "refunded", "prepaid_upgrade", "assigned", "from_offer", "gift", "can_export_at", "transfer_stars", "from_id", "peer", "saved_id", "resale_amount", "can_transfer_at", "can_resell_at", "drop_original_details_stars"}}, // messageActionStarGiftUnique - 0xe846b1a0: {target: 0x13767230, keep: []string{"text", "url"}}, // keyboardButtonWebView - 0xf51006f9: {target: 0x10b78d29, keep: []string{"flags", "text", "fwd_text", "url", "button_id"}}, // keyboardButtonUrlAuth - 0xf8827ebf: {target: 0xe0955a3c, keep: []string{"store_product", "phone_code_hash", "support_email_address", "support_email_subject", "currency", "amount"}}, // auth.sentCodePaymentRequired - 0xfc89f7f3: {target: 0xd58a08c6, keep: []string{"flags", "pinned", "unread_mark", "view_forum_as_messages", "peer", "top_message", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "unread_mentions_count", "unread_reactions_count", "notify_settings", "pts", "draft", "folder_id", "ttl_period"}}, // dialog - 0xfcdad815: {target: 0xcdff0eca, keep: []string{"flags", "my", "closed", "pinned", "short", "hidden", "title_missing", "id", "date", "peer", "title", "icon_color", "icon_emoji_id", "top_message", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "unread_mentions_count", "unread_reactions_count", "from_id", "notify_settings", "draft"}}, // forumTopic - }, - newTypes: []uint32{ - 0x004b572c, 0x01a9fbfc, 0x02ff29d3, 0x0652c1c5, 0x0773c080, 0x096b2aec, - 0x0a617e7b, 0x0e6e47c4, 0x0efa0194, 0x140502d1, 0x16605e3e, 0x199fed96, - 0x1fa01357, 0x1fe9a9bf, 0x24c26789, 0x2999beed, 0x2f51c337, 0x36437737, - 0x399674dc, 0x3c29a3e2, 0x3c60b621, 0x3e2793ba, 0x3e81e078, 0x402b4495, - 0x445663a7, 0x4880ed9a, 0x4c2a5d62, 0x4fdd3430, 0x519524ea, 0x574b617f, - 0x5806b4ec, 0x59080c20, 0x67e731ad, 0x682a41a9, 0x6c24f3dd, 0x6c9d0efe, - 0x71777116, 0x7781fe18, 0x78fbf3a8, 0x79eb8cb3, 0x7b9e1801, 0x83281dbd, - 0x8c0f91fb, 0x904ac7c7, 0x90d7adfa, 0x933ca597, 0x98a3a840, 0x9b00622b, - 0x9bad6414, 0x9d2eac97, 0x9da1cd6c, 0xa26156c0, 0xa2cb24f9, 0xa5b45e2b, - 0xac072444, 0xac6a83aa, 0xae152a69, 0xb07ed085, 0xb22083a6, 0xb43df56c, - 0xb532772b, 0xb956812d, 0xbaf39d8b, 0xbaff072f, 0xbd8367b9, 0xbdac7e70, - 0xbf7d6572, 0xc1f46103, 0xc31c8f4e, 0xc39a2ade, 0xc556a45d, 0xc6c1e5a7, - 0xcd24cf44, 0xcdd4093d, 0xcef7e7a8, 0xcff63ea9, 0xd6e3b813, 0xdacb836a, - 0xdbbe6c6a, 0xdbce6389, 0xdd1fbf93, 0xe188503b, 0xe2b23b51, 0xe4c449fc, - 0xf08d516b, 0xf13bbcd7, 0xf1d628ec, 0xfa2bc90a, - }, - }, - 222: { - rules: map[uint32]ruleRaw{ - 0x033ed001: {target: 0xcd64636c, keep: []string{"flags", "bot_id", "recipients", "rights"}}, // connectedBot - 0x0360d5d2: {target: 0xa0933f5b, keep: []string{"user_id", "inviter_id", "date"}}, // chatParticipantAdmin - 0x06cbe645: {target: 0xa02bc13e, keep: []string{"flags", "blocked", "phone_calls_available", "phone_calls_private", "can_pin_message", "has_scheduled", "video_calls_available", "voice_messages_forbidden", "translations_disabled", "stories_pinned_available", "blocked_my_stories_from", "wallpaper_overridden", "contact_require_premium", "read_dates_private", "flags2", "sponsored_enabled", "can_view_revenue", "bot_can_manage_emoji_status", "display_gifts_button", "id", "about", "settings", "personal_photo", "profile_photo", "fallback_photo", "notify_settings", "bot_info", "pinned_msg_id", "common_chats_count", "folder_id", "ttl_period", "theme", "private_forward_name", "bot_group_admin_rights", "bot_broadcast_admin_rights", "wallpaper", "stories", "business_work_hours", "business_location", "business_greeting_message", "business_away_message", "business_intro", "birthday", "personal_channel_id", "personal_channel_message", "stargifts_count", "starref_program", "bot_verification", "send_paid_messages_stars", "disallowed_gifts", "stars_rating", "stars_my_pending_rating", "stars_my_pending_rating_date", "main_tab", "saved_music", "note"}}, // userFull - 0x15031189: {target: 0x5e068047, structural: "pageListOrderedItemText"}, // field "num": conditional-ness changed - 0x16a4b93c: {target: 0xedf164f1, keep: []string{"flags", "pinned", "public", "close_friends", "min", "noforwards", "edited", "contacts", "selected_contacts", "out", "id", "date", "from_id", "fwd_from", "expire_date", "caption", "entities", "media", "media_areas", "privacy", "views", "sent_reaction", "albums"}}, // storyItem - 0x1b97dd66: {target: 0x6917560b, keep: []string{"flags", "reply_to_scheduled", "forum_topic", "quote", "reply_to_msg_id", "reply_to_peer_id", "reply_from", "reply_media", "reply_to_top_id", "quote_text", "quote_entities", "quote_offset", "todo_item_id"}}, // messageReplyHeader - 0x1bd54456: {target: 0xcb397619, keep: []string{"flags", "user_id", "date", "subscription_until_date"}}, // channelParticipant - 0x1fd6f6c1: {target: 0x9a8ae1e1, keep: []string{"items"}}, // pageBlockOrderedList - 0x2f58683c: {target: 0xb92fb6cd, keep: []string{"text"}}, // pageListItemText - 0x3645230a: {target: 0x3b6ddad2, structural: "pollAnswerVoters"}, // field "voters": conditional-ness changed - 0x38e79fde: {target: 0xc02d4007, keep: []string{"user_id", "inviter_id", "date"}}, // chatParticipant - 0x3bd4b7c2: {target: 0x869fbe10, keep: []string{"flags", "reply_to_msg_id", "top_msg_id", "reply_to_peer_id", "quote_text", "quote_entities", "quote_offset", "monoforum_peer_id", "todo_item_id"}}, // inputReplyToMessage - 0x3cd623ec: {target: 0x32fabf1a, keep: []string{"flags", "request_write_access", "request_phone_number", "bot", "domain", "browser", "platform", "ip", "region"}}, // urlAuthResultRequest - 0x3fc18057: {target: 0x9bb2636d, keep: []string{"flags", "restore", "phone_number", "phone_code_hash", "currency", "amount"}}, // inputStorePaymentAuthCode - 0x4b7d786a: {target: 0xff16e2ca, keep: []string{"text", "option"}}, // pollAnswer - 0x60fe3294: {target: 0x96eaa5eb, keep: []string{"flags", "no_webpage", "invert_media", "reply_to", "message", "entities", "media", "date", "effect", "suggested_post"}}, // draftMessage - 0x63ca67aa: {target: 0x25e073fc, keep: []string{"blocks"}}, // pageListItemBlocks - 0x71e4ea58: {target: 0x56e34970, keep: []string{"flags", "messages_notify_from", "stories_notify_from", "sound", "show_previews"}}, // reactionsNotifySettings - 0x7600b9d3: {target: 0x9cb490e9, keep: []string{"flags", "out", "mentioned", "media_unread", "silent", "post", "from_scheduled", "legacy", "edit_hide", "pinned", "noforwards", "invert_media", "flags2", "offline", "video_processing_pending", "paid_suggested_post_stars", "paid_suggested_post_ton", "id", "from_id", "from_boosts_applied", "peer_id", "saved_peer_id", "fwd_from", "via_bot_id", "via_business_bot_id", "reply_to", "date", "message", "media", "reply_markup", "entities", "views", "forwards", "replies", "edit_date", "post_author", "grouped_id", "reactions", "restriction_reason", "ttl_period", "quick_reply_shortcut_id", "effect", "factcheck", "report_delivery_until_date", "paid_message_stars", "suggested_post", "schedule_repeat_period", "summary_from_language"}}, // message - 0x7699f014: {target: 0x24f40e77, keep: []string{"poll_id", "peer", "options", "qts"}}, // updateMessagePollVote - 0x773f4e66: {target: 0x4bd6e798, keep: []string{"poll", "results"}}, // messageMediaPoll - 0x7cb34d79: {target: 0x11dfa986, keep: []string{"peer", "date", "user_id", "about", "invite", "qts"}}, // updateBotChatInviteRequester - 0x7d8375da: {target: 0x1e287d04, keep: []string{"flags", "spoiler", "file", "stickers", "ttl_seconds"}}, // inputMediaUploadedPhoto - 0x883a4108: {target: 0x0f94e5f1, structural: "inputMediaPoll"}, // field "correct_answers": type changed Vector->Vector - 0x8ff2d5f0: {target: 0x98dd8936, structural: "pageListOrderedItemBlocks"}, // field "num": conditional-ness changed - 0x966e2dbf: {target: 0x58747131, keep: []string{"id", "flags", "closed", "public_voters", "multiple_choice", "quiz", "question", "answers", "close_period", "close_date"}}, // poll - 0xa04e8d3a: {target: 0xe4e0b29d, keep: []string{"flags", "can_view_participants", "can_set_username", "can_set_stickers", "hidden_prehistory", "can_set_location", "has_scheduled", "can_view_stats", "blocked", "flags2", "can_delete_channel", "antispam", "participants_hidden", "translations_disabled", "stories_pinned_available", "view_forum_as_messages", "restricted_sponsored", "can_view_revenue", "paid_media_allowed", "can_view_stars_revenue", "paid_reactions_available", "stargifts_available", "paid_messages_available", "id", "about", "participants_count", "admins_count", "kicked_count", "banned_count", "online_count", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "chat_photo", "notify_settings", "exported_invite", "bot_info", "migrated_from_chat_id", "migrated_from_max_id", "pinned_msg_id", "stickerset", "available_min_id", "folder_id", "linked_chat_id", "location", "slowmode_seconds", "slowmode_next_send_date", "stats_dc", "pts", "call", "ttl_period", "pending_suggestions", "groupcall_default_join_as", "theme_emoticon", "requests_pending", "recent_requesters", "default_send_as", "available_reactions", "reactions_limit", "stories", "wallpaper", "boosts_applied", "boosts_unrestrict", "emojiset", "bot_verification", "stargifts_count", "send_paid_messages_stars", "main_tab"}}, // channelFull - 0xa9478a1a: {target: 0x4f607bef, keep: []string{"flags", "via_request", "user_id", "inviter_id", "date", "subscription_until_date"}}, // channelParticipantSelf - 0xba7bb15e: {target: 0x7adf2420, keep: []string{"flags", "min", "results", "total_voters", "recent_voters", "solution", "solution_entities"}}, // pollResults - 0xd5f0ad91: {target: 0x6df8014e, keep: []string{"flags", "left", "peer", "kicked_by", "date", "banned_rights"}}, // channelParticipantBanned - 0xd64c522b: {target: 0xaca1657b, keep: []string{"flags", "poll_id", "poll", "results"}}, // updateMessagePoll - 0xe1f867b8: {target: 0xe46bcee4, keep: []string{"user_id"}}, // chatParticipantCreator - 0xe216eb63: {target: 0x695150d7, keep: []string{"flags", "spoiler", "photo", "ttl_seconds"}}, // messageMediaPhoto - 0xe3af4434: {target: 0xb3ba0635, keep: []string{"flags", "spoiler", "id", "ttl_seconds"}}, // inputMediaPhoto - 0xf8827ebf: {target: 0xe0955a3c, keep: []string{"store_product", "phone_code_hash", "support_email_address", "support_email_subject", "currency", "amount"}}, // auth.sentCodePaymentRequired - 0xfc89f7f3: {target: 0xd58a08c6, keep: []string{"flags", "pinned", "unread_mark", "view_forum_as_messages", "peer", "top_message", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "unread_mentions_count", "unread_reactions_count", "notify_settings", "pts", "draft", "folder_id", "ttl_period"}}, // dialog - 0xfcdad815: {target: 0xcdff0eca, keep: []string{"flags", "my", "closed", "pinned", "short", "hidden", "title_missing", "id", "date", "peer", "title", "icon_color", "icon_emoji_id", "top_message", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "unread_mentions_count", "unread_reactions_count", "from_id", "notify_settings", "draft"}}, // forumTopic - }, - newTypes: []uint32{ - 0x004b572c, 0x01a9fbfc, 0x02ff29d3, 0x0652c1c5, 0x0773c080, 0x096b2aec, - 0x0a617e7b, 0x0e6e47c4, 0x0efa0194, 0x140502d1, 0x16605e3e, 0x199fed96, - 0x1fa01357, 0x1fe9a9bf, 0x24c26789, 0x2999beed, 0x2f51c337, 0x399674dc, - 0x3c29a3e2, 0x3c60b621, 0x3e2793ba, 0x3e81e078, 0x402b4495, 0x445663a7, - 0x4880ed9a, 0x4c2a5d62, 0x519524ea, 0x574b617f, 0x5806b4ec, 0x59080c20, - 0x67e731ad, 0x682a41a9, 0x6c24f3dd, 0x6c9d0efe, 0x71777116, 0x7781fe18, - 0x79eb8cb3, 0x7b9e1801, 0x83281dbd, 0x8c0f91fb, 0x904ac7c7, 0x90d7adfa, - 0x933ca597, 0x98a3a840, 0x9b00622b, 0x9bad6414, 0x9d2eac97, 0x9da1cd6c, - 0xa26156c0, 0xa2cb24f9, 0xa5b45e2b, 0xac6a83aa, 0xae152a69, 0xb22083a6, - 0xb43df56c, 0xb532772b, 0xb956812d, 0xbaf39d8b, 0xbaff072f, 0xbd8367b9, - 0xbdac7e70, 0xbf7d6572, 0xc1f46103, 0xc31c8f4e, 0xc39a2ade, 0xc556a45d, - 0xc6c1e5a7, 0xcd24cf44, 0xcdd4093d, 0xcff63ea9, 0xd6e3b813, 0xdacb836a, - 0xdbbe6c6a, 0xdd1fbf93, 0xe2b23b51, 0xe4c449fc, 0xf13bbcd7, 0xf1d628ec, - 0xfa2bc90a, - }, - }, - 223: { - rules: map[uint32]ruleRaw{ - 0x033ed001: {target: 0xcd64636c, keep: []string{"flags", "bot_id", "recipients", "rights"}}, // connectedBot - 0x06cbe645: {target: 0xa02bc13e, keep: []string{"flags", "blocked", "phone_calls_available", "phone_calls_private", "can_pin_message", "has_scheduled", "video_calls_available", "voice_messages_forbidden", "translations_disabled", "stories_pinned_available", "blocked_my_stories_from", "wallpaper_overridden", "contact_require_premium", "read_dates_private", "flags2", "sponsored_enabled", "can_view_revenue", "bot_can_manage_emoji_status", "display_gifts_button", "noforwards_my_enabled", "noforwards_peer_enabled", "id", "about", "settings", "personal_photo", "profile_photo", "fallback_photo", "notify_settings", "bot_info", "pinned_msg_id", "common_chats_count", "folder_id", "ttl_period", "theme", "private_forward_name", "bot_group_admin_rights", "bot_broadcast_admin_rights", "wallpaper", "stories", "business_work_hours", "business_location", "business_greeting_message", "business_away_message", "business_intro", "birthday", "personal_channel_id", "personal_channel_message", "stargifts_count", "starref_program", "bot_verification", "send_paid_messages_stars", "disallowed_gifts", "stars_rating", "stars_my_pending_rating", "stars_my_pending_rating_date", "main_tab", "saved_music", "note"}}, // userFull - 0x15031189: {target: 0x5e068047, structural: "pageListOrderedItemText"}, // field "num": conditional-ness changed - 0x16a4b93c: {target: 0xedf164f1, keep: []string{"flags", "pinned", "public", "close_friends", "min", "noforwards", "edited", "contacts", "selected_contacts", "out", "id", "date", "from_id", "fwd_from", "expire_date", "caption", "entities", "media", "media_areas", "privacy", "views", "sent_reaction", "albums"}}, // storyItem - 0x1b97dd66: {target: 0x6917560b, keep: []string{"flags", "reply_to_scheduled", "forum_topic", "quote", "reply_to_msg_id", "reply_to_peer_id", "reply_from", "reply_media", "reply_to_top_id", "quote_text", "quote_entities", "quote_offset", "todo_item_id"}}, // messageReplyHeader - 0x1fd6f6c1: {target: 0x9a8ae1e1, keep: []string{"items"}}, // pageBlockOrderedList - 0x2f58683c: {target: 0xb92fb6cd, keep: []string{"text"}}, // pageListItemText - 0x3645230a: {target: 0x3b6ddad2, structural: "pollAnswerVoters"}, // field "voters": conditional-ness changed - 0x3bd4b7c2: {target: 0x869fbe10, keep: []string{"flags", "reply_to_msg_id", "top_msg_id", "reply_to_peer_id", "quote_text", "quote_entities", "quote_offset", "monoforum_peer_id", "todo_item_id"}}, // inputReplyToMessage - 0x3cd623ec: {target: 0xf8f8eb1e, keep: []string{"flags", "request_write_access", "request_phone_number", "match_codes_first", "bot", "domain", "browser", "platform", "ip", "region", "match_codes", "user_id_hint"}}, // urlAuthResultRequest - 0x3fc18057: {target: 0x9bb2636d, keep: []string{"flags", "restore", "phone_number", "phone_code_hash", "currency", "amount"}}, // inputStorePaymentAuthCode - 0x4b7d786a: {target: 0xff16e2ca, keep: []string{"text", "option"}}, // pollAnswer - 0x60fe3294: {target: 0x96eaa5eb, keep: []string{"flags", "no_webpage", "invert_media", "reply_to", "message", "entities", "media", "date", "effect", "suggested_post"}}, // draftMessage - 0x63ca67aa: {target: 0x25e073fc, keep: []string{"blocks"}}, // pageListItemBlocks - 0x71e4ea58: {target: 0x56e34970, keep: []string{"flags", "messages_notify_from", "stories_notify_from", "sound", "show_previews"}}, // reactionsNotifySettings - 0x7600b9d3: {target: 0x3ae56482, keep: []string{"flags", "out", "mentioned", "media_unread", "silent", "post", "from_scheduled", "legacy", "edit_hide", "pinned", "noforwards", "invert_media", "flags2", "offline", "video_processing_pending", "paid_suggested_post_stars", "paid_suggested_post_ton", "id", "from_id", "from_boosts_applied", "from_rank", "peer_id", "saved_peer_id", "fwd_from", "via_bot_id", "via_business_bot_id", "reply_to", "date", "message", "media", "reply_markup", "entities", "views", "forwards", "replies", "edit_date", "post_author", "grouped_id", "reactions", "restriction_reason", "ttl_period", "quick_reply_shortcut_id", "effect", "factcheck", "report_delivery_until_date", "paid_message_stars", "suggested_post", "schedule_repeat_period", "summary_from_language"}}, // message - 0x7699f014: {target: 0x24f40e77, keep: []string{"poll_id", "peer", "options", "qts"}}, // updateMessagePollVote - 0x773f4e66: {target: 0x4bd6e798, keep: []string{"poll", "results"}}, // messageMediaPoll - 0x7cb34d79: {target: 0x11dfa986, keep: []string{"peer", "date", "user_id", "about", "invite", "qts"}}, // updateBotChatInviteRequester - 0x7d8375da: {target: 0x1e287d04, keep: []string{"flags", "spoiler", "file", "stickers", "ttl_seconds"}}, // inputMediaUploadedPhoto - 0x883a4108: {target: 0x0f94e5f1, structural: "inputMediaPoll"}, // field "correct_answers": type changed Vector->Vector - 0x8ff2d5f0: {target: 0x98dd8936, structural: "pageListOrderedItemBlocks"}, // field "num": conditional-ness changed - 0x966e2dbf: {target: 0x58747131, keep: []string{"id", "flags", "closed", "public_voters", "multiple_choice", "quiz", "question", "answers", "close_period", "close_date"}}, // poll - 0xa04e8d3a: {target: 0xe4e0b29d, keep: []string{"flags", "can_view_participants", "can_set_username", "can_set_stickers", "hidden_prehistory", "can_set_location", "has_scheduled", "can_view_stats", "blocked", "flags2", "can_delete_channel", "antispam", "participants_hidden", "translations_disabled", "stories_pinned_available", "view_forum_as_messages", "restricted_sponsored", "can_view_revenue", "paid_media_allowed", "can_view_stars_revenue", "paid_reactions_available", "stargifts_available", "paid_messages_available", "id", "about", "participants_count", "admins_count", "kicked_count", "banned_count", "online_count", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "chat_photo", "notify_settings", "exported_invite", "bot_info", "migrated_from_chat_id", "migrated_from_max_id", "pinned_msg_id", "stickerset", "available_min_id", "folder_id", "linked_chat_id", "location", "slowmode_seconds", "slowmode_next_send_date", "stats_dc", "pts", "call", "ttl_period", "pending_suggestions", "groupcall_default_join_as", "theme_emoticon", "requests_pending", "recent_requesters", "default_send_as", "available_reactions", "reactions_limit", "stories", "wallpaper", "boosts_applied", "boosts_unrestrict", "emojiset", "bot_verification", "stargifts_count", "send_paid_messages_stars", "main_tab"}}, // channelFull - 0xba7bb15e: {target: 0x7adf2420, keep: []string{"flags", "min", "results", "total_voters", "recent_voters", "solution", "solution_entities"}}, // pollResults - 0xd64c522b: {target: 0xaca1657b, keep: []string{"flags", "poll_id", "poll", "results"}}, // updateMessagePoll - 0xe216eb63: {target: 0x695150d7, keep: []string{"flags", "spoiler", "photo", "ttl_seconds"}}, // messageMediaPhoto - 0xe3af4434: {target: 0xb3ba0635, keep: []string{"flags", "spoiler", "id", "ttl_seconds"}}, // inputMediaPhoto - 0xf8827ebf: {target: 0xe0955a3c, keep: []string{"store_product", "phone_code_hash", "support_email_address", "support_email_subject", "currency", "amount"}}, // auth.sentCodePaymentRequired - 0xfc89f7f3: {target: 0xd58a08c6, keep: []string{"flags", "pinned", "unread_mark", "view_forum_as_messages", "peer", "top_message", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "unread_mentions_count", "unread_reactions_count", "notify_settings", "pts", "draft", "folder_id", "ttl_period"}}, // dialog - 0xfcdad815: {target: 0xcdff0eca, keep: []string{"flags", "my", "closed", "pinned", "short", "hidden", "title_missing", "id", "date", "peer", "title", "icon_color", "icon_emoji_id", "top_message", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "unread_mentions_count", "unread_reactions_count", "from_id", "notify_settings", "draft"}}, // forumTopic - }, - newTypes: []uint32{ - 0x004b572c, 0x01a9fbfc, 0x02ff29d3, 0x0652c1c5, 0x0773c080, 0x096b2aec, - 0x0a617e7b, 0x0e6e47c4, 0x0efa0194, 0x140502d1, 0x16605e3e, 0x199fed96, - 0x1fa01357, 0x1fe9a9bf, 0x24c26789, 0x2999beed, 0x2f51c337, 0x399674dc, - 0x3c29a3e2, 0x3c60b621, 0x3e81e078, 0x402b4495, 0x445663a7, 0x4880ed9a, - 0x4c2a5d62, 0x519524ea, 0x574b617f, 0x59080c20, 0x67e731ad, 0x682a41a9, - 0x6c24f3dd, 0x6c9d0efe, 0x71777116, 0x7781fe18, 0x79eb8cb3, 0x7b9e1801, - 0x83281dbd, 0x8c0f91fb, 0x90d7adfa, 0x933ca597, 0x98a3a840, 0x9b00622b, - 0x9bad6414, 0x9d2eac97, 0x9da1cd6c, 0xa26156c0, 0xa2cb24f9, 0xa5b45e2b, - 0xac6a83aa, 0xae152a69, 0xb22083a6, 0xb43df56c, 0xb532772b, 0xb956812d, - 0xbaf39d8b, 0xbaff072f, 0xbdac7e70, 0xc1f46103, 0xc31c8f4e, 0xc39a2ade, - 0xc556a45d, 0xc6c1e5a7, 0xcd24cf44, 0xcdd4093d, 0xcff63ea9, 0xd6e3b813, - 0xdacb836a, 0xdbbe6c6a, 0xdd1fbf93, 0xe2b23b51, 0xe4c449fc, 0xf13bbcd7, - 0xf1d628ec, 0xfa2bc90a, - }, - }, - 224: { - rules: map[uint32]ruleRaw{ - 0x033ed001: {target: 0xcd64636c, keep: []string{"flags", "bot_id", "recipients", "rights"}}, // connectedBot - 0x15031189: {target: 0x5e068047, structural: "pageListOrderedItemText"}, // field "num": conditional-ness changed - 0x1fd6f6c1: {target: 0x9a8ae1e1, keep: []string{"items"}}, // pageBlockOrderedList - 0x2f58683c: {target: 0xb92fb6cd, keep: []string{"text"}}, // pageListItemText - 0x3fc18057: {target: 0x9bb2636d, keep: []string{"flags", "restore", "phone_number", "phone_code_hash", "currency", "amount"}}, // inputStorePaymentAuthCode - 0x60fe3294: {target: 0x96eaa5eb, keep: []string{"flags", "no_webpage", "invert_media", "reply_to", "message", "entities", "media", "date", "effect", "suggested_post"}}, // draftMessage - 0x63ca67aa: {target: 0x25e073fc, keep: []string{"blocks"}}, // pageListItemBlocks - 0x7600b9d3: {target: 0x3ae56482, keep: []string{"flags", "out", "mentioned", "media_unread", "silent", "post", "from_scheduled", "legacy", "edit_hide", "pinned", "noforwards", "invert_media", "flags2", "offline", "video_processing_pending", "paid_suggested_post_stars", "paid_suggested_post_ton", "id", "from_id", "from_boosts_applied", "from_rank", "peer_id", "saved_peer_id", "fwd_from", "via_bot_id", "via_business_bot_id", "reply_to", "date", "message", "media", "reply_markup", "entities", "views", "forwards", "replies", "edit_date", "post_author", "grouped_id", "reactions", "restriction_reason", "ttl_period", "quick_reply_shortcut_id", "effect", "factcheck", "report_delivery_until_date", "paid_message_stars", "suggested_post", "schedule_repeat_period", "summary_from_language"}}, // message - 0x7cb34d79: {target: 0x11dfa986, keep: []string{"peer", "date", "user_id", "about", "invite", "qts"}}, // updateBotChatInviteRequester - 0x8ff2d5f0: {target: 0x98dd8936, structural: "pageListOrderedItemBlocks"}, // field "num": conditional-ness changed - 0x966e2dbf: {target: 0xb8425be9, keep: []string{"id", "flags", "closed", "public_voters", "multiple_choice", "quiz", "open_answers", "revoting_disabled", "shuffle_answers", "hide_results_until_close", "creator", "question", "answers", "close_period", "close_date", "hash"}}, // poll - 0xa04e8d3a: {target: 0xe4e0b29d, keep: []string{"flags", "can_view_participants", "can_set_username", "can_set_stickers", "hidden_prehistory", "can_set_location", "has_scheduled", "can_view_stats", "blocked", "flags2", "can_delete_channel", "antispam", "participants_hidden", "translations_disabled", "stories_pinned_available", "view_forum_as_messages", "restricted_sponsored", "can_view_revenue", "paid_media_allowed", "can_view_stars_revenue", "paid_reactions_available", "stargifts_available", "paid_messages_available", "id", "about", "participants_count", "admins_count", "kicked_count", "banned_count", "online_count", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "chat_photo", "notify_settings", "exported_invite", "bot_info", "migrated_from_chat_id", "migrated_from_max_id", "pinned_msg_id", "stickerset", "available_min_id", "folder_id", "linked_chat_id", "location", "slowmode_seconds", "slowmode_next_send_date", "stats_dc", "pts", "call", "ttl_period", "pending_suggestions", "groupcall_default_join_as", "theme_emoticon", "requests_pending", "recent_requesters", "default_send_as", "available_reactions", "reactions_limit", "stories", "wallpaper", "boosts_applied", "boosts_unrestrict", "emojiset", "bot_verification", "stargifts_count", "send_paid_messages_stars", "main_tab"}}, // channelFull - 0xf8827ebf: {target: 0xe0955a3c, keep: []string{"store_product", "phone_code_hash", "support_email_address", "support_email_subject", "currency", "amount"}}, // auth.sentCodePaymentRequired - }, - newTypes: []uint32{ - 0x004b572c, 0x01a9fbfc, 0x02ff29d3, 0x0773c080, 0x096b2aec, 0x0a617e7b, - 0x0e6e47c4, 0x0efa0194, 0x140502d1, 0x1fa01357, 0x1fe9a9bf, 0x24c26789, - 0x2999beed, 0x2f51c337, 0x3c29a3e2, 0x445663a7, 0x4c2a5d62, 0x519524ea, - 0x574b617f, 0x59080c20, 0x67e731ad, 0x682a41a9, 0x6c24f3dd, 0x6c9d0efe, - 0x7781fe18, 0x79eb8cb3, 0x7b9e1801, 0x83281dbd, 0x8c0f91fb, 0x933ca597, - 0x98a3a840, 0x9b00622b, 0x9bad6414, 0x9d2eac97, 0xa26156c0, 0xa2cb24f9, - 0xa5b45e2b, 0xac6a83aa, 0xae152a69, 0xb22083a6, 0xb43df56c, 0xb532772b, - 0xb956812d, 0xbaf39d8b, 0xbaff072f, 0xbdac7e70, 0xc1f46103, 0xc31c8f4e, - 0xc39a2ade, 0xc556a45d, 0xcd24cf44, 0xcdd4093d, 0xcff63ea9, 0xd6e3b813, - 0xdacb836a, 0xdbbe6c6a, 0xdd1fbf93, 0xe2b23b51, 0xe4c449fc, 0xf1d628ec, - }, - }, - 225: { - rules: map[uint32]ruleRaw{ - 0x033ed001: {target: 0xcd64636c, keep: []string{"flags", "bot_id", "recipients", "rights"}}, // connectedBot - 0x15031189: {target: 0x5e068047, structural: "pageListOrderedItemText"}, // field "num": conditional-ness changed - 0x1fd6f6c1: {target: 0x9a8ae1e1, keep: []string{"items"}}, // pageBlockOrderedList - 0x2f58683c: {target: 0xb92fb6cd, keep: []string{"text"}}, // pageListItemText - 0x3fc18057: {target: 0x9bb2636d, keep: []string{"flags", "restore", "phone_number", "phone_code_hash", "currency", "amount"}}, // inputStorePaymentAuthCode - 0x60fe3294: {target: 0x96eaa5eb, keep: []string{"flags", "no_webpage", "invert_media", "reply_to", "message", "entities", "media", "date", "effect", "suggested_post"}}, // draftMessage - 0x63ca67aa: {target: 0x25e073fc, keep: []string{"blocks"}}, // pageListItemBlocks - 0x7600b9d3: {target: 0x95ef6f2b, keep: []string{"flags", "out", "mentioned", "media_unread", "silent", "post", "from_scheduled", "legacy", "edit_hide", "pinned", "noforwards", "invert_media", "flags2", "offline", "video_processing_pending", "paid_suggested_post_stars", "paid_suggested_post_ton", "id", "from_id", "from_boosts_applied", "from_rank", "peer_id", "saved_peer_id", "fwd_from", "via_bot_id", "via_business_bot_id", "guestchat_via_from", "reply_to", "date", "message", "media", "reply_markup", "entities", "views", "forwards", "replies", "edit_date", "post_author", "grouped_id", "reactions", "restriction_reason", "ttl_period", "quick_reply_shortcut_id", "effect", "factcheck", "report_delivery_until_date", "paid_message_stars", "suggested_post", "schedule_repeat_period", "summary_from_language"}}, // message - 0x7cb34d79: {target: 0x11dfa986, keep: []string{"peer", "date", "user_id", "about", "invite", "qts"}}, // updateBotChatInviteRequester - 0x8ff2d5f0: {target: 0x98dd8936, structural: "pageListOrderedItemBlocks"}, // field "num": conditional-ness changed - 0xa04e8d3a: {target: 0xe4e0b29d, keep: []string{"flags", "can_view_participants", "can_set_username", "can_set_stickers", "hidden_prehistory", "can_set_location", "has_scheduled", "can_view_stats", "blocked", "flags2", "can_delete_channel", "antispam", "participants_hidden", "translations_disabled", "stories_pinned_available", "view_forum_as_messages", "restricted_sponsored", "can_view_revenue", "paid_media_allowed", "can_view_stars_revenue", "paid_reactions_available", "stargifts_available", "paid_messages_available", "id", "about", "participants_count", "admins_count", "kicked_count", "banned_count", "online_count", "read_inbox_max_id", "read_outbox_max_id", "unread_count", "chat_photo", "notify_settings", "exported_invite", "bot_info", "migrated_from_chat_id", "migrated_from_max_id", "pinned_msg_id", "stickerset", "available_min_id", "folder_id", "linked_chat_id", "location", "slowmode_seconds", "slowmode_next_send_date", "stats_dc", "pts", "call", "ttl_period", "pending_suggestions", "groupcall_default_join_as", "theme_emoticon", "requests_pending", "recent_requesters", "default_send_as", "available_reactions", "reactions_limit", "stories", "wallpaper", "boosts_applied", "boosts_unrestrict", "emojiset", "bot_verification", "stargifts_count", "send_paid_messages_stars", "main_tab"}}, // channelFull - 0xf8827ebf: {target: 0xe0955a3c, keep: []string{"store_product", "phone_code_hash", "support_email_address", "support_email_subject", "currency", "amount"}}, // auth.sentCodePaymentRequired - }, - newTypes: []uint32{ - 0x004b572c, 0x01a9fbfc, 0x02ff29d3, 0x096b2aec, 0x0a617e7b, 0x0e6e47c4, - 0x0efa0194, 0x140502d1, 0x24c26789, 0x2f51c337, 0x3c29a3e2, 0x445663a7, - 0x4c2a5d62, 0x519524ea, 0x574b617f, 0x59080c20, 0x67e731ad, 0x682a41a9, - 0x6c24f3dd, 0x79eb8cb3, 0x7b9e1801, 0x83281dbd, 0x933ca597, 0x98a3a840, - 0x9b00622b, 0x9d2eac97, 0xa26156c0, 0xa2cb24f9, 0xa5b45e2b, 0xac6a83aa, - 0xae152a69, 0xb22083a6, 0xb43df56c, 0xb532772b, 0xb956812d, 0xbaf39d8b, - 0xbaff072f, 0xbdac7e70, 0xc31c8f4e, 0xc39a2ade, 0xc556a45d, 0xcd24cf44, - 0xd6e3b813, 0xdacb836a, 0xdbbe6c6a, 0xe2b23b51, 0xe4c449fc, - }, - }, - 226: { - rules: map[uint32]ruleRaw{ - 0x15031189: {target: 0x5e068047, structural: "pageListOrderedItemText"}, // field "num": conditional-ness changed - 0x1fd6f6c1: {target: 0x9a8ae1e1, keep: []string{"items"}}, // pageBlockOrderedList - 0x2f51c337: {target: 0x774bbdf4, structural: "messages.chatInviteJoinResultWebView"}, // target field "url" not found in canonical (reorder/insert) - 0x2f58683c: {target: 0xb92fb6cd, keep: []string{"text"}}, // pageListItemText - 0x60fe3294: {target: 0x96eaa5eb, keep: []string{"flags", "no_webpage", "invert_media", "reply_to", "message", "entities", "media", "date", "effect", "suggested_post"}}, // draftMessage - 0x63ca67aa: {target: 0x25e073fc, keep: []string{"blocks"}}, // pageListItemBlocks - 0x7600b9d3: {target: 0x95ef6f2b, keep: []string{"flags", "out", "mentioned", "media_unread", "silent", "post", "from_scheduled", "legacy", "edit_hide", "pinned", "noforwards", "invert_media", "flags2", "offline", "video_processing_pending", "paid_suggested_post_stars", "paid_suggested_post_ton", "id", "from_id", "from_boosts_applied", "from_rank", "peer_id", "saved_peer_id", "fwd_from", "via_bot_id", "via_business_bot_id", "guestchat_via_from", "reply_to", "date", "message", "media", "reply_markup", "entities", "views", "forwards", "replies", "edit_date", "post_author", "grouped_id", "reactions", "restriction_reason", "ttl_period", "quick_reply_shortcut_id", "effect", "factcheck", "report_delivery_until_date", "paid_message_stars", "suggested_post", "schedule_repeat_period", "summary_from_language"}}, // message - 0x8ff2d5f0: {target: 0x98dd8936, structural: "pageListOrderedItemBlocks"}, // field "num": conditional-ness changed - }, - newTypes: []uint32{ - 0x004b572c, 0x01a9fbfc, 0x02ff29d3, 0x096b2aec, 0x0a617e7b, 0x0e6e47c4, - 0x24c26789, 0x3c29a3e2, 0x4c2a5d62, 0x519524ea, 0x574b617f, 0x59080c20, - 0x67e731ad, 0x682a41a9, 0x7b9e1801, 0x83281dbd, 0x9b00622b, 0x9d2eac97, - 0xa26156c0, 0xa2cb24f9, 0xa5b45e2b, 0xac6a83aa, 0xb43df56c, 0xb532772b, - 0xb956812d, 0xbaf39d8b, 0xbaff072f, 0xc556a45d, 0xcd24cf44, 0xdacb836a, - 0xdbbe6c6a, 0xe2b23b51, 0xe4c449fc, - }, - }, -} - -// inboundMethodUpgrades maps an old client method constructor id to the -// canonical (227) id. Only upgrade-safe changes (all 227 additions flag-gated) -// are listed: rewriting the 4-byte id yields a valid 227 request body. -// NOT upgrade-safe as a pure id swap (declare a body transform in client-drift.tl when needed): -// -// channels.editAdmin: field "rank": conditional-ness changed -// channels.toggleJoinRequest: 227 inserts flags integer "flags" -// contacts.search: 227 inserts flags integer "flags" -// messages.composeMessageWithAI: target field "change_tone" not found in canonical (reorder/insert) -// messages.getPollResults: 227-only field "poll_hash" is non-conditional -// messages.sendBotRequestedPeer: field "msg_id": conditional-ness changed -// messages.toggleNoForwards: 227 inserts flags integer "flags" -var inboundMethodUpgrades = map[uint32]uint32{ - 0x052b08db: 0xb8f106e3, // messages.setBotGuestChatResult - 0x198fb446: 0x894cc99c, // messages.requestUrlAuth - 0x24b524c5: 0x7f6a1e22, // channels.joinChannel - 0x2d0a0571: 0x60ed4229, // account.toggleWebBrowserSettingsException - 0x51e842e1: 0xb106e66c, // messages.editMessage - 0x545cd15a: 0xfef48f62, // messages.sendMessage - 0x54ae308e: 0xad0fa15c, // messages.saveDraft - 0x63183030: 0xa5eec345, // messages.translateText - 0x6c50051c: 0xde91436e, // messages.importChatInvite - 0x737fc2ec: 0x8f9e6898, // stories.sendStory - 0x83557dba: 0xa423bb51, // messages.editInlineBotMessage - 0x9d4104e2: 0xabbbd346, // messages.summarizeText - 0xb12c7125: 0x67a3f0de, // messages.acceptUrlAuth - 0xb583ba46: 0x2c63a72b, // stories.editStory -} diff --git a/internal/compat/layerwire/transcode_test.go b/internal/compat/layerwire/transcode_test.go deleted file mode 100644 index a2597970..00000000 --- a/internal/compat/layerwire/transcode_test.go +++ /dev/null @@ -1,249 +0,0 @@ -package layerwire - -import ( - "bytes" - "fmt" - "os" - "path/filepath" - "testing" - - "github.com/gotd/td/bin" - "github.com/gotd/td/tg" -) - -// loadLayerModel parses a vendored historical schema (_schema/layer-N.tl) into a -// schemaModel used as an independent oracle: downgraded bytes must parse cleanly -// against the actual target-layer schema. -func loadLayerModel(t *testing.T, layer int) *schemaModel { - t.Helper() - src, err := os.ReadFile(filepath.Join("_schema", fmt.Sprintf("layer-%d.tl", layer))) - if err != nil { - t.Fatalf("read layer %d schema: %v", layer, err) - } - m, err := parseSchemaModel(string(src)) - if err != nil { - t.Fatalf("parse layer %d schema: %v", layer, err) - } - return m -} - -// TestTranscodeIdentity verifies that targeting the canonical layer (or above) -// is a pure passthrough — the transcoder must never mutate 227 bytes. -func TestTranscodeIdentity(t *testing.T) { - for _, o := range canonicalCorpus() { - raw := mustEncode(t, o) - out, err := Transcode(raw, CanonicalLayer) - if err != nil { - t.Fatalf("%T: identity transcode: %v", o, err) - } - if !bytes.Equal(out, raw) { - t.Errorf("%T: identity transcode changed bytes", o) - } - } -} - -// TestTranscodeDowngradeValid downgrades the corpus to every supported layer and -// asserts the result parses cleanly (full byte consumption) against that layer's -// own schema. This is the core correctness oracle for the transcoder. -func TestTranscodeDowngradeValid(t *testing.T) { - for layer := SupportedFloor; layer < CanonicalLayer; layer++ { - model := loadLayerModel(t, layer) - for _, o := range canonicalCorpus() { - raw := mustEncode(t, o) - out, err := Transcode(raw, layer) - if err != nil { - t.Errorf("layer %d %T: transcode: %v", layer, o, err) - continue - } - b := &bin.Buffer{Buf: append([]byte(nil), out...)} - if err := model.skipObject(b); err != nil { - t.Errorf("layer %d %T: result invalid at target: %v", layer, o, err) - continue - } - if b.Len() != 0 { - t.Errorf("layer %d %T: %d trailing bytes in downgraded output", layer, o, b.Len()) - } - } - } -} - -// TestTranscodeMessageGolden checks that a message downgraded to 220 carries the -// 220 constructor id and is strictly shorter (dropped trailing fields). -func TestTranscodeMessageGolden(t *testing.T) { - const message220CRC = 0xb92f76cf - raw := mustEncode(t, canonicalCorpus()[1]) // the rich message - out, err := Transcode(raw, 220) - if err != nil { - t.Fatalf("transcode message->220: %v", err) - } - b := &bin.Buffer{Buf: append([]byte(nil), out...)} - id, err := b.PeekID() - if err != nil { - t.Fatalf("peek id: %v", err) - } - if id != message220CRC { - t.Fatalf("message@220 id = %#08x, want %#08x", id, message220CRC) - } - if len(out) >= len(raw) { - t.Errorf("downgraded message not shorter: %d >= %d", len(out), len(raw)) - } -} - -func TestTranscodeFormattedDateEntityLayerBoundary(t *testing.T) { - const formattedDateEntityCRC = 0x904ac7c7 - entityCRC := func(crc uint32) []byte { - return []byte{byte(crc), byte(crc >> 8), byte(crc >> 16), byte(crc >> 24)} - } - msg := &tg.Message{ - ID: 7, - PeerID: &tg.PeerUser{UserID: 2}, - Date: 100, - Message: "Meet soon", - Entities: []tg.MessageEntityClass{ - &tg.MessageEntityFormattedDate{Offset: 5, Length: 4, Date: 1773436800, ShortDate: true, ShortTime: true}, - }, - } - raw := mustEncode(t, msg) - - out222, err := Transcode(raw, 222) - if err != nil { - t.Fatalf("transcode message->222: %v", err) - } - if bytes.Contains(out222, entityCRC(formattedDateEntityCRC)) { - t.Fatalf("layer 222 output leaked formatted-date entity") - } - if !bytes.Contains(out222, entityCRC(messageEntityUnknownID)) { - t.Fatalf("layer 222 output missing messageEntityUnknown fallback") - } - m222 := loadLayerModel(t, 222) - b222 := &bin.Buffer{Buf: append([]byte(nil), out222...)} - if err := m222.skipObject(b222); err != nil || b222.Len() != 0 { - t.Fatalf("layer 222 formatted-date fallback does not parse cleanly (err=%v left=%d)", err, b222.Len()) - } - - out223, err := Transcode(raw, 223) - if err != nil { - t.Fatalf("transcode message->223: %v", err) - } - if !bytes.Contains(out223, entityCRC(formattedDateEntityCRC)) { - t.Fatalf("layer 223 output did not preserve formatted-date entity") - } - m223 := loadLayerModel(t, 223) - b223 := &bin.Buffer{Buf: append([]byte(nil), out223...)} - if err := m223.skipObject(b223); err != nil || b223.Len() != 0 { - t.Fatalf("layer 223 formatted-date output does not parse cleanly (err=%v left=%d)", err, b223.Len()) - } -} - -// TestTranscodePassthroughNonAPI verifies that a top-level constructor absent -// from the tg schema (an MTProto control object such as rpc_error) passes -// through untouched at any layer. -func TestTranscodePassthroughNonAPI(t *testing.T) { - var b bin.Buffer - b.PutID(0xc4b9f9bb) // rpc_error#c4b9f9bb (mt.*), not a tg API constructor - b.PutInt(420) - b.PutString("FLOOD_WAIT") - raw := b.Copy() - out, err := Transcode(raw, 220) - if err != nil { - t.Fatalf("passthrough transcode: %v", err) - } - if !bytes.Equal(out, raw) { - t.Errorf("non-API object was modified by transcode") - } -} - -// TestTranscodeChangedTypeNestedInUnchangedContainer is the case raised in -// review: an outer constructor whose CRC is IDENTICAL across 227 and the target -// layer (so a naive "same CRC ⇒ copy verbatim" would be wrong) but which nests a -// CHANGED type (message). The dirty closure must mark the outer container dirty -// purely because it can transitively reach a changed type, so the transcoder -// keeps the outer CRC yet recurses and rewrites the inner message to the target. -func TestTranscodeChangedTypeNestedInUnchangedContainer(t *testing.T) { - const ( - message227CRC = 0x7600b9d3 - message220CRC = 0xb92f76cf - ) - // updates#... nests Vector → updateNewMessage → message:Message. - updates := &tg.Updates{ - Updates: []tg.UpdateClass{ - &tg.UpdateNewMessage{ - Message: &tg.Message{ID: 7, PeerID: &tg.PeerUser{UserID: 2}, Date: 1, Message: "nested"}, - Pts: 1, PtsCount: 1, - }, - }, - Users: []tg.UserClass{&tg.User{ID: 2, AccessHash: 5, FirstName: "A"}}, - Chats: []tg.ChatClass{}, - Date: 100, Seq: 1, - } - - // Premise of the question: the OUTER container's CRC is unchanged at 220. - m220 := loadLayerModel(t, 220) - if canonical.byName["updates"].crc != m220.byName["updates"].crc { - t.Skip("updates CRC differs 220<->227; premise no longer holds") - } - - raw := mustEncode(t, updates) - out, err := Transcode(raw, 220) - if err != nil { - t.Fatalf("transcode updates->220: %v", err) - } - - // Outer CRC preserved (it really is unchanged). - if id, _ := (&bin.Buffer{Buf: out}).PeekID(); id != canonical.byName["updates"].crc { - t.Fatalf("outer updates id changed to %#08x", id) - } - // Inner message rewritten to the 220 constructor; the 227 one must be gone. - le := func(crc uint32) []byte { return []byte{byte(crc), byte(crc >> 8), byte(crc >> 16), byte(crc >> 24)} } - if bytes.Contains(out, le(message227CRC)) { - t.Errorf("downgraded output still contains the 227 message constructor") - } - if !bytes.Contains(out, le(message220CRC)) { - t.Errorf("downgraded output missing the 220 message constructor") - } - // Rigorous: the whole thing must parse cleanly against the real 220 schema — - // impossible if a 227-only nested constructor leaked through. - b := &bin.Buffer{Buf: append([]byte(nil), out...)} - if err := m220.skipObject(b); err != nil || b.Len() != 0 { - t.Fatalf("downgraded updates invalid at 220 (err=%v left=%d)", err, b.Len()) - } -} - -// TestTranscodePollResults exercises the pollAnswerVoters structural transform. -func TestTranscodePollResults(t *testing.T) { - raw := mustEncode(t, canonicalCorpus()[10]) // PollResults - for layer := SupportedFloor; layer < CanonicalLayer; layer++ { - out, err := Transcode(raw, layer) - if err != nil { - t.Fatalf("layer %d: pollResults transcode: %v", layer, err) - } - model := loadLayerModel(t, layer) - b := &bin.Buffer{Buf: append([]byte(nil), out...)} - if err := model.skipObject(b); err != nil || b.Len() != 0 { - t.Errorf("layer %d: pollResults invalid (err=%v left=%d)", layer, err, b.Len()) - } - } -} - -// TestTranscodePollAnswerVotersAbsentFlag exercises the structural transform's -// flag-bit-2-unset path: a pollAnswerVoters whose voters field is absent in 227 -// (flags.2 clear) must still emit voters:0 (unconditional int) at older layers. -func TestTranscodePollAnswerVotersAbsentFlag(t *testing.T) { - // voters absent (flag bit 2 unset): Voters=0 ⇒ gotd SetFlags leaves flags.2 clear. - pr := &tg.PollResults{ - Results: []tg.PollAnswerVoters{{Option: []byte{0}, Chosen: true}}, - TotalVoters: 0, - } - raw := mustEncode(t, pr) - for layer := SupportedFloor; layer < CanonicalLayer; layer++ { - out, err := Transcode(raw, layer) - if err != nil { - t.Fatalf("layer %d: transcode: %v", layer, err) - } - model := loadLayerModel(t, layer) - b := &bin.Buffer{Buf: append([]byte(nil), out...)} - if err := model.skipObject(b); err != nil || b.Len() != 0 { - t.Errorf("layer %d: voters-absent pollResults invalid (err=%v left=%d)", layer, err, b.Len()) - } - } -} diff --git a/internal/compat/layerwire/walk.go b/internal/compat/layerwire/walk.go deleted file mode 100644 index 9f89aff3..00000000 --- a/internal/compat/layerwire/walk.go +++ /dev/null @@ -1,433 +0,0 @@ -package layerwire - -import ( - "errors" - "fmt" - "io" - "math" - - "github.com/gotd/td/bin" -) - -// ErrMalformed identifies invalid or truncated TL wire data. Callers may use -// errors.Is to distinguish it from an otherwise well-formed request which was -// rejected by a walker resource limit. -var ErrMalformed = errors.New("layerwire: malformed TL") - -// ErrResourceLimit identifies structurally valid-looking TL input which would -// exceed a walker resource budget. -var ErrResourceLimit = errors.New("layerwire: resource limit") - -const ( - defaultMaxVectorElements = 4096 - defaultMaxWalkDepth = 32 - defaultMaxWalkUnits = 131072 // constructors + declared vector elements - defaultMaxFieldBytes = 16 << 20 - defaultMaxTotalBytes = 32 << 20 -) - -// A very small number of API methods have a documented limit above the -// package-wide default. Keeping overrides keyed by constructor and field makes -// every exception explicit and prevents a large vector in an unrelated method -// from inheriting the larger allowance. -type vectorLimitKey struct { - owner string - field string -} - -var vectorElementLimitOverrides = map[vectorLimitKey]int{ - {owner: "contacts.editCloseFriends", field: "id"}: 5000, - {owner: "contacts.setBlocked", field: "id"}: 5000, -} - -type walkLimits struct { - maxVectorElements int - maxDepth int - maxUnits uint64 - maxFieldBytes uint64 - maxTotalBytes uint64 -} - -var defaultWalkLimits = walkLimits{ - maxVectorElements: defaultMaxVectorElements, - maxDepth: defaultMaxWalkDepth, - maxUnits: defaultMaxWalkUnits, - maxFieldBytes: defaultMaxFieldBytes, - maxTotalBytes: defaultMaxTotalBytes, -} - -// walkState is deliberately request-scoped. Every branch of one transform -// shares it, so splitting a large value across nested constructors or vectors -// cannot reset the aggregate budgets. -type walkState struct { - limits walkLimits - units uint64 - bytes uint64 -} - -func newWalkState() *walkState { - return &walkState{limits: defaultWalkLimits} -} - -func malformedf(format string, args ...any) error { - return fmt.Errorf("%w: %s", ErrMalformed, fmt.Sprintf(format, args...)) -} - -func limitf(format string, args ...any) error { - return fmt.Errorf("%w: %s", ErrResourceLimit, fmt.Sprintf(format, args...)) -} - -// classifyWalkError makes all public walker/transform failures classifiable, -// including errors returned by the low-level gotd bin decoder. -func classifyWalkError(err error) error { - if err == nil || errors.Is(err, ErrMalformed) || errors.Is(err, ErrResourceLimit) { - return err - } - return fmt.Errorf("%w: %v", ErrMalformed, err) -} - -func (s *walkState) enter(depth int, what string) error { - if depth <= 0 || depth > s.limits.maxDepth { - return limitf("%s nesting depth %d exceeds limit %d", what, depth, s.limits.maxDepth) - } - return s.addUnits(1, what) -} - -func (s *walkState) addUnits(n int, what string) error { - if n < 0 { - return malformedf("negative %s count %d", what, n) - } - u := uint64(n) - // Subtraction form avoids overflow even if limits are changed later. - if s.units > s.limits.maxUnits || u > s.limits.maxUnits-s.units { - return limitf("constructor/vector element budget exceeds %d at %s", s.limits.maxUnits, what) - } - s.units += u - return nil -} - -func (s *walkState) addBytes(n uint64, what string) error { - if n > s.limits.maxFieldBytes { - return limitf("%s payload length %d exceeds per-field limit %d", what, n, s.limits.maxFieldBytes) - } - if s.bytes > s.limits.maxTotalBytes || n > s.limits.maxTotalBytes-s.bytes { - return limitf("string/bytes payload budget exceeds %d at %s", s.limits.maxTotalBytes, what) - } - s.bytes += n - return nil -} - -func (s *walkState) vectorLimit(owner *ctorLayout, f *fieldLayout) int { - if owner != nil && f != nil { - if n := vectorElementLimitOverrides[vectorLimitKey{owner: owner.name, field: f.name}]; n > 0 { - return n - } - } - return s.limits.maxVectorElements -} - -const maxConstructorFlagWords = 8 - -type constructorFlagWord struct { - name string - value uint32 -} - -// ValidateCanonicalRequest performs a complete, allocation-free structural -// preflight of one canonical Layer 227 method request. It is intended for the -// router seam immediately before typed dispatch. A successful result means the -// walker consumed exactly one known function constructor and all of its body. -func ValidateCanonicalRequest(body []byte) error { - b := &bin.Buffer{Buf: body} - id, err := b.PeekID() - if err != nil { - return classifyWalkError(err) - } - cl := canonical.byCRC[id] - if cl == nil { - return malformedf("unknown canonical request constructor %#08x", id) - } - if !cl.isFunc { - return malformedf("constructor %s (%#08x) is not a method", cl.name, id) - } - return validateRequestLayout(canonical, cl, body) -} - -func validateRequestLayout(m *schemaModel, cl *ctorLayout, body []byte) error { - b := &bin.Buffer{Buf: body} - s := newWalkState() - if err := s.skipObject(m, b, 1); err != nil { - return classifyWalkError(err) - } - if b.Len() != 0 { - return malformedf("%d trailing bytes after canonical request %s", b.Len(), cl.name) - } - return nil -} - -// skipObject advances b past one boxed object (CRC + body), resolving the -// constructor from m. This compatibility wrapper creates a fresh budget; all -// production transforms call the stateful variant directly. -func (m *schemaModel) skipObject(b *bin.Buffer) error { - return classifyWalkError(newWalkState().skipObject(m, b, 1)) -} - -func (s *walkState) skipObject(m *schemaModel, b *bin.Buffer, depth int) error { - if err := s.enter(depth, "constructor"); err != nil { - return err - } - id, err := b.PeekID() - if err != nil { - return err - } - cl, ok := m.byCRC[id] - if !ok { - return malformedf("unknown constructor %#08x", id) - } - if err := b.ConsumeID(id); err != nil { - return err - } - return s.skipCtorBody(m, b, cl, depth) -} - -// skipCtorBody advances b past a constructor body (no leading CRC), evaluating -// flag integers so conditional fields are read iff present. The constructor's -// unit and depth have already been charged by the caller. -func (s *walkState) skipCtorBody(m *schemaModel, b *bin.Buffer, cl *ctorLayout, depth int) error { - // Layer 227 constructors currently use at most flags + flags2. Keep generous fixed stack - // storage so the allocation-free preflight remains allocation-free on the hottest flagged - // methods; the explicit bound also prevents a future malformed/generated layout from turning - // every request into an attacker-amplified map allocation. - var flags [maxConstructorFlagWords]constructorFlagWord - flagCount := 0 - for i := range cl.fields { - f := &cl.fields[i] - if f.isFlags { - v, err := b.Uint32() - if err != nil { - return fmt.Errorf("%s.%s: %w", cl.name, f.name, err) - } - if flagCount >= len(flags) { - return limitf("constructor %s has more than %d flags words", cl.name, len(flags)) - } - flags[flagCount] = constructorFlagWord{name: f.name, value: v} - flagCount++ - continue - } - if f.conditional() { - var ( - flagValue uint32 - found bool - ) - for j := 0; j < flagCount; j++ { - if flags[j].name == f.flagName { - flagValue = flags[j].value - found = true - break - } - } - if !found { - return malformedf("constructor %s conditional field %s references missing flags word %s", cl.name, f.name, f.flagName) - } - if flagValue&(1< s.limits.maxDepth { - return limitf("vector nesting depth %d exceeds limit %d", vectorDepth, s.limits.maxDepth) - } - if f.kind == kindVector { - id, err := b.Uint32() - if err != nil { - return err - } - if id != vectorTypeID { - return malformedf("expected vector id, got %#08x", id) - } - } - n, err := b.Int() - if err != nil { - return err - } - if n < 0 { - return malformedf("negative vector length %d", n) - } - if max := s.vectorLimit(owner, f); n > max { - return limitf("vector %s.%s length %d exceeds limit %d", ownerName(owner), fieldName(f), n, max) - } - if err := s.addUnits(n, "vector "+ownerName(owner)+"."+fieldName(f)); err != nil { - return err - } - if width, ok := fixedWireWidth(f.elem); ok { - total, ok := checkedMulInt(n, width) - if !ok { - return malformedf("vector byte length overflow: %d * %d", n, width) - } - return skipFixed(b, total) - } - for i := 0; i < n; i++ { - if err := s.skipValue(m, b, f.elem, nil, vectorDepth); err != nil { - return fmt.Errorf("vector element %d: %w", i, err) - } - } - return nil - case kindObject: - return s.skipObject(m, b, depth+1) - case kindBareObject: - bareDepth := depth + 1 - if err := s.enter(bareDepth, "bare constructor"); err != nil { - return err - } - cl, ok := m.bareByT[f.typeName] - if !ok { - return malformedf("unknown bare type %q", f.typeName) - } - return s.skipCtorBody(m, b, cl, bareDepth) - default: - return malformedf("bad wire kind %d", f.kind) - } -} - -// skipTLBytes parses TL's 1/4-byte length prefix directly and advances the -// input slice. Unlike bin.Buffer.Bytes it never copies payload data. -func (s *walkState) skipTLBytes(b *bin.Buffer, what string) error { - if len(b.Buf) == 0 { - return io.ErrUnexpectedEOF - } - var header, payload uint64 - switch b.Buf[0] { - case 254: - if len(b.Buf) < 4 { - return io.ErrUnexpectedEOF - } - header = 4 - payload = uint64(b.Buf[1]) | uint64(b.Buf[2])<<8 | uint64(b.Buf[3])<<16 - case 255: - return malformedf("invalid %s length prefix 255", what) - default: - header = 1 - payload = uint64(b.Buf[0]) - } - if err := s.addBytes(payload, what); err != nil { - return err - } - encoded, ok := checkedAddUint64(header, payload) - if !ok { - return malformedf("%s encoded length overflow", what) - } - withPadding, ok := checkedAddUint64(encoded, 3) - if !ok { - return malformedf("%s padded length overflow", what) - } - padded := withPadding &^ uint64(3) - if padded > uint64(math.MaxInt) { - return malformedf("%s padded length %d overflows int", what, padded) - } - if uint64(len(b.Buf)) < padded { - return io.ErrUnexpectedEOF - } - b.Buf = b.Buf[int(padded):] - return nil -} - -func skipFixed(b *bin.Buffer, n int) error { - if n < 0 { - return malformedf("negative fixed-width skip %d", n) - } - if len(b.Buf) < n { - return io.ErrUnexpectedEOF - } - b.Buf = b.Buf[n:] - return nil -} - -func fixedWireWidth(f *fieldLayout) (int, bool) { - if f == nil { - return 0, false - } - switch f.kind { - case kindInt: - return 4, true - case kindLong, kindDouble: - return 8, true - case kindInt128: - return 16, true - case kindInt256: - return 32, true - case kindTrue: - return 0, true - default: - // Bool deliberately stays on the element loop so constructor ids are - // validated and charged to the aggregate constructor budget. - return 0, false - } -} - -func checkedMulInt(a, b int) (int, bool) { - if a < 0 || b < 0 { - return 0, false - } - if a != 0 && b > math.MaxInt/a { - return 0, false - } - return a * b, true -} - -func checkedAddUint64(a, b uint64) (uint64, bool) { - if b > math.MaxUint64-a { - return 0, false - } - return a + b, true -} - -func ownerName(cl *ctorLayout) string { - if cl == nil || cl.name == "" { - return "" - } - return cl.name -} - -func fieldName(f *fieldLayout) string { - if f == nil || f.name == "" { - return "" - } - return f.name -} diff --git a/internal/compat/layerwire/walk_limits_test.go b/internal/compat/layerwire/walk_limits_test.go deleted file mode 100644 index ca26f885..00000000 --- a/internal/compat/layerwire/walk_limits_test.go +++ /dev/null @@ -1,263 +0,0 @@ -package layerwire - -import ( - "errors" - "math" - "testing" - - "github.com/gotd/td/bin" - "github.com/gotd/td/tg" -) - -func TestValidateCanonicalRequestFlaggedHotPathAllocatesNothing(t *testing.T) { - var body bin.Buffer - req := &tg.MessagesSendMessageRequest{ - Peer: &tg.InputPeerSelf{}, - Message: "hello", - RandomID: 7, - } - if err := req.Encode(&body); err != nil { - t.Fatalf("encode request: %v", err) - } - if err := ValidateCanonicalRequest(body.Buf); err != nil { - t.Fatalf("validate request: %v", err) - } - if allocs := testing.AllocsPerRun(1000, func() { - if err := ValidateCanonicalRequest(body.Buf); err != nil { - panic(err) - } - }); allocs != 0 { - t.Fatalf("canonical request preflight allocations = %.2f, want 0", allocs) - } -} - -func TestValidateCanonicalRequestVectorLimits(t *testing.T) { - editCloseFriends := canonical.byName["contacts.editCloseFriends"] - if editCloseFriends == nil { - t.Fatal("contacts.editCloseFriends missing from canonical schema") - } - - t.Run("explicit_5000_override", func(t *testing.T) { - var body bin.Buffer - body.PutID(editCloseFriends.crc) - body.PutVectorHeader(5000) - for i := 0; i < 5000; i++ { - body.PutLong(int64(i)) - } - if err := ValidateCanonicalRequest(body.Buf); err != nil { - t.Fatalf("validate legal 5000-element close-friends request: %v", err) - } - }) - - t.Run("override_stops_at_5000", func(t *testing.T) { - var body bin.Buffer - body.PutID(editCloseFriends.crc) - body.PutVectorHeader(5001) - err := ValidateCanonicalRequest(body.Buf) - if !errors.Is(err, ErrResourceLimit) { - t.Fatalf("error = %v, want ErrResourceLimit", err) - } - }) - - t.Run("default_4096", func(t *testing.T) { - getMessages := canonical.byName["messages.getMessages"] - var body bin.Buffer - body.PutID(getMessages.crc) - body.PutVectorHeader(defaultMaxVectorElements + 1) - err := ValidateCanonicalRequest(body.Buf) - if !errors.Is(err, ErrResourceLimit) { - t.Fatalf("error = %v, want ErrResourceLimit", err) - } - }) - - t.Run("max_int32_count_rejected_before_iteration", func(t *testing.T) { - var body bin.Buffer - body.PutID(editCloseFriends.crc) - body.PutID(vectorTypeID) - body.PutInt32(math.MaxInt32) - err := ValidateCanonicalRequest(body.Buf) - if !errors.Is(err, ErrResourceLimit) { - t.Fatalf("error = %v, want ErrResourceLimit", err) - } - }) -} - -func TestValidateCanonicalRequestDepthLimit(t *testing.T) { - invoke := canonical.byName["invokeWithoutUpdates"] - leaf := canonical.byName["help.getConfig"] - if invoke == nil || leaf == nil { - t.Fatal("generic wrapper methods missing from canonical schema") - } - request := func(wrappers int) []byte { - var body bin.Buffer - for i := 0; i < wrappers; i++ { - body.PutID(invoke.crc) - } - body.PutID(leaf.crc) - return body.Buf - } - if err := ValidateCanonicalRequest(request(defaultMaxWalkDepth - 1)); err != nil { - t.Fatalf("depth exactly %d rejected: %v", defaultMaxWalkDepth, err) - } - err := ValidateCanonicalRequest(request(defaultMaxWalkDepth)) - if !errors.Is(err, ErrResourceLimit) { - t.Fatalf("depth %d error = %v, want ErrResourceLimit", defaultMaxWalkDepth+1, err) - } -} - -func TestTLBytesSkipIsZeroCopyAndBounded(t *testing.T) { - var encoded bin.Buffer - encoded.PutBytes([]byte("payload")) - fieldLen := len(encoded.Buf) - raw := append(encoded.Copy(), 0xaa, 0xbb, 0xcc, 0xdd) - b := &bin.Buffer{Buf: raw} - walk := newWalkState() - if err := walk.skipTLBytes(b, "bytes"); err != nil { - t.Fatalf("skip bytes: %v", err) - } - if len(b.Buf) != 4 || &b.Buf[0] != &raw[fieldLen] { - t.Fatalf("walker did not retain the original backing buffer") - } - - t.Run("per_field_budget", func(t *testing.T) { - limited := newWalkState() - limited.limits.maxFieldBytes = 3 - probe := &bin.Buffer{Buf: encoded.Copy()} - err := limited.skipTLBytes(probe, "bytes") - if !errors.Is(err, ErrResourceLimit) { - t.Fatalf("error = %v, want ErrResourceLimit", err) - } - }) - - t.Run("aggregate_budget", func(t *testing.T) { - limited := newWalkState() - limited.limits.maxTotalBytes = 10 - first := &bin.Buffer{Buf: encoded.Copy()} - if err := limited.skipTLBytes(first, "bytes"); err != nil { - t.Fatalf("first field: %v", err) - } - second := &bin.Buffer{Buf: encoded.Copy()} - err := limited.skipTLBytes(second, "bytes") - if !errors.Is(err, ErrResourceLimit) { - t.Fatalf("second error = %v, want ErrResourceLimit", err) - } - }) - - t.Run("truncated_payload_is_malformed", func(t *testing.T) { - importAuth := canonical.byName["auth.importAuthorization"] - var body bin.Buffer - body.PutID(importAuth.crc) - body.PutLong(1) - body.Put([]byte{5, 'a', 'b'}) // declares five bytes, lacks payload/padding - err := ValidateCanonicalRequest(body.Buf) - if !errors.Is(err, ErrMalformed) || errors.Is(err, ErrResourceLimit) { - t.Fatalf("error = %v, want only ErrMalformed", err) - } - }) -} - -func TestInboundTransformsShareWalkerBudgets(t *testing.T) { - t.Run("canonical_alias", func(t *testing.T) { - var body bin.Buffer - body.PutID(0x41d41ade) // DrKLO messages.forwardMessages alias - body.PutUint32(0) - body.PutID(canonical.byName["inputPeerEmpty"].crc) - body.PutID(vectorTypeID) - body.PutInt32(math.MaxInt32) - _, ok, err := UpgradeInbound(0x41d41ade, &body) - if !ok || !errors.Is(err, ErrResourceLimit) { - t.Fatalf("ok=%v error=%v, want matched ErrResourceLimit", ok, err) - } - }) - - t.Run("drift_body_transform", func(t *testing.T) { - var body bin.Buffer - body.PutID(0x2e1ee318) // DrKLO langpack.getStrings body transform - body.PutString("en") - body.PutID(vectorTypeID) - body.PutInt32(math.MaxInt32) - _, ok, err := UpgradeInbound(0x2e1ee318, &body) - if !ok || !errors.Is(err, ErrResourceLimit) { - t.Fatalf("ok=%v error=%v, want matched ErrResourceLimit", ok, err) - } - }) - - t.Run("outbound_structural_transform", func(t *testing.T) { - poll := canonical.byName["pollAnswerVoters"] - var body bin.Buffer - body.PutID(poll.crc) - body.PutUint32(1 << 2) - body.PutBytes(nil) - body.PutInt(1) - body.PutID(vectorTypeID) - body.PutInt32(math.MaxInt32) - _, err := Transcode(body.Buf, CanonicalLayer-1) - if !errors.Is(err, ErrResourceLimit) { - t.Fatalf("error = %v, want ErrResourceLimit", err) - } - }) -} - -func TestWalkerArithmeticAndMalformedClassification(t *testing.T) { - if defaultMaxWalkUnits != 131072 { - t.Fatalf("default constructor/vector budget = %d, want 131072", defaultMaxWalkUnits) - } - if _, ok := checkedMulInt(math.MaxInt, 2); ok { - t.Fatal("checkedMulInt accepted overflow") - } - if _, ok := checkedAddUint64(math.MaxUint64, 1); ok { - t.Fatal("checkedAddUint64 accepted overflow") - } - - t.Run("aggregate_constructor_and_vector_units", func(t *testing.T) { - editCloseFriends := canonical.byName["contacts.editCloseFriends"] - var body bin.Buffer - body.PutID(editCloseFriends.crc) - body.PutVectorHeader(4) - for i := 0; i < 4; i++ { - body.PutLong(int64(i)) - } - walk := newWalkState() - walk.limits.maxUnits = 4 // top constructor + four elements needs five - probe := &bin.Buffer{Buf: body.Buf} - err := walk.skipObject(canonical, probe, 1) - if !errors.Is(err, ErrResourceLimit) { - t.Fatalf("error = %v, want ErrResourceLimit", err) - } - }) - - tests := []struct { - name string - body []byte - }{ - {name: "empty"}, - {name: "unknown_constructor", body: []byte{1, 2, 3, 4}}, - {name: "trailing_bytes", body: append(methodIDBytes(canonical.byName["help.getConfig"].crc), 0, 0, 0, 0)}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := ValidateCanonicalRequest(tt.body) - if !errors.Is(err, ErrMalformed) || errors.Is(err, ErrResourceLimit) { - t.Fatalf("error = %v, want only ErrMalformed", err) - } - }) - } -} - -func methodIDBytes(id uint32) []byte { - var b bin.Buffer - b.PutID(id) - return b.Buf -} - -func FuzzValidateCanonicalRequest(f *testing.F) { - f.Add(methodIDBytes(canonical.byName["help.getConfig"].crc)) - f.Add([]byte{}) - f.Add([]byte{1, 2, 3, 4}) - f.Fuzz(func(t *testing.T, body []byte) { - err := ValidateCanonicalRequest(body) - if err != nil && !errors.Is(err, ErrMalformed) && !errors.Is(err, ErrResourceLimit) { - t.Fatalf("unclassified walker error: %v", err) - } - }) -} diff --git a/internal/compat/layerwire/walk_test.go b/internal/compat/layerwire/walk_test.go deleted file mode 100644 index 9aa1c7a3..00000000 --- a/internal/compat/layerwire/walk_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package layerwire - -import ( - "testing" - - "github.com/gotd/td/bin" -) - -func mustEncode(t *testing.T, o bin.Encoder) []byte { - t.Helper() - var b bin.Buffer - if err := o.Encode(&b); err != nil { - t.Fatalf("encode %T: %v", o, err) - } - return b.Copy() -} - -// TestWalkConsumesCanonicalObjects encodes a diverse corpus of canonical (gotd, -// Layer 227) objects and asserts the generic walker consumes every byte. Full -// consumption proves the layout handles each field's wire kind (flags, -// multi-flags, conditionals, vectors, nested boxed/bare objects) exactly as gotd -// encoded them. -func TestWalkConsumesCanonicalObjects(t *testing.T) { - for _, o := range canonicalCorpus() { - raw := mustEncode(t, o) - b := &bin.Buffer{Buf: append([]byte(nil), raw...)} - if err := canonical.skipObject(b); err != nil { - t.Errorf("%T: walk error: %v", o, err) - continue - } - if b.Len() != 0 { - t.Errorf("%T: %d/%d bytes left after walk", o, b.Len(), len(raw)) - } - } -} diff --git a/internal/compat/tdesktop/appearance_seed.go b/internal/compat/tdesktop/appearance_seed.go index 8595ce36..8177e119 100644 --- a/internal/compat/tdesktop/appearance_seed.go +++ b/internal/compat/tdesktop/appearance_seed.go @@ -5,7 +5,7 @@ import ( "telesrv/internal/seed/appearance" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) const appearanceSeedDCID = 2 @@ -18,16 +18,16 @@ var peerColorOptionsCache = struct { profile []tg.HelpPeerColorOption }{} -func seedWallPapers() []tg.WallPaperClass { +func DefaultWallPapers() []tg.WallPaperClass { catalog := appearance.Default() out := make([]tg.WallPaperClass, 0, len(catalog.Wallpapers)) for _, wallpaper := range catalog.Wallpapers { - out = append(out, seedWallPaper(wallpaper)) + out = append(out, DefaultWallPaper(wallpaper)) } return out } -// LookupWallPaper resolves a cloud wallpaper from the default seed catalog. +// LookupWallPaper resolves a cloud wallpaper from the Default seed catalog. func LookupWallPaper(input tg.InputWallPaperClass) (tg.WallPaperClass, bool) { if in, ok := input.(*tg.InputWallPaperNoFile); ok { return &tg.WallPaperNoFile{ID: in.ID}, true @@ -35,13 +35,13 @@ func LookupWallPaper(input tg.InputWallPaperClass) (tg.WallPaperClass, bool) { catalog := appearance.Default() for _, wallpaper := range catalog.Wallpapers { if inputWallPaperMatches(input, wallpaper) { - return seedWallPaper(wallpaper), true + return DefaultWallPaper(wallpaper), true } } return nil, false } -// LookupWallPapers resolves multiple wallpapers from the default seed catalog. +// LookupWallPapers resolves multiple wallpapers from the Default seed catalog. func LookupWallPapers(inputs []tg.InputWallPaperClass) ([]tg.WallPaperClass, bool) { out := make([]tg.WallPaperClass, 0, len(inputs)) for _, input := range inputs { @@ -65,28 +65,28 @@ func inputWallPaperMatches(input tg.InputWallPaperClass, wallpaper appearance.Wa } } -func seedWallPaper(in appearance.Wallpaper) tg.WallPaperClass { +func DefaultWallPaper(in appearance.Wallpaper) tg.WallPaperClass { if in.Type == 1 || in.Document.ID == 0 { out := &tg.WallPaperNoFile{ID: in.ID} out.SetDefault(in.Default) out.SetDark(in.Dark) - out.SetSettings(seedWallPaperSettings(in.Settings)) + out.SetSettings(DefaultWallPaperSettings(in.Settings)) return out } out := &tg.WallPaper{ ID: in.ID, AccessHash: in.AccessHash, Slug: in.Slug, - Document: seedDocument(in.Document), + Document: DefaultDocument(in.Document), } out.SetDefault(in.Default) out.SetPattern(in.Pattern) out.SetDark(in.Dark) - out.SetSettings(seedWallPaperSettings(in.Settings)) + out.SetSettings(DefaultWallPaperSettings(in.Settings)) return out } -func seedWallPaperSettings(in appearance.WallpaperSettings) tg.WallPaperSettings { +func DefaultWallPaperSettings(in appearance.WallpaperSettings) tg.WallPaperSettings { var out tg.WallPaperSettings out.SetBlur(in.Blur) out.SetMotion(in.Motion) @@ -111,7 +111,7 @@ func seedWallPaperSettings(in appearance.WallpaperSettings) tg.WallPaperSettings return out } -func seedDocument(in appearance.Document) tg.DocumentClass { +func DefaultDocument(in appearance.Document) tg.DocumentClass { if in.ID == 0 { return &tg.DocumentEmpty{} } @@ -121,14 +121,14 @@ func seedDocument(in appearance.Document) tg.DocumentClass { Date: in.Date, MimeType: in.MimeType, Size: in.Size, - Thumbs: seedPhotoSizes(in.Thumbs), + Thumbs: DefaultPhotoSizes(in.Thumbs), DCID: appearanceSeedDCID, - Attributes: seedDocumentAttributes(in.Attributes), + Attributes: DefaultDocumentAttributes(in.Attributes), FileReference: nil, } } -func seedPhotoSizes(in []appearance.PhotoSize) []tg.PhotoSizeClass { +func DefaultPhotoSizes(in []appearance.PhotoSize) []tg.PhotoSizeClass { out := make([]tg.PhotoSizeClass, 0, len(in)) for _, size := range in { switch size.Kind { @@ -144,7 +144,7 @@ func seedPhotoSizes(in []appearance.PhotoSize) []tg.PhotoSizeClass { return out } -func seedDocumentAttributes(in []appearance.DocumentAttribute) []tg.DocumentAttributeClass { +func DefaultDocumentAttributes(in []appearance.DocumentAttribute) []tg.DocumentAttributeClass { out := make([]tg.DocumentAttributeClass, 0, len(in)) for _, attr := range in { switch attr.Kind { @@ -159,20 +159,20 @@ func seedDocumentAttributes(in []appearance.DocumentAttribute) []tg.DocumentAttr return out } -func seedPeerColorOptions(profile bool) []tg.HelpPeerColorOption { +func DefaultPeerColorOptions(profile bool) []tg.HelpPeerColorOption { if profile { peerColorOptionsCache.profileOnce.Do(func() { - peerColorOptionsCache.profile = buildSeedPeerColorOptions(true) + peerColorOptionsCache.profile = buildDefaultPeerColorOptions(true) }) return clonePeerColorOptions(peerColorOptionsCache.profile) } peerColorOptionsCache.regularOnce.Do(func() { - peerColorOptionsCache.regular = buildSeedPeerColorOptions(false) + peerColorOptionsCache.regular = buildDefaultPeerColorOptions(false) }) return clonePeerColorOptions(peerColorOptionsCache.regular) } -func buildSeedPeerColorOptions(profile bool) []tg.HelpPeerColorOption { +func buildDefaultPeerColorOptions(profile bool) []tg.HelpPeerColorOption { catalog := appearance.Default() source := catalog.PeerColors if profile { @@ -193,10 +193,10 @@ func buildSeedPeerColorOptions(profile bool) []tg.HelpPeerColorOption { if groupMin > 0 { option.SetGroupMinLevel(groupMin) } - if colors := seedPeerColorSet(color.Colors); colors != nil { + if colors := DefaultPeerColorSet(color.Colors); colors != nil { option.SetColors(colors) } - if colors := seedPeerColorSet(color.DarkColors); colors != nil { + if colors := DefaultPeerColorSet(color.DarkColors); colors != nil { option.SetDarkColors(colors) } out = append(out, option) @@ -246,7 +246,7 @@ func boundedPeerColorMinLevel(level int) int { return level } -func seedPeerColorID(id int, profile bool) (bool, bool) { +func DefaultPeerColorID(id int, profile bool) (bool, bool) { catalog := appearance.Default() source := catalog.PeerColors if profile { @@ -263,7 +263,7 @@ func seedPeerColorID(id int, profile bool) (bool, bool) { return false, true } -func seedPeerColorSet(in *appearance.ColorSet) tg.HelpPeerColorSetClass { +func DefaultPeerColorSet(in *appearance.ColorSet) tg.HelpPeerColorSetClass { if in == nil { return nil } diff --git a/internal/compat/tdesktop/config.go b/internal/compat/tdesktop/config.go index 0a9db37b..f4de71e4 100644 --- a/internal/compat/tdesktop/config.go +++ b/internal/compat/tdesktop/config.go @@ -3,7 +3,7 @@ package tdesktop import ( "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/links" ) diff --git a/internal/compat/tdesktop/defaults.go b/internal/compat/tdesktop/defaults.go index fb1aa145..ac40863f 100644 --- a/internal/compat/tdesktop/defaults.go +++ b/internal/compat/tdesktop/defaults.go @@ -1,7 +1,7 @@ package tdesktop import ( - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/seed/catalog" ) diff --git a/internal/compat/tdesktop/startup_stubs.go b/internal/compat/tdesktop/startup_stubs.go index d0fbe99e..1c992687 100644 --- a/internal/compat/tdesktop/startup_stubs.go +++ b/internal/compat/tdesktop/startup_stubs.go @@ -3,7 +3,7 @@ package tdesktop import ( "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/seed/appearance" "telesrv/internal/seed/catalog" @@ -147,7 +147,7 @@ func catalogThemeSettings(s appearance.ThemeSettings, base tg.BaseThemeClass) tg ts.SetMessageColors(append([]int(nil), s.MessageColors...)) } if s.Wallpaper.ID != 0 || s.Wallpaper.Document.ID != 0 { - ts.SetWallpaper(seedWallPaper(s.Wallpaper)) + ts.SetWallpaper(DefaultWallPaper(s.Wallpaper)) } return ts } @@ -194,13 +194,13 @@ func UniqueGiftChatThemes(hash int64) tg.AccountChatThemesClass { } } -// WallPapers returns the read-only default wallpaper catalog. User wallpaper +// WallPapers returns the read-only Default wallpaper catalog. User wallpaper // upload/save/install remains outside the current TDesktop compatibility scope. func WallPapers(hash int64) tg.AccountWallPapersClass { if hash == wallPapersHash { return &tg.AccountWallPapersNotModified{} } - wallpapers := seedWallPapers() + wallpapers := DefaultWallPapers() return &tg.AccountWallPapers{ Hash: wallPapersHash, Wallpapers: wallpapers, @@ -425,7 +425,7 @@ var defaultPeerColors = []defaultPeerColor{ // IsPeerColorID reports whether id is in the TDesktop-compatible peer color palette. func IsPeerColorID(id int) bool { - if found, seeded := seedPeerColorID(id, false); seeded { + if found, seeded := DefaultPeerColorID(id, false); seeded { return found } for _, color := range defaultPeerColors { @@ -438,7 +438,7 @@ func IsPeerColorID(id int) bool { // IsPeerProfileColorID reports whether id is in the profile background palette. func IsPeerProfileColorID(id int) bool { - if found, seeded := seedPeerColorID(id, true); seeded { + if found, seeded := DefaultPeerColorID(id, true); seeded { return found } return IsPeerColorID(id) @@ -448,7 +448,7 @@ func PeerColors(hash int) tg.HelpPeerColorsClass { if hash == peerColorsHash { return &tg.HelpPeerColorsNotModified{} } - colors := seedPeerColorOptions(false) + colors := DefaultPeerColorOptions(false) if len(colors) == 0 { colors = make([]tg.HelpPeerColorOption, 0, len(defaultPeerColors)) for _, color := range defaultPeerColors { @@ -468,7 +468,7 @@ func PeerProfileColors(hash int) tg.HelpPeerColorsClass { if hash == peerProfileColorsHash { return &tg.HelpPeerColorsNotModified{} } - colors := seedPeerColorOptions(true) + colors := DefaultPeerColorOptions(true) if len(colors) == 0 { colors = make([]tg.HelpPeerColorOption, 0, len(defaultPeerColors)) for _, color := range defaultPeerColors { diff --git a/internal/compat/tdesktop/startup_stubs_test.go b/internal/compat/tdesktop/startup_stubs_test.go index d7ad3e60..8b3b090c 100644 --- a/internal/compat/tdesktop/startup_stubs_test.go +++ b/internal/compat/tdesktop/startup_stubs_test.go @@ -4,7 +4,7 @@ import ( "math" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) func TestNotifySettingsDefaultIsAudible(t *testing.T) { @@ -233,7 +233,7 @@ func TestUniqueGiftChatThemesIsEmptyHashableStub(t *testing.T) { } } -func TestWallPapersUsesOrangeFileCatalog(t *testing.T) { +func TestWallPapersUsesDefaultFileCatalog(t *testing.T) { got, ok := WallPapers(0).(*tg.AccountWallPapers) if !ok { t.Fatalf("WallPapers(0) = %T, want modified list", got) @@ -249,14 +249,14 @@ func TestWallPapersUsesOrangeFileCatalog(t *testing.T) { t.Fatalf("WallPapers(0).Wallpapers[0] = %T, want *tg.WallPaper", got.Wallpapers[0]) } if wallpaper.ID == 0 || wallpaper.AccessHash == 0 || wallpaper.Slug == "" { - t.Fatalf("wallpaper identity = id %d hash %d slug %q, want seed ids", wallpaper.ID, wallpaper.AccessHash, wallpaper.Slug) + t.Fatalf("wallpaper identity = id %d hash %d slug %q, want Default ids", wallpaper.ID, wallpaper.AccessHash, wallpaper.Slug) } doc, ok := wallpaper.Document.(*tg.Document) if !ok { t.Fatalf("wallpaper document = %T, want *tg.Document", wallpaper.Document) } if doc.ID == 0 || doc.AccessHash == 0 || doc.Size == 0 || doc.MimeType == "" || doc.DCID != appearanceSeedDCID { - t.Fatalf("wallpaper document = id %d hash %d size %d mime %q dc %d, want downloadable seed document", + t.Fatalf("wallpaper document = id %d hash %d size %d mime %q dc %d, want downloadable Default document", doc.ID, doc.AccessHash, doc.Size, doc.MimeType, doc.DCID) } if len(doc.Thumbs) == 0 { @@ -392,7 +392,7 @@ func TestPeerColorsAreNonEmptyHashableAccentSets(t *testing.T) { t.Fatalf("PeerColors(0) = hash %d colors %d, want non-empty stable list", got.Hash, len(got.Colors)) } if len(got.Colors) != 21 { - t.Fatalf("PeerColors(0).Colors length = %d, want seed palette count 21", len(got.Colors)) + t.Fatalf("PeerColors(0).Colors length = %d, want Default palette count 21", len(got.Colors)) } withExplicitColors := 0 for i, option := range got.Colors { @@ -412,7 +412,7 @@ func TestPeerColorsAreNonEmptyHashableAccentSets(t *testing.T) { withExplicitColors++ } if withExplicitColors == 0 { - t.Fatal("PeerColors() has no explicit seed color sets") + t.Fatal("PeerColors() has no explicit Default color sets") } if _, ok := PeerColors(got.Hash).(*tg.HelpPeerColorsNotModified); !ok { t.Fatalf("PeerColors(hash) = %#v, want notModified", PeerColors(got.Hash)) @@ -428,7 +428,7 @@ func TestPeerProfileColorsAreNonEmptyHashableProfileSets(t *testing.T) { t.Fatalf("PeerProfileColors(0) = hash %d colors %d, want non-empty stable list", got.Hash, len(got.Colors)) } if len(got.Colors) != 16 { - t.Fatalf("PeerProfileColors(0).Colors length = %d, want seed profile palette count 16", len(got.Colors)) + t.Fatalf("PeerProfileColors(0).Colors length = %d, want Default profile palette count 16", len(got.Colors)) } for i, option := range got.Colors { if !IsPeerProfileColorID(option.ColorID) { diff --git a/internal/config/config.go b/internal/config/config.go index bfc690e0..73c2f5d7 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -36,13 +36,23 @@ type Config struct { // MTProtoMaxConcurrentHandshakes 限制昂贵 RSA/DH exchange 并发;负数关闭。 MTProtoMaxConcurrentHandshakes int // MTProto RPC 使用 Server 共享公平调度器;per-connection 与 global 预算共同限制 - // goroutine、排队任务和 request body 内存。 + // goroutine、排队任务和 request memory charge。legacy charge 等于 copied body, + // exact charge 是 typed decode 前的保守 materialization 上界,不等同 wire bytes。 MTProtoRPCMaxInflight int MTProtoRPCQueueSize int MTProtoRPCTimeout time.Duration MTProtoRPCGlobalWorkers int MTProtoRPCGlobalMaxTasks int MTProtoRPCGlobalMaxBytes int64 + // Pending ownership and completed rpc_result replay state share a three-level + // global/raw-auth/session budget over the full MTProto duplicate horizon. + MTProtoRPCResultCacheMaxEntries int + MTProtoRPCResultCacheMaxBytes int64 + MTProtoRPCResultCacheAuthMaxEntries int + MTProtoRPCResultCacheAuthMaxBytes int64 + MTProtoRPCResultCacheSessionMaxEntries int + MTProtoRPCResultCacheSessionMaxBytes int64 + MTProtoRPCResultPendingPerAuth int // MTProtoInboundFrameGlobalMaxBytes 是 transport wire + 最大解密 plaintext 的 // 进程级在途预算;frame 长度读出后、payload 分配前预留。 MTProtoInboundFrameGlobalMaxBytes int64 @@ -391,18 +401,29 @@ func Load() (Config, error) { // AdvertiseIP 当前不影响 help.getConfig——getConfig 返回空 DCOptions, // 客户端使用其写死的 static DC 地址(见 compat/tdesktop/config.go)。 // 字段与默认值保留,供未来需要显式下发 DC 地址时使用。 - AdvertiseIP: envOr("TELESRV_ADVERTISE_IP", "127.0.0.1"), - RSAKeyPath: envOr("TELESRV_RSA_KEY", "data/server_rsa.pem"), - DC: envIntOr("TELESRV_DC", 2), - MTProtoMaxConnections: envIntOr("TELESRV_MTPROTO_MAX_CONNECTIONS", 200000), - MTProtoMaxConnectionsPerIP: envIntOr("TELESRV_MTPROTO_MAX_CONNECTIONS_PER_IP", 4096), - MTProtoMaxConcurrentHandshakes: envIntOr("TELESRV_MTPROTO_MAX_CONCURRENT_HANDSHAKES", 256), - MTProtoRPCMaxInflight: envIntOr("TELESRV_MTPROTO_RPC_MAX_INFLIGHT", 32), - MTProtoRPCQueueSize: envIntOr("TELESRV_MTPROTO_RPC_QUEUE_SIZE", 64), - MTProtoRPCTimeout: envDurationOr("TELESRV_MTPROTO_RPC_TIMEOUT", 30*time.Second), - MTProtoRPCGlobalWorkers: envIntOr("TELESRV_MTPROTO_RPC_GLOBAL_WORKERS", 256), - MTProtoRPCGlobalMaxTasks: envIntOr("TELESRV_MTPROTO_RPC_GLOBAL_MAX_TASKS", 8192), - MTProtoRPCGlobalMaxBytes: envInt64Or("TELESRV_MTPROTO_RPC_GLOBAL_MAX_BYTES", 512<<20), + AdvertiseIP: envOr("TELESRV_ADVERTISE_IP", "127.0.0.1"), + RSAKeyPath: envOr("TELESRV_RSA_KEY", "data/server_rsa.pem"), + DC: envIntOr("TELESRV_DC", 2), + MTProtoMaxConnections: envIntOr("TELESRV_MTPROTO_MAX_CONNECTIONS", 200000), + MTProtoMaxConnectionsPerIP: envIntOr("TELESRV_MTPROTO_MAX_CONNECTIONS_PER_IP", 4096), + MTProtoMaxConcurrentHandshakes: envIntOr("TELESRV_MTPROTO_MAX_CONCURRENT_HANDSHAKES", 256), + MTProtoRPCMaxInflight: envIntOr("TELESRV_MTPROTO_RPC_MAX_INFLIGHT", 32), + MTProtoRPCQueueSize: envIntOr("TELESRV_MTPROTO_RPC_QUEUE_SIZE", 64), + MTProtoRPCTimeout: envDurationOr("TELESRV_MTPROTO_RPC_TIMEOUT", 30*time.Second), + MTProtoRPCGlobalWorkers: envIntOr("TELESRV_MTPROTO_RPC_GLOBAL_WORKERS", 256), + MTProtoRPCGlobalMaxTasks: envIntOr("TELESRV_MTPROTO_RPC_GLOBAL_MAX_TASKS", 8192), + MTProtoRPCGlobalMaxBytes: envInt64Or("TELESRV_MTPROTO_RPC_GLOBAL_MAX_BYTES", 512<<20), + MTProtoRPCResultCacheMaxEntries: envIntOr("TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES", 1<<18), + MTProtoRPCResultCacheMaxBytes: envInt64Or("TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_BYTES", 64<<20), + MTProtoRPCResultCacheAuthMaxEntries: envIntOr("TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_ENTRIES", 1<<15), + MTProtoRPCResultCacheAuthMaxBytes: envInt64Or("TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_BYTES", 32<<20), + MTProtoRPCResultCacheSessionMaxEntries: envIntOr( + "TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_ENTRIES", 1<<14, + ), + MTProtoRPCResultCacheSessionMaxBytes: envInt64Or( + "TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_BYTES", 16<<20, + ), + MTProtoRPCResultPendingPerAuth: envIntOr("TELESRV_MTPROTO_RPC_RESULT_PENDING_PER_AUTH", 1<<11), MTProtoInboundFrameGlobalMaxBytes: envInt64Or("TELESRV_MTPROTO_INBOUND_FRAME_GLOBAL_MAX_BYTES", 512<<20), MTProtoOutboundQueueSize: envIntOr("TELESRV_MTPROTO_OUTBOUND_QUEUE_SIZE", 128), MTProtoOutboundControlQueueSize: envIntOr("TELESRV_MTPROTO_OUTBOUND_CONTROL_QUEUE_SIZE", 32), @@ -549,9 +570,45 @@ func Load() (Config, error) { if err := validateLoginEmailConfig(cfg); err != nil { return Config{}, err } + if err := validateRPCResultCacheConfig(cfg); err != nil { + return Config{}, err + } return cfg, nil } +const mtProtoRPCResultMinBytes = int64((1 << 24) - (2 << 10)) + +func validateRPCResultCacheConfig(cfg Config) error { + if cfg.MTProtoRPCResultCacheMaxEntries <= 0 || cfg.MTProtoRPCResultCacheAuthMaxEntries <= 0 || + cfg.MTProtoRPCResultCacheSessionMaxEntries <= 0 { + return fmt.Errorf("MTProto rpc_result entry limits must be positive") + } + if cfg.MTProtoRPCResultCacheMaxEntries < cfg.MTProtoRPCResultCacheAuthMaxEntries || + cfg.MTProtoRPCResultCacheAuthMaxEntries < cfg.MTProtoRPCResultCacheSessionMaxEntries { + return fmt.Errorf("MTProto rpc_result entry hierarchy must satisfy global >= auth >= session: %d/%d/%d", + cfg.MTProtoRPCResultCacheMaxEntries, cfg.MTProtoRPCResultCacheAuthMaxEntries, cfg.MTProtoRPCResultCacheSessionMaxEntries) + } + if cfg.MTProtoRPCResultCacheMaxBytes < mtProtoRPCResultMinBytes || + cfg.MTProtoRPCResultCacheAuthMaxBytes < mtProtoRPCResultMinBytes || + cfg.MTProtoRPCResultCacheSessionMaxBytes < mtProtoRPCResultMinBytes { + return fmt.Errorf("MTProto rpc_result byte limits must each be at least %d: %d/%d/%d", + mtProtoRPCResultMinBytes, cfg.MTProtoRPCResultCacheMaxBytes, + cfg.MTProtoRPCResultCacheAuthMaxBytes, cfg.MTProtoRPCResultCacheSessionMaxBytes) + } + if cfg.MTProtoRPCResultCacheMaxBytes < cfg.MTProtoRPCResultCacheAuthMaxBytes || + cfg.MTProtoRPCResultCacheAuthMaxBytes < cfg.MTProtoRPCResultCacheSessionMaxBytes { + return fmt.Errorf("MTProto rpc_result byte hierarchy must satisfy global >= auth >= session: %d/%d/%d", + cfg.MTProtoRPCResultCacheMaxBytes, cfg.MTProtoRPCResultCacheAuthMaxBytes, cfg.MTProtoRPCResultCacheSessionMaxBytes) + } + if cfg.MTProtoRPCGlobalMaxTasks <= 0 || cfg.MTProtoRPCResultPendingPerAuth <= 0 || + cfg.MTProtoRPCResultPendingPerAuth > cfg.MTProtoRPCGlobalMaxTasks || + cfg.MTProtoRPCResultPendingPerAuth > cfg.MTProtoRPCResultCacheAuthMaxEntries { + return fmt.Errorf("MTProto rpc_result pending-per-auth %d must be positive and <= global pending %d and auth entries %d", + cfg.MTProtoRPCResultPendingPerAuth, cfg.MTProtoRPCGlobalMaxTasks, cfg.MTProtoRPCResultCacheAuthMaxEntries) + } + return nil +} + func validateLoginEmailConfig(cfg Config) error { if cfg.LoginEmailRequireSetup && !cfg.LoginEmailEnable { return fmt.Errorf("TELESRV_LOGIN_EMAIL_REQUIRE_SETUP requires TELESRV_LOGIN_EMAIL_ENABLE=true") diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 57135da2..86c5ce1c 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -57,6 +57,13 @@ func TestLoadMTProtoAdmissionAndRPCBudgets(t *testing.T) { t.Setenv("TELESRV_MTPROTO_RPC_GLOBAL_WORKERS", "33") t.Setenv("TELESRV_MTPROTO_RPC_GLOBAL_MAX_TASKS", "444") t.Setenv("TELESRV_MTPROTO_RPC_GLOBAL_MAX_BYTES", "555555") + t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES", "555") + t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_BYTES", "70000000") + t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_ENTRIES", "444") + t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_BYTES", "40000000") + t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_ENTRIES", "333") + t.Setenv("TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_BYTES", "20000000") + t.Setenv("TELESRV_MTPROTO_RPC_RESULT_PENDING_PER_AUTH", "222") t.Setenv("TELESRV_MTPROTO_INBOUND_FRAME_GLOBAL_MAX_BYTES", "777777") t.Setenv("TELESRV_MTPROTO_OUTBOUND_QUEUE_SIZE", "88") t.Setenv("TELESRV_MTPROTO_OUTBOUND_CONTROL_QUEUE_SIZE", "22") @@ -77,6 +84,16 @@ func TestLoadMTProtoAdmissionAndRPCBudgets(t *testing.T) { cfg.MTProtoRPCGlobalWorkers != 33 || cfg.MTProtoRPCGlobalMaxTasks != 444 || cfg.MTProtoRPCGlobalMaxBytes != 555555 { t.Fatalf("rpc budget config = %d/%d/%v/%d/%d/%d", cfg.MTProtoRPCMaxInflight, cfg.MTProtoRPCQueueSize, cfg.MTProtoRPCTimeout, cfg.MTProtoRPCGlobalWorkers, cfg.MTProtoRPCGlobalMaxTasks, cfg.MTProtoRPCGlobalMaxBytes) } + if cfg.MTProtoRPCResultCacheMaxEntries != 555 || cfg.MTProtoRPCResultCacheMaxBytes != 70000000 || + cfg.MTProtoRPCResultCacheAuthMaxEntries != 444 || cfg.MTProtoRPCResultCacheAuthMaxBytes != 40000000 || + cfg.MTProtoRPCResultCacheSessionMaxEntries != 333 || cfg.MTProtoRPCResultCacheSessionMaxBytes != 20000000 || + cfg.MTProtoRPCResultPendingPerAuth != 222 { + t.Fatalf("rpc result cache config = global:%d/%d auth:%d/%d session:%d/%d pending/auth:%d", + cfg.MTProtoRPCResultCacheMaxEntries, cfg.MTProtoRPCResultCacheMaxBytes, + cfg.MTProtoRPCResultCacheAuthMaxEntries, cfg.MTProtoRPCResultCacheAuthMaxBytes, + cfg.MTProtoRPCResultCacheSessionMaxEntries, cfg.MTProtoRPCResultCacheSessionMaxBytes, + cfg.MTProtoRPCResultPendingPerAuth) + } if cfg.MTProtoInboundFrameGlobalMaxBytes != 777777 { t.Fatalf("inbound frame budget config = %d", cfg.MTProtoInboundFrameGlobalMaxBytes) } @@ -88,6 +105,46 @@ func TestLoadMTProtoAdmissionAndRPCBudgets(t *testing.T) { } } +func TestLoadRPCResultFairBudgetDefaults(t *testing.T) { + disableDefaultConfigFile(t) + cfg, err := Load() + if err != nil { + t.Fatalf("Load: %v", err) + } + if cfg.MTProtoRPCResultCacheMaxEntries != 1<<18 || cfg.MTProtoRPCResultCacheMaxBytes != 64<<20 || + cfg.MTProtoRPCResultCacheAuthMaxEntries != 1<<15 || cfg.MTProtoRPCResultCacheAuthMaxBytes != 32<<20 || + cfg.MTProtoRPCResultCacheSessionMaxEntries != 1<<14 || cfg.MTProtoRPCResultCacheSessionMaxBytes != 16<<20 || + cfg.MTProtoRPCResultPendingPerAuth != 1<<11 { + t.Fatalf("rpc_result fair defaults = global:%d/%d auth:%d/%d session:%d/%d pending/auth:%d", + cfg.MTProtoRPCResultCacheMaxEntries, cfg.MTProtoRPCResultCacheMaxBytes, + cfg.MTProtoRPCResultCacheAuthMaxEntries, cfg.MTProtoRPCResultCacheAuthMaxBytes, + cfg.MTProtoRPCResultCacheSessionMaxEntries, cfg.MTProtoRPCResultCacheSessionMaxBytes, + cfg.MTProtoRPCResultPendingPerAuth) + } +} + +func TestLoadRejectsInvalidRPCResultFairBudgets(t *testing.T) { + tests := []struct { + name string + key string + value string + }{ + {name: "entry hierarchy", key: "TELESRV_MTPROTO_RPC_RESULT_CACHE_MAX_ENTRIES", value: "1024"}, + {name: "byte below outbound body", key: "TELESRV_MTPROTO_RPC_RESULT_CACHE_SESSION_MAX_BYTES", value: "16700000"}, + {name: "byte hierarchy", key: "TELESRV_MTPROTO_RPC_RESULT_CACHE_AUTH_MAX_BYTES", value: "70000000"}, + {name: "pending hierarchy", key: "TELESRV_MTPROTO_RPC_RESULT_PENDING_PER_AUTH", value: "9000"}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + disableDefaultConfigFile(t) + t.Setenv(test.key, test.value) + if _, err := Load(); err == nil { + t.Fatalf("Load accepted invalid %s=%s", test.key, test.value) + } + }) + } +} + func TestLoadOutboxPoisonPolicy(t *testing.T) { disableDefaultConfigFile(t) t.Setenv("TELESRV_OUTBOX_POISON_RETENTION", "2m") diff --git a/internal/domain/authorization.go b/internal/domain/authorization.go index 6f79617a..ae52b504 100644 --- a/internal/domain/authorization.go +++ b/internal/domain/authorization.go @@ -5,9 +5,12 @@ import "time" // Authorization 是一条设备授权:auth_key 与 user 的绑定 + initConnection 设备信息。 // auth_key 是协议产物、授权是业务产物,故独立于 store.AuthKeyData。 type Authorization struct { - AuthKeyID [8]byte // 协议原生 auth_key_id;store 边界按小端转 int64 - UserID int64 - Hash int64 + AuthKeyID [8]byte // 协议原生 auth_key_id;store 边界按小端转 int64 + UserID int64 + Hash int64 + // Layer is the last supported protocol profile explicitly observed for this + // auth key. It is a durable default for a new session, never an instruction + // to rewrite an already-active session's own profile. Layer int DeviceModel string Platform string @@ -23,13 +26,18 @@ type Authorization struct { } // AuthKeyClientInfo 是未登录 auth_key 也需要保留的客户端协商元数据。 -// 登录后的设备授权仍由 Authorization 表达;这里仅用于服务端重启后恢复 -// pre-auth / setup 流程的 client type 与 layer。 +// 登录后的设备授权仍由 Authorization 表达。Layer 保存最后一次受支持的显式 +// wire profile,供服务端重启后为同一 auth key 的新 session 初始化默认值;活跃 +// session 仍以自己的显式 invokeWithLayer 纠正值为准。 type AuthKeyClientInfo struct { - Layer int - DeviceModel string - Platform string - SystemVersion string - APIID int - AppVersion string + Layer int + // LayerObservationID is a read-only ordering token owned by the protocol + // store. Generic client metadata updates must never manufacture or advance + // it; only ordered invokeWithLayer evidence may do so. + LayerObservationID int64 + DeviceModel string + Platform string + SystemVersion string + APIID int + AppVersion string } diff --git a/internal/domain/doc.go b/internal/domain/doc.go index 22c78c12..046e8f09 100644 --- a/internal/domain/doc.go +++ b/internal/domain/doc.go @@ -1,4 +1,4 @@ // Package domain 存放业务实体与值对象(User、Peer、Dialog、Message、MessageID 等)。 // -// 铁律:本包禁止依赖 gotd/td/tg 等协议层类型;TL 类型只允许出现在 RPC/MTProto 边界。 +// 铁律:本包禁止依赖 iamxvbaba/td/tg 等协议层类型;TL 类型只允许出现在 RPC/MTProto 边界。 package domain diff --git a/internal/domain/update.go b/internal/domain/update.go index fb36a8e3..07e437cc 100644 --- a/internal/domain/update.go +++ b/internal/domain/update.go @@ -8,3 +8,14 @@ type UpdateState struct { Date int Seq int } + +// UpdateStateCommitMode describes what a physically delivered update-state +// response proves. Every delivered baseline advances the device-local +// confirmed cursor; only an explicitly audited getState baseline also proves +// that retention may advance the client-observed cursor to the same point. +type UpdateStateCommitMode uint8 + +const ( + UpdateStateCommitDeliveredOnly UpdateStateCommitMode = iota + 1 + UpdateStateCommitDeliveredAndObservedBaseline +) diff --git a/internal/mtprotoedge/admission_test.go b/internal/mtprotoedge/admission_test.go index 1ce201ef..7dd96545 100644 --- a/internal/mtprotoedge/admission_test.go +++ b/internal/mtprotoedge/admission_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto/codec" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto/codec" "telesrv/internal/store" "telesrv/internal/store/memory" diff --git a/internal/mtprotoedge/auth_key_expiry_test.go b/internal/mtprotoedge/auth_key_expiry_test.go index 0973b685..88aa5997 100644 --- a/internal/mtprotoedge/auth_key_expiry_test.go +++ b/internal/mtprotoedge/auth_key_expiry_test.go @@ -12,15 +12,15 @@ import ( "go.uber.org/zap/zaptest" "github.com/gotd/log/logzap" - "github.com/gotd/td/bin" - "github.com/gotd/td/clock" - "github.com/gotd/td/crypto" - "github.com/gotd/td/exchange" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" ) func TestAuthKeyProtocolUnavailable(t *testing.T) { @@ -118,9 +118,9 @@ func TestActiveTemporaryAuthKeyExpiresBeforeNextRPCDispatch(t *testing.T) { testClock := newExpiryTestClock(now) handler := &admissionCountingRPC{} addr, pub, srv := startTestServer(t, Options{ - DC: dc, - Clock: testClock, - RPC: handler, + DC: dc, + Clock: testClock, + legacyRPC: handler, }) conn, auth, cipher := dialTemporaryHandshakeForExpiryTest(t, addr, dc, expiresIn, pub) @@ -179,7 +179,7 @@ func TestExpiredTemporaryAuthKeyRejectsServerPushWithoutWireWrite(t *testing.T) c.authKeyExpiresAt = int(now.Unix()) err := c.SendBestEffortEncoded(context.Background(), proto.MessageFromServer, - &encodedOutboundMessage{typeID: tg.UpdatesTooLongTypeID, body: []byte{0x0b, 0xa1, 0x01, 0xe3}}, 0) + exactTestUpdatesTooLong(t, c), 0) if !errors.Is(err, ErrConnClosed) { t.Fatalf("push on expired temp key = %v, want ErrConnClosed", err) } @@ -198,7 +198,7 @@ func TestQueuedPushCannotCrossTemporaryAuthKeyExpiry(t *testing.T) { c := newOutboundTestConn(t, tr, nil) c.now = clock.Now c.authKeyExpiresAt = int(now.Add(time.Minute).Unix()) - encoded := &encodedOutboundMessage{typeID: tg.UpdatesTooLongTypeID, body: []byte{0x0b, 0xa1, 0x01, 0xe3}} + encoded := exactTestUpdatesTooLong(t, c) if err := c.SendBestEffortEncoded(context.Background(), proto.MessageFromServer, encoded, 0); err != nil { t.Fatalf("enqueue first push: %v", err) @@ -247,7 +247,7 @@ func TestTemporaryAuthKeyExpiryWhileWaitingForPhysicalWriterSkipsRawSend(t *test t.Fatal("direct protocol write did not acquire physical writer") } - encoded := &encodedOutboundMessage{typeID: tg.UpdatesTooLongTypeID, body: []byte{0x0b, 0xa1, 0x01, 0xe3}} + encoded := exactTestUpdatesTooLong(t, c) actorDone := make(chan error, 1) go func() { actorDone <- c.SendEncoded(context.Background(), proto.MessageFromServer, encoded) @@ -295,9 +295,9 @@ func TestRetiredActorWaitingForPhysicalWriterDoesNotDefeatLeaseTransfer(t *testi } actorDone := make(chan error, 1) + encoded := exactTestUpdatesTooLong(t, c) go func() { - actorDone <- c.SendEncoded(context.Background(), proto.MessageFromServer, - &encodedOutboundMessage{typeID: tg.UpdatesTooLongTypeID, body: []byte{0x0b, 0xa1, 0x01, 0xe3}}) + actorDone <- c.SendEncoded(context.Background(), proto.MessageFromServer, encoded) }() select { case <-signaling.entered: @@ -350,9 +350,9 @@ func TestTerminalAuthKeyNotFoundSurvivesActorWaitingForPhysicalWriter(t *testing case <-time.After(time.Second): t.Fatal("direct protocol write did not acquire physical writer") } + encoded := exactTestUpdatesTooLong(t, c) go func() { - _ = c.SendEncoded(context.Background(), proto.MessageFromServer, - &encodedOutboundMessage{typeID: tg.UpdatesTooLongTypeID, body: []byte{0x0b, 0xa1, 0x01, 0xe3}}) + _ = c.SendEncoded(context.Background(), proto.MessageFromServer, encoded) }() select { case <-signaling.entered: @@ -402,7 +402,7 @@ func TestTerminalAuthKeyNotFoundWaitsForOutboundAndIsLastFrame(t *testing.T) { c.transportLease = lease c.now = clock.Now c.authKeyExpiresAt = int(now.Add(time.Minute).Unix()) - encoded := &encodedOutboundMessage{typeID: tg.UpdatesTooLongTypeID, body: []byte{0x0b, 0xa1, 0x01, 0xe3}} + encoded := exactTestUpdatesTooLong(t, c) if err := c.SendBestEffortEncoded(context.Background(), proto.MessageFromServer, encoded, 0); err != nil { t.Fatalf("enqueue blocked push: %v", err) } diff --git a/internal/mtprotoedge/auth_key_switch_test.go b/internal/mtprotoedge/auth_key_switch_test.go index 5bd1e65d..229e1a32 100644 --- a/internal/mtprotoedge/auth_key_switch_test.go +++ b/internal/mtprotoedge/auth_key_switch_test.go @@ -4,8 +4,8 @@ import ( "testing" "time" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" ) func TestEncryptedConnectionSwitchesAuthKeyEvenWhenSessionIDIsReused(t *testing.T) { diff --git a/internal/mtprotoedge/bot_callback_e2e_test.go b/internal/mtprotoedge/bot_callback_e2e_test.go index 12f07d53..dcd34342 100644 --- a/internal/mtprotoedge/bot_callback_e2e_test.go +++ b/internal/mtprotoedge/bot_callback_e2e_test.go @@ -12,13 +12,13 @@ import ( "go.uber.org/zap/zaptest" "github.com/gotd/log/logzap" - "github.com/gotd/td/clock" - "github.com/gotd/td/exchange" - "github.com/gotd/td/session" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/session" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" "telesrv/internal/app/account" "telesrv/internal/app/auth" @@ -84,8 +84,19 @@ func newBotCallbackEnv(t *testing.T, ctx context.Context) *botCallbackEnv { router := rpc.New(rpc.Config{DC: dc, IP: tcpAddr.IP.String(), Port: tcpAddr.Port}, deps, zaptest.NewLogger(t), clock.System) botsService.SetRouterHooks(router) botsService.SetTextDraftPusher(router) - srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, RPC: router, ActiveSessions: activeSessions}) - go func() { _ = srv.Serve(ctx, ln) }() + srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, LayerRPC: router, ActiveSessions: activeSessions}) + serveErr := make(chan error, 1) + go func() { serveErr <- srv.Serve(ctx, ln) }() + t.Cleanup(func() { + select { + case err := <-serveErr: + if err != nil { + t.Errorf("serve: %v", err) + } + case <-time.After(5 * time.Second): + t.Error("server did not stop after callback test context cancellation") + } + }) newCli := func(storage *session.StorageMemory, handler telegram.UpdateHandler) *telegram.Client { if handler == nil { diff --git a/internal/mtprotoedge/bot_e2e_test.go b/internal/mtprotoedge/bot_e2e_test.go index 5fbc0021..7ff15bf2 100644 --- a/internal/mtprotoedge/bot_e2e_test.go +++ b/internal/mtprotoedge/bot_e2e_test.go @@ -13,14 +13,14 @@ import ( "go.uber.org/zap/zaptest" "github.com/gotd/log/logzap" - "github.com/gotd/td/clock" - "github.com/gotd/td/exchange" - "github.com/gotd/td/session" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/session" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" + "github.com/iamxvbaba/td/transport" "telesrv/internal/app/account" "telesrv/internal/app/auth" @@ -87,7 +87,7 @@ func TestBotManagementRPCFlow(t *testing.T) { router := rpc.New(rpc.Config{DC: dc, IP: tcpAddr.IP.String(), Port: tcpAddr.Port}, deps, zaptest.NewLogger(t), clock.System) botsService.SetRouterHooks(router) botsService.SetTextDraftPusher(router) - srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, RPC: router, ActiveSessions: activeSessions}) + srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, LayerRPC: router, ActiveSessions: activeSessions}) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() @@ -323,7 +323,7 @@ func TestBotFatherCreateAndBotLoginFlow(t *testing.T) { router := rpc.New(rpc.Config{DC: dc, IP: tcpAddr.IP.String(), Port: tcpAddr.Port}, deps, zaptest.NewLogger(t), clock.System) botsService.SetRouterHooks(router) botsService.SetTextDraftPusher(router) - srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, RPC: router, ActiveSessions: activeSessions}) + srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, LayerRPC: router, ActiveSessions: activeSessions}) ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() diff --git a/internal/mtprotoedge/conn.go b/internal/mtprotoedge/conn.go index 946425b7..ea27aab8 100644 --- a/internal/mtprotoedge/conn.go +++ b/internal/mtprotoedge/conn.go @@ -4,16 +4,16 @@ import ( "bufio" "context" "encoding/hex" + "errors" "sync" "sync/atomic" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/proto" - "github.com/gotd/td/transport" - - "telesrv/internal/compat/layerwire" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" ) // Conn 是一个已识别 session 的客户端连接,持有向其加密发送消息所需的全部上下文。 @@ -39,6 +39,21 @@ const ( connLifecycleRetired ) +var ( + // ErrLayerProfileUnsupported means the requested profile has no generated + // exact codec. Profiles are never clamped to the nearest supported layer. + ErrLayerProfileUnsupported = errors.New("unsupported exact layer profile") + // ErrLayerProfileConflict means one admitted request carried contradictory + // profile evidence. A later, well-formed invokeWithLayer is allowed to correct + // the connection profile and therefore does not use this error. + ErrLayerProfileConflict = errors.New("connection layer profile conflict") + // ErrLayerProfileEpochExhausted is a defensive terminal guard. Reaching it + // would require more than four billion effective layer corrections on one + // physical connection, so wrapping the epoch and making stale pushes current + // again is never safe. + ErrLayerProfileEpochExhausted = errors.New("connection layer profile epoch exhausted") +) + type Conn struct { transport transport.Conn // transportLease owns exactly one generation of the physical transport. @@ -114,14 +129,22 @@ type Conn struct { rpcRunning int rpcReady bool rpcClosed bool + // rpcReplayRestores is a per-physical-connection ordering barrier. An exact + // cached/rewrapped init request has already executed its business handler, + // but its wrapper/client/readiness state becomes authoritative only after the + // replacement rpc_result is physically written. Queued naked RPCs remain + // admitted and budgeted, but are not scheduler-runnable until every such + // restore finishes or the connection is fenced. + rpcReplayRestores int // Rewrap aliasing never delays execution. initialized stops collecting // candidates after the first valid init wrapper on this physical generation. rpcRewrapInitialized atomic.Bool // rpcResultAcked is invoked by the sole outbound actor after it resolves an // acknowledged server frame back to the rpc_result request msg_id. rpcResultAcked func(*Conn, int64) - // inflightRPCBytes 跟踪已入队未完成的 inbound RPC body 总字节,配合 maxInflightRPCBytes - // 给 RPC 队列设字节预算(不止限条数),防对抗客户端发大请求撑内存。 + // inflightRPCBytes 跟踪已预留/入队/执行中 inbound RPC 的 memory charge;legacy + // 等于 copied body,exact 是 typed materialization 的保守放大值。它配合 + // maxInflightRPCBytes 给 RPC 队列设内存预算(不止限条数)。 inflightRPCBytes atomic.Int64 // 单连接只保留并发配额;实际 worker 来自 Server 共享池,避免每连接预留 goroutine。 rpcRootCtx context.Context @@ -152,9 +175,26 @@ type Conn struct { membershipGen atomic.Int64 // createdAt 是连接建立时刻,供同 auth_key session 数触顶时驱逐真正最旧的连接。 createdAt time.Time - // clientLayer 是本连接协商的 TL layer(invokeWithLayer/initConnection),由 handleRPC - // 在每次 Dispatch 后从 RPC 注册表刷新。出站(rpc_result/push)按此把 227 对象降级给老客户端; - // 0 表示尚未协商,按 canonical(227) 处理=不降级。 + // layerProfileState atomically packs profile, provenance and epoch. A profile + // inherited from auth-key metadata is only a default; a later well-formed + // invokeWithLayer may correct it. The epoch fences proactive updates prepared + // before that correction without invalidating request-bound RPC results. + layerProfileMu sync.RWMutex + // layerProfileEvidenceMsgID is protected by layerProfileMu. Zero means the + // selected profile came from inherited/legacy recovery and therefore has no + // ordered client-message cursor yet. Positive values are the newest accepted + // invokeWithLayer message for this exact MTProto session. + layerProfileEvidenceMsgID int64 + // layerProfileEvidenceLayer retains the raw negotiated Layer even when this + // binary has no generated codec for it. In that case the packed profile stays + // Unknown, but msg_id ordering can still admit a newer supported correction + // and reject an older/same-id rollback. + layerProfileEvidenceLayer int + layerProfileState atomic.Uint64 + // clientLayer is the package-internal mirror used only by legacy state-machine + // regression tests. Production application RPC/result/update encoding uses + // the structured profile state. Zero is unknown and must fail closed if a legacy + // application value reaches an outbound boundary. clientLayer atomic.Int32 } @@ -236,16 +276,55 @@ func (c *Conn) isPhysicalTransportCurrentOpen() bool { return c != nil && (c.transportLease == nil || c.transportLease.IsCurrentOpen()) } -// ClientLayer 返回连接协商的 TL layer;未协商时返回 canonical layer(227,不降级)。 -func (c *Conn) ClientLayer() int { - if l := c.clientLayer.Load(); l != 0 { - return int(l) - } - return layerwire.CanonicalLayer +// LayerProfile returns the exact TL profile currently selected for this +// connection. ok is false until admission or an inherited auth-key default +// supplies a supported generated profile. +func (c *Conn) LayerProfile() (profile tg.LayerProfile, ok bool) { + state := c.LayerProfileState() + return state.Profile, state.Origin != LayerProfileUnknown } -// SetClientLayer 记录连接协商的 TL layer。 -func (c *Conn) SetClientLayer(layer int) { c.clientLayer.Store(int32(layer)) } +// FreezeLayerProfile records explicit protocol evidence observed during ordered +// admission. Repeating the same value is idempotent. A later well-formed +// invokeWithLayer may replace either an inherited default or older explicit +// evidence; already-admitted requests retain their own immutable profile. +func (c *Conn) FreezeLayerProfile(profile tg.LayerProfile) error { + _, err := c.setLayerProfile(profile, LayerProfileExplicit, true) + return err +} + +// FreezeLayerProfileAt applies explicit protocol evidence in client msg_id +// order. A duplicate older than the last accepted evidence is inert; the same +// msg_id carrying another Layer is a protocol conflict. Advancing the evidence +// cursor at an unchanged Layer does not rotate the outbound epoch because the +// wire profile itself did not change. +func (c *Conn) FreezeLayerProfileAt(profile tg.LayerProfile, msgID int64) (bool, error) { + return c.freezeLayerProfileAt(profile, msgID) +} + +// SeedLayerProfile restores explicit evidence previously proven for this exact +// logical session. It is kept as the compatible same-session restore API; +// auth-key-wide metadata must use SeedInheritedLayerProfile instead. +func (c *Conn) SeedLayerProfile(profile tg.LayerProfile) error { + _, err := c.setLayerProfile(profile, LayerProfileExplicit, true) + return err +} + +// SeedInheritedLayerProfile installs an auth-key-wide default only while the +// connection is still unknown. It never overwrites explicit evidence or an +// already selected inherited default; client protocol evidence owns correction. +func (c *Conn) SeedInheritedLayerProfile(profile tg.LayerProfile) error { + _, err := c.setLayerProfile(profile, LayerProfileInherited, false) + return err +} + +// legacyClientLayer returns the test-only canonical-transcoder profile. Zero +// deliberately remains unknown; it must never be converted into an implicit +// canonical application profile. +func (c *Conn) legacyClientLayer() int { return int(c.clientLayer.Load()) } + +// setLegacyClientLayer records the package-internal legacy mirror. +func (c *Conn) setLegacyClientLayer(layer int) { c.clientLayer.Store(int32(layer)) } // AuthKeyID 返回连接的 auth_key_id。 func (c *Conn) AuthKeyID() [8]byte { return c.authKeyID } diff --git a/internal/mtprotoedge/conn_layer_profile.go b/internal/mtprotoedge/conn_layer_profile.go new file mode 100644 index 00000000..4ff303ea --- /dev/null +++ b/internal/mtprotoedge/conn_layer_profile.go @@ -0,0 +1,506 @@ +package mtprotoedge + +import ( + "context" + "fmt" + "math" + + "github.com/iamxvbaba/td/tg" + "go.uber.org/zap" +) + +// LayerProfileOrigin records why a Conn currently uses a wire profile. The +// distinction is protocol-significant: inherited auth-key metadata is a useful +// availability default, while explicit invokeWithLayer evidence may correct it. +type LayerProfileOrigin uint8 + +const ( + LayerProfileUnknown LayerProfileOrigin = iota + LayerProfileInherited + LayerProfileExplicit +) + +// LayerProfileSnapshot is one atomic observation of a connection's current +// profile. Epoch advances on every effective correction, including promotion +// from inherited to explicit evidence at the same numeric layer. +type LayerProfileSnapshot struct { + Profile tg.LayerProfile + Origin LayerProfileOrigin + Epoch uint32 +} + +const ( + layerProfileValueBits = 16 + layerProfileOriginBits = 8 + layerProfileOriginShift = layerProfileValueBits + layerProfileEpochShift = 32 + layerProfileValueMask = uint64(1<> layerProfileOriginShift) & layerProfileOriginMask), + Epoch: uint32(raw >> layerProfileEpochShift), + } +} + +// LayerProfileState returns profile, provenance and epoch from one atomic load. +func (c *Conn) LayerProfileState() LayerProfileSnapshot { + if c == nil { + return LayerProfileSnapshot{} + } + return unpackLayerProfileState(c.layerProfileState.Load()) +} + +func (c *Conn) setLayerProfile(profile tg.LayerProfile, origin LayerProfileOrigin, replace bool) (bool, error) { + if err := validateLayerProfile(profile); err != nil { + return false, err + } + if origin != LayerProfileInherited && origin != LayerProfileExplicit { + return false, fmt.Errorf("invalid layer profile origin %d", origin) + } + c.layerProfileMu.Lock() + defer c.layerProfileMu.Unlock() + for { + raw := c.layerProfileState.Load() + current := unpackLayerProfileState(raw) + if origin == LayerProfileInherited && c.layerProfileEvidenceMsgID > 0 { + return false, nil + } + if current.Origin != LayerProfileUnknown { + if !replace { + return false, nil + } + if current.Profile == profile && current.Origin == origin { + // The force-style compatibility APIs carry no ordered msg_id. + // Clearing the cursor keeps a subsequent production observation + // eligible instead of comparing it with unrelated test/recovery state. + c.layerProfileEvidenceMsgID = 0 + c.layerProfileEvidenceLayer = 0 + return false, nil + } + } + if current.Epoch == math.MaxUint32 { + return false, ErrLayerProfileEpochExhausted + } + next := LayerProfileSnapshot{Profile: profile, Origin: origin, Epoch: current.Epoch + 1} + if c.layerProfileState.CompareAndSwap(raw, packLayerProfileState(next)) { + c.layerProfileEvidenceMsgID = 0 + c.layerProfileEvidenceLayer = 0 + c.setLegacyClientLayer(int(profile)) + return true, nil + } + } +} + +func validateLayerProfile(profile tg.LayerProfile) error { + resolved, ok := tg.ResolveLayerProfile(int(profile)) + if !ok || resolved != profile || uint64(profile) > layerProfileValueMask { + return fmt.Errorf("%w: %d", ErrLayerProfileUnsupported, profile) + } + return nil +} + +// layerProfileEvidenceState observes the packed wire state and its ordering +// cursor under one read lock. LayerProfileState remains the allocation-free +// atomic hot-path accessor used by outbound encoding. +func (c *Conn) layerProfileEvidenceState() (LayerProfileSnapshot, int64) { + state, _, msgID := c.layerProfileRawEvidenceState() + return state, msgID +} + +func (c *Conn) layerProfileRawEvidenceState() (LayerProfileSnapshot, int, int64) { + if c == nil { + return LayerProfileSnapshot{}, 0, 0 + } + c.layerProfileMu.RLock() + state := unpackLayerProfileState(c.layerProfileState.Load()) + layer := c.layerProfileEvidenceLayer + msgID := c.layerProfileEvidenceMsgID + c.layerProfileMu.RUnlock() + if layer == 0 && state.Origin == LayerProfileExplicit { + layer = int(state.Profile) + } + return state, layer, msgID +} + +// freezeLayerProfileAt is the production explicit-evidence transition. The +// positive client msg_id is the protocol ordering authority across TCP +// reconnects and cached request replays. +func (c *Conn) freezeLayerProfileAt(profile tg.LayerProfile, msgID int64) (bool, error) { + if c == nil { + return false, fmt.Errorf("nil connection layer profile") + } + if msgID <= 0 { + return false, fmt.Errorf("invalid layer evidence msg_id %d", msgID) + } + if err := validateLayerProfile(profile); err != nil { + return false, err + } + return c.freezeRawLayerProfileAt(int(profile), msgID) +} + +func (c *Conn) freezeRawLayerProfileAt(layer int, msgID int64) (bool, error) { + if c == nil { + return false, fmt.Errorf("nil connection layer profile") + } + if layer <= 0 || msgID <= 0 { + return false, fmt.Errorf("invalid raw layer evidence layer=%d msg_id=%d", layer, msgID) + } + profile, supported := tg.ResolveLayerProfile(layer) + c.layerProfileMu.Lock() + defer c.layerProfileMu.Unlock() + + current := unpackLayerProfileState(c.layerProfileState.Load()) + if c.layerProfileEvidenceMsgID > 0 { + switch { + case msgID < c.layerProfileEvidenceMsgID: + return false, nil + case msgID == c.layerProfileEvidenceMsgID: + if c.layerProfileEvidenceLayer != layer { + return false, fmt.Errorf("%w: msg_id %d selected both layer %d and %d", ErrLayerProfileConflict, msgID, c.layerProfileEvidenceLayer, layer) + } + return false, nil + } + } + + desired := LayerProfileSnapshot{Epoch: current.Epoch} + if supported { + desired.Profile = profile + desired.Origin = LayerProfileExplicit + } + // A newer proof at the same Layer advances only the ordering cursor. No wire + // bytes prepared under this profile become stale, so rotating epoch would be + // unnecessary push churn. + if current.Profile == desired.Profile && current.Origin == desired.Origin { + c.layerProfileEvidenceLayer = layer + c.layerProfileEvidenceMsgID = msgID + return true, nil + } + if current.Epoch == math.MaxUint32 { + return false, ErrLayerProfileEpochExhausted + } + next := desired + next.Epoch = current.Epoch + 1 + c.layerProfileState.Store(packLayerProfileState(next)) + c.layerProfileEvidenceLayer = layer + c.layerProfileEvidenceMsgID = msgID + if supported { + c.setLegacyClientLayer(layer) + } else { + c.setLegacyClientLayer(0) + } + return true, nil +} + +// seedOrderedLayerProfile restores exact-session evidence atomically before +// any request on a replacement physical connection is admitted. +func (c *Conn) seedOrderedLayerProfile(profile tg.LayerProfile, msgID int64) error { + if c == nil { + return nil + } + if msgID < 0 { + return fmt.Errorf("invalid restored layer evidence msg_id %d", msgID) + } + if err := validateLayerProfile(profile); err != nil { + return err + } + if msgID > 0 { + _, err := c.freezeRawLayerProfileAt(int(profile), msgID) + return err + } + c.layerProfileMu.Lock() + defer c.layerProfileMu.Unlock() + current := unpackLayerProfileState(c.layerProfileState.Load()) + if current.Profile != profile || current.Origin != LayerProfileExplicit { + if current.Epoch == math.MaxUint32 { + return ErrLayerProfileEpochExhausted + } + current = LayerProfileSnapshot{Profile: profile, Origin: LayerProfileExplicit, Epoch: current.Epoch + 1} + c.layerProfileState.Store(packLayerProfileState(current)) + c.setLegacyClientLayer(int(profile)) + } + c.layerProfileEvidenceMsgID = msgID + c.layerProfileEvidenceLayer = 0 + return nil +} + +func (c *Conn) seedRawLayerEvidence(layer int, msgID int64) error { + if layer <= 0 || msgID <= 0 { + return fmt.Errorf("invalid restored raw layer evidence layer=%d msg_id=%d", layer, msgID) + } + _, err := c.freezeRawLayerProfileAt(layer, msgID) + return err +} + +// refreshInheritedLayerProfile is reserved for identity normalization at +// auth.bindTempAuthKey: once a raw temporary key is resolved to its permanent +// key, the permanent key's default supersedes an older raw-key shadow. Explicit +// evidence on the concrete session is never overwritten. +func (c *Conn) refreshInheritedLayerProfile(profile tg.LayerProfile) (bool, error) { + if c == nil { + return false, nil + } + if err := validateLayerProfile(profile); err != nil { + return false, err + } + c.layerProfileMu.Lock() + defer c.layerProfileMu.Unlock() + current := unpackLayerProfileState(c.layerProfileState.Load()) + if current.Origin == LayerProfileExplicit || c.layerProfileEvidenceMsgID > 0 { + return false, nil + } + if current.Origin == LayerProfileInherited && current.Profile == profile { + return false, nil + } + if current.Epoch == math.MaxUint32 { + return false, ErrLayerProfileEpochExhausted + } + next := LayerProfileSnapshot{Profile: profile, Origin: LayerProfileInherited, Epoch: current.Epoch + 1} + c.layerProfileState.Store(packLayerProfileState(next)) + c.layerProfileEvidenceMsgID = 0 + c.layerProfileEvidenceLayer = 0 + c.setLegacyClientLayer(int(profile)) + return true, nil +} + +func (c *Conn) clearInheritedLayerProfileState() (bool, error) { + if c == nil { + return false, nil + } + c.layerProfileMu.Lock() + defer c.layerProfileMu.Unlock() + current := unpackLayerProfileState(c.layerProfileState.Load()) + if current.Origin != LayerProfileInherited { + return false, nil + } + if current.Epoch == math.MaxUint32 { + return false, ErrLayerProfileEpochExhausted + } + c.layerProfileState.Store(packLayerProfileState(LayerProfileSnapshot{Epoch: current.Epoch + 1})) + c.layerProfileEvidenceMsgID = 0 + c.layerProfileEvidenceLayer = 0 + c.setLegacyClientLayer(0) + return true, nil +} + +func (c *Conn) clearInheritedLayerProfile() error { + _, err := c.clearInheritedLayerProfileState() + return err +} + +// seedInitialLayerProfile applies recovery sources in descending authority. +// Unsupported metadata never clamps to a nearby generated layer: the Conn stays +// unknown so the client can explicitly renegotiate. +func (s *Server) seedInitialLayerProfile( + ctx context.Context, + c *Conn, + fetchedLayer int, + previous LayerProfileSnapshot, +) error { + if s == nil || c == nil { + return nil + } + durableResolver, hasDurableResolver := s.layerRPC.(LayerRPCDurableSessionProfileResolver) + if hasDurableResolver { + layer, msgID, found, err := durableResolver.ResolveNegotiatedSessionLayerEvidence(ctx, c.authKeyID, c.sessionID) + if err != nil { + if isLayerEvidenceDurabilityUnavailable(err) { + s.log.Warn("Resolve durable exact session Layer during connection seed unavailable; continuing with auth-key default", + zap.String("auth_key_id", c.authKeyHex), zap.Int64("session_id", c.sessionID), zap.Error(err)) + // Exact-session proof is the strongest recovery source, but its + // availability failure must not discard a permanent auth_keys.layer + // already loaded with the key on this same first frame. Continue to the + // auth-key default below; never reuse previous connection-local evidence + // in durable mode. + found = false + } else { + return fmt.Errorf("resolve durable exact session Layer during connection seed: %w", err) + } + } + if found { + if layer <= 0 || msgID < 0 { + return fmt.Errorf("invalid durable exact session Layer seed layer=%d msg_id=%d", layer, msgID) + } + if msgID > 0 { + return c.seedRawLayerEvidence(layer, msgID) + } + // Older in-process exact-session registries did not retain a message + // watermark. Keep that compatibility-only seed usable without treating + // it as durable ordered evidence; real durable stores never persist zero. + profile, supported := tg.ResolveLayerProfile(layer) + if !supported { + return nil + } + return c.seedOrderedLayerProfile(profile, 0) + } + } else if resolver, ok := s.layerRPC.(LayerRPCOrderedSessionProfileResolver); ok { + if layer, msgID, found := resolver.NegotiatedSessionLayerEvidence(c.authKeyID, c.sessionID); found { + if layer <= 0 || msgID < 0 { + return nil + } + if msgID > 0 { + return c.seedRawLayerEvidence(layer, msgID) + } + profile, supported := tg.ResolveLayerProfile(layer) + if !supported { + return nil + } + return c.seedOrderedLayerProfile(profile, 0) + } + } else if resolver, ok := s.layerRPC.(LayerRPCSessionProfileResolver); ok { + if layer, found := resolver.NegotiatedSessionLayer(c.authKeyID, c.sessionID); found { + profile, supported := tg.ResolveLayerProfile(layer) + if !supported { + return nil + } + return c.SeedLayerProfile(profile) + } + } + // A freshly fetched permanent-key row is already the canonical auth-key + // record. Prefer its non-zero Layer without making Router query the same PG + // row again. Unsupported metadata remains unknown and must not fall through + // to a weaker mirror. + if c.authKeyExpiresAt == 0 && fetchedLayer != 0 { + profile, supported := tg.ResolveLayerProfile(fetchedLayer) + if !supported { + return nil + } + return c.SeedInheritedLayerProfile(profile) + } + // Temporary keys resolve through their bound permanent key before consulting + // the raw temp-key shadow, which may predate a client upgrade. + if resolver, ok := s.layerRPC.(LayerRPCInheritedAuthKeyProfileResolver); ok { + layer, found, err := resolver.ResolveInheritedAuthKeyLayer(ctx, c.authKeyID) + if err != nil { + if !isLayerEvidenceDurabilityUnavailable(err) { + // A binding conflict, missing/destroyed key, or malformed durable + // value is not an availability hint. Stay unknown and never let a + // stale raw temp-key shadow outrank that structural failure. + if s.log != nil { + s.log.Warn("Resolve inherited auth-key Layer failed; awaiting explicit evidence", + zap.String("auth_key_id", c.authKeyHex), zap.Error(err)) + } + return nil + } + // The same first frame already authenticated and loaded fetchedLayer + // from this raw temp key. During a transient permanent-identity lookup + // outage it is safe only as this physical Conn's inherited shadow; it + // is never published back to the shared permanent default. + if s.log != nil { + s.log.Warn("Resolve inherited auth-key Layer unavailable; continuing with raw auth-key shadow", + zap.String("auth_key_id", c.authKeyHex), zap.Error(err)) + } + } else if !found { + // Fall through to a raw auth-key shadow when the resolver has no + // canonical permanent-key default (for example an unbound temp key). + } else { + profile, supported := tg.ResolveLayerProfile(layer) + if !supported { + return nil + } + return c.SeedInheritedLayerProfile(profile) + } + } + if fetchedLayer != 0 { + profile, supported := tg.ResolveLayerProfile(fetchedLayer) + if !supported { + return nil + } + return c.SeedInheritedLayerProfile(profile) + } + if hasDurableResolver { + // previous belongs to the old logical Conn which occupied this physical + // transport. In durable mode only an exact session row or auth-key default + // may cross that boundary. In particular, a connection-local selector used + // during a store outage must not leak into a newly selected session. + return nil + } + if previous.Origin != LayerProfileUnknown { + return c.SeedInheritedLayerProfile(previous.Profile) + } + return nil +} + +// refreshActivatedInheritedLayerProfile closes the auth.bindTempAuthKey race +// after BeginActivation has made this Conn visible in claimsByAuth. If bind won +// first, the second resolver read sees the permanent-key default; if the claim +// won first, bind's SessionManager refresh sees and updates this Conn. Explicit +// session evidence always wins either ordering. +func (s *Server) refreshActivatedInheritedLayerProfile(ctx context.Context, c *Conn, fetchedLayer int) error { + if s == nil || c == nil || c.LayerProfileState().Origin == LayerProfileExplicit { + return nil + } + if c.authKeyExpiresAt == 0 { + if fetchedLayer == 0 { + return nil + } + profile, ok := tg.ResolveLayerProfile(fetchedLayer) + if !ok { + return c.clearInheritedLayerProfile() + } + _, err := c.refreshInheritedLayerProfile(profile) + return err + } + if resolver, ok := s.layerRPC.(LayerRPCInheritedAuthKeyProfileResolver); ok { + layer, found, err := resolver.ResolveInheritedAuthKeyLayer(ctx, c.authKeyID) + if err != nil { + if !isLayerEvidenceDurabilityUnavailable(err) { + if s.log != nil { + s.log.Warn("Re-resolve inherited auth-key Layer after activation claim failed", + zap.String("auth_key_id", c.authKeyHex), zap.Error(err)) + } + // A pre-claim raw temp shadow may have been installed before a + // concurrent bind became visible. Structural identity/key failures + // must revoke that weaker inherited evidence; only an explicit + // selector (guarded above) is allowed to survive this branch. + return c.clearInheritedLayerProfile() + } + if s.log != nil { + s.log.Warn("Re-resolve inherited auth-key Layer unavailable; keeping raw auth-key shadow", + zap.String("auth_key_id", c.authKeyHex), zap.Error(err)) + } + } else if found { + profile, supported := tg.ResolveLayerProfile(layer) + if !supported { + return c.clearInheritedLayerProfile() + } + _, err = c.refreshInheritedLayerProfile(profile) + return err + } + } + if fetchedLayer == 0 { + return nil + } + profile, ok := tg.ResolveLayerProfile(fetchedLayer) + if !ok { + return c.clearInheritedLayerProfile() + } + _, err := c.refreshInheritedLayerProfile(profile) + return err +} + +// lockSessionLayerBinding linearizes a proactive update's final validation and +// physical write with profile correction. If correction wins first, validation +// observes the new epoch and drops the update. If the writer wins first, the +// correction becomes visible only after those bytes have landed. Returning a +// bool avoids allocating a release closure on the outbound hot path. +func (c *Conn) lockSessionLayerBinding(binding *outboundLayerBinding) bool { + if c == nil || binding == nil || binding.wireInvariant || + binding.kind == outboundLayerBindingRequest || binding.epoch == 0 { + return false + } + c.layerProfileMu.RLock() + return true +} diff --git a/internal/mtprotoedge/conn_mgmt_fixes_test.go b/internal/mtprotoedge/conn_mgmt_fixes_test.go index fc545fd8..8d88fc43 100644 --- a/internal/mtprotoedge/conn_mgmt_fixes_test.go +++ b/internal/mtprotoedge/conn_mgmt_fixes_test.go @@ -7,8 +7,8 @@ import ( "go.uber.org/zap/zaptest" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) // TestPushSkipsConnReboundToOtherUser 锁定跨账号投递窗口的修复:pushToUserWithSender 在锁外 @@ -28,6 +28,9 @@ func TestPushSkipsConnReboundToOtherUser(t *testing.T) { c.userID.Store(userA) c.userIDResolved.Store(true) c.receivesUpdates.Store(true) + if err := c.FreezeLayerProfile(tg.LayerProfileCanonical); err != nil { + t.Fatal(err) + } sm.Register(c) return c } diff --git a/internal/mtprotoedge/decrypt.go b/internal/mtprotoedge/decrypt.go index 0fe93e9d..77163323 100644 --- a/internal/mtprotoedge/decrypt.go +++ b/internal/mtprotoedge/decrypt.go @@ -8,8 +8,8 @@ import ( "github.com/gotd/ige" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" ) // clientFrame 是解密后的单帧客户端消息视图。data/plaintext 引用调用方持有的复用明文 diff --git a/internal/mtprotoedge/decrypt_test.go b/internal/mtprotoedge/decrypt_test.go index 3eabfab6..5c0c3d7c 100644 --- a/internal/mtprotoedge/decrypt_test.go +++ b/internal/mtprotoedge/decrypt_test.go @@ -9,8 +9,8 @@ import ( "github.com/gotd/ige" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" ) func newTestAuthKey(t *testing.T) crypto.AuthKey { diff --git a/internal/mtprotoedge/destroy_auth_key.go b/internal/mtprotoedge/destroy_auth_key.go index 9862927a..3d0ab842 100644 --- a/internal/mtprotoedge/destroy_auth_key.go +++ b/internal/mtprotoedge/destroy_auth_key.go @@ -1,9 +1,12 @@ package mtprotoedge import ( + "errors" "fmt" - "github.com/gotd/td/bin" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) const ( @@ -12,6 +15,39 @@ const ( destroyAuthKeyFailTypeID = 0xea109b13 ) +var errDestroyAuthKeyMustBeExclusive = errors.New("wrapped destroy_auth_key must be the only logical message") + +// wrappedDestroyAuthKeyTerminal accepts only evidence emitted by the generated +// exact wrapper parser after it has legally reached the innermost non-API +// terminal. It never re-parses wrapper bytes at runtime. +func wrappedDestroyAuthKeyTerminal(err error) (*tg.LayerRPCUnknownTerminalError, bool) { + var terminal *tg.LayerRPCUnknownTerminalError + if !errors.As(err, &terminal) || terminal == nil || terminal.WireID != destroyAuthKeyRequestTypeID { + return nil, false + } + return terminal, true +} + +// validWrappedDestroyAuthKeyChain is deliberately narrower than "some generated +// wrapper decoded". invokeAfter*, takeout and update-suppression wrappers carry +// execution semantics which the service-message fast path must not silently +// discard. The official first-connection path is exactly +// invokeWithLayer(initConnection(destroy_auth_key)); an already initialized +// connection sends the bare service message and is classified before Layer RPC +// admission. +func validWrappedDestroyAuthKeyChain(terminal *tg.LayerRPCUnknownTerminalError) bool { + if terminal == nil || terminal.WrapperCount() != 2 { + return false + } + outer, outerOK := terminal.Wrapper(0) + inner, innerOK := terminal.Wrapper(1) + return outerOK && innerOK && + outer.Profile() == terminal.Profile && + inner.Profile() == terminal.Profile && + outer.Semantic() == tg.LayerSemanticMethodInvokeWithLayer && + inner.Semantic() == tg.LayerSemanticMethodInitConnection +} + type destroyAuthKeyRequest struct{} func (*destroyAuthKeyRequest) Encode(b *bin.Buffer) error { @@ -26,16 +62,26 @@ func (*destroyAuthKeyRequest) Decode(b *bin.Buffer) error { return nil } -type destroyAuthKeyOk struct{} - -func (*destroyAuthKeyOk) Encode(b *bin.Buffer) error { - b.PutID(destroyAuthKeyOkTypeID) - return nil +// destroyAuthKeyRPCResult is the only rpc_result envelope admitted as a +// layer-invariant control value. Its closed result set is part of the type, so +// it can never smuggle a profile-dependent API payload past the exact Layer +// binding boundary. +type destroyAuthKeyRPCResult struct { + RequestMessageID int64 + ResultTypeID uint32 } -type destroyAuthKeyFail struct{} - -func (*destroyAuthKeyFail) Encode(b *bin.Buffer) error { - b.PutID(destroyAuthKeyFailTypeID) +func (r *destroyAuthKeyRPCResult) Encode(b *bin.Buffer) error { + if r == nil { + return fmt.Errorf("encode destroy_auth_key rpc_result: nil result") + } + switch r.ResultTypeID { + case destroyAuthKeyOkTypeID, destroyAuthKeyFailTypeID: + default: + return fmt.Errorf("encode destroy_auth_key rpc_result: invalid inner constructor %#x", r.ResultTypeID) + } + b.PutID(proto.ResultTypeID) + b.PutLong(r.RequestMessageID) + b.PutID(r.ResultTypeID) return nil } diff --git a/internal/mtprotoedge/duplicate_admission_test.go b/internal/mtprotoedge/duplicate_admission_test.go index 4e4f1a7c..110542fe 100644 --- a/internal/mtprotoedge/duplicate_admission_test.go +++ b/internal/mtprotoedge/duplicate_admission_test.go @@ -7,9 +7,9 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) type blockingDuplicateRPC struct { @@ -53,7 +53,7 @@ func TestPendingSameConnectionDuplicateDoesNotBlockFreshRequest(t *testing.T) { defer handler.unblock() addr, pub, server := startTestServer(t, Options{ DC: dc, - RPC: handler, + legacyRPC: handler, RPCMaxInflight: 2, RPCGlobalWorkers: 2, RPCQueueSize: 8, diff --git a/internal/mtprotoedge/e2e_test.go b/internal/mtprotoedge/e2e_test.go index 89630939..fd954e6c 100644 --- a/internal/mtprotoedge/e2e_test.go +++ b/internal/mtprotoedge/e2e_test.go @@ -11,13 +11,13 @@ import ( "go.uber.org/zap/zaptest" "github.com/gotd/log/logzap" - "github.com/gotd/td/clock" - "github.com/gotd/td/exchange" - "github.com/gotd/td/session" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/session" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" "telesrv/internal/app/auth" "telesrv/internal/app/updates" @@ -26,7 +26,7 @@ import ( "telesrv/internal/store/memory" ) -// TestTelegramClientEndToEnd 是连接层的最强端到端验证:用 gotd/td 的完整 +// TestTelegramClientEndToEnd 是连接层的最强端到端验证:用 iamxvbaba/td 的完整 // telegram.Client(而非底层 cipher)连本地 mtprotoedge,client 自动经 // invokeWithLayer(initConnection(help.getConfig)) 完成初始化,并取得含本地 DC 的 Config。 func TestTelegramClientEndToEnd(t *testing.T) { @@ -51,7 +51,7 @@ func TestTelegramClientEndToEnd(t *testing.T) { Updates: updates.NewService(memory.NewUpdateStateStore(), memory.NewUpdateEventStore()), } router := rpc.New(rpc.Config{DC: dc, IP: tcpAddr.IP.String(), Port: tcpAddr.Port}, deps, zaptest.NewLogger(t), clock.System) - srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, RPC: router}) + srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, LayerRPC: router}) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() diff --git a/internal/mtprotoedge/encrypted.go b/internal/mtprotoedge/encrypted.go index 8e252af9..d032e162 100644 --- a/internal/mtprotoedge/encrypted.go +++ b/internal/mtprotoedge/encrypted.go @@ -10,19 +10,20 @@ import ( "fmt" "io" "math" + "runtime/debug" "time" "go.uber.org/zap" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/tgerr" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" + "github.com/iamxvbaba/td/transport" - "telesrv/internal/compat/layerwire" "telesrv/internal/observability/dbtrace" "telesrv/internal/postresponse" "telesrv/internal/store" @@ -140,7 +141,11 @@ func (s *Server) handleEncrypted(ctx context.Context, tc transport.Conn, cs *con // 临时创建 Conn 会在同一 socket 上启动多个 outbound actor,Android 的启动重试 // 风暴随即变成并发写和重复结果放大。 if current == nil || current.sessionID != frame.sessionID || current.authKeyID != key.ID { + var previousLayer LayerProfileSnapshot if current != nil { + if current.authKeyID == key.ID { + previousLayer = current.LayerProfileState() + } cs.reset() current.beginTerminalShutdown() s.conns.Unregister(current) @@ -156,15 +161,20 @@ func (s *Server) handleEncrypted(ctx context.Context, tc transport.Conn, cs *con current = s.newConn(tc, key, frame.sessionID, serverSalt) } current.authKeyExpiresAt = authKeyExpiresAt - // 注册即播种协商 layer:新 Conn 的 clientLayer 为 0(=canonical 227),若等到 - // 首条 RPC 的 Dispatch 返回后才刷新,重连老客户端在首条 RPC handler 执行期间 - // 收到的 pending flush / 并发 push 会漏降级。进程内重连时 rpc 层留有 - // (auth_key, session) / auth_key 两级协商记录,这里一次查询即可闭合该空窗。 + // Same-session evidence is restored as explicit; auth-key metadata is only + // an inherited default and can be corrected by the next invokeWithLayer. if s.rpc != nil { if layer, ok := s.rpc.NegotiatedLayer(current.authKeyID, current.sessionID); ok { - current.SetClientLayer(layer) + current.setLegacyClientLayer(layer) } } + fetchedLayer := 0 + if fetchedKey != nil { + fetchedLayer = fetchedKey.Layer + } + if err := s.seedInitialLayerProfile(ctx, current, fetchedLayer, previousLayer); err != nil { + return current, fmt.Errorf("seed connection layer profile: %w", err) + } } if frame.salt != serverSalt { @@ -194,6 +204,13 @@ func (s *Server) handleEncrypted(ctx context.Context, tc transport.Conn, cs *con } defer plan.close() if err := s.prepareInboundRPCBatch(ctx, current, plan); err != nil { + if errors.Is(err, errDestroyAuthKeyMustBeExclusive) { + s.log.Debug("Rejecting mixed destroy_auth_key container", + zap.Int64("msg_id", frame.messageID), + zap.Int32("seq_no", frame.seqNo), + ) + return current, s.sendBadMsg(ctx, current, frame.messageID, frame.seqNo, badMsgContainer) + } return current, err } if err := sendQuickAckIfRequested(ctx, current.transport, key, frame.plaintext, s.writeTimeout); err != nil { @@ -233,6 +250,12 @@ func (s *Server) handleEncrypted(ctx context.Context, tc transport.Conn, cs *con } return current, errActivationAuthKeyRejected } + // Re-resolve inherited Layer only after the activation claim is visible. + // This closes the bind-vs-connect window for temporary keys without ever + // replacing explicit invokeWithLayer evidence admitted above. + if err := s.refreshActivatedInheritedLayerProfile(ctx, current, fresh.Layer); err != nil { + return current, fmt.Errorf("refresh claimed connection layer profile: %w", err) + } if current.isRetired() || !current.isPhysicalTransportCurrentOpen() { return current, ErrConnClosed } @@ -674,29 +697,44 @@ func (s *Server) handleRPC(ctx context.Context, c *Conn, msgID int64, method str ctx = postresponse.WithCallbacks(ctx) ctx, dbStats := dbtrace.WithStats(ctx) + // legacyRPC is an unexported package-test hook, but its result still has to + // obey the production exact-codec invariant. Admit a defensive copy using + // the generated current profile before the legacy router consumes b. + admissionBody := &bin.Buffer{Buf: append([]byte(nil), b.Buf...)} + admitted, err := tg.NewServerDispatcher(nil).AdmitDefaultLayerWithLimits( + tg.LayerProfileCanonical, + admissionBody, + inboundLayerDecodeLimits, + ) + if err != nil { + return fmt.Errorf("admit legacy test RPC through generated codec: %w", err) + } start := s.clock.Now() effectiveMethod := method var ( - result bin.Encoder - err error + result bin.Encoder + dispatchErr error ) - if detailed, ok := s.rpc.(RPCHandlerWithMethod); ok { + if detailed, ok := s.rpc.(legacyRPCHandlerWithMethod); ok { var innerMethod string - result, innerMethod, err = detailed.DispatchWithMethod(ctx, c.authKeyID, c.sessionID, b) + result, innerMethod, dispatchErr = detailed.DispatchWithMethod(ctx, c.authKeyID, c.sessionID, b) if innerMethod != "" { effectiveMethod = innerMethod } } else { - result, err = s.rpc.Dispatch(ctx, c.authKeyID, c.sessionID, b) + result, dispatchErr = s.rpc.Dispatch(ctx, c.authKeyID, c.sessionID, b) + } + if dispatchErr == nil && result != nil && !isLayerInvariantRPCResultEncoder(result) { + if _, exact := result.(exactLayerRPCResultEncoder); !exact { + result = &legacyTestRPCResultEncoder{call: admitted.Call(), result: result} + } } dur := s.clock.Now().Sub(start) - s.metrics.RPCHandled(effectiveMethod, dur, err) - // 刷新本连接协商 layer(invokeWithLayer/initConnection 已被 Dispatch 处理并登记), - // 供 rpc_result 与后续 push 出站降级使用。仅在确实观测到 layer 时更新——缓存被驱逐 - // 时 NegotiatedLayer 返回 ok=false,此时必须保留连接已记住的 layer,绝不覆盖成默认值, - // 否则长连接老客户端的条目被驱逐后会被误降回 227。 + s.metrics.RPCHandled(effectiveMethod, dur, dispatchErr) + // 刷新本连接由 invokeWithLayer 证明并冻结的 exact-session layer。ok=false + // 表示仍无协议证据;设备/授权元数据和其它 session 都不具备回填资格。 if layer, ok := s.rpc.NegotiatedLayer(c.authKeyID, c.sessionID); ok { - c.SetClientLayer(layer) + c.setLegacyClientLayer(layer) } fields := make([]zap.Field, 0, 12) @@ -725,7 +763,7 @@ func (s *Server) handleRPC(ctx context.Context, c *Conn, msgID int64, method str // Plain connection cancellation remains retryable on the replacement. var terminal bin.Encoder runPostResponse := false - if err == nil && result != nil { + if dispatchErr == nil && result != nil { terminal = result runPostResponse = true } else if errors.Is(ctxErr, context.DeadlineExceeded) { @@ -741,23 +779,23 @@ func (s *Server) handleRPC(ctx context.Context, c *Conn, msgID int64, method str } } cancelFields := append(fields, zap.NamedError("context_error", ctxErr)) - if err != nil { - cancelFields = append(cancelFields, zap.NamedError("dispatch_error", err)) + if dispatchErr != nil { + cancelFields = append(cancelFields, zap.NamedError("dispatch_error", dispatchErr)) } s.log.Info("RPC canceled", cancelFields...) return ctxErr } - if err != nil { + if dispatchErr != nil { var rpcErr *tgerr.Error - if errors.As(err, &rpcErr) { + if errors.As(dispatchErr, &rpcErr) { s.log.Info("RPC error", append(fields, zap.Int("code", rpcErr.Code), zap.String("error", rpcErr.Message))...) return s.publishRPCResult(c, msgID, effectiveMethod, owner, &mt.RPCError{ ErrorCode: rpcErr.Code, ErrorMessage: rpcErr.Message, }, nil) } - s.log.Info("RPC internal error", append(fields, zap.Error(err))...) + s.log.Info("RPC internal error", append(fields, zap.Error(dispatchErr))...) return s.publishRPCResult(c, msgID, effectiveMethod, owner, &mt.RPCError{ ErrorCode: 500, ErrorMessage: "INTERNAL", @@ -768,9 +806,14 @@ func (s *Server) handleRPC(ctx context.Context, c *Conn, msgID int64, method str return s.publishRPCResult(c, msgID, effectiveMethod, owner, result, postresponse.Take(ctx)) } +var errRPCResultRetentionHandoff = errors.New("mtproto rpc result retention handoff failed") + +type rpcResultRetentionHandoff func(*encodedOutboundMessage, error) error + // publishRPCResult ends the inbound worker's ownership at bounded egress -// admission. Physical delivery, fencing, completed-cache publication and the -// post-response hook are thereafter owned by the single outbound actor. +// admission. Physical delivery is thereafter owned either by the single +// outbound actor or, under retained-byte saturation, by a fenced completed-cache +// entry that the replacement connection can replay without rerunning business. func (s *Server) publishRPCResult( c *Conn, reqMsgID int64, @@ -788,45 +831,117 @@ func (s *Server) publishRPCResult( } prepareCtx, cancel := context.WithTimeout(context.Background(), prepareTimeout) defer cancel() - encoded, err := s.encodeRPCResultContext(prepareCtx, c, reqMsgID, result) + prepareEncoded := func(encoded *encodedOutboundMessage) (outboundPriority, bool) { + if owner != nil && owner.Delivery() != nil { + // The owner-level delivery coordinator exists before the handler starts, so + // an initConnection rewrap can retarget even while result encoding is still + // pending. The encoded body itself remains immutable; the actor clones only + // the 12-byte rpc_result prefix when it snapshots the physical target. + encoded.delivery = owner.Delivery() + } + if afterDelivered != nil { + encoded.setDeliveryHook(afterDelivered) + } + priority := rpcResultPriority(method, encoded) + encoded.priority = priority + if metrics, ok := s.metrics.(RPCResultMetrics); ok { + metrics.RPCResultPrepared(method, priority.String(), encoded.uncompressedBytes, len(encoded.body), encoded.compressed) + } + visible := encoded.compressed || priority == outboundPriorityCritical || priority == outboundPriorityBulk + return priority, visible + } + + // A successful business result may never leave the encode slot as an + // unaccounted []byte. If the primary 512MiB retained-body budget is full, make + // overload terminal for this physical generation and publish the exact result + // into the independently bounded completed cache before releasing the slot. + retainForReplay := func(encoded *encodedOutboundMessage, admissionErr error) error { + if s == nil || s.rpcResults == nil || c == nil || encoded == nil || reqMsgID == 0 { + return errors.New("rpc result completed cache is unavailable") + } + if int64(len(encoded.body)) > s.rpcResults.completedBytes.max { + // Every transport-legal result fits the production completed cache by the + // compile-time invariant in rpc_result_cache.go. A test/custom cache that + // violates it cannot safely complete this flight, so fail fast while the + // body is still confined to the encode slot. + panic(fmt.Sprintf( + "mtprotoedge: encoded rpc result exceeds completed-cache budget: body=%d max=%d", + len(encoded.body), s.rpcResults.completedBytes.max, + )) + } + priority, visible := prepareEncoded(encoded) + if owner != nil && !owner.HandOff() { + return ErrRPCResultFlightInvalid + } + started := time.Now() + encoded.markReplayable() + // Put may expose a completed result only after the old logical connection + // is irreversibly unable to accept another same-generation request. + c.fenceUndeliveredRPCResult() + s.storeRPCResult(c, reqMsgID, encoded) + latency := time.Since(started) + if metrics, ok := s.metrics.(RPCResultMetrics); ok { + metrics.RPCResultDelivered(method, latency, len(encoded.body), admissionErr) + } + resultLogLevel := zap.DebugLevel + if visible { + resultLogLevel = zap.InfoLevel + } + if checked := s.log.Check(resultLogLevel, "RPC result retained for replay after egress saturation"); checked != nil { + checked.Write( + zap.String("method", method), zap.Int64("req_msg_id", reqMsgID), + zap.Int64("delivered_req_msg_id", encoded.writtenRequestID()), + zap.String("auth_key_id", c.authKeyHex), zap.Int64("session_id", c.sessionID), + zap.Int("wire_bytes", len(encoded.body)), zap.Bool("gzip", encoded.compressed), + zap.String("priority", priority.String()), zap.Error(admissionErr)) + } + return nil + } + + encoded, reserved, retained, err := s.encodeRPCResultReservedWithHandoffContext( + prepareCtx, c, reqMsgID, result, retainForReplay, + ) + if retained { + return err + } + if errors.Is(err, errRPCResultRetentionHandoff) { + c.fenceUndeliveredRPCResult() + return err + } if err != nil { s.log.Warn("Encode RPC result failed; publishing INTERNAL", zap.String("method", method), zap.Int64("req_msg_id", reqMsgID), zap.Error(err)) afterDelivered = nil - encoded, err = s.encodeRPCResultContext(prepareCtx, c, reqMsgID, &mt.RPCError{ - ErrorCode: 500, ErrorMessage: "INTERNAL", - }) + encoded, reserved, retained, err = s.encodeRPCResultReservedWithHandoffContext( + prepareCtx, c, reqMsgID, &mt.RPCError{ErrorCode: 500, ErrorMessage: "INTERNAL"}, retainForReplay, + ) + if retained { + return err + } if err != nil { c.fenceUndeliveredRPCResult() return err } } - if owner != nil && owner.Delivery() != nil { - // The owner-level delivery coordinator exists before the handler starts, so - // an initConnection rewrap can retarget even while result encoding is still - // pending. The encoded body itself remains immutable; the actor clones only - // the 12-byte rpc_result prefix when it snapshots the physical target. - encoded.delivery = owner.Delivery() - } - if afterDelivered != nil { - encoded.delivery.fn = afterDelivered + if encoded == nil || reserved == nil { + c.fenceUndeliveredRPCResult() + return errors.New("rpc result encode completed without tracked retention") } + // Until enqueue transfers ownership, every exit must return the retained-byte + // charge. A successful transfer clears the reservation and makes this a no-op. + defer reserved.release() + priority, visible := prepareEncoded(encoded) if owner != nil && !owner.HandOff() { return ErrRPCResultFlightInvalid } - priority := rpcResultPriority(method, encoded) - encoded.priority = priority resultLogLevel := zap.DebugLevel - if encoded.compressed || priority == outboundPriorityCritical || priority == outboundPriorityBulk { + if visible { // Keep ordinary small RPCs at debug, but make convergence and bulk/gzip - // delivery visible in default service logs. These are the + // delivery visible in the default service logs. These are the // responses whose queueing and write latency diagnose startup Updating. resultLogLevel = zap.InfoLevel } - if metrics, ok := s.metrics.(RPCResultMetrics); ok { - metrics.RPCResultPrepared(method, priority.String(), encoded.uncompressedBytes, len(encoded.body), encoded.compressed) - } egressStarted := time.Now() terminal := func(deliveryErr error) { latency := time.Since(egressStarted) @@ -848,8 +963,8 @@ func (s *Server) publishRPCResult( } return } - s.storeRPCResult(c, reqMsgID, encoded) encoded.markDelivered() + s.storeRPCResult(c, reqMsgID, encoded) if checked := s.log.Check(resultLogLevel, "RPC result delivered"); checked != nil { checked.Write( zap.String("method", method), zap.Int64("req_msg_id", reqMsgID), @@ -860,7 +975,7 @@ func (s *Server) publishRPCResult( } } encoded.markQueued() - if err := c.enqueueEncodedDelivery(prepareCtx, proto.MessageServerResponse, encoded, priority, terminal); err != nil { + if err := c.enqueueEncodedDeliveryReserved(prepareCtx, proto.MessageServerResponse, encoded, priority, terminal, reserved); err != nil { // HandOff already made the egress path the terminal owner. No bytes were // admitted, so fence this generation before publishing a replayable result. terminal(err) @@ -905,10 +1020,10 @@ func (s *Server) sendResult(ctx context.Context, c *Conn, reqMsgID int64, result s.storeRPCResult(c, reqMsgID, encoded) return err } + encoded.markDelivered() // On a live Conn, completed means the rpc_result has reached the reliable byte // stream. Same-physical duplicates can therefore be ACK-only without data loss. s.storeRPCResult(c, reqMsgID, encoded) - encoded.markDelivered() return nil } @@ -916,24 +1031,114 @@ func (s *Server) sendResult(ctx context.Context, c *Conn, reqMsgID int64, result // for completed-flight replays: either the cached result reaches this physical // byte stream, or this logical Conn is fenced so a replacement may retry it. func (s *Server) sendCachedRPCResult(ctx context.Context, c *Conn, encoded *encodedOutboundMessage) error { + return s.sendCachedRPCResultWithHook(ctx, c, encoded, nil) +} + +func (s *Server) sendCachedRPCResultWithHook( + ctx context.Context, + c *Conn, + encoded *encodedOutboundMessage, + afterSuccessfulDelivery func() error, +) error { if encoded == nil { c.fenceUndeliveredRPCResult() return errors.New("nil cached rpc_result") } - if err := c.SendEncoded(ctx, proto.MessageServerResponse, encoded); err != nil { + attempt, reserved, err := c.cloneRPCResultForRequestReserved(encoded, encoded.reqMsgID, false) + if err != nil { + c.failOutboundBudget(err) c.fenceUndeliveredRPCResult() - encoded.markReplayable() return err } - encoded.markDelivered() - return nil + // take clears the producer reservation after actor admission. Every earlier + // return, including a closed connection, must drop the replay pin here. + defer reserved.release() + pendingLogicalRestore := attempt.pendingLogicalDeliveryHook() + var finishRestore func() + if afterSuccessfulDelivery != nil || pendingLogicalRestore { + finishRestore = c.beginRPCReplayRestore() + defer finishRestore() + } + // Cached replay owns its delivery-gated state synchronously. Calling the + // lower send primitive avoids reserving the process-wide asynchronous hook + // executor; the logical hook is claimed only after this physical write wins. + if err := c.sendOutboundWithTerminalReserved( + ctx, proto.MessageServerResponse, nil, attempt, false, nil, reserved, + ); err != nil { + c.fenceUndeliveredRPCResult() + attempt.markReplayable() + return err + } + // Physical success is irrevocable even if the caller's send context expires + // at the same instant. Give the ordered restore its own bounded lifetime. + restoreCtx, cancelRestore := boundedRPCReplayRestoreContext(context.Background()) + defer cancelRestore() + logicalRestore, claimErr := attempt.claimLogicalDeliveryHook(restoreCtx, false) + attempt.markDelivered() + if claimErr != nil { + // Another replay owns Claimed/InProgress state (or a retarget still owns + // the sticky deferral). Fence before the deferred barrier is released; a + // later physical generation may wait for Done and replay the same bytes. + c.fenceUndeliveredRPCResult() + return fmt.Errorf("wait for cached rpc_result logical restore: %w", claimErr) + } + return s.runBoundedRPCReplayRestore( + restoreCtx, c, "cached rpc_result", logicalRestore, afterSuccessfulDelivery, + ) +} + +// composeRPCReplayRestore keeps replacement-connection metadata first while +// still guaranteeing that the original handler's delivery-gated cursor/outbox +// work runs after a physical replay even when metadata restoration reports an +// error. runRPCReplayRestore provides panic isolation and terminal fencing for +// the combined ordered transaction. +func composeRPCReplayRestore(logical func(), replacement func() error) func() error { + if logical == nil && replacement == nil { + return nil + } + return func() (err error) { + if logical != nil { + defer logical() + } + if replacement != nil { + return replacement() + } + return nil + } +} + +// runRPCReplayRestore is the panic/error boundary executed only by the fixed- +// capacity runner in rpc_replay_restore.go. Replay restore may touch auth/session +// stores and membership state; its caller holds the per-Conn scheduler barrier. +// Any error or panic fences the partially restored physical generation so a +// replacement can retry from the immutable completed result. +func (s *Server) runRPCReplayRestore(c *Conn, source string, restore func() error) (err error) { + if restore == nil { + return nil + } + defer func() { + if recovered := recover(); recovered != nil { + err = fmt.Errorf("restore replay state after %s: panic: %v", source, recovered) + if s != nil && s.log != nil { + s.log.Error("Exact RPC replay state restore panicked", + zap.String("source", source), zap.ByteString("stack", debug.Stack()), zap.Any("panic", recovered)) + } + } + if err != nil { + if s != nil && s.log != nil { + s.log.Warn("Exact RPC replay state restore failed", zap.String("source", source), zap.Error(err)) + } + c.fenceUndeliveredRPCResult() + } + }() + return restore() } // encodeRPCResult 编码 rpc_result。内层对象与 rpc_result 头(type_id + req_msg_id) // 一次性编码进同一 buffer——旧实现先编码内层、再经 proto.Result.Encode 整体拷贝一遍, -// 每条响应多一份全量 body 拷贝。内层按连接协商 layer 降级(layer==227 直通,零开销), -// 降级改写字节时才重建整条消息。降级失败 fail-safe:记日志并发送 canonical 字节—— -// 宁可老客户端对个别长尾对象渲染异常,也不让连接/流崩。 +// 每条响应多一份全量 body 拷贝。生成式结果携带完整 Layer profile + result TypeRef +// 绑定,后续发送、缓存和重放均只能用于同一精确 profile;package 测试保留的 legacy +// handler 也必须先绑定 generated admitted call,生产路径不存在旧转码桥。 func (s *Server) encodeRPCResult(c *Conn, reqMsgID int64, result bin.Encoder) (*encodedOutboundMessage, error) { return s.encodeRPCResultContext(context.Background(), c, reqMsgID, result) } @@ -942,36 +1147,138 @@ func (s *Server) encodeRPCResultContext(ctx context.Context, c *Conn, reqMsgID i if ctx == nil { ctx = context.Background() } - var inner bin.Buffer - // Terminal result preparation must survive physical-generation retirement: - // an overlapping replacement may already be waiting to replay this owner's - // result. Only the bounded preparation context, not the old socket stop, owns it. - if err := withOutboundEncodeSlot(ctx, nil, func() error { - return result.Encode(&inner) - }); err != nil { + var encoded *encodedOutboundMessage + err := withOutboundEncodeSlot(ctx, nil, func() error { + var err error + encoded, err = s.encodeRPCResultWithoutSlot(ctx, c, reqMsgID, result) + return err + }) + return encoded, err +} + +// encodeRPCResultReservedContext keeps the process-wide encode slot until the +// completed immutable body is charged to the shared retained-byte budget. This +// closes the otherwise unbounded interval in which every RPC worker could own +// a large encoded result that neither the inbound nor outbound budget tracked. +func (s *Server) encodeRPCResultReservedContext( + ctx context.Context, + c *Conn, + reqMsgID int64, + result bin.Encoder, +) (*encodedOutboundMessage, *outboundBodyReservation, error) { + encoded, reserved, _, err := s.encodeRPCResultReservedWithHandoffContext(ctx, c, reqMsgID, result, nil) + return encoded, reserved, err +} + +// encodeRPCResultReservedWithHandoffContext has only two successful ownership +// outcomes for a completed body: a primary outbound reservation, or a caller +// handoff that synchronously installs another bounded owner while the encode slot +// is still held. A failed/no handoff clears encoded before the slot is released. +func (s *Server) encodeRPCResultReservedWithHandoffContext( + ctx context.Context, + c *Conn, + reqMsgID int64, + result bin.Encoder, + handoff rpcResultRetentionHandoff, +) (*encodedOutboundMessage, *outboundBodyReservation, bool, error) { + if ctx == nil { + ctx = context.Background() + } + var ( + encoded *encodedOutboundMessage + reserved *outboundBodyReservation + retained bool + ) + err := withOutboundEncodeSlot(ctx, nil, func() error { + var err error + encoded, err = s.encodeRPCResultWithoutSlot(ctx, c, reqMsgID, result) + if err != nil { + return err + } + budget := c.outboundMessageBudget(encoded.typeID, false) + bytes := len(encoded.body) + if budget.reserve(bytes) { + reserved = &outboundBodyReservation{budget: budget, bytes: bytes} + return nil + } + if handoff != nil { + admissionErr := fmt.Errorf("reserve encoded rpc result: %w", ErrOutboundTrackedBudget) + if err := handoff(encoded, admissionErr); err != nil { + encoded = nil + return fmt.Errorf("%w: %w", errRPCResultRetentionHandoff, errors.Join(admissionErr, err)) + } + retained = true + // The handoff owns the only surviving pointer. Do not return a second + // producer reference after the encode slot releases; the completed cache + // may independently evict the entry under its bounded policy. + encoded = nil + return admissionErr + } + // Non-publish callers have no alternate bounded owner. They may wait for + // the caller's deadline, but on failure the body is discarded in-slot. + if err := budget.waitReserve(ctx, nil, bytes); err != nil { + encoded = nil + return fmt.Errorf("reserve encoded rpc result: %w", err) + } + reserved = &outboundBodyReservation{budget: budget, bytes: bytes} + return nil + }) + if err != nil && !retained && reserved == nil { + encoded = nil + } + return encoded, reserved, retained, err +} + +func (s *Server) encodeRPCResultWithoutSlot(ctx context.Context, c *Conn, reqMsgID int64, result bin.Encoder) (*encodedOutboundMessage, error) { + var layerBinding *outboundLayerBinding + exactResult, exactLayerResult := result.(exactLayerRPCResultEncoder) + layerInvariantResult := isLayerInvariantRPCResultEncoder(result) + if !exactLayerResult && !layerInvariantResult { + return nil, ErrOutboundLayerBindingRequired + } + if exactLayerResult { + binding := exactResult.exactLayerRPCResultBinding() + layerBinding = &binding + if err := validateOutboundLayerBinding(c, &encodedOutboundMessage{layer: layerBinding}); err != nil { + return nil, fmt.Errorf("bind exact layer rpc result: %w", err) + } + } + // Encode the ordinary exact/no-gzip path directly behind the rpc_result + // prefix. This avoids both the old generated Prepare snapshot and another + // full-body copy merely to prepend the 12-byte envelope. + var envelope bin.Buffer + envelope.PutID(proto.ResultTypeID) + envelope.PutLong(reqMsgID) + if err := result.Encode(&envelope); err != nil { return nil, fmt.Errorf("encode rpc result: %w", err) } - innerBody := inner.Raw() - if layer := c.ClientLayer(); layer < layerwire.CanonicalLayer { - if down, err := layerwire.Transcode(innerBody, layer); err != nil { - s.log.Warn("layerwire downgrade failed; sending canonical rpc_result", - zap.Int("layer", layer), zap.Int64("req_msg_id", reqMsgID), zap.Error(err)) - } else { - innerBody = down - } + envelopeInner := envelope.Raw()[12:] + innerBody := envelopeInner + // Inputs above gotd's decompression ceiling can never be gzip_packed. Reject + // them before allocating a second transport-envelope-sized buffer. + if len(innerBody) > rpcResultGZIPMaxInputBytes && len(innerBody) > maxOutboundBodyBytes-12 { + return nil, fmt.Errorf("%w: body=%d limit=%d", ErrOutboundMessageTooLarge, len(innerBody)+12, maxOutboundBodyBytes) } wireInner, compressed, err := encodeAdaptiveRPCResultInner(ctx, nil, innerBody) if err != nil { return nil, fmt.Errorf("compress rpc result: %w", err) } - var out bin.Buffer - out.PutID(proto.ResultTypeID) - out.PutLong(reqMsgID) - out.Put(wireInner) + if len(wireInner) > maxOutboundBodyBytes-12 { + return nil, fmt.Errorf("%w: body=%d limit=%d", ErrOutboundMessageTooLarge, len(wireInner)+12, maxOutboundBodyBytes) + } + body := envelope.Raw() + if compressed || !sameBacking(wireInner, envelopeInner) { + var out bin.Buffer + out.PutID(proto.ResultTypeID) + out.PutLong(reqMsgID) + out.Put(wireInner) + body = out.Raw() + } return &encodedOutboundMessage{ - typeID: proto.ResultTypeID, body: out.Raw(), reqMsgID: reqMsgID, - compressed: compressed, uncompressedBytes: len(innerBody), delivery: newRPCResultDelivery(), + typeID: proto.ResultTypeID, body: body, reqMsgID: reqMsgID, + compressed: compressed, uncompressedBytes: len(innerBody), delivery: newRPCResultDelivery(0), + layer: layerBinding, layerInvariant: layerInvariantResult, }, nil } @@ -1075,11 +1382,20 @@ func (s *Server) sendMsgsStateInfo(ctx context.Context, c *Conn, reqMsgID int64, } func (s *Server) sendDestroySession(ctx context.Context, c *Conn, sessionID int64) error { - removed := false + removed, removedDurable := false, false if sessionID != c.sessionID { - removed = s.conns.DestroySessionForAuthKey(c.authKeyID, sessionID) + if deleter, ok := s.layerRPC.(LayerRPCDurableSessionProfileDeleter); ok { + var err error + removedDurable, err = deleter.DeleteNegotiatedSessionLayerEvidence(ctx, c.authKeyID, sessionID) + if err != nil { + return fmt.Errorf("delete durable exact session Layer evidence: %w", err) + } + } + if s.conns != nil { + removed = s.conns.DestroySessionForAuthKey(c.authKeyID, sessionID) + } } - if removed { + if removed || removedDurable { return c.Send(ctx, proto.MessageServerResponse, &mt.DestroySessionOk{SessionID: sessionID}) } return c.Send(ctx, proto.MessageServerResponse, &mt.DestroySessionNone{SessionID: sessionID}) @@ -1113,7 +1429,7 @@ func (s *Server) typeName(id uint32) string { } func validateClientEnvelope(now time.Time, msgID int64, seqNo int32, typeID uint32) int { - if msgID == 0 || proto.MessageID(msgID).Type() != proto.MessageFromClient { + if !validClientMessageIDBits(msgID) { return badMsgIDInvalidBits } msgTime := proto.MessageID(msgID).Time() @@ -1137,7 +1453,7 @@ func validateClientEnvelope(now time.Time, msgID int64, seqNo int32, typeID uint } func validateClientContainerEnvelope(msgID int64, seqNo int32, typeID uint32) int { - if msgID == 0 || proto.MessageID(msgID).Type() != proto.MessageFromClient { + if !validClientMessageIDBits(msgID) { return badMsgIDInvalidBits } if clientMessageAllowsEitherSeqParity(typeID) { diff --git a/internal/mtprotoedge/encrypted_test.go b/internal/mtprotoedge/encrypted_test.go index ab48a05d..889d8ff8 100644 --- a/internal/mtprotoedge/encrypted_test.go +++ b/internal/mtprotoedge/encrypted_test.go @@ -2,17 +2,73 @@ package mtprotoedge import ( "context" + "errors" + "sync" "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" + + "telesrv/internal/store/memory" ) +type durableDestroyLayerRPC struct { + *admissionOnlyLayerRPC + mu sync.Mutex + deleted bool + err error + authKeyID [8]byte + sessionID int64 +} + +type deleteFailAuthKeyStore struct { + *memory.AuthKeyStore + err error +} + +type trailingDestroyAuthKeyRequest struct{} + +func (*trailingDestroyAuthKeyRequest) Encode(b *bin.Buffer) error { + b.PutID(destroyAuthKeyRequestTypeID) + b.PutID(0xdeadbeef) + return nil +} + +func (*trailingDestroyAuthKeyRequest) Decode(b *bin.Buffer) error { + if err := b.ConsumeID(destroyAuthKeyRequestTypeID); err != nil { + return err + } + _, err := b.ID() + return err +} + +func (s *deleteFailAuthKeyStore) Delete(context.Context, [8]byte) error { + return s.err +} + +func (h *durableDestroyLayerRPC) DeleteNegotiatedSessionLayerEvidence( + _ context.Context, + authKeyID [8]byte, + sessionID int64, +) (bool, error) { + h.mu.Lock() + defer h.mu.Unlock() + h.authKeyID = authKeyID + h.sessionID = sessionID + return h.deleted, h.err +} + +func (h *durableDestroyLayerRPC) deletion() ([8]byte, int64) { + h.mu.Lock() + defer h.mu.Unlock() + return h.authKeyID, h.sessionID +} + // TestEncryptedPingPong 验证 M2/M4:握手后 client 加密 ping, // server 回 new_session_created + pong + msgs_ack。 func TestEncryptedPingPong(t *testing.T) { @@ -47,7 +103,7 @@ func TestEncryptedPingPong(t *testing.T) { func TestDuplicateMsgIDIdempotent(t *testing.T) { const dc = 2 handler := &admissionCountingRPC{} - addr, pub, _ := startTestServer(t, Options{DC: dc, RPC: handler}) + addr, pub, _ := startTestServer(t, Options{DC: dc, legacyRPC: handler}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) clientMsgID := proto.NewMessageIDGen(time.Now) @@ -231,8 +287,65 @@ func TestDestroySession(t *testing.T) { } } +func TestDestroySessionAcknowledgesOfflineDurableEvidenceDeletion(t *testing.T) { + const dc = 2 + handler := &durableDestroyLayerRPC{ + admissionOnlyLayerRPC: newAdmissionOnlyLayerRPC(), + deleted: true, + } + addr, pub, _ := startTestServer(t, Options{DC: dc, LayerRPC: handler}) + conn, auth, cipher := dialHandshake(t, addr, dc, pub) + + clientMsgID := proto.NewMessageIDGen(time.Now) + reqMsgID := clientMsgID.New(proto.MessageFromClient) + targetSessionID := auth.SessionID + 4 + sendEncrypted(t, conn, cipher, auth, reqMsgID, &mt.DestroySessionRequest{SessionID: targetSessionID}) + + replies := collectReplies(t, conn, cipher, auth.AuthKey, mt.DestroySessionOkTypeID) + buf := mustHave(t, replies, mt.DestroySessionOkTypeID, "destroy_session_ok") + var res mt.DestroySessionOk + if err := res.Decode(buf); err != nil { + t.Fatal(err) + } + if res.SessionID != targetSessionID { + t.Fatalf("destroy_session_ok.session_id = %d, want %d", res.SessionID, targetSessionID) + } + authKeyID, deletedSessionID := handler.deletion() + if authKeyID == ([8]byte{}) || deletedSessionID != targetSessionID { + t.Fatalf("durable deletion = auth:%x session:%d", authKeyID, deletedSessionID) + } +} + +func TestDestroySessionDurabilityFailureDoesNotAcknowledgeOrRetireLiveSession(t *testing.T) { + boom := errors.New("database unavailable") + handler := &durableDestroyLayerRPC{ + admissionOnlyLayerRPC: newAdmissionOnlyLayerRPC(), + err: boom, + } + manager := NewSessionManager(nil) + authKeyID := [8]byte{0xd3, 0x57} + target := &Conn{authKeyID: authKeyID, sessionID: 2, metrics: NopMetrics{}} + if err := manager.Register(target); err != nil { + t.Fatal(err) + } + defer manager.Unregister(target) + s := New(Options{DC: 2, LayerRPC: handler, ActiveSessions: manager}) + current := &Conn{authKeyID: authKeyID, sessionID: 1, metrics: NopMetrics{}} + + err := s.sendDestroySession(context.Background(), current, target.sessionID) + if !errors.Is(err, boom) { + t.Fatalf("destroy durability error = %v, want %v", err, boom) + } + manager.mu.RLock() + stillCurrent := manager.bySession[connSessionKey(target)] == target + manager.mu.RUnlock() + if !stillCurrent { + t.Fatal("durability failure retired the live target session") + } +} + // TestRPCDropAnswer 验证 rpc_drop_answer 以 rpc_result 包装 RpcDropAnswer 返回, -// 与 gotd/td 和 TDesktop 的请求/响应模型对齐。 +// 与 iamxvbaba/td 和 TDesktop 的请求/响应模型对齐。 func TestRPCDropAnswer(t *testing.T) { const dc = 2 addr, pub, _ := startTestServer(t, Options{DC: dc}) @@ -411,27 +524,218 @@ func TestPingDelayDisconnectOddSeqAccepted(t *testing.T) { } } -// TestDestroyAuthKey 验证 MTProto service message destroy_auth_key 由连接层直接响应, -// 避免 TDesktop 清理旧 key 时落到业务 RPC fallback。 +// TestDestroyAuthKey 验证 MTProto service message destroy_auth_key 无论裸发, +// 还是沿官方客户端的 invokeWithLayer/initConnection 路径发送,都由连接层 +// 直接处理,并以绑定原请求的 rpc_result 回复。 func TestDestroyAuthKey(t *testing.T) { + tests := []struct { + name string + layer int + wrapped bool + }{ + {name: "bare"}, + {name: "layer225_wrapped", layer: 225, wrapped: true}, + {name: "layer226_wrapped", layer: 226, wrapped: true}, + {name: "layer227_wrapped", layer: 227, wrapped: true}, + {name: "layer228_wrapped", layer: 228, wrapped: true}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + const dc = 2 + addr, pub, srv := startTestServer(t, Options{DC: dc, LayerRPC: newAdmissionOnlyLayerRPC()}) + conn, auth, cipher := dialHandshake(t, addr, dc, pub) + + var request bin.Encoder = &destroyAuthKeyRequest{} + if test.wrapped { + request = &tg.InvokeWithLayerRequest{ + Layer: test.layer, + Query: &tg.InitConnectionRequest{ + APIID: 1, + DeviceModel: "destroy-key-test", + SystemVersion: "test", + AppVersion: "test", + SystemLangCode: "en", + LangCode: "en", + Query: &destroyAuthKeyRequest{}, + }, + } + } + + clientMsgID := proto.NewMessageIDGen(time.Now) + reqMsgID := clientMsgID.New(proto.MessageFromClient) + sendEncrypted(t, conn, cipher, auth, reqMsgID, request) + + replies := collectReplies(t, conn, cipher, auth.AuthKey, proto.ResultTypeID) + assertDestroyAuthKeyRPCResult(t, mustHave(t, replies, proto.ResultTypeID, "destroy_auth_key rpc_result"), reqMsgID, destroyAuthKeyOkTypeID) + if _, found, err := srv.authKeys.Get(context.Background(), auth.AuthKey.ID); err != nil || found { + t.Fatalf("auth key after destroy: found=%v err=%v", found, err) + } + ctx, cancel := context.WithTimeout(context.Background(), time.Second) + defer cancel() + var frame bin.Buffer + if err := conn.Recv(ctx, &frame); err == nil { + t.Fatal("destroy_auth_key requester remained readable after required rpc_result(ok)") + } + }) + } +} + +func assertDestroyAuthKeyRPCResult(t *testing.T, b *bin.Buffer, reqMsgID int64, wantInner uint32) { + t.Helper() + var result proto.Result + if err := result.Decode(b); err != nil { + t.Fatalf("decode destroy_auth_key rpc_result: %v", err) + } + if result.RequestMessageID != reqMsgID { + t.Fatalf("destroy_auth_key rpc_result.req_msg_id = %d, want %d", result.RequestMessageID, reqMsgID) + } + inner := &bin.Buffer{Buf: result.Result} + innerID, err := inner.PeekID() + if err != nil { + t.Fatalf("peek destroy_auth_key rpc_result inner: %v", err) + } + if innerID != wantInner || inner.Len() != bin.Word { + t.Fatalf("destroy_auth_key rpc_result inner = %#x/%d bytes, want %#x/%d", innerID, inner.Len(), wantInner, bin.Word) + } +} + +func TestDestroyAuthKeyDeleteFailureReturnsCorrelatedFailAndKeepsConnection(t *testing.T) { const dc = 2 - addr, pub, srv := startTestServer(t, Options{DC: dc}) + deleteErr := errors.New("delete auth key failed") + keys := &deleteFailAuthKeyStore{AuthKeyStore: memory.NewAuthKeyStore(), err: deleteErr} + addr, pub, srv := startTestServer(t, Options{DC: dc, AuthKeys: keys, LayerRPC: newAdmissionOnlyLayerRPC()}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) - clientMsgID := proto.NewMessageIDGen(time.Now) - reqMsgID := clientMsgID.New(proto.MessageFromClient) - sendEncrypted(t, conn, cipher, auth, reqMsgID, &destroyAuthKeyRequest{}) + ids := proto.NewMessageIDGen(time.Now) + destroyReqMsgID := ids.New(proto.MessageFromClient) + sendEncrypted(t, conn, cipher, auth, destroyReqMsgID, &destroyAuthKeyRequest{}) + replies := collectReplies(t, conn, cipher, auth.AuthKey, proto.ResultTypeID) + assertDestroyAuthKeyRPCResult(t, mustHave(t, replies, proto.ResultTypeID, "destroy_auth_key fail rpc_result"), destroyReqMsgID, destroyAuthKeyFailTypeID) - replies := collectReplies(t, conn, cipher, auth.AuthKey, destroyAuthKeyOkTypeID) - mustHave(t, replies, destroyAuthKeyOkTypeID, "destroy_auth_key_ok") - if _, found, err := srv.authKeys.Get(context.Background(), auth.AuthKey.ID); err != nil || found { - t.Fatalf("auth key after destroy: found=%v err=%v", found, err) + if _, found, err := srv.authKeys.Get(context.Background(), auth.AuthKey.ID); err != nil || !found { + t.Fatalf("auth key after failed delete: found=%v err=%v", found, err) } - ctx, cancel := context.WithTimeout(context.Background(), time.Second) - defer cancel() - var frame bin.Buffer - if err := conn.Recv(ctx, &frame); err == nil { - t.Fatal("destroy_auth_key requester remained readable after required ok") + pingReqMsgID := ids.New(proto.MessageFromClient) + sendEncryptedWithSeq(t, conn, cipher, auth, pingReqMsgID, 3, &mt.PingRequest{PingID: 99}) + pongReplies := collectReplies(t, conn, cipher, auth.AuthKey, mt.PongTypeID) + var pong mt.Pong + if err := pong.Decode(mustHave(t, pongReplies, mt.PongTypeID, "pong after failed destroy_auth_key")); err != nil { + t.Fatalf("decode pong after failed destroy_auth_key: %v", err) + } + if pong.MsgID != pingReqMsgID || pong.PingID != 99 { + t.Fatalf("pong after failed destroy_auth_key = %+v", pong) + } +} + +func TestWrappedDestroyAuthKeyTrailingBytesDoNotDelete(t *testing.T) { + const dc = 2 + addr, pub, srv := startTestServer(t, Options{DC: dc, LayerRPC: newAdmissionOnlyLayerRPC()}) + conn, auth, cipher := dialHandshake(t, addr, dc, pub) + ids := proto.NewMessageIDGen(time.Now) + reqMsgID := ids.New(proto.MessageFromClient) + request := &tg.InvokeWithLayerRequest{ + Layer: 228, + Query: &tg.InitConnectionRequest{ + APIID: 1, DeviceModel: "malformed-destroy-key-test", SystemVersion: "test", + AppVersion: "test", SystemLangCode: "en", LangCode: "en", + Query: &trailingDestroyAuthKeyRequest{}, + }, + } + sendEncrypted(t, conn, cipher, auth, reqMsgID, request) + + replies := collectReplies(t, conn, cipher, auth.AuthKey, proto.ResultTypeID) + var result proto.Result + if err := result.Decode(mustHave(t, replies, proto.ResultTypeID, "malformed destroy_auth_key rpc_result")); err != nil { + t.Fatalf("decode malformed destroy_auth_key rpc_result: %v", err) + } + if result.RequestMessageID != reqMsgID { + t.Fatalf("malformed destroy_auth_key req_msg_id = %d, want %d", result.RequestMessageID, reqMsgID) + } + var rpcErr mt.RPCError + if err := rpcErr.Decode(&bin.Buffer{Buf: result.Result}); err != nil { + t.Fatalf("decode malformed destroy_auth_key RPC error: %v", err) + } + if rpcErr.ErrorCode != 400 || rpcErr.ErrorMessage != "INPUT_REQUEST_INVALID" { + t.Fatalf("malformed destroy_auth_key RPC error = %+v", rpcErr) + } + if _, found, err := srv.authKeys.Get(context.Background(), auth.AuthKey.ID); err != nil || !found { + t.Fatalf("auth key after malformed wrapped destroy: found=%v err=%v", found, err) + } +} + +func TestWrappedDestroyAuthKeySemanticWrapperDoesNotDelete(t *testing.T) { + const dc = 2 + addr, pub, srv := startTestServer(t, Options{DC: dc, LayerRPC: newAdmissionOnlyLayerRPC()}) + conn, auth, cipher := dialHandshake(t, addr, dc, pub) + ids := proto.NewMessageIDGen(time.Now) + reqMsgID := ids.New(proto.MessageFromClient) + request := &tg.InvokeWithLayerRequest{ + Layer: 228, + Query: &tg.InitConnectionRequest{ + APIID: 1, DeviceModel: "semantic-wrapper-destroy-key-test", SystemVersion: "test", + AppVersion: "test", SystemLangCode: "en", LangCode: "en", + Query: &tg.InvokeAfterMsgRequest{ + MsgID: 1, + Query: &destroyAuthKeyRequest{}, + }, + }, + } + sendEncrypted(t, conn, cipher, auth, reqMsgID, request) + + replies := collectReplies(t, conn, cipher, auth.AuthKey, proto.ResultTypeID) + var result proto.Result + if err := result.Decode(mustHave(t, replies, proto.ResultTypeID, "semantic-wrapper destroy_auth_key rpc_result")); err != nil { + t.Fatalf("decode semantic-wrapper destroy_auth_key rpc_result: %v", err) + } + if result.RequestMessageID != reqMsgID { + t.Fatalf("semantic-wrapper destroy_auth_key req_msg_id = %d, want %d", result.RequestMessageID, reqMsgID) + } + var rpcErr mt.RPCError + if err := rpcErr.Decode(&bin.Buffer{Buf: result.Result}); err != nil { + t.Fatalf("decode semantic-wrapper destroy_auth_key RPC error: %v", err) + } + if rpcErr.ErrorCode != 400 || rpcErr.ErrorMessage != "INPUT_REQUEST_INVALID" { + t.Fatalf("semantic-wrapper destroy_auth_key RPC error = %+v", rpcErr) + } + if _, found, err := srv.authKeys.Get(context.Background(), auth.AuthKey.ID); err != nil || !found { + t.Fatalf("auth key after semantic-wrapper destroy_auth_key: found=%v err=%v", found, err) + } +} + +func TestWrappedDestroyAuthKeyMixedContainerIsRejectedAtomically(t *testing.T) { + const dc = 2 + addr, pub, srv := startTestServer(t, Options{DC: dc, LayerRPC: newAdmissionOnlyLayerRPC()}) + conn, auth, cipher := dialHandshake(t, addr, dc, pub) + ids := proto.NewMessageIDGen(time.Now) + + destroyBody := encodeClientMessageBodyForTest(t, &tg.InvokeWithLayerRequest{ + Layer: 228, + Query: &tg.InitConnectionRequest{ + APIID: 1, DeviceModel: "mixed-destroy-key-test", SystemVersion: "test", + AppVersion: "test", SystemLangCode: "en", LangCode: "en", + Query: &destroyAuthKeyRequest{}, + }, + }) + pingBody := encodeClientMessageBodyForTest(t, &mt.PingRequest{PingID: 7}) + destroyMsgID := ids.New(proto.MessageFromClient) + pingMsgID := ids.New(proto.MessageFromClient) + outerMsgID := ids.New(proto.MessageFromClient) + container := &proto.MessageContainer{Messages: []proto.Message{ + {ID: destroyMsgID, SeqNo: 1, Bytes: len(destroyBody), Body: destroyBody}, + {ID: pingMsgID, SeqNo: 3, Bytes: len(pingBody), Body: pingBody}, + }} + sendEncrypted(t, conn, cipher, auth, outerMsgID, container) + + replies := collectReplies(t, conn, cipher, auth.AuthKey, mt.BadMsgNotificationTypeID) + var bad mt.BadMsgNotification + if err := bad.Decode(mustHave(t, replies, mt.BadMsgNotificationTypeID, "bad_msg for mixed destroy_auth_key container")); err != nil { + t.Fatalf("decode mixed destroy_auth_key bad_msg: %v", err) + } + if bad.BadMsgID != outerMsgID || bad.ErrorCode != badMsgContainer { + t.Fatalf("mixed destroy_auth_key bad_msg = %+v, want msg_id=%d code=%d", bad, outerMsgID, badMsgContainer) + } + if _, found, err := srv.authKeys.Get(context.Background(), auth.AuthKey.ID); err != nil || !found { + t.Fatalf("auth key after mixed destroy_auth_key container: found=%v err=%v", found, err) } } diff --git a/internal/mtprotoedge/exchange.go b/internal/mtprotoedge/exchange.go index 5acba16c..2643cdbc 100644 --- a/internal/mtprotoedge/exchange.go +++ b/internal/mtprotoedge/exchange.go @@ -8,12 +8,12 @@ import ( "go.uber.org/zap" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/exchange" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/transport" "telesrv/internal/store" ) diff --git a/internal/mtprotoedge/exchange_compat.go b/internal/mtprotoedge/exchange_compat.go index 1e38ead6..8856ab58 100644 --- a/internal/mtprotoedge/exchange_compat.go +++ b/internal/mtprotoedge/exchange_compat.go @@ -13,14 +13,14 @@ import ( gofaster "github.com/go-faster/errors" "go.uber.org/zap" - "github.com/gotd/td/bin" - "github.com/gotd/td/clock" - "github.com/gotd/td/crypto" - "github.com/gotd/td/exchange" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/transport" ) // runServerExchange is a gotd server exchange compatibility shim. @@ -425,7 +425,7 @@ func (s serverExchangeCompat) readUnencrypted(ctx context.Context, b *bin.Buffer if err := msg.Decode(b); err != nil { return err } - if proto.MessageID(msg.MessageID).Type() != proto.MessageFromClient { + if !validClientMessageIDBits(msg.MessageID) { return gofaster.New("bad msg type") } b.ResetTo(msg.MessageData) diff --git a/internal/mtprotoedge/exchange_test.go b/internal/mtprotoedge/exchange_test.go index 57829904..a61d6e6f 100644 --- a/internal/mtprotoedge/exchange_test.go +++ b/internal/mtprotoedge/exchange_test.go @@ -15,12 +15,12 @@ import ( "go.uber.org/zap/zaptest" "github.com/gotd/log/logzap" - "github.com/gotd/td/bin" - "github.com/gotd/td/exchange" - "github.com/gotd/td/mt" - tgproto "github.com/gotd/td/proto" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/mt" + tgproto "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/transport" "telesrv/internal/store" "telesrv/internal/store/memory" diff --git a/internal/mtprotoedge/flush_identity_test.go b/internal/mtprotoedge/flush_identity_test.go index 9ba62632..22f82c57 100644 --- a/internal/mtprotoedge/flush_identity_test.go +++ b/internal/mtprotoedge/flush_identity_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) // TestRunFlushDiscardsBatchOnIdentitySwitch 验证排空进行中连接易主(登出/换号致 diff --git a/internal/mtprotoedge/frame_budget.go b/internal/mtprotoedge/frame_budget.go index 69e11379..1dac53f4 100644 --- a/internal/mtprotoedge/frame_budget.go +++ b/internal/mtprotoedge/frame_budget.go @@ -7,9 +7,9 @@ import ( "io" "sync/atomic" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/transport" ) const defaultInboundFrameGlobalMaxBytes int64 = 512 << 20 diff --git a/internal/mtprotoedge/frame_budget_test.go b/internal/mtprotoedge/frame_budget_test.go index 84182f8a..a0ef896c 100644 --- a/internal/mtprotoedge/frame_budget_test.go +++ b/internal/mtprotoedge/frame_budget_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/transport" ) type frameBudgetTestConn struct { diff --git a/internal/mtprotoedge/handshake_reqpq_cap_test.go b/internal/mtprotoedge/handshake_reqpq_cap_test.go index 1a7c575f..e3f36a04 100644 --- a/internal/mtprotoedge/handshake_reqpq_cap_test.go +++ b/internal/mtprotoedge/handshake_reqpq_cap_test.go @@ -5,10 +5,10 @@ import ( "errors" "testing" - "github.com/gotd/td/bin" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/transport" ) // reqPQConn 是只会不断返回同一个 req_pq_multi 帧的假 transport.Conn,用于驱动 bufferedConn diff --git a/internal/mtprotoedge/helpers_test.go b/internal/mtprotoedge/helpers_test.go index 241d6c12..00cbb353 100644 --- a/internal/mtprotoedge/helpers_test.go +++ b/internal/mtprotoedge/helpers_test.go @@ -11,13 +11,97 @@ import ( "go.uber.org/zap/zaptest" "github.com/gotd/log/logzap" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/exchange" - "github.com/gotd/td/proto" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" ) +// legacyCanonicalTestConn explicitly declares the canonical-only profile used +// by old connection-state tests. Production exact-path tests must instead call +// FreezeLayerProfile/SeedLayerProfile with protocol evidence. +func legacyCanonicalTestConn(t testing.TB, c *Conn) *Conn { + return legacyLayerWireTestConn(t, c, int(tg.LayerProfileCanonical)) +} + +// legacyLayerWireTestConn preserves only the old tests' profile setup. It does +// not enable any wire conversion; application values still need an exact +// generated binding at the outbound boundary. +func legacyLayerWireTestConn(t testing.TB, c *Conn, layer int) *Conn { + t.Helper() + if c == nil { + t.Fatal("nil legacy exact-layer test Conn") + } + profile, ok := tg.ResolveLayerProfile(layer) + if !ok { + t.Fatalf("unsupported generated test Layer %d", layer) + } + if err := c.FreezeLayerProfile(profile); err != nil { + t.Fatalf("freeze generated test Layer %d: %v", layer, err) + } + c.setLegacyClientLayer(layer) + return c +} + +// exactTestUpdatesEncoded gives transport/state-machine tests an explicit +// generated session binding without invoking the production fan-out cache. +// Tests which assert wire conversion use layerUpdatesFanout directly instead. +func exactTestUpdatesEncoded(t testing.TB, c *Conn, body []byte) *encodedOutboundMessage { + t.Helper() + if c == nil { + t.Fatal("nil exact test Conn") + } + state := c.LayerProfileState() + if state.Origin == LayerProfileUnknown { + t.Fatal("exact test Conn has no generated Layer profile") + } + return &encodedOutboundMessage{ + body: append([]byte(nil), body...), + typeID: tg.UpdatesTooLongTypeID, + layer: &outboundLayerBinding{ + profile: state.Profile, + typ: tg.LayerClassUpdatesType().Ref(), + epoch: state.Epoch, + }, + } +} + +func exactTestUpdatesTooLong(t testing.TB, c *Conn) *encodedOutboundMessage { + t.Helper() + var body bin.Buffer + if err := (&tg.UpdatesTooLong{}).Encode(&body); err != nil { + t.Fatalf("encode exact test updatesTooLong: %v", err) + } + return exactTestUpdatesEncoded(t, c, body.Raw()) +} + +// opaqueExactTestRPCResult is an explicit request-bound capability for tests +// of compression, retention and delivery mechanics. Semantic result conversion +// is covered by generated dispatcher tests; no production path constructs it. +type opaqueExactTestRPCResult struct{ result bin.Encoder } + +func (r *opaqueExactTestRPCResult) Encode(b *bin.Buffer) error { return r.result.Encode(b) } + +func (r *opaqueExactTestRPCResult) exactLayerRPCResultBinding() outboundLayerBinding { + return outboundLayerBinding{ + profile: tg.LayerProfileCanonical, + typ: tg.LayerClassUpdatesType().Ref(), + kind: outboundLayerBindingRequest, + } +} + +func exactTestRPCResult(result bin.Encoder) bin.Encoder { + if result == nil || isLayerInvariantRPCResultEncoder(result) { + return result + } + if _, ok := result.(exactLayerRPCResultEncoder); ok { + return result + } + return &opaqueExactTestRPCResult{result: result} +} + // startTestServer 生成 RSA key、监听随机端口并启动 Server,返回监听地址与公钥。 // 通过 t.Cleanup 自动取消并校验优雅退出。opts 的 RSAKey/Logger/DC 会被补默认。 func startTestServer(t *testing.T, opts Options) (addr string, pub exchange.PublicKey, srv *Server) { @@ -92,6 +176,27 @@ func dialTransportOnly(t *testing.T, addr string) transport.Conn { return conn } +// freezeActiveTestSessionProfile gives low-level transport fixtures the exact +// profile that a production invokeWithLayer admission would have proven. It is +// intentionally explicit: handshake/new_session_created alone never implies a +// TL Layer, and production push code must keep failing closed in that state. +func freezeActiveTestSessionProfile(t *testing.T, sessions *SessionManager, authKeyID [8]byte, sessionID int64, profile tg.LayerProfile) { + t.Helper() + if sessions == nil { + t.Fatal("freeze test session profile on nil SessionManager") + } + key := sessionKey{authKeyID: authKeyID, sessionID: sessionID} + sessions.mu.RLock() + c := sessions.bySession[key] + sessions.mu.RUnlock() + if c == nil { + t.Fatalf("active test session %x/%d is missing", authKeyID, sessionID) + } + if err := c.FreezeLayerProfile(profile); err != nil { + t.Fatalf("freeze active test session profile %d: %v", profile, err) + } +} + // sendEncrypted 用 client cipher 加密并发送一条带 msgID 的消息。 func sendEncrypted(t *testing.T, conn transport.Conn, cipher crypto.Cipher, auth exchange.ClientExchangeResult, msgID int64, msg bin.Encoder) { t.Helper() diff --git a/internal/mtprotoedge/inbound_layer_rpc.go b/internal/mtprotoedge/inbound_layer_rpc.go new file mode 100644 index 00000000..a06c8955 --- /dev/null +++ b/internal/mtprotoedge/inbound_layer_rpc.go @@ -0,0 +1,1109 @@ +package mtprotoedge + +import ( + "context" + "errors" + "fmt" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" + "go.uber.org/zap" +) + +var inboundLayerDecodeLimits = tg.LayerDecodeLimits{ + MaxWireBytes: maxInflightRPCBytes, + // contacts.editCloseFriends and contacts.setBlocked deliberately allow + // 5,000 entries. Keep the coarse generated allocation ceiling above every + // registered semantic field cap; field callbacks reject 5,001 before the + // typed decoder allocates the vector. + MaxVectorElements: 8 << 10, + MaxAggregateElements: 128 << 10, + MaxDepth: 32, +} + +var errDefaultLayerAdmission = errors.New("selected layer profile rejected naked RPC") + +const ( + maxLayerRPCDependencyIDs = 128 + + // Exact admission materializes canonical request structs, interface-backed + // nested objects, vectors, strings, and byte slices before a scheduler task + // exists. Current generated request-reachable TL structs are at most 376 + // bytes (guarded by TestLayerRPCAdmissionMaterializationConstants), so 512 + // bytes is the forward-drift ceiling. One ceiling per maximum decode depth is + // reserved as fixed graph slack; the 60x wire factor covers repeated nested + // values, slice/interface headers, payload copies, and allocator rounding. + // The largest legal upload part (512 KiB) charges less than the ordinary + // 32-MiB per-connection budget and therefore remains admissible by default. + layerRPCAdmissionStaticObjectBytes = 512 + layerRPCAdmissionWireFactor = 60 + layerRPCAdmissionGraphSlack = layerRPCAdmissionStaticObjectBytes * 32 +) + +type layerRPCDependencySet struct { + waiters []*rpcResultWaiter + failed bool +} + +type layerRPCProfileEvidence struct { + profile tg.LayerProfile + admissionSeq uint64 + present bool + fresh bool + commit bool + publish bool +} + +// layerRPCAdmissionCursor is the wire-ordered, side-effect-free view used while +// decoding one MTProto container. evidenceMsgID is the last explicit +// invokeWithLayer proof, not merely the profile used by an arbitrary cached +// request. It therefore advances only after generated admission reports +// ProfileEvidence. +type layerRPCAdmissionCursor struct { + state LayerProfileSnapshot + rawLayer int + evidenceMsgID int64 +} + +func (c *layerRPCAdmissionCursor) observe(profile tg.LayerProfile, msgID int64) error { + return c.observeRaw(int(profile), msgID) +} + +func (c *layerRPCAdmissionCursor) observeRaw(layer int, msgID int64) error { + if c == nil || msgID <= 0 { + return fmt.Errorf("invalid provisional Layer evidence msg_id %d", msgID) + } + if layer <= 0 { + return fmt.Errorf("invalid provisional Layer evidence %d", layer) + } + if c.evidenceMsgID != 0 { + switch { + case msgID < c.evidenceMsgID: + return nil + case msgID == c.evidenceMsgID: + if c.rawLayer != layer { + return fmt.Errorf("%w: msg_id %d selected Layer %d after Layer %d", ErrLayerProfileConflict, msgID, layer, c.rawLayer) + } + return nil + } + } + c.state = LayerProfileSnapshot{} + if profile, supported := tg.ResolveLayerProfile(layer); supported { + c.state = LayerProfileSnapshot{Profile: profile, Origin: LayerProfileExplicit} + } + c.rawLayer = layer + c.evidenceMsgID = msgID + return nil +} + +func (s *Server) initialLayerRPCAdmissionCursor(ctx context.Context, c *Conn) (layerRPCAdmissionCursor, error) { + if c == nil { + return layerRPCAdmissionCursor{}, fmt.Errorf("nil Conn for provisional Layer admission") + } + state, rawLayer, msgID := c.layerProfileRawEvidenceState() + if rawLayer == 0 && state.Origin != LayerProfileUnknown { + rawLayer = int(state.Profile) + } + cursor := layerRPCAdmissionCursor{state: state, rawLayer: rawLayer, evidenceMsgID: msgID} + var ( + layer int + registryMsgID int64 + found bool + ) + if _, durable := s.layerRPC.(LayerRPCDurableSessionProfileResolver); durable { + // Production resolves durable exact-session evidence once while creating + // this physical Conn (seedInitialLayerProfile). The Conn snapshot is then + // the admission authority until its own wire carries invokeWithLayer. + // Re-reading PostgreSQL for every RPC/container batch puts a database RTT on + // the protocol hot path and would also let another process silently rewrite + // an already-live physical connection. A stale grammar self-corrects through + // CONNECTION_LAYER_INVALID -> invokeWithLayer; a replacement Conn performs + // a fresh durable seed before admitting its first request. + return cursor, nil + } else if resolver, ok := s.layerRPC.(LayerRPCOrderedSessionProfileResolver); ok { + layer, registryMsgID, found = resolver.NegotiatedSessionLayerEvidence(c.authKeyID, c.sessionID) + } else { + return cursor, nil + } + if !found { + return cursor, nil + } + if registryMsgID < 0 || layer <= 0 { + return layerRPCAdmissionCursor{}, fmt.Errorf("invalid exact session Layer evidence layer=%d msg_id=%d", layer, registryMsgID) + } + if registryMsgID == 0 { + if cursor.evidenceMsgID == 0 { + cursor.state = LayerProfileSnapshot{} + if profile, supported := tg.ResolveLayerProfile(layer); supported { + cursor.state = LayerProfileSnapshot{Profile: profile, Origin: LayerProfileExplicit} + } + cursor.rawLayer = layer + } + return cursor, nil + } + if err := cursor.observeRaw(layer, registryMsgID); err != nil { + return layerRPCAdmissionCursor{}, fmt.Errorf("merge exact session Layer evidence: %w", err) + } + // Restore the same raw watermark onto this physical generation. Unsupported + // future Layers intentionally leave its usable profile unknown. + if registryMsgID > 0 { + if err := c.seedRawLayerEvidence(layer, registryMsgID); err != nil { + return layerRPCAdmissionCursor{}, fmt.Errorf("restore exact session raw Layer evidence: %w", err) + } + cursor.state, cursor.rawLayer, cursor.evidenceMsgID = c.layerProfileRawEvidenceState() + } + return cursor, nil +} + +// layerRPCAdmissionReservationSize returns a saturating conservative charge. +// Saturation deliberately turns hostile integer-sized inputs into ordinary +// capacity rejection; it must never wrap into a small accepted reservation. +func layerRPCAdmissionReservationSize(wireBytes int) int { + if wireBytes < 0 { + wireBytes = 0 + } + maxInt := int(^uint(0) >> 1) + if wireBytes > (maxInt-layerRPCAdmissionGraphSlack)/layerRPCAdmissionWireFactor { + return maxInt + } + return wireBytes*layerRPCAdmissionWireFactor + layerRPCAdmissionGraphSlack +} + +// prepareInboundLayerRPCBatch is the production API path. The whole container +// reserves conservative task/materialization capacity before the first exact +// decoder callback. Admission then classifies every request; fresh owners keep +// their original tickets, while replay/error/join entries are released without +// a release/reacquire gap for the retained tasks. +func (s *Server) prepareInboundLayerRPCBatch(ctx context.Context, c *Conn, plan *inboundPlan) error { + var candidateItems []int + var provisionalSpecs []inboundRPCSpec + for index := range plan.items { + item := &plan.items[index] + if item.kind == inboundItemRPC { + candidateItems = append(candidateItems, index) + provisionalSpecs = append(provisionalSpecs, inboundRPCSpec{ + method: s.typeName(item.typeID), + size: layerRPCAdmissionReservationSize(len(item.body)), + }) + } + } + if len(candidateItems) == 0 { + return nil + } + + reservation, err := c.reserveInboundRPCBatch(ctx, provisionalSpecs) + if err != nil { + if errors.Is(err, ErrInboundRPCQueueFull) { + for _, index := range candidateItems { + plan.items[index].kind = inboundItemCapacityError + } + return nil + } + return err + } + // Install ownership immediately: every return below is covered by plan.close. + plan.rpcReservation = reservation + + // Decode the container in wire order with a provisional cursor. Explicit + // evidence may select the grammar for a following naked item even when the + // evidence request is already pending/completed. The ordered msg_id watermark + // makes an old replay inert and rejects a same-msg_id conflicting selector. + // Nothing mutates Conn/registry until exact flight identity accepts the item. + admissionCursor, err := s.initialLayerRPCAdmissionCursor(ctx, c) + if err != nil { + return err + } + evidence := make([]layerRPCProfileEvidence, len(plan.items)) + for _, index := range candidateItems { + item := &plan.items[index] + itemState := admissionCursor.state + existingProfile, existing := s.rpcResults.ExactAdmissionProfile(c.authKeyID, c.sessionID, item.msgID) + if existing { + itemState = LayerProfileSnapshot{Profile: existingProfile, Origin: LayerProfileExplicit} + } + admitted, method, err := s.decodeInboundLayerRPC(itemState, item.body) + if err != nil { + if terminal, recognized := wrappedDestroyAuthKeyTerminal(err); recognized { + if terminal.WireSize != bin.Word || !validWrappedDestroyAuthKeyChain(terminal) { + s.log.Debug("Wrapped destroy_auth_key terminal rejected", + zap.Int("profile", int(terminal.Profile)), + zap.Int("wire_size", terminal.WireSize), + zap.Int("wrapper_count", terminal.WrapperCount()), + zap.Int64("msg_id", item.msgID), + ) + item.kind = inboundItemRPCAdmissionError + item.method = "destroy_auth_key" + item.payload = &mt.RPCError{ErrorCode: 400, ErrorMessage: "INPUT_REQUEST_INVALID"} + c.metrics.InboundRPCDropped(item.method, "layer_admission") + continue + } + if len(plan.items) != 1 { + return errDestroyAuthKeyMustBeExclusive + } + item.kind = inboundItemDestroyAuthKey + item.method = "destroy_auth_key" + item.payload = destroyAuthKeyRequest{} + continue + } + if errors.Is(err, ErrLayerProfileConflict) { + return err + } + s.log.Debug("RPC exact admission rejected", + zap.String("method", method), + zap.String("auth_key_id", c.authKeyHex), + zap.Int64("session_id", c.sessionID), + zap.Int64("msg_id", item.msgID), + zap.Error(err), + ) + item.kind = inboundItemRPCAdmissionError + item.method = method + item.payload = layerRPCAdmissionError(err) + c.metrics.InboundRPCDropped(method, "layer_admission") + continue + } + item.admitted = admitted + item.method = method + if profile, hasEvidence := admitted.ProfileEvidence(); hasEvidence { + if existing && profile != existingProfile { + return fmt.Errorf("%w: cached msg_id %d used Layer %d but replay selected Layer %d", ErrLayerProfileConflict, item.msgID, existingProfile, profile) + } + evidence[index] = layerRPCProfileEvidence{profile: profile, present: true, fresh: item.profileEvidenceFresh()} + if evidence[index].fresh { + if err := admissionCursor.observe(profile, item.msgID); err != nil { + return err + } + } + } + } + + var indices []int + var reservationIndices []int + var specs []inboundRPCSpec + var ownersInPlan map[int64]*rpcResultOwnerLease + flightCapacity := false + clearedPostInitCandidates := false + provisionalRewrapInitialized := c.rpcRewrapInitialized.Load() + acceptedInitState := false + for reservationIndex, index := range candidateItems { + item := &plan.items[index] + if item.kind != inboundItemRPC { + continue + } + method := item.method + _, isInitRewrap := admittedRPCRewrapInit(item.admitted) + if isInitRewrap { + if item.profileEvidenceFresh() { + provisionalRewrapInitialized = true + acceptedInitState = true + } + if candidate := s.rpcRewrap.claimSemantic( + c, + item.admitted.Prepared().SemanticIdentity(), + item.admitted.Call().Identity(), + ); candidate != nil { + claim, err := s.acquireAdmittedLayerRPC(c, item, &evidence[index]) + if errors.Is(err, ErrRPCResultFlightCapacity) { + s.rpcRewrap.release(candidate) + c.metrics.InboundRPCDropped(candidate.method, "flight_capacity") + flightCapacity = true + item.kind = inboundItemCapacityError + continue + } + if err != nil { + s.rpcRewrap.release(candidate) + return err + } + method = item.method + item.admissionSeq = claim.admissionSeq + if evidence[index].present && evidence[index].fresh { + evidence[index].commit = true + evidence[index].admissionSeq = claim.admissionSeq + evidence[index].publish = claim.state == rpcResultAcquireOwner + } + switch claim.state { + case rpcResultAcquireCompleted: + after, prepareErr := s.prepareAdmittedLayerRPCReplay(ctx, c, item.msgID, claim.admissionSeq, item.profileEvidenceFresh(), item.admitted) + if prepareErr != nil { + s.rpcRewrap.release(candidate) + return prepareErr + } + s.rpcRewrap.commit(candidate) + item.kind = inboundItemReplayRPC + item.payload = claim.encoded + if claim.executionKnown && claim.executionOK { + item.replayAfterSuccessfulDelivery = after + } + case rpcResultAcquirePending: + after, prepareErr := s.prepareAdmittedLayerRPCReplay(ctx, c, item.msgID, claim.admissionSeq, item.profileEvidenceFresh(), item.admitted) + if prepareErr != nil { + s.rpcRewrap.release(candidate) + return prepareErr + } + s.rpcRewrap.commit(candidate) + item.kind = inboundItemRewrappedRPC + item.payload = claim.waiter + plan.rewrapAliases = append(plan.rewrapAliases, &rpcRewrapAlias{ + conn: c, itemIndex: index, newReqID: item.msgID, method: candidate.method, + oldWaiter: claim.waiter, + afterSuccessfulDelivery: after, + }) + case rpcResultAcquireOwner: + after, prepareErr := s.prepareAdmittedLayerRPCReplay(ctx, c, item.msgID, claim.admissionSeq, item.profileEvidenceFresh(), item.admitted) + if prepareErr != nil { + s.rpcRewrap.release(candidate) + claim.owner.Abort() + return prepareErr + } + if ownersInPlan == nil { + ownersInPlan = make(map[int64]*rpcResultOwnerLease) + } + ownersInPlan[item.msgID] = claim.owner + item.kind = inboundItemRewrappedRPC + item.payload = claim.owner + plan.rewrapAliases = append(plan.rewrapAliases, &rpcRewrapAlias{ + conn: c, itemIndex: index, newReqID: item.msgID, method: candidate.method, + oldWaiter: candidate.waiter, newOwner: claim.owner, + sourceConn: candidate.source, sourceOwner: candidate.owner, + afterSuccessfulDelivery: after, + candidate: candidate, registry: s.rpcRewrap, + }) + default: + s.rpcRewrap.release(candidate) + return ErrRPCResultFlightInvalid + } + s.log.Info("RPC init rewrap matched", + zap.String("method", candidate.method), + zap.Int64("old_req_msg_id", candidate.reqMsgID), + zap.Int64("new_req_msg_id", item.msgID), + zap.Bool("same_connection", candidate.source == c), + zap.String("auth_key_id", c.authKeyHex), zap.Int64("session_id", c.sessionID)) + continue + } + } else if provisionalRewrapInitialized && !clearedPostInitCandidates { + s.rpcRewrap.clearSession(c) + clearedPostInitCandidates = true + } + + claim, err := s.acquireAdmittedLayerRPC(c, item, &evidence[index]) + if errors.Is(err, ErrRPCResultFlightCapacity) { + c.metrics.InboundRPCDropped(method, "flight_capacity") + flightCapacity = true + item.kind = inboundItemCapacityError + continue + } + if err != nil { + return err + } + method = item.method + item.admissionSeq = claim.admissionSeq + if evidence[index].present && evidence[index].fresh { + evidence[index].commit = true + evidence[index].publish = claim.state == rpcResultAcquireOwner + evidence[index].admissionSeq = claim.admissionSeq + } + switch claim.state { + case rpcResultAcquireCompleted: + after, prepareErr := s.prepareAdmittedLayerRPCReplay(ctx, c, item.msgID, claim.admissionSeq, item.profileEvidenceFresh(), item.admitted) + if prepareErr != nil { + return prepareErr + } + item.kind = inboundItemReplayRPC + item.payload = claim.encoded + if claim.executionKnown && claim.executionOK { + item.replayAfterSuccessfulDelivery = after + } + case rpcResultAcquirePending: + if ownersInPlan[item.msgID] != nil { + item.kind = inboundItemDuplicate + item.payload = nil + } else { + after, prepareErr := s.prepareAdmittedLayerRPCReplay(ctx, c, item.msgID, claim.admissionSeq, item.profileEvidenceFresh(), item.admitted) + if prepareErr != nil { + return prepareErr + } + item.kind = inboundItemRewrappedRPC + item.payload = claim.waiter + plan.rewrapAliases = append(plan.rewrapAliases, &rpcRewrapAlias{ + conn: c, itemIndex: index, newReqID: item.msgID, method: method, oldWaiter: claim.waiter, + afterSuccessfulDelivery: after, + }) + } + case rpcResultAcquireOwner: + if ownersInPlan == nil { + ownersInPlan = make(map[int64]*rpcResultOwnerLease) + indices = make([]int, 0, len(plan.items)) + specs = make([]inboundRPCSpec, 0, len(plan.items)) + } + ownersInPlan[item.msgID] = claim.owner + plan.rpcOwners = append(plan.rpcOwners, claim.owner) + item.payload = claim.owner + indices = append(indices, index) + reservationIndices = append(reservationIndices, reservationIndex) + specs = append(specs, inboundRPCSpec{ + method: method, + size: layerRPCAdmissionReservationSize(item.admitted.Prepared().WireSize()), + }) + if !provisionalRewrapInitialized && !isInitRewrap { + s.rpcRewrap.registerSemantic( + c, + item.admitted.Prepared().SemanticIdentity(), + item.admitted.Call().Identity(), + item.msgID, + method, + claim.owner, + ) + } + default: + return ErrRPCResultFlightInvalid + } + } + + if flightCapacity { + for _, index := range indices { + plan.items[index].kind = inboundItemCapacityError + } + plan.rejectNewRPCOwners(indices) + for _, index := range candidateItems { + plan.items[index].admitted = tg.LayerRequest{} + } + if err := reservation.retain(nil, nil); err != nil { + return err + } + plan.rpcReservation = nil + return nil + } + var profileCapacityItems map[int]struct{} + for _, index := range candidateItems { + proof := evidence[index] + if !proof.present || !proof.commit { + continue + } + current, err := s.commitLayerProfileEvidence(ctx, c, proof.profile, plan.items[index].msgID) + if err != nil { + if isLayerEvidenceDurabilityUnavailable(err) { + if _, localErr := c.freezeLayerProfileAt(proof.profile, plan.items[index].msgID); localErr != nil { + return fmt.Errorf("apply connection-local Layer evidence fallback: %w", localErr) + } + // The durable failure limits propagation, not validity of the + // selector on this physical connection. Keep fresh=true so an + // initConnection can initialize this Conn, enable updates and retain + // its device metadata. Only exact/auth-key/session publication is + // suppressed; a replacement connection must negotiate again. + evidence[index].publish = false + s.log.Error("Durable exact session Layer unavailable; using connection-local request profile", + zap.String("auth_key_id", c.authKeyHex), zap.Int64("session_id", c.sessionID), + zap.Int64("msg_id", plan.items[index].msgID), zap.Int("layer", int(proof.profile)), zap.Error(err)) + continue + } + if isExactSessionProfileCapacityError(err) { + if profileCapacityItems == nil { + profileCapacityItems = make(map[int]struct{}) + } + profileCapacityItems[index] = struct{}{} + continue + } + return err + } + evidence[index].publish = evidence[index].publish && current + } + if len(profileCapacityItems) != 0 { + // Match the existing whole-container flight-capacity policy: no newly + // acquired owner from this admission unit may execute or publish shared + // evidence. Completed/pending joins remain replayable unless their own + // fresh selector was the capacity failure. + for index := range profileCapacityItems { + item := &plan.items[index] + item.kind = inboundItemCapacityError + if _, ownsFlight := item.payload.(*rpcResultOwnerLease); !ownsFlight { + item.payload = nil + } + } + plan.rejectNewRPCOwners(indices) + keptAliases := plan.rewrapAliases[:0] + for _, alias := range plan.rewrapAliases { + if alias == nil { + continue + } + if _, rejected := profileCapacityItems[alias.itemIndex]; rejected { + alias.releaseCandidate() + continue + } + keptAliases = append(keptAliases, alias) + } + plan.rewrapAliases = keptAliases + for _, index := range candidateItems { + plan.items[index].admitted = tg.LayerRequest{} + } + if err := reservation.retain(nil, nil); err != nil { + return err + } + plan.rpcReservation = nil + return nil + } + if acceptedInitState { + // Every explicit profile commit, including durable local-only fallback, has + // now classified the item. Only a still-fresh init wrapper may advance the + // connection-initialized marker. + for _, index := range candidateItems { + if plan.items[index].profileEvidenceFresh() { + if _, isInit := admittedRPCRewrapInit(plan.items[index].admitted); isInit { + c.rpcRewrapInitialized.Store(true) + break + } + } + } + } + for _, index := range candidateItems { + proof := evidence[index] + if !proof.present || !proof.commit { + continue + } + if evidence[index].publish { + publisher, ok := s.layerRPC.(LayerRPCAdmissionProfilePublisher) + if ok { + if proof.admissionSeq == 0 { + return ErrRPCAdmissionSeqExhausted + } + safeFloor := s.rpcResults.stableAdmissionSafeFloor() + if safeFloor == 0 || safeFloor > proof.admissionSeq { + return fmt.Errorf("invalid active admission safe floor %d for sequence %d", safeFloor, proof.admissionSeq) + } + if err := publisher.PublishAdmittedLayerProfileEvidence( + ctx, c.authKeyID, c.sessionID, plan.items[index].msgID, + proof.admissionSeq, safeFloor, int(proof.profile), + ); err != nil { + return fmt.Errorf("publish admitted Layer profile evidence: %w", err) + } + } + } + } + if len(specs) == 0 { + for _, index := range candidateItems { + plan.items[index].admitted = tg.LayerRequest{} + } + if err := reservation.retain(nil, nil); err != nil { + return err + } + plan.rpcReservation = nil + return nil + } + + dependencies := make([]layerRPCDependencySet, len(indices)) + for taskIndex, itemIndex := range indices { + item := &plan.items[itemIndex] + dependencies[taskIndex] = s.layerRPCDependencies(c, item.msgID, item.admitted) + } + plan.rpcTasks = make([]inboundRPC, len(indices)) + for taskIndex, itemIndex := range indices { + item := &plan.items[itemIndex] + owner, _ := item.payload.(*rpcResultOwnerLease) + plan.rpcTasks[taskIndex] = s.newInboundLayerRPCTask(c, item.msgID, item.admissionSeq, item.method, item.profileEvidenceFresh(), item.admitted, dependencies[taskIndex], owner) + } + // Tasks now own the admitted request leases. Drop the plan's value copies + // before non-fresh reservations become reusable. + for _, index := range candidateItems { + plan.items[index].admitted = tg.LayerRequest{} + } + if err := reservation.retain(reservationIndices, specs); err != nil { + return err + } + return nil +} + +// acquireAdmittedLayerRPC resolves the only legal admission TOCTOU: two +// replacement physical connections may both miss the pre-decode hint and use +// different inherited defaults for the same naked body. The winner's stored +// profile is then authoritative for this msg_id. Re-decode once under that +// profile and retry the full identity claim; a changed body still mismatches. +// The mismatch carries that profile from inside the shard lock, so an immediate +// winner abort/eviction cannot make us fall back to an ambiguous loser default. +func (s *Server) acquireAdmittedLayerRPC( + c *Conn, + item *inboundItem, + evidence *layerRPCProfileEvidence, +) (rpcResultAcquire, error) { + if s == nil || c == nil || item == nil { + return rpcResultAcquire{}, ErrRPCResultFlightInvalid + } + acquire := func() (rpcResultAcquire, error) { + profile := tg.LayerProfile(0) + if effective, known := item.admitted.EffectiveProfile(); known { + profile = effective + } + return s.rpcResults.AcquireLayerIdentified( + c.authKeyID, c.sessionID, item.msgID, + profile, item.admitted.Prepared().Identity(), + ) + } + claim, err := acquire() + if !errors.Is(err, ErrRPCResultIdentityMismatch) { + return claim, err + } + var mismatch *rpcResultIdentityMismatchError + if !errors.As(err, &mismatch) || !mismatch.hasProfile { + return rpcResultAcquire{}, err + } + winnerProfile := mismatch.profile + if winnerProfile == item.admitted.Call().Profile() { + // Same profile plus a different full identity is a same-msg_id body + // mutation, not an inherited-default race. + return rpcResultAcquire{}, err + } + redecoded, method, decodeErr := s.decodeInboundLayerRPC( + LayerProfileSnapshot{Profile: winnerProfile, Origin: LayerProfileExplicit}, + item.body, + ) + if decodeErr != nil { + return rpcResultAcquire{}, decodeErr + } + item.admitted = redecoded + item.method = method + if evidence != nil { + fresh := evidence.fresh + *evidence = layerRPCProfileEvidence{fresh: fresh} + if profile, present := redecoded.ProfileEvidence(); present { + evidence.profile = profile + evidence.present = true + } + } + return acquire() +} + +func (s *Server) prepareAdmittedLayerRPCReplay(ctx context.Context, c *Conn, msgID int64, admissionSeq uint64, profileEvidenceFresh bool, request tg.LayerRequest) (func() error, error) { + preparer, ok := s.layerRPC.(LayerRPCReplayPreparer) + if !ok || c == nil { + return nil, nil + } + ctx = s.withLayerRPCProfileEvidenceFresh(ctx, profileEvidenceFresh) + after, err := preparer.PrepareAdmittedReplay(ctx, c.authKeyID, c.sessionID, msgID, admissionSeq, request) + if err != nil { + s.log.Warn("Prepare exact RPC replay side effects failed", + zap.String("auth_key_id", c.authKeyHex), + zap.Int64("session_id", c.sessionID), + zap.Error(err)) + return nil, fmt.Errorf("prepare exact RPC replay effects: %w", err) + } + return after, nil +} + +func (s *Server) withLayerRPCProfileEvidenceFresh(ctx context.Context, fresh bool) context.Context { + if ctx == nil { + ctx = context.Background() + } + if decorator, ok := s.layerRPC.(LayerRPCProfileEvidenceContext); ok { + if decorated := decorator.WithLayerRPCProfileEvidenceFresh(ctx, fresh); decorated != nil { + return decorated + } + } + return ctx +} + +// admitInboundLayerRPC is the force-style compatibility entry point used by +// focused tests and old embedders. Production must call admitInboundLayerRPCAt +// with the real inner MTProto client msg_id. +func (s *Server) admitInboundLayerRPC(c *Conn, body []byte) (tg.LayerRequest, string, error) { + return s.admitInboundLayerRPCAt(c, 0, body) +} + +func (s *Server) admitInboundLayerRPCAt(c *Conn, msgID int64, body []byte) (tg.LayerRequest, string, error) { + if s == nil || s.layerRPC == nil || c == nil || len(body) < bin.Word { + return tg.LayerRequest{}, "unknown", fmt.Errorf("invalid exact RPC admission input") + } + request, method, err := s.decodeInboundLayerRPC(c.LayerProfileState(), body) + if err != nil { + return tg.LayerRequest{}, method, err + } + if profile, hasEvidence := request.ProfileEvidence(); hasEvidence { + if _, err := s.commitLayerProfileEvidence(context.Background(), c, profile, msgID); err != nil { + if !isLayerEvidenceDurabilityUnavailable(err) { + return tg.LayerRequest{}, method, err + } + if msgID > 0 { + if _, localErr := c.freezeLayerProfileAt(profile, msgID); localErr != nil { + return tg.LayerRequest{}, method, localErr + } + } + } + } + return request, method, nil +} + +// layerRPCAdmissionHasExplicitSelector distinguishes a failed naked request +// under a stale default from a failed explicit correction. Generated +// unsupported/conflicting invokeWithLayer failures carry the wrapper semantic +// in LayerCodecError. A truncated selector can fail before that typed error is +// constructed, so the bounded fallback walks only transparent wrapper prefixes +// whose query offset is fixed and allocation-free. +func layerRPCAdmissionHasExplicitSelector(body []byte, admissionErr error) bool { + var codecErr *tg.LayerCodecError + if errors.As(admissionErr, &codecErr) && codecErr.Semantic == tg.LayerSemanticMethodInvokeWithLayer { + return true + } + + probe := &bin.Buffer{Buf: body} + for depth := 0; depth < inboundLayerDecodeLimits.MaxDepth; depth++ { + id, err := probe.PeekID() + if err != nil { + return false + } + switch id { + case tg.InvokeWithLayerRequestTypeID: + // Seeing the constructor is enough: a missing/malformed layer field is + // itself an explicit correction attempt and must retain its real error. + return true + case tg.InvokeWithoutUpdatesRequestTypeID: + if err := probe.ConsumeID(id); err != nil { + return false + } + case tg.InvokeAfterMsgRequestTypeID: + if err := probe.ConsumeID(id); err != nil { + return false + } + if _, err := probe.Long(); err != nil { + return false + } + case tg.InvokeAfterMsgsRequestTypeID: + if err := probe.ConsumeID(id); err != nil { + return false + } + count, err := probe.VectorHeader() + if err != nil || count > probe.Len()/8 { + return false + } + probe.Buf = probe.Buf[count*8:] + default: + return false + } + } + return false +} + +// decodeInboundLayerRPC is side-effect free. Production batch admission uses +// it with a wire-ordered provisional profile cursor, then publishes explicit +// evidence only after the full request identity has acquired an owner (or a +// genuine new-msg_id rewrap alias). +func (s *Server) decodeInboundLayerRPC(state LayerProfileSnapshot, body []byte) (tg.LayerRequest, string, error) { + if s == nil || s.layerRPC == nil || len(body) < bin.Word { + return tg.LayerRequest{}, "unknown", fmt.Errorf("invalid exact RPC admission input") + } + b := &bin.Buffer{Buf: body} + var ( + request tg.LayerRequest + err error + ) + if state.Origin != LayerProfileUnknown { + if admitter, ok := s.layerRPC.(LayerRPCDefaultProfileAdmitter); ok { + request, err = admitter.AdmitDefaultLayer(state.Profile, b, inboundLayerDecodeLimits) + } else { + // Compatibility fallback for old package tests/mocks. Production Router + // implements default admission so explicit invokeWithLayer can correct. + request, err = s.layerRPC.AdmitLayer(state.Profile, b, inboundLayerDecodeLimits) + } + } else { + request, err = s.layerRPC.AdmitUnprofiled(b, inboundLayerDecodeLimits) + } + method := "unknown" + if err == nil { + _, method, _ = tg.LayerSemanticName(request.Call().Method()) + if b.Len() != 0 { + return tg.LayerRequest{}, method, fmt.Errorf("exact RPC admission left %d bytes", b.Len()) + } + if effective, known := request.EffectiveProfile(); known && effective != request.Call().Profile() { + return tg.LayerRequest{}, method, fmt.Errorf("%w: effective profile %d differs from call profile %d", ErrLayerProfileConflict, effective, request.Call().Profile()) + } + // A generated invariant terminal may use canonical decoding internally + // before the client declares a layer. Only explicit invokeWithLayer (or the + // strict compatibility fallback above) publishes new profile evidence. + if profile, hasEvidence := request.ProfileEvidence(); hasEvidence { + if profile != request.Call().Profile() { + return tg.LayerRequest{}, method, fmt.Errorf("%w: generated profile evidence %d differs from call profile %d", ErrLayerProfileConflict, profile, request.Call().Profile()) + } + } + return request, method, nil + } + if state.Origin != LayerProfileUnknown && !layerRPCAdmissionHasExplicitSelector(body, err) { + // Both inherited metadata and a restored same-session snapshot may be stale + // after a client upgrade. One naked-RPC failure asks the official client to + // clear connectionInited and resend explicit invokeWithLayer. Explicit + // retries keep their real unsupported/conflict/malformed error even when the + // selector sits below invokeAfter* or invokeWithoutUpdates. + err = fmt.Errorf("%w: %w", errDefaultLayerAdmission, err) + } + if id, peekErr := (&bin.Buffer{Buf: body}).PeekID(); peekErr == nil { + method = s.typeName(id) + } + if codecErr := new(tg.LayerCodecError); errors.As(err, &codecErr) { + if codecErr.Semantic != 0 { + if _, semanticMethod, ok := tg.LayerSemanticName(codecErr.Semantic); ok && semanticMethod != "" { + method = semanticMethod + } + } else if codecErr.WireID != 0 { + // Nested unknown terminals have no semantic id. Prefer the generated + // failing constructor over the top-level transparent wrapper so the + // compatibility trace names the actual missing RPC. + method = s.typeName(codecErr.WireID) + } + } + if errors.Is(err, tg.ErrLayerUnknownRPCMethod) && s.log != nil { + if terminal, recognized := wrappedDestroyAuthKeyTerminal(err); recognized { + method = "destroy_auth_key" + s.log.Debug("Generated wrapper admission exposed MTProto service terminal", + zap.String("method", method), + zap.Int("profile", int(terminal.Profile)), + zap.Uint32("wire_id", terminal.WireID), + zap.Int("wire_size", terminal.WireSize), + ) + } else { + s.log.Warn("Unhandled RPC admission (compatibility trace)", + zap.String("method", method), zap.Error(err)) + } + } + return tg.LayerRequest{}, method, err +} + +// commitLayerProfileEvidence publishes one generated invokeWithLayer proof. +// The exact-session registry is the cross-physical-connection linearization +// point; the Conn cursor then prevents a concurrent older admission from +// overwriting its local wire epoch. Older cached duplicates remain decodable +// and request-bound, but cannot mutate session/profile state. +func (s *Server) commitLayerProfileEvidence(ctx context.Context, c *Conn, profile tg.LayerProfile, msgID int64) (bool, error) { + if s == nil || c == nil { + return false, fmt.Errorf("invalid layer profile evidence target") + } + if msgID > 0 { + if registry, ok := s.layerRPC.(LayerRPCDurableSessionProfileAdvancer); ok { + layer, authoritativeMsgID, publishShared, err := registry.AdvanceNegotiatedSessionLayerEvidence( + ctx, c.authKeyID, c.sessionID, int(profile), msgID, + ) + if err != nil { + return false, fmt.Errorf("advance durable exact session Layer evidence: %w", err) + } + if layer <= 0 || authoritativeMsgID <= 0 { + return false, fmt.Errorf("%w: durable exact session evidence returned layer=%d msg_id=%d", ErrLayerProfileConflict, layer, authoritativeMsgID) + } + if s.conns != nil { + if _, err := s.conns.ApplyOrderedRawLayerForSession(c, c.authKeyID, c.sessionID, layer, authoritativeMsgID); err != nil { + return false, err + } + } else if _, err := c.freezeRawLayerProfileAt(layer, authoritativeMsgID); err != nil { + return false, err + } + authoritative, supported := tg.ResolveLayerProfile(layer) + return supported && authoritative == profile && authoritativeMsgID == msgID && publishShared, nil + } + if registry, ok := s.layerRPC.(LayerRPCOrderedSessionProfileRegistry); ok { + _, err := registry.FreezeNegotiatedSessionLayerAt(c.authKeyID, c.sessionID, int(profile), msgID) + if err != nil { + if isExactSessionProfileCapacityError(err) { + return false, fmt.Errorf("freeze ordered exact session registry capacity: %w", err) + } + return false, fmt.Errorf("%w: freeze ordered exact session registry: %w", ErrLayerProfileConflict, err) + } + // Always re-read and broadcast the authoritative registry value, even + // when this proof was stale/identical. Two physical generations may + // interleave registry commit and local publication; broadcasting the + // max cursor to every active/claim Conn makes their final state converge. + layer, authoritativeMsgID, found := registry.NegotiatedSessionLayerEvidence(c.authKeyID, c.sessionID) + if !found || authoritativeMsgID <= 0 { + return false, fmt.Errorf("%w: ordered exact session evidence disappeared after commit", ErrLayerProfileConflict) + } + authoritative, supported := tg.ResolveLayerProfile(layer) + if s.conns != nil { + if _, err := s.conns.ApplyOrderedRawLayerForSession(c, c.authKeyID, c.sessionID, layer, authoritativeMsgID); err != nil { + return false, err + } + } else if _, err := c.freezeRawLayerProfileAt(layer, authoritativeMsgID); err != nil { + return false, err + } + if !supported { + // A future durable Layer is an ordering watermark, not a codec this + // binary can use. Keep every Conn unknown and let a greater supported + // invokeWithLayer self-heal it. + return false, nil + } + return authoritative == profile && authoritativeMsgID == msgID, nil + } + // Older handlers without a persistent ordered registry still receive + // per-Conn replay protection. Production Router implements the interface. + applied, err := c.freezeLayerProfileAt(profile, msgID) + if err != nil || !applied { + return applied, err + } + if registry, ok := s.layerRPC.(LayerRPCSessionProfileRegistry); ok { + if err := registry.FreezeNegotiatedSessionLayer(c.authKeyID, c.sessionID, int(profile)); err != nil { + return false, fmt.Errorf("%w: freeze exact session registry: %v", ErrLayerProfileConflict, err) + } + } + if s.conns != nil { + s.conns.SeedInheritedLayerForRawAuthKey(c.authKeyID, int(profile)) + } + return true, nil + } + + // msgID==0 intentionally preserves the previous force semantics for direct + // admission tests. It is never used by the production batch path. + if registry, ok := s.layerRPC.(LayerRPCSessionProfileRegistry); ok { + if err := registry.FreezeNegotiatedSessionLayer(c.authKeyID, c.sessionID, int(profile)); err != nil { + return false, fmt.Errorf("%w: freeze exact session registry: %v", ErrLayerProfileConflict, err) + } + } + if err := c.FreezeLayerProfile(profile); err != nil { + return false, err + } + if s.conns != nil { + s.conns.SeedInheritedLayerForRawAuthKey(c.authKeyID, int(profile)) + } + return true, nil +} + +type exactSessionProfileCapacityMarker interface { + ExactSessionProfileCapacity() +} + +type layerEvidenceDurabilityUnavailableMarker interface { + LayerEvidenceDurabilityUnavailable() +} + +func isExactSessionProfileCapacityError(err error) bool { + var marker exactSessionProfileCapacityMarker + return errors.As(err, &marker) +} + +func isLayerEvidenceDurabilityUnavailable(err error) bool { + var marker layerEvidenceDurabilityUnavailableMarker + return errors.As(err, &marker) +} + +func layerRPCAdmissionError(err error) *mt.RPCError { + if errors.Is(err, errDefaultLayerAdmission) { + return &mt.RPCError{ErrorCode: 400, ErrorMessage: "CONNECTION_LAYER_INVALID"} + } + if errors.Is(err, tg.ErrLayerProfileRequired) { + return &mt.RPCError{ErrorCode: 400, ErrorMessage: "CONNECTION_NOT_INITED"} + } + var rpcErr *tgerr.Error + if errors.As(err, &rpcErr) { + return &mt.RPCError{ErrorCode: rpcErr.Code, ErrorMessage: rpcErr.Message} + } + if errors.Is(err, tg.ErrLayerUnknownRPCMethod) { + return &mt.RPCError{ErrorCode: 501, ErrorMessage: "NOT_IMPLEMENTED"} + } + return &mt.RPCError{ErrorCode: 400, ErrorMessage: "INPUT_REQUEST_INVALID"} +} + +func (s *Server) layerRPCDependencies(c *Conn, msgID int64, request tg.LayerRequest) layerRPCDependencySet { + result := layerRPCDependencySet{} + seen := make(map[int64]struct{}) + for index := 0; index < request.WrapperCount(); index++ { + wrapper, _ := request.Wrapper(index) + var ids []int64 + switch wrapper.Semantic() { + case tg.LayerSemanticMethodInvokeAfterMsg: + id, err := layerRPCWrapperRequired[int64](wrapper, "msg_id") + if err != nil { + result.failed = true + continue + } + ids = []int64{id} + case tg.LayerSemanticMethodInvokeAfterMsgs: + var err error + ids, err = layerRPCWrapperRequired[[]int64](wrapper, "msg_ids") + if err != nil || len(ids) > maxLayerRPCDependencyIDs { + result.failed = true + continue + } + default: + continue + } + for _, dependencyID := range ids { + if dependencyID <= 0 || dependencyID >= msgID { + result.failed = true + continue + } + if _, duplicate := seen[dependencyID]; duplicate { + continue + } + seen[dependencyID] = struct{}{} + dependency, ok := s.rpcResults.ObserveDependency(c.authKeyID, c.sessionID, dependencyID) + if !ok { + result.failed = true + continue + } + if dependency.completed { + if !dependency.success { + result.failed = true + } + continue + } + if dependency.waiter != nil { + result.waiters = append(result.waiters, dependency.waiter) + } + } + } + return result +} + +func admittedRPCRewrapInit(request tg.LayerRequest) (rpcRewrapInit, bool) { + if request.WrapperCount() != 2 { + return rpcRewrapInit{}, false + } + layerWrapper, ok := request.Wrapper(0) + if !ok || layerWrapper.Semantic() != tg.LayerSemanticMethodInvokeWithLayer { + return rpcRewrapInit{}, false + } + initWrapper, ok := request.Wrapper(1) + if !ok || initWrapper.Semantic() != tg.LayerSemanticMethodInitConnection { + return rpcRewrapInit{}, false + } + layer, err := layerRPCWrapperRequired[int](layerWrapper, "layer") + if err != nil || layer != int(request.Call().Profile()) { + return rpcRewrapInit{}, false + } + apiID, err := layerRPCWrapperRequired[int](initWrapper, "api_id") + if err != nil { + return rpcRewrapInit{}, false + } + deviceModel, err := layerRPCWrapperRequired[string](initWrapper, "device_model") + if err != nil { + return rpcRewrapInit{}, false + } + system, err := layerRPCWrapperRequired[string](initWrapper, "system_version") + if err != nil { + return rpcRewrapInit{}, false + } + appVersion, err := layerRPCWrapperRequired[string](initWrapper, "app_version") + if err != nil { + return rpcRewrapInit{}, false + } + systemLang, err := layerRPCWrapperRequired[string](initWrapper, "system_lang_code") + if err != nil { + return rpcRewrapInit{}, false + } + langPack, err := layerRPCWrapperRequired[string](initWrapper, "lang_pack") + if err != nil { + return rpcRewrapInit{}, false + } + langCode, err := layerRPCWrapperRequired[string](initWrapper, "lang_code") + if err != nil { + return rpcRewrapInit{}, false + } + return rpcRewrapInit{ + layer: layer, apiID: apiID, deviceModel: deviceModel, system: system, + appVersion: appVersion, systemLang: systemLang, langPack: langPack, langCode: langCode, + }, true +} + +func layerRPCWrapperRequired[T any](wrapper tg.LayerRPCWrapper, name string) (T, error) { + var zero T + value, present, ok, err := wrapper.Value(name) + if err != nil || !ok || !present { + return zero, fmt.Errorf("invalid RPC wrapper field %q", name) + } + typed, ok := value.(T) + if !ok { + return zero, fmt.Errorf("RPC wrapper field %q has type %T", name, value) + } + return typed, nil +} diff --git a/internal/mtprotoedge/inbound_layer_rpc_test.go b/internal/mtprotoedge/inbound_layer_rpc_test.go new file mode 100644 index 00000000..1b3a8917 --- /dev/null +++ b/internal/mtprotoedge/inbound_layer_rpc_test.go @@ -0,0 +1,1899 @@ +package mtprotoedge + +import ( + "context" + "errors" + "fmt" + "sync" + "sync/atomic" + "testing" + "time" + + "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/rpc" + "telesrv/internal/store" + "telesrv/internal/store/memory" +) + +func exactLayerRPCBody(t *testing.T, request bin.Encoder) []byte { + t.Helper() + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + return body.Copy() +} + +func exactOutboundLayerRPCBody(t *testing.T, profile tg.LayerProfile, request bin.Object) []byte { + t.Helper() + outbound, err := tg.PrepareLayerOutboundCall(profile, request) + if err != nil { + t.Fatal(err) + } + return exactLayerRPCBody(t, outbound) +} + +type admissionOnlyLayerRPC struct { + dispatcher *tg.ServerDispatcher + mu sync.Mutex + published []publishedLayerEvidence +} + +type orderedAdmissionOnlyLayerRPC struct { + *admissionOnlyLayerRPC + exactMu sync.Mutex + exact map[orderedTestSessionKey]struct { + layer int + msgID int64 + } +} + +type orderedTestSessionKey struct { + authKeyID [8]byte + sessionID int64 +} + +type publishedLayerEvidence struct { + authKeyID [8]byte + sessionID int64 + msgID int64 + admissionSeq uint64 + safeFloor uint64 + layer int +} + +type exactProfileCapacityTestError struct{} + +func (exactProfileCapacityTestError) Error() string { return "exact profile capacity" } +func (exactProfileCapacityTestError) ExactSessionProfileCapacity() {} + +type layerDurabilityUnavailableTestError struct{} + +func (layerDurabilityUnavailableTestError) Error() string { return "layer durability unavailable" } +func (layerDurabilityUnavailableTestError) LayerEvidenceDurabilityUnavailable() {} + +type capacityAdmissionOnlyLayerRPC struct { + *orderedAdmissionOnlyLayerRPC +} + +type unavailableDurableAdmissionLayerRPC struct { + *orderedAdmissionOnlyLayerRPC +} + +type unavailableDurableSeedLayerRPC struct { + *admissionOnlyLayerRPC + resolveCalls atomic.Int32 + inheritedCalls atomic.Int32 +} + +type unavailableEdgeSessionLayerStore struct { + err error +} + +type countingEdgeSessionLayerStore struct { + store.AuthKeySessionLayerStore + getCalls atomic.Int32 +} + +func (s *countingEdgeSessionLayerStore) GetSessionLayer( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, +) (store.AuthKeySessionLayer, bool, error) { + s.getCalls.Add(1) + return s.AuthKeySessionLayerStore.GetSessionLayer(ctx, rawAuthKeyID, sessionID) +} + +func (s unavailableEdgeSessionLayerStore) GetSessionLayer(context.Context, [8]byte, int64) (store.AuthKeySessionLayer, bool, error) { + return store.AuthKeySessionLayer{}, false, s.err +} + +func (s unavailableEdgeSessionLayerStore) AdvanceSessionLayer(context.Context, [8]byte, int64, int, int64) (store.AuthKeySessionLayer, bool, error) { + return store.AuthKeySessionLayer{}, false, s.err +} + +func (s unavailableEdgeSessionLayerStore) DeleteSessionLayer(context.Context, [8]byte, int64) (bool, error) { + return false, s.err +} + +func (s unavailableEdgeSessionLayerStore) DeleteExpiredSessionLayers(context.Context, int) (int, error) { + return 0, s.err +} + +type dispatchProfileCaptureRouter struct { + *rpc.Router + mu sync.Mutex + requestProfile tg.LayerProfile + resultProfile tg.LayerProfile +} + +func (h *dispatchProfileCaptureRouter) DispatchAdmitted( + ctx context.Context, + authKeyID [8]byte, + sessionID int64, + msgID int64, + admissionSeq uint64, + request tg.LayerRequest, +) (tg.LayerRPCResult, string, error) { + result, method, err := h.Router.DispatchAdmitted(ctx, authKeyID, sessionID, msgID, admissionSeq, request) + h.mu.Lock() + h.requestProfile = request.Call().Profile() + if result != nil { + h.resultProfile = result.Prepared().Call().Profile() + } + h.mu.Unlock() + return result, method, err +} + +func (h *dispatchProfileCaptureRouter) profiles() (tg.LayerProfile, tg.LayerProfile) { + h.mu.Lock() + defer h.mu.Unlock() + return h.requestProfile, h.resultProfile +} + +func (*unavailableDurableAdmissionLayerRPC) ResolveNegotiatedSessionLayerEvidence( + context.Context, [8]byte, int64, +) (int, int64, bool, error) { + return 0, 0, false, nil +} + +func (h *unavailableDurableSeedLayerRPC) ResolveNegotiatedSessionLayerEvidence( + context.Context, [8]byte, int64, +) (int, int64, bool, error) { + h.resolveCalls.Add(1) + return 0, 0, false, layerDurabilityUnavailableTestError{} +} + +func (h *unavailableDurableSeedLayerRPC) ResolveInheritedAuthKeyLayer( + context.Context, [8]byte, +) (int, bool, error) { + h.inheritedCalls.Add(1) + return 0, false, layerDurabilityUnavailableTestError{} +} + +func (*unavailableDurableAdmissionLayerRPC) AdvanceNegotiatedSessionLayerEvidence( + context.Context, [8]byte, int64, int, int64, +) (int, int64, bool, error) { + return 0, 0, false, layerDurabilityUnavailableTestError{} +} + +func (h *capacityAdmissionOnlyLayerRPC) FreezeNegotiatedSessionLayerAt([8]byte, int64, int, int64) (bool, error) { + return false, exactProfileCapacityTestError{} +} + +type replayProfileCaptureLayerRPC struct { + *admissionOnlyLayerRPC + mu sync.Mutex + profiles []tg.LayerProfile + known []bool +} + +func (h *replayProfileCaptureLayerRPC) PrepareAdmittedReplay( + _ context.Context, + _ [8]byte, + _ int64, + _ int64, + _ uint64, + request tg.LayerRequest, +) (func() error, error) { + profile, known := request.EffectiveProfile() + h.mu.Lock() + h.profiles = append(h.profiles, profile) + h.known = append(h.known, known) + h.mu.Unlock() + return nil, nil +} + +func (h *replayProfileCaptureLayerRPC) capturedProfiles() ([]tg.LayerProfile, []bool) { + h.mu.Lock() + defer h.mu.Unlock() + return append([]tg.LayerProfile(nil), h.profiles...), append([]bool(nil), h.known...) +} + +func newAdmissionOnlyLayerRPC() *admissionOnlyLayerRPC { + return &admissionOnlyLayerRPC{dispatcher: tg.NewServerDispatcher(nil)} +} + +func newOrderedAdmissionOnlyLayerRPC() *orderedAdmissionOnlyLayerRPC { + return &orderedAdmissionOnlyLayerRPC{ + admissionOnlyLayerRPC: newAdmissionOnlyLayerRPC(), + exact: make(map[orderedTestSessionKey]struct { + layer int + msgID int64 + }), + } +} + +func (h *orderedAdmissionOnlyLayerRPC) NegotiatedSessionLayerEvidence(authKeyID [8]byte, sessionID int64) (int, int64, bool) { + h.exactMu.Lock() + defer h.exactMu.Unlock() + entry, ok := h.exact[orderedTestSessionKey{authKeyID: authKeyID, sessionID: sessionID}] + return entry.layer, entry.msgID, ok +} + +func (h *orderedAdmissionOnlyLayerRPC) FreezeNegotiatedSessionLayerAt(authKeyID [8]byte, sessionID int64, layer int, msgID int64) (bool, error) { + h.exactMu.Lock() + defer h.exactMu.Unlock() + key := orderedTestSessionKey{authKeyID: authKeyID, sessionID: sessionID} + current, ok := h.exact[key] + if ok { + if msgID < current.msgID { + return false, nil + } + if msgID == current.msgID { + if layer != current.layer { + return false, fmt.Errorf("same msg_id selected two layers") + } + return false, nil + } + } + h.exact[key] = struct { + layer int + msgID int64 + }{layer: layer, msgID: msgID} + return true, nil +} + +func (h *admissionOnlyLayerRPC) AdmitLayer(profile tg.LayerProfile, b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) { + return h.dispatcher.AdmitLayerWithLimits(profile, b, limits) +} + +func (h *admissionOnlyLayerRPC) AdmitDefaultLayer(profile tg.LayerProfile, b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) { + return h.dispatcher.AdmitDefaultLayerWithLimits(profile, b, limits) +} + +func (h *admissionOnlyLayerRPC) AdmitUnprofiled(b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) { + return h.dispatcher.AdmitUnprofiledWithLimits(b, limits) +} + +func (*admissionOnlyLayerRPC) DispatchAdmitted(context.Context, [8]byte, int64, int64, uint64, tg.LayerRequest) (tg.LayerRPCResult, string, error) { + return nil, "", fmt.Errorf("admission-only handler") +} + +func (h *admissionOnlyLayerRPC) PublishAdmittedLayerProfileEvidence( + _ context.Context, + authKeyID [8]byte, + sessionID int64, + msgID int64, + admissionSeq uint64, + safeFloor uint64, + layer int, +) error { + h.mu.Lock() + h.published = append(h.published, publishedLayerEvidence{ + authKeyID: authKeyID, sessionID: sessionID, msgID: msgID, + admissionSeq: admissionSeq, safeFloor: safeFloor, layer: layer, + }) + h.mu.Unlock() + return nil +} + +func (h *admissionOnlyLayerRPC) publications() []publishedLayerEvidence { + h.mu.Lock() + defer h.mu.Unlock() + return append([]publishedLayerEvidence(nil), h.published...) +} + +func TestNestedExplicitLayerAdmissionErrorsAreNotDefaultFailures(t *testing.T) { + handler := newAdmissionOnlyLayerRPC() + s := New(Options{DC: 2, LayerRPC: handler}) + state := LayerProfileSnapshot{Profile: tg.LayerProfile227, Origin: LayerProfileInherited} + + unsupported := exactLayerRPCBody(t, &tg.InvokeAfterMsgRequest{ + MsgID: 1, + Query: &tg.InvokeWithLayerRequest{ + Layer: 229, + Query: &tg.HelpGetConfigRequest{}, + }, + }) + conflict := exactLayerRPCBody(t, &tg.InvokeAfterMsgsRequest{ + MsgIDs: []int64{1, 2}, + Query: &tg.InvokeWithLayerRequest{ + Layer: 225, + Query: &tg.InvokeWithoutUpdatesRequest{Query: &tg.InvokeWithLayerRequest{ + Layer: 227, + Query: &tg.HelpGetConfigRequest{}, + }}, + }, + }) + var truncatedSelector bin.Buffer + truncatedSelector.PutID(tg.InvokeWithoutUpdatesRequestTypeID) + truncatedSelector.PutID(tg.InvokeAfterMsgRequestTypeID) + truncatedSelector.PutLong(3) + truncatedSelector.PutID(tg.InvokeWithLayerRequestTypeID) + var malformedSelectedQuery bin.Buffer + malformedSelectedQuery.PutID(tg.InvokeAfterMsgRequestTypeID) + malformedSelectedQuery.PutLong(4) + malformedSelectedQuery.PutID(tg.InvokeWithLayerRequestTypeID) + malformedSelectedQuery.PutInt(225) + malformedSelectedQuery.PutID(tg.MessagesGetHistoryRequestTypeID) + + for _, test := range []struct { + name string + body []byte + wantSemantic bool + }{ + {name: "unsupported", body: unsupported, wantSemantic: true}, + {name: "conflict", body: conflict, wantSemantic: true}, + {name: "truncated_selector", body: truncatedSelector.Copy()}, + {name: "malformed_selected_query", body: malformedSelectedQuery.Copy()}, + } { + t.Run(test.name, func(t *testing.T) { + _, _, err := s.decodeInboundLayerRPC(state, test.body) + if err == nil { + t.Fatal("malformed explicit admission unexpectedly succeeded") + } + if errors.Is(err, errDefaultLayerAdmission) { + t.Fatalf("explicit admission was misclassified as stale default: %v", err) + } + if test.wantSemantic { + var codecErr *tg.LayerCodecError + if !errors.As(err, &codecErr) || codecErr.Semantic != tg.LayerSemanticMethodInvokeWithLayer { + t.Fatalf("explicit error semantic = %#v, err=%v", codecErr, err) + } + } + }) + } + + var nakedMalformed bin.Buffer + nakedMalformed.PutID(tg.MessagesGetHistoryRequestTypeID) + if _, _, err := s.decodeInboundLayerRPC(state, nakedMalformed.Copy()); !errors.Is(err, errDefaultLayerAdmission) { + t.Fatalf("naked malformed request error = %v, want stale-default classification", err) + } +} + +func TestBatchProvisionalCursorKeepsRegistryWatermarkAcrossOldReplay(t *testing.T) { + handler := newOrderedAdmissionOnlyLayerRPC() + s := New(Options{DC: 2, LayerRPC: handler}) + authKeyID := [8]byte{0x31, 0x01} + const sessionID = int64(3101) + if _, err := handler.FreezeNegotiatedSessionLayerAt(authKeyID, sessionID, 227, 104); err != nil { + t.Fatal(err) + } + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + if err := c.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + defer c.Close() + + oldBody := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 225, Query: &tg.HelpGetConfigRequest{}}) + oldAdmitted, _, err := s.decodeInboundLayerRPC( + LayerProfileSnapshot{Profile: tg.LayerProfile225, Origin: LayerProfileExplicit}, oldBody, + ) + if err != nil { + t.Fatal(err) + } + oldClaim, err := s.rpcResults.AcquireLayerIdentified( + authKeyID, sessionID, 100, oldAdmitted.Call().Profile(), oldAdmitted.Prepared().Identity(), + ) + if err != nil || oldClaim.owner == nil { + t.Fatalf("old owner err=%v", err) + } + oldClaim.owner.CompleteExecution(true) + s.rpcResults.Put(authKeyID, sessionID, 100, &encodedOutboundMessage{body: []byte{1}, reqMsgID: 100}) + + nakedBody := exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }) + plan := &inboundPlan{items: []inboundItem{ + {kind: inboundItemRPC, msgID: 100, body: oldBody}, + {kind: inboundItemRPC, msgID: 108, body: nakedBody}, + }} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatal(err) + } + if plan.items[0].kind != inboundItemReplayRPC { + t.Fatalf("old explicit item kind=%d, want completed replay", plan.items[0].kind) + } + if profile, ok := s.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, 108); !ok || profile != tg.LayerProfile227 { + t.Fatalf("following naked admission profile = (%d,%v), want registry Layer 227", profile, ok) + } +} + +func TestBatchProvisionalCursorUsesPendingNewerExplicitEvidence(t *testing.T) { + handler := newAdmissionOnlyLayerRPC() + s := New(Options{DC: 2, LayerRPC: handler}) + authKeyID := [8]byte{0x31, 0x02} + const sessionID = int64(3102) + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + if err := c.seedOrderedLayerProfile(tg.LayerProfile225, 100); err != nil { + t.Fatal(err) + } + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + defer c.Close() + + explicitBody := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: &tg.HelpGetConfigRequest{}}) + explicit, _, err := s.decodeInboundLayerRPC( + LayerProfileSnapshot{Profile: tg.LayerProfile227, Origin: LayerProfileExplicit}, explicitBody, + ) + if err != nil { + t.Fatal(err) + } + pending, err := s.rpcResults.AcquireLayerIdentified( + authKeyID, sessionID, 104, explicit.Call().Profile(), explicit.Prepared().Identity(), + ) + if err != nil || pending.owner == nil { + t.Fatalf("pending explicit owner err=%v", err) + } + defer pending.owner.Abort() + + nakedBody := exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }) + plan := &inboundPlan{items: []inboundItem{ + {kind: inboundItemRPC, msgID: 104, body: explicitBody}, + {kind: inboundItemRPC, msgID: 108, body: nakedBody}, + }} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatal(err) + } + if plan.items[0].kind != inboundItemRewrappedRPC { + t.Fatalf("pending explicit item kind=%d, want pending replay", plan.items[0].kind) + } + if profile, ok := s.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, 108); !ok || profile != tg.LayerProfile227 { + t.Fatalf("following naked admission profile = (%d,%v), want pending Layer 227", profile, ok) + } + if state, msgID := c.layerProfileEvidenceState(); state.Profile != tg.LayerProfile227 || state.Origin != LayerProfileExplicit || msgID != 104 { + t.Fatalf("pending full-identity evidence was not committed = %#v msgID:%d", state, msgID) + } + if got := handler.publications(); len(got) != 0 { + t.Fatalf("pending join published auth-key default: %#v", got) + } +} + +func TestBatchProvisionalCursorRejectsSameMsgIDLayerConflict(t *testing.T) { + handler := newOrderedAdmissionOnlyLayerRPC() + s := New(Options{DC: 2, LayerRPC: handler}) + authKeyID := [8]byte{0x31, 0x03} + const sessionID = int64(3103) + if _, err := handler.FreezeNegotiatedSessionLayerAt(authKeyID, sessionID, 225, 104); err != nil { + t.Fatal(err) + } + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + defer c.Close() + plan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, + msgID: 104, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: &tg.HelpGetConfigRequest{}}), + }}} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); !errors.Is(err, ErrLayerProfileConflict) { + t.Fatalf("same-msg_id Layer conflict err=%v, want %v", err, ErrLayerProfileConflict) + } +} + +func TestFutureExactLayerWatermarkAllowsOnlyNewerSupportedSelfHeal(t *testing.T) { + handler := newOrderedAdmissionOnlyLayerRPC() + s := New(Options{DC: 2, LayerRPC: handler}) + authKeyID := [8]byte{0x31, 0x04} + const sessionID = int64(3104) + if _, err := handler.FreezeNegotiatedSessionLayerAt(authKeyID, sessionID, 229, 100); err != nil { + t.Fatal(err) + } + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + if err := c.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + defer c.Close() + + oldPlan := &inboundPlan{items: []inboundItem{ + { + kind: inboundItemRPC, msgID: 96, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: &tg.HelpGetConfigRequest{}}), + }, + { + kind: inboundItemRPC, msgID: 104, + body: exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }), + }, + }} + defer oldPlan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, oldPlan); err != nil { + t.Fatal(err) + } + if oldPlan.items[1].kind != inboundItemRPCAdmissionError { + t.Fatalf("naked non-invariant after future watermark kind=%d, want admission error", oldPlan.items[1].kind) + } + if state, rawLayer, msgID := c.layerProfileRawEvidenceState(); state.Origin != LayerProfileUnknown || rawLayer != 229 || msgID != 100 { + t.Fatalf("future raw watermark = %#v raw:%d msgID:%d", state, rawLayer, msgID) + } + if got := handler.publications(); len(got) != 0 { + t.Fatalf("older supported selector published shared default: %#v", got) + } + + conflict := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: 100, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: &tg.HelpGetConfigRequest{}}), + }}} + defer conflict.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, conflict); !errors.Is(err, ErrLayerProfileConflict) { + t.Fatalf("same-msg future Layer conflict err=%v, want %v", err, ErrLayerProfileConflict) + } + + newPlan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: 108, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: &tg.HelpGetNearestDCRequest{}}), + }}} + defer newPlan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, newPlan); err != nil { + t.Fatal(err) + } + if state, rawLayer, msgID := c.layerProfileRawEvidenceState(); state.Profile != tg.LayerProfile227 || state.Origin != LayerProfileExplicit || rawLayer != 227 || msgID != 108 { + t.Fatalf("newer supported self-heal = %#v raw:%d msgID:%d", state, rawLayer, msgID) + } + if got := handler.publications(); len(got) != 1 || got[0].layer != 227 || got[0].msgID != 108 { + t.Fatalf("self-heal publication = %#v", got) + } +} + +func TestExactProfileRegistryCapacityBecomesBoundedRPCAdmission(t *testing.T) { + handler := &capacityAdmissionOnlyLayerRPC{orderedAdmissionOnlyLayerRPC: newOrderedAdmissionOnlyLayerRPC()} + s := New(Options{DC: 2, LayerRPC: handler}) + c := &Conn{authKeyID: [8]byte{0x31, 0x05}, sessionID: 3105, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + defer c.Close() + plan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: 100, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: &tg.HelpGetConfigRequest{}}), + }}} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatalf("capacity escaped as connection error: %v", err) + } + if plan.items[0].kind != inboundItemCapacityError || len(plan.rpcTasks) != 0 || plan.rpcReservation != nil { + t.Fatalf("capacity plan = kind:%d tasks:%d reservation:%v", plan.items[0].kind, len(plan.rpcTasks), plan.rpcReservation != nil) + } + if got := handler.publications(); len(got) != 0 { + t.Fatalf("capacity-rejected evidence published: %#v", got) + } + if state := c.LayerProfileState(); state.Origin != LayerProfileUnknown { + t.Fatalf("capacity rejection mutated Conn profile: %#v", state) + } +} + +func TestDurabilityOutageKeepsExplicitLayerConnectionLocal(t *testing.T) { + handler := &unavailableDurableAdmissionLayerRPC{orderedAdmissionOnlyLayerRPC: newOrderedAdmissionOnlyLayerRPC()} + s := New(Options{DC: 2, LayerRPC: handler}) + c := &Conn{authKeyID: [8]byte{0x31, 0x07}, sessionID: 3107, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + defer c.Close() + plan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: 100, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: &tg.HelpGetConfigRequest{}}), + }}} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatalf("durability outage rejected explicit request: %v", err) + } + if plan.items[0].kind != inboundItemRPC || len(plan.rpcTasks) != 1 { + t.Fatalf("local-only plan = kind:%d tasks:%d", plan.items[0].kind, len(plan.rpcTasks)) + } + if !plan.items[0].profileEvidenceFresh() { + t.Fatal("durability fallback incorrectly disabled current-connection wrapper effects") + } + if state, msgID := c.layerProfileEvidenceState(); state.Profile != tg.LayerProfile227 || state.Origin != LayerProfileExplicit || msgID != 100 { + t.Fatalf("connection-local evidence = %#v msgID:%d", state, msgID) + } + if _, _, found := handler.NegotiatedSessionLayerEvidence(c.authKeyID, c.sessionID); found { + t.Fatal("durability fallback polluted exact registry") + } + if got := handler.publications(); len(got) != 0 { + t.Fatalf("durability fallback published auth-key default: %#v", got) + } +} + +func TestDurabilityOutageInitializesOnlyCurrentConnection(t *testing.T) { + ctx := context.Background() + boom := errors.New("layer primary unavailable") + manager := NewSessionManager(zaptest.NewLogger(t)) + router := rpc.New( + rpc.Config{DC: 2}, + rpc.Deps{ + Sessions: manager, + AuthKeySessionLayers: unavailableEdgeSessionLayerStore{err: boom}, + }, + zaptest.NewLogger(t), + clock.System, + ) + s := New(Options{DC: 2, LayerRPC: router, ActiveSessions: manager}) + c := newOutboundTestConn(t, &collectingSessionTransport{}, newOutboundTrackedBudget(1<<20)) + c.authKeyID = [8]byte{0x31, 0x08} + c.sessionID = 3108 + // newOutboundTestConn installs a canonical profile for generic outbound + // tests. This scenario starts before any selector, so reset that fixture-only + // state before exposing the Conn to Router/SessionManager. + c.layerProfileMu.Lock() + c.layerProfileState.Store(0) + c.layerProfileEvidenceLayer = 0 + c.layerProfileEvidenceMsgID = 0 + c.setLegacyClientLayer(0) + c.layerProfileMu.Unlock() + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + if err := manager.Register(c); err != nil { + t.Fatal(err) + } + defer manager.Unregister(c) + manager.BindAuthKeyForSession(c.authKeyID, c.sessionID, c.authKeyID) + manager.BindUserForAuthKey(c.authKeyID, c.sessionID, 42) + // Production wires Channels and marks this after its empty/non-empty + // membership snapshot. This focused test has no channel service, so seed the + // independent membership half of the readiness predicate. + c.membershipsSynced.Store(true) + + msgID := proto.NewMessageIDGen(time.Now).New(proto.MessageFromClient) + plan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: msgID, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ + Layer: 227, + Query: &tg.InitConnectionRequest{ + APIID: 6, + DeviceModel: "Desktop", + SystemVersion: "Windows", + AppVersion: "outage-test", + SystemLangCode: "en", + LangPack: "tdesktop", + LangCode: "en", + Query: &tg.HelpGetConfigRequest{}, + }, + }), + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(ctx, c, plan); err != nil { + t.Fatalf("explicit init during outage: %v", err) + } + if len(plan.rpcTasks) != 1 || !plan.items[0].profileEvidenceFresh() { + t.Fatalf("outage init plan = tasks:%d fresh:%v", len(plan.rpcTasks), plan.items[0].profileEvidenceFresh()) + } + if !c.rpcRewrapInitialized.Load() { + t.Fatal("current connection did not retain successful init wrapper state") + } + if state, evidenceMsgID := c.layerProfileEvidenceState(); state.Profile != tg.LayerProfile227 || state.Origin != LayerProfileExplicit || evidenceMsgID != msgID { + t.Fatalf("current connection profile = %#v msg:%d", state, evidenceMsgID) + } + if _, _, found := router.NegotiatedSessionLayerEvidence(c.authKeyID, c.sessionID); found { + t.Fatal("outage-local selector entered Router exact-session cache") + } + + if err := plan.rpcTasks[0].run(ctx); err != nil { + t.Fatalf("execute outage-local init: %v", err) + } + deadline := time.Now().Add(2 * time.Second) + for !manager.ReceivesUpdatesForAuthKey(c.authKeyID, c.sessionID) { + if time.Now().After(deadline) { + t.Fatal("successful outage-local init never made current session updates-ready") + } + time.Sleep(time.Millisecond) + } + if _, ok := s.rpcResults.Get(c.authKeyID, c.sessionID, msgID); !ok { + t.Fatal("successful outage-local init did not publish its exact RPC result") + } + if layer, found, err := router.ResolveInheritedAuthKeyLayer(ctx, c.authKeyID); err != nil || found || layer != 0 { + t.Fatalf("outage-local init leaked auth-key Layer default = (%d,%v,%v)", layer, found, err) + } + + // Proactive updates use the current connection's local wire profile even + // though no exact/auth-key durable seed was published. + fanout, err := newLayerUpdatesFanout(testLayerUpdatesValue(123)) + if err != nil { + t.Fatal(err) + } + encoded, err := fanout.prepareForConn(ctx, c) + if err != nil || encoded.layer == nil || encoded.layer.profile != tg.LayerProfile227 { + t.Fatalf("outage-local push profile = encoded:%#v err:%v", encoded, err) + } + + // Simulate a new logical session on the same physical transport. Passing the + // old Conn snapshot must not leak the outage-local selector across sessions. + replacement := &Conn{authKeyID: c.authKeyID, sessionID: c.sessionID + 1, metrics: NopMetrics{}} + if err := s.seedInitialLayerProfile(ctx, replacement, 0, c.LayerProfileState()); err != nil { + t.Fatal(err) + } + if state := replacement.LayerProfileState(); state.Origin != LayerProfileUnknown { + t.Fatalf("new session inherited outage-local profile: %#v", state) + } + naked := exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }) + if _, _, err := s.admitInboundLayerRPCAt(replacement, msgID+4, naked); err == nil { + t.Fatal("new session admitted profile-dependent naked RPC without its own selector") + } +} + +func TestInvariantReplayNeverCachesInternalCanonicalProfile(t *testing.T) { + handler := &replayProfileCaptureLayerRPC{admissionOnlyLayerRPC: newAdmissionOnlyLayerRPC()} + s := New(Options{DC: 2, LayerRPC: handler}) + authKeyID := [8]byte{0x31, 0x06} + const sessionID = int64(3106) + newConn := func() *Conn { + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + return c + } + body := exactLayerRPCBody(t, &tg.AuthBindTempAuthKeyRequest{ + PermAuthKeyID: 1, Nonce: 2, ExpiresAt: 3, EncryptedMessage: []byte("bind"), + }) + + original := newConn() + defer original.Close() + first := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: body}}} + defer first.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), original, first); err != nil { + t.Fatal(err) + } + owner, _ := first.items[0].payload.(*rpcResultOwnerLease) + if owner == nil { + t.Fatal("invariant request did not acquire owner") + } + if profile, ok := s.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, 100); ok || profile != 0 { + t.Fatalf("pending invariant cached profile=(%d,%v)", profile, ok) + } + + replacement := newConn() + defer replacement.Close() + pending := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: body}}} + defer pending.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), replacement, pending); err != nil { + t.Fatal(err) + } + if pending.items[0].kind != inboundItemRewrappedRPC || replacement.LayerProfileState().Origin != LayerProfileUnknown { + t.Fatalf("unknown pending replay = kind:%d state:%#v", pending.items[0].kind, replacement.LayerProfileState()) + } + profiles, known := handler.capturedProfiles() + if len(known) != 1 || known[0] || profiles[0] != 0 { + t.Fatalf("unknown pending replay effective profiles=%v known=%v", profiles, known) + } + + owner.CompleteExecution(true) + s.rpcResults.Put(authKeyID, sessionID, 100, &encodedOutboundMessage{body: []byte{1}, reqMsgID: 100}) + if profile, ok := s.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, 100); ok || profile != 0 { + t.Fatalf("completed invariant cached profile=(%d,%v)", profile, ok) + } + profiled := newConn() + defer profiled.Close() + if err := profiled.seedOrderedLayerProfile(tg.LayerProfile225, 104); err != nil { + t.Fatal(err) + } + completed := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: body}}} + defer completed.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), profiled, completed); err != nil { + t.Fatal(err) + } + if completed.items[0].kind != inboundItemReplayRPC { + t.Fatalf("profiled invariant completed replay kind=%d", completed.items[0].kind) + } + if state, msgID := profiled.layerProfileEvidenceState(); state.Profile != tg.LayerProfile225 || state.Origin != LayerProfileExplicit || msgID != 104 { + t.Fatalf("invariant replay polluted explicit profile = %#v msgID:%d", state, msgID) + } +} + +func TestSameMsgIDNakedReplayUsesWinnerAdmissionProfile(t *testing.T) { + handler := newAdmissionOnlyLayerRPC() + s := New(Options{DC: 2, LayerRPC: handler}) + s.rpcResults = newRPCResultCacheWithFlightLimit(time.Now, 8) + authKeyID := [8]byte{0x22, 0x99} + const sessionID = int64(2299) + body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }) + + item220 := inboundItem{msgID: 100, body: body} + var err error + item220.admitted, item220.method, err = s.decodeInboundLayerRPC( + LayerProfileSnapshot{Profile: tg.LayerProfile225, Origin: LayerProfileInherited}, body, + ) + if err != nil { + t.Fatal(err) + } + item227 := inboundItem{msgID: 100, body: body} + item227.admitted, item227.method, err = s.decodeInboundLayerRPC( + LayerProfileSnapshot{Profile: tg.LayerProfile227, Origin: LayerProfileInherited}, body, + ) + if err != nil { + t.Fatal(err) + } + if item220.admitted.Prepared().Identity() == item227.admitted.Prepared().Identity() { + t.Fatal("test request identity is invariant; need profile-dependent result grammar") + } + c220 := &Conn{authKeyID: authKeyID, sessionID: sessionID} + c227 := &Conn{authKeyID: authKeyID, sessionID: sessionID} + winner, err := s.acquireAdmittedLayerRPC(c220, &item220, nil) + if err != nil || winner.state != rpcResultAcquireOwner || winner.owner == nil { + t.Fatalf("winner = state:%d err:%v", winner.state, err) + } + loser, err := s.acquireAdmittedLayerRPC(c227, &item227, nil) + if err != nil || loser.state != rpcResultAcquirePending || loser.admissionSeq != winner.admissionSeq { + t.Fatalf("loser join = state:%d seq:%d err:%v, winner seq:%d", loser.state, loser.admissionSeq, err, winner.admissionSeq) + } + if got := item227.admitted.Call().Profile(); got != tg.LayerProfile225 { + t.Fatalf("loser re-admitted profile = %d, want winner 225", got) + } + + changed := inboundItem{msgID: 100, body: exactLayerRPCBody(t, &tg.HelpGetNearestDCRequest{})} + changed.admitted, changed.method, err = s.decodeInboundLayerRPC( + LayerProfileSnapshot{Profile: tg.LayerProfile225, Origin: LayerProfileInherited}, changed.body, + ) + if err != nil { + t.Fatal(err) + } + if _, err := s.acquireAdmittedLayerRPC(c220, &changed, nil); !errors.Is(err, ErrRPCResultIdentityMismatch) { + t.Fatalf("same-msg_id changed body err=%v, want identity mismatch", err) + } + winner.owner.Abort() +} + +func TestInheritedLayerServesRepeatedNakedRPCsWithoutSelectorRefresh(t *testing.T) { + for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227} { + t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) { + s := New(Options{DC: 2, LayerRPC: newAdmissionOnlyLayerRPC()}) + c := &Conn{authKeyID: [8]byte{0x71, byte(profile)}, sessionID: int64(profile), metrics: NopMetrics{}} + if err := c.SeedInheritedLayerProfile(profile); err != nil { + t.Fatalf("seed inherited profile: %v", err) + } + initial := c.LayerProfileState() + body := exactOutboundLayerRPCBody(t, profile, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }) + for i := 0; i < 512; i++ { + admitted, method, err := s.admitInboundLayerRPC(c, body) + if err != nil { + t.Fatalf("naked admission %d: %v", i, err) + } + if method != "messages.getHistory" || admitted.Call().Profile() != profile { + t.Fatalf("naked admission %d = method:%q profile:%d", i, method, admitted.Call().Profile()) + } + if _, explicit := admitted.ProfileEvidence(); explicit { + t.Fatalf("naked admission %d fabricated explicit Layer evidence", i) + } + } + if got := c.LayerProfileState(); got != initial || got.Origin != LayerProfileInherited { + t.Fatalf("repeated naked traffic changed inherited profile: got %#v want %#v", got, initial) + } + }) + } +} + +func TestLayerEvidencePublicationBelongsOnlyToFreshFlightOwner(t *testing.T) { + handler := newAdmissionOnlyLayerRPC() + s := New(Options{DC: 2, LayerRPC: handler}) + authKeyID := [8]byte{0x22, 0x98} + const sessionID = int64(2298) + body := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ + Layer: 225, Query: &tg.HelpGetConfigRequest{}, + }) + newConn := func() *Conn { + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + return c + } + firstConn := newConn() + defer firstConn.Close() + first := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: body}}} + defer first.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), firstConn, first); err != nil { + t.Fatal(err) + } + publications := handler.publications() + if len(publications) != 1 || publications[0].admissionSeq == 0 || publications[0].msgID != 100 || publications[0].layer != 225 { + t.Fatalf("fresh owner publications = %#v", publications) + } + if first.items[0].admissionSeq != publications[0].admissionSeq { + t.Fatalf("task seq=%d publication seq=%d", first.items[0].admissionSeq, publications[0].admissionSeq) + } + + replayConn := newConn() + defer replayConn.Close() + replay := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: body}}} + defer replay.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), replayConn, replay); err != nil { + t.Fatal(err) + } + if replay.items[0].kind != inboundItemRewrappedRPC || replay.items[0].admissionSeq != publications[0].admissionSeq { + t.Fatalf("pending replay = kind:%d seq:%d", replay.items[0].kind, replay.items[0].admissionSeq) + } + if got := handler.publications(); len(got) != 1 { + t.Fatalf("pending replay republished Layer evidence: %#v", got) + } +} + +func TestLayerEvidenceNotPublishedWhenBatchFlightCapacityRollsBack(t *testing.T) { + handler := newAdmissionOnlyLayerRPC() + s := New(Options{DC: 2, LayerRPC: handler}) + s.rpcResults = newRPCResultCacheWithFlightLimit(time.Now, 1) + c := &Conn{authKeyID: [8]byte{0x22, 0x97}, sessionID: 2297, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + defer c.Close() + plan := &inboundPlan{items: []inboundItem{ + {kind: inboundItemRPC, msgID: 100, body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 225, Query: &tg.HelpGetConfigRequest{}})}, + {kind: inboundItemRPC, msgID: 104, body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 225, Query: &tg.HelpGetNearestDCRequest{}})}, + }} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatal(err) + } + if got := handler.publications(); len(got) != 0 { + t.Fatalf("capacity-rejected batch published evidence: %#v", got) + } + for index := range plan.items { + if plan.items[index].kind != inboundItemCapacityError { + t.Fatalf("item %d kind=%d, want capacity error", index, plan.items[index].kind) + } + } +} + +func TestOldCompletedLayerRequestCannotRollBackCorrectedSession(t *testing.T) { + handler := newOrderedAdmissionOnlyLayerRPC() + s := New(Options{DC: 2, LayerRPC: handler}) + authKeyID := [8]byte{0x22, 0x96} + const sessionID = int64(2296) + newConn := func() *Conn { + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + return c + } + c := newConn() + defer c.Close() + oldBody := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 225, Query: &tg.HelpGetConfigRequest{}}) + oldPlan := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: oldBody}}} + defer oldPlan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, oldPlan); err != nil { + t.Fatal(err) + } + oldOwner, _ := oldPlan.items[0].payload.(*rpcResultOwnerLease) + if oldOwner == nil { + t.Fatal("old request did not acquire owner") + } + oldOwner.CompleteExecution(true) + s.rpcResults.Put(authKeyID, sessionID, 100, &encodedOutboundMessage{body: []byte{1}, reqMsgID: 100}) + + correctPlan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: 104, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: &tg.HelpGetNearestDCRequest{}}), + }}} + defer correctPlan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, correctPlan); err != nil { + t.Fatal(err) + } + if state, msgID := c.layerProfileEvidenceState(); state.Profile != tg.LayerProfile227 || msgID != 104 { + t.Fatalf("corrected Conn = %#v msgID:%d", state, msgID) + } + + replacement := newConn() + defer replacement.Close() + if err := s.seedInitialLayerProfile(context.Background(), replacement, 0, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + replay := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: oldBody}}} + defer replay.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), replacement, replay); err != nil { + t.Fatal(err) + } + if replay.items[0].kind != inboundItemReplayRPC { + t.Fatalf("old request kind=%d, want completed replay", replay.items[0].kind) + } + if state, msgID := replacement.layerProfileEvidenceState(); state.Profile != tg.LayerProfile227 || msgID != 104 { + t.Fatalf("old replay rolled replacement back = %#v msgID:%d", state, msgID) + } + if layer, msgID, ok := handler.NegotiatedSessionLayerEvidence(authKeyID, sessionID); !ok || layer != 227 || msgID != 104 { + t.Fatalf("old replay rolled registry back = (%d,%d,%v)", layer, msgID, ok) + } +} + +func TestLogicalSessionLayerWatermarkSurvivesResultExpiryAndOldContainer(t *testing.T) { + now := newExpiryTestClock(time.Unix(1_900_000_000, 0)) + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), now) + s := New(Options{DC: 2, LayerRPC: router, Clock: now}) + s.rpcResults = newRPCResultCacheWithFlightLimit(now.Now, 8) + authKeyID := [8]byte{0x22, 0x95} + const sessionID = int64(2295) + newConn := func() *Conn { + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + return c + } + + ids := proto.NewMessageIDGen(now.Now) + oldMsgID := ids.New(proto.MessageFromClient) + correctedMsgID := ids.New(proto.MessageFromClient) + original := newConn() + defer original.Close() + oldBody := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 225, Query: &tg.HelpGetConfigRequest{}}) + oldPlan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: oldMsgID, body: oldBody, + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + defer oldPlan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), original, oldPlan); err != nil { + t.Fatal(err) + } + oldOwner, _ := oldPlan.items[0].payload.(*rpcResultOwnerLease) + if oldOwner == nil || !oldOwner.CompleteExecution(true) { + t.Fatal("old Layer 225 request did not establish a completed owner") + } + s.rpcResults.Put(authKeyID, sessionID, oldMsgID, &encodedOutboundMessage{body: []byte{1}, reqMsgID: oldMsgID}) + + correctPlan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: correctedMsgID, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: &tg.HelpGetNearestDCRequest{}}), + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + defer correctPlan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), original, correctPlan); err != nil { + t.Fatal(err) + } + if layer, msgID, ok := router.NegotiatedSessionLayerEvidence(authKeyID, sessionID); !ok || layer != 227 || msgID != correctedMsgID { + t.Fatalf("corrected logical-session watermark = (%d,%d,%v)", layer, msgID, ok) + } + + // Exact-session evidence and completed results are bounded. The auth-key + // inherited default remains Layer 227, while an old inner request may execute + // request-bound but cannot recreate or roll back the exact-session watermark. + now.Advance(10 * time.Minute) + if _, ok := s.rpcResults.Get(authKeyID, sessionID, oldMsgID); ok { + t.Fatal("old completed result did not expire") + } + + replacement := newConn() + defer replacement.Close() + if err := s.seedInitialLayerProfile(context.Background(), replacement, 0, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + if state, msgID := replacement.layerProfileEvidenceState(); state.Profile != tg.LayerProfile227 || state.Origin != LayerProfileInherited || msgID != 0 { + t.Fatalf("replacement seed = %#v msgID:%d, want inherited Layer 227", state, msgID) + } + freshMsgID := proto.NewMessageIDGen(now.Now).New(proto.MessageFromClient) + nakedBody := exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }) + replayPlan := &inboundPlan{items: []inboundItem{ + { + kind: inboundItemRPC, msgID: oldMsgID, body: oldBody, + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceRequestBound, + }, + { + kind: inboundItemRPC, msgID: freshMsgID, body: nakedBody, + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }, + }} + defer replayPlan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), replacement, replayPlan); err != nil { + t.Fatal(err) + } + if profile, ok := s.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, freshMsgID); !ok || profile != tg.LayerProfile227 { + t.Fatalf("naked request after expired old replay = (%d,%v), want Layer 227", profile, ok) + } + if state, msgID := replacement.layerProfileEvidenceState(); state.Profile != tg.LayerProfile227 || state.Origin != LayerProfileInherited || msgID != 0 { + t.Fatalf("old request-bound flight rolled replacement back = %#v msgID:%d", state, msgID) + } + if _, _, ok := router.NegotiatedSessionLayerEvidence(authKeyID, sessionID); ok { + t.Fatal("request-bound old selector recreated expired exact-session evidence") + } +} + +func TestDurableLayerEvidenceRestoresAcrossEdgeRouterRestart(t *testing.T) { + ctx := context.Background() + now := newExpiryTestClock(time.Now().UTC().Truncate(time.Second).Add(123_456_780 * time.Nanosecond)) + keys := memory.NewAuthKeyStore() + authKeyID := [8]byte{0xd0, 0x22, 0x70} + const sessionID = int64(227_001) + if err := keys.Save(ctx, store.AuthKeyData{ID: authKeyID}); err != nil { + t.Fatal(err) + } + + firstRouter := rpc.New( + rpc.Config{DC: 2}, + rpc.Deps{AuthKeySessionLayers: keys}, + zaptest.NewLogger(t), + now, + ) + firstEdge := New(Options{DC: 2, LayerRPC: firstRouter, Clock: now}) + firstConn := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + firstConn.startInboundRPCScheduler(firstEdge.rpcScheduler, 1, 8, time.Second) + defer firstConn.Close() + msgIDs := proto.NewMessageIDGen(now.Now) + selectorMsgID := msgIDs.New(proto.MessageFromClient) + firstPlan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: selectorMsgID, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ + Layer: 225, + Query: &tg.HelpGetConfigRequest{}, + }), + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + defer firstPlan.close() + if err := firstEdge.prepareInboundLayerRPCBatch(ctx, firstConn, firstPlan); err != nil { + t.Fatal(err) + } + durable, found, err := keys.GetSessionLayer(ctx, authKeyID, sessionID) + if err != nil || !found || durable.Layer != 225 || durable.MessageID != selectorMsgID { + t.Fatalf("durable evidence = (%+v,%v,%v)", durable, found, err) + } + + // Recreate both Router and edge to prove the result is not coming from either + // process-local exact-profile registry or the completed-result cache. + restartedRouter := rpc.New( + rpc.Config{DC: 2}, + rpc.Deps{AuthKeySessionLayers: keys}, + zaptest.NewLogger(t), + now, + ) + restartedEdge := New(Options{DC: 2, LayerRPC: restartedRouter, Clock: now}) + replacement := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + replacement.startInboundRPCScheduler(restartedEdge.rpcScheduler, 1, 8, time.Second) + defer replacement.Close() + if err := restartedEdge.seedInitialLayerProfile(ctx, replacement, 0, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + state, rawLayer, evidenceMsgID := replacement.layerProfileRawEvidenceState() + if state.Profile != tg.LayerProfile225 || state.Origin != LayerProfileExplicit || rawLayer != 225 || evidenceMsgID != selectorMsgID { + t.Fatalf("restart seed = state:%#v raw:%d msg:%d", state, rawLayer, evidenceMsgID) + } + + nakedMsgID := msgIDs.New(proto.MessageFromClient) + nakedPlan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: nakedMsgID, + body: exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }), + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + defer nakedPlan.close() + if err := restartedEdge.prepareInboundLayerRPCBatch(ctx, replacement, nakedPlan); err != nil { + t.Fatal(err) + } + profile, profiled := restartedEdge.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, nakedMsgID) + if len(nakedPlan.rpcTasks) != 1 || !profiled || profile != tg.LayerProfile225 { + t.Fatalf("restart naked admission = tasks:%d item:%+v", len(nakedPlan.rpcTasks), nakedPlan.items[0]) + } +} + +func TestPhysicalConnectionReadsDurableLayerOnceBeforeAdmissionHotPath(t *testing.T) { + ctx := context.Background() + now := newExpiryTestClock(time.Now().UTC().Truncate(time.Second).Add(123_456_780 * time.Nanosecond)) + keys := memory.NewAuthKeyStore() + authKeyID := [8]byte{0xda, 0x22, 0x70} + const sessionID = int64(227_003) + if err := keys.Save(ctx, store.AuthKeyData{ID: authKeyID}); err != nil { + t.Fatal(err) + } + msgIDs := proto.NewMessageIDGen(now.Now) + selectorMsgID := msgIDs.New(proto.MessageFromClient) + if current, applied, err := keys.AdvanceSessionLayer(ctx, authKeyID, sessionID, 225, selectorMsgID); err != nil || !applied || current.Layer != 225 { + t.Fatalf("seed durable evidence = current:%#v applied:%v err:%v", current, applied, err) + } + counted := &countingEdgeSessionLayerStore{AuthKeySessionLayerStore: keys} + router := rpc.New( + rpc.Config{DC: 2}, rpc.Deps{AuthKeySessionLayers: counted}, zaptest.NewLogger(t), now, + ) + edge := New(Options{DC: 2, LayerRPC: router, Clock: now}) + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + c.startInboundRPCScheduler(edge.rpcScheduler, 1, 8, time.Second) + defer c.Close() + if err := edge.seedInitialLayerProfile(ctx, c, 0, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + if got := counted.getCalls.Load(); got != 1 { + t.Fatalf("connection seed GetSessionLayer calls=%d, want 1", got) + } + + body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + for i := 0; i < 64; i++ { + plan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: msgIDs.New(proto.MessageFromClient), body: body, + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + if err := edge.prepareInboundLayerRPCBatch(ctx, c, plan); err != nil { + plan.close() + t.Fatalf("batch %d: %v", i, err) + } + plan.close() + } + if got := counted.getCalls.Load(); got != 1 { + t.Fatalf("64 admission batches raised GetSessionLayer calls to %d, want 1", got) + } +} + +func TestDurableExactSeedOutageKeepsFetchedAuthKeyDefaultServing(t *testing.T) { + handler := &unavailableDurableSeedLayerRPC{admissionOnlyLayerRPC: newAdmissionOnlyLayerRPC()} + edge := New(Options{DC: 2, LayerRPC: handler}) + c := &Conn{ + authKeyID: [8]byte{0xdc, 0x22, 0x70}, sessionID: 227_004, + authKeyExpiresAt: 0, metrics: NopMetrics{}, + } + c.startInboundRPCScheduler(edge.rpcScheduler, 1, 8, time.Second) + defer c.Close() + if err := edge.seedInitialLayerProfile(context.Background(), c, 225, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + initial := c.LayerProfileState() + if initial.Profile != tg.LayerProfile225 || initial.Origin != LayerProfileInherited { + t.Fatalf("outage seed discarded fetched auth-key default: %#v", initial) + } + + msgIDs := proto.NewMessageIDGen(time.Now) + body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }) + for i := 0; i < 64; i++ { + plan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: msgIDs.New(proto.MessageFromClient), body: body, + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + if err := edge.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + plan.close() + t.Fatalf("naked batch %d: %v", i, err) + } + plan.close() + } + if got := c.LayerProfileState(); got != initial { + t.Fatalf("naked traffic changed outage fallback: got %#v want %#v", got, initial) + } + if got := handler.resolveCalls.Load(); got != 1 { + t.Fatalf("durable resolver calls=%d after 64 batches, want only initial seed", got) + } + if got := handler.inheritedCalls.Load(); got != 0 { + t.Fatalf("permanent fetched default unexpectedly queried inherited resolver %d times", got) + } +} + +func TestBoundTempSeedOutageKeepsRawFetchedLayerServingCurrentConn(t *testing.T) { + handler := &unavailableDurableSeedLayerRPC{admissionOnlyLayerRPC: newAdmissionOnlyLayerRPC()} + edge := New(Options{DC: 2, LayerRPC: handler}) + c := &Conn{ + authKeyID: [8]byte{0xdc, 0x22, 0x71}, sessionID: 227_005, + authKeyExpiresAt: 1_900_000_000, metrics: NopMetrics{}, + } + c.startInboundRPCScheduler(edge.rpcScheduler, 1, 8, time.Second) + defer c.Close() + if err := edge.seedInitialLayerProfile(context.Background(), c, 225, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + initial := c.LayerProfileState() + if initial.Profile != tg.LayerProfile225 || initial.Origin != LayerProfileInherited { + t.Fatalf("bound-temp outage discarded same-frame raw default: %#v", initial) + } + + msgIDs := proto.NewMessageIDGen(time.Now) + body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }) + for i := 0; i < 64; i++ { + plan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: msgIDs.New(proto.MessageFromClient), body: body, + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + if err := edge.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + plan.close() + t.Fatalf("naked batch %d: %v", i, err) + } + plan.close() + } + if got := c.LayerProfileState(); got != initial { + t.Fatalf("naked traffic changed bound-temp outage shadow: got %#v want %#v", got, initial) + } + if got := handler.resolveCalls.Load(); got != 1 { + t.Fatalf("exact durable resolver calls=%d after 64 batches, want only initial seed", got) + } + if got := handler.inheritedCalls.Load(); got != 1 { + t.Fatalf("inherited durable resolver calls=%d after 64 batches, want only initial seed", got) + } + if got := handler.publications(); len(got) != 0 { + t.Fatalf("raw outage shadow leaked into shared Layer publication: %#v", got) + } +} + +func TestLiveConnectionKeepsFrozenLayerUntilItsOwnExplicitCorrection(t *testing.T) { + ctx := context.Background() + now := newExpiryTestClock(time.Now().UTC().Truncate(time.Second).Add(123_456_780 * time.Nanosecond)) + keys := memory.NewAuthKeyStore() + authKeyID := [8]byte{0xdb, 0x22, 0x70} + const sessionID = int64(227_002) + if err := keys.Save(ctx, store.AuthKeyData{ID: authKeyID}); err != nil { + t.Fatal(err) + } + routerA := rpc.New( + rpc.Config{DC: 2}, rpc.Deps{AuthKeySessionLayers: keys}, zaptest.NewLogger(t), now, + ) + handlerA := &dispatchProfileCaptureRouter{Router: routerA} + edgeA := New(Options{DC: 2, LayerRPC: handlerA, Clock: now}) + connA := newOutboundTestConn(t, &collectingSessionTransport{}, newOutboundTrackedBudget(1<<20)) + connA.authKeyID = authKeyID + connA.sessionID = sessionID + connA.startInboundRPCScheduler(edgeA.rpcScheduler, 1, 8, time.Second) + msgIDs := proto.NewMessageIDGen(now.Now) + + oldMsgID := msgIDs.New(proto.MessageFromClient) + oldPlan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: oldMsgID, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ + Layer: 225, + Query: &tg.HelpGetConfigRequest{}, + }), + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + if err := edgeA.prepareInboundLayerRPCBatch(ctx, connA, oldPlan); err != nil { + oldPlan.close() + t.Fatal(err) + } + oldPlan.close() + if state, raw, msgID := connA.layerProfileRawEvidenceState(); state.Profile != tg.LayerProfile225 || raw != 225 || msgID != oldMsgID { + t.Fatalf("A initial profile = state:%#v raw:%d msg:%d", state, raw, msgID) + } + + // Another server process advances the same logical-session durable watermark. + // It must not silently rewrite A's already-live physical connection or add a + // PostgreSQL read to every inbound batch. A replacement connection reads the + // durable 227 seed; A keeps serving 225 until its own wire corrects itself. + routerB := rpc.New( + rpc.Config{DC: 2}, rpc.Deps{AuthKeySessionLayers: keys}, zaptest.NewLogger(t), now, + ) + remoteMsgID := msgIDs.New(proto.MessageFromClient) + if layer, msgID, _, err := routerB.AdvanceNegotiatedSessionLayerEvidence(ctx, authKeyID, sessionID, 227, remoteMsgID); err != nil || layer != 227 || msgID != remoteMsgID { + t.Fatalf("B durable advance = (%d,%d,%v)", layer, msgID, err) + } + + oldNakedMsgID := msgIDs.New(proto.MessageFromClient) + oldNakedPlan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: oldNakedMsgID, + body: exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}), + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + if err := edgeA.prepareInboundLayerRPCBatch(ctx, connA, oldNakedPlan); err != nil { + oldNakedPlan.close() + t.Fatal(err) + } + if state, raw, msgID := connA.layerProfileRawEvidenceState(); state.Profile != tg.LayerProfile225 || raw != 225 || msgID != oldMsgID { + oldNakedPlan.close() + t.Fatalf("remote durable advance rewrote live A = state:%#v raw:%d msg:%d", state, raw, msgID) + } + if profile, ok := edgeA.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, oldNakedMsgID); !ok || profile != tg.LayerProfile225 { + oldNakedPlan.close() + t.Fatalf("old naked admission profile = (%d,%v), want 225", profile, ok) + } + oldNakedPlan.close() + + // A naked constructor that requires the newer grammar is rejected with the + // normal correction path; it still must not mutate A's frozen snapshot. + mismatchMsgID := msgIDs.New(proto.MessageFromClient) + mismatchPlan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: mismatchMsgID, + body: exactOutboundLayerRPCBody(t, tg.LayerProfile227, &tg.ChannelsJoinChannelRequest{ + Channel: &tg.InputChannelEmpty{}, + }), + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + if err := edgeA.prepareInboundLayerRPCBatch(ctx, connA, mismatchPlan); err != nil { + mismatchPlan.close() + t.Fatal(err) + } + if mismatchPlan.items[0].kind != inboundItemRPCAdmissionError { + mismatchPlan.close() + t.Fatalf("new naked grammar kind=%d, want admission error", mismatchPlan.items[0].kind) + } + mismatchPlan.close() + if state, raw, msgID := connA.layerProfileRawEvidenceState(); state.Profile != tg.LayerProfile225 || raw != 225 || msgID != oldMsgID { + t.Fatalf("failed naked correction mutated A = state:%#v raw:%d msg:%d", state, raw, msgID) + } + + correctionMsgID := msgIDs.New(proto.MessageFromClient) + correctionPlan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: correctionMsgID, + body: exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ + Layer: 227, Query: &tg.HelpGetConfigRequest{}, + }), + layerProfileEvidenceFreshness: inboundLayerProfileEvidenceFresh, + }}} + defer correctionPlan.close() + if err := edgeA.prepareInboundLayerRPCBatch(ctx, connA, correctionPlan); err != nil { + t.Fatal(err) + } + if state, raw, msgID := connA.layerProfileRawEvidenceState(); state.Profile != tg.LayerProfile227 || raw != 227 || msgID != correctionMsgID { + t.Fatalf("A explicit correction = state:%#v raw:%d msg:%d", state, raw, msgID) + } + if profile, ok := edgeA.rpcResults.ExactAdmissionProfile(authKeyID, sessionID, correctionMsgID); !ok || profile != tg.LayerProfile227 { + t.Fatalf("corrected admission profile = (%d,%v), want 227", profile, ok) + } + if len(correctionPlan.rpcTasks) != 1 { + t.Fatalf("corrected tasks = %d, want 1", len(correctionPlan.rpcTasks)) + } + if err := correctionPlan.rpcTasks[0].run(ctx); err != nil { + t.Fatal(err) + } + requestProfile, resultProfile := handlerA.profiles() + if requestProfile != tg.LayerProfile227 || resultProfile != tg.LayerProfile227 { + t.Fatalf("dispatch/result profiles = %d/%d, want 227/227", requestProfile, resultProfile) + } +} + +func TestPreflightMarksOldContainerInnerLayerEvidenceRequestBound(t *testing.T) { + now := time.Unix(1_900_000_000, 123_456_780) + testClock := newExpiryTestClock(now) + s := New(Options{DC: 2, LayerRPC: newAdmissionOnlyLayerRPC(), Clock: testClock}) + innerMsgID := proto.NewMessageIDGen(func() time.Time { return now.Add(-10 * time.Minute) }).New(proto.MessageFromClient) + outerMsgID := proto.NewMessageIDGen(func() time.Time { return now }).New(proto.MessageFromClient) + body := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ + Layer: 225, Query: &tg.HelpGetConfigRequest{}, + }) + container := exactLayerRPCBody(t, &proto.MessageContainer{Messages: []proto.Message{{ + ID: innerMsgID, SeqNo: 1, Bytes: len(body), Body: body, + }}}) + plan, err := s.preflightInbound(newConnState(), outerMsgID, 2, container) + if err != nil { + t.Fatal(err) + } + defer plan.close() + if len(plan.items) != 1 || plan.items[0].kind != inboundItemRPC { + t.Fatalf("old-inner plan items = %+v", plan.items) + } + if plan.items[0].profileEvidenceFresh() { + t.Fatalf("old inner msg_id %d was classified fresh", innerMsgID) + } +} + +func TestExactSessionProfileSurvivesUnregisterAndSeedsNakedReplay(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + authKeyID := [8]byte{0x22, 0x00, 0x77} + const sessionID = int64(22077) + old := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + + first := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ + Layer: 225, + Query: &tg.HelpGetConfigRequest{}, + }) + if _, _, err := s.admitInboundLayerRPC(old, first); err != nil { + t.Fatalf("initial invokeWithLayer admission: %v", err) + } + + manager := NewSessionManager(zaptest.NewLogger(t)) + manager.SetLifecycleObserver(router) + if err := manager.Register(old); err != nil { + t.Fatal(err) + } + manager.Unregister(old) + + replacement := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + layer, ok := router.NegotiatedSessionLayer(authKeyID, sessionID) + if !ok || layer != 225 { + t.Fatalf("reconnect seed = (%d,%v), want (225,true)", layer, ok) + } + profile, ok := tg.ResolveLayerProfile(layer) + if !ok { + t.Fatalf("resolve retained profile %d", layer) + } + if err := replacement.SeedLayerProfile(profile); err != nil { + t.Fatal(err) + } + naked := exactOutboundLayerRPCBody(t, profile, &tg.HelpGetConfigRequest{}) + admitted, method, err := s.admitInboundLayerRPC(replacement, naked) + if err != nil { + t.Fatalf("same-session naked replay admission: %v", err) + } + if method != "help.getConfig" || admitted.Call().Profile() != tg.LayerProfile225 { + t.Fatalf("naked replay = method:%q profile:%d", method, admitted.Call().Profile()) + } +} + +func TestSameAuthKeyNewSessionRequiresOwnLayerEvidence(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + authKeyID := [8]byte{0x22, 0x70, 0x22, 0x70} + const ( + bobSession = int64(227) + aliceSession = int64(228) + ) + + bobConn := &Conn{authKeyID: authKeyID, sessionID: bobSession, metrics: NopMetrics{}} + bobWrapped := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ + Layer: 227, + Query: &tg.HelpGetConfigRequest{}, + }) + bobRequest, _, err := s.admitInboundLayerRPC(bobConn, bobWrapped) + if err != nil { + t.Fatalf("Bob session layer 227: %v", err) + } + if bobRequest.Call().Profile() != tg.LayerProfile227 { + t.Fatalf("Bob profile = %d, want 227", bobRequest.Call().Profile()) + } + + aliceConn := &Conn{authKeyID: authKeyID, sessionID: aliceSession, metrics: NopMetrics{}} + profileDependent := &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, + Limit: 1, + } + naked228 := exactOutboundLayerRPCBody(t, tg.LayerProfile228, profileDependent) + if _, _, err := s.admitInboundLayerRPC(aliceConn, naked228); err == nil { + t.Fatal("new session inherited another session's Layer for naked application RPC") + } + if profile, ok := aliceConn.LayerProfile(); ok || profile != 0 { + t.Fatalf("rejected new session froze profile = (%d,%v)", profile, ok) + } + if layer, ok := router.NegotiatedSessionLayer(authKeyID, aliceSession); ok || layer != 0 { + t.Fatalf("new session registry inherited layer = (%d,%v)", layer, ok) + } + + aliceWrapped := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ + Layer: 228, + Query: profileDependent, + }) + aliceRequest, _, err := s.admitInboundLayerRPC(aliceConn, aliceWrapped) + if err != nil { + t.Fatalf("Alice session own layer 228 evidence: %v", err) + } + if aliceRequest.Call().Profile() != tg.LayerProfile228 { + t.Fatalf("Alice profile = %d, want 228", aliceRequest.Call().Profile()) + } + if layer, ok := router.NegotiatedSessionLayer(authKeyID, bobSession); !ok || layer != 227 { + t.Fatalf("Bob exact registry changed = (%d,%v), want (227,true)", layer, ok) + } + if layer, ok := router.NegotiatedSessionLayer(authKeyID, aliceSession); !ok || layer != 228 { + t.Fatalf("Alice exact registry = (%d,%v), want (228,true)", layer, ok) + } +} + +func TestExactSessionRegistryAllowsOrderedExplicitCorrection(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + authKeyID := [8]byte{0x22, 0x07, 0x07} + const sessionID = int64(22707) + if err := router.FreezeNegotiatedSessionLayer(authKeyID, sessionID, 225); err != nil { + t.Fatal(err) + } + // A later well-formed invokeWithLayer is authoritative correction, including + // when same-session recovery initially restored an older explicit profile. + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + if err := c.SeedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + wrapped := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{ + Layer: 227, + Query: &tg.HelpGetConfigRequest{}, + }) + request, _, err := s.admitInboundLayerRPC(c, wrapped) + if err != nil { + t.Fatalf("profile correction: %v", err) + } + if request.Call().Profile() != tg.LayerProfile227 { + t.Fatalf("corrected request profile = %d", request.Call().Profile()) + } + if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileExplicit || got.Epoch < 2 { + t.Fatalf("corrected Conn profile = %#v", got) + } + if layer, ok := router.NegotiatedSessionLayer(authKeyID, sessionID); !ok || layer != 227 { + t.Fatalf("corrected registry = (%d,%v)", layer, ok) + } +} + +func TestRestoredExplicitProfileNakedFailureRequestsLayerCorrection(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + c := &Conn{authKeyID: [8]byte{2, 2, 0, 2}, sessionID: 220227, metrics: NopMetrics{}} + if err := c.SeedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + request := &tg.ChannelsJoinChannelRequest{Channel: &tg.InputChannelEmpty{}} + naked227 := exactOutboundLayerRPCBody(t, tg.LayerProfile227, request) + if _, _, err := s.admitInboundLayerRPC(c, naked227); err == nil { + t.Fatal("stale explicit profile admitted newer naked constructor") + } else if rpcErr := layerRPCAdmissionError(err); rpcErr.ErrorCode != 400 || rpcErr.ErrorMessage != "CONNECTION_LAYER_INVALID" { + t.Fatalf("stale explicit profile error = (%d,%q): %v", rpcErr.ErrorCode, rpcErr.ErrorMessage, err) + } + if got := c.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileExplicit { + t.Fatalf("failed naked admission changed profile = %#v", got) + } + + wrapped := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 227, Query: request}) + admitted, _, err := s.admitInboundLayerRPC(c, wrapped) + if err != nil { + t.Fatalf("explicit correction retry: %v", err) + } + if admitted.Call().Profile() != tg.LayerProfile227 { + t.Fatalf("corrected call profile = %d", admitted.Call().Profile()) + } + if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileExplicit || got.Epoch < 2 { + t.Fatalf("corrected profile = %#v", got) + } +} + +func TestUnprofiledInvariantBindKeepsProfileUnknownAndReturnsExactBool(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + authKeyID := [8]byte{0xcd, 0xd4, 0x2a, 0x05} + const sessionID = int64(227220) + c := &Conn{authKeyID: authKeyID, sessionID: sessionID, metrics: NopMetrics{}} + bind := &tg.AuthBindTempAuthKeyRequest{ + PermAuthKeyID: 1, + Nonce: 2, + ExpiresAt: 3, + EncryptedMessage: []byte("bind"), + } + body := exactLayerRPCBody(t, bind) + admitted, method, err := s.admitInboundLayerRPC(c, body) + if err != nil { + t.Fatal(err) + } + if method != "auth.bindTempAuthKey" || !admitted.Call().WireInvariant() { + t.Fatalf("unprofiled admission = method:%q invariant:%v", method, admitted.Call().WireInvariant()) + } + if _, evidence := admitted.ProfileEvidence(); evidence { + t.Fatal("unprofiled invariant bind exposed profile evidence") + } + if profile, ok := c.LayerProfile(); ok || profile != 0 { + t.Fatalf("unprofiled invariant froze Conn profile = (%d,%v)", profile, ok) + } + if layer, ok := router.NegotiatedSessionLayer(authKeyID, sessionID); ok || layer != 0 { + t.Fatalf("unprofiled invariant froze session registry = (%d,%v)", layer, ok) + } + + result, dispatchedMethod, err := router.DispatchAdmitted(context.Background(), authKeyID, sessionID, 1, 1, admitted) + if err != nil { + t.Fatal(err) + } + if dispatchedMethod != method || result == nil || !result.WireInvariant() { + t.Fatalf("bind result = method:%q result:%T invariant:%v", dispatchedMethod, result, result != nil && result.WireInvariant()) + } + exact := &layerRPCResultEncoder{call: result.Prepared().Call(), result: result} + encoded, err := s.encodeRPCResult(c, 100, exact) + if err != nil { + t.Fatalf("encode invariant result on unknown-profile Conn: %v", err) + } + if encoded.layer == nil || !encoded.layer.wireInvariant { + t.Fatalf("encoded bind result lost invariant binding: %#v", encoded.layer) + } + var envelope proto.Result + if err := envelope.Decode(&bin.Buffer{Buf: encoded.body}); err != nil { + t.Fatal(err) + } + for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227} { + inner := bin.Buffer{Buf: append([]byte(nil), envelope.Result...)} + decoded, err := tg.DecodeLayer(profile, tg.LayerClassBoolType(), &inner) + if err != nil { + t.Fatalf("decode invariant Bool at layer %d: %v", profile, err) + } + if _, ok := decoded.(*tg.BoolTrue); !ok || inner.Len() != 0 { + t.Fatalf("layer %d bind result = %T remaining:%d", profile, decoded, inner.Len()) + } + } + + // The same immutable bytes remain legal if profile evidence arrives before + // the queued bind result is physically written. + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + if err := validateOutboundLayerBinding(c, encoded); err != nil { + t.Fatalf("validate invariant result after layer 225 freeze: %v", err) + } + profiledBody := exactOutboundLayerRPCBody(t, tg.LayerProfile225, bind) + profiled, _, err := s.admitInboundLayerRPC(c, profiledBody) + if err != nil { + t.Fatal(err) + } + if profiled.Prepared().Identity() != admitted.Prepared().Identity() { + t.Fatal("invariant bind identity changed after layer 225 freeze") + } +} + +func TestLayerRPCBatchCapacityKeepsExistingPendingReplay(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2, IP: "127.0.0.1", Port: 2398}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + s.rpcResults = newRPCResultCacheWithFlightLimit(time.Now, 1) + c := &Conn{ + authKeyID: [8]byte{7, 7, 1}, + sessionID: 771, + metrics: NopMetrics{}, + } + c.startInboundRPCScheduler(s.rpcScheduler, 1, 8, time.Second) + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + + firstBody := exactLayerRPCBody(t, &tg.HelpGetConfigRequest{}) + identityBuffer := &bin.Buffer{Buf: append([]byte(nil), firstBody...)} + admitted, err := router.AdmitLayer(tg.LayerProfile225, identityBuffer, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + source, err := s.rpcResults.AcquireIdentified(c.authKeyID, c.sessionID, 100, admitted.Prepared().Identity()) + if err != nil || source.state != rpcResultAcquireOwner || source.owner == nil { + t.Fatalf("source owner = state:%d err:%v", source.state, err) + } + + plan := &inboundPlan{items: []inboundItem{ + {kind: inboundItemRPC, msgID: 100, body: firstBody}, + {kind: inboundItemRPC, msgID: 104, body: exactLayerRPCBody(t, &tg.HelpGetNearestDCRequest{})}, + }} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatal(err) + } + if plan.items[0].kind != inboundItemRewrappedRPC || len(plan.rewrapAliases) != 1 { + t.Fatalf("pending replay was canceled: kind=%d aliases=%d", plan.items[0].kind, len(plan.rewrapAliases)) + } + if plan.items[1].kind != inboundItemCapacityError { + t.Fatalf("over-capacity request kind = %d, want capacity error", plan.items[1].kind) + } + if dependency, ok := s.rpcResults.ObserveDependency(c.authKeyID, c.sessionID, 100); !ok || dependency.waiter == nil { + t.Fatalf("source flight was completed or removed by rollback: %#v ok:%v", dependency, ok) + } + if got := c.inflightRPCBytes.Load(); got != 0 || c.rpcReserved != 0 { + t.Fatalf("flight-capacity rollback leaked connection budget bytes:%d tasks:%d", got, c.rpcReserved) + } + s.rpcScheduler.budgetMu.Lock() + globalTasks, globalBytes := s.rpcScheduler.tasks, s.rpcScheduler.bytes + s.rpcScheduler.budgetMu.Unlock() + if globalTasks != 0 || globalBytes != 0 { + t.Fatalf("flight-capacity rollback leaked global budget %d/%d", globalTasks, globalBytes) + } + plan.close() + if !source.owner.Abort() { + t.Fatal("batch cleanup touched the existing source owner") + } +} + +func TestLayerRPCBatchCapacityAbortsRejectedRewrapOwner(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 1) + authKeyID := [8]byte{7, 7, 9} + const ( + sessionID = int64(779) + msgID = int64(900) + ) + identity := rpcFlightExactIdentity(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + claim, err := cache.AcquireIdentified(authKeyID, sessionID, msgID, identity) + if err != nil || claim.state != rpcResultAcquireOwner || claim.owner == nil { + t.Fatalf("rewrap owner = state:%d err:%v", claim.state, err) + } + plan := &inboundPlan{ + items: []inboundItem{{kind: inboundItemRewrappedRPC, msgID: msgID, payload: claim.owner}}, + rewrapAliases: []*rpcRewrapAlias{{ + itemIndex: 0, + newOwner: claim.owner, + }}, + } + plan.rejectNewRPCOwners(nil) + if plan.items[0].kind != inboundItemCapacityError || plan.items[0].payload != nil || len(plan.rewrapAliases) != 0 { + t.Fatalf("rejected rewrap plan = kind:%d payload:%T aliases:%d", plan.items[0].kind, plan.items[0].payload, len(plan.rewrapAliases)) + } + + // The same exact request key must be acquirable immediately. A pending + // result here means the rejected alias leaked its one-shot owner. + reacquired, err := cache.AcquireIdentified(authKeyID, sessionID, msgID, identity) + if err != nil || reacquired.state != rpcResultAcquireOwner || reacquired.owner == nil { + t.Fatalf("reacquire after rejected rewrap = state:%d err:%v", reacquired.state, err) + } + if !reacquired.owner.Abort() { + t.Fatal("reacquired owner cleanup failed") + } +} + +func TestLayerRPCDependencyGateUsesBusinessOutcome(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2, IP: "127.0.0.1", Port: 2398}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + c := &Conn{authKeyID: [8]byte{7, 7, 2}, sessionID: 772, metrics: NopMetrics{}} + + for _, test := range []struct { + name string + dependency int64 + requestID int64 + success bool + }{ + {name: "success", dependency: 200, requestID: 204, success: true}, + {name: "rpc_error", dependency: 208, requestID: 212, success: false}, + } { + t.Run(test.name, func(t *testing.T) { + source, err := s.rpcResults.Acquire(c.authKeyID, c.sessionID, test.dependency) + if err != nil || source.owner == nil { + t.Fatalf("source owner err = %v", err) + } + body := exactLayerRPCBody(t, &tg.InvokeAfterMsgRequest{ + MsgID: test.dependency, + Query: &tg.HelpGetConfigRequest{}, + }) + admitted, err := router.AdmitLayer(tg.LayerProfile225, &bin.Buffer{Buf: body}, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + dependencies := s.layerRPCDependencies(c, test.requestID, admitted) + if dependencies.failed || len(dependencies.waiters) != 1 { + t.Fatalf("dependencies before completion = %+v", dependencies) + } + gate := newLayerRPCExecutionGate(c, dependencies) + if gate == nil || gate.runnable() { + t.Fatal("dependency gate was runnable before business completion") + } + if !source.owner.CompleteExecution(test.success) { + t.Fatal("source business completion lost") + } + if !gate.runnable() || gate.success() != test.success { + t.Fatalf("resolved gate = runnable:%v success:%v, want success:%v", gate.runnable(), gate.success(), test.success) + } + if !source.owner.Abort() { + t.Fatal("source cleanup abort lost") + } + }) + } + + missingBody := exactLayerRPCBody(t, &tg.InvokeAfterMsgRequest{ + MsgID: 300, + Query: &tg.HelpGetConfigRequest{}, + }) + missing, err := router.AdmitLayer(tg.LayerProfile225, &bin.Buffer{Buf: missingBody}, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + dependencies := s.layerRPCDependencies(c, 304, missing) + gate := newLayerRPCExecutionGate(c, dependencies) + if !dependencies.failed || gate == nil || !gate.runnable() || gate.success() { + t.Fatalf("missing dependency gate = deps:%+v runnable:%v success:%v", dependencies, gate.runnable(), gate.success()) + } +} + +func TestLayerRPCTimeoutMessageDistinguishesDependencyWait(t *testing.T) { + gate := newInboundRPCGate(1, nil) + gate.resolve(true) + if got := layerRPCTimeoutMessage(gate); got != "MSG_WAIT_TIMEOUT" { + t.Fatalf("blocked gate timeout = %q", got) + } + gate.resolve(true) + if got := layerRPCTimeoutMessage(gate); got != "RPC_TIMEOUT" { + t.Fatalf("resolved gate timeout = %q", got) + } + if got := layerRPCTimeoutMessage(nil); got != "RPC_TIMEOUT" { + t.Fatalf("ordinary timeout = %q", got) + } +} + +func TestLayerRPCAdmissionErrorUsesTypedUnknownClassification(t *testing.T) { + err := &tg.LayerCodecError{ + Operation: "admit RPC request", + Profile: tg.LayerProfile225, + WireID: 0x01020304, + Reason: "wording may change", + Cause: tg.ErrLayerUnknownRPCMethod, + } + rpcErr := layerRPCAdmissionError(err) + if rpcErr.ErrorCode != 501 || rpcErr.ErrorMessage != "NOT_IMPLEMENTED" { + t.Fatalf("unknown admission error = (%d,%q)", rpcErr.ErrorCode, rpcErr.ErrorMessage) + } +} + +func TestLayerRPCAdmissionErrorDistinguishesUnknownAndInheritedProfiles(t *testing.T) { + profileRequired := &tg.LayerCodecError{Operation: "admit", Cause: tg.ErrLayerProfileRequired} + if rpcErr := layerRPCAdmissionError(profileRequired); rpcErr.ErrorCode != 400 || rpcErr.ErrorMessage != "CONNECTION_NOT_INITED" { + t.Fatalf("unknown profile admission = (%d,%q)", rpcErr.ErrorCode, rpcErr.ErrorMessage) + } + inherited := fmt.Errorf("%w: %w", errDefaultLayerAdmission, tg.ErrLayerUnknownRPCMethod) + if rpcErr := layerRPCAdmissionError(inherited); rpcErr.ErrorCode != 400 || rpcErr.ErrorMessage != "CONNECTION_LAYER_INVALID" { + t.Fatalf("inherited profile admission = (%d,%q)", rpcErr.ErrorCode, rpcErr.ErrorMessage) + } +} diff --git a/internal/mtprotoedge/inbound_preflight.go b/internal/mtprotoedge/inbound_preflight.go index 66188a0d..3fafe7c2 100644 --- a/internal/mtprotoedge/inbound_preflight.go +++ b/internal/mtprotoedge/inbound_preflight.go @@ -10,9 +10,10 @@ import ( "go.uber.org/zap" - "github.com/gotd/td/bin" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) type inboundItemKind uint8 @@ -34,6 +35,7 @@ const ( inboundItemDestroyAuthKey inboundItemRPC inboundItemCapacityError + inboundItemRPCAdmissionError // inboundItemRewrappedRPC is an initConnection retry whose exact inner TL // request is already executing (or completed) under the client's old msg_id. // It never dispatches business code a second time. @@ -48,13 +50,33 @@ const ( ) type inboundItem struct { - kind inboundItemKind - msgID int64 - seqNo int32 - typeID uint32 - content bool - body []byte - payload any + kind inboundItemKind + msgID int64 + admissionSeq uint64 + seqNo int32 + typeID uint32 + content bool + body []byte + payload any + admitted tg.LayerRequest + method string + replayAfterSuccessfulDelivery func() error + layerProfileEvidenceFreshness inboundLayerProfileEvidenceFreshness +} + +type inboundLayerProfileEvidenceFreshness uint8 + +const ( + // Unspecified is retained for focused force-style unit tests which construct + // inboundItem directly, outside MTProto envelope preflight. Production items + // are always classified from the frame's one clock sample. + inboundLayerProfileEvidenceFreshnessUnspecified inboundLayerProfileEvidenceFreshness = iota + inboundLayerProfileEvidenceFresh + inboundLayerProfileEvidenceRequestBound +) + +func (i inboundItem) profileEvidenceFresh() bool { + return i.layerProfileEvidenceFreshness != inboundLayerProfileEvidenceRequestBound } type stagedClientMessage struct { @@ -75,13 +97,23 @@ type inboundPlan struct { rpcTasks []inboundRPC rpcOwners []*rpcResultOwnerLease rewrapAliases []*rpcRewrapAlias - rewrapIndices []int } func (p *inboundPlan) close() { if p == nil { return } + // Drop exact typed request graphs and uncommitted task closures before their + // materialization reservation becomes reusable. Otherwise an abort could + // advertise the same bytes to another connection while this plan still kept + // the old graph reachable until its caller returned. + for i := range p.items { + p.items[i].admitted = tg.LayerRequest{} + } + for i := range p.rpcTasks { + p.rpcTasks[i] = inboundRPC{} + } + p.rpcTasks = nil if p.rpcReservation != nil { p.rpcReservation.abort() p.rpcReservation = nil @@ -97,7 +129,6 @@ func (p *inboundPlan) close() { } } p.rewrapAliases = nil - p.rewrapIndices = nil for i := len(p.releases) - 1; i >= 0; i-- { p.releases[i]() } @@ -117,15 +148,47 @@ func (p *inboundPlan) commitRewrapAliases(s *Server) error { } } p.rewrapAliases = nil - p.rewrapIndices = nil return err } } p.rewrapAliases = nil - p.rewrapIndices = nil return nil } +// rejectNewRPCOwners turns only ownership acquired by this batch into bounded +// capacity responses. Existing completed replays and pending joins remain +// active: canceling them would either lose a response or publish into another +// request's flight. +func (p *inboundPlan) rejectNewRPCOwners(indices []int) { + if p == nil { + return + } + for _, index := range indices { + if index >= 0 && index < len(p.items) { + p.items[index].kind = inboundItemCapacityError + } + } + kept := p.rewrapAliases[:0] + for _, alias := range p.rewrapAliases { + if alias == nil || alias.newOwner == nil { + kept = append(kept, alias) + continue + } + if alias.itemIndex >= 0 && alias.itemIndex < len(p.items) { + p.items[alias.itemIndex].kind = inboundItemCapacityError + p.items[alias.itemIndex].payload = nil + } + alias.releaseCandidate() + // This owner was acquired by the rejected batch and is not present in + // plan.rpcOwners because it belonged to a rewrap alias. Abort it here + // before dropping the alias, otherwise the exact flight remains pending + // forever with no task or publisher able to complete it. + alias.newOwner.Abort() + alias.newOwner = nil + } + p.rewrapAliases = kept +} + func (p *inboundPlan) commitRPCBatch() error { if p == nil || p.rpcReservation == nil { return nil @@ -405,6 +468,14 @@ func (s *Server) walkInbound( if err != nil { return err } + if validateInboundMessageID(budget.now, msgID, false) == 0 { + item.layerProfileEvidenceFreshness = inboundLayerProfileEvidenceFresh + } else { + // Inner container messages deliberately bypass the wall-clock rejection + // above, but old/future ids are request-bound and cannot publish mutable + // Layer/init/readiness/auth-bind evidence. + item.layerProfileEvidenceFreshness = inboundLayerProfileEvidenceRequestBound + } plan.items = append(plan.items, item) if content { plan.ackIDs = append(plan.ackIDs, msgID) @@ -413,7 +484,7 @@ func (s *Server) walkInbound( } func validateInboundMessageID(now time.Time, msgID int64, insideContainer bool) int { - if msgID == 0 || proto.MessageID(msgID).Type() != proto.MessageFromClient { + if !validClientMessageIDBits(msgID) { return badMsgIDInvalidBits } // A container's outer envelope supplies the wall-clock admission boundary for @@ -432,6 +503,11 @@ func validateInboundMessageID(now time.Time, msgID int64, insideContainer bool) return 0 } +func validClientMessageIDBits(msgID int64) bool { + return msgID > 0 && uint32(msgID) != 0 && + proto.MessageID(msgID).Type() == proto.MessageFromClient +} + func appendInboundDuplicate(plan *inboundPlan, msgID int64, seqNo int32, typeID uint32, record clientMsgRecord) error { plan.includeLogicalID(msgID) kind := inboundItemDuplicate @@ -653,6 +729,9 @@ func preflightInboundItem(msgID int64, seqNo int32, typeID uint32, content bool, // into one consistent terminal FLOOD_WAIT result per uncached RPC; no business // handler from the batch is allowed to start in that case. func (s *Server) prepareInboundRPCBatch(ctx context.Context, c *Conn, plan *inboundPlan) error { + if s.layerRPC != nil { + return s.prepareInboundLayerRPCBatch(ctx, c, plan) + } // Keep service-only frames (ping/ack/http_wait) allocation-free here. These // collections are needed only after the first real API RPC acquires ownership. var indices []int @@ -676,8 +755,11 @@ func (s *Server) prepareInboundRPCBatch(ctx context.Context, c *Conn, plan *inbo method := s.typeName(item.typeID) init, isInitRewrap := decodeRPCRewrapInit(item.body) if isInitRewrap { - firstInit := !c.rpcRewrapInitialized.Swap(true) - c.SetClientLayer(init.layer) + firstInit := false + if item.profileEvidenceFresh() { + firstInit = !c.rpcRewrapInitialized.Swap(true) + c.setLegacyClientLayer(init.layer) + } if candidate := s.rpcRewrap.claim(c, init.inner); candidate != nil { claim, err := s.rpcResults.Acquire(c.authKeyID, c.sessionID, item.msgID) if errors.Is(err, ErrRPCResultFlightCapacity) { @@ -701,10 +783,9 @@ func (s *Server) prepareInboundRPCBatch(ctx context.Context, c *Conn, plan *inbo item.kind = inboundItemRewrappedRPC item.payload = claim.waiter plan.rewrapAliases = append(plan.rewrapAliases, &rpcRewrapAlias{ - conn: c, newReqID: item.msgID, method: candidate.method, + conn: c, itemIndex: i, newReqID: item.msgID, method: candidate.method, oldWaiter: claim.waiter, observeInit: firstInit, init: init, }) - plan.rewrapIndices = append(plan.rewrapIndices, i) case rpcResultAcquireOwner: if ownersInPlan == nil { ownersInPlan = make(map[int64]*rpcResultOwnerLease) @@ -713,13 +794,12 @@ func (s *Server) prepareInboundRPCBatch(ctx context.Context, c *Conn, plan *inbo item.kind = inboundItemRewrappedRPC item.payload = claim.owner plan.rewrapAliases = append(plan.rewrapAliases, &rpcRewrapAlias{ - conn: c, newReqID: item.msgID, method: candidate.method, + conn: c, itemIndex: i, newReqID: item.msgID, method: candidate.method, oldWaiter: candidate.waiter, newOwner: claim.owner, sourceConn: candidate.source, sourceOwner: candidate.owner, observeInit: firstInit, init: init, candidate: candidate, registry: s.rpcRewrap, }) - plan.rewrapIndices = append(plan.rewrapIndices, i) default: s.rpcRewrap.release(candidate) return ErrRPCResultFlightInvalid @@ -732,7 +812,7 @@ func (s *Server) prepareInboundRPCBatch(ctx context.Context, c *Conn, plan *inbo zap.String("auth_key_id", c.authKeyHex), zap.Int64("session_id", c.sessionID)) continue } - } else if c.rpcRewrapInitialized.Load() && !clearedPostInitCandidates { + } else if item.profileEvidenceFresh() && c.rpcRewrapInitialized.Load() && !clearedPostInitCandidates { // A naked request after this connection has observed initConnection is // event-level proof that the client finished moving its old running set. // Retire any unmatched candidates without a timer. @@ -773,7 +853,7 @@ func (s *Server) prepareInboundRPCBatch(ctx context.Context, c *Conn, plan *inbo item.kind = inboundItemRewrappedRPC item.payload = claim.waiter plan.rewrapAliases = append(plan.rewrapAliases, &rpcRewrapAlias{ - conn: c, newReqID: item.msgID, method: method, oldWaiter: claim.waiter, + conn: c, itemIndex: i, newReqID: item.msgID, method: method, oldWaiter: claim.waiter, }) } case rpcResultAcquireOwner: @@ -807,17 +887,7 @@ func (s *Server) prepareInboundRPCBatch(ctx context.Context, c *Conn, plan *inbo for _, index := range indices { plan.items[index].kind = inboundItemCapacityError } - for _, index := range plan.rewrapIndices { - plan.items[index].kind = inboundItemCapacityError - } - for _, alias := range plan.rewrapAliases { - alias.releaseCandidate() - if alias.newOwner != nil { - alias.newOwner.Abort() - } - } - plan.rewrapAliases = nil - plan.rewrapIndices = nil + plan.rejectNewRPCOwners(indices) return nil } if len(specs) == 0 { @@ -830,17 +900,7 @@ func (s *Server) prepareInboundRPCBatch(ctx context.Context, c *Conn, plan *inbo for _, index := range indices { plan.items[index].kind = inboundItemCapacityError } - for _, index := range plan.rewrapIndices { - plan.items[index].kind = inboundItemCapacityError - } - for _, alias := range plan.rewrapAliases { - alias.releaseCandidate() - if alias.newOwner != nil { - alias.newOwner.Abort() - } - } - plan.rewrapAliases = nil - plan.rewrapIndices = nil + plan.rejectNewRPCOwners(indices) return nil } return err @@ -874,7 +934,7 @@ func (s *Server) executeInboundPlan(ctx context.Context, cs *connState, c *Conn, } case inboundItemReplayRPC: if encoded, _ := item.payload.(*encodedOutboundMessage); encoded != nil { - if err := s.sendCachedRPCResult(ctx, c, encoded); err != nil { + if err := s.sendCachedRPCResultWithHook(ctx, c, encoded, item.replayAfterSuccessfulDelivery); err != nil { return err } } else if err := s.replayRPCResultByRequest(ctx, c, item.msgID); err != nil { @@ -942,13 +1002,22 @@ func (s *Server) executeInboundPlan(ctx context.Context, cs *connState, c *Conn, s.log.Debug("Received destroy_auth_key", zap.String("auth_key_id", c.authKeyHex)) if err := s.authKeys.Delete(ctx, c.authKeyID); err != nil { s.log.Warn("Delete auth key failed", zap.String("auth_key_id", c.authKeyHex), zap.Error(err)) - return c.SendRequiredControl(ctx, proto.MessageServerResponse, &destroyAuthKeyFail{}) + return c.SendRequiredControl(ctx, proto.MessageServerResponse, &destroyAuthKeyRPCResult{ + RequestMessageID: item.msgID, + ResultTypeID: destroyAuthKeyFailTypeID, + }) + } + if registry, ok := s.layerRPC.(LayerRPCSessionProfileRegistry); ok { + registry.ForgetNegotiatedAuthKey(c.authKeyID) } // Fence every other active/claiming generation before acknowledging the // deletion. The exact requester remains writable only long enough to put the - // required destroy_auth_key_ok frame on the wire. + // request-correlated rpc_result(destroy_auth_key_ok) frame on the wire. s.conns.CloseSessionsForRawAuthKeyExceptConn(c.authKeyID, c) - if err := c.SendRequiredControl(ctx, proto.MessageServerResponse, &destroyAuthKeyOk{}); err != nil { + if err := c.SendRequiredControl(ctx, proto.MessageServerResponse, &destroyAuthKeyRPCResult{ + RequestMessageID: item.msgID, + ResultTypeID: destroyAuthKeyOkTypeID, + }); err != nil { return err } c.beginTerminalShutdown() @@ -959,12 +1028,23 @@ func (s *Server) executeInboundPlan(ctx context.Context, cs *connState, c *Conn, // execution begins; commitRPCBatch publishes them after all protocol barriers. continue case inboundItemCapacityError: + if owner, _ := item.payload.(*rpcResultOwnerLease); owner != nil { + owner.CompleteExecution(false) + } if err := s.sendResult(ctx, c, item.msgID, &mt.RPCError{ ErrorCode: 420, ErrorMessage: "FLOOD_WAIT_1", }); err != nil { return err } + case inboundItemRPCAdmissionError: + rpcErr, _ := item.payload.(*mt.RPCError) + if rpcErr == nil { + rpcErr = &mt.RPCError{ErrorCode: 400, ErrorMessage: "INPUT_REQUEST_INVALID"} + } + if err := s.sendResult(ctx, c, item.msgID, rpcErr); err != nil { + return err + } default: return fmt.Errorf("unknown inbound item kind %d", item.kind) } diff --git a/internal/mtprotoedge/inbound_preflight_bench_test.go b/internal/mtprotoedge/inbound_preflight_bench_test.go index 5cd78686..ac2c72ed 100644 --- a/internal/mtprotoedge/inbound_preflight_bench_test.go +++ b/internal/mtprotoedge/inbound_preflight_bench_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) func BenchmarkInboundPlan32RPCContainer(b *testing.B) { diff --git a/internal/mtprotoedge/inbound_rpc.go b/internal/mtprotoedge/inbound_rpc.go index d7cb4272..f1e2abeb 100644 --- a/internal/mtprotoedge/inbound_rpc.go +++ b/internal/mtprotoedge/inbound_rpc.go @@ -12,8 +12,10 @@ import ( // ErrInboundRPCQueueFull 表示 inbound RPC 已触达单连接或进程级预算。 var ErrInboundRPCQueueFull = errors.New("inbound rpc queue full") -// maxInflightRPCBytes 是单连接所有已预留、排队和执行中 RPC body 的总字节上限。 -// 进程级预算在 Copy 前先兜底;这里再隔离单个连接,避免一个客户端独占全局内存。 +// maxInflightRPCBytes 是单连接所有已预留、排队和执行中 RPC 的内存 charge 上限。 +// legacy 路径的 charge 等于 copied body;exact 路径在 typed decode 前按 wire 大小、 +// 生成对象/向量/interface/string/bytes 放大保守计费。它不是可接收 wire bytes 上限。 +// 进程级预算先兜底;这里再隔离单个连接,避免一个客户端独占全局内存。 const maxInflightRPCBytes = 32 << 20 // 32 MiB // rpcCloseWaitTimeout 是连接/Server 关闭时等待在途 RPC 或共享 worker 退出的上限。 @@ -37,8 +39,49 @@ type inboundRPC struct { release func() budget *inboundRPCGlobalReservation ticket *inboundRPCTicket + gate *inboundRPCGate } +// inboundRPCGate keeps dependency waits out of the shared worker pool. A +// gated task remains within the ordinary queue/task/byte budgets, but workers +// skip it until every prerequisite publishes its terminal execution outcome. +type inboundRPCGate struct { + remaining atomic.Int32 + failed atomic.Bool + ready atomic.Bool + wake func() +} + +func newInboundRPCGate(prerequisites int, wake func()) *inboundRPCGate { + if prerequisites < 0 { + prerequisites = 0 + } + g := &inboundRPCGate{wake: wake} + // One sentinel keeps the gate closed while subscribers are installed; the + // caller resolves it after registration is complete. + g.remaining.Store(int32(prerequisites + 1)) + return g +} + +func (g *inboundRPCGate) resolve(success bool) { + if g == nil { + return + } + if !success { + g.failed.Store(true) + } + remaining := g.remaining.Add(-1) + if remaining < 0 { + panic("mtproto inbound RPC gate counter underflow") + } + if remaining == 0 && g.ready.CompareAndSwap(false, true) && g.wake != nil { + g.wake() + } +} + +func (g *inboundRPCGate) runnable() bool { return g == nil || g.ready.Load() } +func (g *inboundRPCGate) success() bool { return g == nil || (g.ready.Load() && !g.failed.Load()) } + type inboundRPCTicket struct { onTimeout func() } @@ -78,7 +121,8 @@ type inboundRPCGlobalReservation struct { } // inboundRPCSpec 是 container preflight 与 RPC scheduler 之间的有界 admission 描述。 -// method 仅用于 metrics,size 是在 Copy 之前必须预留的 request body 字节数。 +// method 仅用于 metrics;size 是 materialization charge。legacy 路径等于 Copy 前 +// request body 字节数,exact 路径是 typed decode 前计算的保守内存上界。 type inboundRPCSpec struct { method string size int @@ -102,6 +146,7 @@ type inboundRPCBatchReservation struct { } var errInboundRPCBatchTaskCount = errors.New("inbound rpc batch task count mismatch") +var errInboundRPCBatchSelection = errors.New("inbound rpc batch selection is invalid") func newInboundRPCScheduler(workers, maxTasks int, maxBytes int64) *inboundRPCScheduler { if workers <= 0 { @@ -499,6 +544,76 @@ func (c *Conn) dropInboundRPCSpecs(specs []inboundRPCSpec, reason string) { } } +// retain keeps a subset of a provisional batch on the original connection and +// global reservations. Exact-layer admission uses this after typed decode has +// classified completed replays, pending joins, admission errors, and fresh +// owners. A retained fresh owner therefore never passes through a release then +// reacquire window where another connection could consume its memory/task +// budget. Entries not retained are returned immediately as one batch. +// +// indices are reservation-entry indices, must be strictly increasing, and have +// a one-to-one correspondence with specs. The original conservative byte +// charge is intentionally retained; a typed request remains reachable from its +// scheduler task until completion, so shrinking it to the wire size would make +// the materialized graph unaccounted. +func (r *inboundRPCBatchReservation) retain(indices []int, specs []inboundRPCSpec) error { + if r == nil || len(indices) != len(specs) || len(indices) > len(r.entries) { + return errInboundRPCBatchSelection + } + retained := make([]inboundRPCBatchEntry, len(indices)) + removed := make([]*inboundRPCGlobalReservation, 0, len(r.entries)-len(indices)) + var ( + previous = -1 + retainedSize int64 + removedSize int64 + ) + selected := 0 + for output, index := range indices { + if index <= previous || index < 0 || index >= len(r.entries) { + return errInboundRPCBatchSelection + } + previous = index + for selected < index { + entry := r.entries[selected] + removed = append(removed, entry.global) + removedSize += int64(entry.size) + selected++ + } + entry := r.entries[index] + // The caller may improve the provisional metric label but may not increase + // or replace its byte charge after materialization has started. + if specs[output].size > entry.size { + return errInboundRPCBatchSelection + } + entry.method = specs[output].method + retained[output] = entry + retainedSize += int64(entry.size) + selected = index + 1 + } + for selected < len(r.entries) { + entry := r.entries[selected] + removed = append(removed, entry.global) + removedSize += int64(entry.size) + selected++ + } + + c := r.conn + c.rpcMu.Lock() + c.rpcReserved -= len(removed) + c.inflightRPCBytes.Add(-removedSize) + r.entries = retained + r.totalSize = retainedSize + c.rpcMu.Unlock() + releaseInboundRPCGlobalBatch(removed) + + if len(retained) == 0 { + // Finish the one reservation waiter as part of the same ownership + // transition. abort sees an empty batch and is therefore accounting-only. + r.abort() + } + return nil +} + // commit 在一次 rpcMu 临界区内把整批 task append 到队列并立即发布 ready token。 // 协议 barrier 必须在调用 commit 前完成;延迟发布 token 无法阻止已有 worker // 从同一连接队列取走新任务,因此不提供虚假的 deferred-schedule 模式。 @@ -581,7 +696,7 @@ func (r *inboundRPCBatchReservation) commit(tasks []inboundRPC) (result error) { firstQueueLen = len(c.rpcQueue) + 1 c.rpcQueue = append(c.rpcQueue, prepared...) queueCap = c.rpcQueueSize - if len(prepared) > 0 && c.rpcRunning < c.rpcMaxInflight && !c.rpcReady { + if c.rpcRunning < c.rpcMaxInflight && !c.rpcReady && c.hasRunnableInboundRPCLocked() { c.rpcReady = true reschedule = true } @@ -636,21 +751,121 @@ func (c *Conn) takeInboundRPC() (task inboundRPC, ok, reschedule bool) { if c.rpcClosed || len(c.rpcQueue) == 0 || c.rpcRunning >= c.rpcMaxInflight { return inboundRPC{}, false, false } - task = c.rpcQueue[0] - c.rpcQueue[0] = inboundRPC{} - c.rpcQueue = c.rpcQueue[1:] + index := -1 + for i := range c.rpcQueue { + if c.rpcQueue[i].gate.runnable() { + index = i + break + } + } + if index < 0 { + return inboundRPC{}, false, false + } + task = c.rpcQueue[index] + if index == 0 { + // The overwhelmingly common FIFO path advances the slice head in O(1). + // Clear the departed element first so its request graph and closures are + // not retained by the shared backing array. + c.rpcQueue[0] = inboundRPC{} + c.rpcQueue = c.rpcQueue[1:] + } else { + copy(c.rpcQueue[index:], c.rpcQueue[index+1:]) + last := len(c.rpcQueue) - 1 + c.rpcQueue[last] = inboundRPC{} + c.rpcQueue = c.rpcQueue[:last] + } if len(c.rpcQueue) == 0 { c.rpcQueue = nil } c.rpcRunning++ c.rpcWG.Add(1) - if len(c.rpcQueue) > 0 && c.rpcRunning < c.rpcMaxInflight { + if c.rpcRunning < c.rpcMaxInflight && c.hasRunnableInboundRPCLocked() { c.rpcReady = true reschedule = true } return task, true, reschedule } +func (c *Conn) hasRunnableInboundRPCLocked() bool { + if c.rpcReplayRestores > 0 { + return false + } + for i := range c.rpcQueue { + if c.rpcQueue[i].gate.runnable() { + return true + } + } + return false +} + +// beginRPCReplayRestore installs a scheduler-level barrier without occupying a +// global RPC worker. The returned idempotent completion function wakes queued +// work only after the last overlapping restore has finished. +func (c *Conn) beginRPCReplayRestore() func() { + if c == nil { + return func() {} + } + active := false + unschedule := false + c.rpcMu.Lock() + if !c.rpcClosed && !c.isRetired() { + c.rpcReplayRestores++ + active = true + if c.rpcReady { + c.rpcReady = false + unschedule = true + } + } + c.rpcMu.Unlock() + if unschedule && c.rpcScheduler != nil { + c.rpcScheduler.unschedule(c) + } + + var once sync.Once + return func() { + once.Do(func() { + if !active { + return + } + reschedule := false + c.rpcMu.Lock() + c.rpcReplayRestores-- + if c.rpcReplayRestores < 0 { + c.rpcMu.Unlock() + panic("mtproto inbound RPC replay restore barrier underflow") + } + if c.rpcReplayRestores == 0 && !c.rpcClosed && c.rpcRunning < c.rpcMaxInflight && + !c.rpcReady && c.hasRunnableInboundRPCLocked() { + c.rpcReady = true + reschedule = true + } + c.rpcMu.Unlock() + if reschedule && c.rpcScheduler != nil { + c.rpcScheduler.schedule(c) + } + }) + } +} + +// wakeInboundRPC is safe from a flight completion callback. It does no work +// while the gate's task has not been committed yet; commit performs the same +// runnable scan and publishes the initial scheduler token. +func (c *Conn) wakeInboundRPC() { + if c == nil || c.rpcScheduler == nil { + return + } + reschedule := false + c.rpcMu.Lock() + if !c.rpcClosed && c.rpcRunning < c.rpcMaxInflight && !c.rpcReady && c.hasRunnableInboundRPCLocked() { + c.rpcReady = true + reschedule = true + } + c.rpcMu.Unlock() + if reschedule { + c.rpcScheduler.schedule(c) + } +} + func (c *Conn) runInboundRPC(task inboundRPC) { defer c.finishInboundRPC(task) @@ -681,7 +896,7 @@ func (c *Conn) finishInboundRPC(task inboundRPC) { c.rpcMu.Lock() c.rpcRunning-- c.inflightRPCBytes.Add(-int64(task.size)) - if !c.rpcClosed && len(c.rpcQueue) > 0 && c.rpcRunning < c.rpcMaxInflight && !c.rpcReady { + if !c.rpcClosed && c.rpcRunning < c.rpcMaxInflight && !c.rpcReady && c.hasRunnableInboundRPCLocked() { c.rpcReady = true reschedule = true } diff --git a/internal/mtprotoedge/inbound_rpc_test.go b/internal/mtprotoedge/inbound_rpc_test.go index e58b8f1e..e554e18a 100644 --- a/internal/mtprotoedge/inbound_rpc_test.go +++ b/internal/mtprotoedge/inbound_rpc_test.go @@ -108,6 +108,57 @@ func TestInboundRPCSchedulerBoundsConcurrentWork(t *testing.T) { } } +func TestInboundRPCSchedulerSkipsUnresolvedDependencyGate(t *testing.T) { + scheduler := newInboundRPCScheduler(1, 8, 1<<20) + scheduler.start() + c := newInboundTestConn(scheduler, 1, 4, time.Second) + defer func() { + c.closeInboundRPCScheduler() + scheduler.stop(time.Second) + }() + + blockedRan := make(chan struct{}, 1) + independentRan := make(chan struct{}, 1) + gate := newInboundRPCGate(1, c.wakeInboundRPC) + gate.resolve(true) // subscriber-installation sentinel; one dependency remains. + if err := c.enqueueInboundRPC(context.Background(), inboundRPC{ + method: "invokeAfter", + gate: gate, + run: func(context.Context) error { + blockedRan <- struct{}{} + return nil + }, + }); err != nil { + t.Fatal(err) + } + if err := c.enqueueInboundRPC(context.Background(), inboundRPC{ + method: "independent", + run: func(context.Context) error { + independentRan <- struct{}{} + return nil + }, + }); err != nil { + t.Fatal(err) + } + + select { + case <-independentRan: + case <-time.After(time.Second): + t.Fatal("independent task was starved behind unresolved invokeAfter") + } + select { + case <-blockedRan: + t.Fatal("invokeAfter ran before its dependency completed") + default: + } + gate.resolve(true) + select { + case <-blockedRan: + case <-time.After(time.Second): + t.Fatal("resolved invokeAfter was not rescheduled") + } +} + func TestInboundRPCSchedulerFairAcrossConnections(t *testing.T) { scheduler := newInboundRPCScheduler(1, 16, 1<<20) c1 := newInboundTestConn(scheduler, 1, 4, time.Second) @@ -491,3 +542,45 @@ func TestInboundRPCCloseDrainsQueueAndReturnsBudgets(t *testing.T) { t.Fatalf("connection inflight bytes after close = %d, want zero", got) } } + +func TestInboundRPCReplayRestoreBarrierKeepsFollowingTaskOffWorkers(t *testing.T) { + scheduler := newInboundRPCScheduler(1, 8, 1<<20) + scheduler.start() + c := newInboundTestConn(scheduler, 1, 4, time.Second) + defer func() { + c.closeInboundRPCScheduler() + scheduler.stop(time.Second) + }() + + finishFirst := c.beginRPCReplayRestore() + finishSecond := c.beginRPCReplayRestore() + ran := make(chan struct{}) + if err := c.enqueueInboundRPC(context.Background(), inboundRPC{ + method: "following.naked.rpc", + size: 4, + run: func(context.Context) error { + close(ran) + return nil + }, + }); err != nil { + t.Fatalf("enqueue following task: %v", err) + } + + select { + case <-ran: + t.Fatal("following RPC ran before replay restore completed") + case <-time.After(30 * time.Millisecond): + } + finishFirst() + select { + case <-ran: + t.Fatal("one of two replay restores released the scheduler early") + case <-time.After(30 * time.Millisecond): + } + finishSecond() + select { + case <-ran: + case <-time.After(time.Second): + t.Fatal("following RPC did not run after the final replay restore") + } +} diff --git a/internal/mtprotoedge/layer_admission_budget_test.go b/internal/mtprotoedge/layer_admission_budget_test.go new file mode 100644 index 00000000..f7483cbb --- /dev/null +++ b/internal/mtprotoedge/layer_admission_budget_test.go @@ -0,0 +1,469 @@ +package mtprotoedge + +import ( + "context" + "errors" + "reflect" + "strings" + "sync/atomic" + "testing" + "time" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/tg" + "go.uber.org/zap/zaptest" + + appfiles "telesrv/internal/app/files" + "telesrv/internal/rpc" +) + +func TestLayerRPCAdmissionMaterializationConstants(t *testing.T) { + constructors := make([]reflect.Type, 0, len(tg.TypesConstructorMap())) + for _, constructor := range tg.TypesConstructorMap() { + if typ := reflect.TypeOf(constructor()); typ != nil { + constructors = append(constructors, typ) + } + } + seen := make(map[reflect.Type]struct{}) + var ( + maxSize uintptr + maxType reflect.Type + visit func(reflect.Type) + ) + visit = func(typ reflect.Type) { + if typ == nil { + return + } + if _, ok := seen[typ]; ok { + return + } + seen[typ] = struct{}{} + switch typ.Kind() { + case reflect.Pointer, reflect.Slice, reflect.Array: + visit(typ.Elem()) + case reflect.Interface: + for _, candidate := range constructors { + // invokeWithLayer/query uses the deliberately broad bin.Object + // interface. Exact admission restricts that slot to generated RPC + // methods, so only request constructors are reachable there. + broad := typ.PkgPath() != "github.com/iamxvbaba/td/tg" + if candidate.Implements(typ) && (!broad || strings.HasSuffix(candidate.Elem().Name(), "Request")) { + visit(candidate) + } + } + case reflect.Struct: + if typ.PkgPath() == "github.com/iamxvbaba/td/tg" && typ.Size() > maxSize { + maxSize, maxType = typ.Size(), typ + } + for i := 0; i < typ.NumField(); i++ { + visit(typ.Field(i).Type) + } + } + } + for _, typ := range constructors { + if typ.Kind() == reflect.Pointer && strings.HasSuffix(typ.Elem().Name(), "Request") { + visit(typ) + } + } + if maxSize > layerRPCAdmissionStaticObjectBytes { + t.Fatalf("request-reachable generated TL object %v is %d bytes, exceeds admission ceiling %d", maxType, maxSize, layerRPCAdmissionStaticObjectBytes) + } + if layerRPCAdmissionGraphSlack != layerRPCAdmissionStaticObjectBytes*inboundLayerDecodeLimits.MaxDepth { + t.Fatalf("graph slack %d does not cover %d bytes across decode depth %d", layerRPCAdmissionGraphSlack, layerRPCAdmissionStaticObjectBytes, inboundLayerDecodeLimits.MaxDepth) + } + // Preserve enough room for the maximum upload payload plus any supported + // transparent wrapper/client-info envelope on a default connection. + if got := layerRPCAdmissionReservationSize(appfiles.MaxUploadPartBytes + (32 << 10)); got > maxInflightRPCBytes { + t.Fatalf("largest legal upload request charge = %d, exceeds default connection budget %d", got, maxInflightRPCBytes) + } + maxInt := int(^uint(0) >> 1) + if got := layerRPCAdmissionReservationSize(maxInt); got != maxInt { + t.Fatalf("saturating charge = %d, want max int %d", got, maxInt) + } + if got := layerRPCAdmissionReservationSize(-1); got != layerRPCAdmissionGraphSlack { + t.Fatalf("negative wire charge = %d, want fixed slack %d", got, layerRPCAdmissionGraphSlack) + } +} + +type countingLayerRPCAdmission struct { + LayerRPCHandler + decodeCalls atomic.Int32 +} + +type failingReplayLayerRPC struct { + LayerRPCHandler + err error +} + +func (h *failingReplayLayerRPC) PrepareAdmittedReplay( + context.Context, + [8]byte, + int64, + int64, + uint64, + tg.LayerRequest, +) (func() error, error) { + return nil, h.err +} + +func (h *countingLayerRPCAdmission) AdmitLayer(profile tg.LayerProfile, b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) { + h.decodeCalls.Add(1) + return h.LayerRPCHandler.AdmitLayer(profile, b, limits) +} + +func (h *countingLayerRPCAdmission) AdmitUnprofiled(b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) { + h.decodeCalls.Add(1) + return h.LayerRPCHandler.AdmitUnprofiled(b, limits) +} + +func TestLayerRPCAdmissionCapacityRejectsBeforeDecoder(t *testing.T) { + for _, test := range []struct { + name string + fillGlobal bool + }{ + {name: "connection_queue"}, + {name: "global_task", fillGlobal: true}, + } { + t.Run(test.name, func(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + counting := &countingLayerRPCAdmission{LayerRPCHandler: router} + s := New(Options{DC: 2, LayerRPC: counting}) + scheduler := newInboundRPCScheduler(1, 1, 1<<30) + s.rpcScheduler = scheduler + + target := &Conn{authKeyID: [8]byte{8, 1}, sessionID: 81, metrics: NopMetrics{}} + target.startInboundRPCScheduler(scheduler, 1, 1, time.Second) + holder := target + if test.fillGlobal { + holder = &Conn{authKeyID: [8]byte{8, 2}, sessionID: 82, metrics: NopMetrics{}} + holder.startInboundRPCScheduler(scheduler, 1, 1, time.Second) + } + occupied, err := holder.reserveInboundRPCBatch(context.Background(), []inboundRPCSpec{{method: "occupied", size: 1}}) + if err != nil { + t.Fatal(err) + } + defer occupied.abort() + + body := exactLayerRPCBody(t, &tg.InvokeWithLayerRequest{Layer: 225, Query: &tg.HelpGetConfigRequest{}}) + plan := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: body}}} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), target, plan); err != nil { + t.Fatal(err) + } + if got := counting.decodeCalls.Load(); got != 0 { + t.Fatalf("typed decoder entered %d times after capacity rejection", got) + } + if plan.items[0].kind != inboundItemCapacityError || plan.rpcReservation != nil || len(plan.rpcTasks) != 0 { + t.Fatalf("rejected plan = kind:%d reservation:%v tasks:%d", plan.items[0].kind, plan.rpcReservation != nil, len(plan.rpcTasks)) + } + }) + } +} + +func TestLayerRPCAdmissionTransfersOriginalReservationToFreshOwner(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + c := &Conn{authKeyID: [8]byte{8, 3}, sessionID: 83, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 4, time.Second) + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + + bad := make([]byte, bin.Word) + bad[0], bad[1], bad[2], bad[3] = 0x04, 0x03, 0x02, 0x01 + fresh := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + plan := &inboundPlan{items: []inboundItem{ + {kind: inboundItemRPC, msgID: 100, body: bad}, + {kind: inboundItemRPC, msgID: 104, body: fresh}, + }} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatal(err) + } + if plan.items[0].kind != inboundItemRPCAdmissionError || len(plan.rpcTasks) != 1 || plan.rpcReservation == nil { + t.Fatalf("classified plan = bad:%d tasks:%d reservation:%v", plan.items[0].kind, len(plan.rpcTasks), plan.rpcReservation != nil) + } + wantCharge := int64(layerRPCAdmissionReservationSize(len(fresh))) + if got := c.inflightRPCBytes.Load(); got != wantCharge { + t.Fatalf("connection retained bytes = %d, want %d", got, wantCharge) + } + s.rpcScheduler.budgetMu.Lock() + globalTasks, globalBytes := s.rpcScheduler.tasks, s.rpcScheduler.bytes + s.rpcScheduler.budgetMu.Unlock() + if globalTasks != 1 || globalBytes != wantCharge { + t.Fatalf("global retained budget = %d/%d, want 1/%d", globalTasks, globalBytes, wantCharge) + } + plan.close() + if got := c.inflightRPCBytes.Load(); got != 0 { + t.Fatalf("plan abort leaked %d connection bytes", got) + } + s.rpcScheduler.budgetMu.Lock() + globalTasks, globalBytes = s.rpcScheduler.tasks, s.rpcScheduler.bytes + s.rpcScheduler.budgetMu.Unlock() + if globalTasks != 0 || globalBytes != 0 { + t.Fatalf("plan abort leaked global budget %d/%d", globalTasks, globalBytes) + } +} + +func TestLayerRPCAdmissionPendingReplayReleasesProvisionalEntry(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + c := &Conn{authKeyID: [8]byte{8, 4}, sessionID: 84, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 4, time.Second) + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + + pendingBody := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + identityBuffer := &bin.Buffer{Buf: append([]byte(nil), pendingBody...)} + pendingRequest, err := router.AdmitLayer(tg.LayerProfile225, identityBuffer, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + pending, err := s.rpcResults.AcquireIdentified(c.authKeyID, c.sessionID, 100, pendingRequest.Prepared().Identity()) + if err != nil || pending.owner == nil { + t.Fatalf("pending owner = %v, %v", pending.owner, err) + } + + freshBody := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetNearestDCRequest{}) + plan := &inboundPlan{items: []inboundItem{ + {kind: inboundItemRPC, msgID: 100, body: pendingBody}, + {kind: inboundItemRPC, msgID: 104, body: freshBody}, + }} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatal(err) + } + if plan.items[0].kind != inboundItemRewrappedRPC || len(plan.rewrapAliases) != 1 || len(plan.rpcTasks) != 1 { + t.Fatalf("pending/fresh classification = kind:%d aliases:%d tasks:%d", plan.items[0].kind, len(plan.rewrapAliases), len(plan.rpcTasks)) + } + wantCharge := int64(layerRPCAdmissionReservationSize(len(freshBody))) + if got := c.inflightRPCBytes.Load(); got != wantCharge { + t.Fatalf("pending replay retained bytes = %d, want only fresh %d", got, wantCharge) + } + plan.close() + if !pending.owner.Abort() { + t.Fatal("plan cleanup aborted the pre-existing pending replay owner") + } +} + +func TestLayerRPCAdmissionCompletedReplayReleasesWholeProvisionalBatch(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + c := &Conn{authKeyID: [8]byte{8, 8}, sessionID: 88, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 2, time.Second) + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + identityBuffer := &bin.Buffer{Buf: append([]byte(nil), body...)} + request, err := router.AdmitLayer(tg.LayerProfile225, identityBuffer, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + claim, err := s.rpcResults.AcquireIdentified(c.authKeyID, c.sessionID, 100, request.Prepared().Identity()) + if err != nil || claim.owner == nil { + t.Fatalf("completed replay owner = %v, %v", claim.owner, err) + } + if !claim.owner.CompleteExecution(true) { + t.Fatal("complete replay business outcome failed") + } + s.rpcResults.Put(c.authKeyID, c.sessionID, 100, &encodedOutboundMessage{body: []byte{1, 2, 3, 4}}) + + plan := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: body}}} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatal(err) + } + if plan.items[0].kind != inboundItemReplayRPC || plan.rpcReservation != nil || len(plan.rpcTasks) != 0 { + t.Fatalf("completed replay plan = kind:%d reservation:%v tasks:%d", plan.items[0].kind, plan.rpcReservation != nil, len(plan.rpcTasks)) + } + if got := c.inflightRPCBytes.Load(); got != 0 || c.rpcReserved != 0 { + t.Fatalf("completed replay leaked connection budget bytes:%d tasks:%d", got, c.rpcReserved) + } + s.rpcScheduler.budgetMu.Lock() + globalTasks, globalBytes := s.rpcScheduler.tasks, s.rpcScheduler.bytes + s.rpcScheduler.budgetMu.Unlock() + if globalTasks != 0 || globalBytes != 0 { + t.Fatalf("completed replay leaked global budget %d/%d", globalTasks, globalBytes) + } +} + +func TestLayerRPCAdmissionReplayPreparationErrorIsNotSilentlyDelivered(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + prepareErr := errors.New("invalid replay wrapper metadata") + s := New(Options{DC: 2, LayerRPC: &failingReplayLayerRPC{ + LayerRPCHandler: router, + err: prepareErr, + }}) + c := &Conn{authKeyID: [8]byte{8, 9}, sessionID: 89, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 2, time.Second) + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + identityBuffer := &bin.Buffer{Buf: append([]byte(nil), body...)} + request, err := router.AdmitLayer(tg.LayerProfile225, identityBuffer, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + claim, err := s.rpcResults.AcquireIdentified(c.authKeyID, c.sessionID, 100, request.Prepared().Identity()) + if err != nil || claim.owner == nil { + t.Fatalf("completed replay owner = %v, %v", claim.owner, err) + } + if !claim.owner.CompleteExecution(true) { + t.Fatal("complete replay business outcome failed") + } + s.rpcResults.Put(c.authKeyID, c.sessionID, 100, &encodedOutboundMessage{body: []byte{1, 2, 3, 4}}) + + plan := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: body}}} + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); !errors.Is(err, prepareErr) { + plan.close() + t.Fatalf("replay preparation error = %v, want %v", err, prepareErr) + } + if plan.items[0].kind == inboundItemReplayRPC { + plan.close() + t.Fatal("invalid replay metadata was converted into a deliverable cached result") + } + plan.close() + if got := c.inflightRPCBytes.Load(); got != 0 || c.rpcReserved != 0 { + t.Fatalf("failed replay preparation leaked connection budget bytes:%d tasks:%d", got, c.rpcReserved) + } + s.rpcScheduler.budgetMu.Lock() + globalTasks, globalBytes := s.rpcScheduler.tasks, s.rpcScheduler.bytes + s.rpcScheduler.budgetMu.Unlock() + if globalTasks != 0 || globalBytes != 0 { + t.Fatalf("failed replay preparation leaked global budget %d/%d", globalTasks, globalBytes) + } +} + +func TestLayerRPCAdmissionTransferredBatchClosesWithoutLeak(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + c := &Conn{authKeyID: [8]byte{8, 5}, sessionID: 85, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 2, time.Second) + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + plan := &inboundPlan{items: []inboundItem{{ + kind: inboundItemRPC, msgID: 100, + body: exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}), + }}} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatal(err) + } + c.beginCloseInboundRPCScheduler() + if err := plan.commitRPCBatch(); err != ErrConnClosed { + t.Fatalf("commit after connection close = %v, want ErrConnClosed", err) + } + plan.close() + if !c.waitInboundShutdown(time.Second) { + t.Fatal("connection close did not converge after transferred reservation failed commit") + } + if got := c.inflightRPCBytes.Load(); got != 0 { + t.Fatalf("connection close leaked %d admission bytes", got) + } + s.rpcScheduler.budgetMu.Lock() + globalTasks, globalBytes := s.rpcScheduler.tasks, s.rpcScheduler.bytes + s.rpcScheduler.budgetMu.Unlock() + if globalTasks != 0 || globalBytes != 0 { + t.Fatalf("connection close leaked global budget %d/%d", globalTasks, globalBytes) + } +} + +func TestLayerRPCAdmissionTransferredBatchCommitsConservativeCharge(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + c := &Conn{authKeyID: [8]byte{8, 6}, sessionID: 86, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 2, time.Second) + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + plan := &inboundPlan{items: []inboundItem{{kind: inboundItemRPC, msgID: 100, body: body}}} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatal(err) + } + if err := plan.commitRPCBatch(); err != nil { + t.Fatal(err) + } + wantCharge := layerRPCAdmissionReservationSize(len(body)) + c.rpcMu.Lock() + queued := len(c.rpcQueue) + gotCharge := 0 + if queued == 1 { + gotCharge = c.rpcQueue[0].size + } + c.rpcMu.Unlock() + if queued != 1 || gotCharge != wantCharge { + t.Fatalf("committed queue = len:%d charge:%d, want 1/%d", queued, gotCharge, wantCharge) + } + c.beginCloseInboundRPCScheduler() + if got := c.inflightRPCBytes.Load(); got != 0 { + t.Fatalf("queued exact task close leaked %d bytes", got) + } + s.rpcScheduler.budgetMu.Lock() + globalTasks, globalBytes := s.rpcScheduler.tasks, s.rpcScheduler.bytes + s.rpcScheduler.budgetMu.Unlock() + if globalTasks != 0 || globalBytes != 0 { + t.Fatalf("queued exact task close leaked global budget %d/%d", globalTasks, globalBytes) + } +} + +func TestLayerRPCAdmissionLocalDuplicateConsumesNoProvisionalEntry(t *testing.T) { + router := rpc.New(rpc.Config{DC: 2}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + s := New(Options{DC: 2, LayerRPC: router}) + c := &Conn{authKeyID: [8]byte{8, 7}, sessionID: 87, metrics: NopMetrics{}} + c.startInboundRPCScheduler(s.rpcScheduler, 1, 2, time.Second) + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + body := exactOutboundLayerRPCBody(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + plan := &inboundPlan{items: []inboundItem{ + {kind: inboundItemDuplicate, msgID: 96, body: body}, + {kind: inboundItemRPC, msgID: 100, body: body}, + }} + defer plan.close() + if err := s.prepareInboundLayerRPCBatch(context.Background(), c, plan); err != nil { + t.Fatal(err) + } + if plan.items[0].kind != inboundItemDuplicate || len(plan.rpcTasks) != 1 || c.rpcReserved != 1 { + t.Fatalf("duplicate/fresh admission = duplicate:%d tasks:%d reserved:%d", plan.items[0].kind, len(plan.rpcTasks), c.rpcReserved) + } +} + +func TestTakeInboundRPCFIFOAdvancesSliceHead(t *testing.T) { + scheduler := newInboundRPCScheduler(1, 8, 1<<20) + c := &Conn{metrics: NopMetrics{}} + c.startInboundRPCScheduler(scheduler, 1, 8, time.Second) + c.rpcQueue = []inboundRPC{{method: "first"}, {method: "second"}, {method: "third"}} + c.rpcReady = true + oldSecond := &c.rpcQueue[1] + task, ok, _ := c.takeInboundRPC() + if !ok || task.method != "first" { + t.Fatalf("take = (%q,%v), want first", task.method, ok) + } + if len(c.rpcQueue) != 2 || &c.rpcQueue[0] != oldSecond { + t.Fatal("FIFO take copied the queue instead of advancing its slice head") + } + c.finishInboundRPC(task) + c.beginCloseInboundRPCScheduler() +} + +func BenchmarkLayerRPCAdmissionReservationSize(b *testing.B) { + for _, size := range []int{64, appfiles.MaxUploadPartBytes + 24} { + b.Run(time.Duration(size).String(), func(b *testing.B) { + b.ReportAllocs() + var charge int + for i := 0; i < b.N; i++ { + charge = layerRPCAdmissionReservationSize(size) + } + if charge == 0 { + b.Fatal("zero admission charge") + } + }) + } +} diff --git a/internal/mtprotoedge/layer_downgrade_test.go b/internal/mtprotoedge/layer_downgrade_test.go index 730e22bb..9514fd47 100644 --- a/internal/mtprotoedge/layer_downgrade_test.go +++ b/internal/mtprotoedge/layer_downgrade_test.go @@ -2,78 +2,82 @@ package mtprotoedge import ( "bytes" + "context" "encoding/binary" + "errors" + "fmt" + "sync/atomic" "testing" + "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap/zaptest" ) -// TestConnDowngradedClone verifies the outbound seam downgrades a canonical -// (227) object to the connection's negotiated layer, is a no-op for 227, and -// — critically for push fan-out — never mutates the shared input message (one -// pre-encoded update is reused across many connections of differing layers). -func TestConnDowngradedClone(t *testing.T) { - const ( - message227CRC = 0x7600b9d3 - message220CRC = 0xb92f76cf - ) - msg := &tg.Message{ - ID: 2, - FromID: &tg.PeerUser{UserID: 3}, - PeerID: &tg.PeerUser{UserID: 3}, - Date: 1, - Message: "hi", - } +type countingLayerRPCResult struct { + inner tg.LayerRPCResult + encodeCalls atomic.Int32 + prepareCalls atomic.Int32 +} - // layer 220: returns a NEW message rewritten to the 220 constructor id, - // leaving the shared input untouched (227). - enc, err := encodeOutboundMessage(msg) - if err != nil { - t.Fatalf("encode: %v", err) - } - c := &Conn{metrics: NopMetrics{}} - c.SetClientLayer(220) - out := c.downgradedClone(enc) +const ( + testChannelWireID227 uint32 = 0x1c32b11c + testChannelWireID228 uint32 = 0xd49f34c6 +) - if id, _ := (&bin.Buffer{Buf: out.body}).PeekID(); id != message220CRC { - t.Fatalf("downgraded id = %#08x, want %#08x", id, message220CRC) - } - if out.typeID != message220CRC { - t.Fatalf("downgraded typeID = %#08x, want %#08x", out.typeID, message220CRC) - } - // Input must be unmodified — this is what makes shared push fan-out safe. - if id, _ := (&bin.Buffer{Buf: enc.body}).PeekID(); id != message227CRC { - t.Fatalf("input message was mutated: id now %#08x, want 227 %#08x", id, message227CRC) +func testChannelWireID(profile tg.LayerProfile) uint32 { + if profile == tg.LayerProfile228 { + return testChannelWireID228 } + return testChannelWireID227 +} - // Two connections sharing one pre-encoded message get independent results. - encShared, _ := encodeOutboundMessage(msg) - c220 := &Conn{metrics: NopMetrics{}} - c220.SetClientLayer(220) - c227 := &Conn{metrics: NopMetrics{}} // ClientLayer() defaults to 227 - out220 := c220.downgradedClone(encShared) - out227 := c227.downgradedClone(encShared) - if id, _ := (&bin.Buffer{Buf: out220.body}).PeekID(); id != message220CRC { - t.Fatalf("shared->220 id = %#08x, want %#08x", id, message220CRC) +func testOtherChannelWireID(profile tg.LayerProfile) uint32 { + if profile == tg.LayerProfile228 { + return testChannelWireID227 } - if out227 != encShared { - t.Errorf("227 connection should pass the shared message through unchanged (same pointer)") - } - if !bytes.Equal(encShared.body, out227.body) { - t.Errorf("227 passthrough altered bytes") + return testChannelWireID228 +} + +func testLayerChannel() *tg.Channel { + return &tg.Channel{ + ID: 100, + Title: "layer proof", + Photo: &tg.ChatPhotoEmpty{}, + Date: 1, } } -func TestEncodeRPCResultDowngradesDifferenceMessagesForNegotiatedLayer225(t *testing.T) { - const ( - message227CRC = 0x7600b9d3 - message225CRC = 0x95ef6f2b - ) - c := &Conn{metrics: NopMetrics{}} - c.SetClientLayer(225) +func (r *countingLayerRPCResult) Encode(b *bin.Buffer) error { + r.encodeCalls.Add(1) + return r.inner.Encode(b) +} + +func (r *countingLayerRPCResult) Prepared() tg.LayerPreparedCall { return r.inner.Prepared() } + +func (r *countingLayerRPCResult) WireInvariant() bool { return r.inner.WireInvariant() } + +func (r *countingLayerRPCResult) Freeze() (tg.LayerFrozenResult, error) { + return r.inner.Freeze() +} + +func (r *countingLayerRPCResult) Prepare() (tg.LayerPreparedResult, error) { + r.prepareCalls.Add(1) + return r.inner.Prepare() +} + +func TestExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t *testing.T) { + for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227, tg.LayerProfile228} { + t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) { + testExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t, profile) + }) + } +} + +func testExactLayerRPCResultEncodesDifferenceWithAdmittedCodec(t *testing.T, profile tg.LayerProfile) { + t.Helper() diff := &tg.UpdatesDifference{ NewMessages: []tg.MessageClass{ &tg.Message{ @@ -86,116 +90,190 @@ func TestEncodeRPCResultDowngradesDifferenceMessagesForNegotiatedLayer225(t *tes }, NewEncryptedMessages: []tg.EncryptedMessageClass{}, OtherUpdates: []tg.UpdateClass{}, - Chats: []tg.ChatClass{}, + Chats: []tg.ChatClass{testLayerChannel()}, Users: []tg.UserClass{}, State: tg.UpdatesState{Pts: 2, Date: 1}, } + dispatcher := tg.NewServerDispatcher(nil) + dispatcher.OnUpdatesGetDifference(func(context.Context, *tg.UpdatesGetDifferenceRequest) (tg.UpdatesDifferenceClass, error) { + return diff, nil + }) + outbound, err := tg.PrepareLayerOutboundCall(profile, &tg.UpdatesGetDifferenceRequest{Pts: 1, Date: 1}) + if err != nil { + t.Fatal(err) + } + var requestBody bin.Buffer + if err := outbound.Encode(&requestBody); err != nil { + t.Fatal(err) + } + admitted, err := dispatcher.AdmitLayer(profile, &requestBody) + if err != nil { + t.Fatal(err) + } + serverResult, err := dispatcher.DispatchAdmitted(context.Background(), admitted) + if err != nil { + t.Fatal(err) + } + counted := &countingLayerRPCResult{inner: serverResult} + exact := &layerRPCResultEncoder{call: counted.Prepared().Call(), result: counted} + + c := &Conn{metrics: NopMetrics{}, msgID: proto.NewMessageIDGen(time.Now)} + if err := c.FreezeLayerProfile(profile); err != nil { + t.Fatal(err) + } + // Simulate an invokeWithLayer correction admitted while this handler was + // still running. The result must retain the request's admitted profile. + corrected := tg.LayerProfile227 + if profile == tg.LayerProfile227 { + corrected = tg.LayerProfile225 + } + if err := c.FreezeLayerProfile(corrected); err != nil { + t.Fatal(err) + } s := &Server{log: zaptest.NewLogger(t)} - encoded, err := s.encodeRPCResult(c, 12345, diff) + encoded, err := s.encodeRPCResult(c, 12345, exact) if err != nil { t.Fatalf("encode rpc_result: %v", err) } - var result proto.Result - if err := result.Decode(&bin.Buffer{Buf: encoded.body}); err != nil { + if got := counted.prepareCalls.Load(); got != 0 { + t.Fatalf("generated Prepare calls = %d, want 0; inbound workers must not snapshot result bytes", got) + } + if got := counted.encodeCalls.Load(); got != 1 { + t.Fatalf("generated Encode calls = %d, want exactly 1 under outbound admission", got) + } + if encoded.layer == nil || encoded.layer.profile != profile || encoded.layer.typ != admitted.Call().WireResultType() { + t.Fatalf("result binding = %#v, want profile %d and admitted result TypeRef", encoded.layer, profile) + } + if encoded.layer.kind != outboundLayerBindingRequest { + t.Fatalf("exact RPC result binding kind = %d, want request-bound", encoded.layer.kind) + } + beforeFrame := append([]byte(nil), encoded.body...) + frame, err := c.buildFrame(context.Background(), proto.MessageServerResponse, nil, encoded) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(frame.body, beforeFrame) { + t.Fatal("exact RPC result was transcoded after generated preparation") + } + var rpcEnvelope proto.Result + if err := rpcEnvelope.Decode(&bin.Buffer{Buf: frame.body}); err != nil { t.Fatalf("decode rpc_result: %v", err) } - if result.RequestMessageID != 12345 { - t.Fatalf("req_msg_id = %d, want 12345", result.RequestMessageID) + if rpcEnvelope.RequestMessageID != 12345 { + t.Fatalf("req_msg_id = %d, want 12345", rpcEnvelope.RequestMessageID) } - if !bytes.Contains(result.Result, littleEndianID(message225CRC)) { - t.Fatalf("rpc_result inner object does not contain layer 225 message id %#08x", message225CRC) + wantChannelID := testChannelWireID(profile) + if !bytes.Contains(rpcEnvelope.Result, littleEndianID(wantChannelID)) { + t.Fatalf("profile %d offline difference lacks channel constructor %#08x", profile, wantChannelID) } - if bytes.Contains(result.Result, littleEndianID(message227CRC)) { - t.Fatalf("rpc_result inner object still contains canonical message id %#08x", message227CRC) + if otherChannelID := testOtherChannelWireID(profile); bytes.Contains(rpcEnvelope.Result, littleEndianID(otherChannelID)) { + t.Fatalf("profile %d offline difference leaked channel constructor %#08x", profile, otherChannelID) + } + inner := bin.Buffer{Buf: rpcEnvelope.Result} + decoded, err := tg.DecodeLayer(profile, tg.LayerClassUpdatesDifferenceType(), &inner) + if err != nil { + t.Fatalf("decode exact difference: %v", err) + } + if inner.Len() != 0 { + t.Fatalf("exact difference left %d bytes", inner.Len()) + } + got, ok := decoded.(*tg.UpdatesDifference) + message, messageOK := func() (*tg.Message, bool) { + if !ok || len(got.NewMessages) != 1 { + return nil, false + } + value, valueOK := got.NewMessages[0].(*tg.Message) + return value, valueOK + }() + if !messageOK || message.ID != 2 { + t.Fatalf("decoded exact difference = %#v", decoded) + } + if len(got.Chats) != 1 { + t.Fatalf("decoded exact difference chats = %#v", got.Chats) + } + channel, channelOK := got.Chats[0].(*tg.Channel) + if !channelOK || channel.ID != 100 { + t.Fatalf("decoded exact difference channel = %#v", got.Chats) } } -func TestEncodeRPCResultDowngradesDialogMessagesForNegotiatedLayer225(t *testing.T) { - const ( - message227CRC = 0x7600b9d3 - message225CRC = 0x95ef6f2b - ) - c := &Conn{metrics: NopMetrics{}} - c.SetClientLayer(225) - dialogs := &tg.MessagesDialogs{ - Dialogs: []tg.DialogClass{ - &tg.Dialog{ - Peer: &tg.PeerUser{UserID: 3}, - TopMessage: 2, - NotifySettings: tg.PeerNotifySettings{}, - }, - }, - Messages: []tg.MessageClass{ - &tg.Message{ - ID: 2, - FromID: &tg.PeerUser{UserID: 3}, - PeerID: &tg.PeerUser{UserID: 3}, - Date: 1, - Message: "hi", - }, - }, - Chats: []tg.ChatClass{}, - Users: []tg.UserClass{ - &tg.User{ID: 3, AccessHash: 5, FirstName: "A"}, - }, - } - - s := &Server{log: zaptest.NewLogger(t)} - encoded, err := s.encodeRPCResult(c, 12345, dialogs) +func TestExactLayerRPCResultUsesHistoricalMethodResultType(t *testing.T) { + const profile = tg.LayerProfile225 + dispatcher := tg.NewServerDispatcher(nil) + dispatcher.OnChannelsJoinChannel(func(context.Context, tg.InputChannelClass) (tg.MessagesChatInviteJoinResultClass, error) { + return &tg.MessagesChatInviteJoinResultOk{Updates: &tg.UpdatesTooLong{}}, nil + }) + outbound, err := tg.PrepareLayerOutboundCall(profile, &tg.ChannelsJoinChannelRequest{Channel: &tg.InputChannelEmpty{}}) if err != nil { - t.Fatalf("encode rpc_result: %v", err) + t.Fatal(err) } - var result proto.Result - if err := result.Decode(&bin.Buffer{Buf: encoded.body}); err != nil { - t.Fatalf("decode rpc_result: %v", err) + var requestBody bin.Buffer + if err := outbound.Encode(&requestBody); err != nil { + t.Fatal(err) } - if !bytes.Contains(result.Result, littleEndianID(message225CRC)) { - t.Fatalf("rpc_result inner object does not contain layer 225 message id %#08x", message225CRC) + admitted, err := dispatcher.AdmitLayer(profile, &requestBody) + if err != nil { + t.Fatal(err) } - if bytes.Contains(result.Result, littleEndianID(message227CRC)) { - t.Fatalf("rpc_result inner object still contains canonical message id %#08x", message227CRC) + if admitted.Call().WireID() == tg.ChannelsJoinChannelRequestTypeID { + t.Fatal("historical request unexpectedly retained canonical method id") + } + serverResult, err := dispatcher.DispatchAdmitted(context.Background(), admitted) + if err != nil { + t.Fatal(err) + } + exact := &layerRPCResultEncoder{call: serverResult.Prepared().Call(), result: serverResult} + c := &Conn{metrics: NopMetrics{}} + if err := c.FreezeLayerProfile(profile); err != nil { + t.Fatal(err) + } + encoded, err := (&Server{log: zaptest.NewLogger(t)}).encodeRPCResult(c, 67890, exact) + if err != nil { + t.Fatal(err) + } + var rpcEnvelope proto.Result + if err := rpcEnvelope.Decode(&bin.Buffer{Buf: encoded.body}); err != nil { + t.Fatal(err) + } + inner := bin.Buffer{Buf: rpcEnvelope.Result} + updates, err := tg.DecodeLayer(profile, tg.LayerClassUpdatesType(), &inner) + if err != nil { + t.Fatalf("decode historical channels.joinChannel result: %v", err) + } + if inner.Len() != 0 { + t.Fatalf("historical result left %d bytes", inner.Len()) + } + if _, ok := updates.(*tg.UpdatesTooLong); !ok { + t.Fatalf("historical result = %T, want Updates", updates) } } -func TestConnDowngradedCloneDowngradesUpdateNewMessageForLayer225(t *testing.T) { - const ( - message227CRC = 0x7600b9d3 - message225CRC = 0x95ef6f2b - ) - updates := &tg.Updates{ - Updates: []tg.UpdateClass{ - &tg.UpdateNewMessage{ - Message: &tg.Message{ - ID: 2, - FromID: &tg.PeerUser{UserID: 3}, - PeerID: &tg.PeerUser{UserID: 3}, - Date: 1, - Message: "hi", - }, - Pts: 2, - PtsCount: 1, - }, - }, - Users: []tg.UserClass{ - &tg.User{ID: 3, AccessHash: 5, FirstName: "A"}, - }, - Chats: []tg.ChatClass{}, - Date: 1, - Seq: 1, - } - enc, err := encodeOutboundMessage(updates) - if err != nil { - t.Fatalf("encode updates: %v", err) - } +func TestProductionUnboundApplicationResultFailsClosedForLayer227(t *testing.T) { c := &Conn{metrics: NopMetrics{}} - c.SetClientLayer(225) - out := c.downgradedClone(enc) - if !bytes.Contains(out.body, littleEndianID(message225CRC)) { - t.Fatalf("push update does not contain layer 225 message id %#08x", message225CRC) + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatal(err) } - if bytes.Contains(out.body, littleEndianID(message227CRC)) { - t.Fatalf("push update still contains canonical message id %#08x", message227CRC) + encoded, err := (&Server{log: zaptest.NewLogger(t)}).encodeRPCResult(c, 12345, testLayerChannel()) + if !errors.Is(err, ErrOutboundLayerBindingRequired) { + t.Fatalf("unbound Layer 228 result error = %v, want %v", err, ErrOutboundLayerBindingRequired) + } + if encoded != nil { + t.Fatalf("unbound result produced %d wire bytes", len(encoded.body)) + } +} + +func TestProductionUnboundApplicationPushFailsClosedForLayer227(t *testing.T) { + c := &Conn{metrics: NopMetrics{}} + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatal(err) + } + frame, err := c.buildFrame(context.Background(), proto.MessageFromServer, testLayerChannelUpdatesValue(321), nil) + if !errors.Is(err, ErrOutboundLayerBindingRequired) { + t.Fatalf("unbound Layer 228 push error = %v, want %v", err, ErrOutboundLayerBindingRequired) + } + if frame != nil { + t.Fatalf("unbound push produced frame %#v", frame) } } diff --git a/internal/mtprotoedge/layer_profile_test.go b/internal/mtprotoedge/layer_profile_test.go new file mode 100644 index 00000000..26be2264 --- /dev/null +++ b/internal/mtprotoedge/layer_profile_test.go @@ -0,0 +1,596 @@ +package mtprotoedge + +import ( + "context" + "errors" + "fmt" + "sync" + "testing" + + "github.com/iamxvbaba/td/tg" +) + +type countingInheritedLayerResolver struct { + LayerRPCHandler + calls int + layer int + found bool + err error +} + +type orderedSessionLayerResolver struct { + LayerRPCHandler + layer int + msgID int64 + found bool +} + +func (r *orderedSessionLayerResolver) NegotiatedSessionLayerEvidence([8]byte, int64) (int, int64, bool) { + return r.layer, r.msgID, r.found +} + +func (r *countingInheritedLayerResolver) ResolveInheritedAuthKeyLayer(context.Context, [8]byte) (int, bool, error) { + r.calls++ + return r.layer, r.found, r.err +} + +func TestConnLayerProfileUnknownFreezeAndIdempotence(t *testing.T) { + c := &Conn{} + if profile, ok := c.LayerProfile(); ok || profile != 0 { + t.Fatalf("initial LayerProfile = (%d, %v), want (0, false)", profile, ok) + } + + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatalf("freeze layer 225: %v", err) + } + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatalf("repeat freeze layer 225: %v", err) + } + if profile, ok := c.LayerProfile(); !ok || profile != tg.LayerProfile225 { + t.Fatalf("LayerProfile = (%d, %v), want (225, true)", profile, ok) + } +} + +func TestConnLayerProfileInheritedCanBeCorrectedExplicitly(t *testing.T) { + c := &Conn{} + if err := c.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatalf("seed inherited layer 225: %v", err) + } + initial := c.LayerProfileState() + if initial.Profile != tg.LayerProfile225 || initial.Origin != LayerProfileInherited || initial.Epoch != 1 { + t.Fatalf("initial inherited state = %#v", initial) + } + if err := c.SeedInheritedLayerProfile(tg.LayerProfile226); err != nil { + t.Fatalf("repeat inherited seed: %v", err) + } + if got := c.LayerProfileState(); got != initial { + t.Fatalf("second inherited seed replaced selected default: got %#v want %#v", got, initial) + } + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatalf("promote inherited evidence: %v", err) + } + promoted := c.LayerProfileState() + if promoted.Profile != tg.LayerProfile225 || promoted.Origin != LayerProfileExplicit || promoted.Epoch != initial.Epoch+1 { + t.Fatalf("promoted explicit state = %#v", promoted) + } + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatalf("correct explicit layer: %v", err) + } + corrected := c.LayerProfileState() + if corrected.Profile != tg.LayerProfile227 || corrected.Origin != LayerProfileExplicit || corrected.Epoch != promoted.Epoch+1 { + t.Fatalf("corrected explicit state = %#v", corrected) + } +} + +func TestConnSeedLayerProfile(t *testing.T) { + c := &Conn{} + if err := c.SeedLayerProfile(tg.LayerProfile226); err != nil { + t.Fatalf("seed layer 226: %v", err) + } + if err := c.SeedLayerProfile(tg.LayerProfile226); err != nil { + t.Fatalf("repeat seed layer 226: %v", err) + } + if err := c.FreezeLayerProfile(tg.LayerProfile226); err != nil { + t.Fatalf("freeze seeded layer 226: %v", err) + } + if profile, ok := c.LayerProfile(); !ok || profile != tg.LayerProfile226 { + t.Fatalf("LayerProfile = (%d, %v), want (226, true)", profile, ok) + } +} + +func TestConnLayerProfileRejectsUnsupported(t *testing.T) { + for _, profile := range []tg.LayerProfile{0, 219, 229} { + t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) { + c := &Conn{} + if err := c.FreezeLayerProfile(profile); !errors.Is(err, ErrLayerProfileUnsupported) { + t.Fatalf("FreezeLayerProfile(%d) error = %v, want ErrLayerProfileUnsupported", profile, err) + } + if err := c.SeedLayerProfile(profile); !errors.Is(err, ErrLayerProfileUnsupported) { + t.Fatalf("SeedLayerProfile(%d) error = %v, want ErrLayerProfileUnsupported", profile, err) + } + if got, ok := c.LayerProfile(); ok || got != 0 { + t.Fatalf("LayerProfile after invalid values = (%d, %v), want (0, false)", got, ok) + } + }) + } +} + +func TestConnLayerProfileConcurrentCorrectionsRemainAtomic(t *testing.T) { + const goroutines = 128 + c := &Conn{} + start := make(chan struct{}) + errs := make([]error, goroutines) + profiles := make([]tg.LayerProfile, goroutines) + var wg sync.WaitGroup + wg.Add(goroutines) + for i := range goroutines { + profile := tg.LayerProfile225 + if i%2 != 0 { + profile = tg.LayerProfile227 + } + profiles[i] = profile + go func(index int, requested tg.LayerProfile) { + defer wg.Done() + <-start + errs[index] = c.FreezeLayerProfile(requested) + }(i, profile) + } + close(start) + wg.Wait() + + state := c.LayerProfileState() + if state.Origin != LayerProfileExplicit || (state.Profile != tg.LayerProfile225 && state.Profile != tg.LayerProfile227) { + t.Fatalf("concurrent final state = %#v, want supported explicit contender", state) + } + if state.Epoch == 0 || state.Epoch > goroutines { + t.Fatalf("concurrent epoch = %d, want 1..%d", state.Epoch, goroutines) + } + for i, err := range errs { + if err != nil { + t.Fatalf("correction contender %d (%d) returned error: %v", i, profiles[i], err) + } + } +} + +func TestConnLayerProfileEvidenceUsesClientMessageOrder(t *testing.T) { + c := &Conn{} + if err := c.seedOrderedLayerProfile(tg.LayerProfile225, 100); err != nil { + t.Fatal(err) + } + if applied, err := c.FreezeLayerProfileAt(tg.LayerProfile227, 104); err != nil || !applied { + t.Fatalf("newer correction applied=%v err=%v", applied, err) + } + corrected := c.LayerProfileState() + if applied, err := c.FreezeLayerProfileAt(tg.LayerProfile225, 100); err != nil || applied { + t.Fatalf("old duplicate applied=%v err=%v", applied, err) + } + if got := c.LayerProfileState(); got != corrected { + t.Fatalf("old duplicate changed profile: got %#v want %#v", got, corrected) + } + if applied, err := c.FreezeLayerProfileAt(tg.LayerProfile225, 104); !errors.Is(err, ErrLayerProfileConflict) || applied { + t.Fatalf("same-msg conflicting evidence applied=%v err=%v", applied, err) + } + if applied, err := c.FreezeLayerProfileAt(tg.LayerProfile227, 108); err != nil || !applied { + t.Fatalf("same-layer newer evidence applied=%v err=%v", applied, err) + } + state, msgID := c.layerProfileEvidenceState() + if state != corrected || msgID != 108 { + t.Fatalf("same-layer cursor advance = state:%#v msgID:%d, want state:%#v msgID:108", state, msgID, corrected) + } +} + +func TestSessionManagerSeedsOnlyUnknownRawAuthKeyConnections(t *testing.T) { + m := NewSessionManager(nil) + authKeyID := [8]byte{2, 2, 7} + unknown := &Conn{authKeyID: authKeyID, sessionID: 1} + explicit := &Conn{authKeyID: authKeyID, sessionID: 2} + inherited := &Conn{authKeyID: authKeyID, sessionID: 3} + if err := explicit.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + if err := inherited.SeedInheritedLayerProfile(tg.LayerProfile226); err != nil { + t.Fatal(err) + } + for _, c := range []*Conn{unknown, explicit, inherited} { + if err := m.Register(c); err != nil { + t.Fatal(err) + } + } + + if seeded := m.SeedInheritedLayerForRawAuthKey(authKeyID, 227); seeded != 1 { + t.Fatalf("seeded connections = %d, want 1", seeded) + } + if got := unknown.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileInherited { + t.Fatalf("unknown connection seed = %#v", got) + } + if got := explicit.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileExplicit { + t.Fatalf("explicit connection was overwritten = %#v", got) + } + if got := inherited.LayerProfileState(); got.Profile != tg.LayerProfile226 || got.Origin != LayerProfileInherited { + t.Fatalf("existing inherited connection was overwritten = %#v", got) + } + if seeded := m.SeedInheritedLayerForRawAuthKey(authKeyID, 229); seeded != 0 { + t.Fatalf("unsupported layer seeded %d connections", seeded) + } +} + +func TestSessionManagerRefreshesInheritedRawKeyShadowAtBind(t *testing.T) { + m := NewSessionManager(nil) + authKeyID := [8]byte{2, 2, 8} + unknown := &Conn{authKeyID: authKeyID, sessionID: 1} + inherited := &Conn{authKeyID: authKeyID, sessionID: 2} + explicit := &Conn{authKeyID: authKeyID, sessionID: 3} + if err := inherited.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + if err := explicit.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + for _, c := range []*Conn{unknown, inherited, explicit} { + if err := m.Register(c); err != nil { + t.Fatal(err) + } + } + + if refreshed := m.RefreshInheritedLayerForRawAuthKey(authKeyID, 227); refreshed != 2 { + t.Fatalf("refreshed connections = %d, want 2", refreshed) + } + for name, c := range map[string]*Conn{"unknown": unknown, "inherited": inherited} { + if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileInherited { + t.Fatalf("%s refresh = %#v", name, got) + } + } + if got := explicit.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileExplicit { + t.Fatalf("explicit evidence overwritten = %#v", got) + } +} + +func TestSessionManagerClearsOnlyInheritedRawKeyShadowAtBind(t *testing.T) { + m := NewSessionManager(nil) + authKeyID := [8]byte{2, 2, 81} + inherited := &Conn{authKeyID: authKeyID, sessionID: 1} + explicit := &Conn{authKeyID: authKeyID, sessionID: 2} + unknown := &Conn{authKeyID: authKeyID, sessionID: 3} + if err := inherited.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + if err := explicit.seedOrderedLayerProfile(tg.LayerProfile227, 104); err != nil { + t.Fatal(err) + } + for _, c := range []*Conn{inherited, explicit, unknown} { + if err := m.Register(c); err != nil { + t.Fatal(err) + } + } + + if cleared := m.ClearInheritedLayerForRawAuthKey(authKeyID); cleared != 1 { + t.Fatalf("cleared connections = %d, want 1", cleared) + } + if got := inherited.LayerProfileState(); got.Origin != LayerProfileUnknown || got.Profile != 0 { + t.Fatalf("inherited shadow after clear = %#v, want unknown", got) + } + if got := explicit.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileExplicit { + t.Fatalf("explicit evidence was cleared = %#v", got) + } + if state, msgID := explicit.layerProfileEvidenceState(); state.Origin != LayerProfileExplicit || msgID != 104 { + t.Fatalf("explicit ordered evidence changed = %#v msgID:%d", state, msgID) + } + if got := unknown.LayerProfileState(); got.Origin != LayerProfileUnknown || got.Profile != 0 { + t.Fatalf("unknown state changed = %#v", got) + } + if cleared := m.ClearInheritedLayerForRawAuthKey(authKeyID); cleared != 0 { + t.Fatalf("idempotent clear changed %d connections", cleared) + } +} + +func TestSessionManagerSeedsUnknownSessionsAcrossBusinessAuthKey(t *testing.T) { + m := NewSessionManager(nil) + permAuthKeyID := [8]byte{9, 9, 9} + rawOne := [8]byte{9, 9, 1} + rawTwo := [8]byte{9, 9, 2} + first := &Conn{authKeyID: rawOne, sessionID: 1} + second := &Conn{authKeyID: rawTwo, sessionID: 2} + explicit := &Conn{authKeyID: rawTwo, sessionID: 3} + inherited := &Conn{authKeyID: rawOne, sessionID: 4} + if err := explicit.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + if err := inherited.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + for _, c := range []*Conn{first, second, explicit, inherited} { + if err := m.Register(c); err != nil { + t.Fatal(err) + } + m.BindAuthKeyForSession(c.authKeyID, c.sessionID, permAuthKeyID) + } + if seeded := m.SeedInheritedLayerForBusinessAuthKey(permAuthKeyID, 227); seeded != 2 { + t.Fatalf("business auth-key seeded=%d, want 2", seeded) + } + for name, c := range map[string]*Conn{"first": first, "second": second} { + if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileInherited { + t.Fatalf("%s business default = %#v", name, got) + } + } + if got := explicit.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileExplicit { + t.Fatalf("business seed overwrote explicit = %#v", got) + } + if got := inherited.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileInherited { + t.Fatalf("business seed overwrote inherited = %#v", got) + } +} + +func TestSessionManagerExplicitLayerEvidenceUsesLiveExactSession(t *testing.T) { + m := NewSessionManager(nil) + authKeyID := [8]byte{2, 2, 9} + const sessionID = int64(229) + c := &Conn{authKeyID: authKeyID, sessionID: sessionID} + if err := c.seedOrderedLayerProfile(tg.LayerProfile226, 1234); err != nil { + t.Fatal(err) + } + if err := m.Register(c); err != nil { + t.Fatal(err) + } + if layer, msgID, ok := m.ExplicitLayerEvidenceForAuthKey(authKeyID, sessionID); !ok || layer != 226 || msgID != 1234 { + t.Fatalf("live explicit evidence = (%d,%d,%v)", layer, msgID, ok) + } + + inherited := &Conn{authKeyID: authKeyID, sessionID: sessionID + 1} + if err := inherited.SeedInheritedLayerProfile(tg.LayerProfile227); err != nil { + t.Fatal(err) + } + if err := m.Register(inherited); err != nil { + t.Fatal(err) + } + if layer, msgID, ok := m.ExplicitLayerEvidenceForAuthKey(authKeyID, sessionID+1); ok || layer != 0 || msgID != 0 { + t.Fatalf("inherited state exposed as explicit = (%d,%d,%v)", layer, msgID, ok) + } +} + +func TestSessionManagerExplicitLayerEvidenceChoosesNewestActiveOrClaim(t *testing.T) { + m := NewSessionManager(nil) + authKeyID := [8]byte{2, 3, 0} + const sessionID = int64(230) + active := &Conn{authKeyID: authKeyID, sessionID: sessionID} + claim := &Conn{authKeyID: authKeyID, sessionID: sessionID} + if err := active.seedOrderedLayerProfile(tg.LayerProfile225, 100); err != nil { + t.Fatal(err) + } + if err := claim.seedOrderedLayerProfile(tg.LayerProfile227, 104); err != nil { + t.Fatal(err) + } + key := sessionKey{authKeyID: authKeyID, sessionID: sessionID} + m.mu.Lock() + m.bySession[key] = active + m.claims[key] = claim + m.mu.Unlock() + if layer, msgID, ok := m.ExplicitLayerEvidenceForAuthKey(authKeyID, sessionID); !ok || layer != 227 || msgID != 104 { + t.Fatalf("newest active/claim evidence = (%d,%d,%v)", layer, msgID, ok) + } + + claim.retire() + if layer, msgID, ok := m.ExplicitLayerEvidenceForAuthKey(authKeyID, sessionID); !ok || layer != 225 || msgID != 100 { + t.Fatalf("retired claim shadowed active evidence = (%d,%d,%v)", layer, msgID, ok) + } +} + +func TestOrderedSessionLayerBroadcastConvergesAcrossPhysicalGenerations(t *testing.T) { + m := NewSessionManager(nil) + authKeyID := [8]byte{3, 0, 0} + const sessionID = int64(300) + oldPhysical := &Conn{authKeyID: authKeyID, sessionID: sessionID} + current := &Conn{authKeyID: authKeyID, sessionID: sessionID} + m.mu.Lock() + m.bySession[sessionKey{authKeyID: authKeyID, sessionID: sessionID}] = current + m.mu.Unlock() + + if applied, err := m.ApplyOrderedLayerProfileForSession(oldPhysical, authKeyID, sessionID, tg.LayerProfile227, 300); err != nil || applied != 2 { + t.Fatalf("newer broadcast applied=%d err=%v", applied, err) + } + if applied, err := m.ApplyOrderedLayerProfileForSession(oldPhysical, authKeyID, sessionID, tg.LayerProfile225, 200); err != nil || applied != 0 { + t.Fatalf("delayed older broadcast applied=%d err=%v", applied, err) + } + for name, c := range map[string]*Conn{"old": oldPhysical, "current": current} { + state, msgID := c.layerProfileEvidenceState() + if state.Profile != tg.LayerProfile227 || state.Origin != LayerProfileExplicit || msgID != 300 { + t.Fatalf("%s physical state = %#v msgID:%d", name, state, msgID) + } + } +} + +func TestInitialProfileSeedAvoidsPermanentKeyResolverAndPrefersPermForTemp(t *testing.T) { + t.Run("fetched permanent metadata is authoritative fast path", func(t *testing.T) { + resolver := &countingInheritedLayerResolver{layer: 225, found: true} + s := &Server{layerRPC: resolver} + c := &Conn{authKeyExpiresAt: 0} + if err := s.seedInitialLayerProfile(context.Background(), c, 227, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + if resolver.calls != 0 { + t.Fatalf("permanent resolver calls = %d, want 0", resolver.calls) + } + if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileInherited { + t.Fatalf("permanent seed = %#v", got) + } + }) + + t.Run("temporary key resolves permanent before raw shadow", func(t *testing.T) { + resolver := &countingInheritedLayerResolver{layer: 227, found: true} + s := &Server{layerRPC: resolver} + c := &Conn{authKeyExpiresAt: 1_900_000_000} + if err := s.seedInitialLayerProfile(context.Background(), c, 225, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + if resolver.calls != 1 { + t.Fatalf("temporary resolver calls = %d, want 1", resolver.calls) + } + if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileInherited { + t.Fatalf("temporary canonical seed = %#v", got) + } + }) + + t.Run("unsupported permanent metadata stays unknown", func(t *testing.T) { + resolver := &countingInheritedLayerResolver{layer: 227, found: true} + s := &Server{layerRPC: resolver} + c := &Conn{authKeyExpiresAt: 0} + if err := s.seedInitialLayerProfile(context.Background(), c, 229, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + if resolver.calls != 0 { + t.Fatalf("unsupported permanent metadata fell through to resolver") + } + if got := c.LayerProfileState(); got.Origin != LayerProfileUnknown { + t.Fatalf("unsupported permanent seed = %#v", got) + } + }) + + t.Run("unsupported bound permanent blocks raw temp shadow", func(t *testing.T) { + resolver := &countingInheritedLayerResolver{layer: 229, found: true} + s := &Server{layerRPC: resolver} + c := &Conn{authKeyExpiresAt: 1_900_000_000} + if err := s.seedInitialLayerProfile(context.Background(), c, 225, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + if got := c.LayerProfileState(); got.Origin != LayerProfileUnknown { + t.Fatalf("authoritative unsupported perm fell back to raw shadow = %#v", got) + } + }) +} + +func TestInitialProfileSeedRestoresOrderedExactSessionEvidence(t *testing.T) { + resolver := &orderedSessionLayerResolver{layer: 226, msgID: 123456, found: true} + s := &Server{layerRPC: resolver} + c := &Conn{authKeyExpiresAt: 0} + if err := s.seedInitialLayerProfile(context.Background(), c, 227, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + state, msgID := c.layerProfileEvidenceState() + if state.Profile != tg.LayerProfile226 || state.Origin != LayerProfileExplicit || msgID != resolver.msgID { + t.Fatalf("ordered exact seed = state:%#v msgID:%d", state, msgID) + } +} + +func TestInheritedLayerResolverFailureLeavesExplicitRecoveryAvailable(t *testing.T) { + resolverErr := errors.New("temporary resolver unavailable") + resolver := &countingInheritedLayerResolver{err: resolverErr} + s := &Server{layerRPC: resolver} + c := &Conn{authKeyExpiresAt: 1_900_000_000} + if err := s.seedInitialLayerProfile(context.Background(), c, 225, LayerProfileSnapshot{}); err != nil { + t.Fatalf("optional inherited resolver error escaped: %v", err) + } + if got := c.LayerProfileState(); got.Origin != LayerProfileUnknown { + t.Fatalf("resolver error selected stale fallback = %#v", got) + } +} + +func TestInheritedLayerResolverAvailabilityUsesOnlySupportedRawTempShadow(t *testing.T) { + for _, tt := range []struct { + name string + fetchedLayer int + wantProfile tg.LayerProfile + wantOrigin LayerProfileOrigin + }{ + {name: "supported raw shadow", fetchedLayer: 225, wantProfile: tg.LayerProfile225, wantOrigin: LayerProfileInherited}, + {name: "future raw shadow stays unknown", fetchedLayer: 229, wantOrigin: LayerProfileUnknown}, + } { + t.Run(tt.name, func(t *testing.T) { + resolver := &countingInheritedLayerResolver{err: layerDurabilityUnavailableTestError{}} + s := &Server{layerRPC: resolver} + c := &Conn{authKeyExpiresAt: 1_900_000_000} + if err := s.seedInitialLayerProfile(context.Background(), c, tt.fetchedLayer, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + if resolver.calls != 1 { + t.Fatalf("resolver calls=%d, want 1", resolver.calls) + } + if got := c.LayerProfileState(); got.Profile != tt.wantProfile || got.Origin != tt.wantOrigin { + t.Fatalf("availability seed = %#v, want profile=%d origin=%d", got, tt.wantProfile, tt.wantOrigin) + } + }) + } +} + +func TestActivationClaimRecheckClosesTempBindLayerRace(t *testing.T) { + authKeyID := [8]byte{4, 0, 0} + + t.Run("bind wins before claimed recheck", func(t *testing.T) { + resolver := &countingInheritedLayerResolver{found: false} + s := &Server{layerRPC: resolver} + m := NewSessionManager(nil) + c := &Conn{authKeyID: authKeyID, sessionID: 401, authKeyExpiresAt: 1_900_000_000} + if err := s.seedInitialLayerProfile(context.Background(), c, 225, LayerProfileSnapshot{}); err != nil { + t.Fatal(err) + } + if err := m.BeginActivation(c); err != nil { + t.Fatal(err) + } + defer m.AbortActivation(c) + resolver.layer, resolver.found = 227, true + if err := s.refreshActivatedInheritedLayerProfile(context.Background(), c, 225); err != nil { + t.Fatal(err) + } + if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileInherited { + t.Fatalf("post-claim permanent recheck = %#v", got) + } + }) + + t.Run("claim wins before bind refresh", func(t *testing.T) { + m := NewSessionManager(nil) + c := &Conn{authKeyID: authKeyID, sessionID: 402, authKeyExpiresAt: 1_900_000_000} + if err := c.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + if err := m.BeginActivation(c); err != nil { + t.Fatal(err) + } + defer m.AbortActivation(c) + if refreshed := m.RefreshInheritedLayerForRawAuthKey(authKeyID, 227); refreshed != 1 { + t.Fatalf("bind refresh count = %d, want 1", refreshed) + } + if got := c.LayerProfileState(); got.Profile != tg.LayerProfile227 || got.Origin != LayerProfileInherited { + t.Fatalf("claim-visible bind refresh = %#v", got) + } + }) + + t.Run("unsupported permanent clears preclaim raw shadow", func(t *testing.T) { + resolver := &countingInheritedLayerResolver{layer: 229, found: true} + s := &Server{layerRPC: resolver} + c := &Conn{authKeyID: authKeyID, sessionID: 403, authKeyExpiresAt: 1_900_000_000} + if err := c.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + if err := s.refreshActivatedInheritedLayerProfile(context.Background(), c, 225); err != nil { + t.Fatal(err) + } + if got := c.LayerProfileState(); got.Origin != LayerProfileUnknown { + t.Fatalf("unsupported permanent kept stale raw shadow = %#v", got) + } + }) + + t.Run("availability outage retains current raw shadow", func(t *testing.T) { + resolver := &countingInheritedLayerResolver{err: layerDurabilityUnavailableTestError{}} + s := &Server{layerRPC: resolver} + c := &Conn{authKeyID: authKeyID, sessionID: 404, authKeyExpiresAt: 1_900_000_000} + if err := s.refreshActivatedInheritedLayerProfile(context.Background(), c, 225); err != nil { + t.Fatal(err) + } + if got := c.LayerProfileState(); got.Profile != tg.LayerProfile225 || got.Origin != LayerProfileInherited { + t.Fatalf("availability recheck lost raw shadow = %#v", got) + } + }) + + t.Run("structural resolver failure clears preclaim raw shadow", func(t *testing.T) { + resolver := &countingInheritedLayerResolver{err: errors.New("invalid binding identity")} + s := &Server{layerRPC: resolver} + c := &Conn{authKeyID: authKeyID, sessionID: 405, authKeyExpiresAt: 1_900_000_000} + if err := c.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + if err := s.refreshActivatedInheritedLayerProfile(context.Background(), c, 225); err != nil { + t.Fatal(err) + } + if got := c.LayerProfileState(); got.Origin != LayerProfileUnknown { + t.Fatalf("structural resolver failure retained raw shadow = %#v", got) + } + }) +} diff --git a/internal/mtprotoedge/layer_rpc_execution.go b/internal/mtprotoedge/layer_rpc_execution.go new file mode 100644 index 00000000..7e075c7d --- /dev/null +++ b/internal/mtprotoedge/layer_rpc_execution.go @@ -0,0 +1,282 @@ +package mtprotoedge + +import ( + "context" + "errors" + "time" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" + "go.uber.org/zap" + + "telesrv/internal/observability/dbtrace" + "telesrv/internal/postresponse" +) + +// layerRPCResultEncoder keeps the generated result bound to the immutable +// admitted call, but deliberately does not prepare a second byte snapshot in +// the inbound worker. The only Encode call happens later under outbound encode +// and retained-byte admission. +type layerRPCResultEncoder struct { + call tg.LayerCall + result tg.LayerRPCResult +} + +func (e *layerRPCResultEncoder) Encode(b *bin.Buffer) error { + if e == nil { + return errors.New("nil layer RPC result") + } + if e.result == nil { + return errors.New("nil generated layer RPC result") + } + return e.result.Encode(b) +} + +func (e *layerRPCResultEncoder) exactLayerRPCResultBinding() outboundLayerBinding { + if e == nil { + return outboundLayerBinding{} + } + return outboundLayerBinding{ + profile: e.call.Profile(), + typ: e.call.WireResultType(), + wireInvariant: e.call.WireInvariant(), + kind: outboundLayerBindingRequest, + } +} + +type exactLayerRPCResultEncoder interface { + bin.Encoder + exactLayerRPCResultBinding() outboundLayerBinding +} + +// legacyTestRPCResultEncoder migrates the unexported legacyRPC package-test +// hook onto the generated result codec. The hook may still exercise the old +// scheduling API, but it no longer has a canonical-bytes escape hatch. +type legacyTestRPCResultEncoder struct { + call tg.LayerCall + result bin.Encoder +} + +func (e *legacyTestRPCResultEncoder) Encode(b *bin.Buffer) error { + if e == nil || e.result == nil { + return errors.New("nil legacy test RPC result") + } + return e.call.EncodeResult(e.result, b) +} + +func (e *legacyTestRPCResultEncoder) exactLayerRPCResultBinding() outboundLayerBinding { + if e == nil { + return outboundLayerBinding{} + } + return outboundLayerBinding{ + profile: e.call.Profile(), + typ: e.call.WireResultType(), + wireInvariant: e.call.WireInvariant(), + kind: outboundLayerBindingRequest, + } +} + +var errLayerRPCResultIdentityMismatch = errors.New("layer RPC result does not match admitted request identity") + +// bindAdmittedLayerRPCResult closes the integration boundary around the +// generated dispatcher. A LayerRPCHandler implementation must return the +// result capability created from this exact admission; accepting a result from +// another request would pair the wrong result TypeRef/profile with this +// flight/cache identity even when both methods happen to share a Go type. +func bindAdmittedLayerRPCResult(request tg.LayerRequest, result tg.LayerRPCResult) (*layerRPCResultEncoder, error) { + if result == nil { + return nil, nil + } + if result.Prepared().Identity() != request.Prepared().Identity() { + return nil, errLayerRPCResultIdentityMismatch + } + return &layerRPCResultEncoder{call: request.Call(), result: result}, nil +} + +func (s *Server) newInboundLayerRPCTask( + c *Conn, + msgID int64, + admissionSeq uint64, + method string, + profileEvidenceFresh bool, + request tg.LayerRequest, + dependencies layerRPCDependencySet, + owner *rpcResultOwnerLease, +) inboundRPC { + wireSize := request.Prepared().WireSize() + gate := newLayerRPCExecutionGate(c, dependencies) + timeoutResponse := func() { + writeTimeout := c.writeTimeout + if writeTimeout <= 0 || writeTimeout > 5*time.Second { + writeTimeout = 5 * time.Second + } + responseCtx, cancel := context.WithTimeout(context.Background(), writeTimeout) + defer cancel() + if sendErr := s.sendResult(responseCtx, c, msgID, &mt.RPCError{ + ErrorCode: 500, ErrorMessage: layerRPCTimeoutMessage(gate), + }); sendErr != nil && !isClientDisconnect(sendErr) { + s.log.Debug("Send RPC timeout failed", + zap.String("method", method), zap.Int64("msg_id", msgID), + zap.String("auth_key_id", c.authKeyHex), zap.Int64("session_id", c.sessionID), + zap.Error(sendErr)) + } + } + return inboundRPC{ + method: method, + size: wireSize, + onTimeout: timeoutResponse, + release: func() { + if owner != nil && owner.Abort() { + c.fenceUndeliveredRPCResult() + } + }, + gate: gate, + run: func(taskCtx context.Context) error { + if gate != nil && !gate.success() { + return s.publishAdmittedLayerRPCResult(c, msgID, method, owner, false, &mt.RPCError{ + ErrorCode: 500, ErrorMessage: "MSG_WAIT_FAILED", + }, nil) + } + if err := s.handleAdmittedLayerRPC(s.withLayerRPCProfileEvidenceFresh(taskCtx, profileEvidenceFresh), c, msgID, admissionSeq, method, request, owner); err != nil { + fields := []zap.Field{ + zap.Int64("msg_id", msgID), zap.String("auth_key_id", c.authKeyHex), + zap.Int64("session_id", c.sessionID), zap.Error(err), + } + if isClientDisconnect(err) { + s.log.Debug("RPC async handler canceled", fields...) + } else { + s.log.Info("RPC async handler failed", fields...) + } + return err + } + return nil + }, + } +} + +func layerRPCTimeoutMessage(gate *inboundRPCGate) string { + if gate != nil && !gate.runnable() { + return "MSG_WAIT_TIMEOUT" + } + return "RPC_TIMEOUT" +} + +func newLayerRPCExecutionGate(c *Conn, dependencies layerRPCDependencySet) *inboundRPCGate { + if len(dependencies.waiters) == 0 && !dependencies.failed { + return nil + } + gate := newInboundRPCGate(len(dependencies.waiters), c.wakeInboundRPC) + if dependencies.failed { + gate.failed.Store(true) + } + for _, waiter := range dependencies.waiters { + if err := waiter.SubscribeExecution(gate.resolve); err != nil { + gate.resolve(false) + } + } + // Release the subscriber-installation sentinel. + gate.resolve(true) + return gate +} + +func (s *Server) publishAdmittedLayerRPCResult( + c *Conn, + msgID int64, + method string, + owner *rpcResultOwnerLease, + success bool, + result bin.Encoder, + after func(), +) error { + if owner != nil { + owner.CompleteExecution(success) + } + return s.publishRPCResult(c, msgID, method, owner, result, after) +} + +func (s *Server) handleAdmittedLayerRPC( + ctx context.Context, + c *Conn, + msgID int64, + admissionSeq uint64, + method string, + request tg.LayerRequest, + owner *rpcResultOwnerLease, +) error { + if s.layerRPC == nil { + return s.publishAdmittedLayerRPCResult(c, msgID, method, owner, false, &mt.RPCError{ + ErrorCode: 500, ErrorMessage: "NOT_IMPLEMENTED", + }, nil) + } + ctx = postresponse.WithCallbacks(ctx) + ctx, dbStats := dbtrace.WithStats(ctx) + start := s.clock.Now() + result, effectiveMethod, err := s.layerRPC.DispatchAdmitted(ctx, c.authKeyID, c.sessionID, msgID, admissionSeq, request) + businessSucceeded := err == nil + if effectiveMethod == "" { + effectiveMethod = method + } + var exact *layerRPCResultEncoder + if err == nil && result != nil { + exact, err = bindAdmittedLayerRPCResult(request, result) + } + dur := s.clock.Now().Sub(start) + s.metrics.RPCHandled(effectiveMethod, dur, err) + fields := []zap.Field{ + zap.String("method", effectiveMethod), zap.String("auth_key_id", c.authKeyHex), + zap.Int64("session_id", c.sessionID), zap.Int64("msg_id", msgID), + zap.Int("profile", int(request.Call().Profile())), zap.Duration("dur", dur), + } + if effectiveMethod != method { + fields = append(fields, zap.String("outer_method", method)) + } + if businessAuthKeyHex, ok := c.BusinessAuthKeyHex(); ok { + fields = append(fields, zap.String("business_auth_key_id", businessAuthKeyHex)) + } + if userID := c.UserID(); userID != 0 { + fields = append(fields, zap.Int64("user_id", userID)) + } + fields = dbtrace.AppendZapFields(fields, "", dbStats.Snapshot()) + + if ctxErr := ctx.Err(); ctxErr != nil { + var terminal bin.Encoder + var after func() + if err == nil && exact != nil { + terminal = exact + after = postresponse.Take(context.WithoutCancel(ctx)) + } else if errors.Is(ctxErr, context.DeadlineExceeded) { + terminal = &mt.RPCError{ErrorCode: 500, ErrorMessage: "RPC_TIMEOUT"} + } + if terminal != nil { + if sendErr := s.publishAdmittedLayerRPCResult(c, msgID, effectiveMethod, owner, err == nil && exact != nil, terminal, after); sendErr != nil { + s.log.Debug("Publish canceled RPC result failed", append(fields, zap.Error(sendErr))...) + } + } + s.log.Info("RPC canceled", append(fields, zap.NamedError("context_error", ctxErr))...) + return ctxErr + } + if err != nil { + var rpcErr *tgerr.Error + if errors.As(err, &rpcErr) { + s.log.Info("RPC error", append(fields, zap.Int("code", rpcErr.Code), zap.String("error", rpcErr.Message))...) + return s.publishAdmittedLayerRPCResult(c, msgID, effectiveMethod, owner, businessSucceeded, &mt.RPCError{ + ErrorCode: rpcErr.Code, ErrorMessage: rpcErr.Message, + }, nil) + } + s.log.Info("RPC internal error", append(fields, zap.Error(err))...) + return s.publishAdmittedLayerRPCResult(c, msgID, effectiveMethod, owner, businessSucceeded, &mt.RPCError{ + ErrorCode: 500, ErrorMessage: "INTERNAL", + }, nil) + } + if exact == nil { + return s.publishAdmittedLayerRPCResult(c, msgID, effectiveMethod, owner, businessSucceeded, &mt.RPCError{ + ErrorCode: 500, ErrorMessage: "INTERNAL", + }, nil) + } + s.log.Info("RPC handled", fields...) + return s.publishAdmittedLayerRPCResult(c, msgID, effectiveMethod, owner, true, exact, postresponse.Take(ctx)) +} + +var _ exactLayerRPCResultEncoder = (*layerRPCResultEncoder)(nil) diff --git a/internal/mtprotoedge/layer_rpc_execution_test.go b/internal/mtprotoedge/layer_rpc_execution_test.go new file mode 100644 index 00000000..97f31875 --- /dev/null +++ b/internal/mtprotoedge/layer_rpc_execution_test.go @@ -0,0 +1,153 @@ +package mtprotoedge + +import ( + "context" + "errors" + "sync/atomic" + "testing" + "time" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" +) + +// preparedOnlyLayerRPCResult is intentionally incapable of encoding. The +// binding guard must reject it solely from immutable admission identity before +// any result method other than Prepared can be observed. +type preparedOnlyLayerRPCResult struct { + tg.LayerRPCResult + prepared tg.LayerPreparedCall +} + +func (r *preparedOnlyLayerRPCResult) Prepared() tg.LayerPreparedCall { return r.prepared } + +func TestBindAdmittedLayerRPCResultRequiresExactRequestIdentity(t *testing.T) { + dispatcher := tg.NewServerDispatcher(nil) + admit := func(request bin.Encoder) tg.LayerRequest { + t.Helper() + body := &bin.Buffer{Buf: exactLayerRPCBody(t, request)} + admitted, err := dispatcher.AdmitLayer(tg.LayerProfile227, body) + if err != nil { + t.Fatal(err) + } + return admitted + } + + request := admit(&tg.HelpGetConfigRequest{}) + other := admit(&tg.HelpGetNearestDCRequest{}) + + if _, err := bindAdmittedLayerRPCResult(request, &preparedOnlyLayerRPCResult{prepared: other.Prepared()}); !errors.Is(err, errLayerRPCResultIdentityMismatch) { + t.Fatalf("mismatched result error = %v, want %v", err, errLayerRPCResultIdentityMismatch) + } + + bound, err := bindAdmittedLayerRPCResult(request, &preparedOnlyLayerRPCResult{prepared: request.Prepared()}) + if err != nil { + t.Fatal(err) + } + if bound == nil || bound.call.Identity() != request.Call().Identity() { + t.Fatal("matching result did not retain the admitted call identity") + } +} + +type mismatchedProjectionLayerRPC struct { + *admissionOnlyLayerRPC + result tg.LayerRPCResult + calls atomic.Int32 +} + +func (h *mismatchedProjectionLayerRPC) DispatchAdmitted( + context.Context, + [8]byte, + int64, + int64, + uint64, + tg.LayerRequest, +) (tg.LayerRPCResult, string, error) { + h.calls.Add(1) + return h.result, "help.getConfig", nil +} + +func TestProjectionFailureCachesInternalWithoutRepeatingBusiness(t *testing.T) { + dispatcher := tg.NewServerDispatcher(nil) + admit := func(request bin.Encoder) tg.LayerRequest { + t.Helper() + body := &bin.Buffer{Buf: exactLayerRPCBody(t, request)} + admitted, err := dispatcher.AdmitLayer(tg.LayerProfile227, body) + if err != nil { + t.Fatal(err) + } + return admitted + } + request := admit(&tg.HelpGetConfigRequest{}) + other := admit(&tg.HelpGetNearestDCRequest{}) + handler := &mismatchedProjectionLayerRPC{ + admissionOnlyLayerRPC: newAdmissionOnlyLayerRPC(), + result: &preparedOnlyLayerRPCResult{prepared: other.Prepared()}, + } + s := New(Options{DC: 2, LayerRPC: handler}) + c := newOutboundTestConn(t, &collectingSessionTransport{}, newOutboundTrackedBudget(1<<20)) + c.authKeyID = [8]byte{0x41, 0x01} + c.sessionID = 4101 + const reqMsgID = int64(410100) + claim, err := s.rpcResults.AcquireLayerIdentified( + c.authKeyID, c.sessionID, reqMsgID, + tg.LayerProfile227, request.Prepared().Identity(), + ) + if err != nil || claim.owner == nil { + t.Fatalf("owner acquisition err=%v", err) + } + if err := s.handleAdmittedLayerRPC( + context.Background(), c, reqMsgID, claim.admissionSeq, + "help.getConfig", request, claim.owner, + ); err != nil { + t.Fatalf("publish projection failure: %v", err) + } + + deadline := time.Now().Add(2 * time.Second) + var completed rpcResultAcquire + for { + completed, err = s.rpcResults.AcquireLayerIdentified( + c.authKeyID, c.sessionID, reqMsgID, + tg.LayerProfile227, request.Prepared().Identity(), + ) + if err == nil && completed.state == rpcResultAcquireCompleted { + break + } + if time.Now().After(deadline) { + t.Fatalf("projection failure did not become completed: state=%d err=%v", completed.state, err) + } + time.Sleep(time.Millisecond) + } + if !completed.executionKnown || !completed.executionOK { + t.Fatalf("projection failure lost successful business outcome: known=%v ok=%v", completed.executionKnown, completed.executionOK) + } + if got := handler.calls.Load(); got != 1 { + t.Fatalf("business calls=%d, want 1", got) + } + var envelope proto.Result + if err := envelope.Decode(&bin.Buffer{Buf: completed.encoded.body}); err != nil { + t.Fatal(err) + } + var rpcErr mt.RPCError + if err := rpcErr.Decode(&bin.Buffer{Buf: envelope.Result}); err != nil { + t.Fatal(err) + } + if rpcErr.ErrorCode != 500 || rpcErr.ErrorMessage != "INTERNAL" { + t.Fatalf("projection terminal = %+v", rpcErr) + } + // A same-msg replay is served from the completed exact identity; there is no + // second DispatchAdmitted call even though projection failed after business + // success. + replay, err := s.rpcResults.AcquireLayerIdentified( + c.authKeyID, c.sessionID, reqMsgID, + tg.LayerProfile227, request.Prepared().Identity(), + ) + if err != nil || replay.state != rpcResultAcquireCompleted || replay.encoded != completed.encoded { + t.Fatalf("projection replay = state:%d err:%v", replay.state, err) + } + if got := handler.calls.Load(); got != 1 { + t.Fatalf("replay repeated business calls=%d", got) + } +} diff --git a/internal/mtprotoedge/layer_seed_test.go b/internal/mtprotoedge/layer_seed_test.go index 7fe4e909..619e3c01 100644 --- a/internal/mtprotoedge/layer_seed_test.go +++ b/internal/mtprotoedge/layer_seed_test.go @@ -5,33 +5,12 @@ import ( "testing" "time" - "go.uber.org/zap/zaptest" - - "github.com/gotd/td/bin" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) -func TestSessionManagerSetClientLayerForAuthKey(t *testing.T) { - sm := NewSessionManager(zaptest.NewLogger(t)) - c := &Conn{sessionID: 42, authKeyID: [8]byte{1, 2, 3}} - sm.Register(c) - defer sm.Unregister(c) - - sm.SetClientLayerForAuthKey([8]byte{1, 2, 3}, 42, 225) - if got := c.ClientLayer(); got != 225 { - t.Fatalf("ClientLayer = %d, want 225", got) - } - // 未注册 session:no-op,不 panic。 - sm.SetClientLayerForAuthKey([8]byte{9}, 1, 220) - // 非法 layer:忽略,保留已有值。 - sm.SetClientLayerForAuthKey([8]byte{1, 2, 3}, 42, 0) - if got := c.ClientLayer(); got != 225 { - t.Fatalf("ClientLayer after layer=0 = %d, want 225", got) - } -} - type seededLayerRPC struct{} func (seededLayerRPC) Dispatch(context.Context, [8]byte, int64, *bin.Buffer) (bin.Encoder, error) { @@ -45,7 +24,7 @@ func (seededLayerRPC) NegotiatedLayer([8]byte, int64) (int, bool) { return 225, // 而不是等首条 RPC 的 Dispatch 返回后才刷新——否则重连老客户端在首条 RPC handler // 执行期间收到的 pending flush / 并发 push 会按 canonical 227 漏降级。 func TestRegisterSeedsNegotiatedLayerBeforeFirstRPC(t *testing.T) { - addr, pub, srv := startTestServer(t, Options{DC: 2, RPC: seededLayerRPC{}}) + addr, pub, srv := startTestServer(t, Options{DC: 2, legacyRPC: seededLayerRPC{}}) conn, auth, cipher := dialHandshake(t, addr, 2, pub) clientMsgID := proto.NewMessageIDGen(time.Now) @@ -67,7 +46,7 @@ func TestRegisterSeedsNegotiatedLayerBeforeFirstRPC(t *testing.T) { if c == nil { t.Fatal("connection not registered") } - if got := c.ClientLayer(); got != 225 { + if got := c.legacyClientLayer(); got != 225 { t.Fatalf("ClientLayer after registration = %d, want seeded 225", got) } } diff --git a/internal/mtprotoedge/layer_updates.go b/internal/mtprotoedge/layer_updates.go new file mode 100644 index 00000000..f427325a --- /dev/null +++ b/internal/mtprotoedge/layer_updates.go @@ -0,0 +1,235 @@ +package mtprotoedge + +import ( + "context" + "errors" + "fmt" + "sync" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/tg" +) + +var ( + ErrOutboundLayerProfileUnknown = errors.New("outbound exact layer profile is unknown") + ErrOutboundLayerProfileMismatch = errors.New("outbound exact layer profile mismatch") + // ErrOutboundLayerBindingRequired means application bytes reached the edge + // without the request- or session-owned profile proof required by the native + // generated codec. Never substitute canonical bytes or the retired legacy + // transcoder on a production connection. + ErrOutboundLayerBindingRequired = errors.New("outbound application value requires exact layer binding") + // ErrOutboundLayerProfileStale means a proactive update was prepared for an + // older connection profile epoch. It is deliberately non-terminal: discard + // the online accelerator and let durable difference recovery fill the gap. + ErrOutboundLayerProfileStale = errors.New("outbound exact layer profile epoch is stale") +) + +type outboundLayerBindingKind uint8 + +const ( + // The zero value preserves strict connection binding for defensive and + // legacy constructions which do not declare a stronger ownership model. + outboundLayerBindingSession outboundLayerBindingKind = iota + // A request-bound result retains the profile captured by admission. A later + // invokeWithLayer correction must not invalidate that in-flight/cached result. + outboundLayerBindingRequest +) + +type outboundLayerBinding struct { + profile tg.LayerProfile + typ *tg.LayerTypeRef + wireInvariant bool + kind outboundLayerBindingKind + // epoch is required for proactive updates. Zero is accepted only for older + // defensive/test bindings which predate mutable profile correction. + epoch uint32 +} + +type preparedLayerUpdates struct { + done chan struct{} + encoded *encodedOutboundMessage + err error +} + +// layerUpdatesFanout is one immutable canonical Updates snapshot plus a +// request-scoped cache of exact prepared bytes. FreezeLayer and +// PrepareFrozenLayer are the same generated TypeRef codec used by RPC results +// and differences; this type adds only fan-out singleflight and ownership. +type layerUpdatesFanout struct { + frozen tg.LayerFrozen[tg.UpdatesClass] + size int + + mu sync.Mutex + prepared map[tg.LayerProfile]*preparedLayerUpdates +} + +func newLayerUpdatesFanout(value tg.UpdatesClass) (*layerUpdatesFanout, error) { + frozen, err := tg.FreezeLayer(tg.LayerClassUpdatesType(), value) + if err != nil { + return nil, fmt.Errorf("freeze exact layer updates: %w", err) + } + return &layerUpdatesFanout{ + frozen: frozen, + size: frozen.CanonicalSize(), + prepared: make(map[tg.LayerProfile]*preparedLayerUpdates), + }, nil +} + +func (u *layerUpdatesFanout) canonicalSize() int { + if u == nil { + return 0 + } + return u.size +} + +func (u *layerUpdatesFanout) prepareForConn(ctx context.Context, c *Conn) (*encodedOutboundMessage, error) { + if u == nil || c == nil { + return nil, errors.New("nil exact layer update or connection") + } + state := c.LayerProfileState() + if state.Origin == LayerProfileUnknown { + return nil, ErrOutboundLayerProfileUnknown + } + base, err := u.prepare(ctx, state.Profile) + if err != nil { + return nil, err + } + if base == nil || base.layer == nil { + return nil, errors.New("prepared exact layer update lost binding") + } + // Exact bytes stay shared per profile. Only the small binding is copied per + // physical target because epoch belongs to that connection. + encoded := *base + binding := *base.layer + binding.kind = outboundLayerBindingSession + binding.epoch = state.Epoch + encoded.layer = &binding + return &encoded, nil +} + +func (u *layerUpdatesFanout) prepare(ctx context.Context, profile tg.LayerProfile) (*encodedOutboundMessage, error) { + if ctx == nil { + ctx = context.Background() + } + u.mu.Lock() + entry := u.prepared[profile] + if entry == nil { + entry = &preparedLayerUpdates{done: make(chan struct{})} + u.prepared[profile] = entry + u.mu.Unlock() + + entry.encoded, entry.err = prepareFrozenLayerUpdatesContext(ctx, profile, u.frozen) + close(entry.done) + if entry.err != nil { + // Context/encode admission failure is attempt-local. Do not poison this + // semantic update for every later connection or pending-flush retry. + u.mu.Lock() + if u.prepared[profile] == entry { + delete(u.prepared, profile) + } + u.mu.Unlock() + } + } else { + u.mu.Unlock() + // A completed profile is immutable and no longer needs caller budget. + // Prefer it deterministically even when the shared fan-out deadline became + // ready at the same instant; otherwise Go's select may randomly choose the + // canceled branch and skip a healthy later connection of the same profile. + select { + case <-entry.done: + return entry.encoded, entry.err + default: + } + select { + case <-entry.done: + case <-ctx.Done(): + return nil, ctx.Err() + } + } + return entry.encoded, entry.err +} + +func (u *layerUpdatesFanout) discardPrepared(profile tg.LayerProfile, encoded *encodedOutboundMessage) { + if u == nil || encoded == nil { + return + } + u.mu.Lock() + entry := u.prepared[profile] + if entry != nil { + select { + case <-entry.done: + if entry.encoded == encoded || (entry.encoded != nil && + entry.encoded.layer != nil && encoded.layer != nil && + entry.encoded.layer.profile == encoded.layer.profile && + sameBacking(entry.encoded.body, encoded.body)) { + delete(u.prepared, profile) + } + default: + } + } + u.mu.Unlock() +} + +func prepareFrozenLayerUpdatesContext( + ctx context.Context, + profile tg.LayerProfile, + frozen tg.LayerFrozen[tg.UpdatesClass], +) (*encodedOutboundMessage, error) { + var encoded *encodedOutboundMessage + err := withOutboundEncodeSlot(ctx, nil, func() error { + prepared, err := tg.PrepareFrozenLayer(profile, frozen) + if err != nil { + return err + } + var body bin.Buffer + typ := tg.LayerClassUpdatesType() + if err := prepared.Encode(profile, typ, &body); err != nil { + return err + } + id, err := body.PeekID() + if err != nil { + return fmt.Errorf("peek exact updates constructor: %w", err) + } + encoded = &encodedOutboundMessage{ + body: body.Copy(), typeID: id, + layer: &outboundLayerBinding{profile: profile, typ: prepared.TypeRef()}, + } + return nil + }) + if err != nil { + return nil, fmt.Errorf("prepare updates for layer %d: %w", profile, err) + } + return encoded, nil +} + +func validateOutboundLayerBinding(c *Conn, encoded *encodedOutboundMessage) error { + if encoded == nil || encoded.layer == nil { + return nil + } + if encoded.layer.typ == nil { + return errors.New("outbound exact layer TypeRef is nil") + } + if encoded.layer.wireInvariant || encoded.layer.kind == outboundLayerBindingRequest { + return nil + } + state := c.LayerProfileState() + if state.Origin == LayerProfileUnknown { + return ErrOutboundLayerProfileUnknown + } + if encoded.layer.epoch != 0 && state.Epoch != encoded.layer.epoch { + return fmt.Errorf("%w: connection=%d encoded=%d", ErrOutboundLayerProfileStale, state.Epoch, encoded.layer.epoch) + } + if state.Profile != encoded.layer.profile { + return fmt.Errorf("%w: connection=%d encoded=%d", ErrOutboundLayerProfileMismatch, state.Profile, encoded.layer.profile) + } + return nil +} + +func isOutboundStaleLayerEpoch(err error) bool { + return errors.Is(err, ErrOutboundLayerProfileStale) +} + +func isOutboundLayerProfileError(err error) bool { + return errors.Is(err, ErrOutboundLayerProfileUnknown) || + errors.Is(err, ErrOutboundLayerProfileMismatch) +} diff --git a/internal/mtprotoedge/layer_updates_test.go b/internal/mtprotoedge/layer_updates_test.go new file mode 100644 index 00000000..12227cb0 --- /dev/null +++ b/internal/mtprotoedge/layer_updates_test.go @@ -0,0 +1,326 @@ +package mtprotoedge + +import ( + "context" + "errors" + "fmt" + "io" + "sync" + "testing" + "time" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/tg" +) + +type epochBlockingTransport struct { + started chan struct{} + release chan struct{} + startedOnce sync.Once + closeOnce sync.Once +} + +func newEpochBlockingTransport() *epochBlockingTransport { + return &epochBlockingTransport{started: make(chan struct{}), release: make(chan struct{})} +} + +func (t *epochBlockingTransport) Send(context.Context, *bin.Buffer) error { + t.startedOnce.Do(func() { close(t.started) }) + <-t.release + return nil +} + +func (t *epochBlockingTransport) Recv(context.Context, *bin.Buffer) error { return io.EOF } +func (t *epochBlockingTransport) Close() error { + t.closeOnce.Do(func() { close(t.release) }) + return nil +} + +func testLayerUpdatesValue(expires int) tg.UpdatesClass { + return &tg.UpdateShort{ + Update: &tg.UpdateUserStatus{ + UserID: 42, + Status: &tg.UserStatusOnline{ + Expires: expires, + }, + }, + Date: 1_900_000_000, + } +} + +func testLayerChannelUpdatesValue(expires int) tg.UpdatesClass { + return &tg.Updates{ + Updates: []tg.UpdateClass{ + &tg.UpdateUserStatus{ + UserID: 42, + Status: &tg.UserStatusOnline{ + Expires: expires, + }, + }, + }, + Users: []tg.UserClass{}, + Chats: []tg.ChatClass{testLayerChannel()}, + Date: 1_900_000_000, + Seq: 1, + } +} + +func testConnWithLayerProfile(t *testing.T, profile tg.LayerProfile) *Conn { + t.Helper() + c := &Conn{} + if err := c.FreezeLayerProfile(profile); err != nil { + t.Fatalf("freeze profile %d: %v", profile, err) + } + return c +} + +func TestLayerUpdatesFanoutPreparesExactMixedProfiles(t *testing.T) { + fanout, err := newLayerUpdatesFanout(testLayerUpdatesValue(123)) + if err != nil { + t.Fatalf("freeze updates: %v", err) + } + for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227, tg.LayerProfile228} { + t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) { + c := testConnWithLayerProfile(t, profile) + encoded, err := fanout.prepareForConn(context.Background(), c) + if err != nil { + t.Fatalf("prepare profile %d: %v", profile, err) + } + if encoded.layer == nil || encoded.layer.profile != profile { + t.Fatalf("binding = %#v, want profile %d", encoded.layer, profile) + } + input := bin.Buffer{Buf: encoded.body} + decoded, err := tg.DecodeLayer(profile, tg.LayerClassUpdatesType(), &input) + if err != nil { + t.Fatalf("decode profile %d: %v", profile, err) + } + if input.Len() != 0 { + t.Fatalf("profile %d left %d trailing bytes", profile, input.Len()) + } + short, ok := decoded.(*tg.UpdateShort) + if !ok { + t.Fatalf("decoded %T, want *tg.UpdateShort", decoded) + } + statusUpdate, ok := short.Update.(*tg.UpdateUserStatus) + if !ok { + t.Fatalf("nested update %T, want *tg.UpdateUserStatus", short.Update) + } + status, ok := statusUpdate.Status.(*tg.UserStatusOnline) + if !ok || status.Expires != 123 { + t.Fatalf("decoded status = %#v", statusUpdate.Status) + } + }) + } +} + +func TestLayerUpdatesFanoutFreezesDefensivelyAndSharesPreparedProfile(t *testing.T) { + value := testLayerUpdatesValue(123) + fanout, err := newLayerUpdatesFanout(value) + if err != nil { + t.Fatalf("freeze updates: %v", err) + } + value.(*tg.UpdateShort).Update.(*tg.UpdateUserStatus).Status.(*tg.UserStatusOnline).Expires = 999 + + c := testConnWithLayerProfile(t, tg.LayerProfile225) + const workers = 16 + prepared := make([]*encodedOutboundMessage, workers) + prepareErrs := make([]error, workers) + var wg sync.WaitGroup + for i := range prepared { + wg.Add(1) + go func(i int) { + defer wg.Done() + prepared[i], prepareErrs[i] = fanout.prepareForConn(context.Background(), c) + }(i) + } + wg.Wait() + for i, prepareErr := range prepareErrs { + if prepareErr != nil { + t.Fatalf("prepare %d: %v", i, prepareErr) + } + } + for i := 1; i < len(prepared); i++ { + if !sameBacking(prepared[i].body, prepared[0].body) { + t.Fatalf("profile preparation %d did not share immutable bytes", i) + } + if prepared[i].layer == prepared[0].layer || prepared[i].layer.epoch != prepared[0].layer.epoch { + t.Fatalf("profile preparation %d did not retain per-target epoch binding", i) + } + } + + input := bin.Buffer{Buf: prepared[0].body} + decoded, err := tg.DecodeLayer(tg.LayerProfile225, tg.LayerClassUpdatesType(), &input) + if err != nil { + t.Fatalf("decode frozen value: %v", err) + } + status := decoded.(*tg.UpdateShort).Update.(*tg.UpdateUserStatus).Status.(*tg.UserStatusOnline) + if status.Expires != 123 { + t.Fatalf("frozen value mutated: expires=%d", status.Expires) + } +} + +func TestLayerUpdatesEpochBecomesStaleWithoutRetiringProfile(t *testing.T) { + fanout, err := newLayerUpdatesFanout(testLayerUpdatesValue(123)) + if err != nil { + t.Fatal(err) + } + c := &Conn{} + if err := c.SeedInheritedLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + encoded, err := fanout.prepareForConn(context.Background(), c) + if err != nil { + t.Fatal(err) + } + oldEpoch := encoded.layer.epoch + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatal(err) + } + if err := validateOutboundLayerBinding(c, encoded); !errors.Is(err, ErrOutboundLayerProfileStale) { + t.Fatalf("old push validation = %v, want ErrOutboundLayerProfileStale", err) + } + state := c.LayerProfileState() + if state.Profile != tg.LayerProfile227 || state.Origin != LayerProfileExplicit || state.Epoch <= oldEpoch { + t.Fatalf("corrected profile state = %#v, old epoch %d", state, oldEpoch) + } +} + +func TestRequestBoundLayerResultSurvivesConnectionCorrection(t *testing.T) { + fanout, err := newLayerUpdatesFanout(testLayerUpdatesValue(123)) + if err != nil { + t.Fatal(err) + } + c := testConnWithLayerProfile(t, tg.LayerProfile225) + encoded, err := fanout.prepare(context.Background(), tg.LayerProfile225) + if err != nil { + t.Fatal(err) + } + encoded.layer.kind = outboundLayerBindingRequest + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatal(err) + } + if err := validateOutboundLayerBinding(c, encoded); err != nil { + t.Fatalf("request-bound old-profile result rejected after correction: %v", err) + } +} + +func TestProfileCorrectionLinearizesAfterStartedPushWrite(t *testing.T) { + transport := newEpochBlockingTransport() + c := newOutboundTestConn(t, transport, nil) + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + fanout, err := newLayerUpdatesFanout(testLayerUpdatesValue(123)) + if err != nil { + t.Fatal(err) + } + encoded, err := fanout.prepareForConn(context.Background(), c) + if err != nil { + t.Fatal(err) + } + if err := c.SendBestEffortEncoded(context.Background(), 0, encoded, 0); err != nil { + t.Fatal(err) + } + select { + case <-transport.started: + case <-time.After(time.Second): + t.Fatal("profile-bound push did not enter physical write") + } + + corrected := make(chan error, 1) + go func() { corrected <- c.FreezeLayerProfile(tg.LayerProfile227) }() + select { + case err := <-corrected: + t.Fatalf("profile correction crossed an old-epoch physical write: %v", err) + case <-time.After(50 * time.Millisecond): + } + if err := transport.Close(); err != nil { + t.Fatal(err) + } + select { + case err := <-corrected: + if err != nil { + t.Fatal(err) + } + case <-time.After(time.Second): + t.Fatal("profile correction did not continue after old write completed") + } + if err := validateOutboundLayerBinding(c, encoded); !errors.Is(err, ErrOutboundLayerProfileStale) { + t.Fatalf("completed old push binding = %v, want stale after correction", err) + } +} + +func TestStaleLayerPushIsRemovedFromResendTracking(t *testing.T) { + c := &Conn{metrics: NopMetrics{}} + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + fanout, err := newLayerUpdatesFanout(testLayerUpdatesValue(123)) + if err != nil { + t.Fatal(err) + } + encoded, err := fanout.prepareForConn(context.Background(), c) + if err != nil { + t.Fatal(err) + } + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatal(err) + } + frame := &outboundFrame{msgID: 100, body: encoded.body, layer: encoded.layer} + state := &outboundState{ + pending: map[int64]*outboundFrame{100: frame}, + order: []int64{100}, + totalBytes: len(frame.body), + } + if _, err := c.handleOutboundResend(state, context.Background(), []int64{100}); err != nil { + t.Fatal(err) + } + if _, ok := state.pending[100]; ok || frame.body != nil { + t.Fatal("stale profile frame remained resendable") + } +} + +func TestOutboundLayerBindingRejectsUnknownAndMismatchedConnections(t *testing.T) { + fanout, err := newLayerUpdatesFanout(testLayerUpdatesValue(123)) + if err != nil { + t.Fatalf("freeze updates: %v", err) + } + encoded, err := fanout.prepare(context.Background(), tg.LayerProfile225) + if err != nil { + t.Fatalf("prepare profile 225: %v", err) + } + if _, err := (&Conn{}).buildFrame(context.Background(), 0, nil, encoded); !errors.Is(err, ErrOutboundLayerProfileUnknown) { + t.Fatalf("unknown profile error = %v", err) + } + wrong := testConnWithLayerProfile(t, tg.LayerProfile227) + if _, err := wrong.buildFrame(context.Background(), 0, nil, encoded); !errors.Is(err, ErrOutboundLayerProfileMismatch) { + t.Fatalf("profile mismatch error = %v", err) + } +} + +func TestPendingPushReservationAccountsPreparedProfilesOnce(t *testing.T) { + budget := newOutboundTrackedBudget(4096) + if !budget.reserve(100) { + t.Fatal("reserve canonical snapshot") + } + reservation := &pendingPushReservation{budget: budget} + reservation.bytes.Store(100) + reservation.refs.Store(1) + + if !reservation.reservePrepared(tg.LayerProfile225, 80) { + t.Fatal("reserve first profile") + } + if !reservation.reservePrepared(tg.LayerProfile225, 80) { + t.Fatal("reuse first profile reservation") + } + if !reservation.reservePrepared(tg.LayerProfile227, 120) { + t.Fatal("reserve second profile") + } + if got := budget.snapshot(); got != 300 { + t.Fatalf("tracked pending bytes = %d, want canonical + unique profiles = 300", got) + } + reservation.release() + if got := budget.snapshot(); got != 0 { + t.Fatalf("tracked pending bytes after final release = %d", got) + } +} diff --git a/internal/mtprotoedge/login_e2e_test.go b/internal/mtprotoedge/login_e2e_test.go index 2af53dcb..d479397c 100644 --- a/internal/mtprotoedge/login_e2e_test.go +++ b/internal/mtprotoedge/login_e2e_test.go @@ -12,13 +12,13 @@ import ( "go.uber.org/zap/zaptest" "github.com/gotd/log/logzap" - "github.com/gotd/td/clock" - "github.com/gotd/td/exchange" - "github.com/gotd/td/session" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/session" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" "telesrv/internal/app/account" "telesrv/internal/app/auth" @@ -93,7 +93,7 @@ func TestLoginRegisterFlow(t *testing.T) { LangPack: langpack.NewService(langPackStore), } router := rpc.New(rpc.Config{DC: dc, IP: tcpAddr.IP.String(), Port: tcpAddr.Port}, deps, zaptest.NewLogger(t), clock.System) - srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, RPC: router}) + srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, LayerRPC: router}) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() @@ -314,7 +314,7 @@ func TestPrivateMessageRoundTripFlow(t *testing.T) { Sessions: activeSessions, } router := rpc.New(rpc.Config{DC: dc, IP: tcpAddr.IP.String(), Port: tcpAddr.Port}, deps, zaptest.NewLogger(t), clock.System) - srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, RPC: router, ActiveSessions: activeSessions}) + srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, LayerRPC: router, ActiveSessions: activeSessions}) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() diff --git a/internal/mtprotoedge/login_email_e2e_test.go b/internal/mtprotoedge/login_email_e2e_test.go index 924044e7..96e8f206 100644 --- a/internal/mtprotoedge/login_email_e2e_test.go +++ b/internal/mtprotoedge/login_email_e2e_test.go @@ -12,13 +12,13 @@ import ( "go.uber.org/zap/zaptest" "github.com/gotd/log/logzap" - "github.com/gotd/td/clock" - "github.com/gotd/td/exchange" - "github.com/gotd/td/session" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/session" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" "telesrv/internal/app/account" "telesrv/internal/app/auth" @@ -100,7 +100,7 @@ func TestLoginEmailEndToEnd(t *testing.T) { Dialogs: dialogs.NewService(dialogStore), } router := rpc.New(rpc.Config{DC: dc, IP: tcpAddr.IP.String(), Port: tcpAddr.Port}, deps, zaptest.NewLogger(t), clock.System) - srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, RPC: router}) + srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, LayerRPC: router}) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) serveErr := make(chan error, 1) diff --git a/internal/mtprotoedge/metrics_test.go b/internal/mtprotoedge/metrics_test.go index ef0d1b91..96f9e5c8 100644 --- a/internal/mtprotoedge/metrics_test.go +++ b/internal/mtprotoedge/metrics_test.go @@ -7,9 +7,9 @@ import ( "go.uber.org/zap/zaptest" - "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" "telesrv/internal/rpc" ) @@ -42,7 +42,7 @@ func TestMetricsHooks(t *testing.T) { const dc = 2 m := &countingMetrics{} router := rpc.New(rpc.Config{DC: dc, IP: "127.0.0.1", Port: 2398}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) - addr, pub, _ := startTestServer(t, Options{DC: dc, RPC: router, Metrics: m}) + addr, pub, _ := startTestServer(t, Options{DC: dc, legacyRPC: router, Metrics: m}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) clientMsgID := proto.NewMessageIDGen(time.Now) diff --git a/internal/mtprotoedge/new_session_uid_test.go b/internal/mtprotoedge/new_session_uid_test.go index a379a6d8..16c71b86 100644 --- a/internal/mtprotoedge/new_session_uid_test.go +++ b/internal/mtprotoedge/new_session_uid_test.go @@ -4,9 +4,9 @@ import ( "testing" "time" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) // TestNewSessionCreatedUniqueIDPerSession 验证两次 session 建立收到的 diff --git a/internal/mtprotoedge/outbound.go b/internal/mtprotoedge/outbound.go index d237ce5f..18b26343 100644 --- a/internal/mtprotoedge/outbound.go +++ b/internal/mtprotoedge/outbound.go @@ -9,16 +9,15 @@ import ( "errors" "fmt" "io" + "log" "sync" "sync/atomic" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - - "telesrv/internal/compat/layerwire" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" ) var ( @@ -108,12 +107,111 @@ type outboundOp struct { terminal func(error) } +// outboundBodyReservation bridges the only gap between producing an immutable +// encoded body and handing it to the outbound actor. Exact RPC results acquire +// this retained-byte reservation before releasing the process-wide encode slot, +// so completed large bodies can never accumulate unaccounted in RPC workers. +// Ownership is transferred into an outboundOp or released by the producer on +// every earlier failure. A failed queue admission may roll it back exactly once; +// the synchronized release request prevents watchdog/rollback resurrection. +type outboundBodyReservation struct { + mu sync.Mutex + budget *outboundTrackedBudget + bytes int + taken bool + releaseRequested bool +} + +func (r *outboundBodyReservation) release() { + if r == nil { + return + } + r.mu.Lock() + if r.bytes <= 0 { + // The actor may already own the raw reservation while queue admission is + // still in progress. Remember a racing watchdog/producer release so a + // later admission rollback cannot restore bytes after that owner is gone. + if r.taken { + r.releaseRequested = true + } + r.mu.Unlock() + return + } + bytes := r.bytes + budget := r.budget + r.bytes = 0 + r.budget = nil + r.mu.Unlock() + budget.release(bytes) +} + +func (r *outboundBodyReservation) take(encoded *encodedOutboundMessage) (outboundOp, error) { + if r == nil { + return outboundOp{}, errors.New("invalid outbound body reservation") + } + r.mu.Lock() + defer r.mu.Unlock() + if r.budget == nil || r.bytes <= 0 || r.taken || r.releaseRequested || encoded == nil || len(encoded.body) != r.bytes { + return outboundOp{}, errors.New("invalid outbound body reservation") + } + op := outboundOp{ + kind: outboundSend, + msgType: proto.MessageServerResponse, + encoded: encoded, + priority: classifyOutboundPriority(encoded, false), + reservedBytes: r.bytes, + reservationBudget: r.budget, + } + r.bytes = 0 + r.budget = nil + r.taken = true + return op, nil +} + +// reclaim moves an op reservation back to the producer when queue admission +// failed before the actor could observe the op. This preserves accounting until +// the producer has retained the immutable body elsewhere (usually completed +// cache) and its deferred release runs. +func (r *outboundBodyReservation) reclaim(op *outboundOp) bool { + if r == nil || op == nil || op.reservedBytes <= 0 || op.reservationBudget == nil { + return false + } + r.mu.Lock() + if r.bytes != 0 || r.budget != nil || !r.taken { + r.mu.Unlock() + return false + } + bytes := op.reservedBytes + budget := op.reservationBudget + op.reservedBytes = 0 + op.reservationBudget = nil + r.taken = false + if r.releaseRequested { + r.mu.Unlock() + budget.release(bytes) + return true + } + r.bytes = bytes + r.budget = budget + r.mu.Unlock() + return true +} + type encodedOutboundMessage struct { - body []byte - typeID uint32 - reqMsgID int64 - priority outboundPriority - delivery *rpcResultDelivery + body []byte + typeID uint32 + reqMsgID int64 + priority outboundPriority + delivery *rpcResultDelivery + // layerInvariant is set only from a closed Go-type proof for an mt.* leaf or + // an rpc_result whose complete inner value is an invariant mt.* service + // result. A constructor ID alone is insufficient proof because RPC envelopes + // and application schemas can contain nested/profiled values. + layerInvariant bool + // layer binds already-prepared TL bytes to the exact generated profile that + // produced them. It is intentionally absent for MTProto control envelopes; + // a bound value must never be transcoded or sent to another profile. + layer *outboundLayerBinding compressed bool uncompressedBytes int } @@ -135,19 +233,261 @@ type rpcResultDelivery struct { // writtenReqMsgID is the actor's immutable snapshot for the physical frame. targetReqMsgID int64 writtenReqMsgID int64 - once sync.Once - fn func() + coordinator *rpcResultDeliveryCoordinator + hookTicket *rpcDeliveryHookTicket + // attemptHook is connection-local replay state. Unlike the coordinator's + // logical-result hook it must run only when this particular physical attempt + // succeeds, even if another replay of the same cached result wins first. + attemptHook func() } -func newRPCResultDelivery(reqMsgID ...int64) *rpcResultDelivery { - d := &rpcResultDelivery{} - if len(reqMsgID) > 0 { - d.targetReqMsgID = reqMsgID[0] +type rpcResultDeliveryHookState uint8 + +const ( + rpcResultDeliveryHookUnset rpcResultDeliveryHookState = iota + rpcResultDeliveryHookPending + rpcResultDeliveryHookClaimed + rpcResultDeliveryHookInProgress + rpcResultDeliveryHookDone +) + +// rpcResultDeliveryCoordinator is logical-result state. Equivalent old/new +// req_msg_id representations and every replay share it, while each physical +// attempt owns a separate rpcResultDelivery state machine and hook ticket. +type rpcResultDeliveryCoordinator struct { + mu sync.Mutex + fn func() + state rpcResultDeliveryHookState + claim *rpcResultDeliveryHookClaim + changed chan struct{} + // deferredToReplay is sticky while a successful initConnection retarget owns + // the logical hook. The ordinary source terminal may mark physical delivery, + // but only the alias restore barrier may claim the hook. On terminal alias + // failure the flag is released so a later completed-cache replay can retry. + deferredToReplay bool +} + +// rpcResultDeliveryHookClaim is an ownership token, not merely the hook +// function. Pointer identity prevents an abandoned claimed hook from running +// after a replacement replay has acquired a newer claim. The coordinator keeps +// claimed and in-progress distinct so another physical replay can wait for the +// exact logical transition instead of mistaking ownership for completion. +type rpcResultDeliveryHookClaim struct { + coordinator *rpcResultDeliveryCoordinator + fn func() +} + +func newRPCResultDelivery(reqMsgID int64, coordinator ...*rpcResultDeliveryCoordinator) *rpcResultDelivery { + c := &rpcResultDeliveryCoordinator{changed: make(chan struct{})} + if len(coordinator) > 0 && coordinator[0] != nil { + c = coordinator[0] + } + d := &rpcResultDelivery{coordinator: c} + if reqMsgID != 0 { + d.targetReqMsgID = reqMsgID } d.state.Store(uint32(rpcResultDeliveryPrepared)) return d } +func (c *rpcResultDeliveryCoordinator) setHook(fn func()) { + if c == nil || fn == nil { + return + } + c.mu.Lock() + if c.fn == nil && c.state != rpcResultDeliveryHookDone { + c.fn = fn + c.state = rpcResultDeliveryHookPending + c.signalLocked() + } + c.mu.Unlock() +} + +func (c *rpcResultDeliveryCoordinator) pendingHook() bool { + if c == nil { + return false + } + c.mu.Lock() + pending := c.fn != nil && c.state != rpcResultDeliveryHookDone + c.mu.Unlock() + return pending +} + +func (c *rpcResultDeliveryCoordinator) pendingAsyncHook() bool { + if c == nil { + return false + } + c.mu.Lock() + pending := c.fn != nil && c.state == rpcResultDeliveryHookPending && !c.deferredToReplay + c.mu.Unlock() + return pending +} + +func (c *rpcResultDeliveryCoordinator) signalLocked() { + if c.changed == nil { + c.changed = make(chan struct{}) + return + } + close(c.changed) + if c.state == rpcResultDeliveryHookDone { + c.changed = nil + } else { + c.changed = make(chan struct{}) + } +} + +func (c *rpcResultDeliveryCoordinator) claimLocked(allowDeferred bool) *rpcResultDeliveryHookClaim { + if c.fn == nil || c.state != rpcResultDeliveryHookPending || + (c.deferredToReplay && !allowDeferred) { + return nil + } + claim := &rpcResultDeliveryHookClaim{coordinator: c, fn: c.fn} + c.claim = claim + c.state = rpcResultDeliveryHookClaimed + if allowDeferred { + c.deferredToReplay = false + } + c.signalLocked() + return claim +} + +func (c *rpcResultDeliveryCoordinator) claimAsyncDeliveredHook() *rpcResultDeliveryHookClaim { + if c == nil { + return nil + } + c.mu.Lock() + claim := c.claimLocked(false) + c.mu.Unlock() + return claim +} + +// claimReplayDeliveredHook waits for an existing claim to finish, or acquires +// the pending hook itself. allowDeferred is reserved for the initConnection +// alias that installed the sticky retarget deferral. Every state transition +// closes changed, giving waiters a concrete happens-before edge to Done. +func (c *rpcResultDeliveryCoordinator) claimReplayDeliveredHook( + ctx context.Context, + allowDeferred bool, +) (*rpcResultDeliveryHookClaim, error) { + if c == nil { + return nil, nil + } + if ctx == nil { + ctx = context.Background() + } + for { + c.mu.Lock() + if c.fn == nil || c.state == rpcResultDeliveryHookDone { + c.mu.Unlock() + return nil, nil + } + if claim := c.claimLocked(allowDeferred); claim != nil { + c.mu.Unlock() + return claim, nil + } + changed := c.changed + if changed == nil { + changed = make(chan struct{}) + c.changed = changed + } + c.mu.Unlock() + select { + case <-changed: + case <-ctx.Done(): + c.mu.Lock() + done := c.fn == nil || c.state == rpcResultDeliveryHookDone + c.mu.Unlock() + if done { + return nil, nil + } + return nil, ctx.Err() + } + } +} + +func (c *rpcResultDeliveryCoordinator) releaseDeferredHook() { + if c == nil { + return + } + c.mu.Lock() + if c.deferredToReplay { + c.deferredToReplay = false + c.signalLocked() + } + c.mu.Unlock() +} + +func (c *rpcResultDeliveryCoordinator) deferHookToReplay() { + if c == nil { + return + } + c.mu.Lock() + if c.state != rpcResultDeliveryHookDone && !c.deferredToReplay { + c.deferredToReplay = true + c.signalLocked() + } + c.mu.Unlock() +} + +func (c *rpcResultDeliveryCoordinator) hookState() rpcResultDeliveryHookState { + if c == nil { + return rpcResultDeliveryHookUnset + } + c.mu.Lock() + state := c.state + c.mu.Unlock() + return state +} + +func (claim *rpcResultDeliveryHookClaim) run() { + if claim == nil || claim.coordinator == nil { + return + } + c := claim.coordinator + c.mu.Lock() + if c.claim != claim || c.state != rpcResultDeliveryHookClaimed { + c.mu.Unlock() + return + } + c.state = rpcResultDeliveryHookInProgress + c.signalLocked() + c.mu.Unlock() + + defer func() { + c.mu.Lock() + if c.claim == claim && c.state == rpcResultDeliveryHookInProgress { + c.claim = nil + c.fn = nil + c.deferredToReplay = false + c.state = rpcResultDeliveryHookDone + c.signalLocked() + } + c.mu.Unlock() + }() + if claim.fn != nil { + claim.fn() + } +} + +// abandon makes a hook claim retryable only while its function has not begun. +// Once InProgress is visible, at-most-once semantics forbid another replay from +// guessing whether a non-cooperative callback partially applied its effects. +func (claim *rpcResultDeliveryHookClaim) abandon() bool { + if claim == nil || claim.coordinator == nil { + return false + } + c := claim.coordinator + c.mu.Lock() + defer c.mu.Unlock() + if c.claim != claim || c.state != rpcResultDeliveryHookClaimed { + return false + } + c.claim = nil + c.state = rpcResultDeliveryHookPending + c.signalLocked() + return true +} + func (m *encodedOutboundMessage) deliveryState() rpcResultDeliveryState { if m == nil || m.delivery == nil { return 0 @@ -191,12 +531,25 @@ func (m *encodedOutboundMessage) tryRetarget(reqMsgID int64) bool { return false } m.delivery.mu.Lock() - defer m.delivery.mu.Unlock() state := m.deliveryState() if state != rpcResultDeliveryPrepared && state != rpcResultDeliveryQueued { + m.delivery.mu.Unlock() return false } + // Retarget and logical-hook deferral are one transition with beginWriting. + // If admission already reserved a global executor ticket, detach it while the + // actor is still unable to enter Writing; the alias barrier owns the hook now. + coordinator := m.delivery.coordinator + if coordinator != nil { + coordinator.deferHookToReplay() + } + ticket := m.delivery.hookTicket + m.delivery.hookTicket = nil m.delivery.targetReqMsgID = reqMsgID + m.delivery.mu.Unlock() + if ticket != nil { + ticket.release() + } return true } @@ -227,7 +580,13 @@ func (m *encodedOutboundMessage) markReplayable() { if m.deliveryState() != rpcResultDeliveryDelivered { m.delivery.state.Store(uint32(rpcResultDeliveryReplayable)) } + ticket := m.delivery.hookTicket + m.delivery.hookTicket = nil + m.delivery.attemptHook = nil m.delivery.mu.Unlock() + if ticket != nil { + ticket.release() + } } func (m *encodedOutboundMessage) markDelivered() { @@ -236,29 +595,170 @@ func (m *encodedOutboundMessage) markDelivered() { } m.delivery.mu.Lock() m.delivery.state.Store(uint32(rpcResultDeliveryDelivered)) + ticket := m.delivery.hookTicket + m.delivery.hookTicket = nil + coordinator := m.delivery.coordinator + attemptHook := m.delivery.attemptHook + m.delivery.attemptHook = nil m.delivery.mu.Unlock() - if m.delivery.fn != nil { - m.delivery.once.Do(func() { scheduleRPCDeliveryHook(m.delivery.fn) }) + logicalClaim := coordinator.claimAsyncDeliveredHook() + if logicalClaim == nil && attemptHook == nil { + if ticket != nil { + ticket.release() + } + return } + if ticket == nil { + // Production write paths reserve before admission. This fallback preserves + // old direct-test callers without ever waiting in the socket writer. + ticket, _ = defaultRPCDeliveryHookExecutor.reserve() + } + if ticket == nil { + logicalClaim.abandon() + log.Printf("mtprotoedge: delivered rpc_result without reserved delivery-hook capacity") + return + } + if !ticket.submit(func() { + if logicalClaim != nil { + logicalClaim.run() + } + if attemptHook != nil { + attemptHook() + } + }) { + logicalClaim.abandon() + ticket.release() + log.Printf("mtprotoedge: reserved rpc delivery hook ticket could not be submitted") + } +} + +func (m *encodedOutboundMessage) setDeliveryHook(fn func()) { + if m == nil || m.delivery == nil || m.delivery.coordinator == nil { + return + } + m.delivery.coordinator.setHook(fn) +} + +// pendingLogicalDeliveryHook reports whether this logical rpc_result still owns +// delivery-gated state from its original successful handler. Cached replay uses +// this before physical admission so it can install a per-Conn scheduler barrier +// without reserving the process-wide asynchronous hook executor. +func (m *encodedOutboundMessage) pendingLogicalDeliveryHook() bool { + return m != nil && m.delivery != nil && m.delivery.coordinator != nil && + m.delivery.coordinator.pendingHook() +} + +// claimLogicalDeliveryHook transfers the logical post-response hook only after +// a replay attempt has physically reached the replacement stream. Calling it +// before markDelivered makes the latter a pure attempt-state transition, so no +// global hook ticket is required on the ordered replay path. +func (m *encodedOutboundMessage) claimLogicalDeliveryHook( + ctx context.Context, + allowDeferred bool, +) (*rpcResultDeliveryHookClaim, error) { + if m == nil || m.delivery == nil || m.delivery.coordinator == nil { + return nil, nil + } + return m.delivery.coordinator.claimReplayDeliveredHook(ctx, allowDeferred) +} + +func (m *encodedOutboundMessage) releaseDeferredLogicalDeliveryHook() { + if m != nil && m.delivery != nil && m.delivery.coordinator != nil { + m.delivery.coordinator.releaseDeferredHook() + } +} + +func (m *encodedOutboundMessage) setAttemptDeliveryHook(fn func()) { + if m == nil || m.delivery == nil || fn == nil { + return + } + m.delivery.mu.Lock() + if m.delivery.attemptHook == nil { + m.delivery.attemptHook = fn + } + m.delivery.mu.Unlock() +} + +func (m *encodedOutboundMessage) prepareDeliveryHook(executor *rpcDeliveryHookExecutor) error { + if m == nil || m.delivery == nil { + return nil + } + m.delivery.mu.Lock() + pending := m.delivery.attemptHook != nil || (m.delivery.coordinator != nil && m.delivery.coordinator.pendingAsyncHook()) + if m.delivery.hookTicket != nil || !pending { + m.delivery.mu.Unlock() + return nil + } + ticket, ok := executor.reserve() + if !ok { + m.delivery.mu.Unlock() + return ErrRPCDeliveryHookCapacity + } + pending = m.delivery.attemptHook != nil || (m.delivery.coordinator != nil && m.delivery.coordinator.pendingAsyncHook()) + if !pending { + m.delivery.mu.Unlock() + ticket.release() + return nil + } + m.delivery.hookTicket = ticket + m.delivery.mu.Unlock() + return nil } func cloneRPCResultForRequest(encoded *encodedOutboundMessage, reqMsgID int64, shareDelivery bool) (*encodedOutboundMessage, error) { if encoded == nil || encoded.typeID != proto.ResultTypeID || len(encoded.body) < 12 || reqMsgID == 0 { return nil, errors.New("invalid rpc_result retarget") } - body := append([]byte(nil), encoded.body...) - binary.LittleEndian.PutUint64(body[4:12], uint64(reqMsgID)) - delivery := newRPCResultDelivery(reqMsgID) + body := encoded.body + if int64(binary.LittleEndian.Uint64(body[4:12])) != reqMsgID { + body = append([]byte(nil), body...) + binary.LittleEndian.PutUint64(body[4:12], uint64(reqMsgID)) + } + var coordinator *rpcResultDeliveryCoordinator + if encoded.delivery != nil { + coordinator = encoded.delivery.coordinator + } + delivery := newRPCResultDelivery(reqMsgID, coordinator) if shareDelivery { delivery = encoded.delivery } return &encodedOutboundMessage{ body: body, typeID: encoded.typeID, reqMsgID: reqMsgID, priority: encoded.priority, delivery: delivery, compressed: encoded.compressed, + layer: encoded.layer, layerInvariant: encoded.layerInvariant, uncompressedBytes: encoded.uncompressedBytes, }, nil } +// cloneRPCResultForRequestReserved charges the target connection's retained-body +// budget before a retarget copy can exist. Even the same-req_id zero-copy case +// needs a reservation: the replay/rewrap owner may outlive cache eviction while +// it is queued, so its immutable body must remain independently pinned. +func (c *Conn) cloneRPCResultForRequestReserved( + encoded *encodedOutboundMessage, + reqMsgID int64, + shareDelivery bool, +) (*encodedOutboundMessage, *outboundBodyReservation, error) { + if c == nil || encoded == nil || encoded.typeID != proto.ResultTypeID || len(encoded.body) < 12 || reqMsgID == 0 { + return nil, nil, errors.New("invalid rpc_result retarget") + } + bytes := len(encoded.body) + if bytes > maxOutboundBodyBytes { + return nil, nil, fmt.Errorf("%w: body=%d limit=%d", ErrOutboundMessageTooLarge, bytes, maxOutboundBodyBytes) + } + budget := c.outboundMessageBudget(encoded.typeID, false) + if !budget.reserve(bytes) { + return nil, nil, ErrOutboundTrackedBudget + } + reserved := &outboundBodyReservation{budget: budget, bytes: bytes} + clone, err := cloneRPCResultForRequest(encoded, reqMsgID, shareDelivery) + if err != nil { + reserved.release() + return nil, nil, err + } + return clone, reserved, nil +} + type outboundResult struct { info []byte resent bool @@ -276,8 +776,11 @@ type outboundFrame struct { // but their bytes must remain on the independent control budget for the full lifetime. reservationBudget *outboundTrackedBudget reqMsgID int64 - sentAt time.Time - sends int + // layer is retained only for proactive session-bound frames so a later + // msg_resend_req cannot replay bytes from an obsolete profile epoch. + layer *outboundLayerBinding + sentAt time.Time + sends int } type outboundState struct { @@ -758,7 +1261,16 @@ func (c *Conn) send(ctx context.Context, t proto.MessageType, msg bin.Encoder, c } func (c *Conn) SendEncoded(ctx context.Context, t proto.MessageType, encoded *encodedOutboundMessage) error { - return c.sendOutbound(ctx, t, nil, encoded, false) + if encoded != nil { + if err := encoded.prepareDeliveryHook(defaultRPCDeliveryHookExecutor); err != nil { + return err + } + } + err := c.sendOutbound(ctx, t, nil, encoded, false) + if err != nil && encoded != nil { + encoded.markReplayable() + } + return err } // enqueueEncodedDelivery transfers an immutable body to the bounded egress actor @@ -770,17 +1282,53 @@ func (c *Conn) enqueueEncodedDelivery( encoded *encodedOutboundMessage, priority outboundPriority, terminal func(error), +) error { + return c.enqueueEncodedDeliveryReserved(ctx, t, encoded, priority, terminal, nil) +} + +// enqueueEncodedDeliveryReserved accepts an optional byte reservation acquired +// while the caller still owned outboundEncodeSlots. Passing nil preserves the +// ordinary pre-encoded path used by callers that did not allocate a retained clone. +func (c *Conn) enqueueEncodedDeliveryReserved( + ctx context.Context, + t proto.MessageType, + encoded *encodedOutboundMessage, + priority outboundPriority, + terminal func(error), + reserved *outboundBodyReservation, ) error { if c.outbound == nil || c.outboundControl == nil || c.outboundCritical == nil || c.outboundBulk == nil { return ErrConnClosed } - op, err := c.newOutboundSendOp(ctx, t, nil, encoded, false) + if encoded != nil { + if err := encoded.prepareDeliveryHook(defaultRPCDeliveryHookExecutor); err != nil { + return err + } + } + var op outboundOp + var err error + if reserved == nil { + op, err = c.newOutboundSendOp(ctx, t, nil, encoded, false) + } else { + op, err = reserved.take(encoded) + if err == nil { + op.msgType = t + } + } if err != nil { + if encoded != nil { + encoded.markReplayable() + } c.failOutboundBudget(err) return err } if !c.beginOutboundEnqueue() { - op.releaseReservation(c.outboundTrackedBudget) + if reserved == nil || !reserved.reclaim(&op) { + op.releaseReservation(c.outboundTrackedBudget) + } + if encoded != nil { + encoded.markReplayable() + } return ErrConnClosed } op.priority = priority @@ -788,8 +1336,13 @@ func (c *Conn) enqueueEncodedDelivery( op.enqueuedAt = time.Now() op.terminal = terminal if err := c.enqueueOutboundRegistered(ctx, op); err != nil { - op.releaseReservation(c.outboundTrackedBudget) + if reserved == nil || !reserved.reclaim(&op) { + op.releaseReservation(c.outboundTrackedBudget) + } c.endOutboundEnqueue() + if encoded != nil { + encoded.markReplayable() + } return err } c.endOutboundEnqueue() @@ -797,25 +1350,86 @@ func (c *Conn) enqueueEncodedDelivery( } func (c *Conn) sendOutbound(ctx context.Context, t proto.MessageType, msg bin.Encoder, encoded *encodedOutboundMessage, control bool) error { + return c.sendOutboundWithTerminal(ctx, t, msg, encoded, control, nil) +} + +// sendOutboundWithTerminal is the synchronous actor path with an optional +// terminal callback. Once queue admission succeeds, terminal runs on the sole +// actor after the transport has definitively reported write success/failure and +// before the caller's done notification. Early admission failures invoke it in +// the caller, so a waiter always observes exactly one terminal outcome. +func (c *Conn) sendOutboundWithTerminal( + ctx context.Context, + t proto.MessageType, + msg bin.Encoder, + encoded *encodedOutboundMessage, + control bool, + terminal func(error), +) error { + return c.sendOutboundWithTerminalReserved(ctx, t, msg, encoded, control, terminal, nil) +} + +// sendOutboundWithTerminalReserved is the synchronous counterpart of +// enqueueEncodedDeliveryReserved. A replay/rewrap producer reserves before it +// clones; take atomically transfers that charge to the actor so a racing +// watchdog can either release the still-owned reservation or observe that the +// actor has already become its sole owner, never both. +func (c *Conn) sendOutboundWithTerminalReserved( + ctx context.Context, + t proto.MessageType, + msg bin.Encoder, + encoded *encodedOutboundMessage, + control bool, + terminal func(error), + reserved *outboundBodyReservation, +) error { if c.outbound == nil || c.outboundControl == nil { + if terminal != nil { + terminal(ErrConnClosed) + } return ErrConnClosed } - op, err := c.newOutboundSendOp(ctx, t, msg, encoded, control) + var op outboundOp + var err error + if reserved == nil { + op, err = c.newOutboundSendOp(ctx, t, msg, encoded, control) + } else { + op, err = reserved.take(encoded) + if err == nil { + op.msgType = t + op.msg = msg + op.priority = classifyOutboundPriority(encoded, control) + } + } if err != nil { c.failOutboundBudget(err) + if terminal != nil { + terminal(err) + } return err } if !c.beginOutboundEnqueue() { - op.releaseReservation(c.outboundTrackedBudget) + if reserved == nil || !reserved.reclaim(&op) { + op.releaseReservation(c.outboundTrackedBudget) + } + if terminal != nil { + terminal(ErrConnClosed) + } return ErrConnClosed } op.control = control op.ctx = ctx op.enqueuedAt = time.Now() op.done = make(chan outboundResult, 1) + op.terminal = terminal if err := c.enqueueOutboundRegistered(ctx, op); err != nil { - op.releaseReservation(c.outboundTrackedBudget) + if reserved == nil || !reserved.reclaim(&op) { + op.releaseReservation(c.outboundTrackedBudget) + } c.endOutboundEnqueue() + if terminal != nil { + terminal(err) + } return err } c.endOutboundEnqueue() @@ -1075,8 +1689,8 @@ func (c *Conn) outboundLoop() { return } if c.isRetired() { - op.releaseReservation(c.outboundTrackedBudget) op.finish(outboundResult{err: ErrConnClosed}) + op.releaseReservation(c.outboundTrackedBudget) c.signalOutboundStop() c.drainOutbound() return @@ -1147,17 +1761,17 @@ func (c *Conn) drainOutbound() { for { select { case op := <-c.outboundControl: - op.releaseReservation(c.outboundTrackedBudget) op.finish(outboundResult{err: ErrConnClosed}) + op.releaseReservation(c.outboundTrackedBudget) case op := <-c.outboundCritical: - op.releaseReservation(c.outboundTrackedBudget) op.finish(outboundResult{err: ErrConnClosed}) + op.releaseReservation(c.outboundTrackedBudget) case op := <-c.outbound: - op.releaseReservation(c.outboundTrackedBudget) op.finish(outboundResult{err: ErrConnClosed}) + op.releaseReservation(c.outboundTrackedBudget) case op := <-c.outboundBulk: - op.releaseReservation(c.outboundTrackedBudget) op.finish(outboundResult{err: ErrConnClosed}) + op.releaseReservation(c.outboundTrackedBudget) default: return } @@ -1168,8 +1782,8 @@ func (c *Conn) handleOutboundOp(state *outboundState, op outboundOp) { // An operation can sit in a bounded queue across the protocol expiry instant. // It must be failed and released without touching the wire. if c.authKeyProtocolUnavailableNow() { - op.releaseReservation(state.budget) op.finish(outboundResult{err: ErrConnClosed}) + op.releaseReservation(state.budget) c.fenceUnavailableAuthKey() return } @@ -1199,17 +1813,17 @@ func (c *Conn) handleOutboundOp(state *outboundState, op outboundOp) { } func (c *Conn) handleOutboundSend(state *outboundState, op outboundOp) { - var err error + var binding *outboundLayerBinding if op.encoded != nil { - targetReqMsgID := op.encoded.beginWriting() - if targetReqMsgID != 0 && targetReqMsgID != op.encoded.reqMsgID { - op.encoded, err = cloneRPCResultForRequest(op.encoded, targetReqMsgID, true) - } + binding = op.encoded.layer } - var frame *outboundFrame - if err == nil { - frame, err = c.buildFrame(op.ctx, op.msgType, op.msg, op.encoded) + if c.lockSessionLayerBinding(binding) { + defer c.layerProfileMu.RUnlock() } + // Extract the admitted reservation before any actor-side retarget or layer + // conversion can allocate another full body. supersededBytes covers immutable + // source bodies still reachable by the terminal callback; reserved covers the + // body that will be transferred to pending if the write succeeds. reserved := op.reservedBytes reservationBudget := op.reservationBudget if reservationBudget == nil { @@ -1217,16 +1831,48 @@ func (c *Conn) handleOutboundSend(state *outboundState, op outboundOp) { } op.reservedBytes = 0 op.reservationBudget = nil - // A per-connection layer downgrade can allocate a different body. Reserve the - // replacement before dropping the canonical queue reservation so the transient - // two-body peak is also covered by the Server budget. + supersededBytes := 0 + defer func() { + reservationBudget.release(reserved) + reservationBudget.release(supersededBytes) + }() + + var err error + if op.encoded != nil { + targetReqMsgID := op.encoded.beginWriting() + if targetReqMsgID != 0 && targetReqMsgID != op.encoded.reqMsgID { + cloneBytes := len(op.encoded.body) + if !reservationBudget.reserve(cloneBytes) { + err = ErrOutboundTrackedBudget + } else { + clone, cloneErr := cloneRPCResultForRequest(op.encoded, targetReqMsgID, true) + if cloneErr != nil { + reservationBudget.release(cloneBytes) + err = cloneErr + } else { + // The terminal callback still owns the original encoded pointer. + // Keep its reservation until that callback has cached/retained it. + supersededBytes += reserved + reserved = cloneBytes + op.encoded = clone + } + } + } + } + var frame *outboundFrame + if err == nil { + frame, err = c.buildFrame(op.ctx, op.msgType, op.msg, op.encoded) + } + // A profile-bound preparation can allocate a different body. Reserve the + // replacement before dropping the original prepared-body reservation. The + // original body stays charged through the terminal callback because cache/rewrap + // subscribers can still retain it there. if err == nil && frame != nil && op.encoded != nil && !sameBacking(frame.body, op.encoded.body) { if !reservationBudget.reserve(len(frame.body)) { err = ErrOutboundTrackedBudget } else { - reservationBudget.release(reserved) + supersededBytes += reserved reserved = len(frame.body) - op.encoded = nil } } if err == nil && frame != nil && frameNeedsAck(frame.typeID) { @@ -1240,6 +1886,11 @@ func (c *Conn) handleOutboundSend(state *outboundState, op outboundOp) { c.metrics.OutboundDropped("tracked_global_byte_budget") c.failTransport() } + if isOutboundStaleLayerEpoch(err) { + // Profile correction is normal client recovery. This proactive update + // belongs to an older epoch; drop it without poisoning the socket. + c.metrics.OutboundDropped("stale_layer_epoch") + } if err == nil { err = c.writeFrame(op.ctx, frame) } @@ -1255,7 +1906,6 @@ func (c *Conn) handleOutboundSend(state *outboundState, op outboundOp) { } } } - reservationBudget.release(reserved) queueWait := time.Since(op.enqueuedAt) bytes := 0 typeID := uint32(0) @@ -1278,10 +1928,28 @@ func (c *Conn) handleOutboundResend(state *outboundState, ctx context.Context, i if !ok { continue } + lockedLayer := c.lockSessionLayerBinding(frame.layer) + if err := validateOutboundLayerBinding(c, &encodedOutboundMessage{layer: frame.layer}); err != nil { + if lockedLayer { + c.layerProfileMu.RUnlock() + } + if isOutboundStaleLayerEpoch(err) || isOutboundLayerProfileError(err) { + state.removePending(id) + c.metrics.OutboundDropped("stale_layer_resend") + continue + } + return info, err + } if err := c.writeFrame(ctx, frame); err != nil { + if lockedLayer { + c.layerProfileMu.RUnlock() + } c.metrics.OutboundResend(resent, err) return info, err } + if lockedLayer { + c.layerProfileMu.RUnlock() + } frame.sentAt = time.Now() frame.sends++ resent++ @@ -1396,6 +2064,11 @@ func (c *Conn) newOutboundSendOp(ctx context.Context, t proto.MessageType, msg b if encoded == nil { return outboundOp{}, errors.New("nil encoded outbound message") } + // Catch correction-before-enqueue synchronously. The actor repeats the same + // validation immediately before framing to close the bounded queue race. + if err := validateOutboundLayerBinding(c, encoded); err != nil { + return outboundOp{}, err + } bytes := len(encoded.body) if bytes > maxOutboundBodyBytes { return outboundOp{}, fmt.Errorf("%w: body=%d limit=%d", ErrOutboundMessageTooLarge, bytes, maxOutboundBodyBytes) @@ -1475,12 +2148,12 @@ func (c *Conn) buildFrame(ctx context.Context, t proto.MessageType, msg bin.Enco return nil, err } } - // 出站统一在此按本连接协商 layer 降级: - // - push fan-out 用 onceEncodedOutbound 把更新编码一次(canonical)再 SendEncoded 给多条 - // 连接共享,故必须在此**逐连接**降级,且**绝不改共享 encoded**(downgradedClone 拷贝)。 - // - rpc_result 的内层对象已在 encodeRPCResult 按 layer 降级,其 mt.* 外壳在此为顶层直通(no-op)。 - // - 控制消息(mt.*)顶层直通。layer>=227 整条零开销。 - encoded = c.downgradedCloneContext(ctx, encoded) + if err := validateOutboundLayerBinding(c, encoded); err != nil { + return nil, err + } + if encoded.layer == nil && !encoded.layerInvariant { + return nil, ErrOutboundLayerBindingRequired + } content := frameNeedsAck(encoded.typeID) msgID := c.msgID.New(t) return &outboundFrame{ @@ -1489,50 +2162,11 @@ func (c *Conn) buildFrame(ctx context.Context, t proto.MessageType, msg bin.Enco typeID: encoded.typeID, body: encoded.body, reqMsgID: encoded.reqMsgID, + layer: encoded.layer, }, nil } -// downgradedClone 返回按本连接协商 layer 降级后的消息,**绝不修改入参**——push fan-out -// 多条连接共享同一 encoded,逐连接降级必须各自拷贝,否则会污染其他连接的字节。 -// layer>=227 或 Transcode 直通(mt.* / 无变化)时原样返回入参,零拷贝。降级失败 fail-safe: -// 返回 canonical 并计 metrics(宁可老客户端对个别长尾对象渲染异常,也不让连接/流崩)。 -func (c *Conn) downgradedClone(encoded *encodedOutboundMessage) *encodedOutboundMessage { - return c.downgradedCloneContext(context.Background(), encoded) -} - -func (c *Conn) downgradedCloneContext(ctx context.Context, encoded *encodedOutboundMessage) *encodedOutboundMessage { - if encoded == nil { - return nil - } - if c.ClientLayer() >= layerwire.CanonicalLayer { - return encoded - } - var down []byte - err := withOutboundEncodeSlot(ctx, c.outboundStop, func() error { - var err error - down, err = layerwire.Transcode(encoded.body, c.ClientLayer()) - return err - }) - if err != nil { - c.metrics.OutboundDropped("layerwire_downgrade_failed") - return encoded - } - if sameBacking(down, encoded.body) { - return encoded // 直通:未变(mt.*/顶层未知),无需拷贝或重算 typeID - } - out := &encodedOutboundMessage{ - body: down, typeID: encoded.typeID, reqMsgID: encoded.reqMsgID, - priority: encoded.priority, delivery: encoded.delivery, compressed: encoded.compressed, - uncompressedBytes: encoded.uncompressedBytes, - } - if id, e := (&bin.Buffer{Buf: down}).PeekID(); e == nil { - out.typeID = id - } - return out -} - -// sameBacking reports whether a and b share the same backing array (Transcode -// returns its input unchanged for passthrough cases). +// sameBacking reports whether a and b share the same backing array. func sameBacking(a, b []byte) bool { return len(a) == len(b) && (len(a) == 0 || &a[0] == &b[0]) } @@ -1564,12 +2198,52 @@ func encodeOutboundMessageWithoutSlot(msg bin.Encoder) (*encodedOutboundMessage, return nil, fmt.Errorf("peek outbound type id: %w", err) } return &encodedOutboundMessage{ - typeID: typeID, - body: body.Raw(), - reqMsgID: outboundRequestMsgID(msg), + typeID: typeID, + body: body.Raw(), + reqMsgID: outboundRequestMsgID(msg), + layerInvariant: isLayerInvariantControlEncoder(msg), }, nil } +// isLayerInvariantRPCResultEncoder proves the complete inner graph of the +// legacy MTProto service results that may be wrapped by rpc_result before an +// application Layer is known. Generated application results use their +// LayerRPCResult proof instead and are intentionally absent here. +func isLayerInvariantRPCResultEncoder(msg bin.Encoder) bool { + switch msg.(type) { + case *mt.RPCError, + *mt.RPCAnswerUnknown, + *mt.RPCAnswerDroppedRunning, + *mt.RPCAnswerDropped: + return true + default: + return false + } +} + +// isLayerInvariantControlEncoder is intentionally a closed type proof. It +// admits leaf MTProto service values plus the closed destroy_auth_key +// rpc_result whose inner constructor is validated by its concrete type. +// Generic rpc_result, gzip and container envelopes remain excluded because +// they can carry profile-dependent application payloads. +func isLayerInvariantControlEncoder(msg bin.Encoder) bool { + switch msg.(type) { + case *mt.Pong, + *mt.FutureSalts, + *mt.NewSessionCreated, + *mt.MsgsAck, + *mt.MsgsStateInfo, + *mt.DestroySessionOk, + *mt.DestroySessionNone, + *mt.BadMsgNotification, + *mt.BadServerSalt, + *destroyAuthKeyRPCResult: + return true + default: + return false + } +} + // peekSeqNo 计算本帧的 seq_no,但不提交 content 计数递增——递增延到 writeFrame 成功后 // (commitContentSeqNo)。这样写失败(超时/连接关)但连接存活时,下一条 content 帧会复用 // 同一 seq_no 而非留下间隙,避免严格校验的客户端把间隙误判为丢帧。只由 outbound actor 调用。 @@ -1851,9 +2525,7 @@ func encodedControlFrame(typeID uint32) bool { mt.DestroySessionNoneTypeID, mt.RPCAnswerUnknownTypeID, mt.RPCAnswerDroppedRunningTypeID, - mt.RPCAnswerDroppedTypeID, - destroyAuthKeyOkTypeID, - destroyAuthKeyFailTypeID: + mt.RPCAnswerDroppedTypeID: return true default: return false @@ -1864,6 +2536,8 @@ func outboundRequestMsgID(msg bin.Encoder) int64 { switch v := msg.(type) { case *proto.Result: return v.RequestMessageID + case *destroyAuthKeyRPCResult: + return v.RequestMessageID default: return 0 } diff --git a/internal/mtprotoedge/outbound_required_control_test.go b/internal/mtprotoedge/outbound_required_control_test.go index abe405bd..77f79a92 100644 --- a/internal/mtprotoedge/outbound_required_control_test.go +++ b/internal/mtprotoedge/outbound_required_control_test.go @@ -10,10 +10,10 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" ) type gatedRequiredControlTransport struct { diff --git a/internal/mtprotoedge/outbound_scratch.go b/internal/mtprotoedge/outbound_scratch.go index 390d2d7d..66d8f884 100644 --- a/internal/mtprotoedge/outbound_scratch.go +++ b/internal/mtprotoedge/outbound_scratch.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/gotd/td/bin" + "github.com/iamxvbaba/td/bin" ) const ( diff --git a/internal/mtprotoedge/outbound_test.go b/internal/mtprotoedge/outbound_test.go index 82057f25..602ea279 100644 --- a/internal/mtprotoedge/outbound_test.go +++ b/internal/mtprotoedge/outbound_test.go @@ -11,12 +11,12 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" ) type failAfterTransport struct { @@ -28,6 +28,44 @@ type failAfterTransport struct { last []byte } +func TestRPCResultReplayAttemptHooksArePhysicalConnectionLocal(t *testing.T) { + const reqMsgID = int64(771) + base := &encodedOutboundMessage{ + body: make([]byte, 12), + typeID: proto.ResultTypeID, + reqMsgID: reqMsgID, + delivery: newRPCResultDelivery(reqMsgID), + } + var logical, firstAttempt, secondAttempt atomic.Int32 + base.setDeliveryHook(func() { logical.Add(1) }) + first, err := cloneRPCResultForRequest(base, reqMsgID, false) + if err != nil { + t.Fatal(err) + } + second, err := cloneRPCResultForRequest(base, reqMsgID, false) + if err != nil { + t.Fatal(err) + } + first.setAttemptDeliveryHook(func() { firstAttempt.Add(1) }) + second.setAttemptDeliveryHook(func() { secondAttempt.Add(1) }) + first.markDelivered() + deadline := time.Now().Add(time.Second) + for (logical.Load() != 1 || firstAttempt.Load() != 1) && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if logical.Load() != 1 || firstAttempt.Load() != 1 || secondAttempt.Load() != 0 { + t.Fatalf("first delivery hooks = logical:%d first:%d second:%d", logical.Load(), firstAttempt.Load(), secondAttempt.Load()) + } + second.markDelivered() + deadline = time.Now().Add(time.Second) + for secondAttempt.Load() != 1 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if logical.Load() != 1 || firstAttempt.Load() != 1 || secondAttempt.Load() != 1 { + t.Fatalf("second delivery hooks = logical:%d first:%d second:%d", logical.Load(), firstAttempt.Load(), secondAttempt.Load()) + } +} + type blockingOutboundTransport struct { started chan struct{} release chan struct{} @@ -166,7 +204,7 @@ func TestEncodedControlFramesUseIndependentBudgetForQueuedAndPendingLifetime(t * defer cancel() // One content frame fills the ordinary body budget and remains pending. - if err := c.Send(ctx, proto.MessageFromServer, &tg.UpdatesTooLong{}); err != nil { + if err := c.SendEncoded(ctx, proto.MessageFromServer, exactTestUpdatesTooLong(t, c)); err != nil { t.Fatalf("fill body budget: %v", err) } first, err := crypto.NewClientCipher(rand.Reader).DecryptFromBuffer(c.key, &bin.Buffer{Buf: tr.lastFrame()}) @@ -297,7 +335,7 @@ func TestOutboundScratchAdmissionUsesWriteTimeoutWithoutClosingHealthyConnection c.writeTimeout = 25 * time.Millisecond start := time.Now() - err = c.Send(context.Background(), proto.MessageFromServer, &tg.UpdatesTooLong{}) + err = c.SendEncoded(context.Background(), proto.MessageFromServer, exactTestUpdatesTooLong(t, c)) elapsed := time.Since(start) if !errors.Is(err, context.DeadlineExceeded) { t.Fatalf("scratch admission err = %v, want deadline exceeded", err) @@ -319,7 +357,7 @@ func TestOutboundScratchAdmissionUsesWriteTimeoutWithoutClosingHealthyConnection pool.release(blocker) c.writeTimeout = time.Second - if err := c.Send(context.Background(), proto.MessageFromServer, &tg.UpdatesTooLong{}); err != nil { + if err := c.SendEncoded(context.Background(), proto.MessageFromServer, exactTestUpdatesTooLong(t, c)); err != nil { t.Fatalf("send after scratch capacity returned: %v", err) } if got := tr.sends.Load(); got != 1 { @@ -387,6 +425,7 @@ func newOutboundTestConn(t *testing.T, tr transport.Conn, budget *outboundTracke sessionID: 456, outboundTrackedBudget: budget, } + legacyCanonicalTestConn(t, c) c.startOutbound() t.Cleanup(c.Close) return c @@ -506,6 +545,7 @@ func TestOutboundActorSerializesConcurrentSends(t *testing.T) { clientMsgID := proto.NewMessageIDGen(time.Now) sendEncrypted(t, conn, cipher, auth, clientMsgID.New(proto.MessageFromClient), &mt.PingRequest{PingID: 1}) collectReplies(t, conn, cipher, auth.AuthKey, mt.MsgsAckTypeID) + freezeActiveTestSessionProfile(t, srv.Conns(), auth.AuthKey.ID, auth.SessionID, tg.LayerProfileCanonical) srv.Conns().SetReceivesUpdates(auth.SessionID, true) const sends = 64 @@ -556,7 +596,7 @@ func TestOutboundWriteErrorTerminallyClosesWithoutActorDeadlock(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - if err := c.Send(ctx, proto.MessageFromServer, &tg.UpdatesTooLong{}); err == nil { + if err := c.SendEncoded(ctx, proto.MessageFromServer, exactTestUpdatesTooLong(t, c)); err == nil { t.Fatal("Send unexpectedly succeeded") } select { @@ -567,7 +607,7 @@ func TestOutboundWriteErrorTerminallyClosesWithoutActorDeadlock(t *testing.T) { if got := tr.closes.Load(); got != 1 { t.Fatalf("transport closes = %d, want 1", got) } - if err := c.Send(ctx, proto.MessageFromServer, &tg.UpdatesTooLong{}); !errors.Is(err, ErrConnClosed) { + if err := c.SendEncoded(ctx, proto.MessageFromServer, exactTestUpdatesTooLong(t, c)); !errors.Is(err, ErrConnClosed) { t.Fatalf("second Send err = %v, want ErrConnClosed", err) } if got := tr.sends.Load(); got != 1 { @@ -581,7 +621,7 @@ func TestOutboundResendWriteErrorTerminallyCloses(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - if err := c.Send(ctx, proto.MessageFromServer, &tg.UpdatesTooLong{}); err != nil { + if err := c.SendEncoded(ctx, proto.MessageFromServer, exactTestUpdatesTooLong(t, c)); err != nil { t.Fatalf("initial Send: %v", err) } data, err := crypto.NewClientCipher(rand.Reader).DecryptFromBuffer(c.key, &bin.Buffer{Buf: tr.lastFrame()}) @@ -608,7 +648,7 @@ func TestOutboundTrackedBudgetSharedAcrossConnections(t *testing.T) { tr2 := &failAfterTransport{} c1 := newOutboundTestConn(t, tr1, budget) c2 := newOutboundTestConn(t, tr2, budget) - body := &encodedOutboundMessage{body: make([]byte, 8), typeID: tg.UpdatesTooLongTypeID} + body := exactTestUpdatesEncoded(t, c1, make([]byte, 8)) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() @@ -687,7 +727,7 @@ func TestOutboundGlobalBudgetIncludesQueuedBodies(t *testing.T) { budget := newOutboundTrackedBudget(24) tr := newBlockingOutboundTransport() c := newOutboundTestConn(t, tr, budget) - body := &encodedOutboundMessage{body: make([]byte, 8), typeID: tg.UpdatesTooLongTypeID} + body := exactTestUpdatesEncoded(t, c, make([]byte, 8)) if err := c.SendBestEffortEncoded(context.Background(), proto.MessageFromServer, body, 0); err != nil { t.Fatalf("enqueue writing body: %v", err) @@ -733,7 +773,7 @@ func TestOutboundOversizedBodyRejectedBeforeEncryption(t *testing.T) { budget := newOutboundTrackedBudget(64 << 20) tr := &failAfterTransport{} c := newOutboundTestConn(t, tr, budget) - body := &encodedOutboundMessage{body: make([]byte, maxOutboundBodyBytes+1), typeID: tg.UpdatesTooLongTypeID} + body := exactTestUpdatesEncoded(t, c, make([]byte, maxOutboundBodyBytes+1)) err := c.SendEncoded(context.Background(), proto.MessageFromServer, body) if !errors.Is(err, ErrOutboundMessageTooLarge) { t.Fatalf("oversized outbound err = %v, want ErrOutboundMessageTooLarge", err) @@ -749,7 +789,7 @@ func TestOutboundOversizedBodyRejectedBeforeEncryption(t *testing.T) { func TestOutboundCloseRaceDrainsEveryProducerReservation(t *testing.T) { budget := newOutboundTrackedBudget(1 << 20) c := newOutboundTestConn(t, &failAfterTransport{}, budget) - body := &encodedOutboundMessage{body: make([]byte, 128), typeID: tg.UpdatesTooLongTypeID} + body := exactTestUpdatesEncoded(t, c, make([]byte, 128)) start := make(chan struct{}) var wg sync.WaitGroup for i := 0; i < 128; i++ { @@ -775,7 +815,7 @@ func TestOutboundTrackedBudgetAckAndCloseReturnExactly(t *testing.T) { c := newOutboundTestConn(t, tr, budget) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - body := &encodedOutboundMessage{body: make([]byte, 12), typeID: tg.UpdatesTooLongTypeID} + body := exactTestUpdatesEncoded(t, c, make([]byte, 12)) if err := c.SendEncoded(ctx, proto.MessageFromServer, body); err != nil { t.Fatalf("send: %v", err) } @@ -801,7 +841,7 @@ func TestOutboundTrackedBudgetAckAndCloseReturnExactly(t *testing.T) { c := newOutboundTestConn(t, &failAfterTransport{}, budget) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - body := &encodedOutboundMessage{body: make([]byte, 12), typeID: tg.UpdatesTooLongTypeID} + body := exactTestUpdatesEncoded(t, c, make([]byte, 12)) if err := c.SendEncoded(ctx, proto.MessageFromServer, body); err != nil { t.Fatalf("send: %v", err) } @@ -822,7 +862,7 @@ func TestOutboundTrackedBudgetWriteFailureReturnsReservation(t *testing.T) { c := newOutboundTestConn(t, tr, budget) ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() - body := &encodedOutboundMessage{body: make([]byte, 12), typeID: tg.UpdatesTooLongTypeID} + body := exactTestUpdatesEncoded(t, c, make([]byte, 12)) if err := c.SendEncoded(ctx, proto.MessageFromServer, body); err == nil { t.Fatal("send unexpectedly succeeded") } @@ -995,6 +1035,7 @@ func TestOutboundResendAndAckState(t *testing.T) { clientMsgID := proto.NewMessageIDGen(time.Now) sendEncrypted(t, conn, cipher, auth, clientMsgID.New(proto.MessageFromClient), &mt.PingRequest{PingID: 1}) collectReplies(t, conn, cipher, auth.AuthKey, mt.MsgsAckTypeID) + freezeActiveTestSessionProfile(t, srv.Conns(), auth.AuthKey.ID, auth.SessionID, tg.LayerProfileCanonical) srv.Conns().SetReceivesUpdates(auth.SessionID, true) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) diff --git a/internal/mtprotoedge/passkey_e2e_test.go b/internal/mtprotoedge/passkey_e2e_test.go index 6c721d3b..2a274749 100644 --- a/internal/mtprotoedge/passkey_e2e_test.go +++ b/internal/mtprotoedge/passkey_e2e_test.go @@ -14,13 +14,13 @@ import ( "go.uber.org/zap/zaptest" "github.com/gotd/log/logzap" - "github.com/gotd/td/clock" - "github.com/gotd/td/exchange" - "github.com/gotd/td/session" - "github.com/gotd/td/telegram" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/tg" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/session" + "github.com/iamxvbaba/td/telegram" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/transport" "telesrv/internal/app/account" "telesrv/internal/app/auth" @@ -115,7 +115,7 @@ func TestPasskeyEndToEnd(t *testing.T) { Passkey: passkeyService, } router := rpc.New(rpc.Config{DC: dc, IP: tcpAddr.IP.String(), Port: tcpAddr.Port}, deps, zaptest.NewLogger(t), clock.System) - srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, RPC: router}) + srv := New(Options{Logger: zaptest.NewLogger(t), DC: dc, RSAKey: rsaKey, AuthKeys: authKeyStore, LayerRPC: router}) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) serveErr := make(chan error, 1) diff --git a/internal/mtprotoedge/pending_flush_test.go b/internal/mtprotoedge/pending_flush_test.go index 89326c30..d92077c7 100644 --- a/internal/mtprotoedge/pending_flush_test.go +++ b/internal/mtprotoedge/pending_flush_test.go @@ -5,9 +5,9 @@ import ( "testing" "time" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) // TestSetReceivesUpdatesFlushesPendingBeforeActivation 验证置位时先排空暂存推送 @@ -23,6 +23,7 @@ func TestSetReceivesUpdatesFlushesPendingBeforeActivation(t *testing.T) { collectReplies(t, conn, cipher, auth.AuthKey, mt.MsgsAckTypeID) raw := auth.AuthKey.ID + freezeActiveTestSessionProfile(t, srv.Conns(), raw, auth.SessionID, tg.LayerProfileCanonical) ctx := context.Background() // 完全就绪还要求 membership 路由建立(ReceivesUpdatesForAuthKey 的另一半条件)。 diff --git a/internal/mtprotoedge/production_compat_test.go b/internal/mtprotoedge/production_compat_test.go index fecfbcff..2e32b474 100644 --- a/internal/mtprotoedge/production_compat_test.go +++ b/internal/mtprotoedge/production_compat_test.go @@ -8,8 +8,9 @@ import ( "go.uber.org/zap" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) var ErrSessionAmbiguous = errors.New("session id is shared by multiple auth keys") @@ -153,7 +154,17 @@ func (m *SessionManager) SetReceivesUpdates(sessionID int64, receives bool) { } } -func (m *SessionManager) PushToSession(ctx context.Context, sessionID int64, t proto.MessageType, msg bin.Encoder) error { +func (m *SessionManager) SetLayerProfile(sessionID int64, profile tg.LayerProfile) bool { + m.mu.RLock() + c, _, ok, ambiguous := m.uniqueSessionForTestLocked(sessionID) + m.mu.RUnlock() + if ambiguous || !ok { + return false + } + return c.SeedLayerProfile(profile) == nil +} + +func (m *SessionManager) PushToSession(ctx context.Context, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error { m.mu.RLock() c, key, ok, ambiguous := m.uniqueSessionForTestLocked(sessionID) if ambiguous { @@ -167,20 +178,28 @@ func (m *SessionManager) PushToSession(ctx context.Context, sessionID int64, t p ready := c.receivesUpdates.Load() m.mu.RUnlock() if ready { - return c.Send(ctx, t, msg) + updates, err := newLayerUpdatesFanoutContext(ctx, msg) + if err != nil { + return err + } + encoded, err := updates.prepareForConn(ctx, c) + if err != nil { + return err + } + return c.SendEncoded(ctx, t, encoded) } return m.queueOrSendPrepared(ctx, key, t, msg) } -func (m *SessionManager) PushToUser(ctx context.Context, userID int64, t proto.MessageType, msg bin.Encoder) (int, error) { +func (m *SessionManager) PushToUser(ctx context.Context, userID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) { return m.PushToUserExceptAuthKeySession(ctx, userID, [8]byte{}, 0, t, msg) } -func (m *SessionManager) PushToUserExceptSession(ctx context.Context, userID, excludeSessionID int64, t proto.MessageType, msg bin.Encoder) (int, error) { +func (m *SessionManager) PushToUserExceptSession(ctx context.Context, userID, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) { return m.pushToUser(ctx, userID, nil, excludeSessionID, t, msg) } -func (m *SessionManager) PushToUserExceptSessionBestEffort(ctx context.Context, userID, excludeSessionID int64, t proto.MessageType, msg bin.Encoder, timeout time.Duration) (int, error) { +func (m *SessionManager) PushToUserExceptSessionBestEffort(ctx context.Context, userID, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error) { return m.pushToUserBestEffort(ctx, userID, nil, excludeSessionID, t, msg, timeout) } @@ -207,8 +226,8 @@ func (m *SessionManager) OnlineChannelIDsAfter(afterChannelID int64, limit int) return all[start:end] } -func (m *SessionManager) queueLocked(key sessionKey, t proto.MessageType, msg bin.Encoder) bool { - encoded, reservation, err := m.preparePendingPush(context.Background(), msg) +func (m *SessionManager) queueLocked(key sessionKey, t proto.MessageType, msg tg.UpdatesClass) bool { + updates, reservation, err := m.preparePendingPush(onceLayerUpdatesFanout(context.Background(), msg)) if err != nil { m.log.Debug("Drop pending push outside byte budget", zap.String("auth_key_id", sessionKeyLog(key.authKeyID)), @@ -218,7 +237,7 @@ func (m *SessionManager) queueLocked(key sessionKey, t proto.MessageType, msg bi return false } defer reservation.release() - return m.queuePreparedLocked(key, t, encoded, reservation) + return m.queuePreparedLocked(key, t, updates, reservation) } func (cs *connState) track(msgID int64, seqNo int32, content bool, state byte) { diff --git a/internal/mtprotoedge/provisional_revocation_test.go b/internal/mtprotoedge/provisional_revocation_test.go index b958a383..516f85ca 100644 --- a/internal/mtprotoedge/provisional_revocation_test.go +++ b/internal/mtprotoedge/provisional_revocation_test.go @@ -8,11 +8,11 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/tg" "telesrv/internal/store" "telesrv/internal/store/memory" @@ -59,7 +59,7 @@ func TestBadSaltStormRevalidatesStoreOnlyAtActivationBoundary(t *testing.T) { const dc = 2 keys := &countingAuthKeyStore{AuthKeyStore: memory.NewAuthKeyStore()} handler := &admissionCountingRPC{} - addr, pub, _ := startTestServer(t, Options{DC: dc, AuthKeys: keys, RPC: handler}) + addr, pub, _ := startTestServer(t, Options{DC: dc, AuthKeys: keys, legacyRPC: handler}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) ids := proto.NewMessageIDGen(time.Now) firstID := ids.New(proto.MessageFromClient) @@ -104,7 +104,7 @@ func TestActivationFinalAuthKeyCheckRunsAfterClaim(t *testing.T) { } }() handler := &admissionCountingRPC{} - addr, pub, srv := startTestServer(t, Options{DC: dc, AuthKeys: keys, RPC: handler}) + addr, pub, srv := startTestServer(t, Options{DC: dc, AuthKeys: keys, legacyRPC: handler}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) msgID := proto.NewMessageIDGen(time.Now).New(proto.MessageFromClient) @@ -148,7 +148,7 @@ func TestActivationFinalAuthKeyCheckRunsAfterClaim(t *testing.T) { func TestBadSaltProvisionalCannotReactivateDeletedAuthKey(t *testing.T) { const dc = 2 handler := &admissionCountingRPC{} - addr, pub, srv := startTestServer(t, Options{DC: dc, RPC: handler}) + addr, pub, srv := startTestServer(t, Options{DC: dc, legacyRPC: handler}) provisional, auth, cipher := dialHandshake(t, addr, dc, pub) ids := proto.NewMessageIDGen(time.Now) reqMsgID := ids.New(proto.MessageFromClient) @@ -174,12 +174,13 @@ func TestBadSaltProvisionalCannotReactivateDeletedAuthKey(t *testing.T) { destroyer := dialTransportOnly(t, addr) destroySessionID := auth.SessionID ^ 1 destroyBody := encodeClientMessageBodyForTest(t, &destroyAuthKeyRequest{}) + destroyReqMsgID := ids.New(proto.MessageFromClient) sendEncryptedWithSessionSaltAndSeq( t, destroyer, cipher, auth, destroySessionID, auth.ServerSalt, - ids.New(proto.MessageFromClient), 1, destroyBody, + destroyReqMsgID, 1, destroyBody, ) - destroyReplies := collectReplies(t, destroyer, cipher, auth.AuthKey, destroyAuthKeyOkTypeID) - mustHave(t, destroyReplies, destroyAuthKeyOkTypeID, "destroy_auth_key_ok") + destroyReplies := collectReplies(t, destroyer, cipher, auth.AuthKey, proto.ResultTypeID) + assertDestroyAuthKeyRPCResult(t, mustHave(t, destroyReplies, proto.ResultTypeID, "destroy_auth_key rpc_result"), destroyReqMsgID, destroyAuthKeyOkTypeID) if _, found, err := srv.authKeys.Get(context.Background(), auth.AuthKey.ID); err != nil || found { t.Fatalf("auth key after destroy: found=%v err=%v", found, err) } diff --git a/internal/mtprotoedge/quick_ack_deadline_test.go b/internal/mtprotoedge/quick_ack_deadline_test.go index 41e79681..75099a4f 100644 --- a/internal/mtprotoedge/quick_ack_deadline_test.go +++ b/internal/mtprotoedge/quick_ack_deadline_test.go @@ -5,8 +5,8 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" ) type quickAckDeadlineProbe struct { diff --git a/internal/mtprotoedge/rpc_admission_tracker.go b/internal/mtprotoedge/rpc_admission_tracker.go new file mode 100644 index 00000000..700cea5a --- /dev/null +++ b/internal/mtprotoedge/rpc_admission_tracker.go @@ -0,0 +1,95 @@ +package mtprotoedge + +import ( + "math" + "sync" + "sync/atomic" +) + +const rpcAdmissionTrackerShards = 64 + +// rpcAdmissionTracker retains exactly the admission sequences whose unique +// owner can still publish/complete. Allocation holds the barrier from sequence +// CAS through shard registration, so a stable floor scan can never observe an +// allocated-but-not-yet-active gap. +type rpcAdmissionTracker struct { + allocationBarrier sync.RWMutex + shards [rpcAdmissionTrackerShards]rpcAdmissionTrackerShard +} + +type rpcAdmissionTrackerShard struct { + mu sync.Mutex + active map[uint64]struct{} +} + +func (t *rpcAdmissionTracker) allocateAndRegister(next *atomic.Uint64) (uint64, error) { + if t == nil || next == nil { + return 0, ErrRPCResultFlightInvalid + } + t.allocationBarrier.RLock() + defer t.allocationBarrier.RUnlock() + var sequence uint64 + for { + current := next.Load() + if current == math.MaxUint64 { + return 0, ErrRPCAdmissionSeqExhausted + } + sequence = current + 1 + if next.CompareAndSwap(current, sequence) { + break + } + } + shard := &t.shards[sequence&(rpcAdmissionTrackerShards-1)] + shard.mu.Lock() + if shard.active == nil { + shard.active = make(map[uint64]struct{}) + } + shard.active[sequence] = struct{}{} + shard.mu.Unlock() + return sequence, nil +} + +func (t *rpcAdmissionTracker) retire(sequence uint64) { + if t == nil || sequence == 0 { + return + } + shard := &t.shards[sequence&(rpcAdmissionTrackerShards-1)] + shard.mu.Lock() + if _, ok := shard.active[sequence]; !ok { + shard.mu.Unlock() + panic("mtprotoedge: rpc admission sequence retired more than once") + } + delete(shard.active, sequence) + shard.mu.Unlock() +} + +// stableSafeFloor returns the lowest sequence which can still publish, or one +// past the last allocated sequence when no owner remains. The short exclusive +// barrier blocks only admission sequence allocation/registration; handler, +// encoding and delivery stay fully concurrent. +func (t *rpcAdmissionTracker) stableSafeFloor(next *atomic.Uint64) uint64 { + if t == nil || next == nil { + return 0 + } + t.allocationBarrier.Lock() + defer t.allocationBarrier.Unlock() + var minimum uint64 + for index := range t.shards { + shard := &t.shards[index] + shard.mu.Lock() + for sequence := range shard.active { + if minimum == 0 || sequence < minimum { + minimum = sequence + } + } + shard.mu.Unlock() + } + if minimum != 0 { + return minimum + } + last := next.Load() + if last == math.MaxUint64 { + return math.MaxUint64 + } + return last + 1 +} diff --git a/internal/mtprotoedge/rpc_delivery_coordinator_test.go b/internal/mtprotoedge/rpc_delivery_coordinator_test.go new file mode 100644 index 00000000..605cdf77 --- /dev/null +++ b/internal/mtprotoedge/rpc_delivery_coordinator_test.go @@ -0,0 +1,467 @@ +package mtprotoedge + +import ( + "context" + "errors" + "sync" + "sync/atomic" + "testing" + "time" +) + +func TestRPCDeliveryCoordinatorWaitsFromClaimedThroughDone(t *testing.T) { + coordinator := newRPCResultDelivery(1).coordinator + started := make(chan struct{}) + release := make(chan struct{}) + coordinator.setHook(func() { + close(started) + <-release + }) + + claim, err := coordinator.claimReplayDeliveredHook(context.Background(), false) + if err != nil || claim == nil { + t.Fatalf("initial hook claim = %p, err=%v", claim, err) + } + if got := coordinator.hookState(); got != rpcResultDeliveryHookClaimed { + t.Fatalf("hook state after claim = %d, want claimed", got) + } + + type claimResult struct { + claim *rpcResultDeliveryHookClaim + err error + } + waited := make(chan claimResult, 1) + go func() { + other, waitErr := coordinator.claimReplayDeliveredHook(context.Background(), false) + waited <- claimResult{claim: other, err: waitErr} + }() + select { + case result := <-waited: + t.Fatalf("second replay passed a claimed hook: claim=%p err=%v", result.claim, result.err) + case <-time.After(20 * time.Millisecond): + } + + go claim.run() + select { + case <-started: + case <-time.After(time.Second): + t.Fatal("claimed hook did not enter in-progress") + } + if got := coordinator.hookState(); got != rpcResultDeliveryHookInProgress { + t.Fatalf("hook state while callback blocked = %d, want in-progress", got) + } + select { + case result := <-waited: + t.Fatalf("second replay passed an in-progress hook: claim=%p err=%v", result.claim, result.err) + case <-time.After(20 * time.Millisecond): + } + + close(release) + select { + case result := <-waited: + if result.err != nil || result.claim != nil { + t.Fatalf("wait after done = claim:%p err:%v", result.claim, result.err) + } + case <-time.After(time.Second): + t.Fatal("completion did not notify the waiting replay") + } + if got := coordinator.hookState(); got != rpcResultDeliveryHookDone { + t.Fatalf("terminal hook state = %d, want done", got) + } +} + +func TestRPCDeliveryCoordinatorAbandonedClaimCannotRunAfterReacquire(t *testing.T) { + coordinator := newRPCResultDelivery(1).coordinator + var calls atomic.Int32 + coordinator.setHook(func() { calls.Add(1) }) + + stale, err := coordinator.claimReplayDeliveredHook(context.Background(), false) + if err != nil || stale == nil || !stale.abandon() { + t.Fatalf("abandon initial claim = %p err=%v", stale, err) + } + current, err := coordinator.claimReplayDeliveredHook(context.Background(), false) + if err != nil || current == nil { + t.Fatalf("reacquire hook = %p err=%v", current, err) + } + stale.run() + if got := calls.Load(); got != 0 { + t.Fatalf("stale claim calls = %d, want 0", got) + } + if got := coordinator.hookState(); got != rpcResultDeliveryHookClaimed { + t.Fatalf("stale claim changed current state to %d", got) + } + current.run() + if got := calls.Load(); got != 1 { + t.Fatalf("current claim calls = %d, want 1", got) + } + if got := coordinator.hookState(); got != rpcResultDeliveryHookDone { + t.Fatalf("terminal hook state = %d, want done", got) + } +} + +func TestBoundedRPCReplayRestoreDoesNotRetainWorkerOrBarrier(t *testing.T) { + s := New(Options{}) + c := &Conn{metrics: NopMetrics{}} + finishBarrier := c.beginRPCReplayRestore() + + coordinator := newRPCResultDelivery(1).coordinator + var hookCalls atomic.Int32 + coordinator.setHook(func() { hookCalls.Add(1) }) + claim, err := coordinator.claimReplayDeliveredHook(context.Background(), false) + if err != nil || claim == nil { + t.Fatalf("claim hook = %p err=%v", claim, err) + } + + replacementStarted := make(chan struct{}) + releaseReplacement := make(chan struct{}) + t.Cleanup(func() { + select { + case <-releaseReplacement: + default: + close(releaseReplacement) + } + }) + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + started := time.Now() + restoreResult := make(chan error, 1) + go func() { + restoreResult <- s.runBoundedRPCReplayRestore(ctx, c, "non-cooperative replacement", claim, func() error { + close(replacementStarted) + <-releaseReplacement // Deliberately ignores ctx. + return nil + }) + }() + select { + case <-replacementStarted: + case <-time.After(time.Second): + t.Fatal("replacement callback never started") + } + select { + case err = <-restoreResult: + case <-time.After(time.Second): + t.Fatal("bounded restore retained its caller past the watchdog") + } + if !errors.Is(err, context.DeadlineExceeded) { + t.Fatalf("bounded restore error = %v, want deadline", err) + } + if elapsed := time.Since(started); elapsed > 500*time.Millisecond { + t.Fatalf("non-cooperative restore retained caller for %v", elapsed) + } + finishBarrier() + if !c.isRetired() { + t.Fatal("timed-out restore did not fence its physical generation") + } + c.rpcMu.Lock() + pendingBarriers := c.rpcReplayRestores + c.rpcMu.Unlock() + if pendingBarriers != 0 { + t.Fatalf("timed-out restore retained %d scheduler barriers", pendingBarriers) + } + if got := coordinator.hookState(); got != rpcResultDeliveryHookPending { + t.Fatalf("not-yet-started timed-out hook state = %d, want pending", got) + } + + // A replacement replay can now acquire the logical hook. The old blocked + // goroutine holds a stale token and must not execute it when it eventually + // returns. + retry, err := coordinator.claimReplayDeliveredHook(context.Background(), false) + if err != nil || retry == nil { + t.Fatalf("retry hook claim = %p err=%v", retry, err) + } + retry.run() + close(releaseReplacement) + deadline := time.Now().Add(time.Second) + for len(rpcReplayRestoreSlots) != 0 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if got := hookCalls.Load(); got != 1 { + t.Fatalf("logical hook calls after stale restore return = %d, want 1", got) + } +} + +func TestBoundedRPCReplayRestoreKeepsInProgressHookAtMostOnce(t *testing.T) { + s := New(Options{}) + c := &Conn{metrics: NopMetrics{}} + finishBarrier := c.beginRPCReplayRestore() + + coordinator := newRPCResultDelivery(1).coordinator + hookStarted := make(chan struct{}) + releaseHook := make(chan struct{}) + t.Cleanup(func() { + select { + case <-releaseHook: + default: + close(releaseHook) + } + }) + coordinator.setHook(func() { + close(hookStarted) + <-releaseHook // Deliberately ignores the restore deadline. + }) + claim, err := coordinator.claimReplayDeliveredHook(context.Background(), false) + if err != nil || claim == nil { + t.Fatalf("claim hook = %p err=%v", claim, err) + } + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) + defer cancel() + restoreResult := make(chan error, 1) + go func() { + restoreResult <- s.runBoundedRPCReplayRestore(ctx, c, "non-cooperative logical hook", claim, nil) + }() + select { + case <-hookStarted: + case <-time.After(time.Second): + t.Fatal("logical hook never entered in-progress") + } + select { + case err = <-restoreResult: + case <-time.After(time.Second): + t.Fatal("non-cooperative logical hook retained its caller past the watchdog") + } + if !errors.Is(err, context.DeadlineExceeded) { + t.Fatalf("bounded logical-hook error = %v, want deadline", err) + } + if got := coordinator.hookState(); got != rpcResultDeliveryHookInProgress { + t.Fatalf("timed-out logical hook state = %d, want in-progress", got) + } + finishBarrier() + if !c.isRetired() { + t.Fatal("timed-out logical hook did not fence its physical generation") + } + c.rpcMu.Lock() + pendingBarriers := c.rpcReplayRestores + c.rpcMu.Unlock() + if pendingBarriers != 0 { + t.Fatalf("timed-out logical hook retained %d scheduler barriers", pendingBarriers) + } + + waitCtx, waitCancel := context.WithTimeout(context.Background(), 20*time.Millisecond) + defer waitCancel() + if retry, retryErr := coordinator.claimReplayDeliveredHook(waitCtx, false); retry != nil || + !errors.Is(retryErr, context.DeadlineExceeded) { + t.Fatalf("retry during in-progress hook = claim:%p err:%v", retry, retryErr) + } + close(releaseHook) + deadline := time.Now().Add(time.Second) + for coordinator.hookState() != rpcResultDeliveryHookDone && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if got := coordinator.hookState(); got != rpcResultDeliveryHookDone { + t.Fatalf("released logical hook state = %d, want done", got) + } +} + +func TestCachedReplacementReplayBarrierWaitsForLogicalHookDone(t *testing.T) { + s := New(Options{}) + const reqMsgID = int64(71001) + encoded := encodedRPCResultForPriorityTest(reqMsgID, 0) + encoded.delivery = newRPCResultDelivery(reqMsgID) + + var order atomic.Int32 + hookStarted := make(chan struct{}) + releaseHook := make(chan struct{}) + t.Cleanup(func() { + select { + case <-releaseHook: + default: + close(releaseHook) + } + }) + encoded.setDeliveryHook(func() { + close(hookStarted) + <-releaseHook + if !order.CompareAndSwap(1, 2) { + panic("logical hook did not follow first replacement restore") + } + }) + + firstConn := newOutboundTestConn(t, &collectingSessionTransport{}, newOutboundTrackedBudget(1<<20)) + firstResult := make(chan error, 1) + go func() { + firstResult <- s.sendCachedRPCResultWithHook(context.Background(), firstConn, encoded, func() error { + if !order.CompareAndSwap(0, 1) { + return errors.New("first replacement restore ran out of order") + } + return nil + }) + }() + select { + case <-hookStarted: + case <-time.After(time.Second): + t.Fatal("first replacement did not enter logical hook") + } + if got := encoded.delivery.coordinator.hookState(); got != rpcResultDeliveryHookInProgress { + t.Fatalf("shared hook state = %d, want in-progress", got) + } + + secondTransport := &collectingSessionTransport{} + secondConn := newOutboundTestConn(t, secondTransport, newOutboundTrackedBudget(1<<20)) + secondReplacement := make(chan struct{}) + secondResult := make(chan error, 1) + go func() { + secondResult <- s.sendCachedRPCResultWithHook(context.Background(), secondConn, encoded, func() error { + if !order.CompareAndSwap(2, 3) { + return errors.New("second replacement restore passed logical hook completion") + } + close(secondReplacement) + return nil + }) + }() + deadline := time.Now().Add(time.Second) + for len(secondTransport.snapshot()) == 0 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if len(secondTransport.snapshot()) == 0 { + t.Fatal("second replacement did not physically deliver cached result") + } + secondConn.rpcMu.Lock() + secondBarriers := secondConn.rpcReplayRestores + secondConn.rpcMu.Unlock() + if secondBarriers != 1 { + t.Fatalf("second replacement barriers while hook in progress = %d, want 1", secondBarriers) + } + select { + case err := <-secondResult: + t.Fatalf("second replacement returned before hook done: %v", err) + case <-time.After(20 * time.Millisecond): + } + select { + case <-secondReplacement: + t.Fatal("second replacement metadata ran before shared hook done") + default: + } + + close(releaseHook) + for name, result := range map[string]<-chan error{ + "first": firstResult, "second": secondResult, + } { + select { + case err := <-result: + if err != nil { + t.Fatalf("%s replacement replay: %v", name, err) + } + case <-time.After(time.Second): + t.Fatalf("%s replacement replay did not finish", name) + } + } + if got := order.Load(); got != 3 { + t.Fatalf("replacement/logical terminal order = %d, want 3", got) + } + secondConn.rpcMu.Lock() + secondBarriers = secondConn.rpcReplayRestores + secondConn.rpcMu.Unlock() + if secondBarriers != 0 { + t.Fatalf("second replacement retained %d barriers after hook done", secondBarriers) + } +} + +func TestRPCRewrapWatchdogCoversCommittedRestoreWithoutBlockingTimerOrWorker(t *testing.T) { + s := New(Options{}) + c := &Conn{metrics: NopMetrics{}} + const reqMsgID = int64(72001) + encoded := encodedRPCResultForPriorityTest(reqMsgID, 0) + encoded.delivery = newRPCResultDelivery(reqMsgID) + var logicalCalls atomic.Int32 + encoded.setDeliveryHook(func() { logicalCalls.Add(1) }) + + replacementStarted := make(chan struct{}) + releaseReplacement := make(chan struct{}) + t.Cleanup(func() { + select { + case <-releaseReplacement: + default: + close(releaseReplacement) + } + }) + alias := &rpcRewrapAlias{ + conn: c, newReqID: reqMsgID, method: "help.getConfig", + afterSuccessfulDelivery: func() error { + close(replacementStarted) + <-releaseReplacement // Deliberately ignores every deadline. + return nil + }, + } + alias.executionOK.Store(true) + alias.beginReplayRestore() + + var ( + once sync.Once + jobs chan rpcRewrapDeliveryJob + ) + workerDone := make(chan error, 1) + watchdogDone := make(chan struct{}) + job := rpcRewrapDeliveryJob{ + deadline: time.Now().Add(80 * time.Millisecond), + run: func(control *rpcRewrapDeliveryControl, _ time.Time) { + if !control.commit() { + workerDone <- errors.New("commit lost before restore") + return + } + restoreCtx, cancel := context.WithTimeout(context.Background(), 250*time.Millisecond) + defer cancel() + workerDone <- s.completeDeliveredRPCRewrapResult( + restoreCtx, alias, encoded, "committed restore watchdog regression", + ) + }, + fail: func(error) { + c.fenceUndeliveredRPCResult() + alias.releaseReplayRestoreBarrier() + close(watchdogDone) + }, + } + if !scheduleRPCRewrapJob(job, &once, &jobs, 1, 2) { + t.Fatal("schedule committed restore job") + } + select { + case <-replacementStarted: + case <-time.After(time.Second): + t.Fatal("committed replacement restore never started") + } + select { + case <-watchdogDone: + case <-time.After(500 * time.Millisecond): + t.Fatal("committed-state watchdog did not return promptly") + } + if !c.isRetired() { + t.Fatal("committed-state watchdog did not fence connection") + } + c.rpcMu.Lock() + pendingBarriers := c.rpcReplayRestores + c.rpcMu.Unlock() + if pendingBarriers != 0 { + t.Fatalf("watchdog retained %d scheduler barriers", pendingBarriers) + } + select { + case err := <-workerDone: + if !errors.Is(err, context.DeadlineExceeded) { + t.Fatalf("bounded committed restore error = %v, want deadline", err) + } + case <-time.After(time.Second): + t.Fatal("non-cooperative restore permanently retained rewrap worker") + } + + followingRan := make(chan struct{}) + if !scheduleRPCRewrapJob(rpcRewrapDeliveryJob{ + deadline: time.Now().Add(time.Second), + run: func(*rpcRewrapDeliveryControl, time.Time) { close(followingRan) }, + }, &once, &jobs, 1, 2) { + t.Fatal("schedule following rewrap job") + } + select { + case <-followingRan: + case <-time.After(time.Second): + t.Fatal("rewrap worker did not accept following job after restore timeout") + } + if got := encoded.delivery.coordinator.hookState(); got != rpcResultDeliveryHookPending { + t.Fatalf("timed-out pre-hook restore state = %d, want pending", got) + } + if got := logicalCalls.Load(); got != 0 { + t.Fatalf("logical hook ran behind non-cooperative replacement = %d", got) + } + close(releaseReplacement) + deadline := time.Now().Add(time.Second) + for len(rpcReplayRestoreSlots) != 0 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } +} diff --git a/internal/mtprotoedge/rpc_delivery_hook_executor_test.go b/internal/mtprotoedge/rpc_delivery_hook_executor_test.go new file mode 100644 index 00000000..e75127cc --- /dev/null +++ b/internal/mtprotoedge/rpc_delivery_hook_executor_test.go @@ -0,0 +1,111 @@ +package mtprotoedge + +import ( + "errors" + "sync/atomic" + "testing" + "time" +) + +func hookTestMessage(reqMsgID int64, coordinator *rpcResultDeliveryCoordinator, fn func()) *encodedOutboundMessage { + msg := &encodedOutboundMessage{delivery: newRPCResultDelivery(reqMsgID, coordinator)} + msg.setDeliveryHook(fn) + return msg +} + +func TestRPCDeliveryHookExecutorBoundsAdmissionWithoutBlockingDelivery(t *testing.T) { + executor := newRPCDeliveryHookExecutor(1, 1) + started := make(chan struct{}) + release := make(chan struct{}) + first := hookTestMessage(1, nil, func() { + close(started) + <-release + }) + if err := first.prepareDeliveryHook(executor); err != nil { + t.Fatalf("reserve first hook: %v", err) + } + delivered := make(chan struct{}) + go func() { + first.markDelivered() + close(delivered) + }() + select { + case <-delivered: + case <-time.After(100 * time.Millisecond): + t.Fatal("physical delivery blocked on hook execution") + } + select { + case <-started: + case <-time.After(time.Second): + t.Fatal("first hook did not start") + } + + second := hookTestMessage(2, nil, func() {}) + if err := second.prepareDeliveryHook(executor); !errors.Is(err, ErrRPCDeliveryHookCapacity) { + t.Fatalf("second reservation = %v, want capacity error", err) + } + close(release) + deadline := time.Now().Add(time.Second) + for len(executor.slots) != 0 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if got := len(executor.slots); got != 0 { + t.Fatalf("executor retained %d capacity slots", got) + } +} + +func TestRPCDeliveryHookExecutorIsolatesPanicsAndContinues(t *testing.T) { + executor := newRPCDeliveryHookExecutor(1, 2) + first := hookTestMessage(1, nil, func() { panic("hook boom") }) + done := make(chan struct{}) + second := hookTestMessage(2, nil, func() { close(done) }) + if err := first.prepareDeliveryHook(executor); err != nil { + t.Fatalf("reserve panic hook: %v", err) + } + if err := second.prepareDeliveryHook(executor); err != nil { + t.Fatalf("reserve following hook: %v", err) + } + first.markDelivered() + second.markDelivered() + select { + case <-done: + case <-time.After(time.Second): + t.Fatal("worker stopped after a hook panic") + } + deadline := time.Now().Add(time.Second) + for executor.panics.Load() != 1 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if got := executor.panics.Load(); got != 1 { + t.Fatalf("recorded hook panics = %d, want 1", got) + } +} + +func TestEquivalentRPCDeliveryAttemptsShareExactlyOnceCoordinator(t *testing.T) { + executor := newRPCDeliveryHookExecutor(1, 2) + var calls atomic.Int32 + first := hookTestMessage(11, nil, func() { calls.Add(1) }) + second := hookTestMessage(22, first.delivery.coordinator, nil) + if err := first.prepareDeliveryHook(executor); err != nil { + t.Fatalf("reserve first attempt: %v", err) + } + if err := second.prepareDeliveryHook(executor); err != nil { + t.Fatalf("reserve equivalent attempt: %v", err) + } + first.markDelivered() + second.markDelivered() + deadline := time.Now().Add(time.Second) + for calls.Load() != 1 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if got := calls.Load(); got != 1 { + t.Fatalf("equivalent delivery hooks = %d, want 1", got) + } + deadline = time.Now().Add(time.Second) + for len(executor.slots) != 0 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if got := len(executor.slots); got != 0 { + t.Fatalf("equivalent attempts leaked %d tickets", got) + } +} diff --git a/internal/mtprotoedge/rpc_flight.go b/internal/mtprotoedge/rpc_flight.go index 8aaebff7..875710f8 100644 --- a/internal/mtprotoedge/rpc_flight.go +++ b/internal/mtprotoedge/rpc_flight.go @@ -5,6 +5,8 @@ import ( "errors" "sync" "sync/atomic" + + "github.com/iamxvbaba/td/tg" ) const rpcResultFlightDefaultMaxPending = 8192 @@ -12,10 +14,49 @@ const rpcResultFlightDefaultMaxPending = 8192 var ( // ErrRPCResultFlightCapacity is returned before installing a new owner when // the process-wide in-flight claim table has reached its hard bound. - ErrRPCResultFlightCapacity = errors.New("mtproto rpc result in-flight capacity exhausted") - ErrRPCResultFlightInvalid = errors.New("mtproto rpc result in-flight claim is invalid") + ErrRPCResultFlightCapacity = errors.New("mtproto rpc result in-flight capacity exhausted") + ErrRPCResultSubscriberCapacity = errors.New("mtproto rpc result subscriber capacity exhausted") + ErrRPCResultFlightInvalid = errors.New("mtproto rpc result in-flight claim is invalid") + ErrRPCResultIdentityMismatch = errors.New("mtproto rpc result request identity mismatch") + ErrRPCAdmissionSeqExhausted = errors.New("mtproto rpc admission sequence exhausted") ) +// rpcResultIdentityMismatchError carries the winner's immutable admission +// profile from inside the cache shard critical section. A replacement Conn can +// re-decode the same naked body under that grammar even if the winner aborts +// immediately after the mismatch is returned. +type rpcResultIdentityMismatchError struct { + profile tg.LayerProfile + hasProfile bool +} + +func (e *rpcResultIdentityMismatchError) Error() string { return ErrRPCResultIdentityMismatch.Error() } +func (e *rpcResultIdentityMismatchError) Is(target error) bool { + return target == ErrRPCResultIdentityMismatch +} + +func identityMismatch(identity rpcResultRequestIdentity) error { + return &rpcResultIdentityMismatchError{profile: identity.profile, hasProfile: identity.valid && identity.profile != 0} +} + +type rpcResultRequestIdentity struct { + exact tg.LayerPreparedCallIdentity + // profile is retained separately because LayerPreparedCallIdentity is opaque. + // It lets a same-msg_id replay be re-admitted with the original request + // grammar after the session default has moved to another Layer. + profile tg.LayerProfile + valid bool +} + +func (i rpcResultRequestIdentity) matches(requested rpcResultRequestIdentity) bool { + if !requested.valid { + // Legacy service/test callers carry no API request identity and preserve + // the historical cache lookup behavior. Exact callers must always match. + return true + } + return i.valid && i.exact == requested.exact +} + type rpcResultAcquireState uint8 const ( @@ -32,20 +73,35 @@ const ( // - pending: waiter joins the already-running owner; // - owner: owner must eventually complete through rpcResultCache.Put or Abort. type rpcResultAcquire struct { - state rpcResultAcquireState - encoded *encodedOutboundMessage - waiter *rpcResultWaiter - owner *rpcResultOwnerLease + state rpcResultAcquireState + admissionSeq uint64 + encoded *encodedOutboundMessage + waiter *rpcResultWaiter + owner *rpcResultOwnerLease + executionKnown bool + executionOK bool } -// rpcResultFlight is not part of the completed cache LRU/TTL lifecycle. Its +// rpcResultFlight is not part of the completed cache TTL lifecycle. Its // done channel is closed exactly once while holding the owning cache shard lock; // channel close publishes encoded/ok to all waiters without a waiter goroutine. type rpcResultFlight struct { - done chan struct{} - encoded *encodedOutboundMessage - ok bool - subscribers []func(*encodedOutboundMessage, bool) + done chan struct{} + encoded *encodedOutboundMessage + ok bool + subscribers []func(*encodedOutboundMessage, bool) + executionDone bool + executionOK bool + executionSubscribers []func(bool) + // subscriberSlots counts callbacks retained by this pending flight. Result + // and execution callbacks are charged independently; a replay alias installs + // both atomically so a capacity failure cannot leave half an alias behind. + subscriberSlots int + identity rpcResultRequestIdentity + admissionSeq uint64 + // reservation owns one entry and at least one byte at global, raw-auth and + // session scopes. Put transfers it to a result/tombstone; Abort releases it. + reservation *rpcResultBudgetReservation } type rpcResultWaiter struct { @@ -86,31 +142,107 @@ func (w *rpcResultWaiter) Wait(ctx context.Context) (encoded *encodedOutboundMes // occupying an RPC worker. The callback is invoked after the cache shard lock is // released; it must remain non-blocking. func (w *rpcResultWaiter) Subscribe(fn func(*encodedOutboundMessage, bool)) error { - if w == nil || w.cache == nil || w.flight == nil || fn == nil { + if fn == nil { + return ErrRPCResultFlightInvalid + } + return w.subscribe(fn, nil) +} + +// SubscribeExecution registers a non-blocking callback for the terminal +// business outcome. This is deliberately separate from physical rpc_result +// delivery: invokeAfter* ordering depends on handler completion and must not +// occupy a shared RPC worker while a socket write is pending. +func (w *rpcResultWaiter) SubscribeExecution(fn func(bool)) error { + if fn == nil { + return ErrRPCResultFlightInvalid + } + return w.subscribe(nil, fn) +} + +// SubscribeResultAndExecution atomically installs both halves of one pending +// replay alias. Either both callbacks are retained, or neither is; this avoids +// an execution-only closure surviving when the result subscriber hits a hard +// capacity limit. +func (w *rpcResultWaiter) SubscribeResultAndExecution( + resultFn func(*encodedOutboundMessage, bool), + executionFn func(bool), +) error { + if resultFn == nil || executionFn == nil { + return ErrRPCResultFlightInvalid + } + return w.subscribe(resultFn, executionFn) +} + +func (w *rpcResultWaiter) subscribe( + resultFn func(*encodedOutboundMessage, bool), + executionFn func(bool), +) error { + if w == nil || w.cache == nil || w.flight == nil || (resultFn == nil && executionFn == nil) { return ErrRPCResultFlightInvalid } s := w.cache.shard(w.key) var ( - encoded *encodedOutboundMessage - ok bool - ready bool + encoded *encodedOutboundMessage + resultOK bool + resultReady = resultFn == nil + executionOK bool + executionReady = executionFn == nil ) s.mu.Lock() if flight, exists := s.pending[w.key]; exists && flight == w.flight { - flight.subscribers = append(flight.subscribers, fn) + slots := 0 + if resultFn != nil { + slots++ + } + if executionFn != nil && !flight.executionDone { + slots++ + } + if slots > 0 { + if flight.subscriberSlots > w.cache.subscriberPerFlight-slots || + !w.cache.subscriberBudget.reserve(w.key, slots) { + s.mu.Unlock() + return ErrRPCResultSubscriberCapacity + } + flight.subscriberSlots += slots + } + if resultFn != nil { + flight.subscribers = append(flight.subscribers, resultFn) + } + if executionFn != nil { + if flight.executionDone { + executionOK, executionReady = flight.executionOK, true + } else { + flight.executionSubscribers = append(flight.executionSubscribers, executionFn) + } + } s.mu.Unlock() + if executionReady && executionFn != nil { + executionFn(executionOK) + } return nil } - select { - case <-w.flight.done: - encoded, ok, ready = w.flight.encoded, w.flight.ok, true - default: + if resultFn != nil { + select { + case <-w.flight.done: + encoded, resultOK, resultReady = w.flight.encoded, w.flight.ok, true + default: + } + } + if executionFn != nil && w.flight.executionDone { + executionOK, executionReady = w.flight.executionOK, true } s.mu.Unlock() - if !ready { + // Atomic late subscription also means no callback runs unless every requested + // terminal state is available. + if !resultReady || !executionReady { return ErrRPCResultFlightInvalid } - fn(encoded, ok) + if executionFn != nil { + executionFn(executionOK) + } + if resultFn != nil { + resultFn(encoded, resultOK) + } return nil } @@ -175,6 +307,33 @@ func (l *rpcResultOwnerLease) Delivery() *rpcResultDelivery { return l.delivery } +// CompleteExecution publishes the handler outcome exactly once while this +// lease still owns the flight. success=false includes RPC errors, internal +// failures and dependency failures. Delivery/cache completion remains a +// separate later transition. +func (l *rpcResultOwnerLease) CompleteExecution(success bool) bool { + if l == nil || l.cache == nil || l.flight == nil { + return false + } + s := l.cache.shard(l.key) + s.mu.Lock() + flight, ok := s.pending[l.key] + if !ok || flight != l.flight || flight.executionDone { + s.mu.Unlock() + return false + } + flight.executionDone = true + flight.executionOK = success + subscribers := append([]func(bool){}, flight.executionSubscribers...) + flight.executionSubscribers = nil + l.cache.releaseFlightSubscriberSlotsLocked(l.key, flight, len(subscribers)) + s.mu.Unlock() + for _, subscriber := range subscribers { + subscriber(success) + } + return true +} + // HandOff transfers completion responsibility from the inbound RPC task to an // already-admitted egress operation. The egress terminal callback must resolve // the flight through Put on both successful delivery and fenced failure. @@ -216,9 +375,23 @@ func (l *rpcResultOwnerLease) Abort() bool { return false } delete(s.pending, l.key) + if flight.reservation != nil { + flight.reservation.release() + flight.reservation = nil + } l.cache.flightLimit.release() + l.cache.activeAdmissions.retire(flight.admissionSeq) subscribers := append([]func(*encodedOutboundMessage, bool){}, flight.subscribers...) flight.subscribers = nil + executionSubscribers := append([]func(bool){}, flight.executionSubscribers...) + flight.executionSubscribers = nil + l.cache.releaseFlightSubscriberSlotsLocked( + l.key, flight, len(subscribers)+len(executionSubscribers), + ) + if !flight.executionDone { + flight.executionDone = true + flight.executionOK = false + } close(flight.done) s.mu.Unlock() l.hookMu.Lock() @@ -231,6 +404,9 @@ func (l *rpcResultOwnerLease) Abort() bool { for _, subscriber := range subscribers { subscriber(nil, false) } + for _, subscriber := range executionSubscribers { + subscriber(false) + } return true } @@ -240,25 +416,39 @@ type rpcResultFlightLimit struct { } func (l *rpcResultFlightLimit) reserve() bool { + return l.reserveN(1) +} + +func (l *rpcResultFlightLimit) reserveN(delta int64) bool { if l == nil || l.max <= 0 { return false } + if delta <= 0 { + return false + } for { used := l.used.Load() - if used >= l.max { + if used < 0 || used > l.max-delta { return false } - if l.used.CompareAndSwap(used, used+1) { + if l.used.CompareAndSwap(used, used+delta) { return true } } } func (l *rpcResultFlightLimit) release() { + l.releaseN(1) +} + +func (l *rpcResultFlightLimit) releaseN(delta int64) { if l == nil { return } - if remaining := l.used.Add(-1); remaining < 0 { + if delta <= 0 { + panic("mtproto rpc result counter release must be positive") + } + if remaining := l.used.Add(-delta); remaining < 0 { // Put/Abort use map removal and lease identity to make double release // impossible. Fail fast instead of masking a capacity-accounting bug that // could otherwise admit more owners than the configured hard limit. @@ -275,45 +465,159 @@ func (l *rpcResultFlightLimit) snapshot() int64 { // Acquire atomically returns a completed result, joins the existing in-flight // owner, or installs the unique owner lease. Pending entries have a separate -// lifecycle from completed cache trim/TTL and consume one process-wide slot. +// lifecycle from completed cache TTL but reserve the same global/auth/session +// ownership that Put later transfers to a completed result or tombstone. func (c *rpcResultCache) Acquire(authKeyID [8]byte, sessionID, reqMsgID int64) (rpcResultAcquire, error) { + return c.acquire(authKeyID, sessionID, reqMsgID, rpcResultRequestIdentity{}) +} + +func (c *rpcResultCache) AcquireIdentified( + authKeyID [8]byte, + sessionID, reqMsgID int64, + identity tg.LayerPreparedCallIdentity, +) (rpcResultAcquire, error) { + return c.acquire(authKeyID, sessionID, reqMsgID, rpcResultRequestIdentity{exact: identity, valid: true}) +} + +// AcquireLayerIdentified is the production exact-RPC claim. In addition to the +// immutable full request identity it retains the admission profile required to +// decode a later same-msg_id naked replay under its original grammar. +func (c *rpcResultCache) AcquireLayerIdentified( + authKeyID [8]byte, + sessionID, reqMsgID int64, + profile tg.LayerProfile, + identity tg.LayerPreparedCallIdentity, +) (rpcResultAcquire, error) { + return c.acquire(authKeyID, sessionID, reqMsgID, rpcResultRequestIdentity{ + exact: identity, profile: profile, valid: true, + }) +} + +// ExactAdmissionProfile returns the immutable profile of an existing exact +// owner/result. It does not create or join a flight. Callers still perform +// AcquireLayerIdentified after decode, which atomically rejects a same-msg_id +// body change by comparing the full prepared identity. +func (c *rpcResultCache) ExactAdmissionProfile(authKeyID [8]byte, sessionID, reqMsgID int64) (tg.LayerProfile, bool) { + if c == nil || reqMsgID == 0 { + return 0, false + } + key := rpcResultCacheKey{authKeyID: authKeyID, sessionID: sessionID, reqMsgID: reqMsgID} + s := c.shard(key) + now := s.now() + s.mu.Lock() + defer s.mu.Unlock() + if elem := s.byKey[key]; elem != nil { + entry := elem.Value.(*rpcResultCacheEntry) + if entry.expiresAt.After(now) { + if entry.identity.valid && entry.identity.profile != 0 { + return entry.identity.profile, true + } + return 0, false + } + s.removeElement(elem) + } + if flight := s.pending[key]; flight != nil && flight.identity.valid && flight.identity.profile != 0 { + return flight.identity.profile, true + } + return 0, false +} + +func (c *rpcResultCache) acquire( + authKeyID [8]byte, + sessionID, reqMsgID int64, + identity rpcResultRequestIdentity, +) (rpcResultAcquire, error) { if c == nil || reqMsgID == 0 { return rpcResultAcquire{}, ErrRPCResultFlightInvalid } key := rpcResultCacheKey{authKeyID: authKeyID, sessionID: sessionID, reqMsgID: reqMsgID} s := c.shard(key) - now := s.now() + reclaimedExpired := false + for { + now := s.now() + s.mu.Lock() + s.expireLocked(now) - s.mu.Lock() - defer s.mu.Unlock() - - if elem, ok := s.byKey[key]; ok { - entry := elem.Value.(*rpcResultCacheEntry) - if entry.expiresAt.After(now) { - return rpcResultAcquire{state: rpcResultAcquireCompleted, encoded: entry.encoded}, nil + if elem, ok := s.byKey[key]; ok { + entry := elem.Value.(*rpcResultCacheEntry) + if !entry.identity.matches(identity) { + s.mu.Unlock() + return rpcResultAcquire{}, identityMismatch(entry.identity) + } + if entry.capacity || entry.encoded == nil { + s.mu.Unlock() + return rpcResultAcquire{}, ErrRPCResultFlightCapacity + } + result := rpcResultAcquire{ + state: rpcResultAcquireCompleted, admissionSeq: entry.admissionSeq, encoded: entry.encoded, + executionKnown: entry.executionKnown, executionOK: entry.executionOK, + } + s.mu.Unlock() + return result, nil } - s.removeElement(elem) - } - if flight, ok := s.pending[key]; ok { + if flight, ok := s.pending[key]; ok { + if !flight.identity.matches(identity) { + s.mu.Unlock() + return rpcResultAcquire{}, identityMismatch(flight.identity) + } + result := rpcResultAcquire{ + state: rpcResultAcquirePending, + admissionSeq: flight.admissionSeq, + waiter: &rpcResultWaiter{cache: c, key: key, flight: flight}, + } + s.mu.Unlock() + return result, nil + } + if s.maxEntries > 0 && len(s.byKey)+len(s.pending) >= s.maxEntries { + s.mu.Unlock() + return rpcResultAcquire{}, ErrRPCResultFlightCapacity + } + if !c.flightLimit.reserve() { + s.mu.Unlock() + return rpcResultAcquire{}, ErrRPCResultFlightCapacity + } + reservation := c.fairBudget.reserveOwner(key) + if reservation == nil { + c.flightLimit.release() + s.mu.Unlock() + if reclaimedExpired { + return rpcResultAcquire{}, ErrRPCResultFlightCapacity + } + // Expired rows in another full-key shard may be the only consumers at + // the global, auth or session scope. Reap once, then retry every identity + // and capacity check because another goroutine may have won this key. + c.expireCompletedResults() + reclaimedExpired = true + continue + } + var admissionSeq uint64 + if identity.valid { + var err error + admissionSeq, err = c.activeAdmissions.allocateAndRegister(&c.nextAdmissionSeq) + if err != nil { + reservation.release() + c.flightLimit.release() + s.mu.Unlock() + return rpcResultAcquire{}, err + } + } + flight := &rpcResultFlight{ + done: make(chan struct{}), identity: identity, admissionSeq: admissionSeq, + reservation: reservation, + } + if s.pending == nil { + s.pending = make(map[rpcResultCacheKey]*rpcResultFlight) + } + s.pending[key] = flight + s.mu.Unlock() return rpcResultAcquire{ - state: rpcResultAcquirePending, - waiter: &rpcResultWaiter{cache: c, key: key, flight: flight}, + state: rpcResultAcquireOwner, + admissionSeq: admissionSeq, + owner: &rpcResultOwnerLease{ + cache: c, key: key, flight: flight, delivery: newRPCResultDelivery(reqMsgID), + }, }, nil } - if !c.flightLimit.reserve() { - return rpcResultAcquire{}, ErrRPCResultFlightCapacity - } - flight := &rpcResultFlight{done: make(chan struct{})} - if s.pending == nil { - s.pending = make(map[rpcResultCacheKey]*rpcResultFlight) - } - s.pending[key] = flight - return rpcResultAcquire{ - state: rpcResultAcquireOwner, - owner: &rpcResultOwnerLease{ - cache: c, key: key, flight: flight, delivery: newRPCResultDelivery(reqMsgID), - }, - }, nil } // completeRPCResultFlightLocked publishes encoded to the current owner claim. @@ -322,20 +626,62 @@ func (c *rpcResultCache) completeRPCResultFlightLocked( s *rpcResultCacheShard, key rpcResultCacheKey, encoded *encodedOutboundMessage, -) []func(*encodedOutboundMessage, bool) { +) ( + []func(*encodedOutboundMessage, bool), + []func(bool), + bool, +) { if c == nil || s == nil || encoded == nil { - return nil + return nil, nil, false } flight, ok := s.pending[key] if !ok { - return nil + return nil, nil, false } delete(s.pending, key) + if flight.reservation != nil { + flight.reservation.releasePending() + // The completed entry now owns the same reservation. + flight.reservation = nil + } flight.encoded = encoded flight.ok = true c.flightLimit.release() + c.activeAdmissions.retire(flight.admissionSeq) subscribers := append([]func(*encodedOutboundMessage, bool){}, flight.subscribers...) flight.subscribers = nil + executionSubscribers := append([]func(bool){}, flight.executionSubscribers...) + flight.executionSubscribers = nil + executionOK := flight.executionOK + if !flight.executionDone { + // A result without an explicit handler-completion proof cannot satisfy an + // invokeAfter dependency. Production completes execution before Put; this + // branch is the conservative terminal cleanup for defensive callers. + flight.executionDone = true + flight.executionOK = false + executionOK = false + } + c.releaseFlightSubscriberSlotsLocked( + key, flight, len(subscribers)+len(executionSubscribers), + ) close(flight.done) - return subscribers + return subscribers, executionSubscribers, executionOK +} + +// releaseFlightSubscriberSlotsLocked releases callbacks detached from a flight. +// The caller holds that flight's cache shard lock, preserving the only lock +// order used by subscription: shard -> subscriber budget. +func (c *rpcResultCache) releaseFlightSubscriberSlotsLocked( + key rpcResultCacheKey, + flight *rpcResultFlight, + slots int, +) { + if slots == 0 { + return + } + if c == nil || flight == nil || slots < 0 || flight.subscriberSlots < slots { + panic("mtproto rpc result subscriber slot underflow") + } + flight.subscriberSlots -= slots + c.subscriberBudget.release(key, slots) } diff --git a/internal/mtprotoedge/rpc_flight_test.go b/internal/mtprotoedge/rpc_flight_test.go index 1aac5c0d..94264746 100644 --- a/internal/mtprotoedge/rpc_flight_test.go +++ b/internal/mtprotoedge/rpc_flight_test.go @@ -6,12 +6,471 @@ import ( "sync" "testing" "time" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/tg" ) func rpcFlightTestAuthID(seed byte) [8]byte { return [8]byte{seed, seed + 1, seed + 2, seed + 3} } +func rpcFlightExactIdentity(t *testing.T, profile tg.LayerProfile, request bin.Encoder) tg.LayerPreparedCallIdentity { + t.Helper() + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatalf("encode exact request: %v", err) + } + admitted, err := tg.NewServerDispatcher(nil).AdmitLayer(profile, &body) + if err != nil { + t.Fatalf("admit exact request: %v", err) + } + if body.Len() != 0 { + t.Fatalf("exact admission left %d bytes", body.Len()) + } + return admitted.Prepared().Identity() +} + +func newRPCResultSubscriberTestCache(global, auth, session, perFlight int) *rpcResultCache { + return newRPCResultCacheWithFairCapacity(time.Now, rpcResultCacheCapacity{ + maxPending: 64, + maxPendingPerAuth: 64, + globalMaxBytes: rpcResultCacheMaxBytes, + globalMaxEntries: rpcResultCacheMaxEntries, + authMaxBytes: rpcResultCacheAuthMaxBytes, + authMaxEntries: rpcResultCacheAuthMaxEntries, + sessionMaxBytes: rpcResultCacheSessionMaxBytes, + sessionMaxEntries: rpcResultCacheSessionMaxEntries, + subscriberMaxGlobal: global, + subscriberMaxAuth: auth, + subscriberMaxSession: session, + subscriberMaxPerFlight: perFlight, + }) +} + +func TestRPCResultFlightSubscriberPairCapacityFailureIsAtomic(t *testing.T) { + cache := newRPCResultSubscriberTestCache(8, 8, 8, 1) + authKeyID := rpcFlightTestAuthID(70) + claim, err := cache.Acquire(authKeyID, 70, 700) + if err != nil || claim.owner == nil { + t.Fatalf("Acquire owner: claim=%#v err=%v", claim, err) + } + var resultCalls, executionCalls int + err = claim.owner.Waiter().SubscribeResultAndExecution( + func(*encodedOutboundMessage, bool) { resultCalls++ }, + func(bool) { executionCalls++ }, + ) + if !errors.Is(err, ErrRPCResultSubscriberCapacity) { + t.Fatalf("pair subscription err=%v, want %v", err, ErrRPCResultSubscriberCapacity) + } + s := cache.shard(rpcResultCacheKey{authKeyID: authKeyID, sessionID: 70, reqMsgID: 700}) + s.mu.Lock() + if got := claim.owner.flight.subscriberSlots; got != 0 { + t.Fatalf("failed pair retained %d subscriber slots", got) + } + if got := len(claim.owner.flight.subscribers) + len(claim.owner.flight.executionSubscribers); got != 0 { + t.Fatalf("failed pair retained %d callbacks", got) + } + s.mu.Unlock() + claim.owner.CompleteExecution(true) + cache.Put(authKeyID, 70, 700, &encodedOutboundMessage{body: []byte{1}, reqMsgID: 700}) + if resultCalls != 0 || executionCalls != 0 { + t.Fatalf("failed pair callbacks ran: result=%d execution=%d", resultCalls, executionCalls) + } + if got := cache.subscriberBudget.global.snapshot(); got != 0 { + t.Fatalf("subscriber global usage=%d after failed pair", got) + } +} + +func TestRPCResultFlightSubscriberBudgetsIsolateSessionAndAuth(t *testing.T) { + cache := newRPCResultSubscriberTestCache(3, 2, 1, 4) + authA := rpcFlightTestAuthID(71) + authB := rpcFlightTestAuthID(72) + type ownerKey struct { + auth [8]byte + session int64 + msgID int64 + owner *rpcResultOwnerLease + } + acquire := func(auth [8]byte, session, msgID int64) ownerKey { + t.Helper() + claim, err := cache.Acquire(auth, session, msgID) + if err != nil || claim.owner == nil { + t.Fatalf("Acquire(%d,%d): claim=%#v err=%v", session, msgID, claim, err) + } + return ownerKey{auth: auth, session: session, msgID: msgID, owner: claim.owner} + } + subscribe := func(owner ownerKey) error { + return owner.owner.Waiter().Subscribe(func(*encodedOutboundMessage, bool) {}) + } + + a1 := acquire(authA, 1, 101) + a2 := acquire(authA, 2, 102) + a3 := acquire(authA, 3, 103) + b1 := acquire(authB, 4, 104) + b2 := acquire(authB, 5, 105) + if err := subscribe(a1); err != nil { + t.Fatalf("first session subscriber: %v", err) + } + if err := subscribe(a1); !errors.Is(err, ErrRPCResultSubscriberCapacity) { + t.Fatalf("same session overflow err=%v", err) + } + if err := subscribe(a2); err != nil { + t.Fatalf("second session subscriber: %v", err) + } + if err := subscribe(a3); !errors.Is(err, ErrRPCResultSubscriberCapacity) { + t.Fatalf("same auth overflow err=%v", err) + } + if err := subscribe(b1); err != nil { + t.Fatalf("other auth subscriber: %v", err) + } + if err := subscribe(b2); !errors.Is(err, ErrRPCResultSubscriberCapacity) { + t.Fatalf("global overflow err=%v", err) + } + if got := cache.subscriberBudget.authSnapshot(authA); got != 2 { + t.Fatalf("auth A usage=%d, want 2", got) + } + if got := cache.subscriberBudget.authSnapshot(authB); got != 1 { + t.Fatalf("auth B usage=%d, want 1", got) + } + if got := cache.subscriberBudget.global.snapshot(); got != 3 { + t.Fatalf("global usage=%d, want 3", got) + } + for _, owner := range []ownerKey{a1, a2, a3, b1, b2} { + owner.owner.Abort() + } + if got := cache.subscriberBudget.global.snapshot(); got != 0 { + t.Fatalf("global usage=%d after aborts", got) + } + if got := cache.subscriberBudget.authSnapshot(authA); got != 0 { + t.Fatalf("auth A usage=%d after aborts", got) + } +} + +func TestRPCResultFlightSubscriberSlotsReleasePerTerminalHalf(t *testing.T) { + cache := newRPCResultSubscriberTestCache(4, 4, 4, 4) + authKeyID := rpcFlightTestAuthID(73) + claim, err := cache.Acquire(authKeyID, 73, 730) + if err != nil || claim.owner == nil { + t.Fatalf("Acquire owner: claim=%#v err=%v", claim, err) + } + result := make(chan bool, 1) + execution := make(chan bool, 1) + if err := claim.owner.Waiter().SubscribeResultAndExecution( + func(_ *encodedOutboundMessage, ok bool) { result <- ok }, + func(ok bool) { execution <- ok }, + ); err != nil { + t.Fatalf("pair subscription: %v", err) + } + if got := cache.subscriberBudget.sessionSnapshot(authKeyID, 73); got != 2 { + t.Fatalf("initial subscriber usage=%d, want 2", got) + } + if !claim.owner.CompleteExecution(true) { + t.Fatal("CompleteExecution lost") + } + if ok := <-execution; !ok { + t.Fatal("execution callback reported failure") + } + if got := cache.subscriberBudget.sessionSnapshot(authKeyID, 73); got != 1 { + t.Fatalf("post-execution subscriber usage=%d, want 1", got) + } + cache.Put(authKeyID, 73, 730, &encodedOutboundMessage{body: []byte{1}, reqMsgID: 730}) + if ok := <-result; !ok { + t.Fatal("result callback reported failure") + } + if got := cache.subscriberBudget.sessionSnapshot(authKeyID, 73); got != 0 { + t.Fatalf("post-result subscriber usage=%d, want 0", got) + } +} + +func TestRPCResultFlightRepeatedReplayJoinsStayBoundedAndPutCleansExecution(t *testing.T) { + cache := newRPCResultSubscriberTestCache(2, 2, 2, 2) + authKeyID := rpcFlightTestAuthID(74) + claim, err := cache.Acquire(authKeyID, 74, 740) + if err != nil || claim.owner == nil { + t.Fatalf("Acquire owner: claim=%#v err=%v", claim, err) + } + var resultCalls, executionCalls int + if err := claim.owner.Waiter().SubscribeResultAndExecution( + func(*encodedOutboundMessage, bool) { resultCalls++ }, + func(success bool) { + if success { + t.Error("Put without execution proof reported dependency success") + } + executionCalls++ + }, + ); err != nil { + t.Fatalf("first pair: %v", err) + } + for i := 0; i < 100; i++ { + err := claim.owner.Waiter().SubscribeResultAndExecution( + func(*encodedOutboundMessage, bool) { resultCalls++ }, + func(bool) { executionCalls++ }, + ) + if !errors.Is(err, ErrRPCResultSubscriberCapacity) { + t.Fatalf("join %d err=%v, want capacity", i, err) + } + } + cache.Put(authKeyID, 74, 740, &encodedOutboundMessage{body: []byte{1}, reqMsgID: 740}) + if resultCalls != 1 || executionCalls != 1 { + t.Fatalf("terminal callback counts result=%d execution=%d", resultCalls, executionCalls) + } + if got := cache.subscriberBudget.global.snapshot(); got != 0 { + t.Fatalf("global usage=%d after Put", got) + } +} + +func TestRPCResultFlightExactIdentityGuardsPendingAndCompletedReuse(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 2) + authKeyID := rpcFlightTestAuthID(90) + firstIdentity := rpcFlightExactIdentity(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + otherIdentity := rpcFlightExactIdentity(t, tg.LayerProfile225, &tg.HelpGetNearestDCRequest{}) + + owner, err := cache.AcquireIdentified(authKeyID, 90, 900, firstIdentity) + if err != nil || owner.state != rpcResultAcquireOwner || owner.owner == nil { + t.Fatalf("exact owner Acquire = state:%d err:%v", owner.state, err) + } + if _, err := cache.AcquireIdentified(authKeyID, 90, 900, otherIdentity); !errors.Is(err, ErrRPCResultIdentityMismatch) { + t.Fatalf("pending mismatched Acquire err = %v, want %v", err, ErrRPCResultIdentityMismatch) + } + same, err := cache.AcquireIdentified(authKeyID, 90, 900, firstIdentity) + if err != nil || same.state != rpcResultAcquirePending || same.waiter == nil { + t.Fatalf("pending matched Acquire = state:%d err:%v", same.state, err) + } + + want := &encodedOutboundMessage{body: []byte{1, 2, 3, 4}, reqMsgID: 900} + cache.Put(authKeyID, 90, 900, want) + if _, err := cache.AcquireIdentified(authKeyID, 90, 900, otherIdentity); !errors.Is(err, ErrRPCResultIdentityMismatch) { + t.Fatalf("completed mismatched Acquire err = %v, want %v", err, ErrRPCResultIdentityMismatch) + } + completed, err := cache.AcquireIdentified(authKeyID, 90, 900, firstIdentity) + if err != nil || completed.state != rpcResultAcquireCompleted || completed.encoded != want { + t.Fatalf("completed matched Acquire = state:%d encoded:%p err:%v", completed.state, completed.encoded, err) + } + if encoded, ok, waitErr := same.waiter.Wait(context.Background()); waitErr != nil || !ok || encoded != want { + t.Fatalf("matched waiter = encoded:%p ok:%v err:%v", encoded, ok, waitErr) + } +} + +func TestRPCResultFlightAdmissionSequenceAllocatedOnceAndReplayed(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 4) + authKeyID := rpcFlightTestAuthID(89) + identity := rpcFlightExactIdentity(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + owner, err := cache.AcquireLayerIdentified(authKeyID, 89, 890, tg.LayerProfile225, identity) + if err != nil || owner.state != rpcResultAcquireOwner || owner.owner == nil || owner.admissionSeq == 0 { + t.Fatalf("owner = state:%d seq:%d err:%v", owner.state, owner.admissionSeq, err) + } + pending, err := cache.AcquireLayerIdentified(authKeyID, 89, 890, tg.LayerProfile225, identity) + if err != nil || pending.state != rpcResultAcquirePending || pending.admissionSeq != owner.admissionSeq { + t.Fatalf("pending = state:%d seq:%d err:%v, want seq:%d", pending.state, pending.admissionSeq, err, owner.admissionSeq) + } + owner.owner.CompleteExecution(true) + encoded := &encodedOutboundMessage{body: []byte{1}, reqMsgID: 890} + cache.Put(authKeyID, 89, 890, encoded) + completed, err := cache.AcquireLayerIdentified(authKeyID, 89, 890, tg.LayerProfile225, identity) + if err != nil || completed.state != rpcResultAcquireCompleted || completed.admissionSeq != owner.admissionSeq { + t.Fatalf("completed = state:%d seq:%d err:%v, want seq:%d", completed.state, completed.admissionSeq, err, owner.admissionSeq) + } + second, err := cache.AcquireLayerIdentified(authKeyID, 89, 894, tg.LayerProfile225, identity) + if err != nil || second.admissionSeq <= owner.admissionSeq { + t.Fatalf("second owner seq=%d err=%v, want > %d", second.admissionSeq, err, owner.admissionSeq) + } + second.owner.Abort() + legacy, err := cache.Acquire(authKeyID, 89, 898) + if err != nil || legacy.admissionSeq != 0 { + t.Fatalf("legacy admission seq=%d err=%v, want 0", legacy.admissionSeq, err) + } + legacy.owner.Abort() +} + +func TestRPCAdmissionSafeFloorTracksOwnersUntilPutOrAbort(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 4) + authKeyID := rpcFlightTestAuthID(86) + identity := rpcFlightExactIdentity(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + first, err := cache.AcquireLayerIdentified(authKeyID, 86, 860, tg.LayerProfile225, identity) + if err != nil || first.owner == nil { + t.Fatalf("first owner err=%v", err) + } + second, err := cache.AcquireLayerIdentified(authKeyID, 86, 864, tg.LayerProfile225, identity) + if err != nil || second.owner == nil { + t.Fatalf("second owner err=%v", err) + } + if floor := cache.stableAdmissionSafeFloor(); floor != first.admissionSeq { + t.Fatalf("two-owner safe floor=%d, want %d", floor, first.admissionSeq) + } + if !first.owner.Abort() { + t.Fatal("first owner abort failed") + } + if floor := cache.stableAdmissionSafeFloor(); floor != second.admissionSeq { + t.Fatalf("post-abort safe floor=%d, want %d", floor, second.admissionSeq) + } + second.owner.CompleteExecution(true) + cache.Put(authKeyID, 86, 864, &encodedOutboundMessage{body: []byte{1}, reqMsgID: 864}) + if floor := cache.stableAdmissionSafeFloor(); floor != second.admissionSeq+1 { + t.Fatalf("terminal safe floor=%d, want %d", floor, second.admissionSeq+1) + } +} + +func TestRPCAdmissionSequenceExhaustionCannotWrap(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 2) + cache.nextAdmissionSeq.Store(^uint64(0) - 1) + authKeyID := rpcFlightTestAuthID(85) + identity := rpcFlightExactIdentity(t, tg.LayerProfile225, &tg.HelpGetConfigRequest{}) + last, err := cache.AcquireLayerIdentified(authKeyID, 85, 850, tg.LayerProfile225, identity) + if err != nil || last.admissionSeq != ^uint64(0) || last.owner == nil { + t.Fatalf("last sequence=%d owner:%v err=%v", last.admissionSeq, last.owner != nil, err) + } + if _, err := cache.AcquireLayerIdentified(authKeyID, 85, 854, tg.LayerProfile225, identity); !errors.Is(err, ErrRPCAdmissionSeqExhausted) { + t.Fatalf("post-max allocation err=%v, want %v", err, ErrRPCAdmissionSeqExhausted) + } + if got := cache.nextAdmissionSeq.Load(); got != ^uint64(0) { + t.Fatalf("exhausted sequence wrapped to %d", got) + } + last.owner.Abort() +} + +func TestRPCIdentityMismatchCarriesWinnerProfileAcrossAbort(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 2) + authKeyID := rpcFlightTestAuthID(88) + request := &tg.MessagesGetHistoryRequest{Peer: &tg.InputPeerSelf{}, Limit: 1} + winnerIdentity := rpcFlightExactIdentity(t, tg.LayerProfile225, request) + loserIdentity := rpcFlightExactIdentity(t, tg.LayerProfile227, request) + winner, err := cache.AcquireLayerIdentified(authKeyID, 88, 880, tg.LayerProfile225, winnerIdentity) + if err != nil || winner.owner == nil { + t.Fatalf("winner owner err=%v", err) + } + _, err = cache.AcquireLayerIdentified(authKeyID, 88, 880, tg.LayerProfile227, loserIdentity) + var mismatch *rpcResultIdentityMismatchError + if !errors.As(err, &mismatch) || !mismatch.hasProfile || mismatch.profile != tg.LayerProfile225 { + t.Fatalf("mismatch = %#v err=%v", mismatch, err) + } + if !winner.owner.Abort() { + t.Fatal("winner abort failed") + } + replacement, err := cache.AcquireLayerIdentified(authKeyID, 88, 880, mismatch.profile, winnerIdentity) + if err != nil || replacement.state != rpcResultAcquireOwner || replacement.owner == nil { + t.Fatalf("replacement under retained winner profile = state:%d err:%v", replacement.state, err) + } + replacement.owner.Abort() +} + +func TestRPCAdmissionProfileHintSurvivesCompletedEvictionWindow(t *testing.T) { + now := time.Unix(1_900_000_000, 0) + cache := newRPCResultCacheWithFlightLimit(func() time.Time { return now }, 2) + authKeyID := rpcFlightTestAuthID(87) + identity := rpcFlightExactIdentity(t, tg.LayerProfile225, &tg.MessagesGetHistoryRequest{ + Peer: &tg.InputPeerSelf{}, Limit: 1, + }) + claim, err := cache.AcquireLayerIdentified(authKeyID, 87, 870, tg.LayerProfile225, identity) + if err != nil || claim.owner == nil { + t.Fatalf("owner err=%v", err) + } + claim.owner.CompleteExecution(true) + cache.Put(authKeyID, 87, 870, &encodedOutboundMessage{body: []byte{1}, reqMsgID: 870}) + profile, ok := cache.ExactAdmissionProfile(authKeyID, 87, 870) + if !ok || profile != tg.LayerProfile225 { + t.Fatalf("profile hint = (%d,%v)", profile, ok) + } + // Admission already copied the hint into its local decoder cursor. Expiry + // between that probe and the atomic claim must not make it fall back to the + // connection's newer default; it simply becomes a fresh owner under 225. + now = now.Add(rpcResultCacheTTL + time.Second) + replacement, err := cache.AcquireLayerIdentified(authKeyID, 87, 870, profile, identity) + if err != nil || replacement.state != rpcResultAcquireOwner || replacement.owner == nil { + t.Fatalf("post-eviction owner = state:%d err:%v", replacement.state, err) + } + replacement.owner.Abort() +} + +func TestRPCInvariantIdentityDoesNotExposeCanonicalProfileHint(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 2) + authKeyID := rpcFlightTestAuthID(84) + identity := rpcFlightExactIdentity(t, tg.LayerProfile227, &tg.AuthBindTempAuthKeyRequest{ + PermAuthKeyID: 1, Nonce: 2, ExpiresAt: 3, EncryptedMessage: []byte("bind"), + }) + claim, err := cache.AcquireLayerIdentified(authKeyID, 84, 840, 0, identity) + if err != nil || claim.owner == nil { + t.Fatalf("invariant owner err=%v", err) + } + if profile, ok := cache.ExactAdmissionProfile(authKeyID, 84, 840); ok || profile != 0 { + t.Fatalf("pending invariant profile hint=(%d,%v), want absent", profile, ok) + } + claim.owner.CompleteExecution(true) + cache.Put(authKeyID, 84, 840, &encodedOutboundMessage{body: []byte{1}, reqMsgID: 840}) + if profile, ok := cache.ExactAdmissionProfile(authKeyID, 84, 840); ok || profile != 0 { + t.Fatalf("completed invariant profile hint=(%d,%v), want absent", profile, ok) + } +} + +func TestRPCResultExecutionCompletionIsExactlyOnceAndDurable(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 2) + authKeyID := rpcFlightTestAuthID(91) + claim, err := cache.Acquire(authKeyID, 91, 910) + if err != nil || claim.state != rpcResultAcquireOwner || claim.owner == nil { + t.Fatalf("owner Acquire = state:%d err:%v", claim.state, err) + } + waiter := claim.owner.Waiter() + results := make(chan bool, 2) + if err := waiter.SubscribeExecution(func(success bool) { results <- success }); err != nil { + t.Fatal(err) + } + if !claim.owner.CompleteExecution(true) { + t.Fatal("first execution completion lost") + } + if claim.owner.CompleteExecution(false) { + t.Fatal("contradictory second execution completion won") + } + select { + case success := <-results: + if !success { + t.Fatal("execution callback reported failure") + } + case <-time.After(time.Second): + t.Fatal("execution callback did not run") + } + select { + case success := <-results: + t.Fatalf("execution callback ran twice: %v", success) + default: + } + + want := &encodedOutboundMessage{body: []byte{9, 1, 0, 0}, reqMsgID: 910} + cache.Put(authKeyID, 91, 910, want) + dependency, ok := cache.ObserveDependency(authKeyID, 91, 910) + if !ok || !dependency.completed || !dependency.success || dependency.waiter != nil { + t.Fatalf("completed dependency = %#v ok:%v", dependency, ok) + } + late := make(chan bool, 1) + if err := waiter.SubscribeExecution(func(success bool) { late <- success }); err != nil { + t.Fatal(err) + } + if success := <-late; !success { + t.Fatal("late execution subscriber lost durable success") + } +} + +func TestRPCResultExecutionAbortPublishesFailure(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 1) + authKeyID := rpcFlightTestAuthID(92) + claim, err := cache.Acquire(authKeyID, 92, 920) + if err != nil || claim.owner == nil { + t.Fatalf("owner Acquire err = %v", err) + } + result := make(chan bool, 1) + if err := claim.owner.Waiter().SubscribeExecution(func(success bool) { result <- success }); err != nil { + t.Fatal(err) + } + if !claim.owner.Abort() { + t.Fatal("Abort lost") + } + if success := <-result; success { + t.Fatal("aborted execution reported success") + } + if _, ok := cache.ObserveDependency(authKeyID, 92, 920); ok { + t.Fatal("aborted flight remained observable as a completed dependency") + } +} + func TestRPCResultFlightConcurrentAcquireHasUniqueOwner(t *testing.T) { const callers = 64 cache := newRPCResultCacheWithFlightLimit(time.Now, callers) @@ -180,7 +639,6 @@ func TestRPCResultFlightCompletedCachePressureDoesNotEvictPending(t *testing.T) shard := cache.shard(key) shard.mu.Lock() shard.maxEntries = 2 - shard.maxBytes = 2 shard.mu.Unlock() for i := int64(0); i < 16; i++ { cache.Put(authKeyID, 40, 500+i, &encodedOutboundMessage{body: []byte{byte(i)}}) @@ -251,7 +709,7 @@ func TestRPCResultFlightCapacityAndCountReturn(t *testing.T) { } } -func TestRPCResultFlightOversizedPutStillResolvesWaiters(t *testing.T) { +func TestRPCResultFlightLargePutPublishesCompletedBeforeResolvingWaiters(t *testing.T) { cache := newRPCResultCacheWithFlightLimit(time.Now, 1) authKeyID := rpcFlightTestAuthID(50) owner, err := cache.Acquire(authKeyID, 60, 600) @@ -263,31 +721,32 @@ func TestRPCResultFlightOversizedPutStillResolvesWaiters(t *testing.T) { t.Fatalf("joined Acquire = state:%d err:%v", joined.state, err) } - key := rpcResultCacheKey{authKeyID: authKeyID, sessionID: 60, reqMsgID: 600} - shard := cache.shard(key) - shard.mu.Lock() - shard.maxBytes = 1 - shard.mu.Unlock() - want := &encodedOutboundMessage{body: []byte{1, 2}, reqMsgID: 600} + // This is larger than the removed 4 MiB per-shard partition but remains a + // legal outbound result and fits the global/auth/session fair byte budgets. + largeSize := rpcResultCacheMaxBytes/rpcResultCacheShards + 1 + want := &encodedOutboundMessage{body: make([]byte, largeSize), reqMsgID: 600} cache.Put(authKeyID, 60, 600, want) if encoded, ok, waitErr := joined.waiter.Wait(context.Background()); waitErr != nil || !ok || encoded != want { - t.Fatalf("oversized Wait = encoded:%p ok:%v err:%v", encoded, ok, waitErr) + t.Fatalf("large Wait = encoded:%p ok:%v err:%v", encoded, ok, waitErr) } - if _, ok := cache.Get(authKeyID, 60, 600); ok { - t.Fatal("oversized result changed completed-cache compatibility") + if got, ok := cache.Get(authKeyID, 60, 600); !ok || got != want { + t.Fatalf("large completed Get = encoded:%p ok:%v", got, ok) } if got := cache.flightLimit.snapshot(); got != 0 { - t.Fatalf("oversized Put leaked pending count %d", got) + t.Fatalf("large Put leaked pending count %d", got) } if owner.owner.Abort() { - t.Fatal("oversized Put left its old owner abortable") + t.Fatal("large Put left its old owner abortable") } - retry, err := cache.Acquire(authKeyID, 60, 600) - if err != nil || retry.state != rpcResultAcquireOwner { - t.Fatalf("retry after uncacheable completion = state:%d err:%v", retry.state, err) + completed, err := cache.Acquire(authKeyID, 60, 600) + if err != nil || completed.state != rpcResultAcquireCompleted || completed.encoded != want { + t.Fatalf("Acquire after large completion = state:%d encoded:%p err:%v", completed.state, completed.encoded, err) } - if !retry.owner.Abort() { - t.Fatal("retry owner failed to abort") + if completed.owner != nil { + t.Fatal("large completed result incorrectly returned a new owner") + } + if got := cache.completedBytes.snapshot(); got != int64(largeSize) { + t.Fatalf("completed byte budget = %d, want %d", got, largeSize) } } @@ -370,11 +829,11 @@ func TestQueuedRPCConnectionCloseAbortsOwnerClaim(t *testing.T) { } reservation, err := c.reserveInboundRPC(context.Background(), "test.queuedFlight", 4) if err != nil { - t.Fatalf("reserve queued RPC: %v", err) + t.Fatalf("reserve queued legacyRPC: %v", err) } task := s.newInboundRPCTask(c, 900, "test.queuedFlight", []byte{1, 2, 3, 4}, claim.owner) if err := reservation.commit(task); err != nil { - t.Fatalf("commit queued RPC: %v", err) + t.Fatalf("commit queued legacyRPC: %v", err) } // The scheduler is intentionally not started, so close must drain the queued diff --git a/internal/mtprotoedge/rpc_replay_restore.go b/internal/mtprotoedge/rpc_replay_restore.go new file mode 100644 index 00000000..e9008c93 --- /dev/null +++ b/internal/mtprotoedge/rpc_replay_restore.go @@ -0,0 +1,87 @@ +package mtprotoedge + +import ( + "context" + "fmt" + "time" +) + +const ( + rpcReplayRestoreTimeout = 5 * time.Second + rpcReplayRestoreMaxActive = 8 +) + +// rpcReplayRestoreSlots bounds callbacks that ignore their own store/context +// deadline. The caller waits only until ctx (and at most +// rpcReplayRestoreTimeout); a stuck callback can retain one of these fixed +// slots, but it cannot retain a rewrap worker, a live Conn scheduler barrier, +// or create an unbounded goroutine population. +var rpcReplayRestoreSlots = make(chan struct{}, rpcReplayRestoreMaxActive) + +func boundedRPCReplayRestoreContext(parent context.Context) (context.Context, context.CancelFunc) { + if parent == nil { + parent = context.Background() + } + return context.WithTimeout(parent, rpcReplayRestoreTimeout) +} + +// runBoundedRPCReplayRestore runs replacement metadata first and the shared +// logical delivery hook second. On timeout it fences the physical generation +// before returning, so releasing that Conn's scheduler barrier cannot expose a +// following RPC to partially restored state. A claim that has not entered the +// hook is abandoned and may be acquired by a later replacement replay; an +// in-progress hook remains at-most-once and every later replay waits for Done. +func (s *Server) runBoundedRPCReplayRestore( + ctx context.Context, + c *Conn, + source string, + claim *rpcResultDeliveryHookClaim, + replacement func() error, +) error { + if claim == nil && replacement == nil { + return nil + } + boundedCtx, cancel := boundedRPCReplayRestoreContext(ctx) + defer cancel() + + select { + case rpcReplayRestoreSlots <- struct{}{}: + case <-boundedCtx.Done(): + claim.abandon() + if c != nil { + c.fenceUndeliveredRPCResult() + } + return fmt.Errorf("restore replay state after %s: %w", source, boundedCtx.Err()) + } + + result := make(chan error, 1) + var logical func() + if claim != nil { + logical = claim.run + } + go func() { + defer func() { <-rpcReplayRestoreSlots }() + result <- s.runRPCReplayRestore(c, source, composeRPCReplayRestore(logical, replacement)) + }() + + select { + case err := <-result: + return err + case <-boundedCtx.Done(): + // Prefer a restore that reached its terminal state concurrently with the + // deadline; its result channel publishes coordinator Done before send. + select { + case err := <-result: + return err + default: + } + // If replacement metadata is still blocked, the hook is only Claimed and + // can be safely re-acquired. Once hook execution is InProgress, abandon + // deliberately fails: retrying an unknown partial side effect is forbidden. + claim.abandon() + if c != nil { + c.fenceUndeliveredRPCResult() + } + return fmt.Errorf("restore replay state after %s: %w", source, boundedCtx.Err()) + } +} diff --git a/internal/mtprotoedge/rpc_result_budget.go b/internal/mtprotoedge/rpc_result_budget.go new file mode 100644 index 00000000..68e62312 --- /dev/null +++ b/internal/mtprotoedge/rpc_result_budget.go @@ -0,0 +1,292 @@ +package mtprotoedge + +import ( + "encoding/binary" + "hash/maphash" + "sync" +) + +const rpcResultBudgetShards = 64 + +type rpcResultBudgetLimit struct { + entries int64 + bytes int64 +} + +type rpcResultBudgetUsage struct { + entries int64 + bytes int64 + pending int64 +} + +type rpcResultSessionBudgetKey struct { + authKeyID [8]byte + sessionID int64 +} + +type rpcResultAuthBudgetShard struct { + mu sync.Mutex + usage map[[8]byte]rpcResultBudgetUsage +} + +type rpcResultSessionBudgetShard struct { + mu sync.Mutex + usage map[rpcResultSessionBudgetKey]rpcResultBudgetUsage +} + +// rpcResultFairBudget accounts one ownership reservation at all three scopes. +// A pending owner and its completed result are the same ownership: admission +// reserves one entry plus one byte, Put resizes that byte reservation and moves +// it to the completed row, while Abort/TTL return the whole reservation. +// +// Auth and session maps are striped independently. Every operation takes the +// auth stripe before the session stripe; global counters remain atomic. This +// keeps unrelated auth keys off one process-wide mutex while preserving hard +// limits at every hierarchy level. +type rpcResultFairBudget struct { + seed maphash.Seed + globalEntries *rpcResultFlightLimit + globalBytes *rpcResultCacheByteBudget + authLimit rpcResultBudgetLimit + sessionLimit rpcResultBudgetLimit + pendingPerAuth int64 + authShards [rpcResultBudgetShards]rpcResultAuthBudgetShard + sessionShards [rpcResultBudgetShards]rpcResultSessionBudgetShard +} + +type rpcResultBudgetReservation struct { + budget *rpcResultFairBudget + key rpcResultCacheKey + bytes int + pending bool + released bool +} + +func newRPCResultFairBudget( + seed maphash.Seed, + globalEntries *rpcResultFlightLimit, + globalBytes *rpcResultCacheByteBudget, + authLimit rpcResultBudgetLimit, + sessionLimit rpcResultBudgetLimit, + pendingPerAuth int, +) *rpcResultFairBudget { + b := &rpcResultFairBudget{ + seed: seed, + globalEntries: globalEntries, + globalBytes: globalBytes, + authLimit: authLimit, + sessionLimit: sessionLimit, + pendingPerAuth: int64(pendingPerAuth), + } + for i := range b.authShards { + b.authShards[i].usage = make(map[[8]byte]rpcResultBudgetUsage) + b.sessionShards[i].usage = make(map[rpcResultSessionBudgetKey]rpcResultBudgetUsage) + } + return b +} + +func (b *rpcResultFairBudget) reserveOwner(key rpcResultCacheKey) *rpcResultBudgetReservation { + return b.reserve(key, 1, true) +} + +func (b *rpcResultFairBudget) reserveCompleted(key rpcResultCacheKey, bytes int) *rpcResultBudgetReservation { + return b.reserve(key, bytes, false) +} + +func (b *rpcResultFairBudget) reserve(key rpcResultCacheKey, bytes int, pending bool) *rpcResultBudgetReservation { + if b == nil || b.globalEntries == nil || b.globalBytes == nil || bytes < 1 { + return nil + } + authShard := b.authShard(key.authKeyID) + sessionKey := rpcResultSessionBudgetKey{authKeyID: key.authKeyID, sessionID: key.sessionID} + sessionShard := b.sessionShard(sessionKey) + authShard.mu.Lock() + sessionShard.mu.Lock() + + authUsage := authShard.usage[key.authKeyID] + sessionUsage := sessionShard.usage[sessionKey] + bytes64 := int64(bytes) + canReserve := withinRPCResultBudget(authUsage.entries, 1, b.authLimit.entries) && + withinRPCResultBudget(authUsage.bytes, bytes64, b.authLimit.bytes) && + withinRPCResultBudget(sessionUsage.entries, 1, b.sessionLimit.entries) && + withinRPCResultBudget(sessionUsage.bytes, bytes64, b.sessionLimit.bytes) + if pending { + canReserve = canReserve && withinRPCResultBudget(authUsage.pending, 1, b.pendingPerAuth) + } + if !canReserve || !b.globalEntries.reserve() { + sessionShard.mu.Unlock() + authShard.mu.Unlock() + return nil + } + if !b.globalBytes.reserve(bytes) { + b.globalEntries.release() + sessionShard.mu.Unlock() + authShard.mu.Unlock() + return nil + } + authUsage.entries++ + authUsage.bytes += bytes64 + sessionUsage.entries++ + sessionUsage.bytes += bytes64 + if pending { + authUsage.pending++ + } + authShard.usage[key.authKeyID] = authUsage + sessionShard.usage[sessionKey] = sessionUsage + sessionShard.mu.Unlock() + authShard.mu.Unlock() + return &rpcResultBudgetReservation{budget: b, key: key, bytes: bytes, pending: pending} +} + +func withinRPCResultBudget(used, delta, limit int64) bool { + return delta >= 0 && limit > 0 && used >= 0 && used <= limit-delta +} + +func (r *rpcResultBudgetReservation) resizeBytes(bytes int) bool { + if r == nil || r.budget == nil || r.released || bytes < 1 { + return false + } + if bytes == r.bytes { + return true + } + b := r.budget + authShard := b.authShard(r.key.authKeyID) + sessionKey := rpcResultSessionBudgetKey{authKeyID: r.key.authKeyID, sessionID: r.key.sessionID} + sessionShard := b.sessionShard(sessionKey) + authShard.mu.Lock() + sessionShard.mu.Lock() + authUsage, authOK := authShard.usage[r.key.authKeyID] + sessionUsage, sessionOK := sessionShard.usage[sessionKey] + if !authOK || !sessionOK || authUsage.entries < 1 || sessionUsage.entries < 1 { + sessionShard.mu.Unlock() + authShard.mu.Unlock() + panic("mtprotoedge: rpc result budget reservation disappeared during resize") + } + delta := int64(bytes) - int64(r.bytes) + if delta > 0 { + if !withinRPCResultBudget(authUsage.bytes, delta, b.authLimit.bytes) || + !withinRPCResultBudget(sessionUsage.bytes, delta, b.sessionLimit.bytes) || + !b.globalBytes.reserve(int(delta)) { + sessionShard.mu.Unlock() + authShard.mu.Unlock() + return false + } + } else { + if authUsage.bytes < -delta || sessionUsage.bytes < -delta { + sessionShard.mu.Unlock() + authShard.mu.Unlock() + panic("mtprotoedge: rpc result byte reservation underflow during resize") + } + } + authUsage.bytes += delta + sessionUsage.bytes += delta + authShard.usage[r.key.authKeyID] = authUsage + sessionShard.usage[sessionKey] = sessionUsage + r.bytes = bytes + if delta < 0 { + b.globalBytes.release(int(-delta)) + } + sessionShard.mu.Unlock() + authShard.mu.Unlock() + return true +} + +func (r *rpcResultBudgetReservation) releasePending() { + if r == nil || r.budget == nil || r.released || !r.pending { + return + } + b := r.budget + authShard := b.authShard(r.key.authKeyID) + authShard.mu.Lock() + authUsage, ok := authShard.usage[r.key.authKeyID] + if !ok || authUsage.pending < 1 { + authShard.mu.Unlock() + panic("mtprotoedge: rpc result per-auth pending budget underflow") + } + authUsage.pending-- + authShard.usage[r.key.authKeyID] = authUsage + r.pending = false + authShard.mu.Unlock() +} + +func (r *rpcResultBudgetReservation) release() { + if r == nil || r.budget == nil || r.released { + return + } + b := r.budget + authShard := b.authShard(r.key.authKeyID) + sessionKey := rpcResultSessionBudgetKey{authKeyID: r.key.authKeyID, sessionID: r.key.sessionID} + sessionShard := b.sessionShard(sessionKey) + authShard.mu.Lock() + sessionShard.mu.Lock() + authUsage, authOK := authShard.usage[r.key.authKeyID] + sessionUsage, sessionOK := sessionShard.usage[sessionKey] + bytes64 := int64(r.bytes) + if !authOK || !sessionOK || authUsage.entries < 1 || sessionUsage.entries < 1 || + authUsage.bytes < bytes64 || sessionUsage.bytes < bytes64 || + (r.pending && authUsage.pending < 1) { + sessionShard.mu.Unlock() + authShard.mu.Unlock() + panic("mtprotoedge: rpc result fair budget underflow") + } + authUsage.entries-- + authUsage.bytes -= bytes64 + sessionUsage.entries-- + sessionUsage.bytes -= bytes64 + if r.pending { + authUsage.pending-- + } + if authUsage == (rpcResultBudgetUsage{}) { + delete(authShard.usage, r.key.authKeyID) + } else { + authShard.usage[r.key.authKeyID] = authUsage + } + if sessionUsage == (rpcResultBudgetUsage{}) { + delete(sessionShard.usage, sessionKey) + } else { + sessionShard.usage[sessionKey] = sessionUsage + } + r.released = true + r.pending = false + r.bytes = 0 + b.globalBytes.release(int(bytes64)) + b.globalEntries.release() + sessionShard.mu.Unlock() + authShard.mu.Unlock() +} + +func (b *rpcResultFairBudget) authSnapshot(authKeyID [8]byte) rpcResultBudgetUsage { + if b == nil { + return rpcResultBudgetUsage{} + } + shard := b.authShard(authKeyID) + shard.mu.Lock() + usage := shard.usage[authKeyID] + shard.mu.Unlock() + return usage +} + +func (b *rpcResultFairBudget) sessionSnapshot(authKeyID [8]byte, sessionID int64) rpcResultBudgetUsage { + if b == nil { + return rpcResultBudgetUsage{} + } + key := rpcResultSessionBudgetKey{authKeyID: authKeyID, sessionID: sessionID} + shard := b.sessionShard(key) + shard.mu.Lock() + usage := shard.usage[key] + shard.mu.Unlock() + return usage +} + +func (b *rpcResultFairBudget) authShard(authKeyID [8]byte) *rpcResultAuthBudgetShard { + index := maphash.Bytes(b.seed, authKeyID[:]) & (rpcResultBudgetShards - 1) + return &b.authShards[index] +} + +func (b *rpcResultFairBudget) sessionShard(key rpcResultSessionBudgetKey) *rpcResultSessionBudgetShard { + var raw [16]byte + copy(raw[:8], key.authKeyID[:]) + binary.LittleEndian.PutUint64(raw[8:], uint64(key.sessionID)) + index := maphash.Bytes(b.seed, raw[:]) & (rpcResultBudgetShards - 1) + return &b.sessionShards[index] +} diff --git a/internal/mtprotoedge/rpc_result_cache.go b/internal/mtprotoedge/rpc_result_cache.go index 231996ef..288f6bcf 100644 --- a/internal/mtprotoedge/rpc_result_cache.go +++ b/internal/mtprotoedge/rpc_result_cache.go @@ -3,17 +3,39 @@ package mtprotoedge import ( "container/list" "encoding/binary" + "hash/maphash" "sync" + "sync/atomic" "time" ) const ( - rpcResultCacheTTL = 3 * time.Minute - rpcResultCacheMaxEntries = 4096 - rpcResultCacheMaxBytes = 64 << 20 - // rpcResultCacheShards 把缓存按 (auth_key_id, session_id) 分片:每条 RPC 都要 - // Get(重复检测)+ Put(结果缓存),单把全局锁会让所有连接的 RPC 热路径在 - // 一个 mutex 上汇聚(同 P0-5 的 SessionManager 教训)。分片数为 2 的幂。 + // Telegram accepts client msg_id values up to five minutes old and up to + // thirty seconds in the future. Retain the result across that complete + // replay horizon, plus one second for boundary/scheduler jitter, so a valid + // duplicate cannot rerun its handler merely because our cache expired first. + rpcResultCacheTTL = 331 * time.Second + // Completed results cover the complete replay horizon under explicit global, + // auth and session hard ceilings. At the default 331-second TTL, the 1<<18 + // global entries permit about 792 unique RPC/s process-wide before bounded + // backpressure; lower scopes provide noisy-neighbor isolation. + rpcResultCacheMaxEntries = 1 << 18 + rpcResultCacheMaxBytes = 64 << 20 + rpcResultCacheAuthMaxEntries = 1 << 15 + rpcResultCacheAuthMaxBytes = 32 << 20 + rpcResultCacheSessionMaxEntries = 1 << 14 + rpcResultCacheSessionMaxBytes = 16 << 20 + rpcResultFlightMaxPendingPerAuth = 1 << 11 + // Keep every transport-legal rpc_result cacheable. Converting the constant + // difference to uint64 intentionally fails compilation if a future transport + // limit grows beyond the completed-result budget. + _ = uint64(rpcResultCacheMaxBytes - maxOutboundBodyBytes) + _ = uint64(rpcResultCacheAuthMaxBytes - maxOutboundBodyBytes) + _ = uint64(rpcResultCacheSessionMaxBytes - maxOutboundBodyBytes) + // rpcResultCacheShards hashes the complete replay identity with a random + // per-instance maphash seed. Including req_msg_id spreads one hot session's + // independent requests instead of forcing them through one mutex. The shard + // count is a power of two. rpcResultCacheShards = 16 ) @@ -24,10 +46,28 @@ type rpcResultCacheKey struct { } type rpcResultCacheEntry struct { - key rpcResultCacheKey - encoded *encodedOutboundMessage - size int - expiresAt time.Time + key rpcResultCacheKey + encoded *encodedOutboundMessage + size int + expiresAt time.Time + identity rpcResultRequestIdentity + admissionSeq uint64 + executionKnown bool + executionOK bool + // capacity marks a bounded replay tombstone. The original owner and its + // already-joined waiters received encoded, but the byte budget could not + // retain that body. Keeping the immutable identity until TTL prevents a + // duplicate from rerunning business; Acquire returns a capacity error. + capacity bool + // reservation is the same global+auth+session ownership acquired before the + // handler ran. Put transfers it from the pending flight; TTL returns it. + reservation *rpcResultBudgetReservation +} + +type rpcResultDependency struct { + waiter *rpcResultWaiter + completed bool + success bool } // rpcResultCache 缓存已有交付证明的 rpc_result(按 auth_key+session+req_msg_id), @@ -36,16 +76,35 @@ type rpcResultCacheEntry struct { // encodedOutboundMessage 构造后不可变(push fan-out 与 pending resend 均依赖该契约), // 因此 Get/Put 直接共享指针,不做防御性拷贝。 type rpcResultCache struct { - shards [rpcResultCacheShards]rpcResultCacheShard - flightLimit rpcResultFlightLimit + shards [rpcResultCacheShards]rpcResultCacheShard + hashSeed maphash.Seed + completedBytes rpcResultCacheByteBudget + completedEntries rpcResultFlightLimit + fairBudget *rpcResultFairBudget + flightLimit rpcResultFlightLimit + subscriberBudget *rpcResultSubscriberBudget + subscriberPerFlight int + // nextAdmissionSeq is the process-wide ordering authority for auth-key + // shared Layer defaults. Exact owners allocate once; joins/replays retain the + // owner's value from their flight/completed descriptor. + nextAdmissionSeq atomic.Uint64 + activeAdmissions rpcAdmissionTracker +} + +func (c *rpcResultCache) stableAdmissionSafeFloor() uint64 { + if c == nil { + return 0 + } + return c.activeAdmissions.stableSafeFloor(&c.nextAdmissionSeq) } type rpcResultCacheShard struct { - mu sync.Mutex - now func() time.Time - ttl time.Duration + mu sync.Mutex + now func() time.Time + ttl time.Duration + // maxEntries is a focused-test seam for one physical shard. Production leaves + // it zero and uses the explicit global/auth/session fair-budget hierarchy. maxEntries int - maxBytes int bytes int order *list.List byKey map[rpcResultCacheKey]*list.Element @@ -56,20 +115,129 @@ type rpcResultCacheShard struct { } func newRPCResultCacheWithFlightLimit(now func() time.Time, maxPending int) *rpcResultCache { - if now == nil { - now = time.Now - } if maxPending <= 0 { maxPending = rpcResultFlightDefaultMaxPending } - c := &rpcResultCache{} - c.flightLimit.max = int64(maxPending) + pendingPerAuth := rpcResultFlightMaxPendingPerAuth + if pendingPerAuth > maxPending { + pendingPerAuth = maxPending + } + return newRPCResultCacheWithFairCapacity(now, rpcResultCacheCapacity{ + maxPending: maxPending, + maxPendingPerAuth: pendingPerAuth, + globalMaxBytes: rpcResultCacheMaxBytes, + globalMaxEntries: rpcResultCacheMaxEntries, + authMaxBytes: rpcResultCacheAuthMaxBytes, + authMaxEntries: rpcResultCacheAuthMaxEntries, + sessionMaxBytes: rpcResultCacheSessionMaxBytes, + sessionMaxEntries: rpcResultCacheSessionMaxEntries, + }) +} + +func newRPCResultCacheWithLimits(now func() time.Time, maxPending, maxCompletedBytes int) *rpcResultCache { + return newRPCResultCacheWithCapacity(now, maxPending, int64(maxCompletedBytes), rpcResultCacheMaxEntries) +} + +func newRPCResultCacheWithCapacity( + now func() time.Time, + maxPending int, + maxCompletedBytes int64, + maxCompletedEntries int, +) *rpcResultCache { + // Compatibility/test constructor: the caller supplied only global limits, so + // keep every fairness scope equal to that global ceiling. Production always + // calls newRPCResultCacheWithFairCapacity with explicit auth/session limits. + return newRPCResultCacheWithFairCapacity(now, rpcResultCacheCapacity{ + maxPending: maxPending, + maxPendingPerAuth: maxPending, + globalMaxBytes: maxCompletedBytes, + globalMaxEntries: maxCompletedEntries, + authMaxBytes: maxCompletedBytes, + authMaxEntries: maxCompletedEntries, + sessionMaxBytes: maxCompletedBytes, + sessionMaxEntries: maxCompletedEntries, + }) +} + +type rpcResultCacheCapacity struct { + maxPending int + maxPendingPerAuth int + globalMaxBytes int64 + globalMaxEntries int + authMaxBytes int64 + authMaxEntries int + sessionMaxBytes int64 + sessionMaxEntries int + subscriberMaxGlobal int + subscriberMaxAuth int + subscriberMaxSession int + subscriberMaxPerFlight int +} + +func newRPCResultCacheWithFairCapacity(now func() time.Time, capacity rpcResultCacheCapacity) *rpcResultCache { + if now == nil { + now = time.Now + } + if capacity.maxPending <= 0 { + capacity.maxPending = rpcResultFlightDefaultMaxPending + } + if capacity.maxPendingPerAuth <= 0 { + capacity.maxPendingPerAuth = capacity.maxPending + } + if capacity.globalMaxBytes <= 0 { + capacity.globalMaxBytes = rpcResultCacheMaxBytes + } + if capacity.globalMaxEntries <= 0 { + capacity.globalMaxEntries = rpcResultCacheMaxEntries + } + if capacity.authMaxBytes <= 0 { + capacity.authMaxBytes = capacity.globalMaxBytes + } + if capacity.authMaxEntries <= 0 { + capacity.authMaxEntries = capacity.globalMaxEntries + } + if capacity.sessionMaxBytes <= 0 { + capacity.sessionMaxBytes = capacity.authMaxBytes + } + if capacity.sessionMaxEntries <= 0 { + capacity.sessionMaxEntries = capacity.authMaxEntries + } + if capacity.subscriberMaxGlobal <= 0 { + capacity.subscriberMaxGlobal = rpcResultSubscriberMaxGlobal + } + if capacity.subscriberMaxAuth <= 0 { + capacity.subscriberMaxAuth = rpcResultSubscriberMaxAuth + } + if capacity.subscriberMaxSession <= 0 { + capacity.subscriberMaxSession = rpcResultSubscriberMaxSession + } + if capacity.subscriberMaxPerFlight <= 0 { + capacity.subscriberMaxPerFlight = rpcResultSubscriberMaxPerFlight + } + c := &rpcResultCache{hashSeed: maphash.MakeSeed()} + c.completedBytes.max = capacity.globalMaxBytes + c.completedEntries.max = int64(capacity.globalMaxEntries) + c.flightLimit.max = int64(capacity.maxPending) + c.fairBudget = newRPCResultFairBudget( + c.hashSeed, + &c.completedEntries, + &c.completedBytes, + rpcResultBudgetLimit{entries: int64(capacity.authMaxEntries), bytes: capacity.authMaxBytes}, + rpcResultBudgetLimit{entries: int64(capacity.sessionMaxEntries), bytes: capacity.sessionMaxBytes}, + capacity.maxPendingPerAuth, + ) + c.subscriberBudget = newRPCResultSubscriberBudget( + c.hashSeed, + capacity.subscriberMaxGlobal, + capacity.subscriberMaxAuth, + capacity.subscriberMaxSession, + ) + c.subscriberPerFlight = capacity.subscriberMaxPerFlight for i := range c.shards { s := &c.shards[i] s.now = now s.ttl = rpcResultCacheTTL - s.maxEntries = rpcResultCacheMaxEntries / rpcResultCacheShards - s.maxBytes = rpcResultCacheMaxBytes / rpcResultCacheShards + s.maxEntries = 0 s.order = list.New() s.byKey = make(map[rpcResultCacheKey]*list.Element) s.pending = make(map[rpcResultCacheKey]*rpcResultFlight) @@ -78,10 +246,16 @@ func newRPCResultCacheWithFlightLimit(now func() time.Time, maxPending int) *rpc } func (c *rpcResultCache) shard(key rpcResultCacheKey) *rpcResultCacheShard { - // auth_key_id 与 session_id 都是均匀随机的 64-bit 值,异或折叠后取低位即可。 - h := binary.LittleEndian.Uint64(key.authKeyID[:]) ^ uint64(key.sessionID) - h ^= h >> 32 - return &c.shards[h&(rpcResultCacheShards-1)] + return &c.shards[c.shardIndex(key)] + +} + +func (c *rpcResultCache) shardIndex(key rpcResultCacheKey) uint64 { + var raw [24]byte + copy(raw[:8], key.authKeyID[:]) + binary.LittleEndian.PutUint64(raw[8:16], uint64(key.sessionID)) + binary.LittleEndian.PutUint64(raw[16:24], uint64(key.reqMsgID)) + return maphash.Bytes(c.hashSeed, raw[:]) & (rpcResultCacheShards - 1) } func (c *rpcResultCache) Get(authKeyID [8]byte, sessionID, reqMsgID int64) (*encodedOutboundMessage, bool) { @@ -104,45 +278,210 @@ func (c *rpcResultCache) Get(authKeyID [8]byte, sessionID, reqMsgID int64) (*enc s.removeElement(elem) return nil, false } + if entry.capacity || entry.encoded == nil { + return nil, false + } return entry.encoded, true } +// ObserveDependency returns a waiter for an admitted in-flight dependency, a +// nil waiter for an already completed dependency, or ok=false when the +// referenced message never established API-RPC ownership. It never creates a +// flight and therefore cannot turn a forged invokeAfterMsg into authority to +// run another request. +func (c *rpcResultCache) ObserveDependency(authKeyID [8]byte, sessionID, reqMsgID int64) (rpcResultDependency, bool) { + if c == nil || reqMsgID == 0 { + return rpcResultDependency{}, false + } + key := rpcResultCacheKey{authKeyID: authKeyID, sessionID: sessionID, reqMsgID: reqMsgID} + s := c.shard(key) + now := s.now() + s.mu.Lock() + defer s.mu.Unlock() + if elem, exists := s.byKey[key]; exists { + entry := elem.Value.(*rpcResultCacheEntry) + if entry.expiresAt.After(now) { + if !entry.executionKnown { + return rpcResultDependency{}, false + } + return rpcResultDependency{completed: true, success: entry.executionOK}, true + } + s.removeElement(elem) + } + if flight := s.pending[key]; flight != nil { + if flight.executionDone { + return rpcResultDependency{completed: true, success: flight.executionOK}, true + } + return rpcResultDependency{waiter: &rpcResultWaiter{cache: c, key: key, flight: flight}}, true + } + return rpcResultDependency{}, false +} + func (c *rpcResultCache) Put(authKeyID [8]byte, sessionID, reqMsgID int64, encoded *encodedOutboundMessage) { if c == nil || reqMsgID == 0 || encoded == nil { return } + if c.putOnce(authKeyID, sessionID, reqMsgID, encoded) { + return + } + // A direct Put has no pre-reserved owner slot. Expired entries in another + // shard may be its only blocker; reap once without holding a shard and retry. + // Production owner publication already carries both reservations and never + // needs this cold path. + c.expireCompletedResults() + _ = c.putOnce(authKeyID, sessionID, reqMsgID, encoded) +} + +// putOnce returns false only when a cross-shard expiry reap may release the +// process-wide entry/body capacity needed by a defensive direct Put. +func (c *rpcResultCache) putOnce(authKeyID [8]byte, sessionID, reqMsgID int64, encoded *encodedOutboundMessage) bool { key := rpcResultCacheKey{authKeyID: authKeyID, sessionID: sessionID, reqMsgID: reqMsgID} s := c.shard(key) - size := len(encoded.body) - cacheable := s.maxBytes <= 0 || size <= s.maxBytes - now := s.now() - - s.mu.Lock() - - if cacheable { - s.expireLocked(now) - if elem, ok := s.byKey[key]; ok { - s.removeElement(elem) - } - entry := &rpcResultCacheEntry{ - key: key, - encoded: encoded, - size: size, - expiresAt: now.Add(s.ttl), - } - elem := s.order.PushBack(entry) - s.byKey[key] = elem - s.bytes += size - s.trimLocked() + accountedSize := len(encoded.body) + if accountedSize < 1 { + // Every owner reserves one byte at admission. Keeping zero-length results + // at the same minimum makes entry and byte capacity linearizable. + accountedSize = 1 } - // Resolve the independent in-flight entry only after the completed cache has - // been published. Waiters awakened by this close can therefore immediately - // observe either the shared encoded result or the completed Get entry. - subscribers := c.completeRPCResultFlightLocked(s, key, encoded) + + // Publication never evicts another unexpired result. A production owner has + // already reserved its entry slot and one byte. If its actual result cannot + // expand that reservation, publish a one-byte identity tombstone: the owner + // and current waiters still receive the immutable result, while later + // duplicates fail admission instead of rerunning the handler. + s.mu.Lock() + now := s.now() + s.expireLocked(now) + old := s.byKey[key] + flight := s.pending[key] + if old == nil && flight == nil && s.maxEntries > 0 && len(s.byKey) >= s.maxEntries { + // Defensive direct Put callers do not own a reserved admission slot. + // Preserve every existing unexpired result and decline the new cache row. + s.mu.Unlock() + return true + } + + identity, admissionSeq, executionKnown, executionOK := rpcResultFlightMetadataLocked(s, key) + var oldEntry *rpcResultCacheEntry + if old != nil { + oldEntry = old.Value.(*rpcResultCacheEntry) + if flight == nil { + // A defensive duplicate terminal publication must never downgrade + // completed dependency/identity metadata after its flight disappeared. + identity = oldEntry.identity + admissionSeq = oldEntry.admissionSeq + executionKnown = oldEntry.executionKnown + executionOK = oldEntry.executionOK + } + } + + var reservation *rpcResultBudgetReservation + switch { + case flight != nil: + reservation = flight.reservation + if reservation == nil { + s.mu.Unlock() + panic("mtprotoedge: pending rpc result has no fair-budget reservation") + } + case oldEntry != nil && oldEntry.reservation != nil: + reservation = oldEntry.reservation + default: + reservation = c.fairBudget.reserveCompleted(key, accountedSize) + if reservation == nil { + s.mu.Unlock() + return false + } + } + + retainedSize := accountedSize + retained := encoded + capacity := false + if !reservation.resizeBytes(accountedSize) { + if flight == nil { + // A direct replacement cannot discard the prior replay body. Leave it + // untouched and let Put perform one cross-shard expiry reap before its + // final bounded failure. + if oldEntry == nil { + reservation.release() + } + s.mu.Unlock() + return false + } + // Owner admission already reserved one byte at all three scopes. When the + // actual body cannot expand, transfer that reservation to an identity + // tombstone so a duplicate never reruns business. + const tombstoneSize = 1 + if !reservation.resizeBytes(tombstoneSize) { + s.mu.Unlock() + panic("mtprotoedge: rpc result owner lost its one-byte tombstone reservation") + } + retainedSize = tombstoneSize + retained = nil + capacity = true + } + + if old != nil { + s.unlinkElement(old) + if oldEntry.reservation != nil && oldEntry.reservation != reservation { + oldEntry.reservation.release() + oldEntry.reservation = nil + } + } + entry := &rpcResultCacheEntry{ + key: key, + encoded: retained, + size: retainedSize, + expiresAt: now.Add(s.ttl), + identity: identity, + admissionSeq: admissionSeq, + executionKnown: executionKnown, + executionOK: executionOK, + capacity: capacity, + reservation: reservation, + } + elem := s.order.PushBack(entry) + s.byKey[key] = elem + s.bytes += retainedSize + + // Resolve the independent in-flight entry only after either the completed + // result or its replay tombstone is published under the same shard lock. + subscribers, executionSubscribers, executionOK := c.completeRPCResultFlightLocked(s, key, encoded) s.mu.Unlock() for _, subscriber := range subscribers { subscriber(encoded, true) } + for _, subscriber := range executionSubscribers { + subscriber(executionOK) + } + return true +} + +func rpcResultFlightMetadataLocked(s *rpcResultCacheShard, key rpcResultCacheKey) ( + rpcResultRequestIdentity, + uint64, + bool, + bool, +) { + if flight := s.pending[key]; flight != nil { + return flight.identity, flight.admissionSeq, flight.executionDone, flight.executionOK + } + return rpcResultRequestIdentity{}, 0, false, false +} + +// expireCompletedResults performs the cold-path cross-shard reap used only +// after a one-byte admission reservation fails. The caller must hold no shard +// lock. Each shard is reaped independently so ordinary result publication on +// the other shards remains parallel. +func (c *rpcResultCache) expireCompletedResults() { + if c == nil { + return + } + for i := range c.shards { + s := &c.shards[i] + s.mu.Lock() + s.expireLocked(s.now()) + s.mu.Unlock() + } } func (s *rpcResultCacheShard) expireLocked(now time.Time) { @@ -157,20 +496,17 @@ func (s *rpcResultCacheShard) expireLocked(now time.Time) { } } -func (s *rpcResultCacheShard) trimLocked() { - for s.order.Len() > 0 { - tooManyEntries := s.maxEntries > 0 && s.order.Len() > s.maxEntries - tooManyBytes := s.maxBytes > 0 && s.bytes > s.maxBytes - if !tooManyEntries && !tooManyBytes { - return - } - s.removeElement(s.order.Front()) +func (s *rpcResultCacheShard) removeElement(elem *list.Element) { + entry := s.unlinkElement(elem) + if entry != nil && entry.reservation != nil { + entry.reservation.release() + entry.reservation = nil } } -func (s *rpcResultCacheShard) removeElement(elem *list.Element) { +func (s *rpcResultCacheShard) unlinkElement(elem *list.Element) *rpcResultCacheEntry { if elem == nil { - return + return nil } entry := elem.Value.(*rpcResultCacheEntry) delete(s.byKey, entry.key) @@ -179,4 +515,45 @@ func (s *rpcResultCacheShard) removeElement(elem *list.Element) { s.bytes = 0 } s.order.Remove(elem) + return entry +} + +type rpcResultCacheByteBudget struct { + max int64 + used atomic.Int64 +} + +func (b *rpcResultCacheByteBudget) reserve(n int) bool { + if n <= 0 { + return true + } + bytes := int64(n) + if b == nil || bytes > b.max { + return false + } + for { + used := b.used.Load() + if used > b.max-bytes { + return false + } + if b.used.CompareAndSwap(used, used+bytes) { + return true + } + } +} + +func (b *rpcResultCacheByteBudget) release(n int) { + if b == nil || n <= 0 { + return + } + if remaining := b.used.Add(-int64(n)); remaining < 0 { + panic("mtprotoedge: rpc result completed-byte budget underflow") + } +} + +func (b *rpcResultCacheByteBudget) snapshot() int64 { + if b == nil { + return 0 + } + return b.used.Load() } diff --git a/internal/mtprotoedge/rpc_result_cache_test.go b/internal/mtprotoedge/rpc_result_cache_test.go index 9d6ac353..51d9b2af 100644 --- a/internal/mtprotoedge/rpc_result_cache_test.go +++ b/internal/mtprotoedge/rpc_result_cache_test.go @@ -1,11 +1,476 @@ package mtprotoedge import ( + "errors" + "sync" + "sync/atomic" "testing" "time" ) +func TestRPCResultCacheFullSessionDoesNotBlockAnotherAuth(t *testing.T) { + now := time.Unix(1000, 0) + cache := newRPCResultCacheWithFairCapacity(func() time.Time { return now }, rpcResultCacheCapacity{ + maxPending: 8, maxPendingPerAuth: 6, + globalMaxEntries: 8, globalMaxBytes: 64, + authMaxEntries: 6, authMaxBytes: 48, + sessionMaxEntries: 2, sessionMaxBytes: 16, + }) + authA := [8]byte{0xa1} + authB := [8]byte{0xb1} + const sessionA = int64(77) + + for i := 0; i < 2; i++ { + msgID := int64(1000 + i) + claim, err := cache.Acquire(authA, sessionA, msgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("same-session admission %d = %#v, %v", i, claim, err) + } + cache.Put(authA, sessionA, msgID, &encodedOutboundMessage{body: []byte{1}}) + } + if _, err := cache.Acquire(authA, sessionA, 2000); !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Fatalf("admission beyond session entry limit = %v, want capacity", err) + } + otherAuth, err := cache.Acquire(authB, 88, 3000) + if err != nil || otherAuth.state != rpcResultAcquireOwner { + t.Fatalf("other auth blocked by full session: %#v, %v", otherAuth, err) + } + if !otherAuth.owner.Abort() { + t.Fatal("other-auth owner did not abort") + } + if _, ok := cache.Get(authA, sessionA, 1000); !ok { + t.Fatal("session capacity pressure evicted an unexpired result") + } +} + +func TestRPCResultCacheFullAuthDoesNotBlockAnotherAuth(t *testing.T) { + cache := newRPCResultCacheWithFairCapacity(time.Now, rpcResultCacheCapacity{ + maxPending: 8, maxPendingPerAuth: 4, + globalMaxEntries: 8, globalMaxBytes: 64, + authMaxEntries: 2, authMaxBytes: 32, + sessionMaxEntries: 2, sessionMaxBytes: 16, + }) + authA := [8]byte{0xa2} + authB := [8]byte{0xb2} + for i := 0; i < 2; i++ { + claim, err := cache.Acquire(authA, int64(10+i), int64(100+i)) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("auth A admission %d = %#v, %v", i, claim, err) + } + cache.Put(authA, int64(10+i), int64(100+i), &encodedOutboundMessage{body: []byte{1}}) + } + if _, err := cache.Acquire(authA, 12, 102); !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Fatalf("same-auth new session at auth limit = %v, want capacity", err) + } + other, err := cache.Acquire(authB, 20, 200) + if err != nil || other.state != rpcResultAcquireOwner { + t.Fatalf("other auth blocked by full auth A: %#v, %v", other, err) + } + other.owner.Abort() +} + +func TestRPCResultCacheAuthAndSessionByteLimitsAreIndependent(t *testing.T) { + cache := newRPCResultCacheWithFairCapacity(time.Now, rpcResultCacheCapacity{ + maxPending: 8, maxPendingPerAuth: 6, + globalMaxEntries: 10, globalMaxBytes: 10, + authMaxEntries: 8, authMaxBytes: 4, + sessionMaxEntries: 6, sessionMaxBytes: 2, + }) + authA := [8]byte{0xa4} + authB := [8]byte{0xb4} + first, err := cache.Acquire(authA, 1, 101) + if err != nil || first.state != rpcResultAcquireOwner { + t.Fatalf("first owner = %#v, %v", first, err) + } + cache.Put(authA, 1, 101, &encodedOutboundMessage{body: []byte{1, 2}}) + if _, err := cache.Acquire(authA, 1, 102); !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Fatalf("same session beyond byte limit = %v, want capacity", err) + } + second, err := cache.Acquire(authA, 2, 201) + if err != nil || second.state != rpcResultAcquireOwner { + t.Fatalf("second session owner = %#v, %v", second, err) + } + cache.Put(authA, 2, 201, &encodedOutboundMessage{body: []byte{3, 4}}) + if _, err := cache.Acquire(authA, 3, 301); !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Fatalf("same auth beyond byte limit = %v, want capacity", err) + } + other, err := cache.Acquire(authB, 3, 302) + if err != nil || other.state != rpcResultAcquireOwner { + t.Fatalf("other auth blocked by auth A byte limit: %#v, %v", other, err) + } + other.owner.Abort() +} + +func TestRPCResultCachePerAuthPendingLimitIsAdditional(t *testing.T) { + cache := newRPCResultCacheWithFairCapacity(time.Now, rpcResultCacheCapacity{ + maxPending: 6, maxPendingPerAuth: 2, + globalMaxEntries: 12, globalMaxBytes: 64, + authMaxEntries: 6, authMaxBytes: 32, + sessionMaxEntries: 4, sessionMaxBytes: 16, + }) + authA := [8]byte{0xa3} + authB := [8]byte{0xb3} + owners := make([]*rpcResultOwnerLease, 0, 3) + for i := 0; i < 2; i++ { + claim, err := cache.Acquire(authA, int64(i+1), int64(100+i)) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("pending auth A %d = %#v, %v", i, claim, err) + } + owners = append(owners, claim.owner) + } + if _, err := cache.Acquire(authA, 3, 103); !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Fatalf("third pending owner for auth A = %v, want capacity", err) + } + other, err := cache.Acquire(authB, 4, 104) + if err != nil || other.state != rpcResultAcquireOwner { + t.Fatalf("auth B blocked by auth A pending limit: %#v, %v", other, err) + } + owners = append(owners, other.owner) + for _, owner := range owners { + if !owner.Abort() { + t.Fatal("pending owner did not abort") + } + } + if usage := cache.fairBudget.authSnapshot(authA); usage != (rpcResultBudgetUsage{}) { + t.Fatalf("auth A budget after abort = %#v", usage) + } +} + +func TestRPCResultCacheFairReservationLifecycleReturnsEveryScope(t *testing.T) { + now := time.Unix(1000, 0) + cache := newRPCResultCacheWithFairCapacity(func() time.Time { return now }, rpcResultCacheCapacity{ + maxPending: 4, maxPendingPerAuth: 3, + globalMaxEntries: 6, globalMaxBytes: 10, + authMaxEntries: 5, authMaxBytes: 8, + sessionMaxEntries: 3, sessionMaxBytes: 6, + }) + auth := [8]byte{0xc1} + + aborted, err := cache.Acquire(auth, 1, 101) + if err != nil || aborted.state != rpcResultAcquireOwner { + t.Fatalf("aborted owner = %#v, %v", aborted, err) + } + if usage := cache.fairBudget.authSnapshot(auth); usage.entries != 1 || usage.bytes != 1 || usage.pending != 1 { + t.Fatalf("pending auth reservation = %#v", usage) + } + if !aborted.owner.Abort() { + t.Fatal("owner Abort lost") + } + if usage := cache.fairBudget.authSnapshot(auth); usage != (rpcResultBudgetUsage{}) { + t.Fatalf("Abort leaked auth reservation %#v", usage) + } + + body, err := cache.Acquire(auth, 1, 102) + if err != nil || body.state != rpcResultAcquireOwner { + t.Fatalf("body owner = %#v, %v", body, err) + } + cache.Put(auth, 1, 102, &encodedOutboundMessage{body: make([]byte, 4)}) + if usage := cache.fairBudget.sessionSnapshot(auth, 1); usage.entries != 1 || usage.bytes != 4 || usage.pending != 0 { + t.Fatalf("body session reservation = %#v", usage) + } + + tombstone, err := cache.Acquire(auth, 2, 201) + if err != nil || tombstone.state != rpcResultAcquireOwner { + t.Fatalf("tombstone owner = %#v, %v", tombstone, err) + } + // This cannot fit the 10-byte global or 8-byte auth ceiling. Put must not + // panic or lose ownership; it transfers the one-byte token to a tombstone. + cache.Put(auth, 2, 201, &encodedOutboundMessage{body: make([]byte, 20)}) + if usage := cache.fairBudget.sessionSnapshot(auth, 2); usage.entries != 1 || usage.bytes != 1 || usage.pending != 0 { + t.Fatalf("tombstone session reservation = %#v", usage) + } + if got := cache.completedEntries.snapshot(); got != 2 { + t.Fatalf("global entries after body+tombstone = %d, want 2", got) + } + if got := cache.completedBytes.snapshot(); got != 5 { + t.Fatalf("global bytes after body+tombstone = %d, want 5", got) + } + + cache.Put(auth, 1, 102, &encodedOutboundMessage{body: make([]byte, 2)}) + if got := cache.completedBytes.snapshot(); got != 3 { + t.Fatalf("replacement did not resize global bytes: %d", got) + } + now = now.Add(rpcResultCacheTTL + time.Second) + _, _ = cache.Get(auth, 1, 102) + _, _ = cache.Get(auth, 2, 201) + if got := cache.completedEntries.snapshot(); got != 0 { + t.Fatalf("TTL leaked global entries %d", got) + } + if got := cache.completedBytes.snapshot(); got != 0 { + t.Fatalf("TTL leaked global bytes %d", got) + } + if usage := cache.fairBudget.authSnapshot(auth); usage != (rpcResultBudgetUsage{}) { + t.Fatalf("TTL leaked auth reservation %#v", usage) + } +} + +func TestRPCResultCacheFullKeyMaphashSpreadsOneSession(t *testing.T) { + first := newRPCResultCacheWithFlightLimit(time.Now, 64) + second := newRPCResultCacheWithFlightLimit(time.Now, 64) + auth := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} + const sessionID = int64(99) + seen := make(map[uint64]struct{}) + differentInstance := false + for msgID := int64(1); msgID <= 256; msgID++ { + key := rpcResultCacheKey{authKeyID: auth, sessionID: sessionID, reqMsgID: msgID} + firstIndex := first.shardIndex(key) + seen[firstIndex] = struct{}{} + if firstIndex != second.shardIndex(key) { + differentInstance = true + } + } + if len(seen) < rpcResultCacheShards/2 { + t.Fatalf("one session used only %d/%d full-key shards", len(seen), rpcResultCacheShards) + } + if !differentInstance { + t.Fatal("two cache instances produced an identical shard stream; seed is not instance-random") + } +} + +func TestRPCResultCacheConcurrentFairReservationsNeverOvercommit(t *testing.T) { + cache := newRPCResultCacheWithFairCapacity(time.Now, rpcResultCacheCapacity{ + maxPending: 24, maxPendingPerAuth: 4, + globalMaxEntries: 24, globalMaxBytes: 24, + authMaxEntries: 8, authMaxBytes: 8, + sessionMaxEntries: 3, sessionMaxBytes: 3, + }) + const callers = 256 + start := make(chan struct{}) + var ( + wg sync.WaitGroup + mu sync.Mutex + owners []*rpcResultOwnerLease + ) + for i := 0; i < callers; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + <-start + auth := [8]byte{byte(i % 4)} + claim, err := cache.Acquire(auth, int64(i%8), int64(1000+i)) + if errors.Is(err, ErrRPCResultFlightCapacity) { + return + } + if err != nil || claim.state != rpcResultAcquireOwner { + t.Errorf("Acquire %d = %#v, %v", i, claim, err) + return + } + mu.Lock() + owners = append(owners, claim.owner) + mu.Unlock() + }(i) + } + close(start) + wg.Wait() + if got := cache.completedEntries.snapshot(); got > 24 || got != int64(len(owners)) { + t.Fatalf("global entry usage=%d owners=%d limit=24", got, len(owners)) + } + if got := cache.completedBytes.snapshot(); got > 24 || got != int64(len(owners)) { + t.Fatalf("global byte usage=%d owners=%d limit=24", got, len(owners)) + } + for i := 0; i < 4; i++ { + auth := [8]byte{byte(i)} + usage := cache.fairBudget.authSnapshot(auth) + if usage.entries > 8 || usage.bytes > 8 || usage.pending > 4 { + t.Fatalf("auth %d overcommitted: %#v", i, usage) + } + for sessionID := int64(0); sessionID < 8; sessionID++ { + session := cache.fairBudget.sessionSnapshot(auth, sessionID) + if session.entries > 3 || session.bytes > 3 { + t.Fatalf("auth %d session %d overcommitted: %#v", i, sessionID, session) + } + } + } + for _, owner := range owners { + if !owner.Abort() { + t.Fatal("concurrent owner did not abort") + } + } + if cache.completedEntries.snapshot() != 0 || cache.completedBytes.snapshot() != 0 { + t.Fatal("concurrent Abort leaked global fair budget") + } +} + +func TestRPCResultCacheConcurrentOwnerPublicationAcrossShards(t *testing.T) { + const publications = 256 + now := time.Unix(1000, 0) + cache := newRPCResultCacheWithFairCapacity(func() time.Time { return now }, rpcResultCacheCapacity{ + maxPending: publications, maxPendingPerAuth: 4, + globalMaxEntries: publications, globalMaxBytes: publications * 4, + authMaxEntries: 4, authMaxBytes: 16, + sessionMaxEntries: 1, sessionMaxBytes: 4, + }) + + type publication struct { + auth [8]byte + session int64 + msgID int64 + owner *rpcResultOwnerLease + } + publicationsByKey := make([]publication, 0, publications) + for i := 0; i < publications; i++ { + auth := [8]byte{byte(i), byte(i >> 8), 0xa5} + sessionID := int64(10_000 + i) + msgID := int64(20_000 + i) + claim, err := cache.Acquire(auth, sessionID, msgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("Acquire %d = %#v, %v", i, claim, err) + } + publicationsByKey = append(publicationsByKey, publication{ + auth: auth, session: sessionID, msgID: msgID, owner: claim.owner, + }) + } + + start := make(chan struct{}) + var wg sync.WaitGroup + for i := range publicationsByKey { + item := publicationsByKey[i] + wg.Add(1) + go func() { + defer wg.Done() + <-start + if !item.owner.CompleteExecution(true) { + t.Errorf("CompleteExecution(%d) lost owner", item.msgID) + return + } + cache.Put(item.auth, item.session, item.msgID, &encodedOutboundMessage{body: []byte{1, 2, 3, 4}}) + }() + } + close(start) + wg.Wait() + + for _, item := range publicationsByKey { + encoded, ok := cache.Get(item.auth, item.session, item.msgID) + if !ok || encoded == nil || len(encoded.body) != 4 { + t.Fatalf("completed publication %d missing: ok=%v encoded=%#v", item.msgID, ok, encoded) + } + } + if got := cache.completedEntries.snapshot(); got != publications { + t.Fatalf("completed entries=%d, want %d", got, publications) + } + if got := cache.completedBytes.snapshot(); got != publications*4 { + t.Fatalf("completed bytes=%d, want %d", got, publications*4) + } + + now = now.Add(rpcResultCacheTTL + time.Second) + cache.expireCompletedResults() + if cache.completedEntries.snapshot() != 0 || cache.completedBytes.snapshot() != 0 { + t.Fatal("parallel publications leaked fair-budget reservations after TTL") + } +} + +func BenchmarkRPCResultCacheParallelShardPut(b *testing.B) { + cache := newRPCResultCacheWithFlightLimit(time.Now, rpcResultFlightDefaultMaxPending) + var nextWorker atomic.Uint64 + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + id := nextWorker.Add(1) + auth := [8]byte{ + byte(id), byte(id >> 8), byte(id >> 16), byte(id >> 24), + byte(id >> 32), byte(id >> 40), byte(id >> 48), byte(id >> 56), + } + sessionID := int64(id) + msgID := int64(1_000_000 + id) + encoded := &encodedOutboundMessage{body: []byte{1, 2, 3, 4}} + for pb.Next() { + cache.Put(auth, sessionID, msgID, encoded) + } + }) +} + +func TestRPCResultCacheEntryReservationTransfersAndReturns(t *testing.T) { + now := time.Unix(1000, 0) + cache := newRPCResultCacheWithCapacity(func() time.Time { return now }, 4, 2, 2) + authKeyID := [8]byte{0xa2} + + first, err := cache.Acquire(authKeyID, 1, 101) + if err != nil || first.state != rpcResultAcquireOwner || cache.completedEntries.snapshot() != 1 { + t.Fatalf("first pending reservation = %#v entries=%d err=%v", first, cache.completedEntries.snapshot(), err) + } + cache.Put(authKeyID, 1, 101, &encodedOutboundMessage{body: []byte{1}}) + if got := cache.completedEntries.snapshot(); got != 1 { + t.Fatalf("pending -> body changed entry count to %d", got) + } + + second, err := cache.Acquire(authKeyID, 2, 202) + if err != nil || second.state != rpcResultAcquireOwner || cache.completedEntries.snapshot() != 2 { + t.Fatalf("second pending reservation = %#v entries=%d err=%v", second, cache.completedEntries.snapshot(), err) + } + // The byte budget has only the second owner's one-byte token remaining. + // Publication therefore leaves an identity tombstone, which still owns its + // real process-wide entry slot. + cache.Put(authKeyID, 2, 202, &encodedOutboundMessage{body: []byte{2, 2, 2}}) + if got := cache.completedEntries.snapshot(); got != 2 { + t.Fatalf("pending -> tombstone changed entry count to %d", got) + } + if _, err := cache.Acquire(authKeyID, 3, 303); !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Fatalf("third admission at entry limit = %v, want capacity", err) + } + + now = now.Add(rpcResultCacheTTL + time.Second) + firstShard := cache.shardIndex(rpcResultCacheKey{authKeyID: authKeyID, sessionID: 1, reqMsgID: 101}) + secondShard := cache.shardIndex(rpcResultCacheKey{authKeyID: authKeyID, sessionID: 2, reqMsgID: 202}) + thirdMsgID := rpcResultTestMsgIDOutsideShards(t, cache, authKeyID, 3, 303, firstShard, secondShard) + third, err := cache.Acquire(authKeyID, 3, thirdMsgID) + if err != nil || third.state != rpcResultAcquireOwner { + t.Fatalf("admission after global expiry reap = %#v, %v", third, err) + } + if got := cache.completedEntries.snapshot(); got != 1 { + t.Fatalf("expired entries were not returned before new owner: %d", got) + } + if !third.owner.Abort() || cache.completedEntries.snapshot() != 0 { + t.Fatalf("Abort did not return entry reservation: entries=%d", cache.completedEntries.snapshot()) + } +} + +func TestRPCResultCacheConcurrentGlobalEntryReservationNeverOvercommits(t *testing.T) { + const limit = 8 + cache := newRPCResultCacheWithCapacity(time.Now, 128, 1<<20, limit) + authKeyID := [8]byte{0xa3} + var ( + wg sync.WaitGroup + mu sync.Mutex + owners []*rpcResultOwnerLease + ) + for i := 0; i < 64; i++ { + wg.Add(1) + go func(i int) { + defer wg.Done() + claim, err := cache.Acquire(authKeyID, int64(i+1), int64(1000+i)) + if err != nil { + if !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Errorf("Acquire %d: %v", i, err) + } + return + } + if claim.state != rpcResultAcquireOwner { + t.Errorf("Acquire %d state = %d", i, claim.state) + return + } + mu.Lock() + owners = append(owners, claim.owner) + mu.Unlock() + }(i) + } + wg.Wait() + if len(owners) != limit || cache.completedEntries.snapshot() != limit { + t.Fatalf("concurrent owners=%d entries=%d, want %d", len(owners), cache.completedEntries.snapshot(), limit) + } + for _, owner := range owners { + if !owner.Abort() { + t.Fatal("reserved owner failed to abort") + } + } + if got := cache.completedEntries.snapshot(); got != 0 { + t.Fatalf("entry reservations after abort = %d", got) + } +} + func TestRPCResultCacheRoundTripAndTTL(t *testing.T) { + if rpcResultCacheTTL != 331*time.Second { + t.Fatalf("replay TTL = %v, want full 300s past + 30s future window + 1s", rpcResultCacheTTL) + } now := time.Unix(1000, 0) cache := newRPCResultCache(func() time.Time { return now }) @@ -17,6 +482,12 @@ func TestRPCResultCacheRoundTripAndTTL(t *testing.T) { t.Fatal("unexpected hit on empty cache") } cache.Put(keyID, 5, 7, encoded) + if got := cache.completedEntries.snapshot(); got != 1 { + t.Fatalf("direct Put entry reservation = %d, want 1", got) + } + if usage := cache.fairBudget.sessionSnapshot(keyID, 5); usage.entries != 1 || usage.bytes != 4 || usage.pending != 0 { + t.Fatalf("direct Put session reservation = %#v", usage) + } got, ok := cache.Get(keyID, 5, 7) if !ok { @@ -40,29 +511,320 @@ func TestRPCResultCacheRoundTripAndTTL(t *testing.T) { if _, ok := cache.Get(keyID, 5, 7); ok { t.Fatal("expected expiry after TTL") } + if got := cache.completedEntries.snapshot(); got != 0 { + t.Fatalf("direct Put expiry left %d entry reservations", got) + } + if usage := cache.fairBudget.authSnapshot(keyID); usage != (rpcResultBudgetUsage{}) { + t.Fatalf("direct Put expiry leaked auth reservation %#v", usage) + } } -func TestRPCResultCacheShardTrim(t *testing.T) { +func TestRPCResultCacheDuplicatePutPreservesCompletedExecutionMetadata(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 1) + keyID := [8]byte{1, 9, 8, 4} + const sessionID, reqMsgID = int64(11), int64(12) + claim, err := cache.Acquire(keyID, sessionID, reqMsgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("Acquire owner = %#v, %v", claim, err) + } + if !claim.owner.CompleteExecution(true) || !claim.owner.HandOff() { + t.Fatal("complete owner metadata") + } + first := &encodedOutboundMessage{body: []byte{1, 2, 3, 4}, typeID: 42, reqMsgID: reqMsgID} + cache.Put(keyID, sessionID, reqMsgID, first) + second := &encodedOutboundMessage{body: []byte{5, 6, 7, 8}, typeID: 42, reqMsgID: reqMsgID} + cache.Put(keyID, sessionID, reqMsgID, second) + + replay, err := cache.Acquire(keyID, sessionID, reqMsgID) + if err != nil || replay.state != rpcResultAcquireCompleted || replay.encoded != second || + !replay.executionKnown || !replay.executionOK { + t.Fatalf("duplicate Put metadata = %#v, err=%v", replay, err) + } +} + +func TestRPCResultCacheShardCapacityNeverEvictsUnexpiredResult(t *testing.T) { now := time.Unix(1000, 0) cache := newRPCResultCache(func() time.Time { return now }) var keyID [8]byte - // 同一 (auth_key, session) 固定落在同一 shard;塞超过单 shard 条数上限,最旧的被逐出。 - perShard := rpcResultCacheMaxEntries / rpcResultCacheShards - for i := 0; i < perShard+1; i++ { - cache.Put(keyID, 1, int64(100+i), &encodedOutboundMessage{body: []byte{byte(i)}}) + firstKey := rpcResultCacheKey{authKeyID: keyID, sessionID: 1, reqMsgID: 100} + shard := cache.shard(firstKey) + shard.mu.Lock() + shard.maxEntries = 1 + shard.mu.Unlock() + + claim, err := cache.Acquire(keyID, 1, 100) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("first admission = %#v, %v", claim, err) } - if _, ok := cache.Get(keyID, 1, 100); ok { - t.Fatal("oldest entry should have been evicted by per-shard entry limit") + first := &encodedOutboundMessage{body: []byte{1}} + cache.Put(keyID, 1, 100, first) + secondMsgID := rpcResultTestMsgIDForShard(t, cache, keyID, 1, 101, cache.shardIndex(firstKey)) + if _, err := cache.Acquire(keyID, 1, secondMsgID); !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Fatalf("full-shard admission = %v, want capacity", err) } - if _, ok := cache.Get(keyID, 1, int64(100+perShard)); !ok { - t.Fatal("newest entry should survive") + if got, ok := cache.Get(keyID, 1, 100); !ok || got != first { + t.Fatalf("unexpired first result was displaced: got=%p ok=%v", got, ok) } - // 单条超过单 shard 字节预算的结果不入缓存。 - huge := &encodedOutboundMessage{body: make([]byte, rpcResultCacheMaxBytes/rpcResultCacheShards+1)} - cache.Put(keyID, 2, 999, huge) - if _, ok := cache.Get(keyID, 2, 999); ok { - t.Fatal("oversized entry should be rejected") + now = now.Add(rpcResultCacheTTL + time.Second) + claim, err = cache.Acquire(keyID, 1, secondMsgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("admission after expiry = %#v, %v", claim, err) + } + claim.owner.Abort() +} + +func TestRPCResultCacheGlobalByteCapacityNeverEvictsUnexpiredResults(t *testing.T) { + now := time.Unix(1000, 0) + cache := newRPCResultCacheWithLimits(func() time.Time { return now }, 32, 10) + var keyID [8]byte + + // Five two-byte results consume the global budget. The sixth admission must + // fail bounded; none of the retained results may be sacrificed for it. + for sessionID := int64(1); sessionID <= 5; sessionID++ { + claim, err := cache.Acquire(keyID, sessionID, 100+sessionID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("admission %d = %#v, %v", sessionID, claim, err) + } + cache.Put(keyID, sessionID, 100+sessionID, &encodedOutboundMessage{body: []byte{1, 2}}) + } + if got := cache.completedBytes.snapshot(); got != 10 { + t.Fatalf("completed bytes at capacity = %d, want 10", got) + } + if _, err := cache.Acquire(keyID, 6, 106); !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Fatalf("byte-full admission = %v, want capacity", err) + } + for sessionID := int64(1); sessionID <= 5; sessionID++ { + if _, ok := cache.Get(keyID, sessionID, 100+sessionID); !ok { + t.Fatalf("unexpired result %d was evicted", sessionID) + } } } + +func TestRPCResultCacheByteBudgetReturnsOnReplaceExpiryAndCapacity(t *testing.T) { + now := time.Unix(1000, 0) + cache := newRPCResultCacheWithLimits(func() time.Time { return now }, 32, 32) + var keyID [8]byte + + cache.Put(keyID, 1, 101, &encodedOutboundMessage{body: make([]byte, 4)}) + cache.Put(keyID, 1, 101, &encodedOutboundMessage{body: make([]byte, 7)}) + if got := cache.completedBytes.snapshot(); got != 7 { + t.Fatalf("completed bytes after growing replacement = %d, want 7", got) + } + if usage := cache.fairBudget.sessionSnapshot(keyID, 1); usage.entries != 1 || usage.bytes != 7 { + t.Fatalf("replacement fair reservation after growth = %#v", usage) + } + cache.Put(keyID, 1, 101, &encodedOutboundMessage{body: make([]byte, 2)}) + if got := cache.completedBytes.snapshot(); got != 2 { + t.Fatalf("completed bytes after shrinking replacement = %d, want 2", got) + } + if usage := cache.fairBudget.sessionSnapshot(keyID, 1); usage.entries != 1 || usage.bytes != 2 { + t.Fatalf("replacement fair reservation after shrink = %#v", usage) + } + + now = now.Add(rpcResultCacheTTL + time.Second) + if _, ok := cache.Get(keyID, 1, 101); ok { + t.Fatal("replacement should expire") + } + if got := cache.completedBytes.snapshot(); got != 0 { + t.Fatalf("completed bytes after expiry = %d, want 0", got) + } + + key := rpcResultCacheKey{authKeyID: keyID, sessionID: 2, reqMsgID: 201} + shard := cache.shard(key) + shard.mu.Lock() + shard.maxEntries = 1 + shard.mu.Unlock() + claim, err := cache.Acquire(keyID, 2, 201) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("entry-capacity first admission = %#v, %v", claim, err) + } + cache.Put(keyID, 2, 201, &encodedOutboundMessage{body: make([]byte, 3)}) + secondMsgID := rpcResultTestMsgIDForShard(t, cache, keyID, 2, 202, cache.shardIndex(key)) + if _, err := cache.Acquire(keyID, 2, secondMsgID); !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Fatalf("entry-capacity second admission = %v", err) + } + if got := cache.completedBytes.snapshot(); got != 3 { + t.Fatalf("completed bytes after capacity rejection = %d, want 3", got) + } + if _, ok := cache.Get(keyID, 2, 201); !ok { + t.Fatal("capacity rejection displaced the first result") + } +} + +func TestRPCResultCachePublicationOverflowLeavesReplayCapacityTombstone(t *testing.T) { + now := time.Unix(1000, 0) + cache := newRPCResultCacheWithLimits(func() time.Time { return now }, 32, 4) + var keyID [8]byte + claim, err := cache.Acquire(keyID, 1, 101) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("owner admission = %#v, %v", claim, err) + } + claim.owner.CompleteExecution(true) + tooLarge := &encodedOutboundMessage{body: make([]byte, 5)} + cache.Put(keyID, 1, 101, tooLarge) + if got := cache.completedBytes.snapshot(); got != 1 { + t.Fatalf("tombstone bytes = %d, want 1", got) + } + if _, ok := cache.Get(keyID, 1, 101); ok { + t.Fatal("capacity tombstone must not masquerade as a replayable body") + } + if _, err := cache.Acquire(keyID, 1, 101); !errors.Is(err, ErrRPCResultFlightCapacity) { + t.Fatalf("duplicate after publication overflow = %v, want capacity", err) + } + + now = now.Add(rpcResultCacheTTL + time.Second) + retry, err := cache.Acquire(keyID, 1, 101) + if err != nil || retry.state != rpcResultAcquireOwner { + t.Fatalf("admission after tombstone expiry = %#v, %v", retry, err) + } + retry.owner.Abort() +} + +func TestRPCResultCacheByteCapacityReclaimsExpiredAcrossShards(t *testing.T) { + now := time.Unix(1000, 0) + cache := newRPCResultCacheWithLimits(func() time.Time { return now }, 32, 2) + var keyID [8]byte + + first, err := cache.Acquire(keyID, 1, 101) + if err != nil || first.state != rpcResultAcquireOwner { + t.Fatalf("first admission = %#v, %v", first, err) + } + cache.Put(keyID, 1, 101, &encodedOutboundMessage{body: []byte{1, 2}}) + if got := cache.completedBytes.snapshot(); got != 2 { + t.Fatalf("full budget = %d, want 2", got) + } + + // Select a key in another full-key shard. Its failed one-byte reservation + // must trigger the cold-path global expiry reap before returning capacity. + now = now.Add(rpcResultCacheTTL + time.Second) + firstKey := rpcResultCacheKey{authKeyID: keyID, sessionID: 1, reqMsgID: 101} + secondMsgID := rpcResultTestMsgIDOutsideShard(t, cache, keyID, 2, 202, cache.shardIndex(firstKey)) + second, err := cache.Acquire(keyID, 2, secondMsgID) + if err != nil || second.state != rpcResultAcquireOwner { + t.Fatalf("cross-shard admission after expiry = %#v, %v", second, err) + } + second.owner.Abort() + if got := cache.completedBytes.snapshot(); got != 0 { + t.Fatalf("bytes after expired reap and abort = %d, want 0", got) + } +} + +func TestRPCResultCacheServerOptionsPropagateFairLimits(t *testing.T) { + sessionBytes := int64(maxOutboundBodyBytes) + s := New(Options{ + RPCGlobalMaxTasks: 6, + RPCResultCacheMaxEntries: 12, + RPCResultCacheMaxBytes: sessionBytes + 2048, + RPCResultCacheAuthMaxEntries: 8, + RPCResultCacheAuthMaxBytes: sessionBytes + 1024, + RPCResultCacheSessionMaxEntries: 4, + RPCResultCacheSessionMaxBytes: sessionBytes, + RPCResultPendingPerAuth: 3, + }) + if s.rpcResults.completedEntries.max != 12 || s.rpcResults.completedBytes.max != sessionBytes+2048 { + t.Fatalf("global option propagation = %d/%d", s.rpcResults.completedEntries.max, s.rpcResults.completedBytes.max) + } + budget := s.rpcResults.fairBudget + if budget.authLimit.entries != 8 || budget.authLimit.bytes != sessionBytes+1024 || + budget.sessionLimit.entries != 4 || budget.sessionLimit.bytes != sessionBytes || budget.pendingPerAuth != 3 { + t.Fatalf("fair option propagation = auth:%#v session:%#v pending:%d", + budget.authLimit, budget.sessionLimit, budget.pendingPerAuth) + } +} + +func TestRPCResultCacheServerOptionsFailFast(t *testing.T) { + base := Options{ + RPCGlobalMaxTasks: 6, + RPCResultCacheMaxEntries: 12, + RPCResultCacheMaxBytes: 64 << 20, + RPCResultCacheAuthMaxEntries: 8, + RPCResultCacheAuthMaxBytes: 32 << 20, + RPCResultCacheSessionMaxEntries: 4, + RPCResultCacheSessionMaxBytes: 16 << 20, + RPCResultPendingPerAuth: 3, + } + tests := []struct { + name string + mutate func(*Options) + }{ + {name: "entry hierarchy", mutate: func(o *Options) { o.RPCResultCacheAuthMaxEntries = 13 }}, + {name: "body does not fit session", mutate: func(o *Options) { o.RPCResultCacheSessionMaxBytes = maxOutboundBodyBytes - 1 }}, + {name: "pending hierarchy", mutate: func(o *Options) { o.RPCResultPendingPerAuth = 7 }}, + } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + opts := base + test.mutate(&opts) + defer func() { + if recover() == nil { + t.Fatal("New accepted invalid rpc_result cache options") + } + }() + _ = New(opts) + }) + } +} + +func rpcResultTestMsgIDForShard( + t *testing.T, + cache *rpcResultCache, + authKeyID [8]byte, + sessionID, start int64, + target uint64, +) int64 { + t.Helper() + for msgID := start; msgID < start+1_000_000; msgID++ { + key := rpcResultCacheKey{authKeyID: authKeyID, sessionID: sessionID, reqMsgID: msgID} + if cache.shardIndex(key) == target { + return msgID + } + } + t.Fatal("failed to find rpc_result key for target shard") + return 0 +} + +func rpcResultTestMsgIDOutsideShard( + t *testing.T, + cache *rpcResultCache, + authKeyID [8]byte, + sessionID, start int64, + excluded uint64, +) int64 { + t.Helper() + for msgID := start; msgID < start+1_000_000; msgID++ { + key := rpcResultCacheKey{authKeyID: authKeyID, sessionID: sessionID, reqMsgID: msgID} + if cache.shardIndex(key) != excluded { + return msgID + } + } + t.Fatal("failed to find rpc_result key outside excluded shard") + return 0 +} + +func rpcResultTestMsgIDOutsideShards( + t *testing.T, + cache *rpcResultCache, + authKeyID [8]byte, + sessionID, start int64, + excluded ...uint64, +) int64 { + t.Helper() + for msgID := start; msgID < start+1_000_000; msgID++ { + key := rpcResultCacheKey{authKeyID: authKeyID, sessionID: sessionID, reqMsgID: msgID} + index := cache.shardIndex(key) + allowed := true + for _, blocked := range excluded { + if index == blocked { + allowed = false + break + } + } + if allowed { + return msgID + } + } + t.Fatal("failed to find rpc_result key outside excluded shards") + return 0 +} diff --git a/internal/mtprotoedge/rpc_result_delivery_test.go b/internal/mtprotoedge/rpc_result_delivery_test.go index 7ba45954..aa694fcf 100644 --- a/internal/mtprotoedge/rpc_result_delivery_test.go +++ b/internal/mtprotoedge/rpc_result_delivery_test.go @@ -8,9 +8,16 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "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" + + appupdates "telesrv/internal/app/updates" + "telesrv/internal/domain" + rpchandler "telesrv/internal/rpc" + "telesrv/internal/store/memory" ) type blockingCloseRPCResultTransport struct { @@ -19,6 +26,60 @@ type blockingCloseRPCResultTransport struct { once sync.Once } +type identifiedRouterHandler struct { + router *rpchandler.Router + userID int64 +} + +type failingRPCResultEncoder struct { + err error +} + +func (e failingRPCResultEncoder) Encode(*bin.Buffer) error { return e.err } + +type encodeFailingIdentifiedRouterHandler struct { + identifiedRouterHandler + err error +} + +func (h encodeFailingIdentifiedRouterHandler) Dispatch(ctx context.Context, authKeyID [8]byte, sessionID int64, b *bin.Buffer) (bin.Encoder, error) { + result, err := h.identifiedRouterHandler.Dispatch(ctx, authKeyID, sessionID, b) + if err != nil { + return nil, err + } + if result == nil { + return nil, nil + } + return failingRPCResultEncoder{err: h.err}, nil +} + +func (h encodeFailingIdentifiedRouterHandler) DispatchWithMethod(ctx context.Context, authKeyID [8]byte, sessionID int64, b *bin.Buffer) (bin.Encoder, string, error) { + result, method, err := h.identifiedRouterHandler.DispatchWithMethod(ctx, authKeyID, sessionID, b) + if err != nil { + return nil, method, err + } + if result == nil { + return nil, method, nil + } + return failingRPCResultEncoder{err: h.err}, method, nil +} + +func (h identifiedRouterHandler) requestContext(ctx context.Context) context.Context { + return rpchandler.WithClientInfo(rpchandler.WithUserID(ctx, h.userID), rpchandler.ClientInfo{Type: rpchandler.ClientTypeTDesktop}) +} + +func (h identifiedRouterHandler) Dispatch(ctx context.Context, authKeyID [8]byte, sessionID int64, b *bin.Buffer) (bin.Encoder, error) { + return h.router.Dispatch(h.requestContext(ctx), authKeyID, sessionID, b) +} + +func (h identifiedRouterHandler) DispatchWithMethod(ctx context.Context, authKeyID [8]byte, sessionID int64, b *bin.Buffer) (bin.Encoder, string, error) { + return h.router.DispatchWithMethod(h.requestContext(ctx), authKeyID, sessionID, b) +} + +func (h identifiedRouterHandler) NegotiatedLayer(authKeyID [8]byte, sessionID int64) (int, bool) { + return h.router.NegotiatedLayer(authKeyID, sessionID) +} + func newBlockingCloseRPCResultTransport() *blockingCloseRPCResultTransport { return &blockingCloseRPCResultTransport{started: make(chan struct{}), release: make(chan struct{})} } @@ -45,7 +106,7 @@ func TestRPCResultCachePublishesOnlyAfterPhysicalWrite(t *testing.T) { } done := make(chan error, 1) go func() { - done <- s.sendResult(context.Background(), c, reqMsgID, &tg.Config{ThisDC: 2}) + done <- s.sendResult(context.Background(), c, reqMsgID, exactTestRPCResult(&tg.Config{ThisDC: 2})) }() select { case <-tr.started: @@ -78,6 +139,217 @@ func TestRPCResultCachePublishesOnlyAfterPhysicalWrite(t *testing.T) { } } +func TestRPCResultPostResponseHookWaitsForPhysicalWrite(t *testing.T) { + tr := newGatedRequiredControlTransport(nil) + s := New(Options{WriteTimeout: time.Second}) + key := newTestAuthKey(t) + c := s.newConn(tr, key, 74006, 1) + legacyCanonicalTestConn(t, c) + t.Cleanup(c.ForceClose) + reqMsgID := proto.NewMessageIDGen(time.Now).New(proto.MessageFromClient) + claim, err := s.rpcResults.Acquire(key.ID, c.sessionID, reqMsgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("initial flight owner = %+v err=%v", claim, err) + } + + delivered := make(chan struct{}) + if err := s.publishRPCResult(c, reqMsgID, "updates.getState", claim.owner, exactTestRPCResult(&tg.UpdatesState{}), func() { + close(delivered) + }); err != nil { + t.Fatalf("publish rpc_result: %v", err) + } + select { + case <-tr.started: + case <-time.After(time.Second): + t.Fatal("rpc_result did not reach physical writer") + } + select { + case <-delivered: + t.Fatal("post-response hook ran while physical writer was blocked") + case <-time.After(20 * time.Millisecond): + } + + tr.unblock() + select { + case <-delivered: + case <-time.After(time.Second): + t.Fatal("post-response hook did not run after physical write") + } +} + +func TestRouterUpdateCursorCommitsOnlyAfterHandleRPCPhysicalWrite(t *testing.T) { + const userID int64 = 1000000301 + events := memory.NewUpdateEventStore() + states := memory.NewUpdateStateStore() + if err := events.Append(context.Background(), userID, domain.UpdateEvent{ + UserID: userID, Type: domain.UpdateEventNewMessage, + Pts: 1, PtsCount: 1, Date: 1700000301, + Message: domain.Message{ID: 1, OwnerUserID: userID}, + }); err != nil { + t.Fatalf("seed update event: %v", err) + } + router := rpchandler.New(rpchandler.Config{}, rpchandler.Deps{ + Updates: appupdates.NewService(states, events), + }, zaptest.NewLogger(t), clock.System) + handler := identifiedRouterHandler{router: router, userID: userID} + tr := newGatedRequiredControlTransport(nil) + s := New(Options{legacyRPC: handler, WriteTimeout: time.Second}) + key := newTestAuthKey(t) + c := s.newConn(tr, key, 74007, 1) + t.Cleanup(c.ForceClose) + reqMsgID := proto.NewMessageIDGen(time.Now).New(proto.MessageFromClient) + claim, err := s.rpcResults.Acquire(key.ID, c.sessionID, reqMsgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("acquire flight = %+v err=%v", claim, err) + } + var request bin.Buffer + if err := (&tg.UpdatesGetStateRequest{}).Encode(&request); err != nil { + t.Fatalf("encode getState: %v", err) + } + handled := make(chan error, 1) + go func() { + handled <- s.handleRPC(context.Background(), c, reqMsgID, "updates.getState", &request, claim.owner) + }() + select { + case <-tr.started: + case <-time.After(time.Second): + t.Fatal("getState rpc_result did not reach physical writer") + } + select { + case err := <-handled: + if err != nil { + t.Fatalf("handleRPC: %v", err) + } + case <-time.After(time.Second): + t.Fatal("handleRPC remained coupled to physical write") + } + if state, found, err := states.Get(context.Background(), key.ID, userID); err != nil || found { + t.Fatalf("confirmed before physical write = %+v/%v err=%v", state, found, err) + } + if state, found := states.ObservedClientState(key.ID, userID); found { + t.Fatalf("observed before physical write = %+v/%v", state, found) + } + + tr.unblock() + deadline := time.Now().Add(time.Second) + for time.Now().Before(deadline) { + confirmed, found, err := states.Get(context.Background(), key.ID, userID) + observed, observedFound := states.ObservedClientState(key.ID, userID) + if err == nil && found && confirmed.Pts == 1 && observedFound && observed.Pts == 1 { + return + } + time.Sleep(time.Millisecond) + } + confirmed, found, err := states.Get(context.Background(), key.ID, userID) + observed, observedFound := states.ObservedClientState(key.ID, userID) + t.Fatalf("post-write cursor = confirmed:%+v/%v err=%v observed:%+v/%v", confirmed, found, err, observed, observedFound) +} + +func TestRouterUpdateCursorDoesNotCommitAfterPhysicalWriteFailure(t *testing.T) { + const userID int64 = 1000000302 + events := memory.NewUpdateEventStore() + states := memory.NewUpdateStateStore() + if err := events.Append(context.Background(), userID, domain.UpdateEvent{ + UserID: userID, Type: domain.UpdateEventNewMessage, + Pts: 1, PtsCount: 1, Date: 1700000302, + Message: domain.Message{ID: 1, OwnerUserID: userID}, + }); err != nil { + t.Fatalf("seed update event: %v", err) + } + router := rpchandler.New(rpchandler.Config{}, rpchandler.Deps{ + Updates: appupdates.NewService(states, events), + }, zaptest.NewLogger(t), clock.System) + tr := &failAfterTransport{} + tr.failAt.Store(1) + s := New(Options{legacyRPC: identifiedRouterHandler{router: router, userID: userID}, WriteTimeout: time.Second}) + key := newTestAuthKey(t) + c := s.newConn(tr, key, 74008, 1) + t.Cleanup(c.ForceClose) + reqMsgID := proto.NewMessageIDGen(time.Now).New(proto.MessageFromClient) + claim, err := s.rpcResults.Acquire(key.ID, c.sessionID, reqMsgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("acquire flight = %+v err=%v", claim, err) + } + var request bin.Buffer + if err := (&tg.UpdatesGetStateRequest{}).Encode(&request); err != nil { + t.Fatalf("encode getState: %v", err) + } + if err := s.handleRPC(context.Background(), c, reqMsgID, "updates.getState", &request, claim.owner); err != nil { + t.Fatalf("handleRPC admission: %v", err) + } + deadline := time.Now().Add(time.Second) + replayable := false + for time.Now().Before(deadline) { + if cached, ok := s.rpcResults.Get(key.ID, c.sessionID, reqMsgID); ok && cached.deliveryState() == rpcResultDeliveryReplayable { + replayable = true + break + } + time.Sleep(time.Millisecond) + } + if !replayable { + t.Fatal("failed physical result did not become replayable") + } + if state, found, err := states.Get(context.Background(), key.ID, userID); err != nil || found { + t.Fatalf("failed write advanced confirmed = %+v/%v err=%v", state, found, err) + } + if state, found := states.ObservedClientState(key.ID, userID); found { + t.Fatalf("failed write advanced observed = %+v/%v", state, found) + } +} + +func TestRouterUpdateCursorDoesNotCommitWhenResultEncodingFails(t *testing.T) { + const userID int64 = 1000000303 + events := memory.NewUpdateEventStore() + states := memory.NewUpdateStateStore() + if err := events.Append(context.Background(), userID, domain.UpdateEvent{ + UserID: userID, Type: domain.UpdateEventNewMessage, + Pts: 1, PtsCount: 1, Date: 1700000303, + Message: domain.Message{ID: 1, OwnerUserID: userID}, + }); err != nil { + t.Fatalf("seed update event: %v", err) + } + router := rpchandler.New(rpchandler.Config{}, rpchandler.Deps{ + Updates: appupdates.NewService(states, events), + }, zaptest.NewLogger(t), clock.System) + handler := encodeFailingIdentifiedRouterHandler{ + identifiedRouterHandler: identifiedRouterHandler{router: router, userID: userID}, + err: errors.New("encode result"), + } + tr := &collectingSessionTransport{} + s := New(Options{legacyRPC: handler, WriteTimeout: time.Second}) + key := newTestAuthKey(t) + c := s.newConn(tr, key, 74009, 1) + t.Cleanup(c.ForceClose) + reqMsgID := proto.NewMessageIDGen(time.Now).New(proto.MessageFromClient) + claim, err := s.rpcResults.Acquire(key.ID, c.sessionID, reqMsgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("acquire flight = %+v err=%v", claim, err) + } + var request bin.Buffer + if err := (&tg.UpdatesGetStateRequest{}).Encode(&request); err != nil { + t.Fatalf("encode getState: %v", err) + } + if err := s.handleRPC(context.Background(), c, reqMsgID, "updates.getState", &request, claim.owner); err != nil { + t.Fatalf("handleRPC encoding fallback: %v", err) + } + deadline := time.Now().Add(time.Second) + for time.Now().Before(deadline) { + if cached, ok := s.rpcResults.Get(key.ID, c.sessionID, reqMsgID); ok && cached.deliveryState() == rpcResultDeliveryDelivered { + break + } + time.Sleep(time.Millisecond) + } + if len(tr.snapshot()) == 0 { + t.Fatal("INTERNAL fallback was not physically delivered") + } + if state, found, err := states.Get(context.Background(), key.ID, userID); err != nil || found { + t.Fatalf("encoding failure advanced confirmed = %+v/%v err=%v", state, found, err) + } + if state, found := states.ObservedClientState(key.ID, userID); found { + t.Fatalf("encoding failure advanced observed = %+v/%v", state, found) + } +} + func TestRPCResultPrewriteFailureFencesConnBeforeCachePublication(t *testing.T) { tr := &collectingSessionTransport{} s := New(Options{WriteTimeout: 20 * time.Millisecond}) @@ -93,7 +365,7 @@ func TestRPCResultPrewriteFailureFencesConnBeforeCachePublication(t *testing.T) t.Fatalf("initial flight owner = %+v err=%v", owner, err) } - err = s.sendResult(context.Background(), c, reqMsgID, &tg.Config{ThisDC: 2}) + err = s.sendResult(context.Background(), c, reqMsgID, exactTestRPCResult(&tg.Config{ThisDC: 2})) if err == nil || (!errors.Is(err, context.DeadlineExceeded) && !errors.Is(err, ErrConnClosed) && !errors.Is(err, ErrOutboundTrackedBudget)) { t.Fatalf("prewrite sendResult error = %v", err) @@ -132,7 +404,7 @@ func TestRPCResultFailureAfterIntentionalTerminalDoesNotCloseTransferLease(t *te // it may publish cache-only, but must not upgrade that intentional fence into // a physical close that makes Transfer fail. oldConn.beginTerminalShutdown() - err = s.sendResult(context.Background(), oldConn, reqMsgID, &tg.Config{ThisDC: 2}) + err = s.sendResult(context.Background(), oldConn, reqMsgID, exactTestRPCResult(&tg.Config{ThisDC: 2})) if !errors.Is(err, ErrOutboundTrackedBudget) { t.Fatalf("late result error = %v, want ErrOutboundTrackedBudget", err) } @@ -171,7 +443,9 @@ func TestRPCResultPublishesBeforePathologicalPhysicalCloseReturns(t *testing.T) } done := make(chan error, 1) - go func() { done <- s.sendResult(context.Background(), c, reqMsgID, &tg.Config{ThisDC: 2}) }() + go func() { + done <- s.sendResult(context.Background(), c, reqMsgID, exactTestRPCResult(&tg.Config{ThisDC: 2})) + }() select { case <-tr.started: case <-time.After(time.Second): diff --git a/internal/mtprotoedge/rpc_result_egress.go b/internal/mtprotoedge/rpc_result_egress.go index 6e89c919..0c96c5da 100644 --- a/internal/mtprotoedge/rpc_result_egress.go +++ b/internal/mtprotoedge/rpc_result_egress.go @@ -2,11 +2,15 @@ package mtprotoedge import ( "context" + "errors" + "log" + "runtime/debug" "strings" "sync" + "sync/atomic" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto" ) const ( @@ -21,30 +25,143 @@ const ( var rpcResultGZIPSlots = make(chan struct{}, rpcResultGZIPConcurrency) -var ( - rpcDeliveryHooksOnce sync.Once - rpcDeliveryHooks chan func() +var defaultRPCDeliveryHookExecutor = newRPCDeliveryHookExecutor(rpcDeliveryHookConcurrency, rpcDeliveryHookQueueSize) + +// ErrRPCDeliveryHookCapacity means an RPC result with a delivery-dependent +// transition cannot reserve reliable executor capacity. The result must not be +// written: its connection is fenced and the immutable result stays replayable. +var ErrRPCDeliveryHookCapacity = errors.New("mtproto rpc delivery hook capacity exhausted") + +type rpcDeliveryHookTicketState uint32 + +const ( + rpcDeliveryHookTicketReserved rpcDeliveryHookTicketState = iota + 1 + rpcDeliveryHookTicketQueued + rpcDeliveryHookTicketReleased + rpcDeliveryHookTicketDone ) -// scheduleRPCDeliveryHook keeps database/update follow-up work off the sole -// socket writer. Hooks are internal, bounded and timeout-aware at registration -// sites; the fixed worker set prevents one delivered result from stalling every -// subsequent frame on that connection. -func scheduleRPCDeliveryHook(fn func()) { - if fn == nil { +type rpcDeliveryHookTicket struct { + executor *rpcDeliveryHookExecutor + state atomic.Uint32 + job rpcDeliveryHookJob +} + +type rpcDeliveryHookJob struct { + next *rpcDeliveryHookJob + ticket *rpcDeliveryHookTicket + fn func() +} + +// rpcDeliveryHookExecutor has process lifetime. Capacity bounds queued plus +// running hooks; every physical write reserves a ticket before admission. A +// successful writer therefore performs only one short O(1) queue append and +// never waits for capacity or hook work. Failed writes release their ticket, +// while the shared logical coordinator remains eligible for a later replay. +type rpcDeliveryHookExecutor struct { + slots chan struct{} + + mu sync.Mutex + cond *sync.Cond + head *rpcDeliveryHookJob + tail *rpcDeliveryHookJob + + panics atomic.Uint64 +} + +func newRPCDeliveryHookExecutor(workers, capacity int) *rpcDeliveryHookExecutor { + if workers <= 0 { + workers = 1 + } + if capacity < workers { + capacity = workers + } + e := &rpcDeliveryHookExecutor{slots: make(chan struct{}, capacity)} + e.cond = sync.NewCond(&e.mu) + for range workers { + go e.run() + } + return e +} + +func (e *rpcDeliveryHookExecutor) reserve() (*rpcDeliveryHookTicket, bool) { + if e == nil { + return nil, false + } + select { + case e.slots <- struct{}{}: + ticket := &rpcDeliveryHookTicket{executor: e} + ticket.state.Store(uint32(rpcDeliveryHookTicketReserved)) + return ticket, true + default: + return nil, false + } +} + +func (t *rpcDeliveryHookTicket) release() { + if t == nil || t.executor == nil || !t.state.CompareAndSwap( + uint32(rpcDeliveryHookTicketReserved), uint32(rpcDeliveryHookTicketReleased), + ) { return } - rpcDeliveryHooksOnce.Do(func() { - rpcDeliveryHooks = make(chan func(), rpcDeliveryHookQueueSize) - for range rpcDeliveryHookConcurrency { - go func() { - for hook := range rpcDeliveryHooks { - hook() - } - }() + <-t.executor.slots +} + +func (t *rpcDeliveryHookTicket) submit(fn func()) bool { + if t == nil || t.executor == nil || fn == nil || !t.state.CompareAndSwap( + uint32(rpcDeliveryHookTicketReserved), uint32(rpcDeliveryHookTicketQueued), + ) { + return false + } + t.job.ticket = t + t.job.fn = fn + t.executor.enqueue(&t.job) + return true +} + +func (e *rpcDeliveryHookExecutor) enqueue(job *rpcDeliveryHookJob) { + e.mu.Lock() + if e.tail == nil { + e.head = job + } else { + e.tail.next = job + } + e.tail = job + e.cond.Signal() + e.mu.Unlock() +} + +func (e *rpcDeliveryHookExecutor) run() { + for { + e.mu.Lock() + for e.head == nil { + e.cond.Wait() } - }) - rpcDeliveryHooks <- fn + job := e.head + e.head = job.next + if e.head == nil { + e.tail = nil + } + job.next = nil + e.mu.Unlock() + e.runOne(job) + } +} + +func (e *rpcDeliveryHookExecutor) runOne(job *rpcDeliveryHookJob) { + defer func() { + if recovered := recover(); recovered != nil { + e.panics.Add(1) + log.Printf("mtprotoedge: rpc delivery hook panic: %v\n%s", recovered, debug.Stack()) + } + if job != nil && job.ticket != nil { + job.ticket.state.Store(uint32(rpcDeliveryHookTicketDone)) + <-e.slots + } + }() + if job != nil && job.fn != nil { + job.fn() + } } // encodeAdaptiveRPCResultInner returns either the original layer-specific TL diff --git a/internal/mtprotoedge/rpc_result_egress_test.go b/internal/mtprotoedge/rpc_result_egress_test.go index cb9e355b..8e7da6fb 100644 --- a/internal/mtprotoedge/rpc_result_egress_test.go +++ b/internal/mtprotoedge/rpc_result_egress_test.go @@ -4,16 +4,17 @@ import ( "bytes" "context" "crypto/rand" + "errors" "io" "sync" "sync/atomic" "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) type opaqueRPCResult struct{ body []byte } @@ -26,9 +27,9 @@ func (o opaqueRPCResult) Encode(b *bin.Buffer) error { func TestEncodeRPCResultUsesAdaptiveGZIP(t *testing.T) { s := New(Options{}) - c := &Conn{metrics: NopMetrics{}} + c := legacyCanonicalTestConn(t, &Conn{metrics: NopMetrics{}}) large := &tg.DataJSON{Data: string(bytes.Repeat([]byte("sticker-metadata-"), 16<<10))} - encoded, err := s.encodeRPCResult(c, 123, large) + encoded, err := s.encodeRPCResult(c, 123, exactTestRPCResult(large)) if err != nil { t.Fatalf("encode compressed rpc_result: %v", err) } @@ -57,12 +58,12 @@ func TestEncodeRPCResultUsesAdaptiveGZIP(t *testing.T) { func TestEncodeRPCResultKeepsIncompressibleBodyRaw(t *testing.T) { s := New(Options{}) - c := &Conn{metrics: NopMetrics{}} + c := legacyCanonicalTestConn(t, &Conn{metrics: NopMetrics{}}) raw := make([]byte, 96<<10) if _, err := rand.Read(raw); err != nil { t.Fatalf("random body: %v", err) } - encoded, err := s.encodeRPCResult(c, 456, opaqueRPCResult{body: raw}) + encoded, err := s.encodeRPCResult(c, 456, exactTestRPCResult(opaqueRPCResult{body: raw})) if err != nil { t.Fatalf("encode incompressible rpc_result: %v", err) } @@ -79,6 +80,349 @@ func TestEncodeRPCResultKeepsIncompressibleBodyRaw(t *testing.T) { } } +func TestEncodeRPCResultReservedChargesBodyBeforeReturning(t *testing.T) { + budget := newOutboundTrackedBudget(1 << 20) + c := legacyCanonicalTestConn(t, &Conn{metrics: NopMetrics{}, outboundTrackedBudget: budget}) + s := New(Options{}) + + encoded, reserved, err := s.encodeRPCResultReservedContext( + context.Background(), c, 789, exactTestRPCResult(&tg.DataJSON{Data: "bounded"}), + ) + if err != nil { + t.Fatalf("encode reserved rpc_result: %v", err) + } + if reserved == nil { + t.Fatal("encode returned no retained-byte reservation") + } + if got, want := budget.used.Load(), int64(len(encoded.body)); got != want { + t.Fatalf("reserved bytes = %d, want encoded body %d", got, want) + } + reserved.release() + if got := budget.used.Load(); got != 0 { + t.Fatalf("reserved bytes after release = %d, want 0", got) + } +} + +func TestEncodeRPCResultReservedDropsBodyOnBudgetTimeout(t *testing.T) { + const maxBytes = 1 << 20 + budget := newOutboundTrackedBudget(maxBytes) + if !budget.reserve(maxBytes) { + t.Fatal("saturate outbound body budget") + } + c := legacyCanonicalTestConn(t, &Conn{metrics: NopMetrics{}, outboundTrackedBudget: budget}) + s := New(Options{}) + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond) + defer cancel() + + encoded, reserved, err := s.encodeRPCResultReservedContext( + ctx, c, 790, exactTestRPCResult(&tg.DataJSON{Data: "must-not-escape"}), + ) + if !errors.Is(err, context.DeadlineExceeded) { + t.Fatalf("saturated reservation error = %v, want deadline exceeded", err) + } + if encoded != nil || reserved != nil { + t.Fatalf("untracked result escaped encode slot: encoded=%p reserved=%p", encoded, reserved) + } + if got := len(outboundEncodeSlots); got != 0 { + t.Fatalf("encode slots retained after timeout = %d, want 0", got) + } + if got := budget.snapshot(); got != maxBytes { + t.Fatalf("primary budget after timeout = %d, want saturated %d", got, maxBytes) + } + budget.release(maxBytes) + if got := budget.snapshot(); got != 0 { + t.Fatalf("primary budget after release = %d, want 0", got) + } +} + +func TestEncodeRPCResultFailedRetentionHandoffDropsBodyInSlot(t *testing.T) { + budget := newOutboundTrackedBudget(1) + if !budget.reserve(1) { + t.Fatal("saturate outbound body budget") + } + c := legacyCanonicalTestConn(t, &Conn{metrics: NopMetrics{}, outboundTrackedBudget: budget}) + s := New(Options{}) + observedInSlot := false + + encoded, reserved, retained, err := s.encodeRPCResultReservedWithHandoffContext( + context.Background(), c, 791, exactTestRPCResult(&tg.DataJSON{Data: "handoff-fails"}), + func(body *encodedOutboundMessage, admissionErr error) error { + observedInSlot = body != nil && len(body.body) > 0 && len(outboundEncodeSlots) > 0 && + errors.Is(admissionErr, ErrOutboundTrackedBudget) + return errors.New("forced retention failure") + }, + ) + if !errors.Is(err, errRPCResultRetentionHandoff) { + t.Fatalf("retention error = %v, want handoff sentinel", err) + } + if !observedInSlot { + t.Fatal("retention handoff did not run while encoded body was slot-confined") + } + if retained || encoded != nil || reserved != nil { + t.Fatalf("failed handoff escaped ownership: retained=%v encoded=%p reserved=%p", retained, encoded, reserved) + } + if got := len(outboundEncodeSlots); got != 0 { + t.Fatalf("encode slots retained after failed handoff = %d, want 0", got) + } + if got := budget.snapshot(); got != 1 { + t.Fatalf("primary budget after failed handoff = %d, want 1", got) + } + budget.release(1) +} + +const saturatedSlotWaveResultData = "exact-business-success" + +type saturatedSlotWaveGate struct { + firstWave int32 + encodes atomic.Int32 + entered chan struct{} + release chan struct{} +} + +type saturatedSlotWaveResult struct{ gate *saturatedSlotWaveGate } + +func (r saturatedSlotWaveResult) Encode(b *bin.Buffer) error { + call := r.gate.encodes.Add(1) + if call <= r.gate.firstWave { + r.gate.entered <- struct{}{} + <-r.gate.release + } + return (&tg.DataJSON{Data: saturatedSlotWaveResultData}).Encode(b) +} + +type saturatedSlotWaveRPC struct { + calls atomic.Int32 + gate *saturatedSlotWaveGate +} + +func (h *saturatedSlotWaveRPC) Dispatch(context.Context, [8]byte, int64, *bin.Buffer) (bin.Encoder, error) { + h.calls.Add(1) + return exactTestRPCResult(saturatedSlotWaveResult{gate: h.gate}), nil +} + +func (*saturatedSlotWaveRPC) NegotiatedLayer([8]byte, int64) (int, bool) { return 227, true } + +func TestPublishRPCResultSaturatedBudgetRetainsExactResultsAcrossSlotWaves(t *testing.T) { + slotCount := cap(outboundEncodeSlots) + requestCount := slotCount*2 + 1 + gate := &saturatedSlotWaveGate{ + firstWave: int32(slotCount), + entered: make(chan struct{}, slotCount), + release: make(chan struct{}), + } + handler := &saturatedSlotWaveRPC{gate: gate} + s := New(Options{legacyRPC: handler}) + now := time.Unix(1_700_000_000, 0) + s.rpcResults = newRPCResultCacheWithFlightLimit(func() time.Time { return now }, requestCount+1) + + const primaryMax = 1 << 20 + primary := newOutboundTrackedBudget(primaryMax) + if !primary.reserve(primaryMax) { + t.Fatal("saturate shared primary outbound budget") + } + + conns := make([]*Conn, requestCount) + tasks := make([]inboundRPC, requestCount) + owners := make([]*rpcResultOwnerLease, requestCount) + reqMsgIDs := make([]int64, requestCount) + requestBody := mustEncodeTL(t, &tg.PhoneGetCallConfigRequest{}) + for i := 0; i < requestCount; i++ { + var authKeyID [8]byte + authKeyID[0] = byte(i + 1) + authKeyID[1] = byte((i + 1) >> 8) + reqMsgID := int64(10_000 + i) + c := &Conn{ + metrics: NopMetrics{}, + writeTimeout: time.Second, + authKeyID: authKeyID, + sessionID: int64(20_000 + i), + outboundTrackedBudget: primary, + } + legacyLayerWireTestConn(t, c, 227) + claim, err := s.rpcResults.Acquire(c.authKeyID, c.sessionID, reqMsgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("acquire request %d = %+v err=%v", i, claim, err) + } + conns[i] = c + owners[i] = claim.owner + reqMsgIDs[i] = reqMsgID + tasks[i] = s.newInboundRPCTask(c, reqMsgID, "phone.getCallConfig", requestBody, claim.owner) + } + + start := make(chan struct{}) + errs := make([]error, requestCount) + var wg sync.WaitGroup + wg.Add(requestCount) + for i := range tasks { + go func(i int) { + defer wg.Done() + <-start + errs[i] = tasks[i].run(context.Background()) + if tasks[i].release != nil { + tasks[i].release() + } + }(i) + } + close(start) + for i := 0; i < slotCount; i++ { + select { + case <-gate.entered: + case <-time.After(time.Second): + close(gate.release) + t.Fatalf("first encode wave entered %d/%d slots; handlers=%d encodes=%d first_err=%v", i, slotCount, handler.calls.Load(), gate.encodes.Load(), errs[0]) + } + } + if got := gate.encodes.Load(); got != int32(slotCount) { + close(gate.release) + t.Fatalf("encodes before releasing first wave = %d, want slot cap %d", got, slotCount) + } + close(gate.release) + done := make(chan struct{}) + go func() { + wg.Wait() + close(done) + }() + select { + case <-done: + case <-time.After(3 * time.Second): + t.Fatal("slot waves did not converge after saturated-budget retention") + } + + if got := handler.calls.Load(); got != int32(requestCount) { + t.Fatalf("business executions = %d, want %d", got, requestCount) + } + if got := gate.encodes.Load(); got != int32(requestCount) { + t.Fatalf("successful result encodes = %d, want %d", got, requestCount) + } + if got := len(outboundEncodeSlots); got != 0 { + t.Fatalf("encode slots after both waves = %d, want 0", got) + } + if got := primary.snapshot(); got != primaryMax { + t.Fatalf("primary budget changed under saturation = %d, want %d", got, primaryMax) + } + + var completedBytes int64 + for i, c := range conns { + if !errors.Is(errs[i], ErrOutboundTrackedBudget) { + t.Fatalf("publish request %d error = %v, want terminal budget saturation", i, errs[i]) + } + if !c.isRetired() { + t.Fatalf("request %d connection was not explicitly fenced", i) + } + if !owners[i].handedOff.Load() { + t.Fatalf("request %d owner was not handed to completed cache", i) + } + cached, ok := s.rpcResults.Get(c.authKeyID, c.sessionID, reqMsgIDs[i]) + if !ok || cached == nil { + t.Fatalf("request %d exact result missing from completed cache", i) + } + completedBytes += int64(len(cached.body)) + var envelope proto.Result + if err := envelope.Decode(&bin.Buffer{Buf: cached.body}); err != nil { + t.Fatalf("decode request %d cached rpc_result: %v", i, err) + } + if envelope.RequestMessageID != reqMsgIDs[i] { + t.Fatalf("request %d cached req_msg_id = %d, want %d", i, envelope.RequestMessageID, reqMsgIDs[i]) + } + var result tg.DataJSON + if err := result.Decode(&bin.Buffer{Buf: envelope.Result}); err != nil { + t.Fatalf("decode request %d exact business result (possibly INTERNAL): %v", i, err) + } + if result.Data != saturatedSlotWaveResultData { + t.Fatalf("request %d cached result = %q, want %q", i, result.Data, saturatedSlotWaveResultData) + } + retry, err := s.rpcResults.Acquire(c.authKeyID, c.sessionID, reqMsgIDs[i]) + if err != nil || retry.state != rpcResultAcquireCompleted || retry.encoded != cached { + t.Fatalf("retry request %d = %+v err=%v, want exact completed result", i, retry, err) + } + } + if got := handler.calls.Load(); got != int32(requestCount) { + t.Fatalf("business executions after retries = %d, want unchanged %d", got, requestCount) + } + if got := s.rpcResults.completedBytes.snapshot(); got != completedBytes { + t.Fatalf("completed-cache charge = %d, want exact retained bytes %d", got, completedBytes) + } + + // Expiry is the completed cache's ownership release point. Force it + // deterministically and prove every retained byte is returned exactly once. + now = now.Add(rpcResultCacheTTL + time.Second) + for i, c := range conns { + if _, ok := s.rpcResults.Get(c.authKeyID, c.sessionID, reqMsgIDs[i]); ok { + t.Fatalf("request %d remained cached after forced expiry", i) + } + } + if got := s.rpcResults.completedBytes.snapshot(); got != 0 { + t.Fatalf("completed-cache bytes after expiry = %d, want 0", got) + } + primary.release(primaryMax) + if got := primary.snapshot(); got != 0 { + t.Fatalf("primary budget after release = %d, want 0", got) + } +} + +func TestCachedReplayRestoreIsSynchronousAndIndependentOfGlobalHookExecutor(t *testing.T) { + // Occupy the entire executor. The replay-state callback must not reserve a + // ticket there: slow auth/store restoration has its own bounded path. + executor := newRPCDeliveryHookExecutor(1, 1) + started := make(chan struct{}) + release := make(chan struct{}) + ticket, ok := executor.reserve() + if !ok || !ticket.submit(func() { + close(started) + <-release + }) { + t.Fatal("occupy delivery hook executor") + } + <-started + oldExecutor := defaultRPCDeliveryHookExecutor + defaultRPCDeliveryHookExecutor = executor + defer func() { + defaultRPCDeliveryHookExecutor = oldExecutor + close(release) + }() + + s := New(Options{WriteTimeout: time.Second}) + transport := &collectingSessionTransport{} + key := newTestAuthKey(t) + c := s.newConn(transport, key, 777, 1) + legacyCanonicalTestConn(t, c) + t.Cleanup(c.ForceClose) + encoded := encodedRPCResultForPriorityTest(9001, 0) + encoded.delivery = newRPCResultDelivery(encoded.reqMsgID) + var restoreOrder atomic.Int32 + encoded.setDeliveryHook(func() { + if !restoreOrder.CompareAndSwap(1, 2) { + panic("logical replay hook did not run after replacement metadata restore") + } + }) + + var restored atomic.Bool + if err := s.sendCachedRPCResultWithHook(context.Background(), c, encoded, func() error { + if got := len(transport.snapshot()); got != 1 { + return errors.New("replay restore ran before physical write") + } + if !restoreOrder.CompareAndSwap(0, 1) { + return errors.New("replacement replay restore ran out of order") + } + restored.Store(true) + return nil + }); err != nil { + t.Fatalf("send cached replay with saturated global executor: %v", err) + } + if !restored.Load() { + t.Fatal("cached replay returned before state restore completed") + } + if got := restoreOrder.Load(); got != 2 { + t.Fatalf("ordered replay restore stage = %d, want replacement then logical hook", got) + } + c.rpcMu.Lock() + pending := c.rpcReplayRestores + c.rpcMu.Unlock() + if pending != 0 { + t.Fatalf("replay restore barriers = %d, want 0", pending) + } +} + func TestBootstrapBarriersAlwaysUseConvergenceLane(t *testing.T) { large := &encodedOutboundMessage{body: make([]byte, bulkOutboundThreshold)} for _, method := range []string{ @@ -144,13 +488,20 @@ func encodedRPCResultForPriorityTest(reqMsgID int64, payloadBytes int) *encodedO if payloadBytes > 0 { b.Put(make([]byte, payloadBytes)) } - return &encodedOutboundMessage{typeID: proto.ResultTypeID, reqMsgID: reqMsgID, body: b.Raw()} + return &encodedOutboundMessage{ + typeID: proto.ResultTypeID, reqMsgID: reqMsgID, body: b.Raw(), + layer: &outboundLayerBinding{ + profile: tg.LayerProfileCanonical, + typ: tg.LayerClassBoolType().Ref(), + kind: outboundLayerBindingRequest, + }, + } } func TestConvergenceResultPassesQueuedBulkAfterBlockedWrite(t *testing.T) { tr := newGatedRecordingTransport() c := newOutboundTestConn(t, tr, newOutboundTrackedBudget(2<<20)) - gate := &encodedOutboundMessage{typeID: tg.UpdatesTooLongTypeID, body: []byte{0x0b, 0xa1, 0x01, 0xe3}} + gate := exactTestUpdatesTooLong(t, c) if err := c.SendBestEffortEncoded(context.Background(), proto.MessageFromServer, gate, 0); err != nil { t.Fatalf("enqueue gate: %v", err) } @@ -270,7 +621,7 @@ func TestRPCResultPipelineExportsPreparationAndDeliveryMetrics(t *testing.T) { t.Fatalf("acquire flight = %+v err=%v", claim, err) } result := &tg.DataJSON{Data: string(bytes.Repeat([]byte("sticker-data"), 12<<10))} - if err := s.publishRPCResult(c, reqMsgID, "updates.getDifference#25939651", claim.owner, result, nil); err != nil { + if err := s.publishRPCResult(c, reqMsgID, "updates.getDifference#25939651", claim.owner, exactTestRPCResult(result), nil); err != nil { t.Fatalf("publish result: %v", err) } select { @@ -293,7 +644,7 @@ func TestRPCResultPipelineExportsPreparationAndDeliveryMetrics(t *testing.T) { func TestWrappedConvergenceMethodDrivesEgressAndReplayPriority(t *testing.T) { metrics := &captureRPCResultMetrics{delivered: make(chan error, 1)} - s := New(Options{RPC: wrappedConvergenceRPC{}, Metrics: metrics}) + s := New(Options{legacyRPC: wrappedConvergenceRPC{}, Metrics: metrics}) c := newOutboundTestConn(t, &failAfterTransport{}, newOutboundTrackedBudget(1<<20)) const reqMsgID = int64(9051) claim, err := s.rpcResults.Acquire(c.authKeyID, c.sessionID, reqMsgID) @@ -302,7 +653,7 @@ func TestWrappedConvergenceMethodDrivesEgressAndReplayPriority(t *testing.T) { } body := mustEncodeTL(t, &tg.HelpGetConfigRequest{}) if err := s.handleRPC(context.Background(), c, reqMsgID, "invokeWithLayer#da9b0d0d", &bin.Buffer{Buf: body}, claim.owner); err != nil { - t.Fatalf("handle wrapped convergence RPC: %v", err) + t.Fatalf("handle wrapped convergence legacyRPC: %v", err) } select { case err := <-metrics.delivered: @@ -336,7 +687,7 @@ func TestWrappedConvergenceMethodDrivesEgressAndReplayPriority(t *testing.T) { } func TestRPCWorkerReleasesAfterEgressAdmissionWhileWriteBlocked(t *testing.T) { - s := New(Options{RPC: immediateLargeRPC{}, WriteTimeout: time.Second}) + s := New(Options{legacyRPC: immediateLargeRPC{}, WriteTimeout: time.Second}) tr := newGatedRecordingTransport() c := newOutboundTestConn(t, tr, newOutboundTrackedBudget(2<<20)) const reqMsgID = int64(9001) @@ -396,7 +747,7 @@ func TestDeliveryHookRunsOnceAfterReplayNotFailedWrite(t *testing.T) { } var hooks atomic.Int32 if err := s.publishRPCResult(oldConn, reqMsgID, "updates.getDifference", claim.owner, - &tg.DataJSON{Data: "difference"}, func() { hooks.Add(1) }); err != nil { + exactTestRPCResult(&tg.DataJSON{Data: "difference"}), func() { hooks.Add(1) }); err != nil { // Admission succeeds; the asynchronous physical failure is observed below. t.Fatalf("publish result: %v", err) } @@ -431,8 +782,12 @@ func TestDeliveryHookRunsOnceAfterReplayNotFailedWrite(t *testing.T) { if got := hooks.Load(); got != 1 { t.Fatalf("delivery hooks after replay = %d, want 1", got) } - if got := cached.deliveryState(); got != rpcResultDeliveryDelivered { - t.Fatalf("replayed delivery state = %d, want delivered", got) + if got := cached.deliveryState(); got != rpcResultDeliveryReplayable { + t.Fatalf("cached representation state = %d, want original replayable attempt", got) + } + if cached.delivery == nil || cached.delivery.coordinator == nil || + cached.delivery.coordinator.hookState() != rpcResultDeliveryHookDone { + t.Fatal("successful replay did not complete shared delivery coordinator") } if err := s.sendCachedRPCResult(context.Background(), replayConn, cached); err != nil { t.Fatalf("second replay: %v", err) diff --git a/internal/mtprotoedge/rpc_result_retention_budget_test.go b/internal/mtprotoedge/rpc_result_retention_budget_test.go new file mode 100644 index 00000000..b00e26a5 --- /dev/null +++ b/internal/mtprotoedge/rpc_result_retention_budget_test.go @@ -0,0 +1,253 @@ +package mtprotoedge + +import ( + "context" + "crypto/rand" + "encoding/binary" + "errors" + "testing" + "time" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/proto" +) + +func TestRPCResultCloneReservationIsOneShotUnderReleaseRace(t *testing.T) { + const iterations = 256 + for i := 0; i < iterations; i++ { + encoded := encodedRPCResultForPriorityTest(int64(i+1), 0) + budget := newOutboundTrackedBudget(int64(len(encoded.body))) + if !budget.reserve(len(encoded.body)) { + t.Fatal("reserve body") + } + reserved := &outboundBodyReservation{budget: budget, bytes: len(encoded.body)} + start := make(chan struct{}) + taken := make(chan outboundOp, 1) + go func() { + <-start + op, _ := reserved.take(encoded) + taken <- op + }() + released := make(chan struct{}) + go func() { + <-start + reserved.release() + close(released) + }() + close(start) + op := <-taken + <-released + op.releaseReservation(budget) + reserved.release() + if got := budget.snapshot(); got != 0 { + t.Fatalf("iteration %d retained bytes = %d, want 0", i, got) + } + } +} + +func TestRPCResultReservationReleaseWinsAdmissionRollback(t *testing.T) { + encoded := encodedRPCResultForPriorityTest(6999, 0) + budget := newOutboundTrackedBudget(int64(len(encoded.body))) + if !budget.reserve(len(encoded.body)) { + t.Fatal("reserve body") + } + reserved := &outboundBodyReservation{budget: budget, bytes: len(encoded.body)} + op, err := reserved.take(encoded) + if err != nil { + t.Fatalf("take reservation: %v", err) + } + // Model a watchdog that retires the queued owner just before queue admission + // rolls the op back. The rollback must observe the release request and return + // the raw op charge instead of resurrecting an owner nobody will release. + reserved.release() + if !reserved.reclaim(&op) { + t.Fatal("reclaim actor reservation") + } + if got := budget.snapshot(); got != 0 { + t.Fatalf("retained bytes after watchdog/rollback race = %d, want 0", got) + } + reserved.release() + op.releaseReservation(budget) +} + +func TestCachedRPCResultReplayUsesPreReservedBodyWithoutDoubleCharge(t *testing.T) { + encoded := encodedRPCResultForPriorityTest(7001, 32<<10) + budget := newOutboundTrackedBudget(int64(len(encoded.body))) + tr := newGatedRecordingTransport() + c := newOutboundTestConn(t, tr, budget) + s := New(Options{WriteTimeout: time.Second}) + + done := make(chan error, 1) + go func() { + done <- s.sendCachedRPCResult(context.Background(), c, encoded) + }() + select { + case <-tr.started: + case <-time.After(time.Second): + t.Fatal("cached replay did not reach the blocked physical write") + } + if got, want := budget.snapshot(), int64(len(encoded.body)); got != want { + t.Fatalf("blocked replay retained bytes = %d, want exactly one body %d", got, want) + } + tr.once.Do(func() { close(tr.release) }) + select { + case err := <-done: + if err != nil { + t.Fatalf("cached replay: %v", err) + } + case <-time.After(time.Second): + t.Fatal("cached replay did not finish") + } + // rpc_result is reliable and remains charged once as resend state until ACK/close. + if got, want := budget.snapshot(), int64(len(encoded.body)); got != want { + t.Fatalf("pending replay retained bytes = %d, want %d", got, want) + } + c.Close() + if got := budget.snapshot(); got != 0 { + t.Fatalf("replay retained bytes after close = %d, want 0", got) + } +} + +func TestQueuedRPCRewrapClonesAreBoundedBeforeAllocation(t *testing.T) { + source := encodedRPCResultForPriorityTest(7101, 64<<10) + perBody := len(source.body) + budget := newOutboundTrackedBudget(int64(2 * perBody)) + c := &Conn{metrics: NopMetrics{}, outboundTrackedBudget: budget} + + first, firstReserved, err := c.cloneRPCResultForRequestReserved(source, 7102, false) + if err != nil || first == nil || firstReserved == nil { + t.Fatalf("first queued clone = %p reservation=%p err=%v", first, firstReserved, err) + } + firstAlias := &rpcRewrapAlias{bodyReservation: firstReserved} + second, secondReserved, err := c.cloneRPCResultForRequestReserved(source, 7103, false) + if err != nil || second == nil || secondReserved == nil { + t.Fatalf("second queued clone = %p reservation=%p err=%v", second, secondReserved, err) + } + secondAlias := &rpcRewrapAlias{bodyReservation: secondReserved} + if got, want := budget.snapshot(), int64(2*perBody); got != want { + t.Fatalf("two queued aliases retained bytes = %d, want %d", got, want) + } + third, thirdReserved, err := c.cloneRPCResultForRequestReserved(source, 7104, false) + if !errors.Is(err, ErrOutboundTrackedBudget) || third != nil || thirdReserved != nil { + t.Fatalf("third queued clone = %p reservation=%p err=%v, want pre-allocation budget rejection", third, thirdReserved, err) + } + if got, want := budget.snapshot(), int64(2*perBody); got != want { + t.Fatalf("budget changed after rejected clone = %d, want %d", got, want) + } + firstAlias.finishReplayRestoreWithoutDelivery() + secondAlias.finishReplayRestoreWithoutDelivery() + if got := budget.snapshot(); got != 0 { + t.Fatalf("queued alias bytes after terminal release = %d, want 0", got) + } +} + +func TestOutboundActorRetargetRequiresSecondBodyReservation(t *testing.T) { + const ( + oldReqID = int64(7201) + newReqID = int64(7202) + ) + encoded := encodedRPCResultForPriorityTest(oldReqID, 32<<10) + encoded.delivery = newRPCResultDelivery(oldReqID) + encoded.markQueued() + if !encoded.tryRetarget(newReqID) { + t.Fatal("retarget prepared rpc_result") + } + budget := newOutboundTrackedBudget(int64(len(encoded.body))) + if !budget.reserve(len(encoded.body)) { + t.Fatal("reserve original queued body") + } + tr := &failAfterTransport{} + c := newOutboundTestConn(t, tr, budget) + state := newOutboundState(budget) + var terminalErr error + var terminalBytes int64 + c.handleOutboundSend(state, outboundOp{ + kind: outboundSend, + ctx: context.Background(), + msgType: proto.MessageServerResponse, + encoded: encoded, + reservedBytes: len(encoded.body), + reservationBudget: budget, + enqueuedAt: time.Now(), + terminal: func(err error) { + terminalErr = err + terminalBytes = budget.snapshot() + }, + }) + if !errors.Is(terminalErr, ErrOutboundTrackedBudget) { + t.Fatalf("retarget terminal error = %v, want %v", terminalErr, ErrOutboundTrackedBudget) + } + if terminalBytes != int64(len(encoded.body)) { + t.Fatalf("bytes visible to terminal = %d, want original body %d retained", terminalBytes, len(encoded.body)) + } + if got := tr.sends.Load(); got != 0 { + t.Fatalf("retarget under one-body budget wrote %d frames, want 0", got) + } + if got := int64(binary.LittleEndian.Uint64(encoded.body[4:12])); got != oldReqID { + t.Fatalf("source req_msg_id mutated to %d before second-body admission", got) + } + if got := budget.snapshot(); got != 0 { + t.Fatalf("retarget bytes after terminal = %d, want 0", got) + } +} + +func TestOutboundActorRetargetTransfersOnlyReplacementToPending(t *testing.T) { + const ( + oldReqID = int64(7301) + newReqID = int64(7302) + ) + encoded := encodedRPCResultForPriorityTest(oldReqID, 32<<10) + encoded.delivery = newRPCResultDelivery(oldReqID) + encoded.markQueued() + if !encoded.tryRetarget(newReqID) { + t.Fatal("retarget prepared rpc_result") + } + perBody := len(encoded.body) + budget := newOutboundTrackedBudget(int64(2 * perBody)) + if !budget.reserve(perBody) { + t.Fatal("reserve original queued body") + } + tr := &failAfterTransport{} + c := newOutboundTestConn(t, tr, budget) + state := newOutboundState(budget) + var terminalErr error + var terminalBytes int64 + c.handleOutboundSend(state, outboundOp{ + kind: outboundSend, + ctx: context.Background(), + msgType: proto.MessageServerResponse, + encoded: encoded, + reservedBytes: perBody, + reservationBudget: budget, + enqueuedAt: time.Now(), + terminal: func(err error) { + terminalErr = err + terminalBytes = budget.snapshot() + }, + }) + if terminalErr != nil { + t.Fatalf("retarget terminal error: %v", terminalErr) + } + if terminalBytes != int64(2*perBody) { + t.Fatalf("bytes visible to terminal = %d, want original+replacement %d", terminalBytes, 2*perBody) + } + if got := budget.snapshot(); got != int64(perBody) { + t.Fatalf("bytes after terminal = %d, want one pending replacement %d", got, perBody) + } + data, err := crypto.NewClientCipher(rand.Reader).DecryptFromBuffer(c.key, &bin.Buffer{Buf: tr.lastFrame()}) + if err != nil { + t.Fatalf("decrypt retargeted frame: %v", err) + } + var result proto.Result + if err := result.Decode(&bin.Buffer{Buf: append([]byte(nil), data.Data()...)}); err != nil { + t.Fatalf("decode retargeted rpc_result: %v", err) + } + if result.RequestMessageID != newReqID { + t.Fatalf("wire req_msg_id = %d, want %d", result.RequestMessageID, newReqID) + } + state.releaseAll() + if got := budget.snapshot(); got != 0 { + t.Fatalf("retarget bytes after pending release = %d, want 0", got) + } +} diff --git a/internal/mtprotoedge/rpc_result_subscriber_budget.go b/internal/mtprotoedge/rpc_result_subscriber_budget.go new file mode 100644 index 00000000..e24ee513 --- /dev/null +++ b/internal/mtprotoedge/rpc_result_subscriber_budget.go @@ -0,0 +1,149 @@ +package mtprotoedge + +import ( + "encoding/binary" + "hash/maphash" + "sync" +) + +const ( + rpcResultSubscriberMaxGlobal = 1 << 16 + rpcResultSubscriberMaxAuth = 1 << 13 + rpcResultSubscriberMaxSession = 1 << 11 + rpcResultSubscriberMaxPerFlight = 1 << 7 +) + +type rpcResultSubscriberBudgetShard[K comparable] struct { + mu sync.Mutex + usage map[K]int64 +} + +// rpcResultSubscriberBudget bounds callbacks retained by pending replay +// flights independently from owner/result bytes. A duplicate does not reserve a +// new result row, so charging only unique owners would otherwise leave an +// unbounded same-msg-id reconnect path. +type rpcResultSubscriberBudget struct { + seed maphash.Seed + global rpcResultFlightLimit + authLimit int64 + sessionLimit int64 + authShards [rpcResultBudgetShards]rpcResultSubscriberBudgetShard[[8]byte] + sessionShards [rpcResultBudgetShards]rpcResultSubscriberBudgetShard[rpcResultSessionBudgetKey] +} + +func newRPCResultSubscriberBudget( + seed maphash.Seed, + globalLimit, authLimit, sessionLimit int, +) *rpcResultSubscriberBudget { + b := &rpcResultSubscriberBudget{ + seed: seed, + authLimit: int64(authLimit), + sessionLimit: int64(sessionLimit), + } + b.global.max = int64(globalLimit) + for i := range b.authShards { + b.authShards[i].usage = make(map[[8]byte]int64) + b.sessionShards[i].usage = make(map[rpcResultSessionBudgetKey]int64) + } + return b +} + +func (b *rpcResultSubscriberBudget) reserve(key rpcResultCacheKey, slots int) bool { + if b == nil || slots <= 0 { + return false + } + authShard := b.authShard(key.authKeyID) + sessionKey := rpcResultSessionBudgetKey{authKeyID: key.authKeyID, sessionID: key.sessionID} + sessionShard := b.sessionShard(sessionKey) + delta := int64(slots) + authShard.mu.Lock() + sessionShard.mu.Lock() + authUsed := authShard.usage[key.authKeyID] + sessionUsed := sessionShard.usage[sessionKey] + if !withinRPCResultBudget(authUsed, delta, b.authLimit) || + !withinRPCResultBudget(sessionUsed, delta, b.sessionLimit) || + !b.global.reserveN(delta) { + sessionShard.mu.Unlock() + authShard.mu.Unlock() + return false + } + authShard.usage[key.authKeyID] = authUsed + delta + sessionShard.usage[sessionKey] = sessionUsed + delta + sessionShard.mu.Unlock() + authShard.mu.Unlock() + return true +} + +func (b *rpcResultSubscriberBudget) release(key rpcResultCacheKey, slots int) { + if b == nil || slots <= 0 { + panic("mtproto rpc result subscriber release must be positive") + } + authShard := b.authShard(key.authKeyID) + sessionKey := rpcResultSessionBudgetKey{authKeyID: key.authKeyID, sessionID: key.sessionID} + sessionShard := b.sessionShard(sessionKey) + delta := int64(slots) + authShard.mu.Lock() + sessionShard.mu.Lock() + authUsed, authOK := authShard.usage[key.authKeyID] + sessionUsed, sessionOK := sessionShard.usage[sessionKey] + if !authOK || !sessionOK || authUsed < delta || sessionUsed < delta { + sessionShard.mu.Unlock() + authShard.mu.Unlock() + panic("mtproto rpc result subscriber budget underflow") + } + authUsed -= delta + sessionUsed -= delta + if authUsed == 0 { + delete(authShard.usage, key.authKeyID) + } else { + authShard.usage[key.authKeyID] = authUsed + } + if sessionUsed == 0 { + delete(sessionShard.usage, sessionKey) + } else { + sessionShard.usage[sessionKey] = sessionUsed + } + b.global.releaseN(delta) + sessionShard.mu.Unlock() + authShard.mu.Unlock() +} + +func (b *rpcResultSubscriberBudget) authSnapshot(authKeyID [8]byte) int64 { + if b == nil { + return 0 + } + shard := b.authShard(authKeyID) + shard.mu.Lock() + used := shard.usage[authKeyID] + shard.mu.Unlock() + return used +} + +func (b *rpcResultSubscriberBudget) sessionSnapshot(authKeyID [8]byte, sessionID int64) int64 { + if b == nil { + return 0 + } + key := rpcResultSessionBudgetKey{authKeyID: authKeyID, sessionID: sessionID} + shard := b.sessionShard(key) + shard.mu.Lock() + used := shard.usage[key] + shard.mu.Unlock() + return used +} + +func (b *rpcResultSubscriberBudget) authShard( + authKeyID [8]byte, +) *rpcResultSubscriberBudgetShard[[8]byte] { + index := maphash.Bytes(b.seed, authKeyID[:]) & (rpcResultBudgetShards - 1) + return &b.authShards[index] +} + +func (b *rpcResultSubscriberBudget) sessionShard( + key rpcResultSessionBudgetKey, +) *rpcResultSubscriberBudgetShard[rpcResultSessionBudgetKey] { + var raw [16]byte + copy(raw[:8], key.authKeyID[:]) + binary.LittleEndian.PutUint64(raw[8:], uint64(key.sessionID)) + index := maphash.Bytes(b.seed, raw[:]) & (rpcResultBudgetShards - 1) + return &b.sessionShards[index] +} diff --git a/internal/mtprotoedge/rpc_rewrap.go b/internal/mtprotoedge/rpc_rewrap.go index 2b5d89c2..4c93e166 100644 --- a/internal/mtprotoedge/rpc_rewrap.go +++ b/internal/mtprotoedge/rpc_rewrap.go @@ -3,15 +3,18 @@ package mtprotoedge import ( "context" "crypto/sha256" + "fmt" + "log" + "runtime/debug" "sync" "sync/atomic" "time" "go.uber.org/zap" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) // rpcRewrapRegistry links only an explicit official-client transition: @@ -37,6 +40,9 @@ type rpcRewrapSessionKey struct { type rpcRewrapKey struct { rpcRewrapSessionKey fingerprint [sha256.Size]byte + semantic tg.LayerSemanticRequestIdentity + call tg.LayerCallIdentity + exact bool } type rpcRewrapRequestKey struct { @@ -102,6 +108,59 @@ func (r *rpcRewrapRegistry) register(c *Conn, body []byte, reqMsgID int64, metho return true } +func (r *rpcRewrapRegistry) registerSemantic( + c *Conn, + identity tg.LayerSemanticRequestIdentity, + call tg.LayerCallIdentity, + reqMsgID int64, + method string, + owner *rpcResultOwnerLease, +) bool { + if identity.Method() == 0 || identity.CanonicalSize() <= 0 { + return false + } + return r.registerKey(c, rpcRewrapKey{ + rpcRewrapSessionKey: rpcRewrapSessionKey{authKeyID: c.authKeyID, sessionID: c.sessionID}, + semantic: identity, + call: call, + exact: true, + }, reqMsgID, method, owner) +} + +func (r *rpcRewrapRegistry) registerKey(c *Conn, key rpcRewrapKey, reqMsgID int64, method string, owner *rpcResultOwnerLease) bool { + if r == nil || c == nil || c.rpcRewrapInitialized.Load() || owner == nil { + return false + } + candidate := &rpcRewrapCandidate{ + active: true, key: key, source: c, reqMsgID: reqMsgID, method: method, + owner: owner, waiter: owner.Waiter(), + } + if candidate.waiter == nil { + return false + } + session := key.rpcRewrapSessionKey + r.mu.Lock() + if r.total >= r.max { + r.mu.Unlock() + return false + } + r.byKey[key] = append(r.byKey[key], candidate) + set := r.bySession[session] + if set == nil { + set = make(map[*rpcRewrapCandidate]struct{}) + r.bySession[session] = set + } + set[candidate] = struct{}{} + r.byRequest[rpcRewrapRequestKey{rpcRewrapSessionKey: session, reqMsgID: reqMsgID}] = candidate + r.total++ + r.mu.Unlock() + if !owner.InstallAbortHook(func() { r.remove(candidate) }) { + r.remove(candidate) + return false + } + return true +} + func (r *rpcRewrapRegistry) claim(c *Conn, inner []byte) *rpcRewrapCandidate { if r == nil || c == nil { return nil @@ -122,6 +181,37 @@ func (r *rpcRewrapRegistry) claim(c *Conn, inner []byte) *rpcRewrapCandidate { return nil } +func (r *rpcRewrapRegistry) claimSemantic( + c *Conn, + identity tg.LayerSemanticRequestIdentity, + call tg.LayerCallIdentity, +) *rpcRewrapCandidate { + if r == nil || c == nil || identity.Method() == 0 || identity.CanonicalSize() <= 0 { + return nil + } + return r.claimKey(rpcRewrapKey{ + rpcRewrapSessionKey: rpcRewrapSessionKey{authKeyID: c.authKeyID, sessionID: c.sessionID}, + semantic: identity, + call: call, + exact: true, + }) +} + +func (r *rpcRewrapRegistry) claimKey(key rpcRewrapKey) *rpcRewrapCandidate { + r.mu.Lock() + queue := r.byKey[key] + for _, candidate := range queue { + if !candidate.active || candidate.claimed { + continue + } + candidate.claimed = true + r.mu.Unlock() + return candidate + } + r.mu.Unlock() + return nil +} + func (r *rpcRewrapRegistry) commit(candidate *rpcRewrapCandidate) { if r == nil || candidate == nil { return @@ -276,107 +366,636 @@ func decodeRPCRewrapInit(body []byte) (rpcRewrapInit, bool) { } type rpcRewrapAlias struct { - conn *Conn - newReqID int64 - method string - oldWaiter *rpcResultWaiter - newOwner *rpcResultOwnerLease - sourceConn *Conn - sourceOwner *rpcResultOwnerLease - retargeted atomic.Bool - observeInit bool - init rpcRewrapInit - candidate *rpcRewrapCandidate - registry *rpcRewrapRegistry + conn *Conn + itemIndex int + newReqID int64 + method string + oldWaiter *rpcResultWaiter + newOwner *rpcResultOwnerLease + sourceConn *Conn + sourceOwner *rpcResultOwnerLease + retargeted atomic.Bool + observeInit bool + init rpcRewrapInit + candidate *rpcRewrapCandidate + registry *rpcRewrapRegistry + afterSuccessfulDelivery func() error + finishReplayRestore func() + afterOnce sync.Once + deliveredFinalizeOnce sync.Once + deliveredFinalizeErr error + resultStoreClaimed atomic.Bool + executionOK atomic.Bool + // bodyReservation pins the replay/retarget clone from before allocation + // through queue residence. It is concurrency-safe because the watchdog and + // outbound actor race to release or take the same one-shot ownership token. + bodyReservation *outboundBodyReservation +} + +func (a *rpcRewrapAlias) beginReplayRestore() { + if a == nil || a.conn == nil || a.finishReplayRestore != nil { + return + } + a.finishReplayRestore = a.conn.beginRPCReplayRestore() +} + +func (a *rpcRewrapAlias) runAfterSuccessfulDelivery() (err error) { + if a == nil || a.afterSuccessfulDelivery == nil { + return nil + } + a.afterOnce.Do(func() { + if a.executionOK.Load() { + err = a.afterSuccessfulDelivery() + } + }) + return err +} + +func (a *rpcRewrapAlias) finishReplayRestoreWithoutDelivery() { + if a == nil { + return + } + a.releaseBodyReservation() + // Win or wait for any concurrent callback before dropping the barrier. + a.afterOnce.Do(func() {}) + a.releaseReplayRestoreBarrier() +} + +func (a *rpcRewrapAlias) releaseBodyReservation() { + if a != nil && a.bodyReservation != nil { + a.bodyReservation.release() + } +} + +func (a *rpcRewrapAlias) releaseReplayRestoreBarrier() { + if a != nil && a.finishReplayRestore != nil { + a.finishReplayRestore() + } +} + +func (a *rpcRewrapAlias) releaseDeferredLogicalHook() { + if a == nil || a.sourceOwner == nil || a.sourceOwner.Delivery() == nil || + a.sourceOwner.Delivery().coordinator == nil { + return + } + a.sourceOwner.Delivery().coordinator.releaseDeferredHook() +} + +func (a *rpcRewrapAlias) storeResultOnce(s *Server, encoded *encodedOutboundMessage) { + if a == nil || s == nil || encoded == nil || !a.resultStoreClaimed.CompareAndSwap(false, true) { + return + } + s.storeRPCResult(a.conn, a.newReqID, encoded) +} + +func claimRPCRewrapLogicalHook( + ctx context.Context, + encoded *encodedOutboundMessage, +) (*rpcResultDeliveryHookClaim, error) { + if encoded == nil { + return nil, nil + } + // Only this alias is allowed to consume a sticky TryRetarget deferral. If a + // late physical success races another replacement replay, the coordinator + // waits for its Claimed/InProgress hook to publish Done. + return encoded.claimLogicalDeliveryHook(ctx, true) +} + +// completeDeliveredRPCRewrapResult is safe after a watchdog has already fenced +// this physical generation. The caller has independent proof that the +// retargeted bytes reached the stream; deliveredFinalizeOnce, the shared hook +// coordinator and cache publication make late/concurrent invocations converge +// while preserving replacement -> logical -> cache -> barrier order. +func (s *Server) completeDeliveredRPCRewrapResult( + ctx context.Context, + a *rpcRewrapAlias, + encoded *encodedOutboundMessage, + source string, +) error { + if s == nil || a == nil || encoded == nil { + return ErrRPCResultFlightInvalid + } + a.deliveredFinalizeOnce.Do(func() { + defer a.releaseBodyReservation() + defer a.releaseReplayRestoreBarrier() + restoreCtx, cancel := boundedRPCReplayRestoreContext(ctx) + defer cancel() + logical, claimErr := claimRPCRewrapLogicalHook(restoreCtx, encoded) + encoded.markDelivered() + if claimErr != nil { + a.conn.fenceUndeliveredRPCResult() + a.deliveredFinalizeErr = fmt.Errorf("wait for rewrapped rpc_result logical restore: %w", claimErr) + a.storeResultOnce(s, encoded) + return + } + a.deliveredFinalizeErr = s.runBoundedRPCReplayRestore( + restoreCtx, a.conn, source, logical, a.runAfterSuccessfulDelivery, + ) + a.storeResultOnce(s, encoded) + }) + return a.deliveredFinalizeErr } var ( - rpcRewrapDeliveryOnce sync.Once - rpcRewrapDeliveryJobs chan func() + rpcRewrapDeliveryOnce sync.Once + rpcRewrapDeliveryJobs chan rpcRewrapDeliveryJob + rpcRewrapObservationOnce sync.Once + rpcRewrapObservationJobs chan rpcRewrapDeliveryJob ) const ( rpcRewrapDeliveryWorkers = 4 rpcRewrapDeliveryQueue = 256 + rpcRewrapObserverWorkers = 1 + rpcRewrapObserverQueue = 64 + // Queue residence, physical delivery and ordered restore share one absolute + // deadline. An admitted alias must never retain a Conn scheduler barrier for + // minutes behind older slow jobs. + rpcRewrapDeliveryQueueTimeout = 5 * time.Second ) -func scheduleRPCRewrapDelivery(fn func()) bool { - if fn == nil { +type rpcRewrapDeliveryJob struct { + run func(*rpcRewrapDeliveryControl, time.Time) + fail func(error) + deadline time.Time + control *rpcRewrapDeliveryControl +} + +type rpcRewrapDeliveryJobState uint32 + +const ( + rpcRewrapJobPending rpcRewrapDeliveryJobState = iota + rpcRewrapJobRunning + rpcRewrapJobCommitted + rpcRewrapJobComplete + rpcRewrapJobFailed +) + +// rpcRewrapDeliveryControl lets an independent deadline timer retire queued, +// running and physically committed jobs. A late worker cannot enter run after +// the timer wins; a committed non-cooperative restore is fenced by fail, and +// its eventual return cannot report failure or finish the barrier a second time. +type rpcRewrapDeliveryControl struct { + state atomic.Uint32 + timerMu sync.Mutex + timer *time.Timer +} + +type rpcRewrapPhysicalOutcome struct { + err error + owned bool +} + +// waitRPCRewrapPhysicalTerminal deliberately keeps one of the four bounded +// workers attached to an in-progress actor write even after the watchdog fences +// the Conn. A broken transport may therefore strand at most four workers, while +// queued jobs still time out independently. If that transport later reports +// success, the worker cannot lose the logical hook merely because timeout won +// before its goroutine resumed. +func waitRPCRewrapPhysicalTerminal( + c *Conn, + ctx context.Context, + encoded *encodedOutboundMessage, + reserved *outboundBodyReservation, + control *rpcRewrapDeliveryControl, +) rpcRewrapPhysicalOutcome { + terminal := make(chan rpcRewrapPhysicalOutcome, 1) + _ = c.sendOutboundWithTerminalReserved( + ctx, proto.MessageServerResponse, nil, encoded, false, + func(err error) { + terminal <- rpcRewrapPhysicalOutcome{err: err, owned: control.commit()} + }, + reserved, + ) + return <-terminal +} + +func newRPCRewrapDeliveryControl() *rpcRewrapDeliveryControl { + c := &rpcRewrapDeliveryControl{} + c.state.Store(uint32(rpcRewrapJobPending)) + return c +} + +func (c *rpcRewrapDeliveryControl) transition(from, to rpcRewrapDeliveryJobState) bool { + return c != nil && c.state.CompareAndSwap(uint32(from), uint32(to)) +} + +func (c *rpcRewrapDeliveryControl) fail() bool { + if c == nil { + return true + } + for { + state := rpcRewrapDeliveryJobState(c.state.Load()) + if state == rpcRewrapJobComplete || state == rpcRewrapJobFailed { + return false + } + if c.transition(state, rpcRewrapJobFailed) { + c.stopTimer() + return true + } + } +} + +func (c *rpcRewrapDeliveryControl) timeout() bool { + if c == nil { + return true + } + for { + state := rpcRewrapDeliveryJobState(c.state.Load()) + if state != rpcRewrapJobPending && state != rpcRewrapJobRunning && + state != rpcRewrapJobCommitted { + return false + } + if c.transition(state, rpcRewrapJobFailed) { + c.stopTimer() + return true + } + } +} + +// commit records successful physical delivery (or an already-proven retarget) +// without disarming the watchdog. The same absolute deadline covers the +// replacement/logical restore and cache/barrier terminal path; complete is the +// only successful transition that stops the timer. +func (c *rpcRewrapDeliveryControl) commit() bool { + if c == nil || !c.transition(rpcRewrapJobRunning, rpcRewrapJobCommitted) { return false } - rpcRewrapDeliveryOnce.Do(func() { - rpcRewrapDeliveryJobs = make(chan func(), rpcRewrapDeliveryQueue) - for range rpcRewrapDeliveryWorkers { + return true +} + +func (c *rpcRewrapDeliveryControl) running() bool { + return c != nil && rpcRewrapDeliveryJobState(c.state.Load()) == rpcRewrapJobRunning +} + +func (c *rpcRewrapDeliveryControl) complete() { + if c == nil { + return + } + for { + state := rpcRewrapDeliveryJobState(c.state.Load()) + if state != rpcRewrapJobRunning && state != rpcRewrapJobCommitted { + return + } + if c.transition(state, rpcRewrapJobComplete) { + c.stopTimer() + return + } + } +} + +func (c *rpcRewrapDeliveryControl) installTimer(timer *time.Timer) { + if c == nil || timer == nil { + return + } + c.timerMu.Lock() + c.timer = timer + state := rpcRewrapDeliveryJobState(c.state.Load()) + terminal := state == rpcRewrapJobComplete || state == rpcRewrapJobFailed + c.timerMu.Unlock() + if terminal { + timer.Stop() + } +} + +func (c *rpcRewrapDeliveryControl) stopTimer() { + if c == nil { + return + } + c.timerMu.Lock() + timer := c.timer + c.timer = nil + c.timerMu.Unlock() + if timer != nil { + timer.Stop() + } +} + +func (j rpcRewrapDeliveryJob) reportFailure(err error) { + if err == nil { + err = fmt.Errorf("rpc rewrap delivery job failed") + } + defer func() { + if recovered := recover(); recovered != nil { + log.Printf("mtprotoedge: rpc rewrap delivery failure callback panicked: %v\n%s", recovered, debug.Stack()) + } + }() + if j.fail != nil { + j.fail(err) + return + } + log.Printf("mtprotoedge: rpc rewrap delivery job failed: %v", err) +} + +func runRPCRewrapDeliveryJob(j rpcRewrapDeliveryJob) { + if j.run == nil { + j.reportFailure(fmt.Errorf("nil rpc rewrap delivery job")) + return + } + control := j.control + if control == nil { + control = newRPCRewrapDeliveryControl() + } + if !control.transition(rpcRewrapJobPending, rpcRewrapJobRunning) { + return + } + if !j.deadline.IsZero() && !time.Now().Before(j.deadline) { + if control.fail() { + j.reportFailure(context.DeadlineExceeded) + } + return + } + defer func() { + if recovered := recover(); recovered != nil { + if control.fail() { + j.reportFailure(fmt.Errorf("rpc rewrap delivery panic: %v", recovered)) + } + log.Printf("mtprotoedge: rpc rewrap delivery job panicked: %v\n%s", recovered, debug.Stack()) + return + } + control.complete() + }() + j.run(control, j.deadline) +} + +func scheduleRPCRewrapJob( + job rpcRewrapDeliveryJob, + once *sync.Once, + jobs *chan rpcRewrapDeliveryJob, + workers, queue int, +) bool { + if job.run == nil { + return false + } + if job.deadline.IsZero() { + job.deadline = time.Now().Add(rpcRewrapDeliveryQueueTimeout) + } + job.control = newRPCRewrapDeliveryControl() + once.Do(func() { + *jobs = make(chan rpcRewrapDeliveryJob, queue) + for range workers { go func() { - for job := range rpcRewrapDeliveryJobs { - job() + for job := range *jobs { + runRPCRewrapDeliveryJob(job) } }() } }) + delay := time.Until(job.deadline) + if delay < 0 { + delay = 0 + } + timer := time.AfterFunc(delay, func() { + if job.control.timeout() { + job.reportFailure(context.DeadlineExceeded) + } + }) + job.control.installTimer(timer) select { - case rpcRewrapDeliveryJobs <- fn: + case *jobs <- job: return true default: + // If the independent timer already won, it owns the fail callback and the + // caller must not report queue failure a second time. + if job.control.transition(rpcRewrapJobPending, rpcRewrapJobComplete) { + job.control.stopTimer() + return false + } + return true + } +} + +func scheduleRPCRewrapDeliveryJob(job rpcRewrapDeliveryJob) bool { + return scheduleRPCRewrapJob(job, &rpcRewrapDeliveryOnce, &rpcRewrapDeliveryJobs, + rpcRewrapDeliveryWorkers, rpcRewrapDeliveryQueue) +} + +func scheduleRPCRewrapObservation(fn func()) bool { + if fn == nil { return false } + return scheduleRPCRewrapJob(rpcRewrapDeliveryJob{ + deadline: time.Now().Add(rpcRewrapDeliveryQueueTimeout), + run: func(*rpcRewrapDeliveryControl, time.Time) { fn() }, + }, &rpcRewrapObservationOnce, &rpcRewrapObservationJobs, + rpcRewrapObserverWorkers, rpcRewrapObserverQueue) +} + +func (s *Server) rpcRewrapRestoreJob( + a *rpcRewrapAlias, + source string, + run func(*rpcRewrapDeliveryControl, time.Time), +) rpcRewrapDeliveryJob { + return rpcRewrapDeliveryJob{ + deadline: time.Now().Add(rpcRewrapDeliveryQueueTimeout), + run: run, + fail: func(err error) { + if a != nil && a.conn != nil { + a.conn.fenceUndeliveredRPCResult() + } + if a != nil { + a.releaseBodyReservation() + a.releaseReplayRestoreBarrier() + } + if s != nil && s.log != nil { + s.log.Warn("RPC rewrap delivery job failed", + zap.String("source", source), zap.Error(err)) + } + }, + } +} + +func (s *Server) failRPCRewrapResultJob( + a *rpcRewrapAlias, + encoded *encodedOutboundMessage, + err error, +) { + if a != nil { + defer a.releaseBodyReservation() + } + if a == nil || a.conn == nil || a.newOwner == nil || encoded == nil { + return + } + a.conn.fenceUndeliveredRPCResult() + publish := a.newOwner.HandOff() + encoded.markReplayable() + encoded.releaseDeferredLogicalDeliveryHook() + // Release the connection-local scheduler before any defensive cache panic; + // the physical generation is already fenced, so no following task can run. + a.releaseReplayRestoreBarrier() + if publish { + a.storeResultOnce(s, encoded) + } + if s != nil && s.log != nil { + s.log.Warn("RPC rewrap result job failed; exact result retained", + zap.String("method", a.method), zap.Int64("req_msg_id", a.newReqID), zap.Error(err)) + } } func (a *rpcRewrapAlias) activate(s *Server) error { if a == nil || s == nil || a.conn == nil || a.oldWaiter == nil { return ErrRPCResultFlightInvalid } - err := a.oldWaiter.Subscribe(func(encoded *encodedOutboundMessage, ok bool) { + // Install the scheduler barrier synchronously, before this plan publishes + // any following naked RPC tasks. The asynchronous physical replay below is + // then free to use a bounded rewrap worker without an ordering race. + a.beginReplayRestore() + var executionSubscriber func(bool) + if a.newOwner != nil || a.afterSuccessfulDelivery != nil { + executionSubscriber = func(success bool) { + a.executionOK.Store(success) + if a.newOwner != nil { + a.newOwner.CompleteExecution(success) + } + } + } + resultSubscriber := func(encoded *encodedOutboundMessage, ok bool) { if !ok || encoded == nil { if a.newOwner != nil { a.newOwner.Abort() } a.conn.fenceUndeliveredRPCResult() + a.releaseDeferredLogicalHook() + a.finishReplayRestoreWithoutDelivery() return } if a.newOwner == nil { - if !scheduleRPCRewrapDelivery(func() { - ctx, cancel := context.WithTimeout(context.Background(), min(5*time.Second, max(time.Second, a.conn.writeTimeout))) - defer cancel() - if err := s.sendCachedRPCResult(ctx, a.conn, encoded); err != nil && !isClientDisconnect(err) { - s.log.Debug("RPC init rewrap pending replay failed", zap.Error(err)) - } - }) { - a.conn.fenceUndeliveredRPCResult() - } - return - } - clone, err := cloneRPCResultForRequest(encoded, a.newReqID, false) - if err != nil { - a.newOwner.Abort() - a.conn.fenceUndeliveredRPCResult() - return - } - if a.retargeted.Load() { - if !a.newOwner.HandOff() { + attempt, reserved, cloneErr := a.conn.cloneRPCResultForRequestReserved(encoded, encoded.reqMsgID, false) + if cloneErr != nil { + a.conn.failOutboundBudget(cloneErr) a.conn.fenceUndeliveredRPCResult() + a.finishReplayRestoreWithoutDelivery() return } - clone.markDelivered() - s.storeRPCResult(a.conn, a.newReqID, clone) + a.bodyReservation = reserved + job := s.rpcRewrapRestoreJob(a, "pending init rewrap replay", func(control *rpcRewrapDeliveryControl, deadline time.Time) { + ctx, cancel := context.WithDeadline(context.Background(), deadline) + defer cancel() + outcome := waitRPCRewrapPhysicalTerminal(a.conn, ctx, attempt, a.bodyReservation, control) + if outcome.err != nil { + if !outcome.owned { + return + } + a.conn.fenceUndeliveredRPCResult() + attempt.markReplayable() + a.releaseBodyReservation() + a.releaseReplayRestoreBarrier() + if !isClientDisconnect(outcome.err) { + s.log.Debug("RPC init rewrap pending replay failed", zap.Error(outcome.err)) + } + return + } + // A watchdog may win after the transport has already returned physical + // success but before this goroutine resumes. Success is irrevocable: run + // the once-only restore with a fresh bounded lifetime if timeout failure + // already fenced/released this physical generation. + restoreParent := ctx + if !outcome.owned { + restoreParent = context.Background() + } + restoreCtx, cancelRestore := boundedRPCReplayRestoreContext(restoreParent) + defer cancelRestore() + logical, claimErr := attempt.claimLogicalDeliveryHook(restoreCtx, false) + attempt.markDelivered() + if claimErr != nil { + a.conn.fenceUndeliveredRPCResult() + a.releaseBodyReservation() + a.releaseReplayRestoreBarrier() + return + } + restoreErr := s.runBoundedRPCReplayRestore( + restoreCtx, a.conn, "pending init rewrap replay", logical, a.runAfterSuccessfulDelivery, + ) + a.releaseBodyReservation() + a.releaseReplayRestoreBarrier() + if restoreErr != nil && !isClientDisconnect(restoreErr) { + s.log.Debug("RPC init rewrap pending replay failed", zap.Error(restoreErr)) + } + }) + if !scheduleRPCRewrapDeliveryJob(job) { + a.conn.fenceUndeliveredRPCResult() + a.finishReplayRestoreWithoutDelivery() + } + return + } + // A successful physical write under the retargeted req_msg_id is the only + // proof that lets the alias reuse that attempt. A mere TryRetarget success + // is not proof: the original socket may have failed before any bytes landed. + retargetDelivered := a.retargeted.Load() && + encoded.deliveryState() == rpcResultDeliveryDelivered && + encoded.writtenRequestID() == a.newReqID + clone, reserved, err := a.conn.cloneRPCResultForRequestReserved(encoded, a.newReqID, retargetDelivered) + if err != nil { + a.conn.failOutboundBudget(err) + a.newOwner.Abort() + a.conn.fenceUndeliveredRPCResult() + a.finishReplayRestoreWithoutDelivery() + return + } + a.bodyReservation = reserved + if retargetDelivered { + if !a.newOwner.HandOff() { + a.conn.fenceUndeliveredRPCResult() + a.finishReplayRestoreWithoutDelivery() + return + } + job := s.rpcRewrapRestoreJob(a, "retargeted init rewrap result", func(control *rpcRewrapDeliveryControl, deadline time.Time) { + if !control.commit() { + return + } + restoreCtx, cancelRestore := context.WithDeadline(context.Background(), deadline) + defer cancelRestore() + restoreErr := s.completeDeliveredRPCRewrapResult( + restoreCtx, a, clone, "retargeted init rewrap result", + ) + if restoreErr != nil && !isClientDisconnect(restoreErr) { + s.log.Debug("Retargeted RPC restore failed", zap.Error(restoreErr)) + } + }) + job.fail = func(err error) { + // Never enter deliveredFinalizeOnce from the timer goroutine: the worker + // may already own a non-cooperative restore. Fence and release its Conn + // barrier first, then retain the immutable delivered result for a later + // replacement replay, which will wait on coordinator Claimed/InProgress. + a.conn.fenceUndeliveredRPCResult() + clone.markReplayable() + clone.releaseDeferredLogicalDeliveryHook() + a.releaseReplayRestoreBarrier() + a.storeResultOnce(s, clone) + a.releaseBodyReservation() + s.log.Warn("Retargeted RPC restore watchdog expired", + zap.String("method", a.method), zap.Int64("req_msg_id", a.newReqID), zap.Error(err)) + } + if !scheduleRPCRewrapDeliveryJob(job) { + job.fail(ErrOutboundQueueFull) + } s.log.Info("RPC init rewrap result retargeted", zap.String("method", a.method), zap.Int64("new_req_msg_id", a.newReqID), zap.String("auth_key_id", a.conn.authKeyHex), zap.Int64("session_id", a.conn.sessionID)) return } - if !scheduleRPCRewrapDelivery(func() { - s.publishRewrappedRPCResult(a.conn, a.newReqID, a.method, a.newOwner, clone) - }) { + job := s.rpcRewrapRestoreJob(a, "pending init rewrap result", func(control *rpcRewrapDeliveryControl, deadline time.Time) { + s.publishRewrappedRPCResult(a.conn, a.newReqID, a.method, a.newOwner, clone, a, control, deadline) + }) + // Once this alias consumed the source candidate, expiration or panic of + // the admitted worker job must still publish the immutable result under + // the new msg_id. Otherwise the alias owner would remain pending forever + // (or a reconnect could execute the business request a second time). + job.fail = func(err error) { s.failRPCRewrapResultJob(a, clone, err) } + if !scheduleRPCRewrapDeliveryJob(job) { // The completed result is durable in memory. Fence before publishing it // under the new msg_id so a replacement can replay without re-executing. - a.conn.fenceUndeliveredRPCResult() - if a.newOwner.HandOff() { - clone.markReplayable() - s.storeRPCResult(a.conn, a.newReqID, clone) - } + s.failRPCRewrapResultJob(a, clone, ErrOutboundQueueFull) } - }) + } + var err error + if executionSubscriber != nil { + err = a.oldWaiter.SubscribeResultAndExecution(resultSubscriber, executionSubscriber) + } else { + err = a.oldWaiter.Subscribe(resultSubscriber) + } if err != nil { + a.finishReplayRestoreWithoutDelivery() s.rpcRewrap.release(a.candidate) return err } @@ -407,7 +1026,7 @@ func (s *Server) scheduleRewrappedInitObservation(c *Conn, init rpcRewrapInit) { if !ok || c == nil { return } - if !scheduleRPCRewrapDelivery(func() { + if !scheduleRPCRewrapObservation(func() { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := observer.ObserveInitConnection( @@ -422,33 +1041,75 @@ func (s *Server) scheduleRewrappedInitObservation(c *Conn, init rpcRewrapInit) { } } -func (s *Server) publishRewrappedRPCResult(c *Conn, reqMsgID int64, method string, owner *rpcResultOwnerLease, encoded *encodedOutboundMessage) { +func (s *Server) publishRewrappedRPCResult( + c *Conn, + reqMsgID int64, + method string, + owner *rpcResultOwnerLease, + encoded *encodedOutboundMessage, + alias *rpcRewrapAlias, + control *rpcRewrapDeliveryControl, + deadline time.Time, +) { if s == nil || c == nil || owner == nil || encoded == nil { + if alias != nil { + alias.finishReplayRestoreWithoutDelivery() + } return } if !owner.HandOff() { c.fenceUndeliveredRPCResult() + alias.finishReplayRestoreWithoutDelivery() + return + } + if control == nil || !control.running() { + alias.releaseBodyReservation() return } priority := rpcResultPriority(method, encoded) encoded.priority = priority - terminal := func(deliveryErr error) { - if deliveryErr != nil { - encoded.markReplayable() - c.fenceUndeliveredRPCResult() - } else { - encoded.markDelivered() - } - s.storeRPCResult(c, reqMsgID, encoded) - } encoded.markQueued() - ctx, cancel := context.WithTimeout(context.Background(), min(5*time.Second, max(time.Second, c.writeTimeout))) + if deadline.IsZero() { + deadline = time.Now().Add(rpcRewrapDeliveryQueueTimeout) + } + ctx, cancel := context.WithDeadline(context.Background(), deadline) defer cancel() - if err := c.enqueueEncodedDelivery(ctx, proto.MessageServerResponse, encoded, priority, terminal); err != nil { - terminal(err) + // Rewrap delivery is synchronous on this small bounded worker pool. This + // makes the queue deadline cover the physical write and lets the pending + // logical hook join the same per-Conn ordered restore, without touching the + // process-wide asynchronous hook executor. + outcome := waitRPCRewrapPhysicalTerminal(c, ctx, encoded, alias.bodyReservation, control) + if outcome.err != nil { + if !outcome.owned { + return + } + encoded.markReplayable() + encoded.releaseDeferredLogicalDeliveryHook() + c.fenceUndeliveredRPCResult() + alias.storeResultOnce(s, encoded) + alias.releaseBodyReservation() + alias.releaseReplayRestoreBarrier() return } - s.log.Info("RPC init rewrap result replay admitted", + // Physical success outranks an already-fired watchdog. The timeout path may + // have fenced and cached a replayable clone, but it cannot revoke bytes; the + // shared once/coordinator below still completes logical state exactly once. + // Run replacement metadata then the original logical hook before publishing + // the alias cache entry. Whole-finalization once also covers a watchdog racing + // a late physical terminal, so completed metadata cannot be overwritten. + restoreParent := ctx + if !outcome.owned { + restoreParent = context.Background() + } + restoreCtx, cancelRestore := boundedRPCReplayRestoreContext(restoreParent) + defer cancelRestore() + restoreErr := s.completeDeliveredRPCRewrapResult( + restoreCtx, alias, encoded, "physically delivered init rewrap result", + ) + if restoreErr != nil && !isClientDisconnect(restoreErr) { + s.log.Debug("RPC init rewrap delivered-state restore failed", zap.Error(restoreErr)) + } + s.log.Info("RPC init rewrap result replay delivered", zap.String("method", method), zap.Int64("req_msg_id", reqMsgID), zap.String("auth_key_id", c.authKeyHex), zap.Int64("session_id", c.sessionID), zap.Int("wire_bytes", len(encoded.body))) diff --git a/internal/mtprotoedge/rpc_rewrap_test.go b/internal/mtprotoedge/rpc_rewrap_test.go index 7582a478..17a629fa 100644 --- a/internal/mtprotoedge/rpc_rewrap_test.go +++ b/internal/mtprotoedge/rpc_rewrap_test.go @@ -3,14 +3,17 @@ package mtprotoedge import ( "context" "encoding/binary" + "errors" + "sync" "sync/atomic" "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/mt" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/tg" + "go.uber.org/zap/zaptest" ) func encodeRewrapTestRequest(t *testing.T) ([]byte, []byte) { @@ -67,6 +70,253 @@ func TestRPCResultDeliveryRetargetHasExactWritingBarrier(t *testing.T) { } } +func TestRPCRewrapAliasKeepsHookAcrossFailedSourceAttempt(t *testing.T) { + executor := newRPCDeliveryHookExecutor(1, 2) + var hooks atomic.Int32 + source := &encodedOutboundMessage{ + typeID: mt.RPCResultTypeID, + reqMsgID: 101, + body: make([]byte, 16), + delivery: newRPCResultDelivery(101), + } + binary.LittleEndian.PutUint32(source.body[:4], mt.RPCResultTypeID) + binary.LittleEndian.PutUint64(source.body[4:12], 101) + source.setDeliveryHook(func() { hooks.Add(1) }) + if err := source.prepareDeliveryHook(executor); err != nil { + t.Fatalf("reserve source attempt: %v", err) + } + source.markReplayable() + + alias, err := cloneRPCResultForRequest(source, 202, false) + if err != nil { + t.Fatalf("clone alias: %v", err) + } + if alias.delivery == source.delivery { + t.Fatal("alias reused source physical-attempt state") + } + if alias.delivery.coordinator != source.delivery.coordinator { + t.Fatal("alias did not inherit logical delivery coordinator") + } + if err := alias.prepareDeliveryHook(executor); err != nil { + t.Fatalf("reserve alias attempt: %v", err) + } + alias.markDelivered() + deadline := time.Now().Add(time.Second) + for hooks.Load() != 1 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if got := hooks.Load(); got != 1 { + t.Fatalf("alias delivery hooks = %d, want 1", got) + } + if got := source.deliveryState(); got != rpcResultDeliveryReplayable { + t.Fatalf("source attempt state = %d, want replayable", got) + } + if got := alias.deliveryState(); got != rpcResultDeliveryDelivered { + t.Fatalf("alias attempt state = %d, want delivered", got) + } +} + +func TestRPCRewrapFailedSourceAttemptPhysicallyDeliversAliasOnce(t *testing.T) { + s := New(Options{WriteTimeout: time.Second}) + failedTransport := &failAfterTransport{} + failedTransport.failAt.Store(1) + aliasTransport := &collectingSessionTransport{} + key := newTestAuthKey(t) + const sessionID, oldReqID, newReqID = int64(89), int64(5101), int64(5201) + sourceConn := s.newConn(failedTransport, key, sessionID, 1) + aliasConn := s.newConn(aliasTransport, key, sessionID, 1) + legacyCanonicalTestConn(t, sourceConn) + legacyCanonicalTestConn(t, aliasConn) + t.Cleanup(sourceConn.ForceClose) + t.Cleanup(aliasConn.ForceClose) + + oldClaim, err := s.rpcResults.Acquire(key.ID, sessionID, oldReqID) + if err != nil || oldClaim.state != rpcResultAcquireOwner { + t.Fatalf("old flight = %+v err=%v", oldClaim, err) + } + requestBody := []byte{1, 2, 3, 4} + if !s.rpcRewrap.register(sourceConn, requestBody, oldReqID, "test.method", oldClaim.owner) { + t.Fatal("register source rewrap candidate") + } + candidate := s.rpcRewrap.claim(aliasConn, requestBody) + if candidate == nil { + t.Fatal("claim source rewrap candidate") + } + newClaim, err := s.rpcResults.Acquire(key.ID, sessionID, newReqID) + if err != nil || newClaim.state != rpcResultAcquireOwner { + t.Fatalf("alias flight = %+v err=%v", newClaim, err) + } + alias := &rpcRewrapAlias{ + conn: aliasConn, newReqID: newReqID, method: "test.method", + oldWaiter: oldClaim.owner.Waiter(), newOwner: newClaim.owner, + sourceConn: sourceConn, sourceOwner: oldClaim.owner, + candidate: candidate, registry: s.rpcRewrap, + } + if err := alias.activate(s); err != nil { + t.Fatalf("activate alias: %v", err) + } + + var hooks atomic.Int32 + if err := s.publishRPCResult(sourceConn, oldReqID, "test.method", oldClaim.owner, + &mt.RPCError{ErrorCode: 400, ErrorMessage: "TEST"}, func() { hooks.Add(1) }); err != nil { + t.Fatalf("publish source result: %v", err) + } + + deadline := time.Now().Add(2 * time.Second) + for time.Now().Before(deadline) { + cached, ok := s.rpcResults.Get(key.ID, sessionID, newReqID) + if ok && cached.deliveryState() == rpcResultDeliveryDelivered && hooks.Load() == 1 { + if got := cached.writtenRequestID(); got != newReqID { + t.Fatalf("alias physical request ID = %d, want %d", got, newReqID) + } + if got := len(aliasTransport.snapshot()); got != 1 { + t.Fatalf("alias physical writes = %d, want 1", got) + } + sourceCached, sourceOK := s.rpcResults.Get(key.ID, sessionID, oldReqID) + if !sourceOK || sourceCached.deliveryState() != rpcResultDeliveryReplayable { + t.Fatalf("source physical attempt = cached:%v state:%d, want replayable", sourceOK, sourceCached.deliveryState()) + } + return + } + time.Sleep(time.Millisecond) + } + cached, ok := s.rpcResults.Get(key.ID, sessionID, newReqID) + t.Fatalf("alias result = cached:%v state:%v hooks:%d writes:%d", ok, cached.deliveryState(), hooks.Load(), len(aliasTransport.snapshot())) +} + +func TestRPCRewrapRepeatedReplacementSubscriberCapacityStaysBounded(t *testing.T) { + s := New(Options{WriteTimeout: time.Second}) + s.rpcResults = newRPCResultSubscriberTestCache(2, 2, 2, 2) + transport := &collectingSessionTransport{} + key := newTestAuthKey(t) + const sessionID, oldReqID, newReqID = int64(188), int64(15101), int64(15201) + c := s.newConn(transport, key, sessionID, 1) + legacyCanonicalTestConn(t, c) + t.Cleanup(c.ForceClose) + + oldClaim, err := s.rpcResults.Acquire(key.ID, sessionID, oldReqID) + if err != nil || oldClaim.owner == nil { + t.Fatalf("old flight = %#v err=%v", oldClaim, err) + } + var sourceResultCalls, sourceExecutionCalls atomic.Int32 + if err := oldClaim.owner.Waiter().SubscribeResultAndExecution( + func(*encodedOutboundMessage, bool) { sourceResultCalls.Add(1) }, + func(bool) { sourceExecutionCalls.Add(1) }, + ); err != nil { + t.Fatalf("fill source subscriber capacity: %v", err) + } + + for i := 0; i < 100; i++ { + newClaim, err := s.rpcResults.Acquire(key.ID, sessionID, newReqID) + if err != nil || newClaim.owner == nil { + t.Fatalf("replacement %d Acquire = %#v err=%v", i, newClaim, err) + } + plan := &inboundPlan{rewrapAliases: []*rpcRewrapAlias{{ + conn: c, oldWaiter: oldClaim.owner.Waiter(), newOwner: newClaim.owner, + newReqID: newReqID, method: "test.method", + }}} + err = plan.commitRewrapAliases(s) + if !errors.Is(err, ErrRPCResultSubscriberCapacity) { + t.Fatalf("replacement %d activation err=%v, want subscriber capacity", i, err) + } + if got := s.rpcResults.subscriberBudget.global.snapshot(); got != 2 { + t.Fatalf("replacement %d subscriber usage=%d, want 2", i, got) + } + c.rpcMu.Lock() + barriers := c.rpcReplayRestores + c.rpcMu.Unlock() + if barriers != 0 { + t.Fatalf("replacement %d leaked replay barrier=%d", i, barriers) + } + } + + if !oldClaim.owner.Abort() { + t.Fatal("abort source owner") + } + if sourceResultCalls.Load() != 1 || sourceExecutionCalls.Load() != 1 { + t.Fatalf("source callbacks result=%d execution=%d", sourceResultCalls.Load(), sourceExecutionCalls.Load()) + } + if got := s.rpcResults.subscriberBudget.global.snapshot(); got != 0 { + t.Fatalf("subscriber usage=%d after source abort", got) + } +} + +func TestRPCRewrapRetargetFailureRequiresReplacementAliasWrite(t *testing.T) { + s := New(Options{WriteTimeout: time.Second}) + failedTransport := &failAfterTransport{} + failedTransport.failAt.Store(1) + key := newTestAuthKey(t) + const sessionID, oldReqID, newReqID = int64(90), int64(6101), int64(6201) + failedConn := s.newConn(failedTransport, key, sessionID, 1) + legacyCanonicalTestConn(t, failedConn) + t.Cleanup(failedConn.ForceClose) + + oldClaim, err := s.rpcResults.Acquire(key.ID, sessionID, oldReqID) + if err != nil || oldClaim.state != rpcResultAcquireOwner { + t.Fatalf("old flight = %+v err=%v", oldClaim, err) + } + requestBody := []byte{5, 6, 7, 8} + if !s.rpcRewrap.register(failedConn, requestBody, oldReqID, "test.method", oldClaim.owner) { + t.Fatal("register source rewrap candidate") + } + candidate := s.rpcRewrap.claim(failedConn, requestBody) + if candidate == nil { + t.Fatal("claim source rewrap candidate") + } + newClaim, err := s.rpcResults.Acquire(key.ID, sessionID, newReqID) + if err != nil || newClaim.state != rpcResultAcquireOwner { + t.Fatalf("alias flight = %+v err=%v", newClaim, err) + } + alias := &rpcRewrapAlias{ + conn: failedConn, newReqID: newReqID, method: "test.method", + oldWaiter: oldClaim.owner.Waiter(), newOwner: newClaim.owner, + sourceConn: failedConn, sourceOwner: oldClaim.owner, + candidate: candidate, registry: s.rpcRewrap, + } + if err := alias.activate(s); err != nil { + t.Fatalf("activate alias: %v", err) + } + if !alias.retargeted.Load() { + t.Fatal("same-Conn queued source was not retargeted") + } + + var hooks atomic.Int32 + if err := s.publishRPCResult(failedConn, oldReqID, "test.method", oldClaim.owner, + &mt.RPCError{ErrorCode: 400, ErrorMessage: "TEST"}, func() { hooks.Add(1) }); err != nil { + t.Fatalf("publish source result: %v", err) + } + deadline := time.Now().Add(2 * time.Second) + var aliasCached *encodedOutboundMessage + for time.Now().Before(deadline) { + if cached, ok := s.rpcResults.Get(key.ID, sessionID, newReqID); ok && cached.deliveryState() == rpcResultDeliveryReplayable { + aliasCached = cached + break + } + time.Sleep(time.Millisecond) + } + if aliasCached == nil { + t.Fatal("failed retarget was incorrectly treated as delivered or alias result was not retained") + } + if hooks.Load() != 0 { + t.Fatalf("failed retarget ran delivery hook %d times", hooks.Load()) + } + + replacementTransport := &collectingSessionTransport{} + replacement := s.newConn(replacementTransport, key, sessionID, 1) + legacyCanonicalTestConn(t, replacement) + t.Cleanup(replacement.ForceClose) + if err := s.sendCachedRPCResult(context.Background(), replacement, aliasCached); err != nil { + t.Fatalf("replacement alias replay: %v", err) + } + deadline = time.Now().Add(time.Second) + for hooks.Load() != 1 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if hooks.Load() != 1 || len(replacementTransport.snapshot()) != 1 { + t.Fatalf("replacement delivery = hooks:%d writes:%d, want 1/1", hooks.Load(), len(replacementTransport.snapshot())) + } +} + func TestRPCResultWaiterSubscribeIsEventDriven(t *testing.T) { cache := newRPCResultCacheWithFlightLimit(time.Now, 8) claim, err := cache.Acquire([8]byte{1}, 2, 3) @@ -286,7 +536,17 @@ func TestInitRewrapAliasesExecutionAndRetargetsQueuedResult(t *testing.T) { encoded.markDelivered() s.rpcResults.Put(c.authKeyID, c.sessionID, oldReqID, encoded) - aliased, ok := s.rpcResults.Get(c.authKeyID, c.sessionID, newReqID) + var ( + aliased *encodedOutboundMessage + ok bool + ) + deadline := time.Now().Add(time.Second) + for time.Now().Before(deadline) { + if aliased, ok = s.rpcResults.Get(c.authKeyID, c.sessionID, newReqID); ok { + break + } + time.Sleep(time.Millisecond) + } if !ok { t.Fatal("new req_msg_id result was not completed") } @@ -297,3 +557,558 @@ func TestInitRewrapAliasesExecutionAndRetargetsQueuedResult(t *testing.T) { t.Fatalf("rewrap registry retained %d consumed candidates", s.rpcRewrap.total) } } + +func TestRPCRewrapDeliveryJobPanicAndDeadlineReleaseBarrier(t *testing.T) { + s := &Server{log: zaptest.NewLogger(t)} + c := &Conn{metrics: NopMetrics{}} + alias := &rpcRewrapAlias{conn: c} + // Even a legacy alias with no replacement metadata callback must hold the + // scheduler barrier until its physical replay reaches a terminal state. + alias.beginReplayRestore() + if alias.finishReplayRestore == nil { + t.Fatal("rewrap alias did not install its replay restore barrier") + } + + job := s.rpcRewrapRestoreJob(alias, "panic regression", func(*rpcRewrapDeliveryControl, time.Time) { + panic("boom") + }) + runRPCRewrapDeliveryJob(job) + + c.rpcMu.Lock() + pending := c.rpcReplayRestores + c.rpcMu.Unlock() + if pending != 0 { + t.Fatalf("replay restore barriers after panic = %d, want 0", pending) + } + if !c.isRetired() { + t.Fatal("panic in a rewrap job did not fence the partially restored connection") + } + + var ran atomic.Bool + var deadlineErr error + runRPCRewrapDeliveryJob(rpcRewrapDeliveryJob{ + deadline: time.Now().Add(-time.Millisecond), + run: func(*rpcRewrapDeliveryControl, time.Time) { ran.Store(true) }, + fail: func(err error) { deadlineErr = err }, + }) + if ran.Load() { + t.Fatal("expired rewrap job ran after its absolute queue deadline") + } + if !errors.Is(deadlineErr, context.DeadlineExceeded) { + t.Fatalf("expired rewrap job error = %v, want context deadline", deadlineErr) + } + + // Recovery is per job: a panic must not poison the worker loop's next item. + runRPCRewrapDeliveryJob(rpcRewrapDeliveryJob{ + deadline: time.Now().Add(time.Second), + run: func(*rpcRewrapDeliveryControl, time.Time) { ran.Store(true) }, + }) + if !ran.Load() { + t.Fatal("rewrap worker did not remain usable after a recovered panic") + } +} + +func TestExpiredRPCRewrapResultJobPublishesCompletedAliasExactlyOnce(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 1) + s := &Server{log: zaptest.NewLogger(t), rpcResults: cache} + c := &Conn{ + metrics: NopMetrics{}, + authKeyID: [8]byte{1, 2, 3, 4, 5, 6, 7, 8}, + sessionID: 7001, + } + const reqMsgID = int64(8001) + + claim, err := cache.Acquire(c.authKeyID, c.sessionID, reqMsgID) + if err != nil { + t.Fatalf("acquire aliased result owner: %v", err) + } + if claim.state != rpcResultAcquireOwner || claim.owner == nil { + t.Fatalf("aliased result claim = %#v, want owner", claim) + } + if !claim.owner.CompleteExecution(true) { + t.Fatal("complete aliased result execution") + } + encoded := encodedRPCResultForPriorityTest(reqMsgID, 0) + encoded.delivery = claim.owner.Delivery() + alias := &rpcRewrapAlias{ + conn: c, + newReqID: reqMsgID, + method: "help.getConfig", + newOwner: claim.owner, + } + alias.finishReplayRestore = c.beginRPCReplayRestore() + + var ran atomic.Bool + job := s.rpcRewrapRestoreJob(alias, "expired aliased result", func(*rpcRewrapDeliveryControl, time.Time) { + ran.Store(true) + }) + job.deadline = time.Now().Add(-time.Millisecond) + job.fail = func(err error) { + if !errors.Is(err, context.DeadlineExceeded) { + t.Errorf("expired result job error = %v, want context deadline", err) + } + s.failRPCRewrapResultJob(alias, encoded, err) + } + runRPCRewrapDeliveryJob(job) + + if ran.Load() { + t.Fatal("expired aliased result job executed") + } + if !c.isRetired() { + t.Fatal("expired aliased result job did not fence its connection") + } + c.rpcMu.Lock() + pendingRestores := c.rpcReplayRestores + c.rpcMu.Unlock() + if pendingRestores != 0 { + t.Fatalf("replay restore barriers = %d, want 0", pendingRestores) + } + if used := cache.flightLimit.snapshot(); used != 0 { + t.Fatalf("pending result flights = %d, want 0", used) + } + + completed, ok := cache.Get(c.authKeyID, c.sessionID, reqMsgID) + if !ok || completed != encoded { + t.Fatalf("completed aliased result = (%p, %v), want (%p, true)", completed, ok, encoded) + } + replay, err := cache.Acquire(c.authKeyID, c.sessionID, reqMsgID) + if err != nil { + t.Fatalf("reacquire completed aliased result: %v", err) + } + if replay.state != rpcResultAcquireCompleted || replay.encoded != encoded || + !replay.executionKnown || !replay.executionOK { + t.Fatalf("completed aliased result metadata = %#v", replay) + } + + // A defensive duplicate failure report must not republish or underflow the + // completed flight. The first handoff/cache completion is the sole winner. + s.failRPCRewrapResultJob(alias, encoded, context.DeadlineExceeded) + if used := cache.flightLimit.snapshot(); used != 0 { + t.Fatalf("pending result flights after duplicate failure = %d, want 0", used) + } + if got, ok := cache.Get(c.authKeyID, c.sessionID, reqMsgID); !ok || got != encoded { + t.Fatalf("completed result changed after duplicate failure = (%p, %v)", got, ok) + } +} + +func TestRetargetedRPCRestoreIsOrderedAndIndependentOfGlobalHookExecutor(t *testing.T) { + executor := newRPCDeliveryHookExecutor(1, 1) + started := make(chan struct{}) + release := make(chan struct{}) + ticket, ok := executor.reserve() + if !ok || !ticket.submit(func() { + close(started) + <-release + }) { + t.Fatal("occupy delivery hook executor") + } + <-started + oldExecutor := defaultRPCDeliveryHookExecutor + defaultRPCDeliveryHookExecutor = executor + defer func() { + defaultRPCDeliveryHookExecutor = oldExecutor + close(release) + }() + + s := New(Options{}) + c := &Conn{ + metrics: NopMetrics{}, + authKeyID: [8]byte{9, 8, 7, 6, 5, 4, 3, 2}, + sessionID: 9101, + } + const oldReqID, newReqID = int64(9201), int64(9202) + oldClaim, err := s.rpcResults.Acquire(c.authKeyID, c.sessionID, oldReqID) + if err != nil || oldClaim.state != rpcResultAcquireOwner { + t.Fatalf("old claim = %#v, err=%v", oldClaim, err) + } + body := []byte{1, 3, 3, 7} + if !s.rpcRewrap.register(c, body, oldReqID, "help.getConfig", oldClaim.owner) { + t.Fatal("register source rewrap candidate") + } + candidate := s.rpcRewrap.claim(c, body) + if candidate == nil { + t.Fatal("claim source rewrap candidate") + } + newClaim, err := s.rpcResults.Acquire(c.authKeyID, c.sessionID, newReqID) + if err != nil || newClaim.state != rpcResultAcquireOwner { + t.Fatalf("new claim = %#v, err=%v", newClaim, err) + } + + var order atomic.Int32 + alias := &rpcRewrapAlias{ + conn: c, newReqID: newReqID, method: "help.getConfig", + oldWaiter: oldClaim.owner.Waiter(), newOwner: newClaim.owner, + sourceConn: c, sourceOwner: oldClaim.owner, + candidate: candidate, registry: s.rpcRewrap, + afterSuccessfulDelivery: func() error { + if !order.CompareAndSwap(0, 1) { + return errors.New("replacement restore ran out of order") + } + return nil + }, + } + if err := alias.activate(s); err != nil { + t.Fatalf("activate retarget alias: %v", err) + } + if !alias.retargeted.Load() { + t.Fatal("source result was not retargeted") + } + + encoded := encodedRPCResultForPriorityTest(oldReqID, 0) + encoded.delivery = oldClaim.owner.Delivery() + encoded.setDeliveryHook(func() { + if !order.CompareAndSwap(1, 2) { + panic("logical hook did not run after replacement restore") + } + }) + if !oldClaim.owner.CompleteExecution(true) { + t.Fatal("complete source execution") + } + if !oldClaim.owner.HandOff() { + t.Fatal("handoff source result") + } + encoded.markQueued() + if got := encoded.beginWriting(); got != newReqID { + t.Fatalf("retargeted physical req_msg_id = %d, want %d", got, newReqID) + } + encoded.markDelivered() + s.rpcResults.Put(c.authKeyID, c.sessionID, oldReqID, encoded) + + deadline := time.Now().Add(time.Second) + for order.Load() != 2 && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if got := order.Load(); got != 2 { + t.Fatalf("retarget restore order = %d, want replacement then logical", got) + } + c.rpcMu.Lock() + pending := c.rpcReplayRestores + c.rpcMu.Unlock() + if pending != 0 { + t.Fatalf("retarget restore barriers = %d, want 0", pending) + } + if _, ok := s.rpcResults.Get(c.authKeyID, c.sessionID, newReqID); !ok { + t.Fatal("retargeted result was not cached under new req_msg_id") + } +} + +func TestRPCRewrapWatchdogReleasesQueuedBarrierWhenAllWorkersAreStuck(t *testing.T) { + var ( + once sync.Once + jobs chan rpcRewrapDeliveryJob + ) + started := make(chan struct{}, rpcRewrapDeliveryWorkers) + release := make(chan struct{}) + done := make(chan struct{}, rpcRewrapDeliveryWorkers) + for range rpcRewrapDeliveryWorkers { + if !scheduleRPCRewrapJob(rpcRewrapDeliveryJob{ + deadline: time.Now().Add(time.Second), + run: func(*rpcRewrapDeliveryControl, time.Time) { + started <- struct{}{} + <-release // Deliberately ignores its deadline. + done <- struct{}{} + }, + }, &once, &jobs, rpcRewrapDeliveryWorkers, 8) { + t.Fatal("schedule blocking rewrap worker") + } + } + for range rpcRewrapDeliveryWorkers { + select { + case <-started: + case <-time.After(time.Second): + t.Fatal("rewrap workers did not all block") + } + } + + s := &Server{log: zaptest.NewLogger(t)} + c := &Conn{metrics: NopMetrics{}} + alias := &rpcRewrapAlias{conn: c} + alias.beginReplayRestore() + var ran atomic.Bool + job := s.rpcRewrapRestoreJob(alias, "queued watchdog regression", func(*rpcRewrapDeliveryControl, time.Time) { + ran.Store(true) + }) + job.deadline = time.Now().Add(30 * time.Millisecond) + if !scheduleRPCRewrapJob(job, &once, &jobs, rpcRewrapDeliveryWorkers, 8) { + t.Fatal("schedule watched rewrap job") + } + + deadline := time.Now().Add(time.Second) + for time.Now().Before(deadline) { + c.rpcMu.Lock() + pending := c.rpcReplayRestores + c.rpcMu.Unlock() + if c.isRetired() && pending == 0 { + break + } + time.Sleep(time.Millisecond) + } + c.rpcMu.Lock() + pending := c.rpcReplayRestores + c.rpcMu.Unlock() + if !c.isRetired() || pending != 0 { + t.Fatalf("watchdog terminal state = retired:%v barriers:%d", c.isRetired(), pending) + } + close(release) + for range rpcRewrapDeliveryWorkers { + select { + case <-done: + case <-time.After(time.Second): + t.Fatal("blocking rewrap worker did not exit") + } + } + // Give a worker the opportunity to dequeue the expired job. Its atomic + // terminal state must suppress the late run entirely. + time.Sleep(10 * time.Millisecond) + if ran.Load() { + t.Fatal("expired queued rewrap job ran after watchdog failure") + } +} + +type deliveredThenBlockedTransport struct { + collectingSessionTransport + delivered chan struct{} + release chan struct{} + once sync.Once +} + +func newDeliveredThenBlockedTransport() *deliveredThenBlockedTransport { + return &deliveredThenBlockedTransport{ + delivered: make(chan struct{}), + release: make(chan struct{}), + } +} + +func (t *deliveredThenBlockedTransport) Send(ctx context.Context, b *bin.Buffer) error { + if err := t.collectingSessionTransport.Send(ctx, b); err != nil { + return err + } + t.once.Do(func() { close(t.delivered) }) + <-t.release // Simulate a transport that reports success late and ignores ctx. + return nil +} + +func TestRPCRewrapPhysicalSuccessAfterWatchdogStillRunsLogicalRestore(t *testing.T) { + s := New(Options{WriteTimeout: time.Second}) + transport := newDeliveredThenBlockedTransport() + defer func() { + select { + case <-transport.release: + default: + close(transport.release) + } + }() + key := newTestAuthKey(t) + c := s.newConn(transport, key, 9401, 1) + legacyCanonicalTestConn(t, c) + t.Cleanup(c.ForceClose) + const reqMsgID = int64(9402) + claim, err := s.rpcResults.Acquire(c.authKeyID, c.sessionID, reqMsgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("rewrap claim = %#v, err=%v", claim, err) + } + if !claim.owner.CompleteExecution(true) { + t.Fatal("complete rewrap execution") + } + + var order atomic.Int32 + encoded := encodedRPCResultForPriorityTest(reqMsgID, 0) + encoded.delivery = claim.owner.Delivery() + encoded.setDeliveryHook(func() { + if !order.CompareAndSwap(1, 2) { + panic("late physical success lost ordered logical restore") + } + }) + alias := &rpcRewrapAlias{ + conn: c, newReqID: reqMsgID, method: "help.getConfig", newOwner: claim.owner, + afterSuccessfulDelivery: func() error { + if !order.CompareAndSwap(0, 1) { + return errors.New("late replacement restore ran out of order") + } + return nil + }, + } + alias.executionOK.Store(true) + alias.beginReplayRestore() + + var ( + once sync.Once + jobs chan rpcRewrapDeliveryJob + ) + done := make(chan struct{}) + job := s.rpcRewrapRestoreJob(alias, "late physical success regression", func(control *rpcRewrapDeliveryControl, deadline time.Time) { + s.publishRewrappedRPCResult(c, reqMsgID, alias.method, claim.owner, encoded, alias, control, deadline) + close(done) + }) + job.deadline = time.Now().Add(30 * time.Millisecond) + job.fail = func(err error) { s.failRPCRewrapResultJob(alias, encoded, err) } + if !scheduleRPCRewrapJob(job, &once, &jobs, 1, 1) { + t.Fatal("schedule late-success rewrap job") + } + select { + case <-transport.delivered: + case <-time.After(time.Second): + t.Fatal("transport did not reach physical delivery gate") + } + + deadline := time.Now().Add(time.Second) + for time.Now().Before(deadline) { + c.rpcMu.Lock() + pending := c.rpcReplayRestores + c.rpcMu.Unlock() + if c.isRetired() && pending == 0 { + break + } + time.Sleep(time.Millisecond) + } + if got := order.Load(); got != 0 { + t.Fatalf("restore ran before transport reported terminal success: %d", got) + } + close(transport.release) + select { + case <-done: + case <-time.After(time.Second): + t.Fatal("late successful physical attempt did not finish") + } + if got := order.Load(); got != 2 { + t.Fatalf("late physical success restore order = %d, want 2", got) + } + if got := len(transport.snapshot()); got != 1 { + t.Fatalf("late physical success writes = %d, want 1", got) + } +} + +func TestConcurrentRPCRewrapDeliveredFinalizationPublishesOnceWithMetadata(t *testing.T) { + cache := newRPCResultCacheWithFlightLimit(time.Now, 1) + s := &Server{log: zaptest.NewLogger(t), rpcResults: cache} + c := &Conn{ + metrics: NopMetrics{}, + authKeyID: [8]byte{4, 4, 4, 4, 4, 4, 4, 4}, + sessionID: 9501, + } + const reqMsgID = int64(9502) + claim, err := cache.Acquire(c.authKeyID, c.sessionID, reqMsgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("finalization claim = %#v, err=%v", claim, err) + } + if !claim.owner.CompleteExecution(true) || !claim.owner.HandOff() { + t.Fatal("prepare finalization owner") + } + var subscribers atomic.Int32 + if err := claim.owner.Waiter().Subscribe(func(*encodedOutboundMessage, bool) { + subscribers.Add(1) + }); err != nil { + t.Fatalf("subscribe finalization probe: %v", err) + } + + var replacement, logical atomic.Int32 + encoded := encodedRPCResultForPriorityTest(reqMsgID, 0) + encoded.delivery = claim.owner.Delivery() + encoded.setDeliveryHook(func() { logical.Add(1) }) + alias := &rpcRewrapAlias{ + conn: c, newReqID: reqMsgID, method: "help.getConfig", newOwner: claim.owner, + afterSuccessfulDelivery: func() error { + replacement.Add(1) + return nil + }, + } + alias.executionOK.Store(true) + alias.beginReplayRestore() + + start := make(chan struct{}) + var wg sync.WaitGroup + for _, source := range []string{"worker", "watchdog"} { + wg.Add(1) + go func(source string) { + defer wg.Done() + <-start + _ = s.completeDeliveredRPCRewrapResult(context.Background(), alias, encoded, source) + }(source) + } + close(start) + wg.Wait() + + if got := replacement.Load(); got != 1 { + t.Fatalf("replacement finalizations = %d, want 1", got) + } + if got := logical.Load(); got != 1 { + t.Fatalf("logical finalizations = %d, want 1", got) + } + if got := subscribers.Load(); got != 1 { + t.Fatalf("cache subscriber calls = %d, want 1", got) + } + replay, err := cache.Acquire(c.authKeyID, c.sessionID, reqMsgID) + if err != nil || replay.state != rpcResultAcquireCompleted || + !replay.executionKnown || !replay.executionOK { + t.Fatalf("completed finalization metadata = %#v, err=%v", replay, err) + } + c.rpcMu.Lock() + pending := c.rpcReplayRestores + c.rpcMu.Unlock() + if pending != 0 { + t.Fatalf("finalization barriers = %d, want 0", pending) + } +} + +func TestRPCRewrapSubscriberPanicCannotLoseClaimedLogicalHook(t *testing.T) { + s := New(Options{WriteTimeout: time.Second}) + transport := &collectingSessionTransport{} + key := newTestAuthKey(t) + c := s.newConn(transport, key, 9301, 1) + legacyCanonicalTestConn(t, c) + t.Cleanup(c.ForceClose) + const reqMsgID = int64(9302) + claim, err := s.rpcResults.Acquire(c.authKeyID, c.sessionID, reqMsgID) + if err != nil || claim.state != rpcResultAcquireOwner { + t.Fatalf("alias claim = %#v, err=%v", claim, err) + } + if !claim.owner.CompleteExecution(true) { + t.Fatal("complete alias execution") + } + if err := claim.owner.Waiter().Subscribe(func(*encodedOutboundMessage, bool) { + panic("subscriber boom") + }); err != nil { + t.Fatalf("subscribe panic probe: %v", err) + } + + var order atomic.Int32 + encoded := encodedRPCResultForPriorityTest(reqMsgID, 0) + encoded.delivery = claim.owner.Delivery() + encoded.setDeliveryHook(func() { + if !order.CompareAndSwap(1, 2) { + panic("logical hook did not run after replacement restore") + } + }) + alias := &rpcRewrapAlias{ + conn: c, newReqID: reqMsgID, method: "help.getConfig", newOwner: claim.owner, + afterSuccessfulDelivery: func() error { + if !order.CompareAndSwap(0, 1) { + return errors.New("replacement restore ran out of order") + } + return nil + }, + } + alias.executionOK.Store(true) + alias.beginReplayRestore() + job := s.rpcRewrapRestoreJob(alias, "subscriber panic regression", func(control *rpcRewrapDeliveryControl, deadline time.Time) { + s.publishRewrappedRPCResult(c, reqMsgID, alias.method, claim.owner, encoded, alias, control, deadline) + }) + job.fail = func(err error) { s.failRPCRewrapResultJob(alias, encoded, err) } + runRPCRewrapDeliveryJob(job) + + if got := order.Load(); got != 2 { + t.Fatalf("restore order after subscriber panic = %d, want 2", got) + } + if !c.isRetired() { + t.Fatal("subscriber panic did not fence the connection") + } + c.rpcMu.Lock() + pending := c.rpcReplayRestores + c.rpcMu.Unlock() + if pending != 0 { + t.Fatalf("restore barriers after subscriber panic = %d, want 0", pending) + } + if cached, ok := s.rpcResults.Get(c.authKeyID, c.sessionID, reqMsgID); !ok || cached != encoded { + t.Fatalf("completed result after subscriber panic = (%p, %v), want (%p, true)", cached, ok, encoded) + } +} diff --git a/internal/mtprotoedge/rpc_test.go b/internal/mtprotoedge/rpc_test.go index 9ed7c4fb..11c616b7 100644 --- a/internal/mtprotoedge/rpc_test.go +++ b/internal/mtprotoedge/rpc_test.go @@ -8,14 +8,14 @@ import ( "go.uber.org/zap/zaptest" - "github.com/gotd/td/bin" - "github.com/gotd/td/clock" - "github.com/gotd/td/crypto" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" + "github.com/iamxvbaba/td/transport" "telesrv/internal/rpc" ) @@ -29,7 +29,7 @@ func TestRPCGetConfig(t *testing.T) { advPort = 12345 ) router := rpc.New(rpc.Config{DC: dc, IP: advIP, Port: advPort}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) - addr, pub, _ := startTestServer(t, Options{DC: dc, RPC: router}) + addr, pub, _ := startTestServer(t, Options{DC: dc, legacyRPC: router}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) clientMsgID := proto.NewMessageIDGen(time.Now) @@ -67,6 +67,52 @@ func TestRPCGetConfig(t *testing.T) { } } +func TestLayerRPCGetConfigUsesExactAdmittedProfile(t *testing.T) { + const ( + dc = 2 + advIP = "127.0.0.1" + advPort = 12345 + ) + router := rpc.New(rpc.Config{DC: dc, IP: advIP, Port: advPort}, rpc.Deps{}, zaptest.NewLogger(t), clock.System) + addr, pub, _ := startTestServer(t, Options{DC: dc, LayerRPC: router}) + conn, auth, cipher := dialHandshake(t, addr, dc, pub) + + clientMsgID := proto.NewMessageIDGen(time.Now) + reqMsgID := clientMsgID.New(proto.MessageFromClient) + request := &tg.InvokeWithLayerRequest{ + Layer: int(tg.LayerProfile225), + Query: &tg.InitConnectionRequest{ + APIID: 123, + DeviceModel: "Desktop", + SystemVersion: "Windows", + AppVersion: "test", + SystemLangCode: "en", + LangPack: "tdesktop", + LangCode: "en", + Query: &tg.HelpGetConfigRequest{}, + }, + } + sendEncrypted(t, conn, cipher, auth, reqMsgID, request) + + replies := collectReplies(t, conn, cipher, auth.AuthKey, proto.ResultTypeID) + resultBuf := mustHave(t, replies, proto.ResultTypeID, "rpc_result") + var result proto.Result + if err := result.Decode(resultBuf); err != nil { + t.Fatalf("decode rpc_result: %v", err) + } + if result.RequestMessageID != reqMsgID { + t.Fatalf("rpc_result req_msg_id = %d, want %d", result.RequestMessageID, reqMsgID) + } + exact := &bin.Buffer{Buf: result.Result} + config, err := tg.DecodeLayer(tg.LayerProfile225, tg.LayerConstructorConfigType(), exact) + if err != nil { + t.Fatalf("decode layer 225 config: %v", err) + } + if exact.Len() != 0 || config.ThisDC != dc { + t.Fatalf("layer 225 config = dc:%d remaining:%d", config.ThisDC, exact.Len()) + } +} + func TestInboundRPCQueueFullReturnsFloodWait(t *testing.T) { const dc = 2 handler := &blockingRPC{ @@ -75,7 +121,7 @@ func TestInboundRPCQueueFullReturnsFloodWait(t *testing.T) { } addr, pub, _ := startTestServer(t, Options{ DC: dc, - RPC: handler, + legacyRPC: handler, RPCMaxInflight: 1, RPCQueueSize: 1, RPCTimeout: 5 * time.Second, @@ -115,7 +161,7 @@ func TestInboundRPCQueuedDeadlineReturnsRPCTimeout(t *testing.T) { } addr, pub, _ := startTestServer(t, Options{ DC: dc, - RPC: handler, + legacyRPC: handler, RPCMaxInflight: 1, RPCQueueSize: 2, RPCTimeout: 60 * time.Millisecond, @@ -168,7 +214,7 @@ func TestInboundRPCRunningDeadlineWaitsForHandlerTerminalResult(t *testing.T) { } addr, pub, _ := startTestServer(t, Options{ DC: dc, - RPC: handler, + legacyRPC: handler, RPCMaxInflight: 1, RPCQueueSize: 1, RPCTimeout: 60 * time.Millisecond, @@ -215,7 +261,7 @@ func TestInboundRPCRunningDeadlineWaitsForHandlerTerminalResult(t *testing.T) { func TestDuplicateRPCResultAcrossReconnectUsesSessionCache(t *testing.T) { const dc = 2 handler := &countingConfigRPC{} - addr, pub, _ := startTestServer(t, Options{DC: dc, RPC: handler}) + addr, pub, _ := startTestServer(t, Options{DC: dc, legacyRPC: handler}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) clientMsgID := proto.NewMessageIDGen(time.Now) @@ -253,7 +299,7 @@ func TestCanceledRPCErrorIsNotCachedAcrossReconnect(t *testing.T) { firstStarted: make(chan struct{}), firstDone: make(chan struct{}), } - addr, pub, _ := startTestServer(t, Options{DC: dc, RPC: handler}) + addr, pub, _ := startTestServer(t, Options{DC: dc, legacyRPC: handler}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) clientMsgID := proto.NewMessageIDGen(time.Now) diff --git a/internal/mtprotoedge/server.go b/internal/mtprotoedge/server.go index 35196c74..4bfde345 100644 --- a/internal/mtprotoedge/server.go +++ b/internal/mtprotoedge/server.go @@ -14,43 +14,191 @@ import ( "go.uber.org/zap" - "github.com/gotd/td/bin" - "github.com/gotd/td/clock" - "github.com/gotd/td/crypto" - "github.com/gotd/td/exchange" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/tg" - "github.com/gotd/td/tmap" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/exchange" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tmap" + "github.com/iamxvbaba/td/transport" "telesrv/internal/store" "telesrv/internal/store/memory" ) -// RPCHandler 把解密后的 RPC 请求体路由到响应。由 internal/rpc 实现。 +// legacyRPCHandler 把解密后的 canonical RPC 请求体路由到响应。 // // b 是明文 RPC 请求(已剥离 MTProto 外壳);返回的 bin.Encoder 会被包成 rpc_result。 // 返回 *tgerr.Error 时连接层将其转为 rpc_error 回发;其他 error 视为连接级故障。 -type RPCHandler interface { +// +// 它只保留给本包旧连接状态机的回归测试。生产 API RPC 必须走 LayerRPCHandler, +// 使 admission、request/result TypeRef 与 exact profile 不可绕过。 +type legacyRPCHandler interface { Dispatch(ctx context.Context, authKeyID [8]byte, sessionID int64, b *bin.Buffer) (bin.Encoder, error) - // NegotiatedLayer returns the TL layer the session negotiated via - // invokeWithLayer and whether one was ever observed. Used to downgrade - // outbound objects for clients compiled on an older layer. ok=false means - // unknown (cold/evicted) — the caller must keep the connection's last-known - // layer rather than overwrite it. + // NegotiatedLayer returns the TL layer proven via invokeWithLayer for this + // exact (auth_key_id, session_id). It must never infer from API ID, device + // metadata, authorization rows, or another session on the same auth key. NegotiatedLayer(authKeyID [8]byte, sessionID int64) (int, bool) } -// RPCHandlerWithMethod returns the canonical innermost RPC method after the +// legacyRPCHandlerWithMethod returns the canonical innermost RPC method after the // router has peeled invokeWithLayer/initConnection/invokeAfter wrappers. Egress // scheduling must use this identity: the outer wrapper is not a useful signal // for prioritizing updates convergence over catalog/media responses. -type RPCHandlerWithMethod interface { +type legacyRPCHandlerWithMethod interface { DispatchWithMethod(ctx context.Context, authKeyID [8]byte, sessionID int64, b *bin.Buffer) (bin.Encoder, string, error) } +// LayerRPCHandler is the production API-RPC boundary. Admission is a separate +// allocation-bounded phase so the edge can freeze the connection profile, +// validate wrapper dependencies and establish exact request identity before +// flight/cache/scheduler ownership is acquired. +type LayerRPCHandler interface { + AdmitLayer(profile tg.LayerProfile, b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) + AdmitUnprofiled(b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) + DispatchAdmitted( + ctx context.Context, + authKeyID [8]byte, + sessionID int64, + msgID int64, + admissionSeq uint64, + request tg.LayerRequest, + ) (tg.LayerRPCResult, string, error) +} + +// LayerRPCDefaultProfileAdmitter decodes with a recoverable inherited/default +// profile. Production handlers should implement it with the same generated +// ServerDispatcher and adapter registry used by AdmitLayer. The split keeps old +// test doubles source-compatible while allowing invokeWithLayer to correct even +// a previously explicit Conn profile. +type LayerRPCDefaultProfileAdmitter interface { + AdmitDefaultLayer(profile tg.LayerProfile, b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) +} + +// LayerRPCSessionProfileResolver may restore an exact profile only when it was +// previously proven for this same (auth_key_id, session_id). Auth-key-wide +// device metadata is intentionally ineligible: a client upgrade can reuse its +// auth key while opening a new session at a newer Layer. +type LayerRPCSessionProfileResolver interface { + NegotiatedSessionLayer(authKeyID [8]byte, sessionID int64) (int, bool) +} + +// LayerRPCOrderedSessionProfileResolver restores both the selected Layer and +// the newest invokeWithLayer client msg_id which proved it. The cursor prevents +// an old cached request replay on a replacement physical connection from +// rolling the logical session back to an older profile. +type LayerRPCOrderedSessionProfileResolver interface { + NegotiatedSessionLayerEvidence(authKeyID [8]byte, sessionID int64) (layer int, msgID int64, ok bool) +} + +// LayerRPCInheritedAuthKeyProfileResolver resolves the best persisted +// auth-key-wide client Layer for a new session. Unlike exact same-session +// evidence this value is only an inherited default: a later invokeWithLayer may +// correct it. Implementations may resolve a temporary raw key through its bound +// permanent key, but must not infer from API ID or device strings. +type LayerRPCInheritedAuthKeyProfileResolver interface { + ResolveInheritedAuthKeyLayer(ctx context.Context, rawAuthKeyID [8]byte) (layer int, found bool, err error) +} + +// LayerRPCSessionProfileRegistry atomically freezes and invalidates the exact +// same-session profile. Its bounded retention may survive a TCP reconnect and +// admit a naked replay while the entry remains live. Expiry or capacity eviction +// loses only that proof and therefore fails closed until fresh invokeWithLayer; +// it never falls back to auth-key-wide metadata. +type LayerRPCSessionProfileRegistry interface { + LayerRPCSessionProfileResolver + FreezeNegotiatedSessionLayer(authKeyID [8]byte, sessionID int64, layer int) error + ForgetNegotiatedSessionLayer(authKeyID [8]byte, sessionID int64) + ForgetNegotiatedAuthKey(authKeyID [8]byte) +} + +// LayerRPCOrderedSessionProfileRegistry linearizes explicit Layer evidence by +// MTProto client msg_id. applied is false for an older or identical duplicate; +// the same msg_id with another Layer must return ErrLayerProfileConflict (or an +// error wrapping it). Implementations advance the cursor even when Layer is +// unchanged. +type LayerRPCOrderedSessionProfileRegistry interface { + LayerRPCOrderedSessionProfileResolver + FreezeNegotiatedSessionLayerAt(authKeyID [8]byte, sessionID int64, layer int, msgID int64) (applied bool, err error) +} + +// LayerRPCDurableSessionProfileResolver restores restart-safe raw Layer +// evidence. layer may be newer than this binary's generated codec universe; +// msgID remains the ordering authority in that case. +type LayerRPCDurableSessionProfileResolver interface { + ResolveNegotiatedSessionLayerEvidence( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + ) (layer int, msgID int64, found bool, err error) +} + +// LayerRPCDurableSessionProfileAdvancer atomically advances exact-session and +// auth-key shared-default evidence. publishShared is true only when this exact +// observation still owns the durable shared default. +type LayerRPCDurableSessionProfileAdvancer interface { + AdvanceNegotiatedSessionLayerEvidence( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + layer int, + msgID int64, + ) (currentLayer int, currentMsgID int64, publishShared bool, err error) +} + +type LayerRPCDurableSessionProfileDeleter interface { + DeleteNegotiatedSessionLayerEvidence( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + ) (deleted bool, err error) +} + +// LayerRPCReplayPreparer reapplies connection-local wrapper state for an +// already-executed exact request without consuming its one-shot business +// dispatch lease. The returned callback is safe to run only after a successful +// cached rpc_result reaches the replacement physical connection. +type LayerRPCReplayPreparer interface { + PrepareAdmittedReplay( + ctx context.Context, + authKeyID [8]byte, + sessionID int64, + msgID int64, + admissionSeq uint64, + request tg.LayerRequest, + ) (afterSuccessfulDelivery func() error, err error) +} + +// LayerRPCProfileEvidenceContext lets a generated/semantic handler carry the +// edge's MTProto msg_id freshness decision through its existing context-based +// dispatch API. fresh=false means the request remains fully request-bound: it +// may decode, execute and produce an exact result, but it must not publish +// mutable Layer/init/readiness/auth-bind state. Production Router implements +// this optional decorator; older handlers which have no such shared state stay +// source compatible. +type LayerRPCProfileEvidenceContext interface { + WithLayerRPCProfileEvidenceFresh(ctx context.Context, fresh bool) context.Context +} + +// LayerRPCAdmissionProfilePublisher advances the auth-key-wide inherited +// default for fresh explicit evidence. admissionSeq is allocated once by the +// edge's exact flight owner and globally orders different MTProto sessions; +// cached joins/replays never call this hook again. +type LayerRPCAdmissionProfilePublisher interface { + PublishAdmittedLayerProfileEvidence( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + msgID int64, + admissionSeq uint64, + safeFloor uint64, + layer int, + ) error +} + // RPCInitConnectionObserver records wrapper metadata when the edge aliases an // initConnection reissue to an already-running request and therefore correctly // skips a second business Dispatch. @@ -115,8 +263,23 @@ type Options struct { RPCGlobalWorkers int // RPCGlobalMaxTasks 是全进程已预留、排队和执行中的 RPC 条数上限。默认 8192。 RPCGlobalMaxTasks int - // RPCGlobalMaxBytes 是上述 RPC body 的总字节预算。默认 512 MiB。 + // RPCGlobalMaxBytes 是上述 RPC 的进程级 memory charge 预算。legacy charge + // 等于 copied body;exact charge 是 typed decode 前的保守 materialization + // 上界,因此该配置不表示可并发接收 512 MiB wire body。默认 512 MiB。 RPCGlobalMaxBytes int64 + // RPCResultCache* limits bound pending ownership and completed rpc_result + // replay state across the full 331-second duplicate horizon. Every owner is + // charged simultaneously at global, raw-auth and session scopes. Defaults: + // global 262144/64 MiB, auth 32768/32 MiB, session 16384/16 MiB. + RPCResultCacheMaxEntries int + RPCResultCacheMaxBytes int64 + RPCResultCacheAuthMaxEntries int + RPCResultCacheAuthMaxBytes int64 + RPCResultCacheSessionMaxEntries int + RPCResultCacheSessionMaxBytes int64 + // RPCResultPendingPerAuth is an additional active-owner bound, independent + // from the retained entry limits and RPCGlobalMaxTasks. Default 2048. + RPCResultPendingPerAuth int // InboundFrameGlobalMaxBytes 是所有物理连接当前正在处理的 transport wire buffer // 与最大解密 plaintext buffer 的总预算。长度前缀读取后、payload 分配前预留,默认 // 512 MiB;非正值使用默认值。 @@ -143,8 +306,13 @@ type Options struct { AuthKeys store.AuthKeyStore // ActiveSessions 管理活跃连接。默认新建;传入时可让 RPC 层共享同一注册表。 ActiveSessions *SessionManager - // RPC 是 typed RPC 路由。nil 时加密 RPC 被丢弃并记录。 - RPC RPCHandler + // legacyRPC is an internal test hook for the pre-exact RPC state machine. + // It is deliberately unexported so production callers cannot bypass + // generated Layer admission by configuring the canonical-only route. + legacyRPC legacyRPCHandler + // LayerRPC is the generated exact-profile production path. When configured, + // every API request must complete admission before flight/cache scheduling. + LayerRPC LayerRPCHandler // Metrics 接收连接层指标。默认 NopMetrics。 Metrics Metrics // OnServing is called after the connection intake loops have been installed. @@ -200,6 +368,30 @@ func (o *Options) setDefaults() { if o.RPCGlobalMaxBytes <= 0 { o.RPCGlobalMaxBytes = 512 << 20 } + if o.RPCResultCacheMaxEntries == 0 { + o.RPCResultCacheMaxEntries = rpcResultCacheMaxEntries + } + if o.RPCResultCacheMaxBytes == 0 { + o.RPCResultCacheMaxBytes = rpcResultCacheMaxBytes + } + if o.RPCResultCacheAuthMaxEntries == 0 { + o.RPCResultCacheAuthMaxEntries = rpcResultCacheAuthMaxEntries + } + if o.RPCResultCacheAuthMaxBytes == 0 { + o.RPCResultCacheAuthMaxBytes = rpcResultCacheAuthMaxBytes + } + if o.RPCResultCacheSessionMaxEntries == 0 { + o.RPCResultCacheSessionMaxEntries = rpcResultCacheSessionMaxEntries + } + if o.RPCResultCacheSessionMaxBytes == 0 { + o.RPCResultCacheSessionMaxBytes = rpcResultCacheSessionMaxBytes + } + if o.RPCResultPendingPerAuth == 0 { + o.RPCResultPendingPerAuth = rpcResultFlightMaxPendingPerAuth + if o.RPCResultPendingPerAuth > o.RPCGlobalMaxTasks { + o.RPCResultPendingPerAuth = o.RPCGlobalMaxTasks + } + } if o.InboundFrameGlobalMaxBytes <= 0 { o.InboundFrameGlobalMaxBytes = defaultInboundFrameGlobalMaxBytes } @@ -232,6 +424,34 @@ func (o *Options) setDefaults() { } } +func validateRPCResultCacheOptions(o Options) error { + if o.RPCResultCacheMaxEntries <= 0 || o.RPCResultCacheAuthMaxEntries <= 0 || o.RPCResultCacheSessionMaxEntries <= 0 { + return fmt.Errorf("rpc_result cache entry limits must be positive") + } + if o.RPCResultCacheMaxEntries < o.RPCResultCacheAuthMaxEntries || + o.RPCResultCacheAuthMaxEntries < o.RPCResultCacheSessionMaxEntries { + return fmt.Errorf("rpc_result cache entry hierarchy must satisfy global >= auth >= session: %d/%d/%d", + o.RPCResultCacheMaxEntries, o.RPCResultCacheAuthMaxEntries, o.RPCResultCacheSessionMaxEntries) + } + if o.RPCResultCacheMaxBytes < int64(maxOutboundBodyBytes) || + o.RPCResultCacheAuthMaxBytes < int64(maxOutboundBodyBytes) || + o.RPCResultCacheSessionMaxBytes < int64(maxOutboundBodyBytes) { + return fmt.Errorf("rpc_result cache byte limits must each be at least max outbound body %d: %d/%d/%d", + maxOutboundBodyBytes, o.RPCResultCacheMaxBytes, o.RPCResultCacheAuthMaxBytes, o.RPCResultCacheSessionMaxBytes) + } + if o.RPCResultCacheMaxBytes < o.RPCResultCacheAuthMaxBytes || + o.RPCResultCacheAuthMaxBytes < o.RPCResultCacheSessionMaxBytes { + return fmt.Errorf("rpc_result cache byte hierarchy must satisfy global >= auth >= session: %d/%d/%d", + o.RPCResultCacheMaxBytes, o.RPCResultCacheAuthMaxBytes, o.RPCResultCacheSessionMaxBytes) + } + if o.RPCResultPendingPerAuth <= 0 || o.RPCResultPendingPerAuth > o.RPCGlobalMaxTasks || + o.RPCResultPendingPerAuth > o.RPCResultCacheAuthMaxEntries { + return fmt.Errorf("rpc_result per-auth pending limit %d must be positive and <= global pending %d and auth entries %d", + o.RPCResultPendingPerAuth, o.RPCGlobalMaxTasks, o.RPCResultCacheAuthMaxEntries) + } + return nil +} + // Server 是 MTProto 连接层(mtprotoedge)。 // // 职责见 doc.go。它把原始 TCP 字节流转换为「已解密、已识别 session 的 RPC 请求」: @@ -262,7 +482,8 @@ type Server struct { key exchange.PrivateKey authKeys store.AuthKeyStore conns *SessionManager - rpc RPCHandler + rpc legacyRPCHandler + layerRPC LayerRPCHandler metrics Metrics onServing func(net.Addr) cipher crypto.Cipher @@ -281,6 +502,9 @@ type Server struct { // New 创建 Server。 func New(opts Options) *Server { opts.setDefaults() + if err := validateRPCResultCacheOptions(opts); err != nil { + panic(fmt.Sprintf("mtprotoedge: invalid result-cache options: %v", err)) + } conns := opts.ActiveSessions if conns == nil { conns = NewSessionManager(opts.Logger.Named("sessions")) @@ -309,16 +533,26 @@ func New(opts Options) *Server { key: exchange.PrivateKey{RSA: opts.RSAKey}, authKeys: opts.AuthKeys, conns: conns, - rpc: opts.RPC, + rpc: opts.legacyRPC, + layerRPC: opts.LayerRPC, metrics: opts.Metrics, onServing: opts.OnServing, cipher: crypto.NewServerCipher(opts.Rand), clock: opts.Clock, rand: opts.Rand, types: tmap.New(tg.TypesMap(), mt.TypesMap(), proto.TypesMap()), - rpcResults: newRPCResultCacheWithFlightLimit(opts.Clock.Now, opts.RPCGlobalMaxTasks), - rpcRewrap: newRPCRewrapRegistry(opts.RPCGlobalMaxTasks), - admission: newAdmissionController(opts.MaxConnections, opts.MaxConnectionsPerIP, opts.MaxConcurrentHandshakes), + rpcResults: newRPCResultCacheWithFairCapacity(opts.Clock.Now, rpcResultCacheCapacity{ + maxPending: opts.RPCGlobalMaxTasks, + maxPendingPerAuth: opts.RPCResultPendingPerAuth, + globalMaxBytes: opts.RPCResultCacheMaxBytes, + globalMaxEntries: opts.RPCResultCacheMaxEntries, + authMaxBytes: opts.RPCResultCacheAuthMaxBytes, + authMaxEntries: opts.RPCResultCacheAuthMaxEntries, + sessionMaxBytes: opts.RPCResultCacheSessionMaxBytes, + sessionMaxEntries: opts.RPCResultCacheSessionMaxEntries, + }), + rpcRewrap: newRPCRewrapRegistry(opts.RPCGlobalMaxTasks), + admission: newAdmissionController(opts.MaxConnections, opts.MaxConnectionsPerIP, opts.MaxConcurrentHandshakes), } } diff --git a/internal/mtprotoedge/server_test.go b/internal/mtprotoedge/server_test.go index 1c129e26..c4812b41 100644 --- a/internal/mtprotoedge/server_test.go +++ b/internal/mtprotoedge/server_test.go @@ -16,12 +16,12 @@ import ( "go.uber.org/zap/zaptest" - "github.com/gotd/td/bin" - "github.com/gotd/td/mtproxy" - "github.com/gotd/td/mtproxy/obfuscator" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/telegram/dcs" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mtproxy" + "github.com/iamxvbaba/td/mtproxy/obfuscator" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/telegram/dcs" + "github.com/iamxvbaba/td/transport" ) // TestServerAcceptAndCodec 验证 M0: diff --git a/internal/mtprotoedge/session_activation_test.go b/internal/mtprotoedge/session_activation_test.go index c6fbe638..6aa6739e 100644 --- a/internal/mtprotoedge/session_activation_test.go +++ b/internal/mtprotoedge/session_activation_test.go @@ -8,8 +8,8 @@ import ( "go.uber.org/zap/zaptest" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" ) func newSessionActivationTestConn(t *testing.T, authKeyID [8]byte, sessionID int64) *Conn { @@ -222,7 +222,7 @@ func TestDestroyFencesOutboundAndReservedRPCBeforeRemoval(t *testing.T) { reservation, err := c.reserveInboundRPC(context.Background(), "test.destroyFence", 8) if err != nil { - t.Fatalf("reserve inbound RPC: %v", err) + t.Fatalf("reserve inbound legacyRPC: %v", err) } destroyed := make(chan bool, 1) go func() { diff --git a/internal/mtprotoedge/session_barrier_integration_test.go b/internal/mtprotoedge/session_barrier_integration_test.go index 755694fc..908ddd5e 100644 --- a/internal/mtprotoedge/session_barrier_integration_test.go +++ b/internal/mtprotoedge/session_barrier_integration_test.go @@ -10,11 +10,11 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/crypto" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" "telesrv/internal/store" ) @@ -44,7 +44,7 @@ func encryptedRPCFrameWithAuthoritativeSaltForBarrierTest( MessageDataLen: int32(len(body)), MessageDataWithPadding: body, }, &frame); err != nil { - t.Fatalf("encrypt client RPC: %v", err) + t.Fatalf("encrypt client legacyRPC: %v", err) } return &frame, store.AuthKeyData{ ID: key.ID, @@ -55,7 +55,7 @@ func encryptedRPCFrameWithAuthoritativeSaltForBarrierTest( func TestBadServerSaltRetainsOneProvisionalConnUntilCorrected(t *testing.T) { handler := &admissionCountingRPC{} - s := New(Options{RPC: handler, WriteTimeout: time.Second}) + s := New(Options{legacyRPC: handler, WriteTimeout: time.Second}) s.rpcScheduler.start() t.Cleanup(func() { s.rpcScheduler.stop(time.Second) }) @@ -149,7 +149,7 @@ func TestWrongSaltSessionChangeTransfersPhysicalOwnership(t *testing.T) { // owner Abort must observe the already-published terminal gate and must not // close the physical lease that is about to transfer to the new session. handler := &cancelThenRetryRPC{started: make(chan struct{})} - s := New(Options{RPC: handler, WriteTimeout: time.Second}) + s := New(Options{legacyRPC: handler, WriteTimeout: time.Second}) s.rpcScheduler.start() t.Cleanup(func() { s.rpcScheduler.stop(time.Second) }) @@ -294,7 +294,7 @@ func (*cancelThenRetryRPC) NegotiatedLayer([8]byte, int64) (int, bool) { return func TestHandleEncryptedRequiredSessionBarrierPrecedesStateRegistrationAndRPC(t *testing.T) { handler := &admissionCountingRPC{} - s := New(Options{RPC: handler, WriteTimeout: time.Second}) + s := New(Options{legacyRPC: handler, WriteTimeout: time.Second}) s.rpcScheduler.start() t.Cleanup(func() { s.rpcScheduler.stop(time.Second) }) @@ -374,7 +374,7 @@ func TestHandleEncryptedRequiredSessionBarrierPrecedesStateRegistrationAndRPC(t func TestHandleEncryptedRequiredSessionBarrierFailureIsAtomic(t *testing.T) { handler := &admissionCountingRPC{} - s := New(Options{RPC: handler, WriteTimeout: time.Second}) + s := New(Options{legacyRPC: handler, WriteTimeout: time.Second}) s.rpcScheduler.start() t.Cleanup(func() { s.rpcScheduler.stop(time.Second) }) @@ -441,7 +441,7 @@ func TestHandleEncryptedRequiredSessionBarrierFailureIsAtomic(t *testing.T) { func TestCrossConnectionInflightRPCHasOneBusinessOwnerAndReplaysResult(t *testing.T) { handler := &reconnectFlightRPC{started: make(chan struct{}), release: make(chan struct{})} - s := New(Options{RPC: handler, WriteTimeout: time.Second, RPCTimeout: 5 * time.Second}) + s := New(Options{legacyRPC: handler, WriteTimeout: time.Second, RPCTimeout: 5 * time.Second}) s.rpcScheduler.start() t.Cleanup(func() { s.rpcScheduler.stop(time.Second) }) @@ -549,7 +549,7 @@ func TestCrossConnectionInflightRPCHasOneBusinessOwnerAndReplaysResult(t *testin func TestCrossConnectionInflightAbortRetriesOnlyAfterOldOwnerStops(t *testing.T) { handler := &cancelThenRetryRPC{started: make(chan struct{})} - s := New(Options{RPC: handler, WriteTimeout: time.Second, RPCTimeout: 5 * time.Second}) + s := New(Options{legacyRPC: handler, WriteTimeout: time.Second, RPCTimeout: 5 * time.Second}) s.rpcScheduler.start() t.Cleanup(func() { s.rpcScheduler.stop(time.Second) }) diff --git a/internal/mtprotoedge/session_boundary_test.go b/internal/mtprotoedge/session_boundary_test.go index 63885f3c..db0ee4b6 100644 --- a/internal/mtprotoedge/session_boundary_test.go +++ b/internal/mtprotoedge/session_boundary_test.go @@ -7,10 +7,10 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) // TestFirstContainerBoundaryKeepsAndroidRequestMap models DrKLO's @@ -120,7 +120,7 @@ func TestContainerRPCAdmissionFailureIsAtomic(t *testing.T) { handler := &admissionCountingRPC{} addr, pub, _ := startTestServer(t, Options{ DC: dc, - RPC: handler, + legacyRPC: handler, RPCMaxInflight: 1, RPCQueueSize: 1, RPCGlobalWorkers: 1, @@ -176,7 +176,7 @@ func TestContainerRPCAdmissionFailureIsAtomic(t *testing.T) { func TestGZIPWrappedRPCUsesLogicalEnvelopeBoundary(t *testing.T) { const dc = 2 handler := &admissionCountingRPC{} - addr, pub, _ := startTestServer(t, Options{DC: dc, RPC: handler}) + addr, pub, _ := startTestServer(t, Options{DC: dc, legacyRPC: handler}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) requestBody := mustEncodeTL(t, &tg.HelpGetConfigRequest{}) @@ -251,7 +251,7 @@ func TestEmptyContainerUsesOuterBoundary(t *testing.T) { func TestDuplicateContainerAcksWithoutBusinessReexecution(t *testing.T) { const dc = 2 handler := &admissionCountingRPC{} - addr, pub, _ := startTestServer(t, Options{DC: dc, RPC: handler}) + addr, pub, _ := startTestServer(t, Options{DC: dc, legacyRPC: handler}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) ids := proto.NewMessageIDGen(time.Now) @@ -322,7 +322,7 @@ func TestAndroidStartupBurstKeepsAllLargeRPCResultsAddressable(t *testing.T) { requests = 30 ) handler := &largeStartupBurstRPC{body: strings.Repeat("x", 192<<10)} - addr, pub, _ := startTestServer(t, Options{DC: dc, RPC: handler}) + addr, pub, _ := startTestServer(t, Options{DC: dc, legacyRPC: handler}) conn, auth, cipher := dialHandshake(t, addr, dc, pub) ids := proto.NewMessageIDGen(time.Now) diff --git a/internal/mtprotoedge/session_manager.go b/internal/mtprotoedge/session_manager.go index fe7feebf..e0727231 100644 --- a/internal/mtprotoedge/session_manager.go +++ b/internal/mtprotoedge/session_manager.go @@ -12,8 +12,8 @@ import ( "go.uber.org/zap" "go.uber.org/zap/zapcore" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) // ErrSessionNotFound 表示目标 session 当前无活跃连接。 @@ -71,15 +71,18 @@ const maxForceCloseParallelism = 64 type queuedPush struct { t proto.MessageType - encoded *encodedOutboundMessage + updates *layerUpdatesFanout reservation *pendingPushReservation at time.Time } type pendingPushReservation struct { budget *outboundTrackedBudget - bytes int + bytes atomic.Int64 refs atomic.Int32 + + mu sync.Mutex + profiles map[tg.LayerProfile]struct{} } func (r *pendingPushReservation) retain() { @@ -100,10 +103,33 @@ func (r *pendingPushReservation) release() { panic("mtprotoedge: pending push reservation released more than retained") } if refs == 0 { - r.budget.release(r.bytes) + r.budget.release(int(r.bytes.Load())) } } +// reservePrepared accounts the profile-specific immutable body retained by the +// semantic pending fanout. Multiple queued sessions sharing this reservation +// and profile share both the bytes and this one budget charge. +func (r *pendingPushReservation) reservePrepared(profile tg.LayerProfile, bytes int) bool { + if r == nil || bytes < 0 { + return false + } + r.mu.Lock() + defer r.mu.Unlock() + if _, ok := r.profiles[profile]; ok { + return true + } + if !r.budget.reserve(bytes) { + return false + } + if r.profiles == nil { + r.profiles = make(map[tg.LayerProfile]struct{}) + } + r.profiles[profile] = struct{}{} + r.bytes.Add(int64(bytes)) + return true +} + type sessionKey struct { authKeyID [8]byte sessionID int64 @@ -114,6 +140,19 @@ type SessionLifecycleObserver interface { SessionOffline(rawAuthKeyID [8]byte, sessionID, userID int64, lastForUser bool) } +// SessionDestructionObserver is an optional explicit control-plane lifecycle. +// It is separate from SessionOffline because a physical disconnect must retain +// logical-session replay metadata, while destroy_session must invalidate it. +type SessionDestructionObserver interface { + SessionDestroyed(rawAuthKeyID [8]byte, sessionID int64) +} + +func notifySessionDestroyed(observer SessionLifecycleObserver, authKeyID [8]byte, sessionID int64) { + if destroyed, ok := observer.(SessionDestructionObserver); ok { + destroyed.SessionDestroyed(authKeyID, sessionID) + } +} + // SessionManager 是活跃连接注册表,支持按 session / auth-key / user 查找并主动 push。 // // 它只管理进程内运行态,持有可发送的活跃连接;协议可恢复事实由 auth key、客户端重连 @@ -171,6 +210,294 @@ func (m *SessionManager) SetLifecycleObserver(observer SessionLifecycleObserver) m.mu.Unlock() } +// SeedInheritedLayerForRawAuthKey supplies an auth-key-wide default to every +// currently unknown active/provisional connection for rawAuthKeyID. Existing +// inherited or explicit state is left untouched; only ordered invokeWithLayer +// admission may correct a selected profile. The return value is the number of +// connections which transitioned from unknown to inherited. +func (m *SessionManager) SeedInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte, layer int) int { + return m.applyInheritedLayerForRawAuthKey(rawAuthKeyID, layer, false) +} + +// RefreshInheritedLayerForRawAuthKey is the auth.bindTempAuthKey identity- +// normalization path. It replaces unknown and inherited raw-temp-key shadows +// with the resolved permanent-key default, while preserving explicit evidence. +// Ordinary auth-key default publication must use SeedInheritedLayerForRawAuthKey +// so it cannot rewrite live sessions which already selected an inherited value. +func (m *SessionManager) RefreshInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte, layer int) int { + return m.applyInheritedLayerForRawAuthKey(rawAuthKeyID, layer, true) +} + +// ClearInheritedLayerForRawAuthKey removes a stale raw-key default after +// identity normalization obtains an authoritative unsupported/unknown +// permanent-key result. Only inherited state is cleared: explicit +// invokeWithLayer evidence belongs to the concrete logical session and remains +// authoritative until newer ordered evidence replaces it. +func (m *SessionManager) ClearInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte) int { + if m == nil || rawAuthKeyID == ([8]byte{}) { + return 0 + } + m.mu.RLock() + conns := make([]*Conn, 0, len(m.byAuthKey[rawAuthKeyID])+len(m.claimsByAuth[rawAuthKeyID])) + seen := make(map[*Conn]struct{}, cap(conns)) + for _, group := range []map[int64]*Conn{m.byAuthKey[rawAuthKeyID], m.claimsByAuth[rawAuthKeyID]} { + for _, c := range group { + if c == nil { + continue + } + if _, duplicate := seen[c]; duplicate { + continue + } + seen[c] = struct{}{} + conns = append(conns, c) + } + } + m.mu.RUnlock() + + cleared := 0 + for _, c := range conns { + if c.isRetired() { + continue + } + if changed, err := c.clearInheritedLayerProfileState(); err == nil && changed { + cleared++ + } + } + return cleared +} + +// SeedInheritedLayerForBusinessAuthKey supplies a canonical permanent-key +// default to every live raw physical key already normalized to that business +// identity. This covers multiple temporary/PFS keys for one authorization; +// explicit and previously-selected inherited session profiles remain stable. +func (m *SessionManager) SeedInheritedLayerForBusinessAuthKey(businessAuthKeyID [8]byte, layer int) int { + if m == nil || businessAuthKeyID == ([8]byte{}) { + return 0 + } + profile, ok := tg.ResolveLayerProfile(layer) + if !ok { + return 0 + } + m.mu.RLock() + group := m.byBusinessAuthKey[businessAuthKeyID] + conns := make([]*Conn, 0, len(group)) + seen := make(map[*Conn]struct{}, len(group)) + for _, c := range group { + if c == nil { + continue + } + if _, duplicate := seen[c]; duplicate { + continue + } + seen[c] = struct{}{} + conns = append(conns, c) + } + m.mu.RUnlock() + + seeded := 0 + for _, c := range conns { + if c.isRetired() { + continue + } + if current, resolved := c.BusinessAuthKeyID(); !resolved || current != businessAuthKeyID { + continue + } + if changed, err := c.setLayerProfile(profile, LayerProfileInherited, false); err == nil && changed { + seeded++ + } + } + return seeded +} + +func (m *SessionManager) applyInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte, layer int, refresh bool) int { + if m == nil { + return 0 + } + profile, ok := tg.ResolveLayerProfile(layer) + if !ok { + return 0 + } + m.mu.RLock() + conns := make([]*Conn, 0, len(m.byAuthKey[rawAuthKeyID])+len(m.claimsByAuth[rawAuthKeyID])) + seen := make(map[*Conn]struct{}, cap(conns)) + for _, group := range []map[int64]*Conn{m.byAuthKey[rawAuthKeyID], m.claimsByAuth[rawAuthKeyID]} { + for _, c := range group { + if c == nil { + continue + } + if _, duplicate := seen[c]; duplicate { + continue + } + seen[c] = struct{}{} + conns = append(conns, c) + } + } + m.mu.RUnlock() + + seeded := 0 + for _, c := range conns { + if c.isRetired() { + continue + } + var ( + changed bool + err error + ) + if refresh { + changed, err = c.refreshInheritedLayerProfile(profile) + } else { + changed, err = c.setLayerProfile(profile, LayerProfileInherited, false) + } + if err == nil && changed { + seeded++ + } + } + return seeded +} + +// ApplyOrderedLayerProfileForSession converges every physical generation +// currently active or claiming the same logical MTProto session. Per-Conn +// msg_id watermarks make broadcasts commutative: even if profile 300 reaches a +// Conn before a delayed profile 200 broadcast, 200 is inert and final state is +// the exact registry's maximum accepted evidence. +func (m *SessionManager) ApplyOrderedLayerProfileForSession( + primary *Conn, + rawAuthKeyID [8]byte, + sessionID int64, + profile tg.LayerProfile, + msgID int64, +) (int, error) { + if err := validateLayerProfile(profile); err != nil { + return 0, err + } + return m.ApplyOrderedRawLayerForSession(primary, rawAuthKeyID, sessionID, int(profile), msgID) +} + +// ApplyOrderedRawLayerForSession also carries future Layers unknown to this +// binary. Their raw watermark converges across physical generations while each +// Conn remains codec-unknown until a newer supported selector is admitted. +func (m *SessionManager) ApplyOrderedRawLayerForSession( + primary *Conn, + rawAuthKeyID [8]byte, + sessionID int64, + layer int, + msgID int64, +) (int, error) { + if msgID <= 0 { + return 0, fmt.Errorf("invalid ordered session layer msg_id %d", msgID) + } + if layer <= 0 { + return 0, fmt.Errorf("invalid ordered session layer %d", layer) + } + conns := make([]*Conn, 0, 3) + seen := make(map[*Conn]struct{}, 3) + if primary != nil { + seen[primary] = struct{}{} + conns = append(conns, primary) + } + if m != nil { + key := sessionKey{authKeyID: rawAuthKeyID, sessionID: sessionID} + m.mu.RLock() + for _, c := range []*Conn{m.bySession[key], m.claims[key]} { + if c == nil { + continue + } + if _, duplicate := seen[c]; duplicate { + continue + } + seen[c] = struct{}{} + conns = append(conns, c) + } + m.mu.RUnlock() + } + + applied := 0 + for _, c := range conns { + if c == nil || c.isRetired() { + continue + } + changed, err := c.freezeRawLayerProfileAt(layer, msgID) + if err != nil { + return applied, err + } + if changed { + applied++ + } + } + return applied, nil +} + +// ExplicitLayerEvidenceForAuthKey exposes live exact-session truth to +// auth.bindTempAuthKey. Router's bounded exact registry may expire while a Conn +// remains active; bind must not replace that explicit profile with a permanent +// key's inherited default merely because the cache TTL elapsed. +func (m *SessionManager) ExplicitLayerEvidenceForAuthKey(rawAuthKeyID [8]byte, sessionID int64) (layer int, msgID int64, ok bool) { + if m == nil || rawAuthKeyID == ([8]byte{}) || sessionID == 0 { + return 0, 0, false + } + key := sessionKey{authKeyID: rawAuthKeyID, sessionID: sessionID} + m.mu.RLock() + conns := []*Conn{m.bySession[key], m.claims[key]} + m.mu.RUnlock() + seen := make(map[*Conn]struct{}, len(conns)) + for _, c := range conns { + if c == nil || c.isRetired() { + continue + } + if _, duplicate := seen[c]; duplicate { + continue + } + seen[c] = struct{}{} + state, evidenceMsgID := c.layerProfileEvidenceState() + if c.isRetired() || state.Origin != LayerProfileExplicit { + continue + } + profile, supported := tg.ResolveLayerProfile(int(state.Profile)) + if !supported || profile != state.Profile { + continue + } + if !ok || evidenceMsgID > msgID { + layer, msgID, ok = int(profile), evidenceMsgID, true + continue + } + if evidenceMsgID == msgID && layer != int(profile) { + // This state contradicts the per-session msg_id ordering invariant; + // do not let bind choose either physical generation arbitrarily. + return 0, 0, false + } + } + return layer, msgID, ok +} + +// SetClientLayerForAuthKey implements rpc.ClientLayerBinder without weakening +// ordered evidence. It is a legacy/readiness safety net: only an unknown exact +// Conn receives the value as inherited state. Explicit or already-selected +// inherited profiles are owned by the edge's msg_id-ordered path. +func (m *SessionManager) SetClientLayerForAuthKey(rawAuthKeyID [8]byte, sessionID int64, layer int) { + if m == nil { + return + } + profile, ok := tg.ResolveLayerProfile(layer) + if !ok { + return + } + key := sessionKey{authKeyID: rawAuthKeyID, sessionID: sessionID} + m.mu.RLock() + conns := []*Conn{m.bySession[key], m.claims[key]} + m.mu.RUnlock() + seen := make(map[*Conn]struct{}, len(conns)) + for _, c := range conns { + if c == nil || c.isRetired() { + continue + } + if _, duplicate := seen[c]; duplicate { + continue + } + seen[c] = struct{}{} + _, _ = c.setLayerProfile(profile, LayerProfileInherited, false) + } +} + // BeginActivation atomically claims auth_key_id + session_id without publishing the // new Conn. Under the manager lock it irreversibly fences every previous owner, // removes active indexes and closes producer/RPC admission gates. Physical close and @@ -344,6 +671,7 @@ func (m *SessionManager) Unregister(c *Conn) { // DestroySessionForAuthKey 精确移除某个 raw auth_key_id 下的 session。 func (m *SessionManager) DestroySessionForAuthKey(authKeyID [8]byte, sessionID int64) bool { m.mu.Lock() + observer := m.lifecycle key := sessionKey{authKeyID: authKeyID, sessionID: sessionID} c, ok := m.bySession[key] if !ok { @@ -356,15 +684,16 @@ func (m *SessionManager) DestroySessionForAuthKey(authKeyID [8]byte, sessionID i zap.Int64("session_id", sessionID), ) } + notifySessionDestroyed(observer, authKeyID, sessionID) return true } m.deletePendingLocked(key) m.mu.Unlock() + notifySessionDestroyed(observer, authKeyID, sessionID) return false } offlineUser := m.retireConnLocked(c, true) lastForUser := offlineUser != 0 && len(m.byUser[offlineUser]) == 0 - observer := m.lifecycle m.log.Debug("Session destroyed", zap.String("auth_key_id", sessionKeyLog(authKeyID)), zap.Int64("session_id", sessionID), @@ -380,6 +709,7 @@ func (m *SessionManager) DestroySessionForAuthKey(authKeyID [8]byte, sessionID i if observer != nil && offlineUser != 0 { observer.SessionOffline(authKeyID, sessionID, offlineUser, lastForUser) } + notifySessionDestroyed(observer, authKeyID, sessionID) return true } @@ -762,6 +1092,18 @@ func (m *SessionManager) setReceivesUpdatesLocked(c *Conn, key sessionKey, recei delete(m.flushing, key) return 0, false } + if _, ok := c.LayerProfile(); !ok { + // A successful wire-invariant bootstrap RPC is not evidence that this + // physical session can decode proactive updates. Keep durable updates + // pending until generated exact admission freezes a real profile; do not + // start a flush which would fail layer binding and retire a healthy socket. + c.receivesUpdates.Store(false) + m.clearChannelInterestsLocked(key) + m.clearChannelMembershipsLocked(c, key) + c.membershipsSynced.Store(false) + delete(m.flushing, key) + return 0, false + } if c.receivesUpdates.Load() || m.flushing[key] { // 已就绪,或已有排空协程在跑(完成时会自行取走新增暂存并置位)。 return 0, false @@ -819,12 +1161,38 @@ func (m *SessionManager) runFlush(c *Conn, key sessionKey, owner int64, attempt // Pending entries are durable account updates. Shared body-budget pressure is not // evidence that this socket is corrupt, so use the non-terminal enqueue path; after // bounded retries, getDifference is the authoritative recovery path. - err := c.SendBestEffortEncoded(ctx, item.t, item.encoded, 5*time.Second) + encoded, err := item.updates.prepareForConn(ctx, c) + if err == nil { + if encoded == nil || encoded.layer == nil { + err = errors.New("pending exact updates lost layer binding") + } else if !item.reservation.reservePrepared(encoded.layer.profile, len(encoded.body)) { + item.updates.discardPrepared(encoded.layer.profile, encoded) + err = ErrOutboundTrackedBudget + } + } + if err == nil { + err = c.SendBestEffortEncoded(ctx, item.t, encoded, 5*time.Second) + } cancel() if err == nil { item.release() continue } + if isOutboundStaleLayerEpoch(err) { + // This durable online accelerator was prepared before a client layer + // correction. Drop only the stale item; difference remains authoritative. + item.release() + continue + } + if isOutboundLayerProfileError(err) { + // updates-ready without an exact profile, or a mismatched final + // body, violates the physical-connection layer invariant. Never + // guess canonical bytes; retire this writer and let durable + // difference recover after a correctly negotiated reconnect. + c.dropSlowConsumer() + releaseQueuedPushes(batch[i:]) + return + } m.mu.Lock() if cur, ok := m.bySession[key]; !ok || cur != c || !m.flushing[key] || c.userID.Load() != owner { // 连接换代/取消/易主:剩余 batch 不属于当前连接当前账号,丢弃。 @@ -884,23 +1252,11 @@ func (m *SessionManager) ReceivesUpdatesForAuthKey(authKeyID [8]byte, sessionID m.mu.RLock() c, ok := m.bySession[sessionKey{authKeyID: authKeyID, sessionID: sessionID}] m.mu.RUnlock() - return ok && c.receivesUpdates.Load() && c.membershipsSynced.Load() -} - -// SetClientLayerForAuthKey 把协商的 TL layer 即时写到指定连接。由 rpc 层在 -// invokeWithLayer 观测到新 layer 时(Dispatch 入口,早于鉴权门与 updates 就绪 -// 置位)调用,使同一条请求触发的 pending flush 与并发 push 立即按正确 layer -// 降级,不必等连接层在 Dispatch 返回后的兜底刷新。 -func (m *SessionManager) SetClientLayerForAuthKey(authKeyID [8]byte, sessionID int64, layer int) { - if m == nil || layer <= 0 { - return - } - m.mu.RLock() - c, ok := m.bySession[sessionKey{authKeyID: authKeyID, sessionID: sessionID}] - m.mu.RUnlock() - if ok { - c.SetClientLayer(layer) + if !ok { + return false } + _, hasProfile := c.LayerProfile() + return hasProfile && c.receivesUpdates.Load() && c.membershipsSynced.Load() } // SetReceivesUpdatesForAuthKey 标记指定 raw auth_key_id + session_id 是否接收主动 updates。 @@ -921,7 +1277,7 @@ func (m *SessionManager) SetReceivesUpdatesForAuthKey(authKeyID [8]byte, session } // PushToSessionForAuthKey 向指定 raw auth_key_id + session_id 推送一条消息。 -func (m *SessionManager) PushToSessionForAuthKey(ctx context.Context, authKeyID [8]byte, sessionID int64, t proto.MessageType, msg bin.Encoder) error { +func (m *SessionManager) PushToSessionForAuthKey(ctx context.Context, authKeyID [8]byte, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error { m.mu.RLock() key := sessionKey{authKeyID: authKeyID, sessionID: sessionID} c, ok := m.bySession[key] @@ -932,13 +1288,22 @@ func (m *SessionManager) PushToSessionForAuthKey(ctx context.Context, authKeyID ready := c.receivesUpdates.Load() m.mu.RUnlock() if ready { - return c.Send(ctx, t, msg) + updates, err := newLayerUpdatesFanoutContext(ctx, msg) + if err != nil { + return err + } + encoded, err := updates.prepareForConn(ctx, c) + if err != nil { + return err + } + return c.SendEncoded(ctx, t, encoded) } return m.queueOrSendPrepared(ctx, key, t, msg) } -func (m *SessionManager) queueOrSendPrepared(ctx context.Context, key sessionKey, t proto.MessageType, msg bin.Encoder) error { - encoded, reservation, err := m.preparePendingPush(ctx, msg) +func (m *SessionManager) queueOrSendPrepared(ctx context.Context, key sessionKey, t proto.MessageType, msg tg.UpdatesClass) error { + getUpdates := onceLayerUpdatesFanout(ctx, msg) + updates, reservation, err := m.preparePendingPush(getUpdates) if err != nil { return err } @@ -951,11 +1316,15 @@ func (m *SessionManager) queueOrSendPrepared(ctx context.Context, key sessionKey return ErrSessionNotFound } if !c.receivesUpdates.Load() { - _ = m.queuePreparedLocked(key, t, encoded, reservation) + _ = m.queuePreparedLocked(key, t, updates, reservation) m.mu.Unlock() return nil } m.mu.Unlock() + encoded, err := updates.prepareForConn(ctx, c) + if err != nil { + return err + } return c.SendEncoded(ctx, t, encoded) } @@ -964,7 +1333,7 @@ func (m *SessionManager) queueOrSendPrepared(ctx context.Context, key sessionKey // 它不等待该 session 进入 updates-ready,也不写 pending 队列。仅用于登录前的握手信号 // (例如 updateLoginToken):这类消息本身就是让客户端继续完成登录的触发器,若走普通 // durable update 队列会卡在客户端尚未调用 updates.getState 的阶段。 -func (m *SessionManager) PushToSessionForAuthKeyImmediate(ctx context.Context, authKeyID [8]byte, sessionID int64, t proto.MessageType, msg bin.Encoder) error { +func (m *SessionManager) PushToSessionForAuthKeyImmediate(ctx context.Context, authKeyID [8]byte, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error { m.mu.RLock() key := sessionKey{authKeyID: authKeyID, sessionID: sessionID} c, ok := m.bySession[key] @@ -972,11 +1341,19 @@ func (m *SessionManager) PushToSessionForAuthKeyImmediate(ctx context.Context, a if !ok { return ErrSessionNotFound } - return c.SendBestEffort(ctx, t, msg, 2*time.Second) + updates, err := newLayerUpdatesFanoutContext(ctx, msg) + if err != nil { + return err + } + encoded, err := updates.prepareForConn(ctx, c) + if err != nil { + return err + } + return c.SendBestEffortEncoded(ctx, t, encoded, 2*time.Second) } // PushToUserExceptAuthKeySession 向某 user 所有活跃连接推送,跳过指定 raw auth_key + session。 -func (m *SessionManager) PushToUserExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder) (int, error) { +func (m *SessionManager) PushToUserExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) { return m.pushToUser(ctx, userID, &excludeAuthKeyID, excludeSessionID, t, msg) } @@ -985,19 +1362,25 @@ func (m *SessionManager) PushToUserExceptAuthKeySession(ctx context.Context, use // businessAuthKeyCandidatesLocked,兼容 temp-key/PFS 连接),不是 byAuthKey(raw 索引会 // 漏 temp-key 设备)。未就绪连接跳过、不进 pending——密聊消息 durable 在 qts 队列, // 离线设备靠 getDifference 补回(在线推送只是加速器)。c.userID 复查防跨账号泄露。 -func (m *SessionManager) PushToUserAuthKey(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg bin.Encoder) (int, error) { +func (m *SessionManager) PushToUserAuthKey(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg tg.UpdatesClass) (int, error) { // Secret-chat qts is the durable source of truth, so online delivery is an accelerator just // like account pts fan-out. Do not synchronously wait for every PFS/raw connection's socket. return m.pushToBusinessAuthKeyBestEffort(ctx, userID, businessAuthKeyID, t, msg, 2*time.Second) } // PushToUserAuthKeyTransient 是 PushToUserAuthKey 的 transient(typing)best-effort 版本。 -func (m *SessionManager) PushToUserAuthKeyTransient(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg bin.Encoder, timeout time.Duration) (int, error) { +func (m *SessionManager) PushToUserAuthKeyTransient(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error) { return m.pushToBusinessAuthKeyBestEffort(ctx, userID, businessAuthKeyID, t, msg, timeout) } -func (m *SessionManager) pushToBusinessAuthKeyBestEffort(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg bin.Encoder, timeout time.Duration) (int, error) { - getEncoded := onceEncodedOutbound(ctx, msg) +func (m *SessionManager) pushToBusinessAuthKeyBestEffort(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error) { + if ctx != nil && ctx.Err() != nil { + return 0, ctx.Err() + } + sendCtx := context.Background() + if ctx != nil { + sendCtx = context.WithoutCancel(ctx) + } var deadline time.Time if timeout > 0 { deadline = time.Now().Add(timeout) @@ -1007,11 +1390,21 @@ func (m *SessionManager) pushToBusinessAuthKeyBestEffort(ctx context.Context, us deadline = ctxDeadline } } + if !deadline.IsZero() { + var cancel context.CancelFunc + sendCtx, cancel = context.WithDeadline(sendCtx, deadline) + defer cancel() + } + getUpdates := onceLayerUpdatesFanout(sendCtx, msg) return m.pushToBusinessAuthKey(ctx, userID, businessAuthKeyID, func(c *Conn) error { if c.outbound == nil || c.outboundControl == nil { return ErrConnClosed } - encoded, err := getEncoded() + updates, err := getUpdates() + if err != nil { + return err + } + encoded, err := updates.prepareForConn(sendCtx, c) if err != nil { return err } @@ -1022,7 +1415,7 @@ func (m *SessionManager) pushToBusinessAuthKeyBestEffort(ctx context.Context, us remaining = 0 } } - return c.SendBestEffortEncoded(ctx, t, encoded, remaining) + return c.SendBestEffortEncoded(sendCtx, t, encoded, remaining) }) } @@ -1049,6 +1442,15 @@ func (m *SessionManager) pushToBusinessAuthKey(ctx context.Context, userID int64 continue } if err := send(c); err != nil { + if isOutboundStaleLayerEpoch(err) { + // A concurrent correction invalidated this prepared push, not the + // connection. Durable qts/difference remains the source of truth. + continue + } + if isOutboundLayerProfileError(err) { + c.dropSlowConsumer() + continue + } if errors.Is(err, ErrOutboundTrackedBudget) { // Shared process pressure is not evidence that this particular socket is // slow. Skip this online accelerator; durable qts/difference is the truth. @@ -1071,13 +1473,17 @@ func (m *SessionManager) pushToBusinessAuthKey(ctx context.Context, userID int64 return sent, firstErr } -func (m *SessionManager) pushToUser(ctx context.Context, userID int64, excludeAuthKeyID *[8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder) (int, error) { - getEncoded := onceEncodedOutbound(ctx, msg) - return m.pushToUserWithSender(ctx, userID, excludeAuthKeyID, excludeSessionID, t, msg, true, func(c *Conn) error { +func (m *SessionManager) pushToUser(ctx context.Context, userID int64, excludeAuthKeyID *[8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) { + getUpdates := onceLayerUpdatesFanout(ctx, msg) + return m.pushToUserWithSender(ctx, userID, excludeAuthKeyID, excludeSessionID, t, getUpdates, true, func(c *Conn) error { if c.outbound == nil || c.outboundControl == nil { return ErrConnClosed } - encoded, err := getEncoded() + updates, err := getUpdates() + if err != nil { + return err + } + encoded, err := updates.prepareForConn(ctx, c) if err != nil { return err } @@ -1090,13 +1496,17 @@ func (m *SessionManager) pushToUser(ctx context.Context, userID int64, excludeAu // 跳过该连接、不进 pending——transient 数据 getDifference 无法补,就绪后由 getState 快照 / // 下一次状态变化重建,囤积过期 transient 既无意义又会被 pending 的老化/溢出/重试耗尽误当 // 「durable 兜底」丢弃。走 best-effort 发送,不阻塞调用方。 -func (m *SessionManager) PushToUserTransientExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder, timeout time.Duration) (int, error) { - getEncoded := onceEncodedOutbound(ctx, msg) - return m.pushToUserWithSender(ctx, userID, &excludeAuthKeyID, excludeSessionID, t, msg, false, func(c *Conn) error { +func (m *SessionManager) PushToUserTransientExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error) { + getUpdates := onceLayerUpdatesFanout(ctx, msg) + return m.pushToUserWithSender(ctx, userID, &excludeAuthKeyID, excludeSessionID, t, getUpdates, false, func(c *Conn) error { if c.outbound == nil || c.outboundControl == nil { return ErrConnClosed } - encoded, err := getEncoded() + updates, err := getUpdates() + if err != nil { + return err + } + encoded, err := updates.prepareForConn(ctx, c) if err != nil { return err } @@ -1104,12 +1514,18 @@ func (m *SessionManager) PushToUserTransientExceptAuthKeySession(ctx context.Con }) } -func (m *SessionManager) PushToUserExceptAuthKeySessionBestEffort(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder, timeout time.Duration) (int, error) { +func (m *SessionManager) PushToUserExceptAuthKeySessionBestEffort(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error) { return m.pushToUserBestEffort(ctx, userID, &excludeAuthKeyID, excludeSessionID, t, msg, timeout) } -func (m *SessionManager) pushToUserBestEffort(ctx context.Context, userID int64, excludeAuthKeyID *[8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder, timeout time.Duration) (int, error) { - getEncoded := onceEncodedOutbound(ctx, msg) +func (m *SessionManager) pushToUserBestEffort(ctx context.Context, userID int64, excludeAuthKeyID *[8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error) { + if ctx != nil && ctx.Err() != nil { + return 0, ctx.Err() + } + sendCtx := context.Background() + if ctx != nil { + sendCtx = context.WithoutCancel(ctx) + } // timeout 是整次 fan-out 的等待预算,不是每个 session 各自一份。健康连接始终先走 // SendBestEffortEncoded 的非阻塞快路径;预算耗尽后 remaining=0,仍会尝试快路径, // 但不会再为后续慢连接串行等待。 @@ -1122,11 +1538,21 @@ func (m *SessionManager) pushToUserBestEffort(ctx context.Context, userID int64, deadline = ctxDeadline } } - return m.pushToUserWithSender(ctx, userID, excludeAuthKeyID, excludeSessionID, t, msg, true, func(c *Conn) error { + if !deadline.IsZero() { + var cancel context.CancelFunc + sendCtx, cancel = context.WithDeadline(sendCtx, deadline) + defer cancel() + } + getUpdates := onceLayerUpdatesFanout(sendCtx, msg) + return m.pushToUserWithSender(ctx, userID, excludeAuthKeyID, excludeSessionID, t, getUpdates, true, func(c *Conn) error { if c.outbound == nil || c.outboundControl == nil { return ErrConnClosed } - encoded, err := getEncoded() + updates, err := getUpdates() + if err != nil { + return err + } + encoded, err := updates.prepareForConn(sendCtx, c) if err != nil { return err } @@ -1137,24 +1563,35 @@ func (m *SessionManager) pushToUserBestEffort(ctx context.Context, userID int64, remaining = 0 } } - return c.SendBestEffortEncoded(ctx, t, encoded, remaining) + return c.SendBestEffortEncoded(sendCtx, t, encoded, remaining) }) } -func onceEncodedOutbound(ctx context.Context, msg bin.Encoder) func() (*encodedOutboundMessage, error) { +func newLayerUpdatesFanoutContext(ctx context.Context, msg tg.UpdatesClass) (*layerUpdatesFanout, error) { + var updates *layerUpdatesFanout + err := withOutboundEncodeSlot(ctx, nil, func() error { + var err error + updates, err = newLayerUpdatesFanout(msg) + return err + }) + return updates, err +} + +func onceLayerUpdatesFanout(ctx context.Context, msg tg.UpdatesClass) func() (*layerUpdatesFanout, error) { var ( - encoded *encodedOutboundMessage + once sync.Once + updates *layerUpdatesFanout err error ) - return func() (*encodedOutboundMessage, error) { - if encoded == nil && err == nil { - encoded, err = encodeOutboundMessageContext(ctx, msg) - } - return encoded, err + return func() (*layerUpdatesFanout, error) { + once.Do(func() { + updates, err = newLayerUpdatesFanoutContext(ctx, msg) + }) + return updates, err } } -func (m *SessionManager) pushToUserWithSender(ctx context.Context, userID int64, excludeAuthKeyID *[8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder, queueWhenNotReady bool, send func(*Conn) error) (int, error) { +func (m *SessionManager) pushToUserWithSender(ctx context.Context, userID int64, excludeAuthKeyID *[8]byte, excludeSessionID int64, t proto.MessageType, getUpdates func() (*layerUpdatesFanout, error), queueWhenNotReady bool, send func(*Conn) error) (int, error) { // push fan-out 是连接层最热路径之一:debug 日志的字段构造(含 auth_key hex 格式化) // 在关闭 debug 时也会求值,先查级别一次、按需记日志。 debug := m.log.Core().Enabled(zapcore.DebugLevel) @@ -1191,7 +1628,7 @@ func (m *SessionManager) pushToUserWithSender(ctx context.Context, userID int64, // TL encoding and the process-wide pending-byte reservation may be expensive or // briefly block on the global encode gate. Do both before taking SessionManager.mu, // then share the immutable body across every not-ready session found by the re-scan. - pendingEncoded, pendingReservation, pendingErr := m.preparePendingPush(ctx, msg) + pendingUpdates, pendingReservation, pendingErr := m.preparePendingPush(getUpdates) // 写锁下完整重扫(读锁释放到此之间状态可能变化,以重扫结果为准)。 conns = conns[:0] queued, dropped, excluded, skipped = 0, 0, 0, 0 @@ -1207,7 +1644,7 @@ func (m *SessionManager) pushToUserWithSender(ctx context.Context, userID int64, skipped++ continue } - if pendingErr == nil && m.queuePreparedLocked(key, t, pendingEncoded, pendingReservation) { + if pendingErr == nil && m.queuePreparedLocked(key, t, pendingUpdates, pendingReservation) { queued++ if debug { m.log.Debug("Push queued (session not updates-ready)", @@ -1252,6 +1689,16 @@ func (m *SessionManager) pushToUserWithSender(ctx context.Context, userID int64, continue } if err := send(c); err != nil { + if isOutboundStaleLayerEpoch(err) { + // Do not classify profile correction as slow-consumer evidence. + dropped++ + continue + } + if isOutboundLayerProfileError(err) { + c.dropSlowConsumer() + dropped++ + continue + } if errors.Is(err, ErrOutboundTrackedBudget) { // Do not turn pressure owned by other sockets into a reconnect storm on // healthy recipients. The durable event remains recoverable by difference. @@ -1828,43 +2275,34 @@ func (m *SessionManager) takePendingLocked(key sessionKey, ready bool) []queuedP return pending } -// preparePendingPush encodes outside SessionManager.mu and reserves the one physical body before -// releasing the process-wide encode slot. Multiple not-ready sessions may then share this -// immutable body via reservation refs instead of encoding/copying it once per session. -func (m *SessionManager) preparePendingPush(ctx context.Context, msg bin.Encoder) (*encodedOutboundMessage, *pendingPushReservation, error) { - var ( - encoded *encodedOutboundMessage - bytes int - ) - err := withOutboundEncodeSlot(ctx, nil, func() error { - var err error - encoded, err = encodeOutboundMessageWithoutSlot(msg) - if err != nil { - return err - } - if encoded == nil { - return errors.New("nil encoded pending push") - } - bytes = len(encoded.body) - if bytes > maxOutboundBodyBytes { - return fmt.Errorf("%w: body=%d limit=%d", ErrOutboundMessageTooLarge, bytes, maxOutboundBodyBytes) - } - if !m.pendingBudget.reserve(bytes) { - return ErrOutboundTrackedBudget - } - return nil - }) +// preparePendingPush reserves the one frozen canonical semantic snapshot. Exact +// wire bytes are deliberately not retained here: they are prepared only when a +// target physical connection has a frozen profile, then cached once per profile +// by layerUpdatesFanout. +func (m *SessionManager) preparePendingPush(getUpdates func() (*layerUpdatesFanout, error)) (*layerUpdatesFanout, *pendingPushReservation, error) { + updates, err := getUpdates() if err != nil { return nil, nil, err } - reservation := &pendingPushReservation{budget: m.pendingBudget, bytes: bytes} + if updates == nil { + return nil, nil, errors.New("nil pending layer updates") + } + bytes := updates.canonicalSize() + if bytes > maxOutboundBodyBytes { + return nil, nil, fmt.Errorf("%w: body=%d limit=%d", ErrOutboundMessageTooLarge, bytes, maxOutboundBodyBytes) + } + if !m.pendingBudget.reserve(bytes) { + return nil, nil, ErrOutboundTrackedBudget + } + reservation := &pendingPushReservation{budget: m.pendingBudget} + reservation.bytes.Store(int64(bytes)) reservation.refs.Store(1) // producer ownership; queue entries retain below. - return encoded, reservation, nil + return updates, reservation, nil } -// queuePreparedLocked 暂存一条已编码的主动推送,返回是否实际入队。 +// queuePreparedLocked 暂存一条已冻结的主动推送,返回是否实际入队。 // 调用方必须在锁外保持 reservation 的 producer ref,并在全部入队完成后 release。 -func (m *SessionManager) queuePreparedLocked(key sessionKey, t proto.MessageType, encoded *encodedOutboundMessage, reservation *pendingPushReservation) bool { +func (m *SessionManager) queuePreparedLocked(key sessionKey, t proto.MessageType, updates *layerUpdatesFanout, reservation *pendingPushReservation) bool { q := m.pending[key] // 过期保护:最早一条暂存已超过 pendingPushMaxAge(session 迟迟未 ready)时,丢整批并 // 不再囤这条,记 trace。避免「登录后从不 getState」的连接长期占用 pending 内存。 @@ -1877,13 +2315,13 @@ func (m *SessionManager) queuePreparedLocked(key sessionKey, t proto.MessageType m.deletePendingLocked(key) return false } - if encoded == nil || reservation == nil { + if updates == nil || reservation == nil { return false } reservation.retain() push := queuedPush{ t: t, - encoded: encoded, + updates: updates, reservation: reservation, at: time.Now(), } diff --git a/internal/mtprotoedge/session_manager_bench_test.go b/internal/mtprotoedge/session_manager_bench_test.go index c7d54099..3adeecff 100644 --- a/internal/mtprotoedge/session_manager_bench_test.go +++ b/internal/mtprotoedge/session_manager_bench_test.go @@ -14,8 +14,8 @@ 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" ) // 连接层 fan-out / churn 压测:聚焦 SessionManager 的锁争用,不走真实 socket / 加密。 diff --git a/internal/mtprotoedge/session_manager_test.go b/internal/mtprotoedge/session_manager_test.go index 18f5c583..e8dc3d37 100644 --- a/internal/mtprotoedge/session_manager_test.go +++ b/internal/mtprotoedge/session_manager_test.go @@ -1,6 +1,7 @@ package mtprotoedge import ( + "bytes" "context" "errors" "sync" @@ -10,25 +11,26 @@ import ( "go.uber.org/zap/zaptest" - "github.com/gotd/td/bin" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) -type countingOutboundEncoder struct { - count *int -} - -func (e *countingOutboundEncoder) Encode(b *bin.Buffer) error { - *e.count++ - return (&tg.UpdatesTooLong{}).Encode(b) -} - type closeCountingTransport struct { closes int } +type sessionDestructionRecorder struct { + destroyed []sessionKey +} + +func (*sessionDestructionRecorder) SessionOffline([8]byte, int64, int64, bool) {} + +func (r *sessionDestructionRecorder) SessionDestroyed(authKeyID [8]byte, sessionID int64) { + r.destroyed = append(r.destroyed, sessionKey{authKeyID: authKeyID, sessionID: sessionID}) +} + type slowCloseTransport struct { delay time.Duration release <-chan struct{} @@ -164,6 +166,8 @@ func TestSessionManagerReplacementClosesOldPhysicalTransport(t *testing.T) { func TestSessionManagerDestroyClosesPhysicalTransport(t *testing.T) { sm := NewSessionManager(zaptest.NewLogger(t)) + observer := &sessionDestructionRecorder{} + sm.SetLifecycleObserver(observer) raw := [8]byte{4, 5, 6} physical := &closeCountingTransport{} c := &Conn{sessionID: 77, authKeyID: raw, transport: physical} @@ -178,11 +182,38 @@ func TestSessionManagerDestroyClosesPhysicalTransport(t *testing.T) { if sm.Online() != 0 { t.Fatalf("online after destroy = %d, want 0", sm.Online()) } + if len(observer.destroyed) != 1 || observer.destroyed[0] != (sessionKey{authKeyID: raw, sessionID: 77}) { + t.Fatalf("destroy callbacks = %+v, want exact destroyed session", observer.destroyed) + } + // An explicit destroy for an already-offline logical session must still + // invalidate retained exact-profile metadata even though the wire response + // remains destroy_session_none. + if sm.DestroySessionForAuthKey(raw, 88) { + t.Fatal("missing session reported destroyed") + } + if len(observer.destroyed) != 2 || observer.destroyed[1] != (sessionKey{authKeyID: raw, sessionID: 88}) { + t.Fatalf("offline destroy callbacks = %+v", observer.destroyed) + } } -func TestSessionManagerBestEffortFanoutPreencodesOnce(t *testing.T) { +func TestSessionManagerUnregisterIsNotSessionDestruction(t *testing.T) { + sm := NewSessionManager(zaptest.NewLogger(t)) + observer := &sessionDestructionRecorder{} + sm.SetLifecycleObserver(observer) + c := &Conn{sessionID: 91, authKeyID: [8]byte{9, 1}} + if err := sm.Register(c); err != nil { + t.Fatal(err) + } + sm.Unregister(c) + if len(observer.destroyed) != 0 { + t.Fatalf("ordinary unregister emitted destruction: %+v", observer.destroyed) + } +} + +func TestSessionManagerBestEffortFanoutPreparesOncePerProfile(t *testing.T) { sm := NewSessionManager(zaptest.NewLogger(t)) const userID = int64(100) + conns := make([]*Conn, 0, 2) for i := 0; i < 2; i++ { c := &Conn{ sessionID: int64(i + 1), @@ -195,16 +226,19 @@ func TestSessionManagerBestEffortFanoutPreencodesOnce(t *testing.T) { c.userID.Store(userID) c.userIDResolved.Store(true) c.receivesUpdates.Store(true) + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatalf("freeze profile: %v", err) + } sm.Register(c) + conns = append(conns, c) } - encodes := 0 sent, err := sm.PushToUserExceptSessionBestEffort( context.Background(), userID, 0, proto.MessageFromServer, - &countingOutboundEncoder{count: &encodes}, + &tg.UpdatesTooLong{}, 0, ) if err != nil { @@ -213,8 +247,91 @@ func TestSessionManagerBestEffortFanoutPreencodesOnce(t *testing.T) { if sent != 2 { t.Fatalf("sent = %d, want 2", sent) } - if encodes != 1 { - t.Fatalf("encoded %d times, want 1", encodes) + first := <-conns[0].outbound + second := <-conns[1].outbound + defer first.releaseReservation(conns[0].outboundTrackedBudget) + defer second.releaseReservation(conns[1].outboundTrackedBudget) + if first.encoded == nil || second.encoded == nil || !sameBacking(first.encoded.body, second.encoded.body) { + t.Fatal("same-profile fanout did not share one exact prepared body") + } + if first.encoded.layer == nil || second.encoded.layer == nil || first.encoded.layer == second.encoded.layer { + t.Fatal("same-profile fanout shared connection-specific epoch binding") + } +} + +func TestSessionManagerMixedLayerFanoutUsesProfileBoundBodies(t *testing.T) { + sm := NewSessionManager(zaptest.NewLogger(t)) + const userID = int64(103) + authKeyID := [8]byte{0x22, 0x70, 0x22, 0x80} + profiles := []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227, tg.LayerProfile228} + conns := make([]*Conn, 0, len(profiles)) + for _, profile := range profiles { + c := &Conn{ + sessionID: int64(profile), + authKeyID: authKeyID, + outbound: make(chan outboundOp, 1), + outboundControl: make(chan outboundOp, 1), + outboundStop: make(chan struct{}), + metrics: NopMetrics{}, + } + c.userID.Store(userID) + c.userIDResolved.Store(true) + c.receivesUpdates.Store(true) + if profile == tg.LayerProfile228 { + if err := c.SeedInheritedLayerProfile(tg.LayerProfile227); err != nil { + t.Fatalf("seed Alice inherited profile: %v", err) + } + } + if err := c.FreezeLayerProfile(profile); err != nil { + t.Fatalf("freeze profile %d: %v", profile, err) + } + sm.Register(c) + conns = append(conns, c) + } + + value := testLayerChannelUpdatesValue(321) + sent, err := sm.PushToUserExceptSessionBestEffort( + context.Background(), userID, 0, proto.MessageFromServer, value, 0, + ) + if err != nil || sent != len(conns) { + t.Fatalf("mixed fanout = sent:%d err:%v", sent, err) + } + var previous *encodedOutboundMessage + for i, c := range conns { + op := <-c.outbound + defer op.releaseReservation(c.outboundTrackedBudget) + if op.encoded == nil || op.encoded.layer == nil || op.encoded.layer.profile != profiles[i] { + t.Fatalf("connection %d binding = %#v", i, op.encoded) + } + state := c.LayerProfileState() + if op.encoded.layer.kind != outboundLayerBindingSession || op.encoded.layer.epoch != state.Epoch { + t.Fatalf("connection %d target binding = %#v, state=%#v", i, op.encoded.layer, state) + } + if previous == op.encoded { + t.Fatal("different profiles shared one final wire body") + } + previous = op.encoded + wantChannelID := testChannelWireID(profiles[i]) + if !bytes.Contains(op.encoded.body, littleEndianID(wantChannelID)) { + t.Fatalf("profile %d push lacks channel constructor %#08x", profiles[i], wantChannelID) + } + if otherChannelID := testOtherChannelWireID(profiles[i]); bytes.Contains(op.encoded.body, littleEndianID(otherChannelID)) { + t.Fatalf("profile %d push leaked channel constructor %#08x", profiles[i], otherChannelID) + } + input := bin.Buffer{Buf: op.encoded.body} + decoded, decodeErr := tg.DecodeLayer(profiles[i], tg.LayerClassUpdatesType(), &input) + if decodeErr != nil || input.Len() != 0 { + t.Fatalf("decode profile %d: remaining=%d err=%v", profiles[i], input.Len(), decodeErr) + } + updates := decoded.(*tg.Updates) + channel, ok := updates.Chats[0].(*tg.Channel) + if !ok || channel.ID != 100 { + t.Fatalf("profile %d decoded channel=%#v", profiles[i], updates.Chats) + } + status := updates.Updates[0].(*tg.UpdateUserStatus).Status.(*tg.UserStatusOnline) + if status.Expires != 321 { + t.Fatalf("profile %d decoded expires=%d", profiles[i], status.Expires) + } } } @@ -230,24 +347,23 @@ func TestSessionManagerPendingFanoutSharesOneEncodedBodyAndBudget(t *testing.T) keys = append(keys, connSessionKey(c)) } - encodes := 0 - msg := &countingOutboundEncoder{count: &encodes} + msg := &tg.UpdatesTooLong{} sent, err := sm.PushToUserExceptSession(context.Background(), userID, 0, proto.MessageFromServer, msg) if err != nil { t.Fatalf("push: %v", err) } - if sent != 2 || encodes != 1 { - t.Fatalf("pending fanout = sent:%d encodes:%d, want 2/1", sent, encodes) + if sent != 2 { + t.Fatalf("pending fanout sent=%d, want 2", sent) } sm.mu.Lock() first := sm.pending[keys[0]][0] second := sm.pending[keys[1]][0] - if first.encoded != second.encoded || first.reservation != second.reservation { + if first.updates != second.updates || first.reservation != second.reservation { sm.mu.Unlock() - t.Fatal("pending sessions did not share encoded body/reservation") + t.Fatal("pending sessions did not share frozen updates/reservation") } - wantBytes := int64(len(first.encoded.body)) + wantBytes := int64(first.updates.canonicalSize()) sm.deletePendingLocked(keys[0]) if got := sm.pendingBudget.snapshot(); got != wantBytes { sm.mu.Unlock() @@ -281,6 +397,9 @@ func TestSessionManagerBestEffortFanoutUsesOneBudgetAndDropsOnlySlowConsumers(t c.userID.Store(userID) c.userIDResolved.Store(true) c.receivesUpdates.Store(true) + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatalf("freeze profile: %v", err) + } sm.Register(c) slow = append(slow, c) } @@ -296,6 +415,9 @@ func TestSessionManagerBestEffortFanoutUsesOneBudgetAndDropsOnlySlowConsumers(t healthy.userID.Store(userID) healthy.userIDResolved.Store(true) healthy.receivesUpdates.Store(true) + if err := healthy.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatalf("freeze healthy profile: %v", err) + } sm.Register(healthy) const budget = 40 * time.Millisecond @@ -625,6 +747,9 @@ func TestPushToUserAuthKeyUsesOneDeadlineAndDropsOnlySlowPFSConnections(t *testi outboundStop: make(chan struct{}), } c.receivesUpdates.Store(true) + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatalf("freeze profile: %v", err) + } if queueFull { c.outbound <- outboundOp{} } @@ -787,6 +912,9 @@ func TestPushToSessionForAuthKeyImmediateBypassesReadinessQueue(t *testing.T) { outboundControl: make(chan outboundOp, 1), outboundStop: make(chan struct{}), } + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatalf("freeze profile: %v", err) + } sm.Register(c) msg := &tg.UpdateShort{Update: &tg.UpdateLoginToken{}, Date: 1700000000} @@ -819,6 +947,77 @@ func TestPushToSessionForAuthKeyImmediateBypassesReadinessQueue(t *testing.T) { } } +func TestSessionManagerWithholdsUpdatesReadinessUntilExactProfile(t *testing.T) { + sm := NewSessionManager(zaptest.NewLogger(t)) + key := sessionKey{authKeyID: [8]byte{0x22, 0x02, 0x27}, sessionID: 220227} + c := &Conn{ + authKeyID: key.authKeyID, + sessionID: key.sessionID, + outbound: make(chan outboundOp, 1), + outboundControl: make(chan outboundOp, 1), + outboundStop: make(chan struct{}), + metrics: NopMetrics{}, + outboundTrackedBudget: newOutboundTrackedBudget(1 << 20), + } + const userID = int64(1000000227) + c.userID.Store(userID) + c.userIDResolved.Store(true) + c.membershipsSynced.Store(true) // model work performed before a defensive Set(true) + if err := sm.Register(c); err != nil { + t.Fatal(err) + } + + update := &tg.UpdateShort{Update: &tg.UpdateUserStatus{UserID: userID, Status: &tg.UserStatusOnline{Expires: 1}}, Date: 1} + if err := sm.PushToSessionForAuthKey(context.Background(), key.authKeyID, key.sessionID, proto.MessageFromServer, update); err != nil { + t.Fatal(err) + } + sm.SetReceivesUpdatesForAuthKey(key.authKeyID, key.sessionID, true) + if c.receivesUpdates.Load() || c.membershipsSynced.Load() || sm.ReceivesUpdatesForAuthKey(key.authKeyID, key.sessionID) { + t.Fatal("unknown-profile connection became updates-ready") + } + if c.isRetired() { + t.Fatal("unknown-profile readiness attempt retired a healthy connection") + } + sm.mu.RLock() + pending, flushing := len(sm.pending[key]), sm.flushing[key] + sm.mu.RUnlock() + if pending != 1 || flushing { + t.Fatalf("unknown-profile readiness changed pending state = pending:%d flushing:%v", pending, flushing) + } + select { + case op := <-c.outbound: + op.releaseReservation(c.outboundTrackedBudget) + t.Fatal("unknown-profile readiness flushed a proactive update") + default: + } + + if err := c.FreezeLayerProfile(tg.LayerProfile225); err != nil { + t.Fatal(err) + } + c.membershipsSynced.Store(true) + sm.SetReceivesUpdatesForAuthKey(key.authKeyID, key.sessionID, true) + var op outboundOp + select { + case op = <-c.outbound: + case <-time.After(time.Second): + t.Fatal("profiled readiness did not flush pending update") + } + if op.encoded == nil || op.encoded.layer == nil || op.encoded.layer.profile != tg.LayerProfile225 { + t.Fatalf("flushed update layer binding = %#v", op.encoded) + } + op.releaseReservation(c.outboundTrackedBudget) + deadline := time.Now().Add(time.Second) + for !c.receivesUpdates.Load() && time.Now().Before(deadline) { + time.Sleep(time.Millisecond) + } + if !c.receivesUpdates.Load() || !sm.ReceivesUpdatesForAuthKey(key.authKeyID, key.sessionID) { + t.Fatal("profiled connection did not become updates-ready after ordered flush") + } + if c.isRetired() { + t.Fatal("profiled pending flush retired connection") + } +} + func TestPendingPushBodiesUseGlobalByteBudgetAndReleaseOnDrop(t *testing.T) { sm := NewSessionManager(zaptest.NewLogger(t)) msg := &tg.UpdateShort{Update: &tg.UpdateLoginToken{}, Date: 1700000000} @@ -863,6 +1062,9 @@ func TestPendingFlushGlobalBodyPressureDoesNotTerminateHealthyConnection(t *test const userID = int64(606) c.userID.Store(userID) c.userIDResolved.Store(true) + if err := c.FreezeLayerProfile(tg.LayerProfileCanonical); err != nil { + t.Fatal(err) + } sm.Register(c) msg := &tg.UpdateShort{Update: &tg.UpdateLoginToken{}, Date: 1700000000} @@ -958,6 +1160,10 @@ func TestSessionManagerPush(t *testing.T) { if got := srv.Conns().Online(); got != 2 { t.Fatalf("online = %d, want 2", got) } + if !srv.Conns().SetLayerProfile(auth1.SessionID, tg.LayerProfile227) || + !srv.Conns().SetLayerProfile(auth2.SessionID, tg.LayerProfile227) { + t.Fatal("seed exact test profiles") + } ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() diff --git a/internal/mtprotoedge/session_membership_gen_test.go b/internal/mtprotoedge/session_membership_gen_test.go index 76e142b2..7798cc46 100644 --- a/internal/mtprotoedge/session_membership_gen_test.go +++ b/internal/mtprotoedge/session_membership_gen_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap/zaptest" ) @@ -66,6 +67,9 @@ func TestSetSessionChannelMembershipsDetectsConcurrentIncrementalUpdates(t *test sm := NewSessionManager(zaptest.NewLogger(t)) raw := [8]byte{1, 2, 3} c := &Conn{sessionID: 42, authKeyID: raw} + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatal(err) + } sm.Register(c) sm.BindUserForAuthKey(raw, 42, 100) sm.SetReceivesUpdatesForAuthKey(raw, 42, true) diff --git a/internal/mtprotoedge/session_ready_test.go b/internal/mtprotoedge/session_ready_test.go index 93ac817b..0f6ea06f 100644 --- a/internal/mtprotoedge/session_ready_test.go +++ b/internal/mtprotoedge/session_ready_test.go @@ -3,6 +3,7 @@ package mtprotoedge import ( "testing" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap/zaptest" ) @@ -15,6 +16,9 @@ func TestReceivesUpdatesForAuthKeyRequiresMembershipSync(t *testing.T) { sm := NewSessionManager(zaptest.NewLogger(t)) raw := [8]byte{1, 2, 3} c := &Conn{sessionID: 42, authKeyID: raw} + if err := c.FreezeLayerProfile(tg.LayerProfile227); err != nil { + t.Fatal(err) + } sm.Register(c) sm.BindUserForAuthKey(raw, 42, 100) diff --git a/internal/mtprotoedge/structural_limits_test.go b/internal/mtprotoedge/structural_limits_test.go index b8a64ce6..12ef3512 100644 --- a/internal/mtprotoedge/structural_limits_test.go +++ b/internal/mtprotoedge/structural_limits_test.go @@ -9,9 +9,9 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/mt" - "github.com/gotd/td/proto" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/mt" + "github.com/iamxvbaba/td/proto" "go.uber.org/zap/zaptest" ) @@ -296,6 +296,7 @@ func TestInvalidMessageIDRejectsBeforeGZIPExpansion(t *testing.T) { {name: "stale", msgID: proto.NewMessageIDGen(func() time.Time { return time.Now().Add(-10 * time.Minute) }).New(proto.MessageFromClient), badCode: badMsgIDTooLow}, {name: "future", msgID: proto.NewMessageIDGen(func() time.Time { return time.Now().Add(time.Minute) }).New(proto.MessageFromClient), badCode: badMsgIDTooHigh}, {name: "invalid bits", msgID: current + 1, badCode: badMsgIDInvalidBits}, + {name: "empty fractional bits", msgID: time.Now().Unix() << 32, badCode: badMsgIDInvalidBits}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/internal/mtprotoedge/transient_push_test.go b/internal/mtprotoedge/transient_push_test.go index 1298ee69..4498fb8f 100644 --- a/internal/mtprotoedge/transient_push_test.go +++ b/internal/mtprotoedge/transient_push_test.go @@ -6,8 +6,8 @@ import ( "go.uber.org/zap/zaptest" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) // TestPushTransientSkipsNotReadySession 锁定不变量:transient 推送(typing/presence)对 diff --git a/internal/mtprotoedge/transport_compat.go b/internal/mtprotoedge/transport_compat.go index 83fee282..7b42229b 100644 --- a/internal/mtprotoedge/transport_compat.go +++ b/internal/mtprotoedge/transport_compat.go @@ -14,10 +14,10 @@ import ( "github.com/go-faster/errors" "go.uber.org/multierr" - "github.com/gotd/td/bin" - tdcrypto "github.com/gotd/td/crypto" - "github.com/gotd/td/proto/codec" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + tdcrypto "github.com/iamxvbaba/td/crypto" + "github.com/iamxvbaba/td/proto/codec" + "github.com/iamxvbaba/td/transport" ) const maxTransportMessageSize = 1 << 24 diff --git a/internal/mtprotoedge/transport_compat_test.go b/internal/mtprotoedge/transport_compat_test.go index 6bfd926a..ed56cbdb 100644 --- a/internal/mtprotoedge/transport_compat_test.go +++ b/internal/mtprotoedge/transport_compat_test.go @@ -8,7 +8,7 @@ import ( "testing" "time" - "github.com/gotd/td/bin" + "github.com/iamxvbaba/td/bin" ) type messageWriteTestConn struct { diff --git a/internal/mtprotoedge/transport_ownership.go b/internal/mtprotoedge/transport_ownership.go index 90f317b8..c86eae4a 100644 --- a/internal/mtprotoedge/transport_ownership.go +++ b/internal/mtprotoedge/transport_ownership.go @@ -6,8 +6,8 @@ import ( "sync/atomic" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/transport" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/transport" ) const ( diff --git a/internal/mtprotoedge/transport_ownership_test.go b/internal/mtprotoedge/transport_ownership_test.go index ee80403d..a4612b28 100644 --- a/internal/mtprotoedge/transport_ownership_test.go +++ b/internal/mtprotoedge/transport_ownership_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/gotd/td/bin" + "github.com/iamxvbaba/td/bin" ) type ownershipTestTransport struct { diff --git a/internal/rpc/account.go b/internal/rpc/account.go index 3dcaef45..45872759 100644 --- a/internal/rpc/account.go +++ b/internal/rpc/account.go @@ -5,7 +5,7 @@ import ( "errors" "strings" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ioscompat "telesrv/internal/compat/ios" "telesrv/internal/compat/tdesktop" diff --git a/internal/rpc/account_birthday_rpc_test.go b/internal/rpc/account_birthday_rpc_test.go index d398d039..059ad83a 100644 --- a/internal/rpc/account_birthday_rpc_test.go +++ b/internal/rpc/account_birthday_rpc_test.go @@ -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" diff --git a/internal/rpc/account_business.go b/internal/rpc/account_business.go index 87466de1..a5653f8c 100644 --- a/internal/rpc/account_business.go +++ b/internal/rpc/account_business.go @@ -5,7 +5,7 @@ import ( "errors" "strings" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/account_color_rpc_test.go b/internal/rpc/account_color_rpc_test.go index 9bef1e1b..ce25b711 100644 --- a/internal/rpc/account_color_rpc_test.go +++ b/internal/rpc/account_color_rpc_test.go @@ -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" diff --git a/internal/rpc/account_notify.go b/internal/rpc/account_notify.go index 3ce780c6..1e207539 100644 --- a/internal/rpc/account_notify.go +++ b/internal/rpc/account_notify.go @@ -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" diff --git a/internal/rpc/account_notify_rpc_test.go b/internal/rpc/account_notify_rpc_test.go index 3e27ef24..7731eed1 100644 --- a/internal/rpc/account_notify_rpc_test.go +++ b/internal/rpc/account_notify_rpc_test.go @@ -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" diff --git a/internal/rpc/account_phone.go b/internal/rpc/account_phone.go index c1d6b296..b96e5c01 100644 --- a/internal/rpc/account_phone.go +++ b/internal/rpc/account_phone.go @@ -5,7 +5,7 @@ import ( "go.uber.org/zap" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/account_phone_rpc_test.go b/internal/rpc/account_phone_rpc_test.go index f0ce8fcc..6a8c5450 100644 --- a/internal/rpc/account_phone_rpc_test.go +++ b/internal/rpc/account_phone_rpc_test.go @@ -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" diff --git a/internal/rpc/account_profile_emoji_test.go b/internal/rpc/account_profile_emoji_test.go index ee6d87e5..f1d1e8ef 100644 --- a/internal/rpc/account_profile_emoji_test.go +++ b/internal/rpc/account_profile_emoji_test.go @@ -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" diff --git a/internal/rpc/account_settings_rpc_test.go b/internal/rpc/account_settings_rpc_test.go index 628825b5..67134377 100644 --- a/internal/rpc/account_settings_rpc_test.go +++ b/internal/rpc/account_settings_rpc_test.go @@ -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" diff --git a/internal/rpc/account_themes.go b/internal/rpc/account_themes.go index 060661ee..59d384d9 100644 --- a/internal/rpc/account_themes.go +++ b/internal/rpc/account_themes.go @@ -4,7 +4,7 @@ import ( "context" "strings" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" diff --git a/internal/rpc/account_themes_compat.go b/internal/rpc/account_themes_compat.go deleted file mode 100644 index b2c34e00..00000000 --- a/internal/rpc/account_themes_compat.go +++ /dev/null @@ -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) -} diff --git a/internal/rpc/account_themes_compat_test.go b/internal/rpc/account_themes_compat_test.go index 10dd319a..93618dbf 100644 --- a/internal/rpc/account_themes_compat_test.go +++ b/internal/rpc/account_themes_compat_test.go @@ -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) diff --git a/internal/rpc/account_themes_rpc_test.go b/internal/rpc/account_themes_rpc_test.go index aa8b5287..f4fed48d 100644 --- a/internal/rpc/account_themes_rpc_test.go +++ b/internal/rpc/account_themes_rpc_test.go @@ -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" diff --git a/internal/rpc/admin_hooks.go b/internal/rpc/admin_hooks.go index f33a0923..51caf393 100644 --- a/internal/rpc/admin_hooks.go +++ b/internal/rpc/admin_hooks.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/aicompose.go b/internal/rpc/aicompose.go index 08fcd8c6..e445202c 100644 --- a/internal/rpc/aicompose.go +++ b/internal/rpc/aicompose.go @@ -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" ) diff --git a/internal/rpc/aicompose_rpc_test.go b/internal/rpc/aicompose_rpc_test.go index babd629a..c707bfe5 100644 --- a/internal/rpc/aicompose_rpc_test.go +++ b/internal/rpc/aicompose_rpc_test.go @@ -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" diff --git a/internal/rpc/android_compat_test.go b/internal/rpc/android_compat_test.go index 1e389e89..1f4c901c 100644 --- a/internal/rpc/android_compat_test.go +++ b/internal/rpc/android_compat_test.go @@ -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,7 +105,7 @@ 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 + // Routed through the generated static client overlay + the normal gotd // dispatcher, which boxes a class result (auth.Authorization) as *...Box. box, ok := enc.(*tg.AuthAuthorizationBox) if !ok { @@ -160,7 +160,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}, diff --git a/internal/rpc/android_private_layer_gate_test.go b/internal/rpc/android_private_layer_gate_test.go new file mode 100644 index 00000000..4d13eb8a --- /dev/null +++ b/internal/rpc/android_private_layer_gate_test.go @@ -0,0 +1,282 @@ +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" + + compatandroid "telesrv/internal/compat/android" +) + +type androidPrivateLayerFixture struct { + name string + privateID uint32 + semantic tg.LayerSemanticID + 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(tg.LayerProfileCanonical, &private, tg.LayerDecodeLimits{}) + 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 := tg.LayerWireID(tg.LayerProfileCanonical, 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 []tg.LayerProfile{tg.LayerProfile227, tg.LayerProfile228} { + 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, tg.LayerDecodeLimits{}) + 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 := tg.LayerSemanticName(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 := tg.LayerWireID(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: tg.LayerSemanticMethodMessagesForwardMessages, method: "messages.forwardMessages", + wire: func(*testing.T) []byte { return androidPrivateForwardMessagesWire() }, + }, + { + name: "channels.inviteToChannel_alias", privateID: 0x199f3a6c, + semantic: tg.LayerSemanticMethodChannelsInviteToChannel, 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: tg.LayerSemanticMethodUpdatesGetDifference, 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: tg.LayerSemanticMethodMessagesCreateChat, 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: tg.LayerSemanticMethodMessagesUploadMedia, 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: tg.LayerSemanticMethodAuthSignUp, 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: tg.LayerSemanticMethodMessagesGetMessages, 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: tg.LayerSemanticMethodChannelsGetMessages, 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: tg.LayerSemanticMethodBotsExportBotToken, 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: tg.LayerSemanticMethodAccountRegisterDevice, 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: tg.LayerSemanticMethodContactsSearch, 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: tg.LayerSemanticMethodLangpackGetLangPack, 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: tg.LayerSemanticMethodLangpackGetStrings, 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: tg.LayerSemanticMethodLangpackGetLanguages, 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: tg.LayerSemanticMethodMessagesEditChatCreator, 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() +} diff --git a/internal/rpc/auth.go b/internal/rpc/auth.go index 7977788b..0eb4f8e9 100644 --- a/internal/rpc/auth.go +++ b/internal/rpc/auth.go @@ -10,8 +10,8 @@ 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" "telesrv/internal/app/auth" "telesrv/internal/domain" @@ -54,6 +54,12 @@ func (r *Router) registerAuth(d *tg.ServerDispatcher) { // 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,23 +77,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) } + // 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 { - permID := authKeyIDFromInt64(req.PermAuthKeyID) if all, ok := r.deps.Sessions.(RawAuthKeySessionBinder); ok { all.BindAuthKeyForRawAuthKey(id, permID) } else { r.deps.Sessions.BindAuthKeyForSession(id, sessionID, permID) } } - r.invalidateAuthUserCache(id) + 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) { diff --git a/internal/rpc/auth_code_rate_limit_test.go b/internal/rpc/auth_code_rate_limit_test.go index 566f1d87..f4ed92a6 100644 --- a/internal/rpc/auth_code_rate_limit_test.go +++ b/internal/rpc/auth_code_rate_limit_test.go @@ -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" diff --git a/internal/rpc/auth_gate.go b/internal/rpc/auth_gate.go index e1ca9078..4beaf504 100644 --- a/internal/rpc/auth_gate.go +++ b/internal/rpc/auth_gate.go @@ -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 diff --git a/internal/rpc/auth_login_email_rpc_test.go b/internal/rpc/auth_login_email_rpc_test.go index 53c3dc16..55ae0a0f 100644 --- a/internal/rpc/auth_login_email_rpc_test.go +++ b/internal/rpc/auth_login_email_rpc_test.go @@ -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" diff --git a/internal/rpc/auth_password_pending_test.go b/internal/rpc/auth_password_pending_test.go index fe47b96e..69fb57c5 100644 --- a/internal/rpc/auth_password_pending_test.go +++ b/internal/rpc/auth_password_pending_test.go @@ -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" diff --git a/internal/rpc/auth_qr_login_test.go b/internal/rpc/auth_qr_login_test.go index d20ae378..ab4cad2a 100644 --- a/internal/rpc/auth_qr_login_test.go +++ b/internal/rpc/auth_qr_login_test.go @@ -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" diff --git a/internal/rpc/bootstrap_updates.go b/internal/rpc/bootstrap_updates.go index 91ae2f9b..052dc02a 100644 --- a/internal/rpc/bootstrap_updates.go +++ b/internal/rpc/bootstrap_updates.go @@ -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 { diff --git a/internal/rpc/botapi_gateway_test.go b/internal/rpc/botapi_gateway_test.go index 7cb23d4c..277a4ad6 100644 --- a/internal/rpc/botapi_gateway_test.go +++ b/internal/rpc/botapi_gateway_test.go @@ -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" diff --git a/internal/rpc/bots.go b/internal/rpc/bots.go index 51ea5c9d..63bb3357 100644 --- a/internal/rpc/bots.go +++ b/internal/rpc/bots.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/bots_callback.go b/internal/rpc/bots_callback.go index 304a8806..948393e8 100644 --- a/internal/rpc/bots_callback.go +++ b/internal/rpc/bots_callback.go @@ -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" ) diff --git a/internal/rpc/bots_errors.go b/internal/rpc/bots_errors.go index abed13cd..952f84af 100644 --- a/internal/rpc/bots_errors.go +++ b/internal/rpc/bots_errors.go @@ -3,7 +3,7 @@ package rpc import ( "errors" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tgerr" "telesrv/internal/domain" ) diff --git a/internal/rpc/bots_group_rpc_test.go b/internal/rpc/bots_group_rpc_test.go index 889fdfe5..a8698b64 100644 --- a/internal/rpc/bots_group_rpc_test.go +++ b/internal/rpc/bots_group_rpc_test.go @@ -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" diff --git a/internal/rpc/bots_hooks.go b/internal/rpc/bots_hooks.go index 98ee6353..2241017f 100644 --- a/internal/rpc/bots_hooks.go +++ b/internal/rpc/bots_hooks.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/bots_hooks_test.go b/internal/rpc/bots_hooks_test.go index 5c49edbc..3cc51bc0 100644 --- a/internal/rpc/bots_hooks_test.go +++ b/internal/rpc/bots_hooks_test.go @@ -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" diff --git a/internal/rpc/bots_inline.go b/internal/rpc/bots_inline.go index fd9672aa..e96bbca6 100644 --- a/internal/rpc/bots_inline.go +++ b/internal/rpc/bots_inline.go @@ -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" diff --git a/internal/rpc/bots_inline_message_id.go b/internal/rpc/bots_inline_message_id.go index d0899ebf..c5668523 100644 --- a/internal/rpc/bots_inline_message_id.go +++ b/internal/rpc/bots_inline_message_id.go @@ -5,7 +5,7 @@ import ( "crypto/sha256" "encoding/binary" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/bots_inline_rpc_test.go b/internal/rpc/bots_inline_rpc_test.go index efba7077..42ad7798 100644 --- a/internal/rpc/bots_inline_rpc_test.go +++ b/internal/rpc/bots_inline_rpc_test.go @@ -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" diff --git a/internal/rpc/bots_longtail.go b/internal/rpc/bots_longtail.go index d7b5a22b..097cb8b8 100644 --- a/internal/rpc/bots_longtail.go +++ b/internal/rpc/bots_longtail.go @@ -13,7 +13,7 @@ import ( "strings" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/bots_longtail_rpc_test.go b/internal/rpc/bots_longtail_rpc_test.go index 9c3187ce..ac647f30 100644 --- a/internal/rpc/bots_longtail_rpc_test.go +++ b/internal/rpc/bots_longtail_rpc_test.go @@ -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" ) diff --git a/internal/rpc/bots_rpc_test.go b/internal/rpc/bots_rpc_test.go index ff192de5..afaf5b6a 100644 --- a/internal/rpc/bots_rpc_test.go +++ b/internal/rpc/bots_rpc_test.go @@ -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" diff --git a/internal/rpc/bots_startbot.go b/internal/rpc/bots_startbot.go index 6322df17..0f46499a 100644 --- a/internal/rpc/bots_startbot.go +++ b/internal/rpc/bots_startbot.go @@ -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" ) diff --git a/internal/rpc/channel_fanout_classifier_test.go b/internal/rpc/channel_fanout_classifier_test.go index d5346ad3..da4ac3d2 100644 --- a/internal/rpc/channel_fanout_classifier_test.go +++ b/internal/rpc/channel_fanout_classifier_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/channel_fanout_dispatcher.go b/internal/rpc/channel_fanout_dispatcher.go index 7b4e37d8..076351a4 100644 --- a/internal/rpc/channel_fanout_dispatcher.go +++ b/internal/rpc/channel_fanout_dispatcher.go @@ -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" diff --git a/internal/rpc/channel_fanout_dispatcher_test.go b/internal/rpc/channel_fanout_dispatcher_test.go index 11f84e96..44135338 100644 --- a/internal/rpc/channel_fanout_dispatcher_test.go +++ b/internal/rpc/channel_fanout_dispatcher_test.go @@ -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() diff --git a/internal/rpc/channel_fanout_privacy_bot_rpc_test.go b/internal/rpc/channel_fanout_privacy_bot_rpc_test.go index 3da5deea..be0fb052 100644 --- a/internal/rpc/channel_fanout_privacy_bot_rpc_test.go +++ b/internal/rpc/channel_fanout_privacy_bot_rpc_test.go @@ -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" diff --git a/internal/rpc/channel_full_bot_cache.go b/internal/rpc/channel_full_bot_cache.go index d40fe6f0..40bc5530 100644 --- a/internal/rpc/channel_full_bot_cache.go +++ b/internal/rpc/channel_full_bot_cache.go @@ -5,7 +5,7 @@ import ( "fmt" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/channels_admin_log_users_rpc_test.go b/internal/rpc/channels_admin_log_users_rpc_test.go index c5003505..708cbc59 100644 --- a/internal/rpc/channels_admin_log_users_rpc_test.go +++ b/internal/rpc/channels_admin_log_users_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_core.go b/internal/rpc/channels_core.go index c56ff7ed..d1c34e50 100644 --- a/internal/rpc/channels_core.go +++ b/internal/rpc/channels_core.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" "unicode/utf8" ) diff --git a/internal/rpc/channels_delete_monoforum_test.go b/internal/rpc/channels_delete_monoforum_test.go index d9ba1bb4..9d21acf1 100644 --- a/internal/rpc/channels_delete_monoforum_test.go +++ b/internal/rpc/channels_delete_monoforum_test.go @@ -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" diff --git a/internal/rpc/channels_dialogs.go b/internal/rpc/channels_dialogs.go index b704d719..62db939a 100644 --- a/internal/rpc/channels_dialogs.go +++ b/internal/rpc/channels_dialogs.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/channels_dialogs_rpc_test.go b/internal/rpc/channels_dialogs_rpc_test.go index bf89991d..07871390 100644 --- a/internal/rpc/channels_dialogs_rpc_test.go +++ b/internal/rpc/channels_dialogs_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_invite_errors_rpc_test.go b/internal/rpc/channels_invite_errors_rpc_test.go index bab696c0..239fbf47 100644 --- a/internal/rpc/channels_invite_errors_rpc_test.go +++ b/internal/rpc/channels_invite_errors_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_invites.go b/internal/rpc/channels_invites.go index 84ea32e6..dcd42742 100644 --- a/internal/rpc/channels_invites.go +++ b/internal/rpc/channels_invites.go @@ -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" ) diff --git a/internal/rpc/channels_invites_members_rpc_test.go b/internal/rpc/channels_invites_members_rpc_test.go index f6f520d2..2ee18378 100644 --- a/internal/rpc/channels_invites_members_rpc_test.go +++ b/internal/rpc/channels_invites_members_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_join_dialog_rpc_test.go b/internal/rpc/channels_join_dialog_rpc_test.go index 45918e19..006b460a 100644 --- a/internal/rpc/channels_join_dialog_rpc_test.go +++ b/internal/rpc/channels_join_dialog_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_leave_rpc_test.go b/internal/rpc/channels_leave_rpc_test.go index 91631f50..31e53c8a 100644 --- a/internal/rpc/channels_leave_rpc_test.go +++ b/internal/rpc/channels_leave_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_legacy_chat.go b/internal/rpc/channels_legacy_chat.go index 3174ec1c..9b15a651 100644 --- a/internal/rpc/channels_legacy_chat.go +++ b/internal/rpc/channels_legacy_chat.go @@ -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" diff --git a/internal/rpc/channels_legacy_settings_rpc_test.go b/internal/rpc/channels_legacy_settings_rpc_test.go index 459b7a95..5a70c5da 100644 --- a/internal/rpc/channels_legacy_settings_rpc_test.go +++ b/internal/rpc/channels_legacy_settings_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_member_rank_rpc_test.go b/internal/rpc/channels_member_rank_rpc_test.go index ffc95f77..d95c3aaf 100644 --- a/internal/rpc/channels_member_rank_rpc_test.go +++ b/internal/rpc/channels_member_rank_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_members.go b/internal/rpc/channels_members.go index f8d2d742..7ec4b87d 100644 --- a/internal/rpc/channels_members.go +++ b/internal/rpc/channels_members.go @@ -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" diff --git a/internal/rpc/channels_messages.go b/internal/rpc/channels_messages.go index d333dbe1..d5ee8fa3 100644 --- a/internal/rpc/channels_messages.go +++ b/internal/rpc/channels_messages.go @@ -8,7 +8,7 @@ import ( "strings" "unicode/utf8" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/channels_messages_rpc_test.go b/internal/rpc/channels_messages_rpc_test.go index d7d20f36..fb06e9cd 100644 --- a/internal/rpc/channels_messages_rpc_test.go +++ b/internal/rpc/channels_messages_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_multi_pin_android_rpc_test.go b/internal/rpc/channels_multi_pin_android_rpc_test.go index 95fda8c0..2d62092b 100644 --- a/internal/rpc/channels_multi_pin_android_rpc_test.go +++ b/internal/rpc/channels_multi_pin_android_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_passive_stubs_rpc_test.go b/internal/rpc/channels_passive_stubs_rpc_test.go index e0ebc7c9..f31be6ea 100644 --- a/internal/rpc/channels_passive_stubs_rpc_test.go +++ b/internal/rpc/channels_passive_stubs_rpc_test.go @@ -1,7 +1,7 @@ package rpc import ( - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "strings" "telesrv/internal/domain" "testing" diff --git a/internal/rpc/channels_public_preview_rpc_test.go b/internal/rpc/channels_public_preview_rpc_test.go index 3792e5ce..cce1cd24 100644 --- a/internal/rpc/channels_public_preview_rpc_test.go +++ b/internal/rpc/channels_public_preview_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_read_reactions.go b/internal/rpc/channels_read_reactions.go index 75d0110a..02a16152 100644 --- a/internal/rpc/channels_read_reactions.go +++ b/internal/rpc/channels_read_reactions.go @@ -3,7 +3,7 @@ package rpc import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/channels_register.go b/internal/rpc/channels_register.go index 888581ad..6be28641 100644 --- a/internal/rpc/channels_register.go +++ b/internal/rpc/channels_register.go @@ -1,7 +1,7 @@ package rpc import ( - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) // registerChannels 注册超级群/频道相关 RPC。messages.createChat 在这里注册, diff --git a/internal/rpc/channels_send_as_foreign_rpc_test.go b/internal/rpc/channels_send_as_foreign_rpc_test.go index 1ba1fa46..1856091f 100644 --- a/internal/rpc/channels_send_as_foreign_rpc_test.go +++ b/internal/rpc/channels_send_as_foreign_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_settings.go b/internal/rpc/channels_settings.go index 116692fa..fde35b8e 100644 --- a/internal/rpc/channels_settings.go +++ b/internal/rpc/channels_settings.go @@ -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" diff --git a/internal/rpc/channels_settings_rpc_test.go b/internal/rpc/channels_settings_rpc_test.go index 6c7289cb..8dd378b1 100644 --- a/internal/rpc/channels_settings_rpc_test.go +++ b/internal/rpc/channels_settings_rpc_test.go @@ -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" diff --git a/internal/rpc/channels_state_mutation.go b/internal/rpc/channels_state_mutation.go index 665be41a..8495869f 100644 --- a/internal/rpc/channels_state_mutation.go +++ b/internal/rpc/channels_state_mutation.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/channels_stubs.go b/internal/rpc/channels_stubs.go index f6d7a36a..57d52322 100644 --- a/internal/rpc/channels_stubs.go +++ b/internal/rpc/channels_stubs.go @@ -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 { diff --git a/internal/rpc/channels_topics.go b/internal/rpc/channels_topics.go index cfbdb818..0b769fe8 100644 --- a/internal/rpc/channels_topics.go +++ b/internal/rpc/channels_topics.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/channels_updates.go b/internal/rpc/channels_updates.go index c7db7409..22072256 100644 --- a/internal/rpc/channels_updates.go +++ b/internal/rpc/channels_updates.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/channels_updates_rpc_test.go b/internal/rpc/channels_updates_rpc_test.go index 736e7506..b05d0b08 100644 --- a/internal/rpc/channels_updates_rpc_test.go +++ b/internal/rpc/channels_updates_rpc_test.go @@ -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" diff --git a/internal/rpc/chat_automation_rpc_test.go b/internal/rpc/chat_automation_rpc_test.go index 4216f4e2..93a40b83 100644 --- a/internal/rpc/chat_automation_rpc_test.go +++ b/internal/rpc/chat_automation_rpc_test.go @@ -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" diff --git a/internal/rpc/chatlists.go b/internal/rpc/chatlists.go index c9a78320..628b1fa5 100644 --- a/internal/rpc/chatlists.go +++ b/internal/rpc/chatlists.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/chatlists_rpc_test.go b/internal/rpc/chatlists_rpc_test.go index e63384ec..ac1b6b62 100644 --- a/internal/rpc/chatlists_rpc_test.go +++ b/internal/rpc/chatlists_rpc_test.go @@ -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" diff --git a/internal/rpc/compat.go b/internal/rpc/compat.go index fa0a09d7..6de295e4 100644 --- a/internal/rpc/compat.go +++ b/internal/rpc/compat.go @@ -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 diff --git a/internal/rpc/contacts.go b/internal/rpc/contacts.go index 38bd6ebc..2ba5f792 100644 --- a/internal/rpc/contacts.go +++ b/internal/rpc/contacts.go @@ -7,7 +7,7 @@ import ( "strings" "unicode/utf8" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/app/contacts" diff --git a/internal/rpc/contacts_users_projection_test.go b/internal/rpc/contacts_users_projection_test.go index 9a1edd14..54be0dfa 100644 --- a/internal/rpc/contacts_users_projection_test.go +++ b/internal/rpc/contacts_users_projection_test.go @@ -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" diff --git a/internal/rpc/contacts_users_rpc_test.go b/internal/rpc/contacts_users_rpc_test.go index 0f6e625c..f7630e3c 100644 --- a/internal/rpc/contacts_users_rpc_test.go +++ b/internal/rpc/contacts_users_rpc_test.go @@ -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" diff --git a/internal/rpc/context.go b/internal/rpc/context.go index 0049f1e3..69e1e40c 100644 --- a/internal/rpc/context.go +++ b/internal/rpc/context.go @@ -4,6 +4,8 @@ import ( "context" "regexp" "strings" + + "github.com/iamxvbaba/td/tg" ) type ctxKey int @@ -31,7 +33,7 @@ func inboundRPCBytesFrom(ctx context.Context) int { return v } -const currentClientLayer = 227 +const currentClientLayer = tg.Layer var androidSDKVersionRE = regexp.MustCompile(`\bsdk\s+\d+\b`) diff --git a/internal/rpc/convert_business.go b/internal/rpc/convert_business.go index e86bbb2b..3b3d87b6 100644 --- a/internal/rpc/convert_business.go +++ b/internal/rpc/convert_business.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_channels_core.go b/internal/rpc/convert_channels_core.go index 23d77ca6..bbc5e649 100644 --- a/internal/rpc/convert_channels_core.go +++ b/internal/rpc/convert_channels_core.go @@ -1,7 +1,7 @@ package rpc import ( - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_channels_core_test.go b/internal/rpc/convert_channels_core_test.go index e6cc9709..9855d1cc 100644 --- a/internal/rpc/convert_channels_core_test.go +++ b/internal/rpc/convert_channels_core_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_dialogs.go b/internal/rpc/convert_dialogs.go index f272be2c..ca72a92a 100644 --- a/internal/rpc/convert_dialogs.go +++ b/internal/rpc/convert_dialogs.go @@ -1,7 +1,7 @@ package rpc import ( - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_encrypted.go b/internal/rpc/convert_encrypted.go index 6a9d2555..755ea3be 100644 --- a/internal/rpc/convert_encrypted.go +++ b/internal/rpc/convert_encrypted.go @@ -3,7 +3,7 @@ package rpc import ( "encoding/binary" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_encrypted_test.go b/internal/rpc/convert_encrypted_test.go index d60c35c0..56980628 100644 --- a/internal/rpc/convert_encrypted_test.go +++ b/internal/rpc/convert_encrypted_test.go @@ -5,7 +5,7 @@ import ( "encoding/binary" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_markup.go b/internal/rpc/convert_markup.go index bc963e74..127df4fd 100644 --- a/internal/rpc/convert_markup.go +++ b/internal/rpc/convert_markup.go @@ -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" ) diff --git a/internal/rpc/convert_media.go b/internal/rpc/convert_media.go index edd6fabb..784df441 100644 --- a/internal/rpc/convert_media.go +++ b/internal/rpc/convert_media.go @@ -3,7 +3,7 @@ package rpc import ( "strings" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_media_webpage_test.go b/internal/rpc/convert_media_webpage_test.go index ea63d7b0..f7901212 100644 --- a/internal/rpc/convert_media_webpage_test.go +++ b/internal/rpc/convert_media_webpage_test.go @@ -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" ) diff --git a/internal/rpc/convert_messages.go b/internal/rpc/convert_messages.go index cee1b6e3..7cb91901 100644 --- a/internal/rpc/convert_messages.go +++ b/internal/rpc/convert_messages.go @@ -1,7 +1,7 @@ package rpc import ( - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_misc.go b/internal/rpc/convert_misc.go index 15d1d330..52f4f7b8 100644 --- a/internal/rpc/convert_misc.go +++ b/internal/rpc/convert_misc.go @@ -2,7 +2,7 @@ package rpc import ( "encoding/json" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "sort" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_passkey.go b/internal/rpc/convert_passkey.go index 4c114d15..cea7367c 100644 --- a/internal/rpc/convert_passkey.go +++ b/internal/rpc/convert_passkey.go @@ -3,7 +3,7 @@ package rpc import ( "encoding/base64" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_phone.go b/internal/rpc/convert_phone.go index c4b5e5bc..de57d440 100644 --- a/internal/rpc/convert_phone.go +++ b/internal/rpc/convert_phone.go @@ -1,7 +1,7 @@ package rpc import ( - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_phone_group.go b/internal/rpc/convert_phone_group.go index 4b89979f..a621c2e9 100644 --- a/internal/rpc/convert_phone_group.go +++ b/internal/rpc/convert_phone_group.go @@ -5,7 +5,7 @@ import ( "fmt" "strconv" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" "telesrv/internal/sfu" diff --git a/internal/rpc/convert_polls.go b/internal/rpc/convert_polls.go index 3cf3aa9f..e9faa678 100644 --- a/internal/rpc/convert_polls.go +++ b/internal/rpc/convert_polls.go @@ -6,7 +6,7 @@ import ( "strings" "unicode/utf8" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_rich_message.go b/internal/rpc/convert_rich_message.go index a9265d4a..5397e13b 100644 --- a/internal/rpc/convert_rich_message.go +++ b/internal/rpc/convert_rich_message.go @@ -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" ) diff --git a/internal/rpc/convert_stories.go b/internal/rpc/convert_stories.go index 226341df..517718d8 100644 --- a/internal/rpc/convert_stories.go +++ b/internal/rpc/convert_stories.go @@ -1,7 +1,7 @@ package rpc import ( - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_test.go b/internal/rpc/convert_test.go index 0e3f9916..50bea886 100644 --- a/internal/rpc/convert_test.go +++ b/internal/rpc/convert_test.go @@ -3,8 +3,8 @@ package rpc import ( "testing" - "github.com/gotd/td/bin" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_theme.go b/internal/rpc/convert_theme.go index 23f1caeb..e8fcf7ce 100644 --- a/internal/rpc/convert_theme.go +++ b/internal/rpc/convert_theme.go @@ -4,7 +4,7 @@ import ( "context" "sort" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_updates.go b/internal/rpc/convert_updates.go index bdd6d8aa..0a65d45d 100644 --- a/internal/rpc/convert_updates.go +++ b/internal/rpc/convert_updates.go @@ -1,7 +1,7 @@ package rpc import ( - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_updates_pin_service_test.go b/internal/rpc/convert_updates_pin_service_test.go index f25a602c..c804bc5c 100644 --- a/internal/rpc/convert_updates_pin_service_test.go +++ b/internal/rpc/convert_updates_pin_service_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_users.go b/internal/rpc/convert_users.go index 037e8ce1..9ccb617c 100644 --- a/internal/rpc/convert_users.go +++ b/internal/rpc/convert_users.go @@ -3,7 +3,7 @@ package rpc import ( "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/convert_users_premium_test.go b/internal/rpc/convert_users_premium_test.go index eb4d9bda..7d8ad0b6 100644 --- a/internal/rpc/convert_users_premium_test.go +++ b/internal/rpc/convert_users_premium_test.go @@ -4,7 +4,7 @@ import ( "testing" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/deps.go b/internal/rpc/deps.go index 6f4352e8..6643036d 100644 --- a/internal/rpc/deps.go +++ b/internal/rpc/deps.go @@ -4,8 +4,8 @@ import ( "context" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" "telesrv/internal/sfu" @@ -40,7 +40,6 @@ type AuthService interface { SignInBot(ctx context.Context, a domain.Authorization, token string) (domain.User, error) LogOut(ctx context.Context, authKeyID [8]byte) error Authorization(ctx context.Context, authKeyID [8]byte) (domain.Authorization, bool, error) - UpdateAuthorizationLayer(ctx context.Context, authKeyID [8]byte, layer int) error AuthKeyClientInfo(ctx context.Context, authKeyID [8]byte) (domain.AuthKeyClientInfo, bool, error) UpdateAuthKeyClientInfo(ctx context.Context, authKeyID [8]byte, info domain.AuthKeyClientInfo) error ListAuthorizations(ctx context.Context, userID int64) ([]domain.Authorization, error) @@ -60,9 +59,9 @@ type SessionBinder interface { UserIDResolvedForAuthKey(rawAuthKeyID [8]byte, sessionID int64) (userID int64, resolved bool) UnbindAuthKey(authKeyID [8]byte) int SetReceivesUpdatesForAuthKey(rawAuthKeyID [8]byte, sessionID int64, receives bool) - PushToSessionForAuthKey(ctx context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg bin.Encoder) error + PushToSessionForAuthKey(ctx context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error // excludeAuthKeyID/excludeSessionID 必须同时为零(不排除)或同时非零(精确排除)。 - PushToUserExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder) (int, error) + PushToUserExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) } // RawAuthKeySessionBinder 在 auth.bindTempAuthKey 成功后,把同一 raw temporary key @@ -83,7 +82,7 @@ type RawAuthKeyMetadataProvider interface { // 它绕过登录后 updates-ready 队列,只能用于会解锁登录流程本身的握手消息, // 例如 updateLoginToken。 type ImmediateSessionPusher interface { - PushToSessionForAuthKeyImmediate(ctx context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg bin.Encoder) error + PushToSessionForAuthKeyImmediate(ctx context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error } // SessionUpdatesStateProvider 暴露连接当前的 updates 接收状态(可选能力)。 @@ -100,6 +99,52 @@ type ClientLayerBinder interface { SetClientLayerForAuthKey(rawAuthKeyID [8]byte, sessionID int64, layer int) } +// AuthKeyLayerBinder seeds an inherited auth-key default into every live +// session that still has no explicit invokeWithLayer observation. Implementors +// must not overwrite an explicit per-session profile; the returned count is +// diagnostic only. +// +// Router uses this optional capability after auth.bindTempAuthKey normalizes a +// raw temporary key to its permanent identity. Keeping it separate from +// ClientLayerBinder makes the source distinction explicit: inherited defaults +// are mutable initialization state, while an explicit session observation is a +// correction for exactly one logical session. +type AuthKeyLayerBinder interface { + SeedInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte, layer int) int +} + +// BusinessAuthKeyLayerBinder seeds unknown live sessions across every raw PFS +// key currently normalized to the same permanent/business auth key. +type BusinessAuthKeyLayerBinder interface { + SeedInheritedLayerForBusinessAuthKey(authKeyID [8]byte, layer int) int +} + +// AuthKeyLayerRefresher is the identity-normalization variant used after +// auth.bindTempAuthKey. It may replace an inherited raw-key shadow with the +// permanent key's default, but must still preserve every explicit session +// profile. +type AuthKeyLayerRefresher interface { + RefreshInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte, layer int) int +} + +// AuthKeyInheritedLayerClearer removes only the mutable inherited default for +// a physical/raw key. Explicit per-session invokeWithLayer profiles are wire +// evidence and must survive. Router uses this when a temp key binds to a +// permanent key whose durable Layer is authoritative but unsupported by this +// binary; retaining the raw key's older inherited default would silently +// downgrade naked RPCs instead of asking the client to correct explicitly. +type AuthKeyInheritedLayerClearer interface { + ClearInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte) int +} + +// ActiveSessionLayerEvidenceProvider exposes the live connection's explicit +// profile when auth.bindTempAuthKey runs after the Router's bounded exact- +// profile retention window. It is deliberately session-scoped and must never +// report an inherited profile as explicit evidence. +type ActiveSessionLayerEvidenceProvider interface { + ExplicitLayerEvidenceForAuthKey(rawAuthKeyID [8]byte, sessionID int64) (layer int, msgID int64, ok bool) +} + // SessionTerminator 暴露按业务 auth_key 强制断开活跃连接的能力(可选)。 // 授权撤销(被踢设备)必须断开连接:出站推送用连接持有的密钥加密、不回查授权, // perm-key 连接的授权缓存也只有断开重连才会重新回查授权表。 @@ -117,22 +162,22 @@ type RawSessionTerminator interface { // BestEffortSessionBinder 是带 raw auth_key_id 精确排除当前设备的短超时推送接口; // 不用于 RPC result/ack。 type BestEffortSessionBinder interface { - PushToUserExceptAuthKeySessionBestEffort(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder, timeout time.Duration) (int, error) + PushToUserExceptAuthKeySessionBestEffort(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error) } // TransientSessionBinder 推送短命、不写 durable log 的 update(typing / presence)。 // 与普通推送的关键区别:目标 session 未就绪时直接跳过、不进 pending——transient 数据 // getDifference 无法补,就绪后由 getState 快照/下次状态变化重建,囤积过期 transient 无意义。 type TransientSessionBinder interface { - PushToUserTransientExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder, timeout time.Duration) (int, error) + PushToUserTransientExceptAuthKeySession(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error) } // AuthKeyTargetedSessionBinder 把 update 定向投递给某用户【绑定到具体 business auth_key // 这台设备】的就绪连接(密聊设备级投递)。SessionManager 实现;测试替身/未装配时 // rpc 层回退账号级推送。未就绪连接跳过、不进 pending(密聊离线靠 getDifference 补)。 type AuthKeyTargetedSessionBinder interface { - PushToUserAuthKey(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg bin.Encoder) (int, error) - PushToUserAuthKeyTransient(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg bin.Encoder, timeout time.Duration) (int, error) + PushToUserAuthKey(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg tg.UpdatesClass) (int, error) + PushToUserAuthKeyTransient(ctx context.Context, userID int64, businessAuthKeyID [8]byte, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error) } // OnlineUserProvider exposes a bounded runtime snapshot for best-effort fanout. @@ -346,8 +391,9 @@ type UpdatesService interface { GetState(ctx context.Context, authKeyID [8]byte, userID int64) (domain.UpdateState, error) CurrentState(ctx context.Context, userID int64) (domain.UpdateState, error) ConfirmedState(ctx context.Context, authKeyID [8]byte, userID int64) (domain.UpdateState, bool, error) - AcknowledgeCurrentState(ctx context.Context, authKeyID [8]byte, userID int64) (domain.UpdateState, error) + ObserveDifferenceRequest(ctx context.Context, authKeyID [8]byte, userID int64, from domain.UpdateState) (domain.UpdateState, error) GetDifference(ctx context.Context, authKeyID [8]byte, userID int64, from domain.UpdateState) (domain.UpdateDifference, error) + CommitDeliveredState(ctx context.Context, authKeyID [8]byte, userID int64, state domain.UpdateState, mode domain.UpdateStateCommitMode) error ClearAuthKey(ctx context.Context, authKeyID [8]byte) error RecordNewMessage(ctx context.Context, authKeyID [8]byte, userID int64, msg domain.Message) (domain.UpdateEvent, domain.UpdateState, error) PublishNewMessage(ctx context.Context, userID int64, msg domain.Message) (domain.UpdateEvent, domain.UpdateState, error) @@ -740,40 +786,44 @@ type AIComposeService interface { // Deps 按业务域注入服务接口。各域的 handler 注册见对应文件(auth.go / users.go / updates.go)。 type Deps struct { - Auth AuthService - Account AccountService - Privacy PrivacyService - Help HelpService - AICompose AIComposeService - Users UsersService - Updates UpdatesService - BootstrapUpdates store.BootstrapUpdateJobStore - BotAPIUpdates store.BotAPIUpdateStore - Contacts ContactsService - Dialogs DialogsService - Chatlists ChatlistsService - Messages MessagesService - Translation TranslationService - Stories StoriesService - Channels ChannelsService - Files FilesService - Bots BotsService - Polls PollsService - Phone PhoneService - GroupCalls GroupCallsService - LiveStreams LiveStreamsService - SFU sfu.Service - TURN turnsrv.Service - LangPack LangPackService - Sessions SessionBinder - Inline store.InlineRegistryStore - Limiter RateLimiter - Metrics Metrics - SecretChats SecretChatService - Stars StarsService - Gifts GiftsService - Passkey PasskeyService - Themes ThemeService + Auth AuthService + // AuthKeySessionLayers is the protocol-only durable ordering boundary for + // explicit invokeWithLayer evidence. Production must wire the same auth-key + // store used by the MTProto edge; nil is reserved for isolated router tests. + AuthKeySessionLayers store.AuthKeySessionLayerStore + Account AccountService + Privacy PrivacyService + Help HelpService + AICompose AIComposeService + Users UsersService + Updates UpdatesService + BootstrapUpdates store.BootstrapUpdateJobStore + BotAPIUpdates store.BotAPIUpdateStore + Contacts ContactsService + Dialogs DialogsService + Chatlists ChatlistsService + Messages MessagesService + Translation TranslationService + Stories StoriesService + Channels ChannelsService + Files FilesService + Bots BotsService + Polls PollsService + Phone PhoneService + GroupCalls GroupCallsService + LiveStreams LiveStreamsService + SFU sfu.Service + TURN turnsrv.Service + LangPack LangPackService + Sessions SessionBinder + Inline store.InlineRegistryStore + Limiter RateLimiter + Metrics Metrics + SecretChats SecretChatService + Stars StarsService + Gifts GiftsService + Passkey PasskeyService + Themes ThemeService } // ThemeService 抽象自定义云主题(app/themes):创建/更新/查询主题 + 维护每用户已安装列表。 diff --git a/internal/rpc/dialogs_monoforum_test.go b/internal/rpc/dialogs_monoforum_test.go index 571b5cc7..4565e29b 100644 --- a/internal/rpc/dialogs_monoforum_test.go +++ b/internal/rpc/dialogs_monoforum_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" "telesrv/internal/store/memory" ) diff --git a/internal/rpc/dialogs_rpc_test.go b/internal/rpc/dialogs_rpc_test.go index 224dc516..4d01c997 100644 --- a/internal/rpc/dialogs_rpc_test.go +++ b/internal/rpc/dialogs_rpc_test.go @@ -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" "reflect" "strings" diff --git a/internal/rpc/dispatch_context.go b/internal/rpc/dispatch_context.go new file mode 100644 index 00000000..99462a64 --- /dev/null +++ b/internal/rpc/dispatch_context.go @@ -0,0 +1,103 @@ +package rpc + +import ( + "context" + "time" + + "go.uber.org/zap" +) + +// prepareRPCDispatchContext resolves the physical/business auth-key boundary, +// current authorization and persisted client metadata once for both the +// historical canonical dispatcher and the generated exact-layer dispatcher. +// Wire admission stays outside this function so callers can reject malformed +// requests before any store lookup. +func (r *Router) prepareRPCDispatchContext( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + wireBytes int, + method string, +) (context.Context, *updatesDeliveryPlan, error) { + preStart := r.clock.Now() + ctx = withInboundRPCBytes(ctx, wireBytes) + ctx = WithRawAuthKeyID(ctx, rawAuthKeyID) + effectiveAuthKeyID, err := r.effectiveAuthKeyID(ctx, rawAuthKeyID, sessionID) + if err != nil { + return nil, nil, internalErr() + } + tAuth := r.clock.Now() + ctx = WithAuthKeyID(ctx, effectiveAuthKeyID) + ctx = WithSessionID(ctx, sessionID) + // Ignore caller-injected values. Exact same-session evidence wins; otherwise + // the durable auth-key default restored below initializes this new session. + // A generated admitted request still owns its immutable request/result + // profile independently of this mutable session default. + ctx = WithLayer(ctx, 0) + if layer, ok := r.NegotiatedSessionLayer(rawAuthKeyID, sessionID); ok { + ctx = WithLayer(ctx, layer) + } + userID, hasUserID, err := r.effectiveUserID(ctx, rawAuthKeyID, effectiveAuthKeyID, sessionID) + if err != nil { + return nil, nil, internalErr() + } + if hasUserID { + ctx = WithUserID(ctx, userID) + } + tUser := r.clock.Now() + info, hasClientMetadata, clientMetadataStored := r.clientSessionInfo(ctx) + lookupInfo := info + if effectiveAuthKeyID != rawAuthKeyID { + // Check markers and raw shadows belong to the physical temp key. They + // cannot suppress or outrank lookup of the canonical permanent default. + lookupInfo.authKeyInfoChecked = false + lookupInfo.authorizationChecked = false + if LayerFrom(ctx) == 0 { + lookupInfo.layer = 0 + info.layer = 0 + } + } + if authInfo, ok := r.clientSessionInfoFromAuthKey(ctx, effectiveAuthKeyID, lookupInfo); ok { + info = mergeClientSessionInfo(info, authInfo) + hasClientMetadata = true + r.rememberClientSessionInfo(ctx, info) + clientMetadataStored = true + } + if hasUserID { + lookupInfo = info + if effectiveAuthKeyID != rawAuthKeyID { + lookupInfo.authorizationChecked = false + } + if authInfo, ok := r.clientSessionInfoFromAuthorization(ctx, userID, effectiveAuthKeyID, lookupInfo); ok { + info = mergeClientSessionInfo(info, authInfo) + hasClientMetadata = true + r.rememberClientSessionInfo(ctx, info) + clientMetadataStored = true + } + } + if r.log != nil { + if tInfo := r.clock.Now(); tInfo.Sub(preStart) > 50*time.Millisecond { + r.log.Info("slow pre-handler", + zap.String("method", method), + zap.Duration("pre_total", tInfo.Sub(preStart)), + zap.Duration("auth_resolve", tAuth.Sub(preStart)), + zap.Duration("user_resolve", tUser.Sub(tAuth)), + zap.Duration("client_info", tInfo.Sub(tUser)), + zap.Int64("session_id", sessionID), + ) + } + } + if hasClientMetadata { + if !clientMetadataStored { + r.rememberClientSessionInfoIfMissing(ctx, info) + } + if info.hasClientInfo { + ctx = WithClientInfo(ctx, info.clientInfo) + } + if LayerFrom(ctx) == 0 && isSupportedLayer(info.layer) { + ctx = WithLayer(ctx, info.layer) + } + } + ctx, updatesDelivery := withUpdatesDeliveryPlan(ctx) + return ctx, updatesDelivery, nil +} diff --git a/internal/rpc/doc.go b/internal/rpc/doc.go index eb8041f7..d608ee68 100644 --- a/internal/rpc/doc.go +++ b/internal/rpc/doc.go @@ -1,5 +1,5 @@ // Package rpc 是按 TypeID 路由的 RPC 层:封装 tg.ServerDispatcher(或等价薄封装), -// 在 handler 边界把 gotd/td/tg 类型转换为内部 domain command/query,统一 tgerr.Error 到 +// 在 handler 边界把 iamxvbaba/td/tg 类型转换为内部 domain command/query,统一 tgerr.Error 到 // rpc_error 的映射,注入 auth_key_id/session_id/user_id/layer/设备/语言 等上下文, // 并对未知 RPC 进入 compatibility trace(不静默吞掉,记入 docs/compatibility-matrix.md)。 package rpc diff --git a/internal/rpc/durable_layer_evidence.go b/internal/rpc/durable_layer_evidence.go new file mode 100644 index 00000000..c6364c20 --- /dev/null +++ b/internal/rpc/durable_layer_evidence.go @@ -0,0 +1,248 @@ +package rpc + +import ( + "context" + "errors" + "fmt" + + "github.com/iamxvbaba/td/tg" + + "telesrv/internal/store" +) + +type layerEvidenceDurabilityUnavailableError struct { + cause error +} + +func (e *layerEvidenceDurabilityUnavailableError) Error() string { + return fmt.Sprintf("durable Layer evidence unavailable: %v", e.cause) +} + +func (e *layerEvidenceDurabilityUnavailableError) Unwrap() error { return e.cause } + +// LayerEvidenceDurabilityUnavailable is a structural marker consumed by the +// lower MTProto edge without importing rpc. It permits an explicit selector to +// remain connection-local during a transient store outage; conflicts and +// missing/destroyed auth keys never use this availability fallback. +func (*layerEvidenceDurabilityUnavailableError) LayerEvidenceDurabilityUnavailable() {} + +func wrapLayerEvidenceStoreAvailability(err error) error { + if err == nil || + errors.Is(err, store.ErrAuthKeySessionLayerConflict) || + errors.Is(err, store.ErrAuthKeySessionLayerInvalid) || + errors.Is(err, store.ErrAuthKeyNotFound) || + errors.Is(err, store.ErrAuthKeyBindingInvalid) { + return err + } + return &layerEvidenceDurabilityUnavailableError{cause: err} +} + +// ResolveNegotiatedSessionLayerEvidence is the restart-safe resolver used by +// the MTProto edge on a physical connection's first exact admission. When a +// durable store is configured it is authoritative on every resolve: another +// Router process may have advanced the same logical session since this +// process cached it. The local registry is only the no-store implementation or +// an availability fallback. A durable future Layer is returned verbatim but +// is not installed into the old binary's typed registry; the edge keeps its raw +// msg_id watermark so a newer supported invokeWithLayer can self-heal. +func (r *Router) ResolveNegotiatedSessionLayerEvidence( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, +) (layer int, msgID int64, found bool, err error) { + if r == nil || rawAuthKeyID == ([8]byte{}) || sessionID == 0 { + return 0, 0, false, nil + } + if r.deps.AuthKeySessionLayers == nil { + layer, msgID, found := r.NegotiatedSessionLayerEvidence(rawAuthKeyID, sessionID) + return layer, msgID, found, nil + } + localLayer, localMsgID, localFound := r.NegotiatedSessionLayerEvidence(rawAuthKeyID, sessionID) + value, found, err := r.deps.AuthKeySessionLayers.GetSessionLayer(ctx, rawAuthKeyID, sessionID) + if err != nil { + if localFound { + // This exact process observed the selector earlier. It is weaker than + // primary and is refreshed as soon as the store recovers, but remains a + // safe same-session availability fallback. Fresh explicit evidence still + // goes through durable Advance and becomes connection-local on failure. + return localLayer, localMsgID, true, nil + } + return 0, 0, false, wrapLayerEvidenceStoreAvailability(err) + } + if !found { + r.forgetCachedDurableSessionLayer(rawAuthKeyID, sessionID) + return 0, 0, false, nil + } + if value.MessageID <= 0 || value.Layer <= 0 || value.ObservationID <= 0 { + return 0, 0, false, store.ErrAuthKeySessionLayerInvalid + } + if err := r.cacheResolvedDurableSessionLayer(rawAuthKeyID, sessionID, value); err != nil { + return 0, 0, false, err + } + return value.Layer, value.MessageID, true, nil +} + +// AdvanceNegotiatedSessionLayerEvidence commits the same-session watermark and +// auth-key-wide default atomically before any connection/profile/readiness +// state is mutated. publishShared is true only when this observation is still +// the durable shared default; an old duplicate cannot overwrite a newer +// session's local cache after restart. +func (r *Router) AdvanceNegotiatedSessionLayerEvidence( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + layer int, + msgID int64, +) (currentLayer int, currentMsgID int64, publishShared bool, err error) { + if r == nil || rawAuthKeyID == ([8]byte{}) || sessionID == 0 || msgID <= 0 { + return 0, 0, false, store.ErrAuthKeySessionLayerInvalid + } + if r.deps.AuthKeySessionLayers == nil { + if _, err := r.FreezeNegotiatedSessionLayerAt(rawAuthKeyID, sessionID, layer, msgID); err != nil { + return 0, 0, false, err + } + currentLayer, currentMsgID, found := r.NegotiatedSessionLayerEvidence(rawAuthKeyID, sessionID) + if !found { + return 0, 0, false, fmt.Errorf("exact session Layer disappeared after in-memory advance") + } + return currentLayer, currentMsgID, currentLayer == layer && currentMsgID == msgID, nil + } + current, _, err := r.deps.AuthKeySessionLayers.AdvanceSessionLayer( + ctx, + rawAuthKeyID, + sessionID, + layer, + msgID, + ) + if err != nil { + if errors.Is(err, store.ErrAuthKeySessionLayerConflict) { + return current.Layer, current.MessageID, false, err + } + return 0, 0, false, wrapLayerEvidenceStoreAvailability(err) + } + if current.ObservationID <= 0 { + return 0, 0, false, store.ErrAuthKeySessionLayerInvalid + } + if err := r.cacheResolvedDurableSessionLayer(rawAuthKeyID, sessionID, current); err != nil { + return 0, 0, false, err + } + return current.Layer, current.MessageID, current.SharedDefault, nil +} + +// cacheResolvedDurableSessionLayer updates only the bounded typed accelerator; +// callers always return the store row itself as authority. Ordered replacement +// prevents an older read, which linearized immediately before a concurrent +// Advance, from rolling this process cache back after that Advance completed. +func (r *Router) cacheResolvedDurableSessionLayer( + rawAuthKeyID [8]byte, + sessionID int64, + value store.AuthKeySessionLayer, +) error { + if r == nil { + return nil + } + key := clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} + profile, supported := tg.ResolveLayerProfile(value.Layer) + if !supported || int(profile) != value.Layer { + // A newer binary may have persisted a future profile. Never leave an old + // typed codec shadow beside that raw authoritative watermark. Observation + // order still protects a concurrent newer supported Advance from an older + // in-flight read of this future row. + r.exactProfileMu.Lock() + if current, exists := r.exactProfiles[key]; exists && r.clock.Now().Before(current.expiresAt) { + if current.observationID > value.ObservationID && value.ObservationID > 0 { + r.exactProfileMu.Unlock() + return nil + } + if current.observationID == value.ObservationID && value.ObservationID > 0 { + r.exactProfileMu.Unlock() + return fmt.Errorf("%w: observation %d maps to supported Layer %d and raw Layer %d", + store.ErrAuthKeySessionLayerConflict, value.ObservationID, current.layer, value.Layer) + } + } + delete(r.exactProfiles, key) + r.exactProfileMu.Unlock() + return nil + } + now := r.clock.Now() + expiresAt := value.ExpiresAt + if expiresAt.IsZero() { + expiresAt = exactSessionLayerEvidenceExpiry(now, value.MessageID) + } + entry := exactSessionProfileEntry{ + layer: value.Layer, msgID: value.MessageID, + observationID: value.ObservationID, expiresAt: expiresAt, + } + r.exactProfileMu.Lock() + defer r.exactProfileMu.Unlock() + if r.exactProfiles == nil { + r.exactProfiles = make(map[clientInfoSessionKey]exactSessionProfileEntry) + } + if current, exists := r.exactProfiles[key]; exists && now.Before(current.expiresAt) { + switch { + case current.observationID > entry.observationID && entry.observationID > 0: + // This DB read linearized immediately before a concurrent durable + // Advance which already refreshed the local cache. Do not roll it back. + return nil + case current.observationID == entry.observationID && entry.observationID > 0: + if current.layer != entry.layer || current.msgID != entry.msgID { + return fmt.Errorf("%w: observation %d maps to (%d,%d) and (%d,%d)", + store.ErrAuthKeySessionLayerConflict, entry.observationID, + current.layer, current.msgID, entry.layer, entry.msgID) + } + // The store row may have an authoritative expiry refresh; replace it. + case entry.observationID <= 0 && current.msgID > entry.msgID: + // Defensive compatibility for an old custom store without observation + // ids. Production stores always take the branches above. + return nil + } + } + if _, exists := r.exactProfiles[key]; !exists && len(r.exactProfiles) >= maxExactSessionProfileEntries { + r.purgeExpiredExactSessionProfilesLocked(now) + if len(r.exactProfiles) >= maxExactSessionProfileEntries { + // Durable primary remains authoritative; skipping this accelerator can + // never reject the request or lose the raw watermark returned to edge. + return nil + } + } + r.exactProfiles[key] = entry + if len(r.exactProfiles) == 1 { + r.exactProfileEarliestExpiry = entry.expiresAt + } else { + r.noteExactSessionProfileExpiryLocked(entry.expiresAt) + } + return nil +} + +func (r *Router) forgetCachedDurableSessionLayer(rawAuthKeyID [8]byte, sessionID int64) { + if r == nil { + return + } + r.exactProfileMu.Lock() + delete(r.exactProfiles, clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID}) + r.exactProfileMu.Unlock() +} + +// DeleteNegotiatedSessionLayerEvidence is the durable destroy_session +// boundary. The edge must complete this call before acknowledging destruction; +// ordinary transport disconnect never invokes it. +func (r *Router) DeleteNegotiatedSessionLayerEvidence( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, +) (bool, error) { + if r == nil || rawAuthKeyID == ([8]byte{}) || sessionID == 0 { + return false, nil + } + _, _, inMemory := r.NegotiatedSessionLayerEvidence(rawAuthKeyID, sessionID) + deleted := false + if r.deps.AuthKeySessionLayers != nil { + var err error + deleted, err = r.deps.AuthKeySessionLayers.DeleteSessionLayer(ctx, rawAuthKeyID, sessionID) + if err != nil { + return false, err + } + } + r.ForgetNegotiatedSessionLayer(rawAuthKeyID, sessionID) + return deleted || inMemory, nil +} diff --git a/internal/rpc/durable_layer_evidence_test.go b/internal/rpc/durable_layer_evidence_test.go new file mode 100644 index 00000000..5dad6fe5 --- /dev/null +++ b/internal/rpc/durable_layer_evidence_test.go @@ -0,0 +1,215 @@ +package rpc + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/proto" + "go.uber.org/zap/zaptest" + + "telesrv/internal/domain" + "telesrv/internal/store" + "telesrv/internal/store/memory" +) + +func TestDurableSessionLayerSurvivesRestartAndRejectsOldSelectorRollback(t *testing.T) { + ctx := context.Background() + keys := memory.NewAuthKeyStore() + authKeyID := [8]byte{1} + if err := keys.Save(ctx, store.AuthKeyData{ID: authKeyID}); err != nil { + t.Fatal(err) + } + now := time.Now().UTC() + olderID := int64(proto.NewMessageIDGen(func() time.Time { return now.Add(-time.Second) }).New(proto.MessageFromClient)) + newerID := int64(proto.NewMessageIDGen(func() time.Time { return now }).New(proto.MessageFromClient)) + first := New(Config{}, Deps{AuthKeySessionLayers: keys}, zaptest.NewLogger(t), clock.System) + if layer, msgID, publish, err := first.AdvanceNegotiatedSessionLayerEvidence(ctx, authKeyID, 10, 225, olderID); err != nil || layer != 225 || msgID != olderID || !publish { + t.Fatalf("first evidence = (%d,%d,%v,%v)", layer, msgID, publish, err) + } + if layer, msgID, publish, err := first.AdvanceNegotiatedSessionLayerEvidence(ctx, authKeyID, 10, 227, newerID); err != nil || layer != 227 || msgID != newerID || !publish { + t.Fatalf("newer evidence = (%d,%d,%v,%v)", layer, msgID, publish, err) + } + + // A fresh Router has no process-local registry. The durable raw-session + // watermark restores the exact codec before a naked same-session replay. + restarted := New(Config{}, Deps{AuthKeySessionLayers: keys}, zaptest.NewLogger(t), clock.System) + layer, msgID, found, err := restarted.ResolveNegotiatedSessionLayerEvidence(ctx, authKeyID, 10) + if err != nil || !found || layer != 227 || msgID != newerID { + t.Fatalf("restart restore = (%d,%d,%v,%v)", layer, msgID, found, err) + } + layer, msgID, publish, err := restarted.AdvanceNegotiatedSessionLayerEvidence(ctx, authKeyID, 10, 225, olderID) + if err != nil || layer != 227 || msgID != newerID || !publish { + t.Fatalf("old selector after restart = (%d,%d,%v,%v)", layer, msgID, publish, err) + } + key, found, err := keys.Get(ctx, authKeyID) + if err != nil || !found || key.Layer != 227 { + t.Fatalf("durable default rolled back: key=%+v found=%v err=%v", key, found, err) + } +} + +func TestDurableSessionLayerResolveRefreshesStaleRouterFromSharedStore(t *testing.T) { + ctx := context.Background() + keys := memory.NewAuthKeyStore() + authKeyID := [8]byte{1, 0xa2} + const sessionID = int64(102) + if err := keys.Save(ctx, store.AuthKeyData{ID: authKeyID}); err != nil { + t.Fatal(err) + } + now := time.Now().UTC() + msgIDs := proto.NewMessageIDGen(func() time.Time { return now }) + oldMsgID := msgIDs.New(proto.MessageFromClient) + newMsgID := msgIDs.New(proto.MessageFromClient) + routerA := New(Config{}, Deps{AuthKeySessionLayers: keys}, zaptest.NewLogger(t), clock.System) + routerB := New(Config{}, Deps{AuthKeySessionLayers: keys}, zaptest.NewLogger(t), clock.System) + if layer, msgID, _, err := routerA.AdvanceNegotiatedSessionLayerEvidence(ctx, authKeyID, sessionID, 225, oldMsgID); err != nil || layer != 225 || msgID != oldMsgID { + t.Fatalf("A advance = (%d,%d,%v)", layer, msgID, err) + } + if layer, msgID, found, err := routerA.ResolveNegotiatedSessionLayerEvidence(ctx, authKeyID, sessionID); err != nil || !found || layer != 225 || msgID != oldMsgID { + t.Fatalf("A initial resolve = (%d,%d,%v,%v)", layer, msgID, found, err) + } + if layer, msgID, _, err := routerB.AdvanceNegotiatedSessionLayerEvidence(ctx, authKeyID, sessionID, 227, newMsgID); err != nil || layer != 227 || msgID != newMsgID { + t.Fatalf("B advance = (%d,%d,%v)", layer, msgID, err) + } + + // A still has 225 in its process-local accelerator. Durable-store mode must + // read primary first and converge both the return value and that accelerator. + if layer, msgID, found, err := routerA.ResolveNegotiatedSessionLayerEvidence(ctx, authKeyID, sessionID); err != nil || !found || layer != 227 || msgID != newMsgID { + t.Fatalf("A refreshed resolve = (%d,%d,%v,%v), want B's 227", layer, msgID, found, err) + } + if layer, msgID, found := routerA.NegotiatedSessionLayerEvidence(authKeyID, sessionID); !found || layer != 227 || msgID != newMsgID { + t.Fatalf("A refreshed local cache = (%d,%d,%v)", layer, msgID, found) + } +} + +func TestDurableSessionLayerFutureProfileCanBeCorrectedByGreaterSelector(t *testing.T) { + ctx := context.Background() + keys := memory.NewAuthKeyStore() + authKeyID := [8]byte{2} + if err := keys.Save(ctx, store.AuthKeyData{ID: authKeyID}); err != nil { + t.Fatal(err) + } + now := time.Now().UTC() + futureID := int64(proto.NewMessageIDGen(func() time.Time { return now }).New(proto.MessageFromClient)) + correctID := int64(proto.NewMessageIDGen(func() time.Time { return now.Add(time.Second) }).New(proto.MessageFromClient)) + if _, applied, err := keys.AdvanceSessionLayer(ctx, authKeyID, 20, 229, futureID); err != nil || !applied { + t.Fatalf("seed future evidence = applied %v err %v", applied, err) + } + r := New(Config{}, Deps{AuthKeySessionLayers: keys}, zaptest.NewLogger(t), clock.System) + layer, msgID, found, err := r.ResolveNegotiatedSessionLayerEvidence(ctx, authKeyID, 20) + if err != nil || !found || layer != 229 || msgID != futureID { + t.Fatalf("future restore = (%d,%d,%v,%v)", layer, msgID, found, err) + } + if _, _, cached := r.NegotiatedSessionLayerEvidence(authKeyID, 20); cached { + t.Fatal("unsupported future profile polluted typed process cache") + } + layer, msgID, publish, err := r.AdvanceNegotiatedSessionLayerEvidence(ctx, authKeyID, 20, 228, correctID) + if err != nil || layer != 228 || msgID != correctID || !publish { + t.Fatalf("future self-heal = (%d,%d,%v,%v)", layer, msgID, publish, err) + } +} + +func TestDurableSessionLayerExpiryCoversAcceptedFutureSkew(t *testing.T) { + ctx := context.Background() + keys := memory.NewAuthKeyStore() + authKeyID := [8]byte{3} + if err := keys.Save(ctx, store.AuthKeyData{ID: authKeyID}); err != nil { + t.Fatal(err) + } + now := time.Now().UTC() + msgID := int64(proto.NewMessageIDGen(func() time.Time { return now.Add(29 * time.Second) }).New(proto.MessageFromClient)) + r := New(Config{}, Deps{AuthKeySessionLayers: keys}, zaptest.NewLogger(t), clock.System) + if _, _, _, err := r.AdvanceNegotiatedSessionLayerEvidence(ctx, authKeyID, 30, 227, msgID); err != nil { + t.Fatal(err) + } + value, found, err := keys.GetSessionLayer(ctx, authKeyID, 30) + if err != nil || !found { + t.Fatalf("future-skew evidence = found %v err %v", found, err) + } + wantMin := proto.MessageID(msgID).Time().Add(300 * time.Second) + if value.ExpiresAt.Before(wantMin) { + t.Fatalf("future-skew expiry = %v, want >= %v", value.ExpiresAt, wantMin) + } +} + +type unavailableSessionLayerStore struct { + store.AuthKeySessionLayerStore + err error +} + +func (s unavailableSessionLayerStore) GetSessionLayer(context.Context, [8]byte, int64) (store.AuthKeySessionLayer, bool, error) { + return store.AuthKeySessionLayer{}, false, s.err +} + +type mutableSessionLayerStore struct { + store.AuthKeySessionLayerStore + value store.AuthKeySessionLayer +} + +func (s *mutableSessionLayerStore) GetSessionLayer(context.Context, [8]byte, int64) (store.AuthKeySessionLayer, bool, error) { + return s.value, true, nil +} + +func TestDurableSessionLayerCacheOrdersRebuiltRowsByObservationID(t *testing.T) { + now := time.Now().UTC() + primary := &mutableSessionLayerStore{value: store.AuthKeySessionLayer{ + Layer: 227, MessageID: 10_000, ObservationID: 10, ExpiresAt: now.Add(time.Hour), + }} + r := New(Config{}, Deps{AuthKeySessionLayers: primary}, zaptest.NewLogger(t), clock.System) + authKeyID := [8]byte{3, 0xb5} + const sessionID = int64(305) + if layer, msgID, found, err := r.ResolveNegotiatedSessionLayerEvidence(context.Background(), authKeyID, sessionID); err != nil || !found || layer != 227 || msgID != 10_000 { + t.Fatalf("first row = (%d,%d,%v,%v)", layer, msgID, found, err) + } + + // An expired durable row may be rebuilt with a lower client msg_id. The + // globally increasing observation id, not msg_id, orders those row lifetimes. + primary.value = store.AuthKeySessionLayer{ + Layer: 225, MessageID: 100, ObservationID: 11, ExpiresAt: now.Add(time.Hour), + } + if layer, msgID, found, err := r.ResolveNegotiatedSessionLayerEvidence(context.Background(), authKeyID, sessionID); err != nil || !found || layer != 225 || msgID != 100 { + t.Fatalf("rebuilt row = (%d,%d,%v,%v)", layer, msgID, found, err) + } + if layer, msgID, found := r.NegotiatedSessionLayerEvidence(authKeyID, sessionID); !found || layer != 225 || msgID != 100 { + t.Fatalf("rebuilt local cache = (%d,%d,%v)", layer, msgID, found) + } +} + +func TestDurableSessionLayerAvailabilityErrorCarriesStructuralMarker(t *testing.T) { + boom := errors.New("database unavailable") + r := New(Config{}, Deps{AuthKeySessionLayers: unavailableSessionLayerStore{err: boom}}, zaptest.NewLogger(t), clock.System) + _, _, _, err := r.ResolveNegotiatedSessionLayerEvidence(context.Background(), [8]byte{4}, 40) + var marker interface{ LayerEvidenceDurabilityUnavailable() } + if !errors.Is(err, boom) || !errors.As(err, &marker) { + t.Fatalf("availability error = %v, marker=%v", err, marker != nil) + } +} + +func TestDurableInheritedLayerRevalidatesEachNewSession(t *testing.T) { + ctx := context.Background() + authKeyID := [8]byte{5} + keys := memory.NewAuthKeyStore() + if err := keys.Save(ctx, store.AuthKeyData{ID: authKeyID}); err != nil { + t.Fatal(err) + } + auth := &captureAuthService{authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + authKeyID: {Layer: 225, LayerObservationID: 1}, + }} + r := New(Config{}, Deps{Auth: auth, AuthKeySessionLayers: keys}, zaptest.NewLogger(t), clock.System) + if layer, found, err := r.ResolveInheritedAuthKeyLayer(ctx, authKeyID); err != nil || !found || layer != 225 { + t.Fatalf("initial default = (%d,%v,%v)", layer, found, err) + } + auth.authKeyClientInfos[authKeyID] = domain.AuthKeyClientInfo{Layer: 229, LayerObservationID: 2} + if layer, found, err := r.ResolveInheritedAuthKeyLayer(ctx, authKeyID); err != nil || !found || layer != 0 { + t.Fatalf("future authoritative default = (%d,%v,%v)", layer, found, err) + } + auth.authKeyClientInfos[authKeyID] = domain.AuthKeyClientInfo{Layer: 228, LayerObservationID: 3} + if layer, found, err := r.ResolveInheritedAuthKeyLayer(ctx, authKeyID); err != nil || !found || layer != 228 { + t.Fatalf("corrected default = (%d,%v,%v)", layer, found, err) + } + if auth.authKeyInfoLookups != 3 { + t.Fatalf("auth_keys lookups = %d, want one per new session resolution", auth.authKeyInfoLookups) + } +} diff --git a/internal/rpc/effects_rpc_test.go b/internal/rpc/effects_rpc_test.go index 02cc18ca..4e62968b 100644 --- a/internal/rpc/effects_rpc_test.go +++ b/internal/rpc/effects_rpc_test.go @@ -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" diff --git a/internal/rpc/encrypted_chats.go b/internal/rpc/encrypted_chats.go index fca5532f..a79de082 100644 --- a/internal/rpc/encrypted_chats.go +++ b/internal/rpc/encrypted_chats.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" appsecret "telesrv/internal/app/secretchat" diff --git a/internal/rpc/encrypted_chats_test.go b/internal/rpc/encrypted_chats_test.go index 802a0113..c42d54ee 100644 --- a/internal/rpc/encrypted_chats_test.go +++ b/internal/rpc/encrypted_chats_test.go @@ -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" appsecret "telesrv/internal/app/secretchat" diff --git a/internal/rpc/encrypted_files.go b/internal/rpc/encrypted_files.go index f9543ea3..c95ea96d 100644 --- a/internal/rpc/encrypted_files.go +++ b/internal/rpc/encrypted_files.go @@ -5,7 +5,7 @@ import ( "go.uber.org/zap" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/encrypted_files_test.go b/internal/rpc/encrypted_files_test.go index 78fa5a43..e7a45d74 100644 --- a/internal/rpc/encrypted_files_test.go +++ b/internal/rpc/encrypted_files_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) // TestSendEncryptedFileFlow:sendEncryptedFile 铸造 EncryptedFile、随消息投递、返回 diff --git a/internal/rpc/encrypted_messages.go b/internal/rpc/encrypted_messages.go index e1fc6736..64bdd9a9 100644 --- a/internal/rpc/encrypted_messages.go +++ b/internal/rpc/encrypted_messages.go @@ -3,8 +3,8 @@ package rpc import ( "context" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) @@ -171,7 +171,6 @@ func (r *Router) encryptedStateUpdates(ctx context.Context, userID int64) (updat return nil, nil, nil } for _, ev := range events { - eventIDs = append(eventIDs, ev.ID) switch ev.Type { case domain.EncryptedStateEventEncryption: chat, found, gerr := r.deps.SecretChats.GetSecretChat(ctx, ev.ChatID) @@ -183,12 +182,14 @@ func (r *Router) encryptedStateUpdates(ctx context.Context, userID int64) (updat Date: ev.Date, }) peerUserIDs = append(peerUserIDs, chat.AdminUserID, chat.ParticipantUserID) + eventIDs = append(eventIDs, ev.ID) case domain.EncryptedStateEventRead: updates = append(updates, &tg.UpdateEncryptedMessagesRead{ ChatID: ev.ChatID, MaxDate: ev.MaxDate, Date: ev.Date, }) + eventIDs = append(eventIDs, ev.ID) } } return updates, peerUserIDs, eventIDs diff --git a/internal/rpc/encrypted_messages_test.go b/internal/rpc/encrypted_messages_test.go index fe3cac21..6f8dbcf9 100644 --- a/internal/rpc/encrypted_messages_test.go +++ b/internal/rpc/encrypted_messages_test.go @@ -1,9 +1,13 @@ package rpc import ( + "context" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" + + "telesrv/internal/domain" + "telesrv/internal/postresponse" ) // acceptChat 跑完 request→accept,返回 normal 态密聊 id 与 participant 视角 access_hash。 @@ -85,7 +89,8 @@ func TestSendEncryptedRPCFlow(t *testing.T) { } // participant 离线补差分:从 qts=0 拿回该加密消息。 - diff, err := f.router.onUpdatesGetDifference(f.participantCtx(), &tg.UpdatesGetDifferenceRequest{Qts: 0}) + differenceCtx := postresponse.WithCallbacks(f.participantCtx()) + diff, err := f.router.onUpdatesGetDifference(differenceCtx, &tg.UpdatesGetDifferenceRequest{Qts: 0}) if err != nil { t.Fatalf("getDifference: %v", err) } @@ -100,6 +105,7 @@ func TestSendEncryptedRPCFlow(t *testing.T) { if !ok || string(gotEM.Bytes) != string(data) { t.Fatalf("difference message = %+v, want bytes verbatim", full.NewEncryptedMessages[0]) } + postresponse.Run(differenceCtx) // receivedQueue:确认到 qts=1,返回空 Vector。 rq, err := f.router.onMessagesReceivedQueue(f.participantCtx(), 1) @@ -165,7 +171,8 @@ func TestEncryptionStateEventOfflineDelivery(t *testing.T) { chatID := res.(*tg.EncryptedChatWaiting).ID // participant 离线补差分:拿到 updateEncryption(encryptedChatRequested, 携 g_a)。 - diff, err := f.router.onUpdatesGetDifference(f.participantCtx(), &tg.UpdatesGetDifferenceRequest{Qts: 0}) + differenceCtx := postresponse.WithCallbacks(f.participantCtx()) + diff, err := f.router.onUpdatesGetDifference(differenceCtx, &tg.UpdatesGetDifferenceRequest{Qts: 0}) if err != nil { t.Fatalf("getDifference: %v", err) } @@ -174,6 +181,16 @@ func TestEncryptionStateEventOfflineDelivery(t *testing.T) { if !ok || requested.ID != chatID || len(requested.GA) == 0 { t.Fatalf("offline handshake update = %+v, want EncryptedChatRequested with g_a", upd.Chat) } + deviceKey := businessAuthKeyInt64(encPartAuthKey) + beforeDelivery, err := f.queue.ListUndeliveredStateEvents(f.ctx, f.participant.ID, deviceKey, 10) + if err != nil || len(beforeDelivery) == 0 { + t.Fatalf("state events before difference delivery = %v err=%v, want pending", beforeDelivery, err) + } + postresponse.Run(differenceCtx) + afterDelivery, err := f.queue.ListUndeliveredStateEvents(f.ctx, f.participant.ID, deviceKey, 10) + if err != nil || len(afterDelivery) != 0 { + t.Fatalf("state events after difference delivery = %v err=%v, want none", afterDelivery, err) + } // 再次补差分:已投递 → 不重复(DifferenceEmpty)。 diff2, err := f.router.onUpdatesGetDifference(f.participantCtx(), &tg.UpdatesGetDifferenceRequest{Qts: 0}) @@ -185,6 +202,76 @@ func TestEncryptionStateEventOfflineDelivery(t *testing.T) { } } +func TestEncryptedDifferenceAcknowledgesOnlyProjectedStateEvents(t *testing.T) { + f := newEncryptedFixture(t) + chatID, _ := f.acceptChat(t) + deviceKey := businessAuthKeyInt64(encPartAuthKey) + // Retire handshake events created while establishing the fixture; the test + // below owns the complete pending set. + prior, err := f.queue.ListUndeliveredStateEvents(f.ctx, f.participant.ID, deviceKey, 100) + if err != nil { + t.Fatalf("list prior events: %v", err) + } + priorIDs := make([]int64, 0, len(prior)) + for _, event := range prior { + priorIDs = append(priorIDs, event.ID) + } + if err := f.queue.MarkStateEventsDelivered(context.Background(), deviceKey, priorIDs); err != nil { + t.Fatalf("retire prior events: %v", err) + } + + validID, err := f.queue.AppendStateEvent(f.ctx, domain.EncryptedStateEvent{ + TargetUserID: f.participant.ID, + ChatID: chatID, + Type: domain.EncryptedStateEventRead, + MaxDate: 1700001000, + Date: 1700001001, + }) + if err != nil { + t.Fatalf("append valid event: %v", err) + } + missingChatID, err := f.queue.AppendStateEvent(f.ctx, domain.EncryptedStateEvent{ + TargetUserID: f.participant.ID, + ChatID: 999999, + Type: domain.EncryptedStateEventEncryption, + Date: 1700001002, + }) + if err != nil { + t.Fatalf("append missing-chat event: %v", err) + } + unknownID, err := f.queue.AppendStateEvent(f.ctx, domain.EncryptedStateEvent{ + TargetUserID: f.participant.ID, + ChatID: chatID, + Type: domain.EncryptedStateEventType(99), + Date: 1700001003, + }) + if err != nil { + t.Fatalf("append unknown event: %v", err) + } + + ctx := postresponse.WithCallbacks(f.participantCtx()) + diff, err := f.router.onUpdatesGetDifference(ctx, &tg.UpdatesGetDifferenceRequest{}) + if err != nil { + t.Fatalf("getDifference: %v", err) + } + read := encOtherUpdate[*tg.UpdateEncryptedMessagesRead](t, diff) + if read.ChatID != chatID { + t.Fatalf("projected read chat_id = %d, want %d", read.ChatID, chatID) + } + postresponse.Run(ctx) + pending, err := f.queue.ListUndeliveredStateEvents(f.ctx, f.participant.ID, deviceKey, 100) + if err != nil { + t.Fatalf("list pending after delivery: %v", err) + } + remaining := make(map[int64]bool, len(pending)) + for _, event := range pending { + remaining[event.ID] = true + } + if remaining[validID] || !remaining[missingChatID] || !remaining[unknownID] { + t.Fatalf("pending IDs after delivery = %v; valid=%d missing=%d unknown=%d", remaining, validID, missingChatID, unknownID) + } +} + // TestDiscardStateEventOfflineDelivery:admin 在 participant 未接受时 discard(账号级), // participant 离线设备 getDifference 补回 encryptedChatDiscarded。 func TestDiscardStateEventOfflineDelivery(t *testing.T) { diff --git a/internal/rpc/encrypted_read_typing.go b/internal/rpc/encrypted_read_typing.go index f5ee83de..6cf25dc0 100644 --- a/internal/rpc/encrypted_read_typing.go +++ b/internal/rpc/encrypted_read_typing.go @@ -3,8 +3,8 @@ package rpc import ( "context" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/encrypted_register.go b/internal/rpc/encrypted_register.go index f4e151db..3b33cdc5 100644 --- a/internal/rpc/encrypted_register.go +++ b/internal/rpc/encrypted_register.go @@ -1,6 +1,6 @@ package rpc -import "github.com/gotd/td/tg" +import "github.com/iamxvbaba/td/tg" // registerEncrypted 注册私聊端对端加密(Secret Chat)域 RPC。 // diff --git a/internal/rpc/errors.go b/internal/rpc/errors.go index a6c87ba4..b29c7c08 100644 --- a/internal/rpc/errors.go +++ b/internal/rpc/errors.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tgerr" "telesrv/internal/app/auth" "telesrv/internal/domain" diff --git a/internal/rpc/errors_test.go b/internal/rpc/errors_test.go index 657d483f..45fe746f 100644 --- a/internal/rpc/errors_test.go +++ b/internal/rpc/errors_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tgerr" "telesrv/internal/app/auth" "telesrv/internal/domain" diff --git a/internal/rpc/exact_profile_registry_test.go b/internal/rpc/exact_profile_registry_test.go new file mode 100644 index 00000000..17bff66e --- /dev/null +++ b/internal/rpc/exact_profile_registry_test.go @@ -0,0 +1,203 @@ +package rpc + +import ( + "encoding/binary" + "errors" + "sync/atomic" + "testing" + "time" + + "github.com/iamxvbaba/td/clock" + "go.uber.org/zap" + "go.uber.org/zap/zaptest" +) + +type exactProfileTestClock struct { + now time.Time +} + +func BenchmarkExactSessionProfileRefreshParallel(b *testing.B) { + clk := &exactProfileTestClock{now: time.Unix(1_700_000_000, 0)} + r := New(Config{DC: 2}, Deps{}, zap.NewNop(), clk) + const sessions = 4096 + for i := 1; i <= sessions; i++ { + authKeyID := [8]byte{byte(i), byte(i >> 8), 1} + if err := r.FreezeNegotiatedSessionLayer(authKeyID, int64(i), 227); err != nil { + b.Fatal(err) + } + } + b.ReportAllocs() + b.ResetTimer() + var next atomic.Uint64 + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + i := int(next.Add(1)%sessions) + 1 + authKeyID := [8]byte{byte(i), byte(i >> 8), 1} + if err := r.FreezeNegotiatedSessionLayer(authKeyID, int64(i), 227); err != nil { + b.Fatal(err) + } + } + }) +} + +func (c *exactProfileTestClock) Now() time.Time { return c.now } +func (c *exactProfileTestClock) Timer(d time.Duration) clock.Timer { return clock.System.Timer(d) } +func (c *exactProfileTestClock) Ticker(d time.Duration) clock.Ticker { return clock.System.Ticker(d) } +func (c *exactProfileTestClock) advance(d time.Duration) { c.now = c.now.Add(d) } + +func TestExactSessionProfileSurvivesTransportOfflineUntilTTL(t *testing.T) { + clk := &exactProfileTestClock{now: time.Unix(1_700_000_000, 0)} + r := New(Config{DC: 2}, Deps{}, zaptest.NewLogger(t), clk) + authKeyID := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} + const sessionID = int64(44) + + if err := r.FreezeNegotiatedSessionLayer(authKeyID, sessionID, 225); err != nil { + t.Fatal(err) + } + // SessionOffline is a physical transport event. It may clear transient + // client metadata, but the same logical MTProto session can reconnect and + // immediately replay a naked exact request. + r.SessionOffline(authKeyID, sessionID, 0, true) + if layer, ok := r.NegotiatedSessionLayer(authKeyID, sessionID); !ok || layer != 225 { + t.Fatalf("profile after transport offline = (%d,%v), want (225,true)", layer, ok) + } + + clk.advance(exactSessionProfileTTL + time.Nanosecond) + if layer, ok := r.NegotiatedSessionLayer(authKeyID, sessionID); ok || layer != 0 { + t.Fatalf("expired profile = (%d,%v), want (0,false)", layer, ok) + } + if got := len(r.exactProfiles); got != 0 { + t.Fatalf("expired registry entries = %d, want 0", got) + } +} + +func TestExactSessionProfileSupportsOrderedCorrectionAndRefreshesTTL(t *testing.T) { + clk := &exactProfileTestClock{now: time.Unix(1_700_000_000, 0)} + r := New(Config{DC: 2}, Deps{}, zaptest.NewLogger(t), clk) + authKeyID := [8]byte{9, 8, 7, 6, 5, 4, 3, 2} + const sessionID = int64(45) + + if err := r.FreezeNegotiatedSessionLayer(authKeyID, sessionID, 225); err != nil { + t.Fatal(err) + } + clk.advance(exactSessionProfileTTL - time.Second) + if err := r.FreezeNegotiatedSessionLayer(authKeyID, sessionID, 225); err != nil { + t.Fatalf("idempotent refresh: %v", err) + } + if err := r.FreezeNegotiatedSessionLayer(authKeyID, sessionID, 227); err == nil { + // accepted below + } else { + t.Fatalf("ordered profile correction: %v", err) + } + clk.advance(2 * time.Second) + if layer, ok := r.NegotiatedSessionLayer(authKeyID, sessionID); !ok || layer != 227 { + t.Fatalf("corrected profile = (%d,%v), want (227,true)", layer, ok) + } +} + +func TestExactSessionProfileMessageIDEvidenceLinearizesCorrections(t *testing.T) { + r := New(Config{DC: 2}, Deps{}, zaptest.NewLogger(t), clock.System) + authKeyID := [8]byte{4, 5, 6, 7} + const sessionID = int64(46) + + if applied, err := r.FreezeNegotiatedSessionLayerAt(authKeyID, sessionID, 225, 100); err != nil || !applied { + t.Fatalf("first evidence = (%v,%v), want (true,nil)", applied, err) + } + if applied, err := r.FreezeNegotiatedSessionLayerAt(authKeyID, sessionID, 227, 90); err != nil || applied { + t.Fatalf("older evidence = (%v,%v), want (false,nil)", applied, err) + } + if applied, err := r.FreezeNegotiatedSessionLayerAt(authKeyID, sessionID, 227, 100); err == nil || applied { + t.Fatalf("same msg_id conflicting evidence = (%v,%v), want conflict", applied, err) + } + if layer, msgID, ok := r.NegotiatedSessionLayerEvidence(authKeyID, sessionID); !ok || layer != 225 || msgID != 100 { + t.Fatalf("evidence after stale/conflict = (%d,%d,%v), want (225,100,true)", layer, msgID, ok) + } + if applied, err := r.FreezeNegotiatedSessionLayerAt(authKeyID, sessionID, 227, 110); err != nil || !applied { + t.Fatalf("newer correction = (%v,%v), want (true,nil)", applied, err) + } + // A same-layer legacy refresh must not erase the positive ordering watermark. + if err := r.FreezeNegotiatedSessionLayer(authKeyID, sessionID, 227); err != nil { + t.Fatal(err) + } + if layer, msgID, ok := r.NegotiatedSessionLayerEvidence(authKeyID, sessionID); !ok || layer != 227 || msgID != 110 { + t.Fatalf("same-layer legacy refresh = (%d,%d,%v), want (227,110,true)", layer, msgID, ok) + } + // A different legacy value remains the explicit force API and resets order. + if err := r.FreezeNegotiatedSessionLayer(authKeyID, sessionID, 225); err != nil { + t.Fatal(err) + } + if layer, msgID, ok := r.NegotiatedSessionLayerEvidence(authKeyID, sessionID); !ok || layer != 225 || msgID != 0 { + t.Fatalf("legacy force = (%d,%d,%v), want (225,0,true)", layer, msgID, ok) + } +} + +func TestExactSessionProfileExplicitInvalidation(t *testing.T) { + clk := &exactProfileTestClock{now: time.Unix(1_700_000_000, 0)} + r := New(Config{DC: 2}, Deps{}, zaptest.NewLogger(t), clk) + authKeyID := [8]byte{7, 7, 7, 7, 7, 7, 7, 7} + otherAuthKeyID := [8]byte{8, 8, 8, 8, 8, 8, 8, 8} + + for _, key := range []struct { + authKeyID [8]byte + sessionID int64 + }{ + {authKeyID, 1}, + {authKeyID, 2}, + {otherAuthKeyID, 3}, + } { + if err := r.FreezeNegotiatedSessionLayer(key.authKeyID, key.sessionID, 225); err != nil { + t.Fatal(err) + } + } + + r.SessionDestroyed(authKeyID, 1) + if _, ok := r.NegotiatedSessionLayer(authKeyID, 1); ok { + t.Fatal("destroy_session retained exact profile") + } + if _, ok := r.NegotiatedSessionLayer(authKeyID, 2); !ok { + t.Fatal("destroy_session removed a sibling session") + } + + r.ForgetNegotiatedAuthKey(authKeyID) + if _, ok := r.NegotiatedSessionLayer(authKeyID, 2); ok { + t.Fatal("auth-key revocation retained exact profile") + } + if layer, ok := r.NegotiatedSessionLayer(otherAuthKeyID, 3); !ok || layer != 225 { + t.Fatalf("unrelated auth profile = (%d,%v), want (225,true)", layer, ok) + } +} + +func TestExactSessionProfileCapacityNeverEvictsLiveWatermark(t *testing.T) { + clk := &exactProfileTestClock{now: time.Unix(1_700_000_000, 0)} + r := New(Config{DC: 2}, Deps{}, zaptest.NewLogger(t), clk) + expiresAt := clk.now.Add(exactSessionProfileTTL) + for i := uint64(1); i <= maxExactSessionProfileEntries; i++ { + var authKeyID [8]byte + binary.LittleEndian.PutUint64(authKeyID[:], i) + r.exactProfiles[clientInfoSessionKey{rawAuthKeyID: authKeyID, sessionID: int64(i)}] = exactSessionProfileEntry{ + layer: 225, msgID: int64(i), expiresAt: expiresAt, + } + } + r.exactProfileEarliestExpiry = expiresAt + + newAuthKeyID := [8]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + _, err := r.FreezeNegotiatedSessionLayerAt(newAuthKeyID, 99, 227, 99) + var capacityErr *ExactSessionProfileCapacityError + if !errors.As(err, &capacityErr) || capacityErr.Limit != maxExactSessionProfileEntries { + t.Fatalf("full live registry err = %v, want typed capacity %d", err, maxExactSessionProfileEntries) + } + if len(r.exactProfiles) != maxExactSessionProfileEntries { + t.Fatalf("capacity refusal evicted live watermark: entries=%d", len(r.exactProfiles)) + } + if _, ok := r.NegotiatedSessionLayer(newAuthKeyID, 99); ok { + t.Fatal("capacity-refused logical session was installed") + } + + clk.advance(exactSessionProfileTTL + time.Nanosecond) + if applied, err := r.FreezeNegotiatedSessionLayerAt(newAuthKeyID, 99, 227, 99); err != nil || !applied { + t.Fatalf("claim after expiry purge = (%v,%v), want (true,nil)", applied, err) + } + if len(r.exactProfiles) != 1 { + t.Fatalf("expired capacity purge entries=%d, want 1", len(r.exactProfiles)) + } +} diff --git a/internal/rpc/expiry_dispatcher.go b/internal/rpc/expiry_dispatcher.go index 88e961b3..a02d7af9 100644 --- a/internal/rpc/expiry_dispatcher.go +++ b/internal/rpc/expiry_dispatcher.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" ) diff --git a/internal/rpc/external_media_rpc_test.go b/internal/rpc/external_media_rpc_test.go index 98cf8fd4..309acd8a 100644 --- a/internal/rpc/external_media_rpc_test.go +++ b/internal/rpc/external_media_rpc_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" "telesrv/internal/domain" ) diff --git a/internal/rpc/folders.go b/internal/rpc/folders.go index 5e6babf4..c2b8babc 100644 --- a/internal/rpc/folders.go +++ b/internal/rpc/folders.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/forum_general_read_rpc_test.go b/internal/rpc/forum_general_read_rpc_test.go index 2b0d0b21..b7a3e237 100644 --- a/internal/rpc/forum_general_read_rpc_test.go +++ b/internal/rpc/forum_general_read_rpc_test.go @@ -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" diff --git a/internal/rpc/help.go b/internal/rpc/help.go index e5b3229d..428672e0 100644 --- a/internal/rpc/help.go +++ b/internal/rpc/help.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" androidcompat "telesrv/internal/compat/android" ioscompat "telesrv/internal/compat/ios" diff --git a/internal/rpc/help_dismiss_suggestion_test.go b/internal/rpc/help_dismiss_suggestion_test.go index 47a816f7..5619a410 100644 --- a/internal/rpc/help_dismiss_suggestion_test.go +++ b/internal/rpc/help_dismiss_suggestion_test.go @@ -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" ) diff --git a/internal/rpc/inline_push.go b/internal/rpc/inline_push.go index 141b20b5..fee041c5 100644 --- a/internal/rpc/inline_push.go +++ b/internal/rpc/inline_push.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/store" diff --git a/internal/rpc/inline_push_test.go b/internal/rpc/inline_push_test.go index 692395f8..4d90d4ed 100644 --- a/internal/rpc/inline_push_test.go +++ b/internal/rpc/inline_push_test.go @@ -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" botsapp "telesrv/internal/app/bots" diff --git a/internal/rpc/inline_registry_shared_test.go b/internal/rpc/inline_registry_shared_test.go index 8ed72aae..245a71fc 100644 --- a/internal/rpc/inline_registry_shared_test.go +++ b/internal/rpc/inline_registry_shared_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/gotd/td/clock" + "github.com/iamxvbaba/td/clock" "telesrv/internal/domain" "telesrv/internal/store" diff --git a/internal/rpc/langpack.go b/internal/rpc/langpack.go index 6ad7de33..fc3dfe8a 100644 --- a/internal/rpc/langpack.go +++ b/internal/rpc/langpack.go @@ -4,12 +4,12 @@ import ( "context" "strings" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) // registerLangpack 注册 langpack.* RPC handler。 // -// 老客户端(DrKLO)发的是不带 lang_pack 参数的旧构造器,已由 layerwire 入站升级为 227 +// 老客户端(DrKLO)发的是不带 lang_pack 参数的旧构造器,已由 gotdgen client overlay 入站升级为 canonical // 形态并把 lang_pack 置空;故这里 lang_pack 为空时回退到按 client 信息派生(langPackFromClient), // 与历史 handleLegacyLangpack* 的行为一致。 func (r *Router) registerLangpack(d *tg.ServerDispatcher) { @@ -56,7 +56,7 @@ func (r *Router) registerLangpack(d *tg.ServerDispatcher) { }) } -// langPackOrClient 返回请求里的 lang_pack;为空(老客户端经 layerwire 升级而来)时按 client 派生。 +// langPackOrClient 返回请求里的 lang_pack;为空(老客户端经生成 overlay 升级而来)时按 client 派生。 func langPackOrClient(ctx context.Context, langPack string) string { if langPack != "" { return langPack diff --git a/internal/rpc/langpack_compat_test.go b/internal/rpc/langpack_compat_test.go index b5ad1c16..c5a14b24 100644 --- a/internal/rpc/langpack_compat_test.go +++ b/internal/rpc/langpack_compat_test.go @@ -6,9 +6,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" ) func TestLangpackGetLanguagesCurrentAndLegacy(t *testing.T) { diff --git a/internal/rpc/layer_dispatch.go b/internal/rpc/layer_dispatch.go new file mode 100644 index 00000000..c0f15b2f --- /dev/null +++ b/internal/rpc/layer_dispatch.go @@ -0,0 +1,520 @@ +package rpc + +import ( + "context" + "fmt" + "sync" + "time" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/tg" + "go.uber.org/zap" + + compatandroid "telesrv/internal/compat/android" + "telesrv/internal/observability/dbtrace" +) + +type layerWrappersAppliedKey struct{} +type layerAdmissionSequenceKey struct{} +type layerRPCProfileEvidenceFreshKey struct{} + +// WithLayerRPCProfileEvidenceFresh records whether an admitted request's +// explicit selector is inside MTProto's mutable msg_id freshness window. A +// stale selector still owns its immutable request/result codec, but wrapper +// metadata, readiness and auth-key default effects must not escape into shared +// state. mtprotoedge discovers this method through a structural interface. +func (r *Router) WithLayerRPCProfileEvidenceFresh(ctx context.Context, fresh bool) context.Context { + if ctx == nil { + ctx = context.Background() + } + return context.WithValue(ctx, layerRPCProfileEvidenceFreshKey{}, fresh) +} + +func layerRPCProfileEvidenceFresh(ctx context.Context) bool { + fresh, specified := ctx.Value(layerRPCProfileEvidenceFreshKey{}).(bool) + return !specified || fresh +} + +func withLayerAdmissionSequence(ctx context.Context, sequence uint64) context.Context { + return context.WithValue(ctx, layerAdmissionSequenceKey{}, sequence) +} + +func layerAdmissionSequenceFrom(ctx context.Context) uint64 { + sequence, _ := ctx.Value(layerAdmissionSequenceKey{}).(uint64) + return sequence +} + +type layerRPCWrapperApplyMode uint8 + +const ( + layerRPCWrapperApplyDispatch layerRPCWrapperApplyMode = iota + layerRPCWrapperApplyReplayRestore +) + +const layerRPCReplayRestoreTimeout = 5 * time.Second + +// AdmitLayer performs generated, bounded, exact-profile admission without +// touching auth/session stores. The MTProto edge must call it before acquiring +// an RPC flight/cache slot or scheduling business work. +func (r *Router) AdmitLayer(profile tg.LayerProfile, b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) { + if r == nil || r.dispatcher == nil { + return tg.LayerRequest{}, internalErr() + } + if b == nil { + return tg.LayerRequest{}, inputRequestInvalidErr() + } + return r.dispatcher.AdmitLayerWithLimits(profile, b, limits) +} + +// AdmitDefaultLayer admits a request using an inherited auth-key profile as +// its effective codec while still allowing an explicit invokeWithLayer in the +// same wrapper chain to correct that default. Generated admission preserves +// the distinction through EffectiveProfile and ProfileEvidence. +func (r *Router) AdmitDefaultLayer(profile tg.LayerProfile, b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) { + if r == nil || r.dispatcher == nil { + return tg.LayerRequest{}, internalErr() + } + if b == nil { + return tg.LayerRequest{}, inputRequestInvalidErr() + } + return r.dispatcher.AdmitDefaultLayerWithLimits(profile, b, limits) +} + +// registerAndroidLayerRPCAdapter installs the only client-private schema seam. +// The generated exact switch invokes it only for an unknown innermost terminal +// after recursively peeling every official wrapper. AdaptCanonical runs this +// dispatcher's semantic field policies before the first generated typed +// materialization, then core revalidates exact wire with the adapter disabled. +func (r *Router) registerAndroidLayerRPCAdapter(d *tg.ServerDispatcher) { + if d == nil { + panic("rpc: register Android layer RPC adapter on nil dispatcher") + } + d.OnLayerRPCUnknownMethod(func(view tg.LayerRPCUnknownMethodView) (tg.LayerOutboundCall, bool, error) { + outbound, handled, err := compatandroid.AdaptPrivateLayerRPC(view) + if !handled { + return tg.LayerOutboundCall{}, false, nil + } + if err != nil { + return tg.LayerOutboundCall{}, true, err + } + if r.log != nil { + _, method, _ := tg.LayerSemanticName(outbound.Method()) + r.log.Info("Android private RPC admitted through generated exact adapter", + zap.Int("profile", int(view.Profile())), + zap.String("method", method), + zap.String("private_wire_id", fmt.Sprintf("%#x", view.WireID())), + zap.String("exact_wire_id", fmt.Sprintf("%#x", outbound.WireID()))) + } + return outbound, true, nil + }) +} + +// PrepareAdmittedReplay restores wrapper/client metadata and stages only the +// connection-local delivery effects of a successful cached request. It never +// calls the generated handler and therefore cannot repeat business side +// effects or advance a difference cursor a second time. +func (r *Router) PrepareAdmittedReplay( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + msgID int64, + admissionSeq uint64, + request tg.LayerRequest, +) (func() error, error) { + if r == nil || r.dispatcher == nil || request.Prepared().WireSize() <= 0 { + return nil, inputRequestInvalidErr() + } + _, method, ok := tg.LayerSemanticName(request.Call().Method()) + if !ok || method == "" { + return nil, inputRequestInvalidErr() + } + effects, err := r.snapshotLayerRPCWrapperEffects(ctx, request) + if err != nil { + return nil, err + } + wireSize := request.Prepared().WireSize() + profile := request.Call().Profile() + _, profileKnown := request.EffectiveProfile() + identity := request.Prepared().Identity() + // The callback owns every cache/binder/store side effect and is attached to + // the concrete rpc_result write attempt. Admission and protocol-plan commit + // can therefore fail without publishing client metadata or readiness for a + // response that never reached the replacement transport. + var once sync.Once + return func() error { + var restoreErr error + once.Do(func() { + // A replay may happen after the request/read context is canceled, but it + // must never turn slow auth/store/membership work into an unbounded + // delivery hook. One deadline covers the complete restore transaction. + replayCtx, cancel := context.WithTimeout(context.WithoutCancel(ctx), layerRPCReplayRestoreTimeout) + defer cancel() + replayCtx = withLayerAdmissionSequence(replayCtx, admissionSeq) + replayCtx, updatesDelivery, prepareErr := r.prepareRPCDispatchContext( + replayCtx, + rawAuthKeyID, + sessionID, + wireSize, + method, + ) + if prepareErr != nil { + r.log.Warn("prepare delivered exact RPC replay metadata", + zap.String("method", method), + zap.Int64("session_id", sessionID), + zap.Error(prepareErr)) + restoreErr = fmt.Errorf("prepare delivered exact RPC replay metadata: %w", prepareErr) + return + } + replayCtx = r.applyLayerRPCWrapperEffects(replayCtx, profile, profileKnown, identity, effects, msgID, admissionSeq, layerRPCWrapperApplyReplayRestore) + if profileKnown && layerRPCProfileEvidenceFresh(replayCtx) { + r.maybeMarkSessionReceivesUpdates(replayCtx) + } else { + updatesDelivery.suppressSessionActivation() + } + if updatesDelivery.hasWork() { + // prepareRPCDispatchContext normally snapshots a cancellation-free + // base for ordinary post-response work. Replay restoration is a + // stricter ordered barrier, so every phase shares the overall deadline. + updatesDelivery.baseCtx = replayCtx + r.runUpdatesDeliveryPlan(updatesDelivery.snapshot()) + } + if err := replayCtx.Err(); err != nil { + restoreErr = fmt.Errorf("restore delivered exact RPC replay metadata: %w", err) + } + }) + return restoreErr + }, nil +} + +// AdmitUnprofiled is the only first-request admission path. Generated code +// either obtains authoritative profile evidence from invokeWithLayer or admits +// a closed terminal whose complete request and result wire graphs were proven +// invariant across every generated profile. The latter never freezes a layer. +func (r *Router) AdmitUnprofiled(b *bin.Buffer, limits tg.LayerDecodeLimits) (tg.LayerRequest, error) { + if r == nil || r.dispatcher == nil { + return tg.LayerRequest{}, internalErr() + } + return r.dispatcher.AdmitUnprofiledWithLimits(b, limits) +} + +// DispatchAdmitted executes one generated admission lease. invokeAfterMsg(s) +// dependencies must already have reached a terminal business outcome at the +// MTProto edge before this method is called. +func (r *Router) DispatchAdmitted( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + msgID int64, + admissionSeq uint64, + request tg.LayerRequest, +) (tg.LayerRPCResult, string, error) { + if r == nil || r.dispatcher == nil { + return nil, "", internalErr() + } + prepared := request.Prepared() + call := request.Call() + category, method, ok := tg.LayerSemanticName(call.Method()) + if !ok || category != "function" || method == "" || prepared.WireSize() <= 0 { + return nil, "", inputRequestInvalidErr() + } + _, profileKnown := request.EffectiveProfile() + profileEvidenceFresh := layerRPCProfileEvidenceFresh(ctx) + ctx = withLayerAdmissionSequence(ctx, admissionSeq) + ctx, updatesDelivery, err := r.prepareRPCDispatchContext(ctx, rawAuthKeyID, sessionID, prepared.WireSize(), method) + if err != nil { + return nil, method, err + } + ctx, err = r.applyLayerRPCWrappers(ctx, msgID, admissionSeq, request) + if err != nil { + return nil, method, err + } + if !r.dispatcher.HasLayerRPCHandler(call.Method()) { + fields := append([]zap.Field{ + zap.String("method", method), + zap.String("type_id", fmt.Sprintf("%#x", call.WireID())), + zap.Int("profile", int(call.Profile())), + }, r.contextLogFields(ctx)...) + if r.log != nil { + r.log.Warn("Unhandled RPC (compatibility trace)", fields...) + } + return nil, method, notImplementedErr() + } + canonicalID, hasCanonicalID := tg.LayerWireID(tg.LayerProfileCanonical, call.Method()) + if !hasCanonicalID { + return nil, method, inputRequestInvalidErr() + } + if r.deps.Auth != nil { + if _, authorized := UserIDFrom(ctx); !authorized && !rpcAllowedWithoutAuthorization(canonicalID) { + fields := append([]zap.Field{ + zap.String("method", method), + zap.String("type_id", fmt.Sprintf("%#x", call.WireID())), + zap.Int("profile", int(call.Profile())), + }, r.contextLogFields(ctx)...) + r.log.Info("RPC rejected before authorization", fields...) + return nil, method, authKeyUnregisteredErr() + } + } + if profileKnown && profileEvidenceFresh { + r.maybeMarkSessionReceivesUpdates(ctx) + } + dbBefore := dbtrace.SnapshotFromContext(ctx) + start := time.Now() + result, err := r.dispatcher.DispatchAdmitted(ctx, request) + dur := time.Since(start) + dbDelta := dbtrace.SnapshotFromContext(ctx).Sub(dbBefore) + fields := append([]zap.Field{ + zap.String("method", method), + zap.String("type_id", fmt.Sprintf("%#x", call.WireID())), + zap.Int("profile", int(call.Profile())), + zap.Duration("dur", dur), + }, r.contextLogFields(ctx)...) + fields = dbtrace.AppendZapFields(fields, "handler_", dbDelta) + if err != nil || dur > 100*time.Millisecond { + if err != nil { + fields = append(fields, zap.Error(err)) + } + r.log.Info("RPC inner handled", fields...) + } else { + r.log.Debug("RPC inner handled", fields...) + } + if err == nil && result != nil { + if !profileKnown || !profileEvidenceFresh { + // A generated wire-invariant terminal can safely complete before the + // client profile is known, but it is not evidence that this physical + // session can consume proactive updates. Preserve delivery-gated cursor + // and secret-event facts while withholding readiness/bootstrap effects. + updatesDelivery.suppressSessionActivation() + } + r.registerUpdatesDeliveryPlan(ctx, updatesDelivery) + } + return result, method, err +} + +type layerRPCWrapperEffect struct { + semantic tg.LayerSemanticID + layer int + info ClientInfo +} + +func (r *Router) snapshotLayerRPCWrapperEffects(ctx context.Context, request tg.LayerRequest) ([]layerRPCWrapperEffect, error) { + if err := r.validateLayerRPCWrappers(ctx, request); err != nil { + return nil, err + } + profile := request.Call().Profile() + evidenceProfile, hasProfileEvidence := request.ProfileEvidence() + if hasProfileEvidence && evidenceProfile != profile { + return nil, inputRequestInvalidErr() + } + effectiveProfile, hasEffectiveProfile := request.EffectiveProfile() + if hasEffectiveProfile && effectiveProfile != profile { + return nil, inputRequestInvalidErr() + } + if !hasEffectiveProfile && request.WrapperCount() != 0 { + // The generated no-profile route is deliberately a closed terminal. A + // wrapper chain without an authoritative selector must never smuggle the + // canonical representative into client/session metadata. + return nil, inputRequestInvalidErr() + } + effects := make([]layerRPCWrapperEffect, 0, request.WrapperCount()) + for index := 0; index < request.WrapperCount(); index++ { + wrapper, _ := request.Wrapper(index) + effect := layerRPCWrapperEffect{semantic: wrapper.Semantic()} + switch wrapper.Semantic() { + case tg.LayerSemanticMethodInvokeWithLayer: + layer, err := layerWrapperRequired[int](wrapper, "layer") + if err != nil || layer != int(profile) { + return nil, inputRequestInvalidErr() + } + effect.layer = layer + case tg.LayerSemanticMethodInitConnection: + info, err := clientInfoFromLayerWrapper(wrapper) + if err != nil { + return nil, err + } + effect.info = info + case tg.LayerSemanticMethodInvokeAfterMsg, tg.LayerSemanticMethodInvokeAfterMsgs: + // Dependency completion is an MTProto message-lifecycle fact. The edge + // validates it before scheduling this one-shot admission lease. + } + effects = append(effects, effect) + } + return effects, nil +} + +func (r *Router) applyLayerRPCWrapperEffects( + ctx context.Context, + profile tg.LayerProfile, + profileKnown bool, + identity tg.LayerPreparedCallIdentity, + effects []layerRPCWrapperEffect, + msgID int64, + admissionSeq uint64, + mode layerRPCWrapperApplyMode, +) context.Context { + mutableEffectsCurrent := layerRPCProfileEvidenceFresh(ctx) + rawAuthKeyID, hasRawAuthKeyID := RawAuthKeyIDFrom(ctx) + sessionID, hasSessionID := SessionIDFrom(ctx) + if msgID > 0 && hasRawAuthKeyID && hasSessionID { + if currentLayer, currentMsgID, exists := r.NegotiatedSessionLayerEvidence(rawAuthKeyID, sessionID); exists { + if currentMsgID > msgID || (currentMsgID == msgID && currentLayer != int(profile)) { + mutableEffectsCurrent = false + } + } + if mutableEffectsCurrent && hasMutableLayerRPCWrapperEffect(effects) { + mutableEffectsCurrent = r.claimSessionWrapperEffects(rawAuthKeyID, sessionID, msgID) + } + } + if profileKnown { + // Handler and wrapper metadata always see the immutable admitted request + // profile. This may intentionally differ from a later correction to the + // mutable session default while an older request is still executing. + ctx = WithLayer(ctx, int(profile)) + } else { + // A wire-invariant terminal admitted with no effective profile must not + // inherit an incidental metadata value loaded during context preparation. + ctx = WithLayer(ctx, 0) + } + for _, effect := range effects { + switch effect.semantic { + case tg.LayerSemanticMethodInvokeWithLayer: + ctx = WithLayer(ctx, effect.layer) + // Shared Layer publication is an admission-time protocol effect. It has + // already been linearized by admissionSeq before the scheduler/rewrap + // split; handler execution and physical replay are intentionally unable + // to move that auth-key-wide default. + case tg.LayerSemanticMethodInvokeWithoutUpdates: + ctx = withInvokeWithoutUpdates(ctx) + case tg.LayerSemanticMethodInitConnection: + if mode == layerRPCWrapperApplyReplayRestore { + if _, exists := ClientInfoFrom(ctx); exists { + // prepareRPCDispatchContext restored newer session/auth metadata. + // Do not overwrite it with an older cached initConnection. + continue + } + } + ctx = WithClientInfo(ctx, effect.info) + if !mutableEffectsCurrent { + // Preserve request-local wrapper data for the delayed handler while + // refusing to publish stale session/auth metadata. + continue + } + r.rememberClientInfoAt(ctx, effect.info, admissionSeq) + if r.log != nil { + r.log.Debug("initConnection", + zap.Int("api_id", effect.info.APIID), + zap.String("device", effect.info.DeviceModel), + zap.String("app_version", effect.info.AppVersion), + zap.Int("layer", int(profile)), + zap.String("client_type", string(ClientTypeFrom(ctx))), + ) + } + } + } + return context.WithValue(ctx, layerWrappersAppliedKey{}, identity) +} + +func (r *Router) applyLayerRPCWrappers(ctx context.Context, msgID int64, admissionSeq uint64, request tg.LayerRequest) (context.Context, error) { + effects, err := r.snapshotLayerRPCWrapperEffects(ctx, request) + if err != nil { + return nil, err + } + _, profileKnown := request.EffectiveProfile() + return r.applyLayerRPCWrapperEffects(ctx, request.Call().Profile(), profileKnown, request.Prepared().Identity(), effects, msgID, admissionSeq, layerRPCWrapperApplyDispatch), nil +} + +func hasMutableLayerRPCWrapperEffect(effects []layerRPCWrapperEffect) bool { + for _, effect := range effects { + switch effect.semantic { + case tg.LayerSemanticMethodInvokeWithLayer, tg.LayerSemanticMethodInitConnection: + return true + } + } + return false +} + +func (r *Router) validateLayerRPCWrappers(ctx context.Context, request tg.LayerRequest) error { + for index := 0; index < request.WrapperCount(); index++ { + wrapper, _ := request.Wrapper(index) + switch wrapper.Semantic() { + case tg.LayerSemanticMethodInvokeWithLayer, + tg.LayerSemanticMethodInvokeWithoutUpdates, + tg.LayerSemanticMethodInitConnection, + tg.LayerSemanticMethodInvokeAfterMsg, + tg.LayerSemanticMethodInvokeAfterMsgs: + continue + default: + _, name, _ := tg.LayerSemanticName(wrapper.Semantic()) + fields := append([]zap.Field{ + zap.String("wrapper", name), + zap.String("type_id", fmt.Sprintf("%#x", wrapper.WireID())), + zap.Int("profile", int(wrapper.Profile())), + }, r.contextLogFields(ctx)...) + if r.log != nil { + r.log.Warn("Unhandled RPC wrapper (compatibility trace)", fields...) + } + return notImplementedErr() + } + } + return nil +} + +func (r *Router) consumeLayerRPCWrappers(ctx context.Context, request tg.LayerRequest, next tg.LayerRPCNext) error { + applied, ok := ctx.Value(layerWrappersAppliedKey{}).(tg.LayerPreparedCallIdentity) + if !ok || applied != request.Prepared().Identity() { + return fmt.Errorf("rpc: exact wrapper context was not applied to admitted request") + } + return next(ctx) +} + +func layerWrapperRequired[T any](wrapper tg.LayerRPCWrapper, name string) (T, error) { + var zero T + value, present, ok, err := wrapper.Value(name) + if err != nil || !ok || !present { + return zero, inputRequestInvalidErr() + } + typed, ok := value.(T) + if !ok { + return zero, inputRequestInvalidErr() + } + return typed, nil +} + +func clientInfoFromLayerWrapper(wrapper tg.LayerRPCWrapper) (ClientInfo, error) { + apiID, err := layerWrapperRequired[int](wrapper, "api_id") + if err != nil { + return ClientInfo{}, err + } + deviceModel, err := layerWrapperRequired[string](wrapper, "device_model") + if err != nil { + return ClientInfo{}, err + } + systemVersion, err := layerWrapperRequired[string](wrapper, "system_version") + if err != nil { + return ClientInfo{}, err + } + appVersion, err := layerWrapperRequired[string](wrapper, "app_version") + if err != nil { + return ClientInfo{}, err + } + systemLangCode, err := layerWrapperRequired[string](wrapper, "system_lang_code") + if err != nil { + return ClientInfo{}, err + } + langPack, err := layerWrapperRequired[string](wrapper, "lang_pack") + if err != nil { + return ClientInfo{}, err + } + langCode, err := layerWrapperRequired[string](wrapper, "lang_code") + if err != nil { + return ClientInfo{}, err + } + return ClientInfo{ + APIID: apiID, + DeviceModel: deviceModel, + SystemVersion: systemVersion, + AppVersion: appVersion, + SystemLangCode: systemLangCode, + LangPack: langPack, + LangCode: langCode, + }, nil +} diff --git a/internal/rpc/layer_dispatch_test.go b/internal/rpc/layer_dispatch_test.go new file mode 100644 index 00000000..cefcf5e4 --- /dev/null +++ b/internal/rpc/layer_dispatch_test.go @@ -0,0 +1,1009 @@ +package rpc + +import ( + "bytes" + "context" + "encoding/binary" + "errors" + "fmt" + "testing" + + "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" + + appfiles "telesrv/internal/app/files" + "telesrv/internal/domain" + "telesrv/internal/postresponse" +) + +func TestLayerAdmissionAndroidPrivateOverlayUsesExactProfile(t *testing.T) { + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) + + // DrKLO's private messages.forwardMessages constructor has the canonical + // body layout for this empty flags/vectors fixture, but is not an official + // Layer 227 method id. + var body bin.Buffer + body.PutID(0x41d41ade) + body.PutInt(0) + body.PutID(0x7f3b18ea) // inputPeerEmpty + body.PutVectorHeader(0) + body.PutVectorHeader(0) + body.PutID(0x7f3b18ea) // inputPeerEmpty + + admitted, err := r.AdmitLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + if body.Len() != 0 { + t.Fatalf("private request left %d bytes", body.Len()) + } + call := admitted.Call() + if call.Profile() != tg.LayerProfile227 || call.Method() != tg.LayerSemanticMethodMessagesForwardMessages { + t.Fatalf("private admission = profile:%d method:%#x", call.Profile(), call.Method()) + } + if want, ok := tg.LayerWireID(tg.LayerProfile227, call.Method()); !ok || call.WireID() != want { + t.Fatalf("private admission wire id = %#x, want %#x (ok=%v)", call.WireID(), want, ok) + } +} + +func TestLayerAdmissionOfficialProfileOwnsOverlappingAndroidID(t *testing.T) { + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) + request := &tg.ContactsSearchRequest{Q: "exact", Limit: 20} + body := encodeExactLayerRPC(t, tg.LayerProfile225, request) + admitted, err := r.AdmitLayer(tg.LayerProfile225, &body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + if body.Len() != 0 || admitted.Call().Method() != tg.LayerSemanticMethodContactsSearch { + t.Fatalf("official overlap = remaining:%d method:%#x", body.Len(), admitted.Call().Method()) + } +} + +func TestLayerAdmissionAndroidOverlayFailureDoesNotConsumeInput(t *testing.T) { + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) + bounded := bin.Buffer{Buf: androidPrivateForwardMessagesWire()} + boundedOriginal := bounded.Copy() + if _, err := r.AdmitLayer(tg.LayerProfile227, &bounded, tg.LayerDecodeLimits{MaxWireBytes: len(boundedOriginal) - 1}); err == nil { + t.Fatal("oversized Android-private request was admitted") + } + if !bytes.Equal(bounded.Raw(), boundedOriginal) { + t.Fatal("wire-limited Android-private request consumed or mutated caller input") + } + + malformed := bin.Buffer{} + malformed.PutID(0x41d41ade) + original := malformed.Copy() + if _, err := r.AdmitLayer(tg.LayerProfile227, &malformed, tg.LayerDecodeLimits{}); err == nil { + t.Fatal("malformed Android-private request was admitted") + } + if string(malformed.Raw()) != string(original) { + t.Fatal("failed Android-private admission consumed or mutated caller input") + } + + unknown := bin.Buffer{} + unknown.PutID(0xdeadbeef) + original = unknown.Copy() + if _, err := r.AdmitLayer(tg.LayerProfile227, &unknown, tg.LayerDecodeLimits{}); !errors.Is(err, tg.ErrLayerUnknownRPCMethod) { + t.Fatalf("official unknown error = %v", err) + } + if string(unknown.Raw()) != string(original) { + t.Fatal("unknown official request consumed or mutated caller input") + } +} + +func androidPrivateForwardMessagesWire() []byte { + var body bin.Buffer + body.PutID(0x41d41ade) + body.PutInt(0) + body.PutID(0x7f3b18ea) // inputPeerEmpty + body.PutVectorHeader(0) + body.PutVectorHeader(0) + body.PutID(0x7f3b18ea) // inputPeerEmpty + return body.Copy() +} + +func replaceTerminalRPC(t *testing.T, encoded *bin.Buffer, terminal []byte) { + t.Helper() + var placeholder bin.Buffer + if err := (&tg.HelpGetConfigRequest{}).Encode(&placeholder); err != nil { + t.Fatal(err) + } + if !bytes.HasSuffix(encoded.Raw(), placeholder.Raw()) { + t.Fatalf("wrapper does not end in placeholder RPC: %x", encoded.Raw()) + } + encoded.Buf = append(encoded.Buf[:encoded.Len()-placeholder.Len()], terminal...) +} + +func TestLayerAdmissionAndroidPrivateInnermostAcrossWrappers(t *testing.T) { + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) + private := androidPrivateForwardMessagesWire() + + var withoutUpdates bin.Buffer + withoutUpdates.PutID(tg.InvokeWithoutUpdatesRequestTypeID) + withoutUpdates.Put(private) + + var afterMsg bin.Buffer + afterMsg.PutID(tg.InvokeAfterMsgRequestTypeID) + afterMsg.PutLong(11) + afterMsg.Put(private) + + var afterMsgs bin.Buffer + afterMsgs.PutID(tg.InvokeAfterMsgsRequestTypeID) + afterMsgs.PutVectorHeader(2) + afterMsgs.PutLong(11) + afterMsgs.PutLong(12) + afterMsgs.Put(private) + + init := &tg.InitConnectionRequest{ + APIID: 6, + DeviceModel: "Android", + SystemVersion: "test", + AppVersion: "private-layer", + SystemLangCode: "en", + LangPack: "android", + LangCode: "en", + Query: &tg.HelpGetConfigRequest{}, + } + var initWire bin.Buffer + if err := init.Encode(&initWire); err != nil { + t.Fatal(err) + } + replaceTerminalRPC(t, &initWire, private) + var unprofiledInit bin.Buffer + unprofiledInit.PutID(tg.InvokeWithLayerRequestTypeID) + unprofiledInit.PutInt(int(tg.LayerProfile227)) + unprofiledInit.Put(initWire.Raw()) + + var unprofiledBare bin.Buffer + unprofiledBare.PutID(tg.InvokeWithLayerRequestTypeID) + unprofiledBare.PutInt(int(tg.LayerProfile227)) + unprofiledBare.Put(private) + + tests := []struct { + name string + body []byte + unprofiled bool + wrappers int + }{ + {"naked", private, false, 0}, + {"invokeWithoutUpdates", withoutUpdates.Copy(), false, 1}, + {"invokeAfterMsg", afterMsg.Copy(), false, 1}, + {"invokeAfterMsgs", afterMsgs.Copy(), false, 1}, + {"invokeWithLayer", unprofiledBare.Copy(), true, 1}, + {"invokeWithLayer_initConnection", unprofiledInit.Copy(), true, 2}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + body := bin.Buffer{Buf: append([]byte(nil), tc.body...)} + var ( + admitted tg.LayerRequest + err error + ) + if tc.unprofiled { + admitted, err = r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + } else { + admitted, err = r.AdmitLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{}) + } + if err != nil { + t.Fatal(err) + } + if body.Len() != 0 || admitted.WrapperCount() != tc.wrappers || admitted.Call().Method() != tg.LayerSemanticMethodMessagesForwardMessages { + t.Fatalf("admission = remaining:%d wrappers:%d method:%#x", body.Len(), admitted.WrapperCount(), admitted.Call().Method()) + } + }) + } +} + +func TestLayerAdmissionAndroidPrivateFieldPolicyBeforeTypedMaterialization(t *testing.T) { + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) + request := &tg.MessagesCreateChatRequest{ + Users: repeatLayerPreflightValue[tg.InputUserClass](201, &tg.InputUserEmpty{}), + Title: "private-field-policy", + } + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + // DrKLO's private createChat constructor is body-identical to canonical. + binary.LittleEndian.PutUint32(body.Buf[:4], 0x0034a818) + original := body.Copy() + if _, err := r.AdmitLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{MaxVectorElements: 8 << 10}); !tgerr.Is(err, "LIMIT_INVALID") { + t.Fatalf("private createChat admission err = %v, want LIMIT_INVALID", err) + } + if !bytes.Equal(body.Raw(), original) { + t.Fatal("field-rejected private createChat consumed or mutated input") + } +} + +func TestLayerDispatchExactProfilesShareOneHandler(t *testing.T) { + for _, profile := range []tg.LayerProfile{tg.LayerProfile225, tg.LayerProfile227} { + t.Run(fmt.Sprintf("layer_%d", profile), func(t *testing.T) { + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) + request := &tg.InvokeWithLayerRequest{ + Layer: int(profile), + Query: &tg.InitConnectionRequest{ + APIID: 123, + DeviceModel: "Desktop", + SystemVersion: "Windows", + AppVersion: "test", + SystemLangCode: "en", + LangPack: "tdesktop", + LangCode: "en", + Query: &tg.HelpGetConfigRequest{}, + }, + } + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + if body.Len() != 0 || admitted.Call().Profile() != profile { + t.Fatalf("admission = profile:%d remaining:%d", admitted.Call().Profile(), body.Len()) + } + result, method, err := r.DispatchAdmitted(context.Background(), [8]byte{1}, 10, 0, 0, admitted) + if err != nil { + t.Fatal(err) + } + if method != "help.getConfig" || result.Prepared().Call().Identity() != admitted.Call().Identity() { + t.Fatalf("result = method:%q call:%#v", method, result.Prepared().Call()) + } + var exact bin.Buffer + if err := result.Encode(&exact); err != nil { + t.Fatal(err) + } + decoded, err := tg.DecodeLayer(profile, tg.LayerConstructorConfigType(), &exact) + if err != nil { + t.Fatal(err) + } + if exact.Len() != 0 || decoded.ThisDC != 2 { + t.Fatalf("decoded config = dc:%d remaining:%d", decoded.ThisDC, exact.Len()) + } + frozen, err := result.Freeze() + if err != nil { + t.Fatal(err) + } + prepared, err := admitted.Call().PrepareFrozenResult(frozen) + if err != nil { + t.Fatal(err) + } + var replay bin.Buffer + if err := prepared.Encode(admitted.Call(), &replay); err != nil { + t.Fatal(err) + } + if string(replay.Raw()) != string(tgBufferBytes(t, result)) { + t.Fatalf("prepared replay differs from direct result") + } + }) + } +} + +func TestLayerDispatchUnprofiledInvariantDoesNotPublishRepresentativeLayer(t *testing.T) { + rawAuthKeyID := [8]byte{1} + const sessionID = int64(10) + auth := &captureAuthService{ + authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + rawAuthKeyID: {Layer: 225, DeviceModel: "stale-device"}, + }, + } + sessions := &layerCaptureSessions{} + r := New( + Config{DC: 2, IP: "127.0.0.1", Port: 2398}, + Deps{Auth: auth, Sessions: sessions}, + zaptest.NewLogger(t), + clock.System, + ) + request := &tg.AuthBindTempAuthKeyRequest{ + PermAuthKeyID: 1, + Nonce: 2, + ExpiresAt: 3, + EncryptedMessage: []byte("bind"), + } + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + if _, ok := admitted.ProfileEvidence(); ok { + t.Fatal("unprofiled invariant request exposed its canonical codec representative as client evidence") + } + if !admitted.Call().WireInvariant() { + t.Fatal("auth.bindTempAuthKey did not carry generated wire-invariant proof") + } + result, method, err := r.DispatchAdmitted(WithLayer(context.Background(), 226), rawAuthKeyID, sessionID, 0, 0, admitted) + if err != nil { + t.Fatal(err) + } + if method != "auth.bindTempAuthKey" || result == nil || !result.WireInvariant() { + t.Fatalf("invariant dispatch = method:%q result:%T invariant:%v", method, result, result != nil && result.WireInvariant()) + } + if auth.bindTempCalls != 1 || auth.bindTempLayer != 0 { + t.Fatalf("unprofiled bind handler context = calls:%d layer:%d, want one call with unknown layer", auth.bindTempCalls, auth.bindTempLayer) + } + if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { + t.Fatalf("stale auth metadata reached exact layer binder: %+v", calls) + } + if layer, ok := r.NegotiatedSessionLayer(rawAuthKeyID, sessionID); ok || layer != 0 { + t.Fatalf("unprofiled invariant published session layer = (%d,%v)", layer, ok) + } + + var profiledBody bin.Buffer + if err := (&tg.InvokeWithLayerRequest{Layer: 227, Query: request}).Encode(&profiledBody); err != nil { + t.Fatal(err) + } + profiled, err := r.AdmitUnprofiled(&profiledBody, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + if profile, ok := profiled.ProfileEvidence(); !ok || profile != tg.LayerProfile227 { + t.Fatalf("profiled bind evidence = (%d,%v), want layer 227", profile, ok) + } + freezeAndPublishLayer(t, r, rawAuthKeyID, sessionID, 100, 1, 227) + if _, _, err := r.DispatchAdmitted(context.Background(), rawAuthKeyID, sessionID, 100, 1, profiled); err != nil { + t.Fatal(err) + } + if auth.bindTempCalls != 2 || auth.bindTempLayer != 227 { + t.Fatalf("profiled bind handler context = calls:%d layer:%d, want layer 227", auth.bindTempCalls, auth.bindTempLayer) + } + if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { + t.Fatalf("Router duplicated edge exact-profile binder calls = %+v", calls) + } + if layer, ok := r.NegotiatedSessionLayer(rawAuthKeyID, sessionID); !ok || layer != 227 { + t.Fatalf("authoritative wrapper session layer = (%d,%v), want (227,true)", layer, ok) + } +} + +func TestLayerDispatchInheritedDefaultIsEffectiveWithoutBecomingExplicitEvidence(t *testing.T) { + rawAuthKeyID := [8]byte{0x73} + const sessionID = int64(73) + auth := &captureAuthService{} + r := New( + Config{DC: 2, IP: "127.0.0.1", Port: 2398}, + Deps{Auth: auth}, + zaptest.NewLogger(t), + clock.System, + ) + request := &tg.AuthBindTempAuthKeyRequest{PermAuthKeyID: businessAuthKeyInt64(rawAuthKeyID)} + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + admitted, err := r.AdmitDefaultLayer(tg.LayerProfile225, &body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + if profile, ok := admitted.EffectiveProfile(); !ok || profile != tg.LayerProfile225 { + t.Fatalf("effective profile = (%d,%v), want (225,true)", profile, ok) + } + if profile, ok := admitted.ProfileEvidence(); ok || profile != tg.LayerProfile(0) { + t.Fatalf("explicit evidence = (%d,%v), want (0,false)", profile, ok) + } + result, _, err := r.DispatchAdmitted(WithLayer(context.Background(), 227), rawAuthKeyID, sessionID, 0, 0, admitted) + if err != nil || result == nil { + t.Fatalf("dispatch inherited default = (%T,%v)", result, err) + } + if auth.bindTempLayer != 225 { + t.Fatalf("handler layer = %d, want immutable effective 225", auth.bindTempLayer) + } + if layer, ok := r.NegotiatedSessionLayer(rawAuthKeyID, sessionID); ok || layer != 0 { + t.Fatalf("inherited default became explicit registry state = (%d,%v)", layer, ok) + } +} + +func TestLayerDispatchProfiledBareIgnoresStaleMetadataLayer(t *testing.T) { + rawAuthKeyID := [8]byte{2, 2, 0} + const sessionID = int64(225) + auth := &captureAuthService{ + authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + rawAuthKeyID: {Layer: 227, DeviceModel: "newer-device-metadata"}, + }, + } + sessions := &layerCaptureSessions{} + r := New( + Config{DC: 2, IP: "127.0.0.1", Port: 2398}, + Deps{Auth: auth, Sessions: sessions}, + zaptest.NewLogger(t), + clock.System, + ) + request := &tg.AuthBindTempAuthKeyRequest{ + PermAuthKeyID: 1, + Nonce: 2, + ExpiresAt: 3, + EncryptedMessage: []byte("bind"), + } + body := encodeExactLayerRPC(t, tg.LayerProfile225, request) + admitted, err := r.AdmitLayer(tg.LayerProfile225, &body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + if _, _, err := r.DispatchAdmitted(WithLayer(context.Background(), 226), rawAuthKeyID, sessionID, 0, 0, admitted); err != nil { + t.Fatal(err) + } + if auth.bindTempCalls != 1 || auth.bindTempLayer != 225 { + t.Fatalf("profiled bare handler context = calls:%d layer:%d, want one call at 225", auth.bindTempCalls, auth.bindTempLayer) + } + if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { + t.Fatalf("profiled bare request rebound stale metadata before exact evidence: %+v", calls) + } +} + +func TestLayerDispatchUnprofiledInvariantWithholdsUpdatesReadinessUntilEvidence(t *testing.T) { + const ( + userID = int64(1000000227) + sessionID = int64(220227) + ) + rawAuthKeyID := [8]byte{0x22, 0x02, 0x27} + auth := &captureAuthService{ + userID: userID, + authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + rawAuthKeyID: {Layer: 225, DeviceModel: "stale-device"}, + }, + } + sessions := &layerCaptureSessions{} + r := New( + Config{DC: 2, IP: "127.0.0.1", Port: 2398}, + Deps{Auth: auth, Sessions: sessions}, + zaptest.NewLogger(t), + clock.System, + ) + // updates.getState stages readiness inside its handler in addition to the + // common bare-RPC path, so this locks both no-evidence gates. + request := &tg.UpdatesGetStateRequest{} + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + if _, evidence := admitted.ProfileEvidence(); evidence || !admitted.Call().WireInvariant() { + t.Fatalf("unprofiled getState evidence/invariant = %v/%v", evidence, admitted.Call().WireInvariant()) + } + + dispatchCtx := postresponse.WithCallbacks(context.Background()) + result, method, err := r.DispatchAdmitted(dispatchCtx, rawAuthKeyID, sessionID, 10, 1, admitted) + if err != nil || result == nil || method != "updates.getState" { + t.Fatalf("unprofiled getState dispatch = method:%q result:%T err:%v", method, result, err) + } + postresponse.Run(dispatchCtx) + if got := sessions.snapshot(); got.receives || got.receivesCalls != 0 { + t.Fatalf("unprofiled invariant activated updates after delivery: %+v", got) + } + if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { + t.Fatalf("unprofiled invariant bound stale layer: %+v", calls) + } + + restore, err := r.PrepareAdmittedReplay(context.Background(), rawAuthKeyID, sessionID, 10, 1, admitted) + if err != nil || restore == nil { + t.Fatalf("prepare unprofiled invariant replay = callback:%v err:%v", restore != nil, err) + } + if err := restore(); err != nil { + t.Fatal(err) + } + if got := sessions.snapshot(); got.receives || got.receivesCalls != 0 { + t.Fatalf("unprofiled invariant replay activated updates: %+v", got) + } + + var wrapped bin.Buffer + if err := (&tg.InvokeWithLayerRequest{Layer: 227, Query: request}).Encode(&wrapped); err != nil { + t.Fatal(err) + } + profiled, err := r.AdmitUnprofiled(&wrapped, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + freezeAndPublishLayer(t, r, rawAuthKeyID, sessionID, 20, 2, 227) + profiledCtx := postresponse.WithCallbacks(context.Background()) + if _, _, err := r.DispatchAdmitted(profiledCtx, rawAuthKeyID, sessionID, 20, 2, profiled); err != nil { + t.Fatal(err) + } + postresponse.Run(profiledCtx) + if got := sessions.snapshot(); !got.receives || got.receivesCalls != 1 { + t.Fatalf("authoritative profile did not activate updates: %+v", got) + } + if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { + t.Fatalf("Router duplicated edge authoritative-profile bind: %+v", calls) + } +} + +func TestLayerAdmissionPreflightRunsBeforeLargeVectorDecode(t *testing.T) { + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) + users := make([]tg.InputUserClass, 101) + for index := range users { + users[index] = &tg.InputUserEmpty{} + } + request := &tg.InvokeWithLayerRequest{ + Layer: int(tg.LayerProfile225), + Query: &tg.UsersGetUsersRequest{ID: users}, + } + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + if _, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}); !tgerr.Is(err, "INPUT_REQUEST_TOO_LONG") { + t.Fatalf("admission err = %v, want INPUT_REQUEST_TOO_LONG", err) + } +} + +func TestLayerAdmissionFieldPoliciesCoverEveryRoutableProfile(t *testing.T) { + type vectorCase struct { + name string + method tg.LayerSemanticID + max int + errorCode string + request func(int) bin.Object + } + cases := []vectorCase{ + {"users.getUsers", tg.LayerSemanticMethodUsersGetUsers, 100, "INPUT_REQUEST_TOO_LONG", func(n int) bin.Object { + return &tg.UsersGetUsersRequest{ID: repeatLayerPreflightValue[tg.InputUserClass](n, &tg.InputUserEmpty{})} + }}, + {"users.getRequirementsToContact", tg.LayerSemanticMethodUsersGetRequirementsToContact, maxRequirementsToContactUsers, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.UsersGetRequirementsToContactRequest{ID: repeatLayerPreflightValue[tg.InputUserClass](n, &tg.InputUserEmpty{})} + }}, + {"contacts.importContacts", tg.LayerSemanticMethodContactsImportContacts, maxContactImportBatch, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.ContactsImportContactsRequest{Contacts: make([]tg.InputPhoneContact, n)} + }}, + {"contacts.deleteContacts", tg.LayerSemanticMethodContactsDeleteContacts, maxContactDeleteBatch, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.ContactsDeleteContactsRequest{ID: repeatLayerPreflightValue[tg.InputUserClass](n, &tg.InputUserEmpty{})} + }}, + {"contacts.editCloseFriends", tg.LayerSemanticMethodContactsEditCloseFriends, maxCloseFriendsCount, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.ContactsEditCloseFriendsRequest{ID: make([]int64, n)} + }}, + {"contacts.setBlocked", tg.LayerSemanticMethodContactsSetBlocked, maxContactSetBlocked, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.ContactsSetBlockedRequest{ID: repeatLayerPreflightValue[tg.InputPeerClass](n, &tg.InputPeerEmpty{})} + }}, + {"messages.getMessages", tg.LayerSemanticMethodMessagesGetMessages, maxGetMessagesIDs, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.MessagesGetMessagesRequest{ID: repeatLayerPreflightValue[tg.InputMessageClass](n, &tg.InputMessageID{})} + }}, + {"messages.getChats", tg.LayerSemanticMethodMessagesGetChats, maxGetMessagesIDs, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.MessagesGetChatsRequest{ID: make([]int64, n)} + }}, + {"messages.getPeerDialogs", tg.LayerSemanticMethodMessagesGetPeerDialogs, maxDialogInputPeers, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.MessagesGetPeerDialogsRequest{Peers: repeatLayerPreflightValue[tg.InputDialogPeerClass](n, &tg.InputDialogPeer{Peer: &tg.InputPeerEmpty{}})} + }}, + {"messages.readMessageContents", tg.LayerSemanticMethodMessagesReadMessageContents, maxGetMessagesIDs, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.MessagesReadMessageContentsRequest{ID: make([]int, n)} + }}, + {"messages.getCustomEmojiDocuments", tg.LayerSemanticMethodMessagesGetCustomEmojiDocuments, maxEmojiDocuments, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.MessagesGetCustomEmojiDocumentsRequest{DocumentID: make([]int64, n)} + }}, + {"messages.deleteMessages", tg.LayerSemanticMethodMessagesDeleteMessages, domain.MaxDeleteMessageIDs, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.MessagesDeleteMessagesRequest{ID: make([]int, n)} + }}, + {"messages.createChat", tg.LayerSemanticMethodMessagesCreateChat, 200, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.MessagesCreateChatRequest{Users: repeatLayerPreflightValue[tg.InputUserClass](n, &tg.InputUserEmpty{}), Title: "layer-policy"} + }}, + {"channels.getChannels", tg.LayerSemanticMethodChannelsGetChannels, maxGetMessagesIDs, "LIMIT_INVALID", func(n int) bin.Object { + return &tg.ChannelsGetChannelsRequest{ID: repeatLayerPreflightValue[tg.InputChannelClass](n, &tg.InputChannelEmpty{})} + }}, + } + + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) + limits := tg.LayerDecodeLimits{MaxVectorElements: 8 << 10} + for profile := tg.LayerProfile225; profile <= tg.LayerProfile227; profile++ { + for _, tc := range cases { + tc := tc + if _, available := tg.LayerWireID(profile, tc.method); !available { + continue + } + t.Run(fmt.Sprintf("layer_%d/%s/at_cap", profile, tc.name), func(t *testing.T) { + body := encodeExactLayerRPC(t, profile, tc.request(tc.max)) + if _, err := r.AdmitLayer(profile, &body, limits); err != nil { + t.Fatal(err) + } + if body.Len() != 0 { + t.Fatalf("admitted request left %d bytes", body.Len()) + } + }) + t.Run(fmt.Sprintf("layer_%d/%s/over_cap", profile, tc.name), func(t *testing.T) { + body := encodeExactLayerRPC(t, profile, tc.request(tc.max+1)) + original := body.Copy() + if _, err := r.AdmitLayer(profile, &body, limits); !tgerr.Is(err, tc.errorCode) { + t.Fatalf("admission err = %v, want %s", err, tc.errorCode) + } + if string(body.Raw()) != string(original) { + t.Fatal("rejected request consumed or mutated caller input") + } + }) + } + } +} + +func TestLayerAdmissionUploadFieldsCoverEveryProfile(t *testing.T) { + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) + for profile := tg.LayerProfile225; profile <= tg.LayerProfile227; profile++ { + t.Run(fmt.Sprintf("layer_%d/saveFilePart", profile), func(t *testing.T) { + atCap := encodeExactLayerRPC(t, profile, &tg.UploadSaveFilePartRequest{Bytes: make([]byte, appfiles.MaxUploadPartBytes)}) + if _, err := r.AdmitLayer(profile, &atCap, tg.LayerDecodeLimits{}); err != nil { + t.Fatal(err) + } + over := encodeExactLayerRPC(t, profile, &tg.UploadSaveFilePartRequest{Bytes: make([]byte, appfiles.MaxUploadPartBytes+1)}) + original := over.Copy() + if _, err := r.AdmitLayer(profile, &over, tg.LayerDecodeLimits{}); !tgerr.Is(err, "FILE_PART_TOO_BIG") { + t.Fatalf("oversized part err = %v", err) + } + if string(over.Raw()) != string(original) { + t.Fatal("oversized part consumed input") + } + }) + t.Run(fmt.Sprintf("layer_%d/saveBigFilePart", profile), func(t *testing.T) { + atCap := encodeExactLayerRPC(t, profile, &tg.UploadSaveBigFilePartRequest{FileTotalParts: appfiles.MaxUploadParts, Bytes: make([]byte, appfiles.MaxUploadPartBytes)}) + if _, err := r.AdmitLayer(profile, &atCap, tg.LayerDecodeLimits{}); err != nil { + t.Fatal(err) + } + for _, totalParts := range []int{0, -1, appfiles.MaxUploadParts + 1} { + body := encodeExactLayerRPC(t, profile, &tg.UploadSaveBigFilePartRequest{FileTotalParts: totalParts}) + original := body.Copy() + if _, err := r.AdmitLayer(profile, &body, tg.LayerDecodeLimits{}); !tgerr.Is(err, "FILE_PART_INVALID") { + t.Fatalf("total parts %d err = %v", totalParts, err) + } + if string(body.Raw()) != string(original) { + t.Fatalf("invalid total parts %d consumed input", totalParts) + } + } + over := encodeExactLayerRPC(t, profile, &tg.UploadSaveBigFilePartRequest{FileTotalParts: 1, Bytes: make([]byte, appfiles.MaxUploadPartBytes+1)}) + if _, err := r.AdmitLayer(profile, &over, tg.LayerDecodeLimits{}); !tgerr.Is(err, "FILE_PART_TOO_BIG") { + t.Fatalf("oversized big part err = %v", err) + } + }) + } +} + +func repeatLayerPreflightValue[T any](n int, value T) []T { + result := make([]T, n) + for index := range result { + result[index] = value + } + return result +} + +func encodeExactLayerRPC(t *testing.T, profile tg.LayerProfile, request bin.Object) bin.Buffer { + t.Helper() + outbound, err := tg.PrepareLayerOutboundCall(profile, request) + if err != nil { + t.Fatal(err) + } + var body bin.Buffer + if err := outbound.Encode(&body); err != nil { + t.Fatal(err) + } + return body +} + +func TestLayerDispatchRejectsUnsupportedWrapperBeforeHandler(t *testing.T) { + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) + request := &tg.InvokeWithLayerRequest{ + Layer: int(tg.LayerProfile227), + Query: &tg.InvokeWithTakeoutRequest{ + TakeoutID: 1, + Query: &tg.HelpGetConfigRequest{}, + }, + } + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + if _, method, err := r.DispatchAdmitted(context.Background(), [8]byte{1}, 10, 0, 0, admitted); method != "help.getConfig" || !tgerr.Is(err, "NOT_IMPLEMENTED") { + t.Fatalf("dispatch = method:%q err:%v", method, err) + } +} + +func TestPrepareAdmittedReplayRestoresReadinessOnlyAfterDelivery(t *testing.T) { + const ( + userID = int64(1000000901) + sessionID = int64(901) + ) + authKeyID := [8]byte{9, 0, 1} + sessions := &captureSessions{userID: userID, userResolved: true} + r := New( + Config{DC: 2, IP: "127.0.0.1", Port: 2398}, + Deps{Sessions: sessions}, + zaptest.NewLogger(t), + clock.System, + ) + request := &tg.InvokeWithLayerRequest{ + Layer: int(tg.LayerProfile225), + Query: &tg.InitConnectionRequest{ + APIID: 123, DeviceModel: "Desktop", SystemVersion: "Windows", AppVersion: "test", + SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", + Query: &tg.HelpGetConfigRequest{}, + }, + } + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + freezeAndPublishLayer(t, r, authKeyID, sessionID, 9010, 1, 225) + after, err := r.PrepareAdmittedReplay(context.Background(), authKeyID, sessionID, 9010, 1, admitted) + if err != nil { + t.Fatal(err) + } + if after == nil { + t.Fatal("successful naked replay has no delivery callback") + } + if got := sessions.snapshot(); got.receives || got.receivesCalls != 0 { + t.Fatalf("replay marked ready before physical delivery: %+v", got) + } + if layer, ok := r.NegotiatedSessionLayer(authKeyID, sessionID); !ok || layer != 225 { + t.Fatalf("admission-time protocol evidence = (%d,%v), want (225,true)", layer, ok) + } + if err := after(); err != nil { + t.Fatalf("restore delivered replay: %v", err) + } + if got := sessions.snapshot(); !got.receives || got.receivesCalls != 1 { + t.Fatalf("delivered replay readiness = %+v", got) + } + if layer, ok := r.NegotiatedSessionLayer(authKeyID, sessionID); !ok || layer != 225 { + t.Fatalf("delivered replay changed protocol evidence = (%d,%v), want (225,true)", layer, ok) + } + if err := after(); err != nil { + t.Fatalf("idempotent replay restore: %v", err) + } + if got := sessions.snapshot(); got.receivesCalls != 1 { + t.Fatalf("replay delivery callback was not idempotent: %+v", got) + } +} + +func TestRequestBoundOnlyLayerRPCDoesNotPublishMetadataOrReadiness(t *testing.T) { + for _, mode := range []string{"dispatch", "replay"} { + t.Run(mode, func(t *testing.T) { + authKeyID := [8]byte{9, 0, 11, byte(len(mode))} + const sessionID = int64(911) + sessions := &captureSessions{} + r := New( + Config{DC: 2, IP: "127.0.0.1", Port: 2398}, + Deps{Sessions: sessions}, + zaptest.NewLogger(t), + clock.System, + ) + request := &tg.InvokeWithLayerRequest{ + Layer: int(tg.LayerProfile225), + Query: &tg.InitConnectionRequest{ + APIID: 123, DeviceModel: "Stale Desktop", SystemVersion: "Windows", AppVersion: "stale", + SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", + Query: &tg.HelpGetConfigRequest{}, + }, + } + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + ctx := r.WithLayerRPCProfileEvidenceFresh(context.Background(), false) + switch mode { + case "dispatch": + if result, method, err := r.DispatchAdmitted(ctx, authKeyID, sessionID, 9011, 1, admitted); err != nil || result == nil || method != "help.getConfig" { + t.Fatalf("request-bound dispatch = (%T,%q,%v)", result, method, err) + } + case "replay": + after, err := r.PrepareAdmittedReplay(ctx, authKeyID, sessionID, 9011, 1, admitted) + if err != nil { + t.Fatal(err) + } + if err := after(); err != nil { + t.Fatal(err) + } + } + if got := sessions.snapshot(); got.receives || got.receivesCalls != 0 { + t.Fatalf("request-bound %s published readiness: %+v", mode, got) + } + r.clientInfoMu.RLock() + sessionInfo := r.clientInfo[clientInfoSessionKey{rawAuthKeyID: authKeyID, sessionID: sessionID}] + authInfo := r.authInfo[authKeyID] + r.clientInfoMu.RUnlock() + if sessionInfo.hasClientInfo || authInfo.hasClientInfo { + t.Fatalf("request-bound %s published init metadata: session=%+v auth=%+v", mode, sessionInfo, authInfo) + } + }) + } +} + +func TestPrepareAdmittedReplayDoesNotRollBackNewerExplicitLayerOrClientInfo(t *testing.T) { + authKeyID := [8]byte{9, 0, 2} + const sessionID = int64(902) + auth := &captureAuthService{authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo)} + sessions := &layerCaptureSessions{} + r := New( + Config{DC: 2, IP: "127.0.0.1", Port: 2398}, + Deps{Auth: auth, Sessions: sessions}, + zaptest.NewLogger(t), + clock.System, + ) + oldRequest := &tg.InvokeWithLayerRequest{ + Layer: int(tg.LayerProfile225), + Query: &tg.InitConnectionRequest{ + APIID: 123, DeviceModel: "Old Desktop", SystemVersion: "Windows 10", AppVersion: "old", + SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", + Query: &tg.HelpGetConfigRequest{}, + }, + } + var body bin.Buffer + if err := oldRequest.Encode(&body); err != nil { + t.Fatal(err) + } + admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + freezeAndPublishLayer(t, r, authKeyID, sessionID, 10, 1, 225) + after, err := r.PrepareAdmittedReplay(context.Background(), authKeyID, sessionID, 10, 1, admitted) + if err != nil { + t.Fatal(err) + } + + freezeAndPublishLayer(t, r, authKeyID, sessionID, 20, 2, 227) + newerCtx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), authKeyID), sessionID), authKeyID) + r.rememberClientInfoAt(newerCtx, ClientInfo{ + APIID: 123, DeviceModel: "New Desktop", SystemVersion: "Windows 11", AppVersion: "new", Type: ClientTypeTDesktop, + }, 2) + if err := after(); err != nil { + t.Fatalf("restore old replay after correction: %v", err) + } + + if layer, ok := r.NegotiatedSessionLayer(authKeyID, sessionID); !ok || layer != 227 { + t.Fatalf("exact session rolled back = (%d,%v), want (227,true)", layer, ok) + } + if got := auth.authKeyClientInfos[authKeyID].Layer; got != 227 { + t.Fatalf("durable default rolled back = %d, want 227", got) + } + if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { + t.Fatalf("Router replay touched edge-owned exact binder: %+v", calls) + } + info, ok, _ := r.clientSessionInfo(newerCtx) + if !ok || !info.hasClientInfo || info.clientInfo.DeviceModel != "New Desktop" || info.clientInfo.AppVersion != "new" { + t.Fatalf("newer client info was overwritten by replay: %+v ok=%v", info, ok) + } +} + +func TestDelayedExplicitDispatchCannotRollBackAdmissionTimeLayerOrInitMetadata(t *testing.T) { + authKeyID := [8]byte{9, 0, 3} + const sessionID = int64(903) + auth := &captureAuthService{authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo)} + sessions := &layerCaptureSessions{} + r := New( + Config{DC: 2, IP: "127.0.0.1", Port: 2398}, + Deps{Auth: auth, Sessions: sessions}, + zaptest.NewLogger(t), + clock.System, + ) + admit := func(layer int, device, version string) tg.LayerRequest { + t.Helper() + request := &tg.InvokeWithLayerRequest{ + Layer: layer, + Query: &tg.InitConnectionRequest{ + APIID: 123, DeviceModel: device, SystemVersion: "Windows", AppVersion: version, + SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", + Query: &tg.HelpGetConfigRequest{}, + }, + } + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + admitted, err := r.AdmitUnprofiled(&body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + return admitted + } + old := admit(225, "Old Desktop", "old") + newer := admit(227, "New Desktop", "new") + freezeAndPublishLayer(t, r, authKeyID, sessionID, 10, 1, 225) + freezeAndPublishLayer(t, r, authKeyID, sessionID, 20, 2, 227) + + if _, _, err := r.DispatchAdmitted(context.Background(), authKeyID, sessionID, 20, 2, newer); err != nil { + t.Fatal(err) + } + if _, _, err := r.DispatchAdmitted(context.Background(), authKeyID, sessionID, 10, 1, old); err != nil { + t.Fatal(err) + } + if layer, msgID, ok := r.NegotiatedSessionLayerEvidence(authKeyID, sessionID); !ok || layer != 227 || msgID != 20 { + t.Fatalf("exact evidence after delayed dispatch = (%d,%d,%v), want (227,20,true)", layer, msgID, ok) + } + if got := auth.authKeyClientInfos[authKeyID]; got.Layer != 227 || got.DeviceModel != "New Desktop" || got.AppVersion != "new" { + t.Fatalf("durable protocol metadata rolled back: %+v", got) + } + if calls := sessions.layerCallsSnapshot(); len(calls) != 0 { + t.Fatalf("handler dispatch duplicated/rolled back edge profile binding: %+v", calls) + } +} + +func TestSameLayerNakedInitConnectionUsesMessageIDWatermark(t *testing.T) { + authKeyID := [8]byte{9, 0, 4} + const sessionID = int64(904) + auth := &captureAuthService{authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + authKeyID: {Layer: 227}, + }} + r := New( + Config{DC: 2, IP: "127.0.0.1", Port: 2398}, + Deps{Auth: auth}, + zaptest.NewLogger(t), + clock.System, + ) + admit := func(device, version string) tg.LayerRequest { + t.Helper() + request := &tg.InitConnectionRequest{ + APIID: 123, DeviceModel: device, SystemVersion: "Windows", AppVersion: version, + SystemLangCode: "en", LangPack: "tdesktop", LangCode: "en", + Query: &tg.HelpGetConfigRequest{}, + } + var body bin.Buffer + if err := request.Encode(&body); err != nil { + t.Fatal(err) + } + admitted, err := r.AdmitDefaultLayer(tg.LayerProfile227, &body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatal(err) + } + return admitted + } + newer := admit("New Desktop", "new") + old := admit("Old Desktop", "old") + if _, _, err := r.DispatchAdmitted(context.Background(), authKeyID, sessionID, 20, 2, newer); err != nil { + t.Fatal(err) + } + if _, _, err := r.DispatchAdmitted(context.Background(), authKeyID, sessionID, 10, 1, old); err != nil { + t.Fatal(err) + } + if got := auth.authKeyClientInfos[authKeyID]; got.DeviceModel != "New Desktop" || got.AppVersion != "new" || got.Layer != 227 { + t.Fatalf("same-layer naked init metadata rolled back: %+v", got) + } + ctx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), authKeyID), sessionID), authKeyID) + info, ok, _ := r.clientSessionInfo(ctx) + if !ok || info.wrapperMsgID != 20 || !info.hasClientInfo || info.clientInfo.DeviceModel != "New Desktop" { + t.Fatalf("session wrapper watermark/client info = %+v ok=%v", info, ok) + } +} + +func TestCrossSessionInitMetadataUsesAdmissionSequence(t *testing.T) { + rawOld := [8]byte{9, 0, 5, 1} + rawNew := [8]byte{9, 0, 5, 2} + permAuthKeyID := [8]byte{9, 0, 5, 3} + auth := &captureAuthService{ + resolvedAuthKeyID: permAuthKeyID, + hasResolved: true, + authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo), + } + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + newCtx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), rawNew), 2), permAuthKeyID) + oldCtx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), rawOld), 1), permAuthKeyID) + r.rememberClientInfoAt(newCtx, ClientInfo{APIID: 123, DeviceModel: "New Desktop", AppVersion: "new", Type: ClientTypeTDesktop}, 2) + r.rememberClientInfoAt(oldCtx, ClientInfo{APIID: 123, DeviceModel: "Old Desktop", AppVersion: "old", Type: ClientTypeTDesktop}, 1) + + if got := auth.authKeyClientInfos[permAuthKeyID]; got.DeviceModel != "New Desktop" || got.AppVersion != "new" { + t.Fatalf("cross-session durable metadata rolled back: %+v", got) + } + oldInfo, ok, _ := r.clientSessionInfo(oldCtx) + if !ok || !oldInfo.hasClientInfo || oldInfo.clientInfo.DeviceModel != "Old Desktop" { + t.Fatalf("old session lost its request-local metadata: %+v ok=%v", oldInfo, ok) + } +} + +func tgBufferBytes(t *testing.T, encoder interface{ Encode(*bin.Buffer) error }) []byte { + t.Helper() + var encoded bin.Buffer + if err := encoder.Encode(&encoded); err != nil { + t.Fatal(err) + } + return encoded.Copy() +} diff --git a/internal/rpc/layer_inheritance.go b/internal/rpc/layer_inheritance.go new file mode 100644 index 00000000..93832a39 --- /dev/null +++ b/internal/rpc/layer_inheritance.go @@ -0,0 +1,614 @@ +package rpc + +import ( + "context" + "encoding/binary" + "fmt" + "sort" + "time" + + "github.com/iamxvbaba/td/tg" + "go.uber.org/zap" + + "telesrv/internal/domain" + "telesrv/internal/store" +) + +const ( + inheritedAuthKeyLayerSingleflightPrefix = "inherited-layer:" + durableInheritedAuthKeyLayerSingleflightPrefix = "durable-inherited-layer:" +) + +const authLayerCommitStripes = 4096 + +const ( + authLayerPublicationTimeout = 5 * time.Second + maxAuthLayerEvidenceEntries = maxAuthInfoEntries +) + +type inheritedAuthKeyLayerResult struct { + layer int + found bool +} + +// PublishAdmittedLayerProfileEvidence commits protocol evidence before an +// admitted request can be delayed by the business scheduler or replaced by an +// initConnection rewrap alias. admissionSeq is allocated by mtprotoedge when +// the fresh request obtains flight ownership; it orders process-local/no-store +// publication and supplies the active-admission safe floor. In durable mode the +// store's ObservationID is the cross-session/cross-process publication order. +// Replays reuse the owner's admission sequence and do not publish again. +func (r *Router) PublishAdmittedLayerProfileEvidence( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + msgID int64, + admissionSeq uint64, + safeFloor uint64, + layer int, +) error { + if r == nil || rawAuthKeyID == ([8]byte{}) || sessionID == 0 { + return fmt.Errorf("invalid admitted layer evidence identity") + } + if admissionSeq == 0 { + return fmt.Errorf("invalid admitted layer evidence sequence") + } + if safeFloor == 0 || safeFloor > admissionSeq { + return fmt.Errorf("invalid admitted layer evidence safe floor %d for sequence %d", safeFloor, admissionSeq) + } + if !isSupportedLayer(layer) { + return fmt.Errorf("unsupported admitted layer evidence %d", layer) + } + // The edge tracker owns admission lifecycle and supplies an exact global + // retirement floor. Advance it even if this particular proof became stale: + // the floor itself remains valid capacity-reclamation evidence. + r.clientInfoMu.Lock() + if safeFloor > r.authLayerSafeEvictionFloor { + r.authLayerSafeEvictionFloor = safeFloor + } + r.clientInfoMu.Unlock() + if r.deps.AuthKeySessionLayers == nil { + currentLayer, currentMsgID, ok := r.NegotiatedSessionLayerEvidence(rawAuthKeyID, sessionID) + if !ok || currentLayer != layer || (msgID > 0 && currentMsgID != msgID) { + // A newer correction or bounded registry eviction makes this evidence + // stale, not invalid. The admitted request keeps its immutable codec but + // no longer owns shared mutable state. + return nil + } + } + if ctx == nil { + ctx = context.Background() + } + publicationSequence := admissionSeq + publicationDurable := false + if r.deps.AuthKeySessionLayers != nil { + current, found, err := r.deps.AuthKeySessionLayers.GetSessionLayer(ctx, rawAuthKeyID, sessionID) + if err != nil { + // The durable transaction has already committed the protocol fact. + // A failed cache revalidation must not reject/re-execute the RPC; leave + // this process cache untouched and let the next session read primary. + if r.log != nil { + r.log.Warn("revalidate durable auth-key Layer default for local publication failed", + zap.String("raw_auth_key_id", fmt.Sprintf("%x", rawAuthKeyID[:])), + zap.Int64("session_id", sessionID), + zap.Error(err)) + } + return nil + } + if !found || !current.SharedDefault || current.Layer != layer || current.MessageID != msgID { + // Another session/process has already committed a newer shared + // default. This request keeps its immutable result codec but cannot + // overwrite process-local inherited state. + return nil + } + if current.ObservationID <= 0 { + return store.ErrAuthKeySessionLayerInvalid + } + publicationSequence = uint64(current.ObservationID) + publicationDurable = true + } + + effectiveAuthKeyID := rawAuthKeyID + if r.deps.Auth != nil { + resolveCtx, cancel := context.WithTimeout(ctx, authLayerPublicationTimeout) + resolved, found, err := r.deps.Auth.ResolveAuthKey(resolveCtx, rawAuthKeyID) + cancel() + switch { + case err != nil: + // Persistence identity lookup is availability metadata, not proof of + // whether this request's generated wire profile is valid. Publish the + // raw-key default now; a later bind/explicit observation can retry the + // durable permanent-key normalization. + if r.log != nil { + r.log.Warn("resolve auth key for admitted layer evidence failed; publishing raw default", + zap.String("raw_auth_key_id", fmt.Sprintf("%x", rawAuthKeyID[:])), + zap.Uint64("admission_seq", admissionSeq), + zap.Error(err)) + } + case found && resolved == ([8]byte{}): + return fmt.Errorf("admitted layer evidence resolved an empty permanent auth key") + case found: + effectiveAuthKeyID = resolved + } + } + + unlockCommit := r.lockAuthLayerCommit(rawAuthKeyID, effectiveAuthKeyID) + defer unlockCommit() + // Freeze may have admitted a newer same-session correction while identity + // resolution was in flight. The old request stays decodable, but can no + // longer publish shared state. + if r.deps.AuthKeySessionLayers == nil { + if currentLayer, currentMsgID, ok := r.NegotiatedSessionLayerEvidence(rawAuthKeyID, sessionID); !ok || currentLayer != layer || (msgID > 0 && currentMsgID != msgID) { + return nil + } + } + + r.clientInfoMu.Lock() + applied, err := r.claimAuthLayerDefaultEvidenceLocked( + layer, publicationSequence, publicationDurable, rawAuthKeyID, effectiveAuthKeyID, + ) + if err == nil && applied { + if r.clientInfo == nil { + r.clientInfo = make(map[clientInfoSessionKey]clientSessionInfo) + } + key := clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} + info, exists := r.clientInfo[key] + if !exists { + evictMapEntryIfFullLocked(r.clientInfo, maxClientInfoEntries) + } + info.layer = layer + if publicationDurable { + info.layerObservationID = int64(publicationSequence) + } else { + info.layerAdmissionSeq = admissionSeq + } + r.clientInfo[key] = info + } + r.clientInfoMu.Unlock() + if err != nil || !applied { + return err + } + if binder, ok := r.deps.Sessions.(AuthKeyLayerBinder); ok { + binder.SeedInheritedLayerForRawAuthKey(rawAuthKeyID, layer) + } + if effectiveAuthKeyID != rawAuthKeyID { + if binder, ok := r.deps.Sessions.(BusinessAuthKeyLayerBinder); ok { + binder.SeedInheritedLayerForBusinessAuthKey(effectiveAuthKeyID, layer) + } else if binder, ok := r.deps.Sessions.(AuthKeyLayerBinder); ok { + // Compatibility fallback for test doubles/older embedders where a + // permanent key is itself also the raw connection key. + binder.SeedInheritedLayerForRawAuthKey(effectiveAuthKeyID, layer) + } + } + + // Production durable evidence already updated raw/permanent auth_keys and + // the authorization mirror in one transaction. The legacy path remains only + // for isolated Router tests that intentionally omit the protocol store. + if r.deps.AuthKeySessionLayers == nil { + r.persistAdmittedAuthKeyLayer(ctx, effectiveAuthKeyID, layer, admissionSeq) + if effectiveAuthKeyID != rawAuthKeyID { + r.persistAdmittedAuthKeyLayer(ctx, rawAuthKeyID, layer, admissionSeq) + } + } + return nil +} + +func (r *Router) claimAuthLayerDefaultEvidenceLocked( + layer int, + sequence uint64, + durable bool, + authKeyIDs ...[8]byte, +) (bool, error) { + if r.authLayerEvidence == nil { + r.authLayerEvidence = make(map[[8]byte]authLayerDefaultEvidence) + } + ids := make([][8]byte, 0, len(authKeyIDs)) + for _, authKeyID := range authKeyIDs { + if authKeyID == ([8]byte{}) { + continue + } + duplicate := false + for _, existing := range ids { + if existing == authKeyID { + duplicate = true + break + } + } + if !duplicate { + ids = append(ids, authKeyID) + } + } + for _, authKeyID := range ids { + info := r.authInfo[authKeyID] + if durable { + if info.layerObservationID < 0 { + return false, fmt.Errorf("invalid cached auth-key layer observation %d", info.layerObservationID) + } + if uint64(info.layerObservationID) > sequence { + return false, nil + } + if info.layerObservationID > 0 && uint64(info.layerObservationID) == sequence && info.layer != layer { + return false, fmt.Errorf("auth-key layer evidence conflict at durable observation %d: current=%d requested=%d", sequence, info.layer, layer) + } + } else { + if info.layerAdmissionSeq > sequence { + return false, nil + } + if info.layerAdmissionSeq == sequence && info.layerAdmissionSeq > 0 && info.layer != layer { + return false, fmt.Errorf("auth-key layer evidence conflict at admission sequence %d: current=%d requested=%d", sequence, info.layer, layer) + } + } + current, exists := r.authLayerEvidence[authKeyID] + if !exists { + continue + } + if current.durable && !durable { + return false, nil + } + if durable && !current.durable { + continue + } + if current.sequence > sequence { + return false, nil + } + if current.sequence == sequence && current.layer != layer { + kind := "admission sequence" + if durable { + kind = "durable observation" + } + return false, fmt.Errorf("auth-key layer evidence conflict at %s %d: current=%d requested=%d", kind, sequence, current.layer, layer) + } + } + + missing := 0 + for _, authKeyID := range ids { + if _, exists := r.authLayerEvidence[authKeyID]; !exists { + missing++ + } + } + if len(r.authLayerEvidence)+missing > maxAuthLayerEvidenceEntries { + for len(r.authLayerEvidence)+missing > maxAuthLayerEvidenceEntries { + var ( + candidate [8]byte + candidateSeq uint64 + haveCandidate bool + ) + for currentID, current := range r.authLayerEvidence { + keep := false + for _, id := range ids { + if currentID == id { + keep = true + break + } + } + if keep { + continue + } + if !current.durable && current.sequence >= r.authLayerSafeEvictionFloor { + continue + } + if !haveCandidate || current.sequence < candidateSeq { + candidate, candidateSeq, haveCandidate = currentID, current.sequence, true + } + } + if !haveCandidate { + if r.log != nil { + r.log.Warn("auth-key layer evidence capacity exhausted; skip shared default", + zap.Int("entries", len(r.authLayerEvidence)), + zap.Uint64("evidence_sequence", sequence), + zap.Bool("durable", durable), + zap.Int("layer", layer)) + } + return false, nil + } + delete(r.authLayerEvidence, candidate) + } + } + + for _, authKeyID := range ids { + r.authLayerEvidence[authKeyID] = authLayerDefaultEvidence{ + layer: layer, sequence: sequence, durable: durable, + } + if durable { + r.rememberAuthClientLayerObservationLocked(authKeyID, layer, int64(sequence)) + } else { + r.rememberAuthClientLayerAtLocked(authKeyID, layer, sequence) + } + } + return true, nil +} + +func (r *Router) persistAdmittedAuthKeyLayer(ctx context.Context, authKeyID [8]byte, layer int, admissionSeq uint64) { + if r.deps.Auth == nil || authKeyID == ([8]byte{}) { + return + } + persistCtx, cancel := context.WithTimeout(ctx, authLayerPublicationTimeout) + err := r.deps.Auth.UpdateAuthKeyClientInfo(persistCtx, authKeyID, domain.AuthKeyClientInfo{Layer: layer}) + cancel() + if err != nil && r.log != nil { + r.log.Warn("persist admitted auth-key layer default failed", + zap.String("auth_key_id", fmt.Sprintf("%x", authKeyID[:])), + zap.Int("layer", layer), + zap.Uint64("admission_seq", admissionSeq), + zap.Error(err)) + } +} + +func (r *Router) lockAuthLayerCommit(authKeyIDs ...[8]byte) func() { + indices := make([]int, 0, len(authKeyIDs)) + for _, authKeyID := range authKeyIDs { + if authKeyID == ([8]byte{}) { + continue + } + index := authLayerCommitIndex(authKeyID) + duplicate := false + for _, existing := range indices { + if existing == index { + duplicate = true + break + } + } + if !duplicate { + indices = append(indices, index) + } + } + sort.Ints(indices) + for _, index := range indices { + r.authLayerCommit[index].Lock() + } + return func() { + for index := len(indices) - 1; index >= 0; index-- { + r.authLayerCommit[indices[index]].Unlock() + } + } +} + +func authLayerCommitIndex(authKeyID [8]byte) int { + return int(binary.LittleEndian.Uint64(authKeyID[:]) % authLayerCommitStripes) +} + +// ResolveInheritedAuthKeyLayer resolves the durable last-known default for a +// newly-created connection. The input is always the physical/raw auth key. A +// bound temporary key is normalized to its permanent identity before reading +// Layer, so an old raw shadow can never outrank the current permanent default. +// +// found=false means no canonical default exists and permits the edge to inspect +// a raw-key fallback. found=true with layer=0 means the canonical record carries +// a future Layer not generated into this binary; it is authoritative-but- +// unusable and therefore blocks fallback/clamping until fresh supported explicit +// invokeWithLayer evidence or a newer binary establishes a usable profile. +func (r *Router) ResolveInheritedAuthKeyLayer(ctx context.Context, rawAuthKeyID [8]byte) (int, bool, error) { + if r == nil || rawAuthKeyID == ([8]byte{}) { + return 0, false, nil + } + if ctx == nil { + ctx = context.Background() + } + effectiveAuthKeyID := rawAuthKeyID + if r.deps.Auth != nil { + resolved, found, err := r.deps.Auth.ResolveAuthKey(ctx, rawAuthKeyID) + if err != nil { + return 0, false, wrapLayerEvidenceStoreAvailability(err) + } + if found { + if resolved == ([8]byte{}) { + return 0, false, fmt.Errorf("resolved empty permanent auth key") + } + effectiveAuthKeyID = resolved + } + } + layer, found, err := r.resolveAuthKeyLayerDefault(ctx, effectiveAuthKeyID) + if err != nil { + return 0, false, wrapLayerEvidenceStoreAvailability(err) + } + if !found { + return 0, false, nil + } + var durableProjection clientSessionInfo + if r.deps.AuthKeySessionLayers != nil { + // resolveDurableAuthKeyLayerDefault may have completed a stale DB read + // after a newer same-process explicit observation was published. The + // observation-aware cache merge keeps the newer tuple; re-read it before + // returning or projecting to a bound raw identity. + r.clientInfoMu.RLock() + current := r.authInfo[effectiveAuthKeyID] + r.clientInfoMu.RUnlock() + if current.layerObservationID > 0 { + durableProjection = clientSessionInfo{ + layer: current.layer, + layerObservationID: current.layerObservationID, + layerBlocked: current.layerBlocked, + layerBlockedByAuthKey: current.layerBlockedByAuthKey, + authKeyInfoChecked: current.authKeyInfoChecked, + authorizationChecked: current.authorizationChecked, + } + switch { + case isSupportedLayer(current.layer): + layer, found = current.layer, true + case current.layerBlocked: + layer, found = 0, true + } + } + } + if layer == 0 { + // found=true with no usable profile is an authoritative future/unsupported + // canonical default. The edge must stay unknown rather than falling back + // to an older raw temporary-key shadow. + return 0, true, nil + } + if effectiveAuthKeyID != rawAuthKeyID { + // This updates only the auth-key default/shadow. Existing session entries + // remain untouched and therefore keep mixed Layer 225/227 profiles. + r.clientInfoMu.Lock() + if durableProjection.layerObservationID > 0 { + r.rememberAuthClientInfoLocked(rawAuthKeyID, durableProjection) + } else { + r.rememberAuthClientLayerLocked(rawAuthKeyID, layer) + } + r.clientInfoMu.Unlock() + } + return layer, true, nil +} + +func (r *Router) resolveAuthKeyLayerDefault(ctx context.Context, authKeyID [8]byte) (int, bool, error) { + if r == nil || authKeyID == ([8]byte{}) { + return 0, false, nil + } + if r.deps.AuthKeySessionLayers != nil { + return r.resolveDurableAuthKeyLayerDefault(ctx, authKeyID) + } + if layer, found, resolved := r.cachedAuthKeyLayerResolution(authKeyID); resolved { + return layer, found, nil + } + if r.deps.Auth == nil { + return 0, false, nil + } + v, err, _ := r.authUserSF.Do(inheritedAuthKeyLayerSingleflightPrefix+string(authKeyID[:]), func() (any, error) { + if layer, found, resolved := r.cachedAuthKeyLayerResolution(authKeyID); resolved { + return inheritedAuthKeyLayerResult{layer: layer, found: found}, nil + } + + keyInfo, keyFound, err := r.deps.Auth.AuthKeyClientInfo(ctx, authKeyID) + if err != nil { + return inheritedAuthKeyLayerResult{}, err + } + if keyFound { + r.cacheAuthKeyClientInfo(authKeyID, clientSessionInfoFromAuthKeyClientInfo(keyInfo)) + if current, ok := r.cachedAuthKeyLayerDefault(authKeyID); ok { + return inheritedAuthKeyLayerResult{layer: current, found: true}, nil + } + if keyInfo.Layer != 0 { + if !isSupportedLayer(keyInfo.Layer) { + r.cacheAuthKeyClientInfo(authKeyID, clientSessionInfo{layerBlocked: true, layerBlockedByAuthKey: true}) + return inheritedAuthKeyLayerResult{found: true}, nil + } + return inheritedAuthKeyLayerResult{layer: keyInfo.Layer, found: true}, nil + } + } else { + r.cacheAuthKeyClientInfo(authKeyID, clientSessionInfo{authKeyInfoChecked: true}) + } + // auth_keys.layer is the only protocol authority. A zero value means no + // default exists yet; authorization.layer is a materialized device-list + // projection and must never be promoted back into wire evidence. + return inheritedAuthKeyLayerResult{}, nil + }) + if err != nil { + return 0, false, err + } + if current, ok := r.cachedAuthKeyLayerDefault(authKeyID); ok { + return current, true, nil + } + result := v.(inheritedAuthKeyLayerResult) + return result.layer, result.found, nil +} + +// resolveDurableAuthKeyLayerDefault deliberately re-reads auth_keys for each +// new logical session. A process-local cache has no way to observe a newer +// observation committed by another server process; using it as authority would +// make new sessions inherit an old supported Layer forever (and could hide a +// future authoritative Layer). singleflight only coalesces the concurrent +// startup burst; it does not turn the result into an unbounded authority. +func (r *Router) resolveDurableAuthKeyLayerDefault(ctx context.Context, authKeyID [8]byte) (int, bool, error) { + if r.deps.Auth == nil { + return 0, false, nil + } + v, err, _ := r.authUserSF.Do(durableInheritedAuthKeyLayerSingleflightPrefix+string(authKeyID[:]), func() (any, error) { + keyInfo, keyFound, err := r.deps.Auth.AuthKeyClientInfo(ctx, authKeyID) + if err != nil { + return inheritedAuthKeyLayerResult{}, err + } + if keyFound { + parsed := clientSessionInfoFromAuthKeyClientInfo(keyInfo) + r.cacheAuthKeyClientInfo(authKeyID, parsed) + if keyInfo.Layer != 0 { + if !isSupportedLayer(keyInfo.Layer) { + return inheritedAuthKeyLayerResult{found: true}, nil + } + return inheritedAuthKeyLayerResult{layer: keyInfo.Layer, found: true}, nil + } + } + + // Do not normalize old authorization mirrors on read. Missing primary + // evidence stays unknown until a selector advances auth_keys explicitly; + // any legacy repair belongs in an audited migration. + return inheritedAuthKeyLayerResult{}, nil + }) + if err != nil { + return 0, false, err + } + result := v.(inheritedAuthKeyLayerResult) + return result.layer, result.found, nil +} + +func (r *Router) cachedAuthKeyLayerDefault(authKeyID [8]byte) (int, bool) { + r.clientInfoMu.RLock() + layer := r.authInfo[authKeyID].layer + r.clientInfoMu.RUnlock() + return layer, isSupportedLayer(layer) +} + +func (r *Router) cachedAuthKeyLayerResolution(authKeyID [8]byte) (layer int, found, resolved bool) { + r.clientInfoMu.RLock() + info, ok := r.authInfo[authKeyID] + r.clientInfoMu.RUnlock() + if !ok { + return 0, false, false + } + if isSupportedLayer(info.layer) { + return info.layer, true, true + } + if info.layerBlocked { + return 0, true, true + } + if info.authKeyInfoChecked { + return 0, false, true + } + return 0, false, false +} + +func (r *Router) cacheAuthKeyClientInfo(authKeyID [8]byte, info clientSessionInfo) { + r.clientInfoMu.Lock() + r.rememberAuthClientInfoLocked(authKeyID, info) + r.clientInfoMu.Unlock() +} + +func (r *Router) setAuthKeyLayerDefaults(layer int, authKeyIDs ...[8]byte) { + if !isSupportedLayer(layer) { + return + } + r.clientInfoMu.Lock() + for _, authKeyID := range authKeyIDs { + r.rememberAuthClientLayerLocked(authKeyID, layer) + } + r.clientInfoMu.Unlock() +} + +func (r *Router) persistAuthKeyLayerDefaults(ctx context.Context, layer int, authKeyIDs ...[8]byte) { + if r == nil || r.deps.Auth == nil || !isSupportedLayer(layer) { + return + } + seen := make(map[[8]byte]struct{}, len(authKeyIDs)) + for _, authKeyID := range authKeyIDs { + if authKeyID == ([8]byte{}) { + continue + } + if _, ok := seen[authKeyID]; ok { + continue + } + seen[authKeyID] = struct{}{} + if err := r.deps.Auth.UpdateAuthKeyClientInfo(ctx, authKeyID, domain.AuthKeyClientInfo{Layer: layer}); err != nil && r.log != nil { + r.log.Warn("persist inherited auth key layer default failed", + zap.String("auth_key_id", fmt.Sprintf("%x", authKeyID[:])), + zap.Int("layer", layer), + zap.Error(err)) + } + } +} + +func isSupportedLayer(layer int) bool { + if layer <= 0 { + return false + } + profile, ok := tg.ResolveLayerProfile(layer) + return ok && int(profile) == layer +} diff --git a/internal/rpc/layer_inheritance_test.go b/internal/rpc/layer_inheritance_test.go new file mode 100644 index 00000000..f39403e0 --- /dev/null +++ b/internal/rpc/layer_inheritance_test.go @@ -0,0 +1,979 @@ +package rpc + +import ( + "context" + "encoding/binary" + "errors" + "sync" + "testing" + "time" + + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" + "go.uber.org/zap/zaptest" + + "telesrv/internal/domain" + "telesrv/internal/store" + "telesrv/internal/store/memory" +) + +type unavailableResolveAuthService struct { + *captureAuthService + err error +} + +func (s *unavailableResolveAuthService) ResolveAuthKey(context.Context, [8]byte) ([8]byte, bool, error) { + return [8]byte{}, false, s.err +} + +type unavailableAuthKeyInfoService struct { + *captureAuthService + err error +} + +func (s *unavailableAuthKeyInfoService) AuthKeyClientInfo(context.Context, [8]byte) (domain.AuthKeyClientInfo, bool, error) { + return domain.AuthKeyClientInfo{}, false, s.err +} + +func TestResolveInheritedAuthKeyLayerUsesAuthKeyAuthorityOnly(t *testing.T) { + tests := []struct { + name string + keyLayer int + authorization int + want int + found bool + }{ + {name: "auth key primary", keyLayer: 225, authorization: 227, want: 225, found: true}, + {name: "authorization mirror is not protocol evidence", keyLayer: 0, authorization: 225}, + {name: "unsupported primary is authoritative unknown", keyLayer: 229, authorization: 227, found: true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + authKeyID := [8]byte{byte(tt.keyLayer), 0x71} + auth := &captureAuthService{ + authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + authKeyID: {Layer: tt.keyLayer}, + }, + authorizations: []domain.Authorization{{AuthKeyID: authKeyID, UserID: 10, Layer: tt.authorization}}, + } + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + got, found, err := r.ResolveInheritedAuthKeyLayer(context.Background(), authKeyID) + if err != nil { + t.Fatal(err) + } + if got != tt.want || found != tt.found { + t.Fatalf("resolved layer = (%d,%v), want (%d,%v)", got, found, tt.want, tt.found) + } + got, found, err = r.ResolveInheritedAuthKeyLayer(context.Background(), authKeyID) + if err != nil || got != tt.want || found != tt.found { + t.Fatalf("cached resolved layer = (%d,%v,%v), want (%d,%v,nil)", got, found, err, tt.want, tt.found) + } + if auth.authKeyInfoLookups != 1 { + t.Fatalf("auth key info lookups = %d, want 1 after repeated resolve", auth.authKeyInfoLookups) + } + if auth.authorizationLookups != 0 { + t.Fatalf("authorization Layer mirror lookups = %d, want 0", auth.authorizationLookups) + } + }) + } +} + +func TestResolveInheritedAuthKeyLayerNormalizesBoundTempToPermanent(t *testing.T) { + rawAuthKeyID := [8]byte{0x31} + permAuthKeyID := [8]byte{0x32} + auth := &captureAuthService{ + resolvedAuthKeyID: permAuthKeyID, + hasResolved: true, + authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + rawAuthKeyID: {Layer: 225}, // stale shadow + permAuthKeyID: {Layer: 227}, // canonical shared default + }, + } + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + + layer, found, err := r.ResolveInheritedAuthKeyLayer(context.Background(), rawAuthKeyID) + if err != nil { + t.Fatal(err) + } + if !found || layer != 227 { + t.Fatalf("bound temp layer = (%d,%v), want (227,true)", layer, found) + } + if cached, ok := r.cachedAuthKeyLayerDefault(rawAuthKeyID); !ok || cached != 227 { + t.Fatalf("raw in-memory shadow = (%d,%v), want (227,true)", cached, ok) + } +} + +func TestResolveInheritedAuthKeyLayerMarksOnlyAvailabilityFailures(t *testing.T) { + boom := errors.New("postgres temporarily unavailable") + for _, tt := range []struct { + name string + auth AuthService + want error + wantMarker bool + }{ + { + name: "temporary binding lookup outage", + auth: &unavailableResolveAuthService{ + captureAuthService: &captureAuthService{}, err: boom, + }, + want: boom, wantMarker: true, + }, + { + name: "auth key default lookup outage", + auth: &unavailableAuthKeyInfoService{ + captureAuthService: &captureAuthService{}, err: boom, + }, + want: boom, wantMarker: true, + }, + { + name: "structural binding failure", + auth: &unavailableResolveAuthService{ + captureAuthService: &captureAuthService{}, err: store.ErrAuthKeyBindingInvalid, + }, + want: store.ErrAuthKeyBindingInvalid, + }, + } { + t.Run(tt.name, func(t *testing.T) { + r := New(Config{DC: 2}, Deps{Auth: tt.auth}, zaptest.NewLogger(t), clock.System) + layer, found, err := r.ResolveInheritedAuthKeyLayer(context.Background(), [8]byte{0x33}) + if layer != 0 || found || !errors.Is(err, tt.want) { + t.Fatalf("resolution = (%d,%v,%v), want (0,false,%v)", layer, found, err, tt.want) + } + var marker interface{ LayerEvidenceDurabilityUnavailable() } + if got := errors.As(err, &marker); got != tt.wantMarker { + t.Fatalf("availability marker=%v, want %v", got, tt.wantMarker) + } + }) + } +} + +func TestResolveInheritedDurableAuthKeyLayerIgnoresAuthorizationMirror(t *testing.T) { + authKeyID := [8]byte{0x39, 0x71} + auth := &captureAuthService{ + authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + authKeyID: {}, + }, + authorizations: []domain.Authorization{{ + AuthKeyID: authKeyID, + UserID: 10, + Layer: 227, + }}, + } + r := New(Config{DC: 2}, Deps{ + Auth: auth, AuthKeySessionLayers: memory.NewAuthKeyStore(), + }, zaptest.NewLogger(t), clock.System) + + layer, found, err := r.ResolveInheritedAuthKeyLayer(context.Background(), authKeyID) + if err != nil || found || layer != 0 { + t.Fatalf("durable zero primary = (%d,%v,%v), want (0,false,nil)", layer, found, err) + } + if auth.authKeyInfoLookups != 1 || auth.authorizationLookups != 0 { + t.Fatalf("durable lookups = auth_key:%d authorization:%d, want 1/0", + auth.authKeyInfoLookups, auth.authorizationLookups) + } +} + +func TestExplicitLayerCorrectionUpdatesDefaultWithoutChangingSibling(t *testing.T) { + authKeyID := [8]byte{0x41} + auth := &captureAuthService{authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo)} + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + + ctx1 := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), authKeyID), 1), authKeyID) + ctx2 := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), authKeyID), 2), authKeyID) + r.rememberClientLayer(ctx1, 225) + r.rememberClientLayer(ctx2, 225) + r.rememberClientLayer(ctx1, 227) + + if layer, ok := r.NegotiatedSessionLayer(authKeyID, 1); !ok || layer != 227 { + t.Fatalf("corrected session = (%d,%v), want (227,true)", layer, ok) + } + if layer, ok := r.NegotiatedSessionLayer(authKeyID, 2); !ok || layer != 225 { + t.Fatalf("sibling session = (%d,%v), want unchanged (225,true)", layer, ok) + } + if got := auth.authKeyClientInfos[authKeyID].Layer; got != 227 { + t.Fatalf("durable shared default = %d, want 227", got) + } + layer, found, err := r.ResolveInheritedAuthKeyLayer(context.Background(), authKeyID) + if err != nil || !found || layer != 227 { + t.Fatalf("new session default = (%d,%v,%v), want (227,true,nil)", layer, found, err) + } +} + +type inheritedLayerSeedCall struct { + rawAuthKeyID [8]byte + layer int +} + +type inheritedLayerCaptureSessions struct { + captureSessions + seeds []inheritedLayerSeedCall + refreshes []inheritedLayerSeedCall + clears [][8]byte + explicitLayer int + explicitMsgID int64 +} + +func (s *inheritedLayerCaptureSessions) BindAuthKeyForRawAuthKey(rawAuthKeyID [8]byte, authKeyID [8]byte) int { + s.BindAuthKeyForSession(rawAuthKeyID, 0, authKeyID) + return 1 +} + +func (s *inheritedLayerCaptureSessions) SeedInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte, layer int) int { + s.seeds = append(s.seeds, inheritedLayerSeedCall{rawAuthKeyID: rawAuthKeyID, layer: layer}) + return 1 +} + +func (s *inheritedLayerCaptureSessions) RefreshInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte, layer int) int { + s.refreshes = append(s.refreshes, inheritedLayerSeedCall{rawAuthKeyID: rawAuthKeyID, layer: layer}) + return 1 +} + +func (s *inheritedLayerCaptureSessions) ClearInheritedLayerForRawAuthKey(rawAuthKeyID [8]byte) int { + s.clears = append(s.clears, rawAuthKeyID) + return 1 +} + +func (s *inheritedLayerCaptureSessions) ExplicitLayerEvidenceForAuthKey([8]byte, int64) (int, int64, bool) { + return s.explicitLayer, s.explicitMsgID, s.explicitLayer != 0 +} + +func TestBindTempAuthKeyLayerPrecedenceAndRawShadow(t *testing.T) { + for _, tt := range []struct { + name string + explicitLayer int + want int + }{ + {name: "inherit permanent", want: 225}, + {name: "current explicit wins", explicitLayer: 227, want: 227}, + } { + t.Run(tt.name, func(t *testing.T) { + rawAuthKeyID := [8]byte{0x51, byte(tt.want)} + permAuthKeyID := [8]byte{0x52, byte(tt.want)} + const sessionID = int64(99) + auth := &captureAuthService{authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + permAuthKeyID: {Layer: 225}, + }} + // Model the store-owned bind transaction. The router must only reload + // this merged permanent primary; it must not derive or persist a winner + // from its process-local exact-session registry after Bind returns. + auth.bindTempHook = func(domain.TempAuthKeyBinding) error { + auth.authKeyClientInfos[rawAuthKeyID] = domain.AuthKeyClientInfo{Layer: tt.want, LayerObservationID: 42} + auth.authKeyClientInfos[permAuthKeyID] = domain.AuthKeyClientInfo{Layer: tt.want, LayerObservationID: 42} + return nil + } + sessions := &inheritedLayerCaptureSessions{} + r := New(Config{DC: 2}, Deps{Auth: auth, Sessions: sessions}, zaptest.NewLogger(t), clock.System) + if tt.explicitLayer != 0 { + freezeAndPublishLayer(t, r, rawAuthKeyID, sessionID, 10, 1, tt.explicitLayer) + sessions.seeds = nil + } + ctx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), rawAuthKeyID), sessionID), rawAuthKeyID) + ok, err := r.onAuthBindTempAuthKey(ctx, &tg.AuthBindTempAuthKeyRequest{PermAuthKeyID: businessAuthKeyInt64(permAuthKeyID)}) + if err != nil || !ok { + t.Fatalf("bind = (%v,%v), want (true,nil)", ok, err) + } + if got := auth.authKeyClientInfos[rawAuthKeyID].Layer; got != tt.want { + t.Fatalf("raw shadow = %d, want %d", got, tt.want) + } + if got := auth.authKeyClientInfos[permAuthKeyID].Layer; got != tt.want { + t.Fatalf("permanent default = %d, want %d", got, tt.want) + } + if len(sessions.refreshes) != 1 || sessions.refreshes[0] != (inheritedLayerSeedCall{rawAuthKeyID: rawAuthKeyID, layer: tt.want}) { + t.Fatalf("refresh calls = %+v", sessions.refreshes) + } + if len(sessions.seeds) != 0 { + t.Fatalf("bind used ordinary seed instead of identity refresh: %+v", sessions.seeds) + } + if cached, found := r.cachedAuthKeyLayerDefault(rawAuthKeyID); !found || cached != tt.want { + t.Fatalf("raw cached default = (%d,%v), want (%d,true)", cached, found, tt.want) + } + r.clientInfoMu.RLock() + rawCached := r.authInfo[rawAuthKeyID] + permCached := r.authInfo[permAuthKeyID] + r.clientInfoMu.RUnlock() + if rawCached.layerObservationID != 42 || rawCached.layerObservationID != permCached.layerObservationID { + t.Fatalf("bound observation shadow = raw:%d perm:%d, want 42/42", + rawCached.layerObservationID, permCached.layerObservationID) + } + }) + } +} + +func TestResolveInheritedAuthKeyLayerCachesTerminalMissingRows(t *testing.T) { + authKeyID := [8]byte{0x61} + auth := &captureAuthService{authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo)} + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + + for i := 0; i < 2; i++ { + layer, found, err := r.ResolveInheritedAuthKeyLayer(context.Background(), authKeyID) + if err != nil || found || layer != 0 { + t.Fatalf("resolve %d = (%d,%v,%v), want (0,false,nil)", i, layer, found, err) + } + } + if auth.authKeyInfoLookups != 1 || auth.authorizationLookups != 0 { + t.Fatalf("terminal missing lookups = auth_key:%d authorization:%d, want 1/0", auth.authKeyInfoLookups, auth.authorizationLookups) + } +} + +func TestResolveInheritedBoundTempUnsupportedPermanentBlocksRawShadow(t *testing.T) { + rawAuthKeyID := [8]byte{0x62} + permAuthKeyID := [8]byte{0x63} + auth := &captureAuthService{ + resolvedAuthKeyID: permAuthKeyID, + hasResolved: true, + authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + rawAuthKeyID: {Layer: 225}, + permAuthKeyID: {Layer: 229}, + }, + } + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + + layer, authoritative, err := r.ResolveInheritedAuthKeyLayer(context.Background(), rawAuthKeyID) + if err != nil || !authoritative || layer != 0 { + t.Fatalf("bound future default = (%d,%v,%v), want (0,true,nil)", layer, authoritative, err) + } + if auth.authKeyInfoLookups != 1 { + t.Fatalf("canonical auth-key lookups = %d, want 1", auth.authKeyInfoLookups) + } +} + +func TestBindTempAuthKeyFuturePermanentClearsInheritedUntilFreshExplicit(t *testing.T) { + rawAuthKeyID := [8]byte{0x62, 1} + permAuthKeyID := [8]byte{0x62, 2} + const sessionID = int64(621) + auth := &captureAuthService{ + resolvedAuthKeyID: permAuthKeyID, + hasResolved: true, + authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + rawAuthKeyID: {Layer: 225}, + permAuthKeyID: {Layer: 229, LayerObservationID: 44}, + }, + } + auth.bindTempHook = func(domain.TempAuthKeyBinding) error { + auth.authKeyClientInfos[rawAuthKeyID] = domain.AuthKeyClientInfo{Layer: 229, LayerObservationID: 44} + return nil + } + sessions := &inheritedLayerCaptureSessions{} + r := New(Config{DC: 2}, Deps{Auth: auth, Sessions: sessions}, zaptest.NewLogger(t), clock.System) + r.setAuthKeyLayerDefaults(225, rawAuthKeyID) + ctx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), rawAuthKeyID), sessionID), rawAuthKeyID) + ok, err := r.onAuthBindTempAuthKey(ctx, &tg.AuthBindTempAuthKeyRequest{PermAuthKeyID: businessAuthKeyInt64(permAuthKeyID)}) + if err != nil || !ok { + t.Fatalf("bind to future permanent = (%v,%v)", ok, err) + } + if len(sessions.clears) != 1 || sessions.clears[0] != rawAuthKeyID { + t.Fatalf("inherited clear calls = %x", sessions.clears) + } + if len(sessions.refreshes) != 0 { + t.Fatalf("future permanent refreshed stale inherited profile: %+v", sessions.refreshes) + } + r.clientInfoMu.RLock() + blocked := r.authInfo[rawAuthKeyID] + r.clientInfoMu.RUnlock() + if blocked.layer != 0 || blocked.layerObservationID != 44 || !blocked.layerBlocked || !blocked.layerBlockedByAuthKey { + t.Fatalf("raw blocked shadow = %+v", blocked) + } + + // A later in-window explicit selector is new wire evidence and may correct + // both the session and the permanent shared default. + freezeAndPublishLayer(t, r, rawAuthKeyID, sessionID, 20, 1, 225) + if got := auth.authKeyClientInfos[permAuthKeyID].Layer; got != 225 { + t.Fatalf("fresh explicit did not self-heal future default: %d", got) + } + if got, found := r.cachedAuthKeyLayerDefault(rawAuthKeyID); !found || got != 225 { + t.Fatalf("raw default after self-heal = (%d,%v)", got, found) + } +} + +func TestSupportedExplicitEvidenceClearsUnsupportedCacheState(t *testing.T) { + authKeyID := [8]byte{0x63, 1} + auth := &captureAuthService{authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + authKeyID: {Layer: 229}, + }} + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + if layer, found, err := r.ResolveInheritedAuthKeyLayer(context.Background(), authKeyID); err != nil || !found || layer != 0 { + t.Fatalf("future default = (%d,%v,%v), want (0,true,nil)", layer, found, err) + } + freezeAndPublishLayer(t, r, authKeyID, 1, 10, 1, 228) + r.clientInfoMu.RLock() + info := r.authInfo[authKeyID] + r.clientInfoMu.RUnlock() + if info.layer != 228 || info.layerBlocked || info.layerBlockedByAuthKey { + t.Fatalf("supported and blocked cache state coexisted: %+v", info) + } +} + +type inheritedLayerResolution struct { + layer int + found bool + err error +} + +type blockingLayerReadAuthService struct { + *captureAuthService + started chan struct{} + release chan struct{} + once sync.Once + stale domain.AuthKeyClientInfo +} + +func (s *blockingLayerReadAuthService) AuthKeyClientInfo(ctx context.Context, _ [8]byte) (domain.AuthKeyClientInfo, bool, error) { + s.authKeyInfoLookups++ + s.once.Do(func() { close(s.started) }) + select { + case <-s.release: + return s.stale, true, nil + case <-ctx.Done(): + return domain.AuthKeyClientInfo{}, false, ctx.Err() + } +} + +func TestResolveInheritedLayerDoesNotReturnStaleSingleflightRead(t *testing.T) { + authKeyID := [8]byte{0x64} + const sessionID = int64(640) + auth := &blockingLayerReadAuthService{ + captureAuthService: &captureAuthService{authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo)}, + started: make(chan struct{}), + release: make(chan struct{}), + stale: domain.AuthKeyClientInfo{Layer: 225}, + } + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + resolved := make(chan inheritedLayerResolution, 1) + go func() { + layer, found, err := r.ResolveInheritedAuthKeyLayer(context.Background(), authKeyID) + resolved <- inheritedLayerResolution{layer: layer, found: found, err: err} + }() + <-auth.started + + freezeAndPublishLayer(t, r, authKeyID, sessionID, 100, 2, 227) + close(auth.release) + got := <-resolved + if got.err != nil || !got.found || got.layer != 227 { + t.Fatalf("resolver returned stale DB value = (%d,%v,%v), want (227,true,nil)", got.layer, got.found, got.err) + } +} + +func TestBoundDurableResolveCannotProjectStalePermanentLayerOverNewObservation(t *testing.T) { + ctx := context.Background() + keys := memory.NewAuthKeyStore() + bindings := memory.NewTempAuthKeyBindingStore(keys) + rawAuthKeyID := [8]byte{0x64, 1} + permAuthKeyID := [8]byte{0x64, 2} + const ( + sessionID = int64(641) + tempExpiry = 2_000_000_000 + ) + if err := keys.Save(ctx, store.AuthKeyData{ID: rawAuthKeyID, ExpiresAt: tempExpiry}); err != nil { + t.Fatal(err) + } + if err := keys.Save(ctx, store.AuthKeyData{ + ID: permAuthKeyID, Layer: 225, LayerObservationID: 1, + }); err != nil { + t.Fatal(err) + } + if err := bindings.Save(ctx, domain.TempAuthKeyBinding{ + TempAuthKeyID: rawAuthKeyID, + PermAuthKeyID: int64(binary.LittleEndian.Uint64(permAuthKeyID[:])), + ExpiresAt: tempExpiry, + }); err != nil { + t.Fatal(err) + } + auth := &blockingLayerReadAuthService{ + captureAuthService: &captureAuthService{ + resolvedAuthKeyID: permAuthKeyID, + hasResolved: true, + }, + started: make(chan struct{}), + release: make(chan struct{}), + stale: domain.AuthKeyClientInfo{Layer: 225, LayerObservationID: 1}, + } + sessions := &inheritedLayerCaptureSessions{} + r := New(Config{DC: 2}, Deps{ + Auth: auth, Sessions: sessions, AuthKeySessionLayers: keys, + }, zaptest.NewLogger(t), clock.System) + resolved := make(chan inheritedLayerResolution, 1) + go func() { + layer, found, err := r.ResolveInheritedAuthKeyLayer(ctx, rawAuthKeyID) + resolved <- inheritedLayerResolution{layer: layer, found: found, err: err} + }() + <-auth.started + + msgID := int64((uint64(time.Now().UTC().Unix()) << 32) | 4) + if layer, gotMsgID, publish, err := r.AdvanceNegotiatedSessionLayerEvidence( + ctx, rawAuthKeyID, sessionID, 227, msgID, + ); err != nil || layer != 227 || gotMsgID != msgID || !publish { + t.Fatalf("advance while stale read blocked = (%d,%d,%v,%v)", layer, gotMsgID, publish, err) + } + if err := r.PublishAdmittedLayerProfileEvidence(ctx, rawAuthKeyID, sessionID, msgID, 2, 1, 227); err != nil { + t.Fatal(err) + } + close(auth.release) + got := <-resolved + if got.err != nil || !got.found || got.layer != 227 { + t.Fatalf("bound resolver returned stale permanent read = (%d,%v,%v)", got.layer, got.found, got.err) + } + + permanent, found, err := keys.Get(ctx, permAuthKeyID) + if err != nil || !found || permanent.Layer != 227 || permanent.LayerObservationID <= 1 { + t.Fatalf("durable permanent tuple = (%+v,%v,%v)", permanent, found, err) + } + r.clientInfoMu.RLock() + rawInfo := r.authInfo[rawAuthKeyID] + permInfo := r.authInfo[permAuthKeyID] + r.clientInfoMu.RUnlock() + for id, info := range map[[8]byte]clientSessionInfo{ + rawAuthKeyID: rawInfo, permAuthKeyID: permInfo, + } { + if info.layer != permanent.Layer || info.layerObservationID != permanent.LayerObservationID { + t.Fatalf("cache %x = layer/obs %d/%d, durable %d/%d", + id, info.layer, info.layerObservationID, permanent.Layer, permanent.LayerObservationID) + } + } +} + +func TestAdmittedLayerSequenceOrdersSharedDefaultAcrossSessions(t *testing.T) { + rawOld := [8]byte{0x65, 1} + rawNew := [8]byte{0x65, 2} + permAuthKeyID := [8]byte{0x65, 3} + auth := &captureAuthService{ + resolvedAuthKeyID: permAuthKeyID, + hasResolved: true, + authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo), + } + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + if _, err := r.FreezeNegotiatedSessionLayerAt(rawOld, 1, 225, 10); err != nil { + t.Fatal(err) + } + if _, err := r.FreezeNegotiatedSessionLayerAt(rawNew, 2, 227, 20); err != nil { + t.Fatal(err) + } + + if err := r.PublishAdmittedLayerProfileEvidence(context.Background(), rawNew, 2, 20, 2, 1, 227); err != nil { + t.Fatal(err) + } + if err := r.PublishAdmittedLayerProfileEvidence(context.Background(), rawOld, 1, 10, 1, 1, 225); err != nil { + t.Fatal(err) + } + if got := auth.authKeyClientInfos[permAuthKeyID].Layer; got != 227 { + t.Fatalf("durable shared default rolled back = %d, want 227", got) + } + if got, ok := r.cachedAuthKeyLayerDefault(permAuthKeyID); !ok || got != 227 { + t.Fatalf("memory shared default = (%d,%v), want (227,true)", got, ok) + } + if got, ok := r.NegotiatedSessionLayer(rawOld, 1); !ok || got != 225 { + t.Fatalf("old live session changed = (%d,%v), want (225,true)", got, ok) + } +} + +func TestDurableObservationOrdersLocalDefaultWhenAdmissionCommitsInReverse(t *testing.T) { + ctx := context.Background() + keys := memory.NewAuthKeyStore() + bindings := memory.NewTempAuthKeyBindingStore(keys) + rawEarlierAdmission := [8]byte{0x65, 0x11} + rawLaterAdmission := [8]byte{0x65, 0x12} + permAuthKeyID := [8]byte{0x65, 0x13} + const tempExpiry = 2_000_000_000 + for _, key := range []store.AuthKeyData{ + {ID: rawEarlierAdmission, ExpiresAt: tempExpiry}, + {ID: rawLaterAdmission, ExpiresAt: tempExpiry}, + {ID: permAuthKeyID}, + } { + if err := keys.Save(ctx, key); err != nil { + t.Fatal(err) + } + } + for index, raw := range [][8]byte{rawEarlierAdmission, rawLaterAdmission} { + if err := bindings.Save(ctx, domain.TempAuthKeyBinding{ + TempAuthKeyID: raw, + PermAuthKeyID: int64(binary.LittleEndian.Uint64(permAuthKeyID[:])), + Nonce: int64(index + 1), + ExpiresAt: tempExpiry, + }); err != nil { + t.Fatal(err) + } + } + auth := &captureAuthService{resolvedAuthKeyID: permAuthKeyID, hasResolved: true} + sessions := &inheritedLayerCaptureSessions{} + r := New(Config{DC: 2}, Deps{ + Auth: auth, Sessions: sessions, AuthKeySessionLayers: keys, + }, zaptest.NewLogger(t), clock.System) + now := time.Now().UTC() + msgLaterAdmission := int64((uint64(now.Unix()) << 32) | 4) + msgEarlierAdmission := int64((uint64(now.Unix()) << 32) | 8) + + // Admission sequence 2 reaches the permanent identity gate and commits + // first. It is temporarily the durable/local default. + if layer, msgID, publish, err := r.AdvanceNegotiatedSessionLayerEvidence( + ctx, rawLaterAdmission, 2, 227, msgLaterAdmission, + ); err != nil || layer != 227 || msgID != msgLaterAdmission || !publish { + t.Fatalf("later admission first commit = (%d,%d,%v,%v)", layer, msgID, publish, err) + } + if err := r.PublishAdmittedLayerProfileEvidence( + ctx, rawLaterAdmission, 2, msgLaterAdmission, 2, 1, 227, + ); err != nil { + t.Fatal(err) + } + + // Admission sequence 1 was allocated earlier but commits second. Database + // observation order is authoritative, so local authInfo/session seeding must + // move to 225 despite the lower process admission sequence. + if layer, msgID, publish, err := r.AdvanceNegotiatedSessionLayerEvidence( + ctx, rawEarlierAdmission, 1, 225, msgEarlierAdmission, + ); err != nil || layer != 225 || msgID != msgEarlierAdmission || !publish { + t.Fatalf("earlier admission late commit = (%d,%d,%v,%v)", layer, msgID, publish, err) + } + if err := r.PublishAdmittedLayerProfileEvidence( + ctx, rawEarlierAdmission, 1, msgEarlierAdmission, 1, 1, 225, + ); err != nil { + t.Fatal(err) + } + + permanent, found, err := keys.Get(ctx, permAuthKeyID) + if err != nil || !found || permanent.Layer != 225 || permanent.LayerObservationID <= 0 { + t.Fatalf("durable permanent default = (%+v,%v,%v)", permanent, found, err) + } + r.clientInfoMu.RLock() + local := r.authInfo[permAuthKeyID] + r.clientInfoMu.RUnlock() + if local.layer != permanent.Layer || local.layerObservationID != permanent.LayerObservationID { + t.Fatalf("local default = layer/obs %d/%d, durable %d/%d", + local.layer, local.layerObservationID, permanent.Layer, permanent.LayerObservationID) + } + lastSeed := 0 + for _, seed := range sessions.seeds { + if seed.rawAuthKeyID == permAuthKeyID { + lastSeed = seed.layer + } + } + if lastSeed != 225 { + t.Fatalf("SessionManager permanent seed = %d, want 225", lastSeed) + } +} + +type blockingLayerWriteAuthService struct { + *captureAuthService + mu sync.Mutex + started chan struct{} + release chan struct{} + updates int + blockFirst sync.Once +} + +func (s *blockingLayerWriteAuthService) UpdateAuthKeyClientInfo(ctx context.Context, authKeyID [8]byte, info domain.AuthKeyClientInfo) error { + s.mu.Lock() + s.updates++ + first := s.updates == 1 + s.mu.Unlock() + if first { + s.blockFirst.Do(func() { close(s.started) }) + select { + case <-s.release: + case <-ctx.Done(): + return ctx.Err() + } + } + s.mu.Lock() + defer s.mu.Unlock() + return s.captureAuthService.UpdateAuthKeyClientInfo(ctx, authKeyID, info) +} + +func (s *blockingLayerWriteAuthService) layer(authKeyID [8]byte) int { + s.mu.Lock() + defer s.mu.Unlock() + return s.authKeyClientInfos[authKeyID].Layer +} + +func TestAdmittedLayerPersistentWritesFollowAdmissionSequence(t *testing.T) { + rawOld := [8]byte{0x66, 1} + rawNew := [8]byte{0x66, 2} + permAuthKeyID := [8]byte{0x66, 3} + auth := &blockingLayerWriteAuthService{ + captureAuthService: &captureAuthService{ + resolvedAuthKeyID: permAuthKeyID, + hasResolved: true, + authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo), + }, + started: make(chan struct{}), + release: make(chan struct{}), + } + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + if _, err := r.FreezeNegotiatedSessionLayerAt(rawOld, 1, 225, 10); err != nil { + t.Fatal(err) + } + if _, err := r.FreezeNegotiatedSessionLayerAt(rawNew, 2, 227, 20); err != nil { + t.Fatal(err) + } + + errs := make(chan error, 2) + go func() { errs <- r.PublishAdmittedLayerProfileEvidence(context.Background(), rawOld, 1, 10, 1, 1, 225) }() + <-auth.started + go func() { errs <- r.PublishAdmittedLayerProfileEvidence(context.Background(), rawNew, 2, 20, 2, 1, 227) }() + close(auth.release) + for i := 0; i < 2; i++ { + if err := <-errs; err != nil { + t.Fatal(err) + } + } + if got := auth.layer(permAuthKeyID); got != 227 { + t.Fatalf("ordered durable default = %d, want 227", got) + } +} + +func TestAuthLayerEvidenceCapacityUsesExactSafeFloor(t *testing.T) { + fill := func(r *Router) { + for i := uint64(1); i <= maxAuthLayerEvidenceEntries; i++ { + var id [8]byte + binary.LittleEndian.PutUint64(id[:], i) + r.authLayerEvidence[id] = authLayerDefaultEvidence{layer: 225, sequence: 1} + } + } + newID := [8]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff} + + t.Run("retired entry is evictable", func(t *testing.T) { + r := New(Config{DC: 2}, Deps{}, zaptest.NewLogger(t), clock.System) + fill(r) + r.authLayerSafeEvictionFloor = 2 + applied, err := r.claimAuthLayerDefaultEvidenceLocked(227, 2, false, newID) + if err != nil || !applied { + t.Fatalf("claim with retired capacity = (%v,%v), want (true,nil)", applied, err) + } + if len(r.authLayerEvidence) != maxAuthLayerEvidenceEntries { + t.Fatalf("evidence entries = %d, want %d", len(r.authLayerEvidence), maxAuthLayerEvidenceEntries) + } + if got := r.authLayerEvidence[newID]; got != (authLayerDefaultEvidence{layer: 227, sequence: 2}) { + t.Fatalf("new evidence = %+v", got) + } + }) + + t.Run("live entry is not evicted", func(t *testing.T) { + r := New(Config{DC: 2}, Deps{}, zaptest.NewLogger(t), clock.System) + fill(r) + r.authLayerSafeEvictionFloor = 1 + applied, err := r.claimAuthLayerDefaultEvidenceLocked(227, 2, false, newID) + if err != nil || applied { + t.Fatalf("claim with all-live capacity = (%v,%v), want (false,nil)", applied, err) + } + if _, exists := r.authLayerEvidence[newID]; exists { + t.Fatal("capacity refusal installed new evidence") + } + }) +} + +func TestAdmittedLayerSafeFloorIsMonotonic(t *testing.T) { + r := New(Config{DC: 2}, Deps{}, zaptest.NewLogger(t), clock.System) + first := [8]byte{0x67, 1} + second := [8]byte{0x67, 2} + if _, err := r.FreezeNegotiatedSessionLayerAt(first, 1, 225, 10); err != nil { + t.Fatal(err) + } + if err := r.PublishAdmittedLayerProfileEvidence(context.Background(), first, 1, 10, 2, 2, 225); err != nil { + t.Fatal(err) + } + if _, err := r.FreezeNegotiatedSessionLayerAt(second, 2, 227, 20); err != nil { + t.Fatal(err) + } + if err := r.PublishAdmittedLayerProfileEvidence(context.Background(), second, 2, 20, 3, 1, 227); err != nil { + t.Fatal(err) + } + r.clientInfoMu.RLock() + floor := r.authLayerSafeEvictionFloor + r.clientInfoMu.RUnlock() + if floor != 2 { + t.Fatalf("safe eviction floor regressed = %d, want 2", floor) + } +} + +func TestInvalidateAuthUserCachePreservesLayerEvidenceWatermark(t *testing.T) { + rawOld := [8]byte{0x68, 1} + permAuthKeyID := [8]byte{0x68, 2} + auth := &captureAuthService{ + resolvedAuthKeyID: permAuthKeyID, + hasResolved: true, + authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo), + } + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + freezeAndPublishLayer(t, r, permAuthKeyID, 2, 20, 2, 227) + r.invalidateAuthUserCache(permAuthKeyID) + freezeAndPublishLayer(t, r, rawOld, 1, 10, 1, 225) + if got := auth.authKeyClientInfos[permAuthKeyID].Layer; got != 227 { + t.Fatalf("authorization invalidation erased protocol order = %d, want 227", got) + } +} + +func TestStaleExactCorrectionSkipsSharedPublicationWithoutFailingRPC(t *testing.T) { + authKeyID := [8]byte{0x69} + auth := &captureAuthService{authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo)} + r := New(Config{DC: 2}, Deps{Auth: auth}, zaptest.NewLogger(t), clock.System) + if _, err := r.FreezeNegotiatedSessionLayerAt(authKeyID, 1, 225, 10); err != nil { + t.Fatal(err) + } + if _, err := r.FreezeNegotiatedSessionLayerAt(authKeyID, 1, 227, 20); err != nil { + t.Fatal(err) + } + if err := r.PublishAdmittedLayerProfileEvidence(context.Background(), authKeyID, 1, 10, 1, 1, 225); err != nil { + t.Fatalf("stale publication rejected immutable old RPC: %v", err) + } + if _, exists := auth.authKeyClientInfos[authKeyID]; exists { + t.Fatal("stale exact observation published durable default") + } + if err := r.PublishAdmittedLayerProfileEvidence(context.Background(), authKeyID, 1, 20, 2, 2, 227); err != nil { + t.Fatal(err) + } +} + +func TestBindTempAuthKeyUsesLiveExplicitLayerAfterExactTTL(t *testing.T) { + clk := &exactProfileTestClock{now: time.Unix(1_700_000_000, 0)} + rawAuthKeyID := [8]byte{0x6a, 1} + permAuthKeyID := [8]byte{0x6a, 2} + const sessionID = int64(106) + auth := &captureAuthService{authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + permAuthKeyID: {Layer: 225}, + }} + auth.bindTempHook = func(domain.TempAuthKeyBinding) error { + // The durable raw observation was published before the in-process exact + // registry expired. Bind merges that observation into the permanent row. + auth.authKeyClientInfos[rawAuthKeyID] = domain.AuthKeyClientInfo{Layer: 227} + auth.authKeyClientInfos[permAuthKeyID] = domain.AuthKeyClientInfo{Layer: 227} + return nil + } + sessions := &inheritedLayerCaptureSessions{explicitLayer: 227, explicitMsgID: 100} + r := New(Config{DC: 2}, Deps{Auth: auth, Sessions: sessions}, zaptest.NewLogger(t), clk) + freezeAndPublishLayer(t, r, rawAuthKeyID, sessionID, 100, 5, 227) + sessions.seeds = nil + clk.advance(exactSessionProfileTTL + time.Second) + if _, ok := r.NegotiatedSessionLayer(rawAuthKeyID, sessionID); ok { + t.Fatal("test setup retained expired exact registry entry") + } + + ctx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), rawAuthKeyID), sessionID), rawAuthKeyID) + ok, err := r.onAuthBindTempAuthKey(ctx, &tg.AuthBindTempAuthKeyRequest{PermAuthKeyID: businessAuthKeyInt64(permAuthKeyID)}) + if err != nil || !ok { + t.Fatalf("bind after exact TTL = (%v,%v)", ok, err) + } + if got := auth.authKeyClientInfos[permAuthKeyID].Layer; got != 227 { + t.Fatalf("live explicit Layer was lost at bind = %d, want 227", got) + } + if len(sessions.refreshes) != 1 || sessions.refreshes[0].layer != 227 { + t.Fatalf("bind refresh calls = %+v", sessions.refreshes) + } +} + +func TestNakedBindDoesNotRedateOlderExplicitEvidence(t *testing.T) { + rawAuthKeyID := [8]byte{0x6b, 1} + permAuthKeyID := [8]byte{0x6b, 2} + const sessionID = int64(107) + auth := &captureAuthService{authKeyClientInfos: make(map[[8]byte]domain.AuthKeyClientInfo)} + auth.bindTempHook = func(domain.TempAuthKeyBinding) error { + // The permanent observation is globally newer than the raw observation. + // Model the transaction's observation_id merge before the router reloads. + auth.authKeyClientInfos[rawAuthKeyID] = domain.AuthKeyClientInfo{Layer: 227} + auth.authKeyClientInfos[permAuthKeyID] = domain.AuthKeyClientInfo{Layer: 227} + return nil + } + sessions := &inheritedLayerCaptureSessions{explicitLayer: 225, explicitMsgID: 10} + r := New(Config{DC: 2}, Deps{Auth: auth, Sessions: sessions}, zaptest.NewLogger(t), clock.System) + freezeAndPublishLayer(t, r, rawAuthKeyID, sessionID, 10, 1, 225) + freezeAndPublishLayer(t, r, permAuthKeyID, 2, 20, 2, 227) + + ctx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), rawAuthKeyID), sessionID), rawAuthKeyID) + ctx = withLayerAdmissionSequence(ctx, 99) // naked bind order is not Layer evidence order. + ok, err := r.onAuthBindTempAuthKey(ctx, &tg.AuthBindTempAuthKeyRequest{PermAuthKeyID: businessAuthKeyInt64(permAuthKeyID)}) + if err != nil || !ok { + t.Fatalf("naked bind = (%v,%v)", ok, err) + } + if got := auth.authKeyClientInfos[permAuthKeyID].Layer; got != 227 { + t.Fatalf("naked bind re-dated old explicit Layer = %d, want 227", got) + } + if got := auth.authKeyClientInfos[rawAuthKeyID].Layer; got != 227 { + t.Fatalf("raw inherited shadow did not normalize to permanent default = %d", got) + } +} + +func TestRequestBoundBindHasNoStoreCacheOrSessionSideEffects(t *testing.T) { + rawAuthKeyID := [8]byte{0x6c, 1} + permAuthKeyID := [8]byte{0x6c, 2} + oldPermAuthKeyID := [8]byte{0x6c, 3} + const sessionID = int64(108) + auth := &captureAuthService{authKeyClientInfos: map[[8]byte]domain.AuthKeyClientInfo{ + rawAuthKeyID: {Layer: 227, DeviceModel: "raw-before"}, + permAuthKeyID: {Layer: 225}, + }} + sessions := &inheritedLayerCaptureSessions{explicitLayer: 227, explicitMsgID: 10} + r := New(Config{DC: 2}, Deps{Auth: auth, Sessions: sessions}, zaptest.NewLogger(t), clock.System) + sessions.BindAuthKeyForSession(rawAuthKeyID, sessionID, oldPermAuthKeyID) + beforeSession := sessions.snapshot() + now := time.Now() + r.tempKeyResolveCache.Store(rawAuthKeyID, oldPermAuthKeyID, now.Add(time.Hour), now) + r.setAuthUserCache(rawAuthKeyID, 101, true) + r.setAuthUserCache(permAuthKeyID, 202, true) + r.clientInfoMu.Lock() + if r.authInfo == nil { + r.authInfo = make(map[[8]byte]clientSessionInfo) + } + r.authInfo[rawAuthKeyID] = clientSessionInfo{ + layer: 227, layerAdmissionSeq: 11, authKeyInfoChecked: true, + authorizationChecked: true, hasClientInfo: true, + clientInfo: ClientInfo{DeviceModel: "raw-cache"}, + } + r.authInfo[permAuthKeyID] = clientSessionInfo{ + layer: 225, layerAdmissionSeq: 9, authKeyInfoChecked: true, + authorizationChecked: true, hasClientInfo: true, + clientInfo: ClientInfo{DeviceModel: "perm-cache"}, + } + beforeRawInfo := r.authInfo[rawAuthKeyID] + beforePermInfo := r.authInfo[permAuthKeyID] + r.clientInfoMu.Unlock() + + ctx := WithAuthKeyID(WithSessionID(WithRawAuthKeyID(context.Background(), rawAuthKeyID), sessionID), rawAuthKeyID) + ctx = r.WithLayerRPCProfileEvidenceFresh(ctx, false) + ok, err := r.onAuthBindTempAuthKey(ctx, &tg.AuthBindTempAuthKeyRequest{PermAuthKeyID: businessAuthKeyInt64(permAuthKeyID)}) + if ok || !tgerr.Is(err, "TEMP_AUTH_KEY_EMPTY") { + t.Fatalf("stale request-bound bind = (%v,%v), want (false,TEMP_AUTH_KEY_EMPTY)", ok, err) + } + if auth.bindTempCalls != 0 || auth.resolveCount != 0 || auth.authKeyInfoLookups != 0 || auth.authorizationLookups != 0 { + t.Fatalf("stale bind touched auth store: bind=%d resolve=%d key=%d authorization=%d", + auth.bindTempCalls, auth.resolveCount, auth.authKeyInfoLookups, auth.authorizationLookups) + } + if got := auth.authKeyClientInfos[rawAuthKeyID]; got != (domain.AuthKeyClientInfo{Layer: 227, DeviceModel: "raw-before"}) { + t.Fatalf("stale bind changed raw durable fake: %+v", got) + } + if got := auth.authKeyClientInfos[permAuthKeyID]; got != (domain.AuthKeyClientInfo{Layer: 225}) { + t.Fatalf("stale bind changed permanent durable fake: %+v", got) + } + if got := sessions.snapshot(); got != beforeSession { + t.Fatalf("stale bind changed session binding: got %+v want %+v", got, beforeSession) + } + if len(sessions.seeds) != 0 || len(sessions.refreshes) != 0 || len(sessions.clears) != 0 { + t.Fatalf("stale bind changed inherited session state: seeds=%+v refreshes=%+v clears=%x", + sessions.seeds, sessions.refreshes, sessions.clears) + } + if got, found := r.tempKeyResolveCache.Get(rawAuthKeyID, oldPermAuthKeyID, now); !found || got != oldPermAuthKeyID { + t.Fatalf("stale bind changed temp-key cache: got=%x found=%v", got, found) + } + r.authUserMu.RLock() + rawUser := r.authUsers[rawAuthKeyID] + permUser := r.authUsers[permAuthKeyID] + r.authUserMu.RUnlock() + if rawUser != (authUserCacheEntry{userID: 101, found: true}) || permUser != (authUserCacheEntry{userID: 202, found: true}) { + t.Fatalf("stale bind changed auth-user cache: raw=%+v perm=%+v", rawUser, permUser) + } + r.clientInfoMu.RLock() + afterRawInfo := r.authInfo[rawAuthKeyID] + afterPermInfo := r.authInfo[permAuthKeyID] + r.clientInfoMu.RUnlock() + if afterRawInfo != beforeRawInfo || afterPermInfo != beforePermInfo { + t.Fatalf("stale bind changed layer cache: raw=%+v/%+v perm=%+v/%+v", + afterRawInfo, beforeRawInfo, afterPermInfo, beforePermInfo) + } +} + +func freezeAndPublishLayer(t *testing.T, r *Router, rawAuthKeyID [8]byte, sessionID, msgID int64, admissionSeq uint64, layer int) { + t.Helper() + if _, err := r.FreezeNegotiatedSessionLayerAt(rawAuthKeyID, sessionID, layer, msgID); err != nil { + t.Fatal(err) + } + if err := r.PublishAdmittedLayerProfileEvidence(context.Background(), rawAuthKeyID, sessionID, msgID, admissionSeq, 1, layer); err != nil { + t.Fatal(err) + } +} diff --git a/internal/rpc/linked_discussion_projection.go b/internal/rpc/linked_discussion_projection.go index beda05c1..d071efc0 100644 --- a/internal/rpc/linked_discussion_projection.go +++ b/internal/rpc/linked_discussion_projection.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/media_count.go b/internal/rpc/media_count.go index 53f694b5..bd0cb01a 100644 --- a/internal/rpc/media_count.go +++ b/internal/rpc/media_count.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/message_edit_hide_projection_test.go b/internal/rpc/message_edit_hide_projection_test.go index f94d360e..7b88cbff 100644 --- a/internal/rpc/message_edit_hide_projection_test.go +++ b/internal/rpc/message_edit_hide_projection_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/message_effect_projection_test.go b/internal/rpc/message_effect_projection_test.go index 6f71e1d8..bc599265 100644 --- a/internal/rpc/message_effect_projection_test.go +++ b/internal/rpc/message_effect_projection_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/message_entities_autodetect.go b/internal/rpc/message_entities_autodetect.go index 5e9e2490..472a448a 100644 --- a/internal/rpc/message_entities_autodetect.go +++ b/internal/rpc/message_entities_autodetect.go @@ -5,7 +5,7 @@ import ( "unicode" "unicode/utf8" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) // 服务端自动实体检测:@mention / #hashtag / $cashtag / bot command。 diff --git a/internal/rpc/message_grouped_projection_test.go b/internal/rpc/message_grouped_projection_test.go index de11ec62..0c3d3289 100644 --- a/internal/rpc/message_grouped_projection_test.go +++ b/internal/rpc/message_grouped_projection_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/message_idempotency.go b/internal/rpc/message_idempotency.go index c70677f8..4c06b4c6 100644 --- a/internal/rpc/message_idempotency.go +++ b/internal/rpc/message_idempotency.go @@ -4,8 +4,8 @@ import ( "crypto/sha256" "fmt" - "github.com/gotd/td/bin" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/tg" ) // rpcRequestFingerprint 在任何自动实体补全、链接预览解析或上传媒体落库之前, diff --git a/internal/rpc/message_idempotency_test.go b/internal/rpc/message_idempotency_test.go index 7633995b..5ef09c31 100644 --- a/internal/rpc/message_idempotency_test.go +++ b/internal/rpc/message_idempotency_test.go @@ -6,9 +6,9 @@ import ( "fmt" "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" "telesrv/internal/domain" diff --git a/internal/rpc/message_replay_preflight_test.go b/internal/rpc/message_replay_preflight_test.go index 6d1d33b2..2e97e56a 100644 --- a/internal/rpc/message_replay_preflight_test.go +++ b/internal/rpc/message_replay_preflight_test.go @@ -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" diff --git a/internal/rpc/messages_attach_menu.go b/internal/rpc/messages_attach_menu.go index be2d866f..7423e84e 100644 --- a/internal/rpc/messages_attach_menu.go +++ b/internal/rpc/messages_attach_menu.go @@ -4,7 +4,7 @@ import ( "context" "strconv" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_attach_menu_rpc_test.go b/internal/rpc/messages_attach_menu_rpc_test.go index ef729403..bb9cc256 100644 --- a/internal/rpc/messages_attach_menu_rpc_test.go +++ b/internal/rpc/messages_attach_menu_rpc_test.go @@ -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" ) func TestMessagesAttachMenuBotsEmptyCatalog(t *testing.T) { diff --git a/internal/rpc/messages_bot_longtail.go b/internal/rpc/messages_bot_longtail.go index c75f2f52..68cf4f81 100644 --- a/internal/rpc/messages_bot_longtail.go +++ b/internal/rpc/messages_bot_longtail.go @@ -6,7 +6,7 @@ import ( "strings" "unicode/utf8" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_bot_longtail_rpc_test.go b/internal/rpc/messages_bot_longtail_rpc_test.go index e4386f88..7f92bd87 100644 --- a/internal/rpc/messages_bot_longtail_rpc_test.go +++ b/internal/rpc/messages_bot_longtail_rpc_test.go @@ -5,9 +5,9 @@ import ( "strings" "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" "telesrv/internal/store" diff --git a/internal/rpc/messages_bot_no_state.go b/internal/rpc/messages_bot_no_state.go index d18edd86..ea271fb8 100644 --- a/internal/rpc/messages_bot_no_state.go +++ b/internal/rpc/messages_bot_no_state.go @@ -4,7 +4,7 @@ import ( "context" "unicode/utf8" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_bot_no_state_rpc_test.go b/internal/rpc/messages_bot_no_state_rpc_test.go index 8e6a2cd5..03a16c2d 100644 --- a/internal/rpc/messages_bot_no_state_rpc_test.go +++ b/internal/rpc/messages_bot_no_state_rpc_test.go @@ -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" ) diff --git a/internal/rpc/messages_channel_forward_rpc_test.go b/internal/rpc/messages_channel_forward_rpc_test.go index 6240c76e..305a0fe5 100644 --- a/internal/rpc/messages_channel_forward_rpc_test.go +++ b/internal/rpc/messages_channel_forward_rpc_test.go @@ -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" appchannels "telesrv/internal/app/channels" appmessages "telesrv/internal/app/messages" diff --git a/internal/rpc/messages_chat_theme_rpc_test.go b/internal/rpc/messages_chat_theme_rpc_test.go index e0af9bc9..5d426df7 100644 --- a/internal/rpc/messages_chat_theme_rpc_test.go +++ b/internal/rpc/messages_chat_theme_rpc_test.go @@ -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" diff --git a/internal/rpc/messages_compat.go b/internal/rpc/messages_compat.go index bf8a776d..af120cdb 100644 --- a/internal/rpc/messages_compat.go +++ b/internal/rpc/messages_compat.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "strings" "telesrv/internal/domain" diff --git a/internal/rpc/messages_contracts.go b/internal/rpc/messages_contracts.go index daf4acab..13478fa2 100644 --- a/internal/rpc/messages_contracts.go +++ b/internal/rpc/messages_contracts.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_create_chat_test.go b/internal/rpc/messages_create_chat_test.go index 1ab72f68..9176b763 100644 --- a/internal/rpc/messages_create_chat_test.go +++ b/internal/rpc/messages_create_chat_test.go @@ -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" "strings" appchannels "telesrv/internal/app/channels" diff --git a/internal/rpc/messages_delete.go b/internal/rpc/messages_delete.go index adea5ce9..69b2f8be 100644 --- a/internal/rpc/messages_delete.go +++ b/internal/rpc/messages_delete.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_delete_rpc_test.go b/internal/rpc/messages_delete_rpc_test.go index 1361ff09..ced63a3e 100644 --- a/internal/rpc/messages_delete_rpc_test.go +++ b/internal/rpc/messages_delete_rpc_test.go @@ -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" "telesrv/internal/domain" diff --git a/internal/rpc/messages_dialogs.go b/internal/rpc/messages_dialogs.go index ade702fe..b9f98689 100644 --- a/internal/rpc/messages_dialogs.go +++ b/internal/rpc/messages_dialogs.go @@ -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/domain" "unicode/utf8" diff --git a/internal/rpc/messages_drafts_difference_test.go b/internal/rpc/messages_drafts_difference_test.go index 9d053d18..5e5de2e6 100644 --- a/internal/rpc/messages_drafts_difference_test.go +++ b/internal/rpc/messages_drafts_difference_test.go @@ -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" appdialogs "telesrv/internal/app/dialogs" diff --git a/internal/rpc/messages_edit.go b/internal/rpc/messages_edit.go index 28d15e1c..8c92807e 100644 --- a/internal/rpc/messages_edit.go +++ b/internal/rpc/messages_edit.go @@ -3,7 +3,7 @@ package rpc import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" "unicode/utf8" ) diff --git a/internal/rpc/messages_edit_geolive.go b/internal/rpc/messages_edit_geolive.go index a09c28c0..5875dc3d 100644 --- a/internal/rpc/messages_edit_geolive.go +++ b/internal/rpc/messages_edit_geolive.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_edit_geolive_test.go b/internal/rpc/messages_edit_geolive_test.go index 3399df38..0fb1ffbb 100644 --- a/internal/rpc/messages_edit_geolive_test.go +++ b/internal/rpc/messages_edit_geolive_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" ) func sendTestLiveLocation(t *testing.T, r *Router, fromID int64, peer tg.InputPeerClass, randomID int64, period int) *tg.Message { diff --git a/internal/rpc/messages_edit_rpc_test.go b/internal/rpc/messages_edit_rpc_test.go index df17f88d..563b102f 100644 --- a/internal/rpc/messages_edit_rpc_test.go +++ b/internal/rpc/messages_edit_rpc_test.go @@ -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" "strings" "telesrv/internal/domain" diff --git a/internal/rpc/messages_forum.go b/internal/rpc/messages_forum.go index d61204f6..b85a7442 100644 --- a/internal/rpc/messages_forum.go +++ b/internal/rpc/messages_forum.go @@ -3,7 +3,7 @@ package rpc import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "strings" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" diff --git a/internal/rpc/messages_forum_read.go b/internal/rpc/messages_forum_read.go index 16dbda61..3d7e96c7 100644 --- a/internal/rpc/messages_forum_read.go +++ b/internal/rpc/messages_forum_read.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_forward.go b/internal/rpc/messages_forward.go index 4ac9a8e6..2111b3d6 100644 --- a/internal/rpc/messages_forward.go +++ b/internal/rpc/messages_forward.go @@ -5,7 +5,7 @@ import ( "errors" "strings" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_forward_rpc_test.go b/internal/rpc/messages_forward_rpc_test.go index 4ccc7e36..065b58f6 100644 --- a/internal/rpc/messages_forward_rpc_test.go +++ b/internal/rpc/messages_forward_rpc_test.go @@ -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" "strings" appchannels "telesrv/internal/app/channels" diff --git a/internal/rpc/messages_games.go b/internal/rpc/messages_games.go index e0c0826d..e52deee1 100644 --- a/internal/rpc/messages_games.go +++ b/internal/rpc/messages_games.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) func (r *Router) onMessagesGetEmojiGameInfo(ctx context.Context) (tg.MessagesEmojiGameInfoClass, error) { diff --git a/internal/rpc/messages_games_rpc_test.go b/internal/rpc/messages_games_rpc_test.go index 2857005e..ba18a464 100644 --- a/internal/rpc/messages_games_rpc_test.go +++ b/internal/rpc/messages_games_rpc_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" ) func TestMessagesGetEmojiGameInfoUnavailable(t *testing.T) { diff --git a/internal/rpc/messages_get_webpage_test.go b/internal/rpc/messages_get_webpage_test.go index ebec9e04..23b2e500 100644 --- a/internal/rpc/messages_get_webpage_test.go +++ b/internal/rpc/messages_get_webpage_test.go @@ -5,7 +5,7 @@ import ( "errors" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_helpers.go b/internal/rpc/messages_helpers.go index 26a24ff8..b580e8b1 100644 --- a/internal/rpc/messages_helpers.go +++ b/internal/rpc/messages_helpers.go @@ -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" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_history.go b/internal/rpc/messages_history.go index 804e92c5..65e34811 100644 --- a/internal/rpc/messages_history.go +++ b/internal/rpc/messages_history.go @@ -3,7 +3,7 @@ package rpc import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "sort" "telesrv/internal/domain" "unicode/utf8" @@ -528,6 +528,13 @@ func (r *Router) onMessagesGetRichMessage(ctx context.Context, req *tg.MessagesG } func (r *Router) onMessagesSearchGlobal(ctx context.Context, req *tg.MessagesSearchGlobalRequest) (tg.MessagesMessagesClass, error) { + // Layer 228 adds an optional community scope. telesrv has no Communities + // membership/link read model yet, so treating this as an ordinary global + // search would leak results outside the requested scope. Reject it before + // any search/store work until that model exists. + if _, ok := req.GetCommunity(); ok || req.Community != nil { + return nil, channelInvalidErr(domain.ErrChannelInvalid) + } if req.BroadcastsOnly && req.GroupsOnly { return &tg.MessagesMessages{}, nil } diff --git a/internal/rpc/messages_history_rpc_test.go b/internal/rpc/messages_history_rpc_test.go index 2c6964f8..2fa237e8 100644 --- a/internal/rpc/messages_history_rpc_test.go +++ b/internal/rpc/messages_history_rpc_test.go @@ -3,10 +3,11 @@ package rpc import ( "context" "errors" - "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" + "github.com/iamxvbaba/td/tgerr" "go.uber.org/zap/zaptest" "strings" appchannels "telesrv/internal/app/channels" @@ -16,6 +17,21 @@ import ( "testing" ) +func TestMessagesSearchGlobalRejectsUnsupportedCommunityScope(t *testing.T) { + r := New(Config{}, Deps{}, zaptest.NewLogger(t), clock.System) + req := &tg.MessagesSearchGlobalRequest{ + Q: "scoped", + Filter: &tg.InputMessagesFilterEmpty{}, + OffsetPeer: &tg.InputPeerEmpty{}, + Limit: 20, + } + req.SetCommunity(&tg.InputChannel{ChannelID: 42, AccessHash: 84}) + + if _, err := r.onMessagesSearchGlobal(WithUserID(context.Background(), 1000000001), req); !tgerr.Is(err, "CHANNEL_INVALID") { + t.Fatalf("community-scoped messages.searchGlobal err = %v, want CHANNEL_INVALID", err) + } +} + func TestMessagesSearchChannelPeerReturnsSingleCopyMessages(t *testing.T) { ctx := context.Background() userStore := memory.NewUserStore() diff --git a/internal/rpc/messages_monoforum.go b/internal/rpc/messages_monoforum.go index 5034da1a..c0fb50a6 100644 --- a/internal/rpc/messages_monoforum.go +++ b/internal/rpc/messages_monoforum.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_monoforum_rpc_test.go b/internal/rpc/messages_monoforum_rpc_test.go index eb475af9..4b8ab926 100644 --- a/internal/rpc/messages_monoforum_rpc_test.go +++ b/internal/rpc/messages_monoforum_rpc_test.go @@ -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" diff --git a/internal/rpc/messages_paid_reaction.go b/internal/rpc/messages_paid_reaction.go index 16564c82..7e58c833 100644 --- a/internal/rpc/messages_paid_reaction.go +++ b/internal/rpc/messages_paid_reaction.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_paid_reaction_test.go b/internal/rpc/messages_paid_reaction_test.go index a7030752..e5cd8b1e 100644 --- a/internal/rpc/messages_paid_reaction_test.go +++ b/internal/rpc/messages_paid_reaction_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_pin.go b/internal/rpc/messages_pin.go index 3aa4fe1c..f090ca23 100644 --- a/internal/rpc/messages_pin.go +++ b/internal/rpc/messages_pin.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_pin_rpc_test.go b/internal/rpc/messages_pin_rpc_test.go index 5a2e66df..ff053e82 100644 --- a/internal/rpc/messages_pin_rpc_test.go +++ b/internal/rpc/messages_pin_rpc_test.go @@ -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" appcontacts "telesrv/internal/app/contacts" diff --git a/internal/rpc/messages_polls.go b/internal/rpc/messages_polls.go index 16e9d4c4..946ae15d 100644 --- a/internal/rpc/messages_polls.go +++ b/internal/rpc/messages_polls.go @@ -6,8 +6,8 @@ import ( "strings" "unicode/utf8" - "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" diff --git a/internal/rpc/messages_polls_rpc_test.go b/internal/rpc/messages_polls_rpc_test.go index cb1d99a3..05ec968b 100644 --- a/internal/rpc/messages_polls_rpc_test.go +++ b/internal/rpc/messages_polls_rpc_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" ) // sendTestPoll 用 sendMedia 发一个 poll,返回消息与 poll id。 diff --git a/internal/rpc/messages_polls_tdesktop_shape_test.go b/internal/rpc/messages_polls_tdesktop_shape_test.go index cfb2ff1f..8993d435 100644 --- a/internal/rpc/messages_polls_tdesktop_shape_test.go +++ b/internal/rpc/messages_polls_tdesktop_shape_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) // 回归:TDesktop 创建 poll 的真实请求形状(kDefaultPollCreateFlags 默认带 diff --git a/internal/rpc/messages_polls_updates.go b/internal/rpc/messages_polls_updates.go index 2200aee7..a68c41fe 100644 --- a/internal/rpc/messages_polls_updates.go +++ b/internal/rpc/messages_polls_updates.go @@ -4,8 +4,8 @@ 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" "telesrv/internal/domain" diff --git a/internal/rpc/messages_private_rpc_test.go b/internal/rpc/messages_private_rpc_test.go index 9ab09d14..b936d868 100644 --- a/internal/rpc/messages_private_rpc_test.go +++ b/internal/rpc/messages_private_rpc_test.go @@ -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" appcontacts "telesrv/internal/app/contacts" diff --git a/internal/rpc/messages_quick_replies.go b/internal/rpc/messages_quick_replies.go index fa42a854..23d8ce66 100644 --- a/internal/rpc/messages_quick_replies.go +++ b/internal/rpc/messages_quick_replies.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_reactions_catalog.go b/internal/rpc/messages_reactions_catalog.go index 706b50fa..f4cad6ea 100644 --- a/internal/rpc/messages_reactions_catalog.go +++ b/internal/rpc/messages_reactions_catalog.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "hash/fnv" "strconv" "strings" diff --git a/internal/rpc/messages_reactions_helpers.go b/internal/rpc/messages_reactions_helpers.go index 98cfe719..aace5861 100644 --- a/internal/rpc/messages_reactions_helpers.go +++ b/internal/rpc/messages_reactions_helpers.go @@ -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" diff --git a/internal/rpc/messages_reactions_lists.go b/internal/rpc/messages_reactions_lists.go index daf42a9c..0f3250c9 100644 --- a/internal/rpc/messages_reactions_lists.go +++ b/internal/rpc/messages_reactions_lists.go @@ -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" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_reactions_policy_rpc_test.go b/internal/rpc/messages_reactions_policy_rpc_test.go index 81bc845d..af9dbb23 100644 --- a/internal/rpc/messages_reactions_policy_rpc_test.go +++ b/internal/rpc/messages_reactions_policy_rpc_test.go @@ -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" diff --git a/internal/rpc/messages_reactions_privacy.go b/internal/rpc/messages_reactions_privacy.go index f51befe3..3215aba9 100644 --- a/internal/rpc/messages_reactions_privacy.go +++ b/internal/rpc/messages_reactions_privacy.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/messages_reactions_send.go b/internal/rpc/messages_reactions_send.go index 016fbdbe..e81f948f 100644 --- a/internal/rpc/messages_reactions_send.go +++ b/internal/rpc/messages_reactions_send.go @@ -4,7 +4,7 @@ import ( "context" "sync" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_reactions_test.go b/internal/rpc/messages_reactions_test.go index f7324be7..d0cdeedc 100644 --- a/internal/rpc/messages_reactions_test.go +++ b/internal/rpc/messages_reactions_test.go @@ -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" appchannels "telesrv/internal/app/channels" "telesrv/internal/domain" diff --git a/internal/rpc/messages_reactions_viewpoint_test.go b/internal/rpc/messages_reactions_viewpoint_test.go index 3fcfec65..0794d96b 100644 --- a/internal/rpc/messages_reactions_viewpoint_test.go +++ b/internal/rpc/messages_reactions_viewpoint_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_read.go b/internal/rpc/messages_read.go index 406e156f..02249d3e 100644 --- a/internal/rpc/messages_read.go +++ b/internal/rpc/messages_read.go @@ -3,7 +3,7 @@ package rpc import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_read_rpc_test.go b/internal/rpc/messages_read_rpc_test.go index b876b9e8..2b57ded1 100644 --- a/internal/rpc/messages_read_rpc_test.go +++ b/internal/rpc/messages_read_rpc_test.go @@ -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" "reflect" "telesrv/internal/domain" diff --git a/internal/rpc/messages_recent_locations.go b/internal/rpc/messages_recent_locations.go index 48c440be..a404e1fd 100644 --- a/internal/rpc/messages_recent_locations.go +++ b/internal/rpc/messages_recent_locations.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_recent_locations_test.go b/internal/rpc/messages_recent_locations_test.go index 7569c375..dafa4b7d 100644 --- a/internal/rpc/messages_recent_locations_test.go +++ b/internal/rpc/messages_recent_locations_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" ) func TestMessagesGetRecentLocationsReturnsOnlyGeoLive(t *testing.T) { diff --git a/internal/rpc/messages_register.go b/internal/rpc/messages_register.go index b487d74a..cd8af767 100644 --- a/internal/rpc/messages_register.go +++ b/internal/rpc/messages_register.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" "unicode/utf8" diff --git a/internal/rpc/messages_reports.go b/internal/rpc/messages_reports.go index a68feb11..aa84d1c5 100644 --- a/internal/rpc/messages_reports.go +++ b/internal/rpc/messages_reports.go @@ -2,8 +2,8 @@ package rpc import ( "context" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" "telesrv/internal/domain" "unicode/utf8" ) diff --git a/internal/rpc/messages_rich_message_rpc_test.go b/internal/rpc/messages_rich_message_rpc_test.go index e9c7043e..d53974e1 100644 --- a/internal/rpc/messages_rich_message_rpc_test.go +++ b/internal/rpc/messages_rich_message_rpc_test.go @@ -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" diff --git a/internal/rpc/messages_saved_dialogs.go b/internal/rpc/messages_saved_dialogs.go index f1c6b878..fb61bcf5 100644 --- a/internal/rpc/messages_saved_dialogs.go +++ b/internal/rpc/messages_saved_dialogs.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_saved_dialogs_rpc_test.go b/internal/rpc/messages_saved_dialogs_rpc_test.go index 345dca42..d85ea3db 100644 --- a/internal/rpc/messages_saved_dialogs_rpc_test.go +++ b/internal/rpc/messages_saved_dialogs_rpc_test.go @@ -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" appcontacts "telesrv/internal/app/contacts" @@ -600,7 +600,7 @@ func TestModernForwardMessagesConstructorSavesToSelf(t *testing.T) { if err != nil { t.Fatalf("dispatch messages.forwardMessages#41d41ade: %v", err) } - // Now routed through the unified layerwire client-alias (4-byte id swap) and + // Now routed through the generated static client overlay and // the normal gotd dispatcher, which boxes a class result as *tg.UpdatesBox // (wire-identical to the raw UpdatesClass the dedicated handler used to return). switch v := enc.(type) { diff --git a/internal/rpc/messages_scheduled.go b/internal/rpc/messages_scheduled.go index 072c5078..0eb6ea37 100644 --- a/internal/rpc/messages_scheduled.go +++ b/internal/rpc/messages_scheduled.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_scheduled_ttl_test.go b/internal/rpc/messages_scheduled_ttl_test.go index 218b108a..defda72f 100644 --- a/internal/rpc/messages_scheduled_ttl_test.go +++ b/internal/rpc/messages_scheduled_ttl_test.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap/zaptest" "telesrv/internal/domain" "testing" diff --git a/internal/rpc/messages_send.go b/internal/rpc/messages_send.go index 77d7697a..7664d1e7 100644 --- a/internal/rpc/messages_send.go +++ b/internal/rpc/messages_send.go @@ -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" diff --git a/internal/rpc/messages_send_as.go b/internal/rpc/messages_send_as.go index 8b9b6064..c5a82199 100644 --- a/internal/rpc/messages_send_as.go +++ b/internal/rpc/messages_send_as.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_send_rpc_test.go b/internal/rpc/messages_send_rpc_test.go index f2ff5c46..680cebb0 100644 --- a/internal/rpc/messages_send_rpc_test.go +++ b/internal/rpc/messages_send_rpc_test.go @@ -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" "strconv" "strings" diff --git a/internal/rpc/messages_send_webpage_rpc_test.go b/internal/rpc/messages_send_webpage_rpc_test.go index 63b2f18d..5f3be62a 100644 --- a/internal/rpc/messages_send_webpage_rpc_test.go +++ b/internal/rpc/messages_send_webpage_rpc_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_sticker_sets.go b/internal/rpc/messages_sticker_sets.go index 4e6db4bd..3b2a366a 100644 --- a/internal/rpc/messages_sticker_sets.go +++ b/internal/rpc/messages_sticker_sets.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_sticker_sets_rpc_test.go b/internal/rpc/messages_sticker_sets_rpc_test.go index 896e6533..5eb844c8 100644 --- a/internal/rpc/messages_sticker_sets_rpc_test.go +++ b/internal/rpc/messages_sticker_sets_rpc_test.go @@ -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" diff --git a/internal/rpc/messages_stickers_personal.go b/internal/rpc/messages_stickers_personal.go index d129abcc..677df576 100644 --- a/internal/rpc/messages_stickers_personal.go +++ b/internal/rpc/messages_stickers_personal.go @@ -5,7 +5,7 @@ import ( "context" "fmt" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_stickers_personal_rpc_test.go b/internal/rpc/messages_stickers_personal_rpc_test.go index ebd4258d..ce4983eb 100644 --- a/internal/rpc/messages_stickers_personal_rpc_test.go +++ b/internal/rpc/messages_stickers_personal_rpc_test.go @@ -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" diff --git a/internal/rpc/messages_todos.go b/internal/rpc/messages_todos.go index fc89b460..0754af59 100644 --- a/internal/rpc/messages_todos.go +++ b/internal/rpc/messages_todos.go @@ -5,8 +5,8 @@ import ( "strings" "unicode/utf8" - "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" diff --git a/internal/rpc/messages_todos_rpc_test.go b/internal/rpc/messages_todos_rpc_test.go index a561cf51..8a055fd9 100644 --- a/internal/rpc/messages_todos_rpc_test.go +++ b/internal/rpc/messages_todos_rpc_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_translation.go b/internal/rpc/messages_translation.go index c67600c1..459ec781 100644 --- a/internal/rpc/messages_translation.go +++ b/internal/rpc/messages_translation.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_translation_rpc_test.go b/internal/rpc/messages_translation_rpc_test.go index fa73f988..629746a8 100644 --- a/internal/rpc/messages_translation_rpc_test.go +++ b/internal/rpc/messages_translation_rpc_test.go @@ -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" diff --git a/internal/rpc/messages_ttl.go b/internal/rpc/messages_ttl.go index bd3ca1f4..bbb7a19b 100644 --- a/internal/rpc/messages_ttl.go +++ b/internal/rpc/messages_ttl.go @@ -2,7 +2,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/messages_upload_media_android_compat_test.go b/internal/rpc/messages_upload_media_android_compat_test.go index fb1a6949..8662cb21 100644 --- a/internal/rpc/messages_upload_media_android_compat_test.go +++ b/internal/rpc/messages_upload_media_android_compat_test.go @@ -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" appusers "telesrv/internal/app/users" @@ -44,7 +44,7 @@ func TestLegacyAndroidMessagesUploadMediaDispatch(t *testing.T) { if err != nil { t.Fatalf("dispatch legacy uploadMedia: %v", err) } - // Routed through the unified layerwire inbound body-transform + the normal + // Routed through the generated static client overlay + the normal // gotd dispatcher, which boxes a class result (MessageMedia) as *...Box. box, ok := enc.(*tg.MessageMediaBox) if !ok { diff --git a/internal/rpc/messages_webpage_preview_rpc_test.go b/internal/rpc/messages_webpage_preview_rpc_test.go index ff390e4a..b5218b7a 100644 --- a/internal/rpc/messages_webpage_preview_rpc_test.go +++ b/internal/rpc/messages_webpage_preview_rpc_test.go @@ -5,8 +5,8 @@ import ( "errors" "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" aiapp "telesrv/internal/app/ai" diff --git a/internal/rpc/messages_webview.go b/internal/rpc/messages_webview.go index 164954e5..74c224c6 100644 --- a/internal/rpc/messages_webview.go +++ b/internal/rpc/messages_webview.go @@ -14,7 +14,7 @@ import ( "time" "unicode/utf8" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" "telesrv/internal/store" diff --git a/internal/rpc/messages_webview_rpc_test.go b/internal/rpc/messages_webview_rpc_test.go index bd8d201f..15d42e99 100644 --- a/internal/rpc/messages_webview_rpc_test.go +++ b/internal/rpc/messages_webview_rpc_test.go @@ -7,7 +7,7 @@ import ( "strings" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/music_rpc_test.go b/internal/rpc/music_rpc_test.go index 1ed682d0..e9c98878 100644 --- a/internal/rpc/music_rpc_test.go +++ b/internal/rpc/music_rpc_test.go @@ -5,9 +5,9 @@ import ( "strings" "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" appaccount "telesrv/internal/app/account" diff --git a/internal/rpc/outbox_dispatcher.go b/internal/rpc/outbox_dispatcher.go index 57e10389..e0e12af9 100644 --- a/internal/rpc/outbox_dispatcher.go +++ b/internal/rpc/outbox_dispatcher.go @@ -7,8 +7,8 @@ import ( "sync" "time" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/outbox_dispatcher_test.go b/internal/rpc/outbox_dispatcher_test.go index 00e4829b..32940992 100644 --- a/internal/rpc/outbox_dispatcher_test.go +++ b/internal/rpc/outbox_dispatcher_test.go @@ -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" @@ -772,7 +772,7 @@ type captureBestEffortSessions struct { timeout time.Duration } -func (s *captureBestEffortSessions) PushToUserExceptAuthKeySessionBestEffort(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder, timeout time.Duration) (int, error) { +func (s *captureBestEffortSessions) PushToUserExceptAuthKeySessionBestEffort(ctx context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass, timeout time.Duration) (int, error) { s.bestEffort = true s.timeout = timeout return s.PushToUserExceptAuthKeySession(ctx, userID, excludeAuthKeyID, excludeSessionID, t, msg) @@ -795,7 +795,7 @@ type selectiveFailOutboxSessions struct { attempts []outboxPushAttempt } -func (s *selectiveFailOutboxSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder) (int, error) { +func (s *selectiveFailOutboxSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) { pts := 0 if updates, ok := msg.(*tg.Updates); ok { pts = firstOutboxUpdatePts(updates) @@ -811,7 +811,7 @@ func (s *selectiveFailOutboxSessions) pushAttempts() []outboxPushAttempt { return append([]outboxPushAttempt(nil), s.attempts...) } -func (s *orderedOutboxCaptureSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder) (int, error) { +func (s *orderedOutboxCaptureSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) { if updates, ok := msg.(*tg.Updates); ok { s.pushed = append(s.pushed, firstOutboxUpdatePts(updates)) } @@ -1023,12 +1023,12 @@ func (s *captureScopedSessions) SetReceivesUpdatesForAuthKey(rawAuthKeyID [8]byt s.captureSessions.SetReceivesUpdatesForAuthKey(rawAuthKeyID, sessionID, receives) } -func (s *captureScopedSessions) PushToSessionForAuthKey(_ context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg bin.Encoder) error { +func (s *captureScopedSessions) PushToSessionForAuthKey(_ context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error { s.setScopedAuthKeyID(rawAuthKeyID) return s.captureSessions.PushToSessionForAuthKey(context.Background(), rawAuthKeyID, sessionID, t, msg) } -func (s *captureScopedSessions) PushToSessionForAuthKeyImmediate(_ context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg bin.Encoder) error { +func (s *captureScopedSessions) PushToSessionForAuthKeyImmediate(_ context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error { s.scopedMu.Lock() s.immediatePush = true s.scopedAuthKeyID = rawAuthKeyID @@ -1038,7 +1038,7 @@ func (s *captureScopedSessions) PushToSessionForAuthKeyImmediate(_ context.Conte return s.captureSessions.PushToSessionForAuthKey(context.Background(), rawAuthKeyID, sessionID, t, msg) } -func (s *captureScopedSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder) (int, error) { +func (s *captureScopedSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) { s.setScopedAuthKeyID(excludeAuthKeyID) return s.captureSessions.PushToUserExceptAuthKeySession(context.Background(), userID, excludeAuthKeyID, excludeSessionID, t, msg) } @@ -1119,7 +1119,7 @@ type interruptedBestEffortSessions struct { attempts int } -func (s *interruptedBestEffortSessions) PushToUserExceptAuthKeySessionBestEffort(_ context.Context, _ int64, _ [8]byte, _ int64, _ proto.MessageType, _ bin.Encoder, _ time.Duration) (int, error) { +func (s *interruptedBestEffortSessions) PushToUserExceptAuthKeySessionBestEffort(_ context.Context, _ int64, _ [8]byte, _ int64, _ proto.MessageType, _ tg.UpdatesClass, _ time.Duration) (int, error) { s.attempts++ return 0, context.DeadlineExceeded } diff --git a/internal/rpc/outbox_update_builder.go b/internal/rpc/outbox_update_builder.go index 21291462..b5b442d1 100644 --- a/internal/rpc/outbox_update_builder.go +++ b/internal/rpc/outbox_update_builder.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/passive_compat_test.go b/internal/rpc/passive_compat_test.go index 8c24e22b..c329a891 100644 --- a/internal/rpc/passive_compat_test.go +++ b/internal/rpc/passive_compat_test.go @@ -5,9 +5,9 @@ import ( "strings" "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" ) @@ -61,7 +61,7 @@ func TestAccountGetUniqueGiftChatThemesReturnsEmptyStub(t *testing.T) { } } -func TestAccountGetWallPapersReturnsOrangeCatalog(t *testing.T) { +func TestAccountGetWallPapersReturnsDefaultCatalog(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) req := &tg.AccountGetWallPapersRequest{} var in bin.Buffer @@ -82,7 +82,7 @@ func TestAccountGetWallPapersReturnsOrangeCatalog(t *testing.T) { t.Fatalf("boxed response type = %T, want *tg.AccountWallPapers", box.WallPapers) } if wallpapers.Hash == 0 || len(wallpapers.Wallpapers) == 0 { - t.Fatalf("wallpapers = %+v, want stable seed catalog", wallpapers) + t.Fatalf("wallpapers = %+v, want stable Default catalog", wallpapers) } } diff --git a/internal/rpc/payments.go b/internal/rpc/payments.go index c3c5e1f3..0cd20576 100644 --- a/internal/rpc/payments.go +++ b/internal/rpc/payments.go @@ -5,7 +5,7 @@ import ( "errors" "strconv" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" diff --git a/internal/rpc/payments_star_gifts.go b/internal/rpc/payments_star_gifts.go index 279e6b9b..de8ec3f1 100644 --- a/internal/rpc/payments_star_gifts.go +++ b/internal/rpc/payments_star_gifts.go @@ -4,8 +4,8 @@ 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" "telesrv/internal/domain" diff --git a/internal/rpc/payments_star_gifts_rpc_test.go b/internal/rpc/payments_star_gifts_rpc_test.go index db92d0bc..4b1ce168 100644 --- a/internal/rpc/payments_star_gifts_rpc_test.go +++ b/internal/rpc/payments_star_gifts_rpc_test.go @@ -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" appchannels "telesrv/internal/app/channels" diff --git a/internal/rpc/payments_stars_rpc_test.go b/internal/rpc/payments_stars_rpc_test.go index dc16458b..3b04e5a5 100644 --- a/internal/rpc/payments_stars_rpc_test.go +++ b/internal/rpc/payments_stars_rpc_test.go @@ -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" appstars "telesrv/internal/app/stars" diff --git a/internal/rpc/peer_projection_cache_test.go b/internal/rpc/peer_projection_cache_test.go index 7ab1465d..193c02f3 100644 --- a/internal/rpc/peer_projection_cache_test.go +++ b/internal/rpc/peer_projection_cache_test.go @@ -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" diff --git a/internal/rpc/phone_calls.go b/internal/rpc/phone_calls.go index 742b0776..4f303776 100644 --- a/internal/rpc/phone_calls.go +++ b/internal/rpc/phone_calls.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" appphone "telesrv/internal/app/phone" "telesrv/internal/domain" diff --git a/internal/rpc/phone_conference.go b/internal/rpc/phone_conference.go index 8a442040..89377561 100644 --- a/internal/rpc/phone_conference.go +++ b/internal/rpc/phone_conference.go @@ -5,7 +5,7 @@ import ( "encoding/binary" "net/url" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/phone_conference_rpc_test.go b/internal/rpc/phone_conference_rpc_test.go index 4d95ca6c..2489e274 100644 --- a/internal/rpc/phone_conference_rpc_test.go +++ b/internal/rpc/phone_conference_rpc_test.go @@ -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" appgroupcalls "telesrv/internal/app/groupcalls" diff --git a/internal/rpc/phone_dh.go b/internal/rpc/phone_dh.go index c0d6ca60..f6072ccd 100644 --- a/internal/rpc/phone_dh.go +++ b/internal/rpc/phone_dh.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" appphone "telesrv/internal/app/phone" ) diff --git a/internal/rpc/phone_group_call.go b/internal/rpc/phone_group_call.go index 494c7c87..4edf74dd 100644 --- a/internal/rpc/phone_group_call.go +++ b/internal/rpc/phone_group_call.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/phone_group_call_edit.go b/internal/rpc/phone_group_call_edit.go index 4fb287b6..5631d9de 100644 --- a/internal/rpc/phone_group_call_edit.go +++ b/internal/rpc/phone_group_call_edit.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/phone_group_call_joinas_test.go b/internal/rpc/phone_group_call_joinas_test.go index 1fcac73f..767d0f44 100644 --- a/internal/rpc/phone_group_call_joinas_test.go +++ b/internal/rpc/phone_group_call_joinas_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) // TestGroupCallJoinAsChannel 覆盖 join_as 身份闭环:admin 以频道身份入会 → diff --git a/internal/rpc/phone_group_call_presentation.go b/internal/rpc/phone_group_call_presentation.go index 0abbce6a..a3e4b3a6 100644 --- a/internal/rpc/phone_group_call_presentation.go +++ b/internal/rpc/phone_group_call_presentation.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" diff --git a/internal/rpc/phone_group_call_rpc_test.go b/internal/rpc/phone_group_call_rpc_test.go index ddeaadfe..0a49a6e9 100644 --- a/internal/rpc/phone_group_call_rpc_test.go +++ b/internal/rpc/phone_group_call_rpc_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap/zaptest" appchannels "telesrv/internal/app/channels" diff --git a/internal/rpc/phone_group_call_rtmp.go b/internal/rpc/phone_group_call_rtmp.go index 81522d9e..08b4cf3b 100644 --- a/internal/rpc/phone_group_call_rtmp.go +++ b/internal/rpc/phone_group_call_rtmp.go @@ -6,7 +6,7 @@ import ( "encoding/binary" "encoding/json" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/phone_group_call_rtmp_test.go b/internal/rpc/phone_group_call_rtmp_test.go index 44573b11..0d04e83e 100644 --- a/internal/rpc/phone_group_call_rtmp_test.go +++ b/internal/rpc/phone_group_call_rtmp_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap/zaptest" appchannels "telesrv/internal/app/channels" diff --git a/internal/rpc/phone_group_call_scheduled.go b/internal/rpc/phone_group_call_scheduled.go index 15c9747d..5feeed52 100644 --- a/internal/rpc/phone_group_call_scheduled.go +++ b/internal/rpc/phone_group_call_scheduled.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/phone_group_call_scheduled_test.go b/internal/rpc/phone_group_call_scheduled_test.go index d3bb7afc..e9bb869c 100644 --- a/internal/rpc/phone_group_call_scheduled_test.go +++ b/internal/rpc/phone_group_call_scheduled_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) // TestScheduledGroupCallLifecycle 覆盖定时通话闭环:create(schedule_date) → diff --git a/internal/rpc/phone_group_call_updates.go b/internal/rpc/phone_group_call_updates.go index c3e3abac..82096140 100644 --- a/internal/rpc/phone_group_call_updates.go +++ b/internal/rpc/phone_group_call_updates.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/phone_group_call_video_rpc_test.go b/internal/rpc/phone_group_call_video_rpc_test.go index ea2c6373..49516b4c 100644 --- a/internal/rpc/phone_group_call_video_rpc_test.go +++ b/internal/rpc/phone_group_call_video_rpc_test.go @@ -6,7 +6,7 @@ import ( "fmt" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/phone_push.go b/internal/rpc/phone_push.go index b0a670a1..f6fe9b88 100644 --- a/internal/rpc/phone_push.go +++ b/internal/rpc/phone_push.go @@ -3,8 +3,8 @@ package rpc import ( "context" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/phone_register.go b/internal/rpc/phone_register.go index 0ae1125b..10231c5d 100644 --- a/internal/rpc/phone_register.go +++ b/internal/rpc/phone_register.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) // registerPhone 注册通话域 RPC。 diff --git a/internal/rpc/phone_rpc_test.go b/internal/rpc/phone_rpc_test.go index 5184bab0..97f53331 100644 --- a/internal/rpc/phone_rpc_test.go +++ b/internal/rpc/phone_rpc_test.go @@ -8,11 +8,11 @@ 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/gotd/td/tgerr" + "github.com/iamxvbaba/td/bin" + "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" appmessages "telesrv/internal/app/messages" @@ -47,14 +47,14 @@ func (s *phoneCaptureSessions) UserIDResolvedForAuthKey([8]byte, int64) (int64, func (s *phoneCaptureSessions) UnbindAuthKey([8]byte) int { return 0 } func (s *phoneCaptureSessions) SetReceivesUpdatesForAuthKey([8]byte, int64, bool) {} -func (s *phoneCaptureSessions) PushToSessionForAuthKey(_ context.Context, _ [8]byte, sessionID int64, _ proto.MessageType, msg bin.Encoder) error { +func (s *phoneCaptureSessions) PushToSessionForAuthKey(_ context.Context, _ [8]byte, sessionID int64, _ proto.MessageType, msg tg.UpdatesClass) error { s.mu.Lock() defer s.mu.Unlock() s.log = append(s.log, phonePushRecord{targetSession: sessionID, msg: msg}) return nil } -func (s *phoneCaptureSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, _ [8]byte, excludeSessionID int64, _ proto.MessageType, msg bin.Encoder) (int, error) { +func (s *phoneCaptureSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, _ [8]byte, excludeSessionID int64, _ proto.MessageType, msg tg.UpdatesClass) (int, error) { s.mu.Lock() defer s.mu.Unlock() s.log = append(s.log, phonePushRecord{userID: userID, excludeSession: excludeSessionID, msg: msg}) diff --git a/internal/rpc/phone_stubs.go b/internal/rpc/phone_stubs.go index 0b6c25e4..176d987c 100644 --- a/internal/rpc/phone_stubs.go +++ b/internal/rpc/phone_stubs.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) // 群通话范围外入口的被动 stub(防点崩)。未列出的 phone.*(conference 族 / diff --git a/internal/rpc/photos.go b/internal/rpc/photos.go index 35986342..c7ca889d 100644 --- a/internal/rpc/photos.go +++ b/internal/rpc/photos.go @@ -5,8 +5,8 @@ import ( "errors" "time" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/photos_contact_profile_test.go b/internal/rpc/photos_contact_profile_test.go index d37037dd..0adb20fe 100644 --- a/internal/rpc/photos_contact_profile_test.go +++ b/internal/rpc/photos_contact_profile_test.go @@ -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" appcontacts "telesrv/internal/app/contacts" diff --git a/internal/rpc/photos_get_user_photos_test.go b/internal/rpc/photos_get_user_photos_test.go index f1e3cf01..03cc596b 100644 --- a/internal/rpc/photos_get_user_photos_test.go +++ b/internal/rpc/photos_get_user_photos_test.go @@ -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" appstories "telesrv/internal/app/stories" diff --git a/internal/rpc/photos_push_test.go b/internal/rpc/photos_push_test.go index 53eee401..15f8c51d 100644 --- a/internal/rpc/photos_push_test.go +++ b/internal/rpc/photos_push_test.go @@ -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" appusers "telesrv/internal/app/users" @@ -93,9 +93,18 @@ func TestUploadProfilePhotoEchoesUpdateToCurrentSession(t *testing.T) { reqCtx := WithSessionID(WithUserID(ctx, owner.ID), currentSessionID) req := &tg.PhotosUploadProfilePhotoRequest{} req.SetVideoEmojiMarkup(&tg.VideoSizeEmojiMarkup{EmojiID: 99, BackgroundColors: []int{0xffffff}}) - if _, err := r.onPhotosUploadProfilePhoto(reqCtx, req); err != nil { + got, err := r.onPhotosUploadProfilePhoto(reqCtx, req) + if err != nil { t.Fatalf("uploadProfilePhoto: %v", err) } + returned, ok := got.Photo.(*tg.Photo) + if !ok || len(returned.Sizes) < 1 { + t.Fatalf("returned photo = %T %+v, want photo with s/a/c sizes", got.Photo, got.Photo) + } + transientSize, ok := returned.Sizes[0].(*tg.PhotoSize) + if !ok || transientSize.Type != "s" || transientSize.W != 150 || transientSize.H != 150 { + t.Fatalf("returned first size = %+v, want real s=150 transient response location", returned.Sizes[0]) + } // PushToSession 在 PushToUserExceptSession 之后调用,snapshot().message 即当前 session 回显。 snap := sessions.snapshot() diff --git a/internal/rpc/premium.go b/internal/rpc/premium.go index d9e45729..b4ead78b 100644 --- a/internal/rpc/premium.go +++ b/internal/rpc/premium.go @@ -6,7 +6,7 @@ import ( "fmt" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/premium_sweeper.go b/internal/rpc/premium_sweeper.go index 0881fb4a..2e0377a7 100644 --- a/internal/rpc/premium_sweeper.go +++ b/internal/rpc/premium_sweeper.go @@ -4,7 +4,7 @@ import ( "context" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/presence.go b/internal/rpc/presence.go index 24da0a01..419ae6f9 100644 --- a/internal/rpc/presence.go +++ b/internal/rpc/presence.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/push.go b/internal/rpc/push.go index e4ed8838..a9d9691e 100644 --- a/internal/rpc/push.go +++ b/internal/rpc/push.go @@ -3,12 +3,12 @@ package rpc import ( "context" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" ) -func (r *Router) pushUserMessage(ctx context.Context, userID int64, logMessage string, msg bin.Encoder) int { +func (r *Router) pushUserMessage(ctx context.Context, userID int64, logMessage string, msg tg.UpdatesClass) int { if r.deps.Sessions == nil || userID == 0 || msg == nil { return 0 } @@ -36,7 +36,7 @@ func (r *Router) pushUserMessage(ctx context.Context, userID int64, logMessage s // pushUserMessageTransient 推送 transient(typing/presence)update:未就绪的 session 直接 // 跳过、不进 pending。实现未提供 TransientSessionBinder 能力时回退到普通 pushUserMessage // (退化为旧行为:会进 pending,但仍不影响 durable 正确性)。 -func (r *Router) pushUserMessageTransient(ctx context.Context, userID int64, logMessage string, msg bin.Encoder) int { +func (r *Router) pushUserMessageTransient(ctx context.Context, userID int64, logMessage string, msg tg.UpdatesClass) int { if r.deps.Sessions == nil || userID == 0 || msg == nil { return 0 } @@ -52,7 +52,7 @@ func (r *Router) pushUserMessageTransient(ctx context.Context, userID int64, log return r.pushUserMessage(ctx, userID, logMessage, msg) } -func (r *Router) pushCurrentSessionMessage(ctx context.Context, logMessage string, msg bin.Encoder) { +func (r *Router) pushCurrentSessionMessage(ctx context.Context, logMessage string, msg tg.UpdatesClass) { if r.deps.Sessions == nil || msg == nil { return } diff --git a/internal/rpc/rate_limit_catchup_test.go b/internal/rpc/rate_limit_catchup_test.go index e0e1560f..ce877a0c 100644 --- a/internal/rpc/rate_limit_catchup_test.go +++ b/internal/rpc/rate_limit_catchup_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/gotd/td/clock" + "github.com/iamxvbaba/td/clock" "go.uber.org/zap/zaptest" ) diff --git a/internal/rpc/reactions_android_compat.go b/internal/rpc/reactions_android_compat.go index 4bafedaa..045acb56 100644 --- a/internal/rpc/reactions_android_compat.go +++ b/internal/rpc/reactions_android_compat.go @@ -5,7 +5,7 @@ import ( "strings" "sync" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/receives_updates_mark_test.go b/internal/rpc/receives_updates_mark_test.go index f0f5fec3..a1232416 100644 --- a/internal/rpc/receives_updates_mark_test.go +++ b/internal/rpc/receives_updates_mark_test.go @@ -2,15 +2,24 @@ package rpc import ( "context" + "errors" + "reflect" + "sync" "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" + appsecret "telesrv/internal/app/secretchat" + "telesrv/internal/domain" + "telesrv/internal/postresponse" + "telesrv/internal/store/memory" ) -func dispatchForReceivesUpdates(t *testing.T, sessions *captureSessions, wrapWithoutUpdates, loggedIn bool) { +func dispatchForReceivesUpdates(t *testing.T, sessions SessionBinder, wrapWithoutUpdates, loggedIn bool) context.Context { t.Helper() r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Sessions: sessions}, zaptest.NewLogger(t), clock.System) @@ -24,13 +33,14 @@ func dispatchForReceivesUpdates(t *testing.T, sessions *captureSessions, wrapWit } in.Put(inner.Buf) - ctx := context.Background() + ctx := postresponse.WithCallbacks(context.Background()) if loggedIn { ctx = WithUserID(ctx, 1000000001) } if _, err := r.Dispatch(ctx, [8]byte{1}, 42, &in); err != nil { t.Fatalf("dispatch: %v", err) } + return ctx } // TestDispatchMarksSessionReceivesUpdates 验证已登录连接发出的裸 RPC(未包 @@ -39,7 +49,11 @@ func dispatchForReceivesUpdates(t *testing.T, sessions *captureSessions, wrapWit // 暂存直至超时丢弃,表现为另一端消息不再实时同步。 func TestDispatchMarksSessionReceivesUpdates(t *testing.T) { sessions := &captureSessions{} - dispatchForReceivesUpdates(t, sessions, false, true) + ctx := dispatchForReceivesUpdates(t, sessions, false, true) + if sessions.snapshot().receives { + t.Fatal("plain RPC marked receivesUpdates before rpc_result delivery") + } + postresponse.Run(ctx) sessions.mu.Lock() defer sessions.mu.Unlock() if !sessions.receives { @@ -54,7 +68,8 @@ func TestDispatchMarksSessionReceivesUpdates(t *testing.T) { // 包装的请求(media/temp 连接)不会把该 session 标记为 updates 接收者。 func TestDispatchSkipsReceivesUpdatesForInvokeWithoutUpdates(t *testing.T) { sessions := &captureSessions{} - dispatchForReceivesUpdates(t, sessions, true, true) + ctx := dispatchForReceivesUpdates(t, sessions, true, true) + postresponse.Run(ctx) sessions.mu.Lock() defer sessions.mu.Unlock() if sessions.receives { @@ -62,13 +77,187 @@ func TestDispatchSkipsReceivesUpdatesForInvokeWithoutUpdates(t *testing.T) { } } +type captureBootstrapReadyStore struct { + *memory.BootstrapUpdateJobStore + readyCalls int +} + +func (s *captureBootstrapReadyStore) MarkReadyForSession(ctx context.Context, userID int64, authKeyID [8]byte, sessionID int64) (int, error) { + s.readyCalls++ + return s.BootstrapUpdateJobStore.MarkReadyForSession(ctx, userID, authKeyID, sessionID) +} + +func TestInvokeWithoutUpdatesBaselineCommitsResultAndSecretEventsWithoutSubscribing(t *testing.T) { + const userID int64 = 1000000201 + authKeyID := [8]byte{21} + deviceKey := businessAuthKeyInt64(authKeyID) + queue := memory.NewEncryptedQueueStore() + secret := appsecret.NewService(memory.NewSecretChatStore(), queue, &seqSecretChatIDAllocator{}) + eventID, err := queue.AppendStateEvent(context.Background(), domain.EncryptedStateEvent{ + TargetUserID: userID, + ChatID: 77, + Type: domain.EncryptedStateEventRead, + MaxDate: 1700000200, + Date: 1700000201, + }) + if err != nil { + t.Fatalf("append state event: %v", err) + } + sessions := &captureSessions{} + updates := &captureUpdates{state: domain.UpdateState{Pts: 4, Date: 1700000201}} + bootstrap := &captureBootstrapReadyStore{BootstrapUpdateJobStore: memory.NewBootstrapUpdateJobStore()} + r := New(Config{}, Deps{ + Sessions: sessions, Updates: updates, SecretChats: secret, BootstrapUpdates: bootstrap, + }, zaptest.NewLogger(t), clock.System) + + var inner bin.Buffer + if err := (&tg.UpdatesGetDifferenceRequest{Pts: 4, Date: 1700000201}).Encode(&inner); err != nil { + t.Fatalf("encode getDifference: %v", err) + } + var wrapped bin.Buffer + wrapped.PutID(tg.InvokeWithoutUpdatesRequestTypeID) + wrapped.Put(inner.Raw()) + ctx := postresponse.WithCallbacks(WithAuthKeyID(WithSessionID(WithUserID(context.Background(), userID), 202), authKeyID)) + if _, err := r.Dispatch(ctx, authKeyID, 202, &wrapped); err != nil { + t.Fatalf("dispatch wrapped baseline: %v", err) + } + if updates.commitCalls != 0 || sessions.snapshot().receivesCalls != 0 { + t.Fatalf("pre-delivery effects = commits:%d ready_calls:%d", updates.commitCalls, sessions.snapshot().receivesCalls) + } + pending, err := queue.ListUndeliveredStateEvents(context.Background(), userID, deviceKey, 10) + if err != nil || len(pending) != 1 || pending[0].ID != eventID { + t.Fatalf("pending before delivery = %+v err=%v", pending, err) + } + + postresponse.Run(ctx) + if updates.commitCalls != 1 || updates.committedState.Pts != 4 { + t.Fatalf("delivered cursor commit = calls:%d state:%+v", updates.commitCalls, updates.committedState) + } + if got := sessions.snapshot(); got.receives || got.receivesCalls != 0 { + t.Fatalf("invokeWithoutUpdates subscribed session: receives=%v calls=%d", got.receives, got.receivesCalls) + } + if bootstrap.readyCalls != 0 { + t.Fatalf("invokeWithoutUpdates released bootstrap %d times", bootstrap.readyCalls) + } + pending, err = queue.ListUndeliveredStateEvents(context.Background(), userID, deviceKey, 10) + if err != nil || len(pending) != 0 { + t.Fatalf("secret events after delivered wrapped baseline = %+v err=%v", pending, err) + } +} + // TestDispatchSkipsReceivesUpdatesWhenLoggedOut 验证未登录连接的 RPC 不置位。 func TestDispatchSkipsReceivesUpdatesWhenLoggedOut(t *testing.T) { sessions := &captureSessions{} - dispatchForReceivesUpdates(t, sessions, false, false) + ctx := dispatchForReceivesUpdates(t, sessions, false, false) + postresponse.Run(ctx) sessions.mu.Lock() defer sessions.mu.Unlock() if sessions.receives { t.Fatal("RPC without bound user must not mark receivesUpdates") } } + +type fifoFlushCaptureSessions struct { + *captureSessions + flushMu sync.Mutex + pending []int + flushed []int +} + +func (s *fifoFlushCaptureSessions) SetReceivesUpdatesForAuthKey(rawAuthKeyID [8]byte, sessionID int64, receives bool) { + if receives { + s.flushMu.Lock() + s.flushed = append(s.flushed, s.pending...) + s.pending = nil + s.flushMu.Unlock() + } + s.captureSessions.SetReceivesUpdatesForAuthKey(rawAuthKeyID, sessionID, receives) +} + +func (s *fifoFlushCaptureSessions) flushedSnapshot() []int { + s.flushMu.Lock() + defer s.flushMu.Unlock() + return append([]int(nil), s.flushed...) +} + +// TestDispatchDefersMembershipAndFIFOFlushUntilPostResponse pins the complete +// readiness barrier: channel membership and pending updates remain untouched +// while the rpc_result is only prepared, then the delivery hook rebuilds +// membership before SetReceivesUpdates drains the original FIFO order. +func TestDispatchDefersMembershipAndFIFOFlushUntilPostResponse(t *testing.T) { + const ( + userID = int64(1000000111) + sessionID = int64(87) + ) + channelSvc := appchannels.NewService(memory.NewChannelStore()) + created, err := channelSvc.CreateMegagroupFromCreateChat(context.Background(), userID, domain.CreateChannelRequest{ + Title: "delivery barrier", + Date: 1700000000, + }) + if err != nil { + t.Fatalf("create channel: %v", err) + } + sessions := &fifoFlushCaptureSessions{ + captureSessions: &captureSessions{}, + pending: []int{11, 22, 33}, + } + r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{ + Sessions: sessions, + Channels: channelSvc, + }, zaptest.NewLogger(t), clock.System) + + var in bin.Buffer + if err := (&tg.HelpGetConfigRequest{}).Encode(&in); err != nil { + t.Fatalf("encode help.getConfig: %v", err) + } + ctx := postresponse.WithCallbacks(WithUserID(context.Background(), userID)) + if _, err := r.Dispatch(ctx, [8]byte{7}, sessionID, &in); err != nil { + t.Fatalf("dispatch: %v", err) + } + if got := sessions.flushedSnapshot(); len(got) != 0 { + t.Fatalf("pending flushed before result delivery: %v", got) + } + if got := sessions.onlineChannelMemberIDs(created.Channel.ID); len(got) != 0 { + t.Fatalf("membership synced before result delivery: %v", got) + } + if sessions.snapshot().receives { + t.Fatal("session ready before result delivery") + } + + postresponse.Run(ctx) + if got, want := sessions.flushedSnapshot(), []int{11, 22, 33}; !reflect.DeepEqual(got, want) { + t.Fatalf("FIFO flush after result delivery = %v, want %v", got, want) + } + if got := sessions.onlineChannelMemberIDs(created.Channel.ID); !reflect.DeepEqual(got, []int64{userID}) { + t.Fatalf("membership after result delivery = %v, want [%d]", got, userID) + } + if !sessions.snapshot().receives { + t.Fatal("session not ready after result delivery") + } +} + +type failingCurrentStateUpdates struct{ *captureUpdates } + +func (s *failingCurrentStateUpdates) CurrentState(context.Context, int64) (domain.UpdateState, error) { + return domain.UpdateState{}, errors.New("current state failed") +} + +func TestFailedRPCDoesNotRegisterSessionReadyPostResponse(t *testing.T) { + sessions := &captureSessions{} + r := New(Config{}, Deps{ + Sessions: sessions, + Updates: &failingCurrentStateUpdates{captureUpdates: &captureUpdates{}}, + }, zaptest.NewLogger(t), clock.System) + var in bin.Buffer + if err := (&tg.UpdatesGetStateRequest{}).Encode(&in); err != nil { + t.Fatalf("encode updates.getState: %v", err) + } + ctx := postresponse.WithCallbacks(WithUserID(context.Background(), 1000000123)) + if _, err := r.Dispatch(ctx, [8]byte{8}, 91, &in); err == nil { + t.Fatal("updates.getState unexpectedly succeeded") + } + postresponse.Run(ctx) + if sessions.snapshot().receives { + t.Fatal("failed RPC marked session ready") + } +} diff --git a/internal/rpc/request_preflight.go b/internal/rpc/request_preflight.go index 9cb7f195..d0d625b0 100644 --- a/internal/rpc/request_preflight.go +++ b/internal/rpc/request_preflight.go @@ -4,8 +4,8 @@ import ( "encoding/binary" "fmt" - "github.com/gotd/td/bin" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/tg" appfiles "telesrv/internal/app/files" "telesrv/internal/domain" @@ -20,6 +20,30 @@ type requestVectorPolicy struct { tooLong func() error } +type rpcPreflightWire interface { + WireSize() int + ByteAt(offset int) (byte, error) + Uint32At(offset int) (uint32, error) +} + +type rawRPCPreflightWire []byte + +func (w rawRPCPreflightWire) WireSize() int { return len(w) } + +func (w rawRPCPreflightWire) ByteAt(offset int) (byte, error) { + if offset < 0 || offset >= len(w) { + return 0, fmt.Errorf("byte offset %d outside request size %d", offset, len(w)) + } + return w[offset], nil +} + +func (w rawRPCPreflightWire) Uint32At(offset int) (uint32, error) { + if offset < 0 || offset > len(w) || len(w)-offset < 4 { + return 0, fmt.Errorf("uint32 offset %d outside request size %d", offset, len(w)) + } + return binary.LittleEndian.Uint32(w[offset:]), nil +} + // requestVectorPolicies mirrors limits already enforced by typed handlers, but does so before // gotd's generated decoder materializes attacker-controlled interface slices. users.getUsers is // the one newly introduced cap: TDesktop's four current call sites all send exactly one user. @@ -40,37 +64,136 @@ var requestVectorPolicies = map[uint32]requestVectorPolicy{ tg.ChannelsGetChannelsRequestTypeID: {vectorOffset: 4, max: maxGetMessagesIDs, minElemBytes: 4, tooLong: limitInvalidErr}, } +// layerRPCVectorPolicies bind resource limits to generated semantic field +// identities, not constructor CRCs, profile-specific field order, flags bits, +// or byte offsets. gotdgen proves at generation time that each registered +// field exposes the same metric in every routable profile. Importing a future +// schema therefore either extends these policies automatically or makes +// dispatcher construction fail closed until an explicit conversion policy is +// supplied. +var layerRPCVectorPolicies = []struct { + fieldID tg.LayerRPCFieldID + max int + tooLong func() error +}{ + {tg.LayerRPCFieldUsersGetUsersID, 100, inputRequestTooLongErr}, + {tg.LayerRPCFieldUsersGetRequirementsToContactID, maxRequirementsToContactUsers, limitInvalidErr}, + {tg.LayerRPCFieldContactsImportContactsContacts, maxContactImportBatch, limitInvalidErr}, + {tg.LayerRPCFieldContactsDeleteContactsID, maxContactDeleteBatch, limitInvalidErr}, + {tg.LayerRPCFieldContactsEditCloseFriendsID, maxCloseFriendsCount, limitInvalidErr}, + {tg.LayerRPCFieldContactsSetBlockedID, maxContactSetBlocked, limitInvalidErr}, + {tg.LayerRPCFieldMessagesGetMessagesID, maxGetMessagesIDs, limitInvalidErr}, + {tg.LayerRPCFieldMessagesGetChatsID, maxGetMessagesIDs, limitInvalidErr}, + {tg.LayerRPCFieldMessagesGetPeerDialogsPeers, maxDialogInputPeers, limitInvalidErr}, + {tg.LayerRPCFieldMessagesReadMessageContentsID, maxGetMessagesIDs, limitInvalidErr}, + {tg.LayerRPCFieldMessagesGetCustomEmojiDocumentsDocumentID, maxEmojiDocuments, limitInvalidErr}, + {tg.LayerRPCFieldMessagesDeleteMessagesID, domain.MaxDeleteMessageIDs, limitInvalidErr}, + {tg.LayerRPCFieldMessagesCreateChatUsers, 200, limitInvalidErr}, + {tg.LayerRPCFieldChannelsGetChannelsID, maxGetMessagesIDs, limitInvalidErr}, +} + +func registerLayerRPCAdmissionFieldPreflights(d *tg.ServerDispatcher) error { + if d == nil { + return fmt.Errorf("nil layer RPC dispatcher") + } + for _, policy := range layerRPCVectorPolicies { + policy := policy + if err := d.OnLayerRPCAdmissionFieldPreflight(policy.fieldID, func(view tg.LayerRPCAdmissionFieldView) error { + length, ok := view.VectorLength() + if !ok { + return inputRequestInvalidErr() + } + if length <= policy.max { + return nil + } + if policy.tooLong != nil { + return policy.tooLong() + } + return inputRequestTooLongErr() + }); err != nil { + return fmt.Errorf("register vector field %#016x: %w", uint64(policy.fieldID), err) + } + } + + for _, fieldID := range []tg.LayerRPCFieldID{ + tg.LayerRPCFieldUploadSaveFilePartBytes, + tg.LayerRPCFieldUploadSaveBigFilePartBytes, + } { + if err := d.OnLayerRPCAdmissionFieldPreflight(fieldID, func(view tg.LayerRPCAdmissionFieldView) error { + length, ok := view.BytesLength() + if !ok { + return inputRequestInvalidErr() + } + if length > appfiles.MaxUploadPartBytes { + return filePartTooBigErr() + } + return nil + }); err != nil { + return fmt.Errorf("register upload bytes field %#016x: %w", uint64(fieldID), err) + } + } + + if err := d.OnLayerRPCAdmissionFieldPreflight( + tg.LayerRPCFieldUploadSaveBigFilePartFileTotalParts, + func(view tg.LayerRPCAdmissionFieldView) error { + totalParts, ok := view.Int32() + if !ok { + return inputRequestInvalidErr() + } + if totalParts <= 0 || totalParts > int32(appfiles.MaxUploadParts) { + return filePartInvalidErr() + } + return nil + }, + ); err != nil { + return fmt.Errorf("register upload total-parts field: %w", err) + } + return nil +} + func preflightRPCRequest(id uint32, b *bin.Buffer) error { if b == nil { return inputRequestInvalidErr() } + return preflightRPCWire(id, rawRPCPreflightWire(b.Buf)) +} + +func preflightRPCWire(id uint32, wire rpcPreflightWire) error { + if wire == nil { + return inputRequestInvalidErr() + } if policy, ok := requestVectorPolicies[id]; ok { - if err := preflightFixedVector(b.Buf, policy); err != nil { + if err := preflightFixedVector(wire, policy); err != nil { return err } } switch id { case tg.UploadSaveFilePartRequestTypeID: - return preflightUploadPart(b.Buf, 16, false) + return preflightUploadPart(wire, 16, false) case tg.UploadSaveBigFilePartRequestTypeID: - return preflightUploadPart(b.Buf, 20, true) + return preflightUploadPart(wire, 20, true) default: return nil } } -func preflightFixedVector(raw []byte, policy requestVectorPolicy) error { - if policy.vectorOffset < 4 || policy.minElemBytes <= 0 || len(raw) < policy.vectorOffset+8 { +func preflightFixedVector(wire rpcPreflightWire, policy requestVectorPolicy) error { + if policy.vectorOffset < 4 || policy.minElemBytes <= 0 || wire.WireSize() < policy.vectorOffset+8 { return inputRequestInvalidErr() } - if binary.LittleEndian.Uint32(raw[policy.vectorOffset:]) != tlVectorTypeID { + typeID, err := wire.Uint32At(policy.vectorOffset) + if err != nil || typeID != tlVectorTypeID { return inputRequestInvalidErr() } - count := int64(int32(binary.LittleEndian.Uint32(raw[policy.vectorOffset+4:]))) + rawCount, err := wire.Uint32At(policy.vectorOffset + 4) + if err != nil { + return inputRequestInvalidErr() + } + count := int64(int32(rawCount)) if count < 0 { return inputRequestInvalidErr() } - remaining := int64(len(raw) - policy.vectorOffset - 8) + remaining := int64(wire.WireSize() - policy.vectorOffset - 8) // Check the cheapest possible encoding before the policy cap. A forged MaxInt32 count with // a truncated body is malformed, not merely a large valid request, and is rejected O(1). if count > remaining/int64(policy.minElemBytes) { @@ -85,21 +208,25 @@ func preflightFixedVector(raw []byte, policy requestVectorPolicy) error { return nil } -func preflightUploadPart(raw []byte, bytesOffset int, big bool) error { +func preflightUploadPart(wire rpcPreflightWire, bytesOffset int, big bool) error { if big { - if len(raw) < 20 { + if wire.WireSize() < 20 { return inputRequestInvalidErr() } - totalParts := int32(binary.LittleEndian.Uint32(raw[16:20])) + rawTotalParts, err := wire.Uint32At(16) + if err != nil { + return inputRequestInvalidErr() + } + totalParts := int32(rawTotalParts) if totalParts <= 0 || totalParts > appfiles.MaxUploadParts { return filePartInvalidErr() } } - n, encoded, err := tlBytesSizeAt(raw, bytesOffset) + n, encoded, err := tlBytesSizeAt(wire, bytesOffset) if err != nil { return inputRequestInvalidErr() } - if encoded != len(raw)-bytesOffset { + if encoded != wire.WireSize()-bytesOffset { return inputRequestInvalidErr() } if n > appfiles.MaxUploadPartBytes { @@ -110,27 +237,36 @@ func preflightUploadPart(raw []byte, bytesOffset int, big bool) error { // tlBytesSizeAt parses a TL bytes prefix without copying the payload. encoded includes prefix, // payload and 4-byte padding. -func tlBytesSizeAt(raw []byte, offset int) (n, encoded int, err error) { - if offset < 0 || offset >= len(raw) { +func tlBytesSizeAt(wire rpcPreflightWire, offset int) (n, encoded int, err error) { + if offset < 0 || offset >= wire.WireSize() { return 0, 0, fmt.Errorf("bytes prefix out of range") } - first := raw[offset] + first, err := wire.ByteAt(offset) + if err != nil { + return 0, 0, err + } prefix := 1 switch { case first < 254: n = int(first) case first == 254: - if len(raw)-offset < 4 { + if wire.WireSize()-offset < 4 { return 0, 0, fmt.Errorf("truncated long bytes prefix") } - n = int(raw[offset+1]) | int(raw[offset+2])<<8 | int(raw[offset+3])<<16 + second, secondErr := wire.ByteAt(offset + 1) + third, thirdErr := wire.ByteAt(offset + 2) + fourth, fourthErr := wire.ByteAt(offset + 3) + if secondErr != nil || thirdErr != nil || fourthErr != nil { + return 0, 0, fmt.Errorf("truncated long bytes prefix") + } + n = int(second) | int(third)<<8 | int(fourth)<<16 prefix = 4 default: return 0, 0, fmt.Errorf("invalid bytes prefix") } total := prefix + n padding := (4 - total%4) % 4 - if total > len(raw)-offset-padding { + if total > wire.WireSize()-offset-padding { return 0, 0, fmt.Errorf("truncated bytes payload") } return n, total + padding, nil diff --git a/internal/rpc/request_preflight_test.go b/internal/rpc/request_preflight_test.go index 0ca59a81..7d3768db 100644 --- a/internal/rpc/request_preflight_test.go +++ b/internal/rpc/request_preflight_test.go @@ -5,10 +5,10 @@ import ( "encoding/binary" "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" appfiles "telesrv/internal/app/files" diff --git a/internal/rpc/router.go b/internal/rpc/router.go index f44fb8e3..847f4f37 100644 --- a/internal/rpc/router.go +++ b/internal/rpc/router.go @@ -11,11 +11,12 @@ import ( "go.uber.org/zap" "golang.org/x/sync/singleflight" - "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/proto" + "github.com/iamxvbaba/td/tg" - "telesrv/internal/compat/layerwire" + compatandroid "telesrv/internal/compat/android" "telesrv/internal/domain" "telesrv/internal/observability/dbtrace" ) @@ -91,32 +92,46 @@ type Config struct { // Router 把解密后的 RPC 请求按 TypeID 路由到 typed handler(tg.ServerDispatcher)。 // -// handler 输入输出均为 gotd/td/tg 类型,各业务域的 handler +// handler 输入输出均为 iamxvbaba/td/tg 类型,各业务域的 handler // 与注册见 help.go / auth.go / users.go / updates.go。Router 本身只负责协议外壳: // 剥离 invokeWithLayer / initConnection / invokeWithoutUpdates / invokeAfter*,并兜底未注册 RPC。 type Router struct { - cfg Config - log *zap.Logger - clock clock.Clock - deps Deps - dispatcher *tg.ServerDispatcher - clientInfoMu sync.RWMutex - clientInfo map[clientInfoSessionKey]clientSessionInfo - authInfo map[[8]byte]clientSessionInfo - authUserMu sync.RWMutex - authUsers map[[8]byte]authUserCacheEntry - authUserSF singleflight.Group - mediaCountSF singleflight.Group - dialogsPinnedSF singleflight.Group - channelFullBotSF singleflight.Group - presence *presenceTracker - callbacks *callbackRegistry - inlines *inlineRegistry - webviews *webViewRegistry - loginTokens *loginTokenRegistry - botAPIUpdates *botAPIUpdateNotifier - instanceID string - channelFanout *channelFanoutDispatcher + cfg Config + log *zap.Logger + clock clock.Clock + deps Deps + dispatcher *tg.ServerDispatcher + clientInfoMu sync.RWMutex + clientInfo map[clientInfoSessionKey]clientSessionInfo + authInfo map[[8]byte]clientSessionInfo + authLayerEvidence map[[8]byte]authLayerDefaultEvidence + authLayerCommit [authLayerCommitStripes]sync.Mutex + // authLayerSafeEvictionFloor is the monotonic lower bound supplied by the + // edge-owned exact admission tracker. Evidence below this sequence has no + // live owner that can still enter publication and is therefore capacity- + // evictable. clientInfoMu protects it together with authLayerEvidence. + authLayerSafeEvictionFloor uint64 + exactProfileMu sync.RWMutex + exactProfiles map[clientInfoSessionKey]exactSessionProfileEntry + // exactProfileEarliestExpiry is a conservative lower bound. Refresh/deletes + // may leave it earlier than the true minimum (safe); a capacity scan + // recomputes it exactly. This makes the normal all-live full-capacity reject + // O(1) without a heap on every refresh. + exactProfileEarliestExpiry time.Time + authUserMu sync.RWMutex + authUsers map[[8]byte]authUserCacheEntry + authUserSF singleflight.Group + mediaCountSF singleflight.Group + dialogsPinnedSF singleflight.Group + channelFullBotSF singleflight.Group + presence *presenceTracker + callbacks *callbackRegistry + inlines *inlineRegistry + webviews *webViewRegistry + loginTokens *loginTokenRegistry + botAPIUpdates *botAPIUpdateNotifier + instanceID string + channelFanout *channelFanoutDispatcher // botAPIEnqueueQueue 把 user→bot 私聊消息的 bot_api_updates 写入移出发送者 RPC 同步 // 路径(性能审计 H2);队列满同步回退,绝不丢(队列行是 Bot API 投递真值)。 botAPIEnqueueQueue *botAPIEnqueueDispatcher @@ -163,11 +178,51 @@ type clientInfoSessionKey struct { } type clientSessionInfo struct { - layer int - clientInfo ClientInfo - hasClientInfo bool - authKeyInfoChecked bool - authorizationChecked bool + layer int + // layerObservationID is the durable cross-restart ordering token from + // auth_keys. It is independent from process-local admission sequence. + layerObservationID int64 + // layerAdmissionSeq is the server-assigned admission order of explicit + // invokeWithLayer evidence. It is retained on auth-key defaults and on the + // exact raw-session metadata shadow written by admission publication. Client + // msg_id is deliberately not used because its ordering is session-local. + layerAdmissionSeq uint64 + wrapperMsgID int64 + clientInfoAdmissionSeq uint64 + clientInfo ClientInfo + hasClientInfo bool + authKeyInfoChecked bool + authorizationChecked bool + layerBlocked bool + layerBlockedByAuthKey bool +} + +type exactSessionProfileEntry struct { + layer int + msgID int64 + observationID int64 + expiresAt time.Time +} + +// ExactSessionProfileCapacityError reports that the bounded replay/profile +// registry contains only still-live logical sessions. Callers must fail closed +// for shared profile mutation; no unexpired msg_id watermark was evicted. +// The marker method lets mtprotoedge recognize the condition without importing +// the higher-level rpc package. +type ExactSessionProfileCapacityError struct { + Limit int +} + +func (e *ExactSessionProfileCapacityError) Error() string { + return fmt.Sprintf("exact session profile capacity exhausted (limit %d)", e.Limit) +} + +func (*ExactSessionProfileCapacityError) ExactSessionProfileCapacity() {} + +type authLayerDefaultEvidence struct { + layer int + sequence uint64 + durable bool } type authUserCacheEntry struct { @@ -181,7 +236,7 @@ func New(cfg Config, deps Deps, log *zap.Logger, clk clock.Clock) *Router { if instanceID == "" { instanceID = fmt.Sprintf("%016x", randomNonZeroInt64()) } - r := &Router{cfg: cfg, log: log, clock: clk, deps: deps, presence: newPresenceTracker(), callbacks: newCallbackRegistry(), inlines: newInlineRegistry(botInlineQueryTTL, deps.Inline), webviews: newWebViewRegistry(webViewSessionTTL, deps.Inline), loginTokens: newLoginTokenRegistry(), botAPIUpdates: newBotAPIUpdateNotifier(), tempKeyResolveCache: newTempKeyResolveCache(cfg.TempKeyResolveCacheMaxEntries), storyProjectionCache: newStoryProjectionCache(clk.Now), storyPinnedCache: newStoryPinnedAvailableCache(clk.Now), storyPinnedListCache: newStoryPinnedStoriesCache(clk.Now), channelFullBotCache: newChannelFullBotInfoCache(clk.Now), userFullProjectionCache: newUserFullProjectionCache(clk.Now), peerSettingsProjectionCache: newPeerSettingsProjectionCache(clk.Now), channelFullProjectionCache: newChannelFullProjectionCache(clk.Now), emojiStickers: newEmojiStickerIndex(clk.Now), notifySettings: newNotifySettingsCache(clk.Now), stickerCatalog: newStickerCatalogCache(clk.Now), accountSettings: newAccountSettingsCache(clk.Now), instanceID: instanceID} + r := &Router{cfg: cfg, log: log, clock: clk, deps: deps, exactProfiles: make(map[clientInfoSessionKey]exactSessionProfileEntry), authLayerEvidence: make(map[[8]byte]authLayerDefaultEvidence), presence: newPresenceTracker(), callbacks: newCallbackRegistry(), inlines: newInlineRegistry(botInlineQueryTTL, deps.Inline), webviews: newWebViewRegistry(webViewSessionTTL, deps.Inline), loginTokens: newLoginTokenRegistry(), botAPIUpdates: newBotAPIUpdateNotifier(), tempKeyResolveCache: newTempKeyResolveCache(cfg.TempKeyResolveCacheMaxEntries), storyProjectionCache: newStoryProjectionCache(clk.Now), storyPinnedCache: newStoryPinnedAvailableCache(clk.Now), storyPinnedListCache: newStoryPinnedStoriesCache(clk.Now), channelFullBotCache: newChannelFullBotInfoCache(clk.Now), userFullProjectionCache: newUserFullProjectionCache(clk.Now), peerSettingsProjectionCache: newPeerSettingsProjectionCache(clk.Now), channelFullProjectionCache: newChannelFullProjectionCache(clk.Now), emojiStickers: newEmojiStickerIndex(clk.Now), notifySettings: newNotifySettingsCache(clk.Now), stickerCatalog: newStickerCatalogCache(clk.Now), accountSettings: newAccountSettingsCache(clk.Now), instanceID: instanceID} r.channelFanout = newChannelFanoutDispatcher(r, defaultChannelFanoutShards, defaultChannelFanoutBuffer) r.botAPIEnqueueQueue = newBotAPIEnqueueDispatcher(log, defaultBotAPIEnqueueBuffer) r.webPageResolveSem = make(chan struct{}, webPageResolveConcurrency) @@ -190,6 +245,11 @@ func New(cfg Config, deps Deps, log *zap.Logger, clk clock.Clock) *Router { groupCallStreamDCID = cfg.DC } d := tg.NewServerDispatcher(r.fallback) + if err := registerLayerRPCAdmissionFieldPreflights(d); err != nil { + panic(fmt.Sprintf("register exact layer RPC admission policy: %v", err)) + } + r.registerAndroidLayerRPCAdapter(d) + d.OnLayerRPCWrappers(r.consumeLayerRPCWrappers) r.registerHelp(d) r.registerAuth(d) @@ -220,7 +280,7 @@ func New(cfg Config, deps Deps, log *zap.Logger, clk clock.Clock) *Router { // Dispatch routes one RPC and preserves the historical two-value API used by // domain/RPC tests. The MTProto edge uses DispatchWithMethod so outbound -// scheduling sees the canonical inner method rather than an invoke wrapper. +// scheduling sees the exact innermost method rather than an invoke wrapper. func (r *Router) Dispatch(ctx context.Context, authKeyID [8]byte, sessionID int64, b *bin.Buffer) (bin.Encoder, error) { enc, _, err := r.DispatchWithMethod(ctx, authKeyID, sessionID, b) return enc, err @@ -228,87 +288,24 @@ func (r *Router) Dispatch(ctx context.Context, authKeyID [8]byte, sessionID int6 // DispatchWithMethod 路由一条 RPC 请求:先剥离 invokeWithLayer / initConnection / // invokeWithoutUpdates / invokeAfter* 等 wrapper(注入 layer / 客户端信息到 ctx), -// 再按 TypeID 路由到 typed handler,并返回 canonical innermost method。 +// 再按 TypeID 路由到 typed handler,并返回 exact innermost method。 func (r *Router) DispatchWithMethod(ctx context.Context, authKeyID [8]byte, sessionID int64, b *bin.Buffer) (bin.Encoder, string, error) { - preStart := r.clock.Now() - ctx = withInboundRPCBytes(ctx, b.Len()) - ctx = WithRawAuthKeyID(ctx, authKeyID) - effectiveAuthKeyID, err := r.effectiveAuthKeyID(ctx, authKeyID, sessionID) + if b == nil { + return nil, "", inputRequestInvalidErr() + } + method := "unknown" + if id, peekErr := b.PeekID(); peekErr == nil { + method = tlTypeName(id) + } + ctx, updatesDelivery, err := r.prepareRPCDispatchContext(ctx, authKeyID, sessionID, b.Len(), method) if err != nil { - return nil, "", internalErr() - } - tAuth := r.clock.Now() - ctx = WithAuthKeyID(ctx, effectiveAuthKeyID) - ctx = WithSessionID(ctx, sessionID) - userID, hasUserID, err := r.effectiveUserID(ctx, authKeyID, effectiveAuthKeyID, sessionID) - if err != nil { - return nil, "", internalErr() - } - if hasUserID { - ctx = WithUserID(ctx, userID) - } - tUser := r.clock.Now() - info, hasClientMetadata, clientMetadataStored := r.clientSessionInfo(ctx) - if authInfo, ok := r.clientSessionInfoFromAuthKey(ctx, effectiveAuthKeyID, info); ok { - info = mergeClientSessionInfo(info, authInfo) - hasClientMetadata = true - r.rememberClientSessionInfo(ctx, info) - clientMetadataStored = true - if info.layer != 0 { - if binder, okBinder := r.deps.Sessions.(ClientLayerBinder); okBinder { - if rawAuthKeyID, okRaw := RawAuthKeyIDFrom(ctx); okRaw { - binder.SetClientLayerForAuthKey(rawAuthKeyID, sessionID, info.layer) - } - } - } - } - if hasUserID { - if authInfo, ok := r.clientSessionInfoFromAuthorization(ctx, userID, effectiveAuthKeyID, info); ok { - info = mergeClientSessionInfo(info, authInfo) - hasClientMetadata = true - r.rememberClientSessionInfo(ctx, info) - clientMetadataStored = true - // 冷启动回填:授权表恢复的 layer 即时下推到连接,防止本条 RPC handler - // 执行期间的 push 仍按 canonical 227 发给老客户端(该分支只在元数据 - // 尚未入缓存时走到,稳态 RPC 不经过这里)。 - if info.layer != 0 { - if binder, okBinder := r.deps.Sessions.(ClientLayerBinder); okBinder { - if rawAuthKeyID, okRaw := RawAuthKeyIDFrom(ctx); okRaw { - binder.SetClientLayerForAuthKey(rawAuthKeyID, sessionID, info.layer) - } - } - } - } - } - // 前置鉴权阶段(auth key 解析 / user 重校验 / client info)慢路径告警:超阈值才记,避免刷屏。 - // 常驻观测——正常应 ≪50ms;再现 >50ms 时按 auth_resolve / user_resolve / client_info 三段拆分 - // 即可定位(历史上 client_info ~1s 的根因是 DSN 用 localhost 触发 IPv6 连接回退,已改 127.0.0.1)。 - if r.log != nil { - if tInfo := r.clock.Now(); tInfo.Sub(preStart) > 50*time.Millisecond { - id, _ := b.PeekID() - r.log.Info("slow pre-handler", - zap.String("method", tlTypeName(id)), - zap.Duration("pre_total", tInfo.Sub(preStart)), - zap.Duration("auth_resolve", tAuth.Sub(preStart)), - zap.Duration("user_resolve", tUser.Sub(tAuth)), - zap.Duration("client_info", tInfo.Sub(tUser)), - zap.Int64("session_id", sessionID), - ) - } - } - if hasClientMetadata { - if !clientMetadataStored { - r.rememberClientSessionInfoIfMissing(ctx, info) - } - if info.layer != 0 { - ctx = WithLayer(ctx, info.layer) - } - if info.hasClientInfo { - ctx = WithClientInfo(ctx, info.clientInfo) - } + return nil, "", err } meta := rpcDispatchMetadata{} enc, err := r.dispatch(ctx, b, 0, &meta) + if err == nil && enc != nil { + r.registerUpdatesDeliveryPlan(ctx, updatesDelivery) + } return enc, meta.method, err } @@ -511,13 +508,24 @@ func (r *Router) invalidateAuthUserCache(authKeyID [8]byte) { delete(r.authUsers, authKeyID) r.authUserMu.Unlock() r.clientInfoMu.Lock() - delete(r.authInfo, authKeyID) + if info, ok := r.authInfo[authKeyID]; ok { + // Authorization membership can change independently of protocol + // metadata. Preserve the Layer/default ordering watermark so an older + // in-flight publisher cannot roll durable state back after login/logout. + info.authorizationChecked = false + if !info.layerBlockedByAuthKey { + info.layerBlocked = false + } + r.authInfo[authKeyID] = info + } r.clientInfoMu.Unlock() key := string(authKeyID[:]) r.authUserSF.Forget(key) r.authUserSF.Forget(authKeyResolveSingleflightPrefix + key) r.authUserSF.Forget(authClientInfoSingleflightPrefix + key) r.authUserSF.Forget(authKeyClientInfoSingleflightPrefix + key) + r.authUserSF.Forget(inheritedAuthKeyLayerSingleflightPrefix + key) + r.authUserSF.Forget(durableInheritedAuthKeyLayerSingleflightPrefix + key) } type rpcDispatchMetadata struct { @@ -611,27 +619,28 @@ func (r *Router) dispatch(ctx context.Context, b *bin.Buffer, depth int, meta *r return r.dispatch(ctx, &bin.Buffer{Buf: inner.data}, depth+1, meta) default: - // 入站兼容统一入口(先于鉴权门/dispatcher):layerwire 把老客户端请求升级为 - // canonical(227) 形态——①官方层漂移(生成表,flag-gated 新增→换 4 字节 id) - // ②客户端构造器漂移(client_aliases 纯换 id / client-drift.tl 通用 body 变换: - // 插 flags、按 kind 补默认、类型转换、改名映射)。替代了原先散落在 rpc 的 - // dispatchCompat + 各 handleLegacy* 解码器。提前到鉴权门之前,使后续一切只面对 227 - // 形态(鉴权白名单、dispatcher 均无需再认旧构造器 id)。 + // Router.Dispatch is a legacy test seam. Production uses generated exact + // Layer admission, whose unknown-method view invokes the same static DrKLO + // overlay while sharing the outer request budget. if id != 0 { - clientDrift := layerwire.IsClientDrift(id) - if up, ok, err := layerwire.UpgradeInbound(id, b); ok { - if err != nil { - return nil, err - } - b = up - newID, err := b.PeekID() - if err != nil { - return nil, err - } - id = newID - if clientDrift { - // 客户端漂移只能证明这是 Android 兼容路径;layer 仍以 - // invokeWithLayer 或授权记录里的真实观测值为准。 + profile := tg.LayerProfileCanonical + if selected, ok := tg.ResolveLayerProfile(LayerFrom(ctx)); ok { + profile = selected + } + _, official := tg.LayerSemanticForWireID(profile, id) + if !official { + if up, ok, err := compatandroid.UpgradePrivateLayerRPC(profile, b, tg.LayerDecodeLimits{}); ok { + if err != nil { + return nil, inputRequestInvalidErr() + } + b = up + newID, err := b.PeekID() + if err != nil { + return nil, err + } + id = newID + // A private constructor identifies the DrKLO compatibility seam but + // never selects or changes the connection's Layer profile. ctx = r.withClientDriftMetadata(ctx, ClientTypeAndroid) } } @@ -639,14 +648,13 @@ func (r *Router) dispatch(ctx context.Context, b *bin.Buffer, depth int, meta *r if meta != nil { meta.method = tlTypeName(id) } - knownRequest, structuralErr := layerwire.ValidateRoutableRequest(b.Buf) + semantic, knownRequest := tg.LayerSemanticForWireID(tg.LayerProfileCanonical, id) + if knownRequest { + category, _, named := tg.LayerSemanticName(semantic) + knownRequest = named && category == "function" + } if !knownRequest { - if structuralErr != nil { - return nil, mapLayerwirePreflightError(structuralErr) - } - // Unknown methods are opaque after the bounded/alignment check above: no generated - // decoder will touch their body. Route them directly to the compatibility fallback - // so every unknown constructor is traced, including pre-login probes. + // Unknown methods remain opaque and go to the compatibility trace. return r.fallback(ctx, b) } if r.deps.Auth != nil { @@ -662,13 +670,6 @@ func (r *Router) dispatch(ctx context.Context, b *bin.Buffer, depth int, meta *r if err := preflightRPCRequest(id, b); err != nil { return nil, err } - // Run the same allocation-free schema walker used by layer aliases/DrKLO transforms on - // every canonical request before gotd's generated decoder materializes vectors/bytes. - // Method-specific caps above preserve exact existing RPC errors; this generic budget - // closes variable-offset/nested-object paths and malformed constructor recursion. - if structuralErr != nil { - return nil, mapLayerwirePreflightError(structuralErr) - } // 任何未包 invokeWithoutUpdates 的已登录 RPC 都把当前 session 视为 updates // 接收者。仅靠 updates.getState/getDifference 置位会漏掉 DrKLO 热恢复: // 它重连后不重建同步基线(pts 在进程内存里),只发普通业务请求,置位 @@ -697,13 +698,6 @@ func (r *Router) dispatch(ctx context.Context, b *bin.Buffer, depth int, meta *r } } -func mapLayerwirePreflightError(err error) error { - if errors.Is(err, layerwire.ErrResourceLimit) { - return inputRequestTooLongErr() - } - return inputRequestInvalidErr() -} - func tlTypeName(id uint32) string { tlTypeNamesOnce.Do(func() { names := tg.NamesMap() @@ -721,11 +715,22 @@ func tlTypeName(id uint32) string { // maxClientInfoEntries / maxAuthInfoEntries 是客户端元数据缓存的容量上限兜底。 // 条目含客户端可控字符串且 session_id 由客户端任意生成,无上限时恶意客户端 // 在单连接上反复换 session_id / 轮换 temp auth key 可线速膨胀直至 OOM。 -// 达到上限后驱逐任意旧条目:受害条目只损失 layer/clientType 缓存, -// 下一次 initConnection 或 authorization 回填即恢复。 +// 达到上限后驱逐任意旧条目:受害条目只损失进程内默认/客户端描述缓存, +// 下一次 auth-key resolver、initConnection 或 authorization 回填即可恢复。 +// exact profile 由下方独立的 same-session registry 管理,永远优先于默认。 const ( maxClientInfoEntries = 1 << 16 maxAuthInfoEntries = 1 << 16 + // exactSessionProfileLegacyTTL covers the normal 300-second client msg_id + // window plus the allowed 30-second future skew and a one-second equality + // margin. Ordered evidence uses its own msg_id timestamp instead of blindly + // refreshing this TTL on duplicate replay. + exactSessionProfileLegacyTTL = 331 * time.Second + // exactSessionProfileTTL remains the maximum/legacy force-path retention + // used by focused registry tests. Real ordered evidence uses the expiry + // derived above from its msg_id. + exactSessionProfileTTL = exactSessionProfileLegacyTTL + maxExactSessionProfileEntries = 1 << 16 // maxAuthUsersCached 给 authUsers 授权缓存设容量上界,与 clientInfo/authInfo 一致。 // 原本无任何上限:设备轮换 temp 键而不显式登出时每个新 authKeyID 永久累积一条, // 只靠 logout/reset 的显式 invalidate 清理。达上限驱逐任意旧条目,下次按需回查回填。 @@ -733,16 +738,80 @@ const ( ) func (r *Router) rememberClientInfo(ctx context.Context, info ClientInfo) { + r.rememberClientInfoAt(ctx, info, 0) +} + +func (r *Router) rememberClientInfoAt(ctx context.Context, info ClientInfo, admissionSeq uint64) { info = normalizeClientInfo(info) - layer := LayerFrom(ctx) - r.mutateClientSessionInfo(ctx, func(sessionInfo *clientSessionInfo) { - sessionInfo.clientInfo = info - sessionInfo.hasClientInfo = true - if layer != 0 { - sessionInfo.layer = layer + rawAuthKeyID, hasRawAuthKeyID := RawAuthKeyIDFrom(ctx) + sessionID, hasSessionID := SessionIDFrom(ctx) + if !hasRawAuthKeyID || !hasSessionID { + return + } + authKeyID, hasAuthKeyID := AuthKeyIDFrom(ctx) + if !hasAuthKeyID { + authKeyID = rawAuthKeyID + } + unlockCommit := r.lockAuthLayerCommit(rawAuthKeyID, authKeyID) + defer unlockCommit() + + r.clientInfoMu.Lock() + if r.clientInfo == nil { + r.clientInfo = make(map[clientInfoSessionKey]clientSessionInfo) + } + key := clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} + sessionInfo, exists := r.clientInfo[key] + if !exists { + evictMapEntryIfFullLocked(r.clientInfo, maxClientInfoEntries) + } + sessionInfo.clientInfo = info + sessionInfo.hasClientInfo = true + if admissionSeq > 0 { + sessionInfo.clientInfoAdmissionSeq = admissionSeq + } + r.clientInfo[key] = sessionInfo + + publishAuthMetadata := true + for _, id := range [][8]byte{rawAuthKeyID, authKeyID} { + current := r.authInfo[id] + if current.clientInfoAdmissionSeq > admissionSeq || + (admissionSeq == 0 && current.clientInfoAdmissionSeq > 0) { + publishAuthMetadata = false + break } - }) - r.persistAuthKeyClientInfo(ctx, clientSessionInfo{layer: layer, clientInfo: info, hasClientInfo: true}) + if admissionSeq > 0 && current.clientInfoAdmissionSeq == admissionSeq && + current.hasClientInfo && current.clientInfo != info { + publishAuthMetadata = false + break + } + } + if publishAuthMetadata { + for _, id := range [][8]byte{rawAuthKeyID, authKeyID} { + if id == ([8]byte{}) { + continue + } + if r.authInfo == nil { + r.authInfo = make(map[[8]byte]clientSessionInfo) + } + if _, exists := r.authInfo[id]; !exists { + evictMapEntryIfFullLocked(r.authInfo, maxAuthInfoEntries) + } + current := r.authInfo[id] + current.clientInfo = info + current.hasClientInfo = true + if admissionSeq > 0 { + current.clientInfoAdmissionSeq = admissionSeq + } + r.authInfo[id] = current + } + } + r.clientInfoMu.Unlock() + // initConnection metadata is not fresh Layer evidence when admitted under an + // inherited default. Only rememberClientLayer (explicit invokeWithLayer) + // advances the auth-key-wide durable default. + if publishAuthMetadata { + r.persistAuthKeyClientInfo(ctx, clientSessionInfo{clientInfo: info, hasClientInfo: true}) + } } func (r *Router) rememberClientAPIID(ctx context.Context, apiID int) { @@ -758,10 +827,15 @@ func (r *Router) rememberClientAPIID(ctx context.Context, apiID int) { if effective, ok, _ := r.clientSessionInfo(ctx); ok { sessionInfo = effective } + sessionInfo.layer = 0 r.persistAuthKeyClientInfo(ctx, sessionInfo) } func (r *Router) rememberClientLayer(ctx context.Context, layer int) { + r.rememberClientLayerAt(ctx, layer, 0) +} + +func (r *Router) rememberClientLayerAt(ctx context.Context, layer int, msgID int64) { if layer <= 0 { return } @@ -773,17 +847,37 @@ func (r *Router) rememberClientLayer(ctx context.Context, layer int) { if !ok { return } + if _, err := r.FreezeNegotiatedSessionLayerAt(rawAuthKeyID, sessionID, layer, msgID); err != nil { + // Only invalid identities and profiles not generated into this binary can + // fail. Never clamp a future persisted/wire Layer to canonical. + if r.log != nil { + r.log.Warn("refuse unsupported exact session layer", + zap.Int("layer", layer), + zap.Int64("session_id", sessionID), + zap.String("auth_key_id", fmt.Sprintf("%x", rawAuthKeyID[:])), + zap.Error(err)) + } + return + } authKeyID, hasAuthKeyID := AuthKeyIDFrom(ctx) - persistAuthLayer := false + if !hasAuthKeyID { + authKeyID = rawAuthKeyID + } + unlockCommit := r.lockAuthLayerCommit(rawAuthKeyID, authKeyID) + defer unlockCommit() + if msgID > 0 { + currentLayer, currentMsgID, exists := r.NegotiatedSessionLayerEvidence(rawAuthKeyID, sessionID) + if !exists || currentLayer != layer || currentMsgID != msgID { + // A greater msg_id won after this request was admitted or while it + // waited for the auth-key commit stripe. The request remains valid, + // but its mutable default/binder effects are stale. + return + } + } r.clientInfoMu.Lock() if r.clientInfo == nil { r.clientInfo = make(map[clientInfoSessionKey]clientSessionInfo) } - if hasAuthKeyID { - if info, ok := r.authInfo[authKeyID]; !ok || info.layer != layer { - persistAuthLayer = true - } - } sessionKey := clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} sessionInfo, exists := r.clientInfo[sessionKey] // session 级记录缺失或 layer 变化时把新值即时下推到连接:invokeWithLayer 在 @@ -797,9 +891,26 @@ func (r *Router) rememberClientLayer(ctx context.Context, layer int) { evictMapEntryIfFullLocked(r.clientInfo, maxClientInfoEntries) } r.clientInfo[sessionKey] = sessionInfo - r.rememberAuthClientLayerLocked(rawAuthKeyID, layer) + publishDefault := r.authInfo[rawAuthKeyID].layerAdmissionSeq == 0 + if _, ordered := r.authLayerEvidence[rawAuthKeyID]; ordered { + publishDefault = false + } + if hasAuthKeyID && r.authInfo[authKeyID].layerAdmissionSeq != 0 { + publishDefault = false + } if hasAuthKeyID { - r.rememberAuthClientLayerLocked(authKeyID, layer) + if _, ordered := r.authLayerEvidence[authKeyID]; ordered { + publishDefault = false + } + } + defaultChanged := false + if publishDefault { + defaultChanged = r.authClientLayerLocked(rawAuthKeyID) != layer + r.rememberAuthClientLayerLocked(rawAuthKeyID, layer) + if hasAuthKeyID { + defaultChanged = defaultChanged || r.authClientLayerLocked(authKeyID) != layer + r.rememberAuthClientLayerLocked(authKeyID, layer) + } } r.clientInfoMu.Unlock() if notifyConn { @@ -807,14 +918,11 @@ func (r *Router) rememberClientLayer(ctx context.Context, layer int) { binder.SetClientLayerForAuthKey(rawAuthKeyID, sessionID, layer) } } - r.persistAuthKeyClientInfo(ctx, clientSessionInfo{layer: layer}) - if persistAuthLayer && r.deps.Auth != nil { - if err := r.deps.Auth.UpdateAuthorizationLayer(ctx, authKeyID, layer); err != nil { - r.log.Warn("update authorization layer failed", - zap.Int("layer", layer), - zap.String("auth_key_id", fmt.Sprintf("%x", authKeyID[:])), - zap.Error(err)) - } + // The newest explicit observation becomes the default for future sessions. + // A repeat from an older live session may legitimately move that default + // back without changing any sibling session's already-selected profile. + if publishDefault && (notifyConn || defaultChanged) { + r.persistAuthKeyClientInfo(ctx, clientSessionInfo{layer: layer}) } } @@ -848,25 +956,218 @@ func (r *Router) persistAuthKeyClientInfo(ctx context.Context, info clientSessio } } -// NegotiatedLayer returns the TL layer the given session negotiated via -// invokeWithLayer/initConnection. It is keyed first by (auth_key, session) then -// falls back to the stable auth_key — so a reconnect with a new session_id still -// inherits the layer within the process lifetime. ok=false means no layer was -// ever observed (cold connection, or the in-memory entry was evicted): callers -// MUST NOT overwrite a connection's last-known layer in that case, only treat it -// as canonical (227) when no value was ever recorded. +// NegotiatedLayer is the legacy exact-session lookup. Auth-key-wide inheritance +// is intentionally exposed separately by ResolveInheritedAuthKeyLayer so the +// edge can retain the source distinction and let a later explicit selector +// correct an inherited Conn profile. func (r *Router) NegotiatedLayer(authKeyID [8]byte, sessionID int64) (int, bool) { - r.clientInfoMu.RLock() - defer r.clientInfoMu.RUnlock() - if info, ok := r.clientInfo[clientInfoSessionKey{rawAuthKeyID: authKeyID, sessionID: sessionID}]; ok && info.layer != 0 { - return info.layer, true - } - if info, ok := r.authInfo[authKeyID]; ok && info.layer != 0 { - return info.layer, true + if layer, ok := r.NegotiatedSessionLayer(authKeyID, sessionID); ok { + return layer, true } return currentClientLayer, false } +// NegotiatedSessionLayer returns only an exact same-session observation. The +// profile registry is deliberately independent from transient client metadata: +// ordinary transport offline removes presence/device cache entries but must not +// erase the immutable profile needed by same-session naked RPC replay. +func (r *Router) NegotiatedSessionLayer(authKeyID [8]byte, sessionID int64) (int, bool) { + layer, _, ok := r.NegotiatedSessionLayerEvidence(authKeyID, sessionID) + return layer, ok +} + +// NegotiatedSessionLayerEvidence returns the latest explicit profile together +// with the MTProto message id that linearized it. msgID=0 denotes a legacy +// caller that had no wire-order evidence. +func (r *Router) NegotiatedSessionLayerEvidence(authKeyID [8]byte, sessionID int64) (layer int, msgID int64, ok bool) { + if r == nil || authKeyID == ([8]byte{}) || sessionID == 0 { + return 0, 0, false + } + key := clientInfoSessionKey{rawAuthKeyID: authKeyID, sessionID: sessionID} + now := r.clock.Now() + r.exactProfileMu.RLock() + entry, ok := r.exactProfiles[key] + r.exactProfileMu.RUnlock() + if !ok || entry.layer == 0 { + return 0, 0, false + } + if now.Before(entry.expiresAt) { + return entry.layer, entry.msgID, true + } + // Expiry is a state transition, not a read-time fallback. Delete only the + // value observed above so a concurrent refresh cannot be lost. + r.exactProfileMu.Lock() + if current, exists := r.exactProfiles[key]; exists && current == entry && !now.Before(current.expiresAt) { + delete(r.exactProfiles, key) + } + r.exactProfileMu.Unlock() + return 0, 0, false +} + +// FreezeNegotiatedSessionLayer atomically records the latest explicit profile +// proven for one MTProto (raw auth key, session) identity. A later valid +// invokeWithLayer is an ordered correction, not a connection conflict: replace +// the old value and refresh its retention. Request/result encoding remains +// bound to each admitted request's immutable profile outside this registry. +func (r *Router) FreezeNegotiatedSessionLayer(authKeyID [8]byte, sessionID int64, layer int) error { + _, err := r.FreezeNegotiatedSessionLayerAt(authKeyID, sessionID, layer, 0) + return err +} + +// FreezeNegotiatedSessionLayerAt linearizes explicit invokeWithLayer evidence +// by MTProto message id. Older evidence is ignored; the same message id is +// idempotent only for the same profile; a greater id may correct the session. +// msgID=0 is the legacy force API. Repeating the current layer through that API +// refreshes TTL without erasing a positive ordering watermark. +func (r *Router) FreezeNegotiatedSessionLayerAt(authKeyID [8]byte, sessionID int64, layer int, msgID int64) (bool, error) { + if r == nil || authKeyID == ([8]byte{}) || sessionID == 0 { + return false, errors.New("invalid exact session profile identity") + } + profile, ok := tg.ResolveLayerProfile(layer) + if !ok || int(profile) != layer { + return false, fmt.Errorf("unsupported exact session profile %d", layer) + } + if msgID < 0 { + return false, fmt.Errorf("invalid exact session profile message id %d", msgID) + } + unlockCommit := r.lockAuthLayerCommit(authKeyID) + defer unlockCommit() + now := r.clock.Now() + expiresAt := exactSessionLayerEvidenceExpiry(now, msgID) + key := clientInfoSessionKey{rawAuthKeyID: authKeyID, sessionID: sessionID} + r.exactProfileMu.Lock() + defer r.exactProfileMu.Unlock() + if r.exactProfiles == nil { + r.exactProfiles = make(map[clientInfoSessionKey]exactSessionProfileEntry) + } + if current, exists := r.exactProfiles[key]; exists && now.Before(current.expiresAt) { + if msgID == 0 { + if current.layer == layer { + current.expiresAt = expiresAt + r.exactProfiles[key] = current + r.noteExactSessionProfileExpiryLocked(current.expiresAt) + return false, nil + } + current = exactSessionProfileEntry{layer: layer, expiresAt: expiresAt} + r.exactProfiles[key] = current + r.noteExactSessionProfileExpiryLocked(current.expiresAt) + return true, nil + } + if current.msgID > msgID { + return false, nil + } + if current.msgID == msgID { + if current.layer != layer { + return false, fmt.Errorf("exact session profile conflict at msg_id %d: current=%d requested=%d", msgID, current.layer, layer) + } + // Duplicate replay never extends the original selector's mutable + // window; otherwise a client could retain exact state forever. + return false, nil + } + current = exactSessionProfileEntry{layer: layer, msgID: msgID, expiresAt: expiresAt} + r.exactProfiles[key] = current + r.noteExactSessionProfileExpiryLocked(current.expiresAt) + return true, nil + } + delete(r.exactProfiles, key) + if len(r.exactProfiles) >= maxExactSessionProfileEntries { + if r.exactProfileEarliestExpiry.IsZero() || !now.Before(r.exactProfileEarliestExpiry) { + r.purgeExpiredExactSessionProfilesLocked(now) + } + if len(r.exactProfiles) >= maxExactSessionProfileEntries { + return false, &ExactSessionProfileCapacityError{Limit: maxExactSessionProfileEntries} + } + } + entry := exactSessionProfileEntry{layer: layer, msgID: msgID, expiresAt: expiresAt} + r.exactProfiles[key] = entry + if len(r.exactProfiles) == 1 { + r.exactProfileEarliestExpiry = entry.expiresAt + } else { + r.noteExactSessionProfileExpiryLocked(entry.expiresAt) + } + return true, nil +} + +func exactSessionLayerEvidenceExpiry(now time.Time, msgID int64) time.Time { + if msgID <= 0 { + return now.Add(exactSessionProfileLegacyTTL) + } + expiresAt := proto.MessageID(msgID).Time().Add(300*time.Second + time.Second) + if !now.Before(expiresAt) { + // Production freshness admission prevents this branch. Keep the force + // API/test seam short-lived instead of manufacturing a long watermark + // from an ancient or synthetic msg_id. + return now.Add(time.Second) + } + return expiresAt +} + +func (r *Router) purgeExpiredExactSessionProfilesLocked(now time.Time) { + earliest := time.Time{} + for key, entry := range r.exactProfiles { + if !now.Before(entry.expiresAt) { + delete(r.exactProfiles, key) + continue + } + if earliest.IsZero() || entry.expiresAt.Before(earliest) { + earliest = entry.expiresAt + } + } + r.exactProfileEarliestExpiry = earliest +} + +func (r *Router) noteExactSessionProfileExpiryLocked(expiry time.Time) { + if r.exactProfileEarliestExpiry.IsZero() || expiry.Before(r.exactProfileEarliestExpiry) { + r.exactProfileEarliestExpiry = expiry + } +} + +// ForgetNegotiatedSessionLayer is reserved for explicit destroy_session. +func (r *Router) ForgetNegotiatedSessionLayer(authKeyID [8]byte, sessionID int64) { + if r == nil { + return + } + r.exactProfileMu.Lock() + delete(r.exactProfiles, clientInfoSessionKey{rawAuthKeyID: authKeyID, sessionID: sessionID}) + r.exactProfileMu.Unlock() + r.clientInfoMu.Lock() + delete(r.clientInfo, clientInfoSessionKey{rawAuthKeyID: authKeyID, sessionID: sessionID}) + r.clientInfoMu.Unlock() +} + +// ForgetNegotiatedAuthKey is reserved for physical auth-key destruction. A +// business authorization logout/revoke must not call it: Layer is protocol +// metadata and survives authorization state. This is intentionally cold +// O(capacity); hot lookup and refresh stay O(1). +func (r *Router) ForgetNegotiatedAuthKey(authKeyID [8]byte) { + if r == nil || authKeyID == ([8]byte{}) { + return + } + r.exactProfileMu.Lock() + for key := range r.exactProfiles { + if key.rawAuthKeyID == authKeyID { + delete(r.exactProfiles, key) + } + } + r.exactProfileMu.Unlock() + r.clientInfoMu.Lock() + delete(r.authInfo, authKeyID) + delete(r.authLayerEvidence, authKeyID) + for key := range r.clientInfo { + if key.rawAuthKeyID == authKeyID { + delete(r.clientInfo, key) + } + } + r.clientInfoMu.Unlock() +} + +// SessionDestroyed is the explicit lifecycle callback. SessionOffline must not +// call this: a physical TCP loss is not destruction of the logical MTProto +// session. +func (r *Router) SessionDestroyed(rawAuthKeyID [8]byte, sessionID int64) { + r.ForgetNegotiatedSessionLayer(rawAuthKeyID, sessionID) +} + // ObserveInitConnection records the protocol metadata of an initConnection // whose inner request was aliased by mtprotoedge to an already-running naked // request. It deliberately performs no handler dispatch and therefore cannot @@ -889,7 +1190,10 @@ func (r *Router) ObserveInitConnection( ctx = WithAuthKeyID(ctx, effectiveAuthKeyID) ctx = WithSessionID(ctx, sessionID) ctx = WithLayer(ctx, layer) - r.rememberClientLayer(ctx, layer) + // Exact Layer/default publication belongs to generated admission and has + // already happened before a rewrap alias can reach this legacy metadata + // observer. Replaying it here would have no msg_id/admission sequence and + // could reset a newer exact profile. r.rememberClientInfo(ctx, ClientInfo{ APIID: apiID, DeviceModel: deviceModel, SystemVersion: systemVersion, AppVersion: appVersion, SystemLangCode: systemLangCode, @@ -921,9 +1225,13 @@ func (r *Router) mutateClientSessionInfo(ctx context.Context, mutate func(*clien evictMapEntryIfFullLocked(r.clientInfo, maxClientInfoEntries) } r.clientInfo[sessionKey] = sessionInfo - r.rememberAuthClientInfoLocked(rawAuthKeyID, sessionInfo) + authInfo := sessionInfo + authInfo.layer = 0 + authInfo.layerAdmissionSeq = 0 + authInfo.clientInfoAdmissionSeq = 0 + r.rememberAuthClientInfoLocked(rawAuthKeyID, authInfo) if authKeyID, ok := AuthKeyIDFrom(ctx); ok { - r.rememberAuthClientInfoLocked(authKeyID, sessionInfo) + r.rememberAuthClientInfoLocked(authKeyID, authInfo) } } @@ -995,10 +1303,15 @@ func (r *Router) clientSessionInfoStoredLocked(rawAuthKeyID [8]byte, sessionID i if !clientSessionInfoContains(r.clientInfo[clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID}], required) { return false } - if !clientSessionInfoContains(r.authInfo[rawAuthKeyID], required) { + // authInfo is deliberately auth-key-wide and can only cache the client + // description/check markers. Exact-session Layer is not a required fact in + // either auth-key fallback entry. + authRequired := required + authRequired.layer = 0 + if !clientSessionInfoContains(r.authInfo[rawAuthKeyID], authRequired) { return false } - if hasAuthKeyID && !clientSessionInfoContains(r.authInfo[authKeyID], required) { + if hasAuthKeyID && !clientSessionInfoContains(r.authInfo[authKeyID], authRequired) { return false } return true @@ -1021,6 +1334,15 @@ func clientSessionInfoContains(current, required clientSessionInfo) bool { } func (r *Router) rememberAuthClientInfoLocked(authKeyID [8]byte, info clientSessionInfo) { + if authKeyID == ([8]byte{}) { + return + } + // Wrapper ordering is a logical-session fact and must never leak into an + // auth-key-wide metadata/default entry. Ordered Layer publication uses + // rememberAuthClientLayerAtLocked directly. + info.wrapperMsgID = 0 + info.layerAdmissionSeq = 0 + info.clientInfoAdmissionSeq = 0 if r.authInfo == nil { r.authInfo = make(map[[8]byte]clientSessionInfo) } @@ -1032,7 +1354,11 @@ func (r *Router) rememberAuthClientInfoLocked(authKeyID [8]byte, info clientSess } func (r *Router) rememberAuthClientLayerLocked(authKeyID [8]byte, layer int) { - if layer <= 0 { + r.rememberAuthClientLayerAtLocked(authKeyID, layer, 0) +} + +func (r *Router) rememberAuthClientLayerAtLocked(authKeyID [8]byte, layer int, admissionSeq uint64) { + if authKeyID == ([8]byte{}) || !isSupportedLayer(layer) { return } if r.authInfo == nil { @@ -1042,22 +1368,108 @@ func (r *Router) rememberAuthClientLayerLocked(authKeyID [8]byte, layer int) { evictMapEntryIfFullLocked(r.authInfo, maxAuthInfoEntries) } info := r.authInfo[authKeyID] + if admissionSeq == 0 && info.layerObservationID > 0 { + // An unordered restoration/shadow write can never replace a durable + // observation. In particular, do not manufacture (new observation, + // old layer) by changing only the layer field. + return + } + if admissionSeq == 0 && info.layerAdmissionSeq > 0 { + // Store restoration and legacy callers carry no cross-session order and + // must not overwrite a default established by a fresh admission. + return + } + if admissionSeq > 0 && info.layerAdmissionSeq > admissionSeq { + return + } info.layer = layer + info.layerBlocked = false + info.layerBlockedByAuthKey = false + if admissionSeq > 0 { + info.layerAdmissionSeq = admissionSeq + } r.authInfo[authKeyID] = info } -// forgetClientSessionInfo 随连接下线移除该 session 的元数据缓存条目,并清掉以该 raw -// auth_key 为键的 authInfo 兜底条目,使 authInfo 收敛到活跃 raw auth key(主导的单 -// session/key 场景下严格回收)。共享同一 raw auth_key 的其它 session 若仍在线,会在下一次 -// initConnection/authorization 回填——authInfo 只是廉价的元数据兜底。temp→perm 解析后以 -// 业务 perm key 为键的条目仍靠容量上限兜底(SessionOffline 不带业务 key,无法在此精确清理)。 +func (r *Router) rememberAuthClientLayerObservationLocked(authKeyID [8]byte, layer int, observationID int64) { + if authKeyID == ([8]byte{}) || !isSupportedLayer(layer) || observationID <= 0 { + return + } + if r.authInfo == nil { + r.authInfo = make(map[[8]byte]clientSessionInfo) + } + if _, exists := r.authInfo[authKeyID]; !exists { + evictMapEntryIfFullLocked(r.authInfo, maxAuthInfoEntries) + } + info := r.authInfo[authKeyID] + if info.layerObservationID > observationID { + return + } + if info.layerObservationID == observationID && info.layerObservationID > 0 && info.layer != 0 && info.layer != layer { + return + } + info.layer = layer + info.layerObservationID = observationID + // Durable database order supersedes any process-local admission order for + // the shared default. Exact request/session ordering remains in its own + // msg_id/flight structures. + info.layerAdmissionSeq = 0 + info.layerBlocked = false + info.layerBlockedByAuthKey = false + r.authInfo[authKeyID] = info +} + +func (r *Router) authClientLayerLocked(authKeyID [8]byte) int { + return r.authInfo[authKeyID].layer +} + +// forgetClientSessionInfo removes only transport/session-local metadata. The +// auth-key default is durable protocol state and stays cached across ordinary +// disconnects; the bounded authInfo map handles eviction. func (r *Router) forgetClientSessionInfo(rawAuthKeyID [8]byte, sessionID int64) { r.clientInfoMu.Lock() - delete(r.clientInfo, clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID}) - delete(r.authInfo, rawAuthKeyID) + key := clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} + if current := r.clientInfo[key]; current.wrapperMsgID > 0 || current.layerAdmissionSeq > 0 { + // Preserve only the bounded ordering watermark across a physical + // reconnect; metadata is restored from the auth-key default/store. + r.clientInfo[key] = clientSessionInfo{ + layerAdmissionSeq: current.layerAdmissionSeq, + wrapperMsgID: current.wrapperMsgID, + } + } else { + delete(r.clientInfo, key) + } r.clientInfoMu.Unlock() } +func (r *Router) claimSessionWrapperEffects(rawAuthKeyID [8]byte, sessionID, msgID int64) bool { + if msgID <= 0 { + return true + } + if rawAuthKeyID == ([8]byte{}) || sessionID == 0 { + return false + } + key := clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} + r.clientInfoMu.Lock() + defer r.clientInfoMu.Unlock() + if r.clientInfo == nil { + r.clientInfo = make(map[clientInfoSessionKey]clientSessionInfo) + } + current, exists := r.clientInfo[key] + if current.wrapperMsgID > msgID { + return false + } + if current.wrapperMsgID == msgID { + return true + } + if !exists { + evictMapEntryIfFullLocked(r.clientInfo, maxClientInfoEntries) + } + current.wrapperMsgID = msgID + r.clientInfo[key] = current + return true +} + func evictMapEntryIfFullLocked[K comparable, V any](m map[K]V, limit int) { if len(m) < limit { return @@ -1081,16 +1493,18 @@ func (r *Router) clientSessionInfo(ctx context.Context) (clientSessionInfo, bool defer r.clientInfoMu.RUnlock() info, ok := r.clientInfo[clientInfoSessionKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID}] authKeyID, hasAuthKeyID := AuthKeyIDFrom(ctx) - if authInfo, authOK := r.authInfo[rawAuthKeyID]; authOK { - info = mergeClientSessionInfo(info, authInfo) - ok = true - } + // For a bound temporary key, the permanent/business auth key is the + // canonical shared default. The raw shadow is only a pre-bind/restart aid. if hasAuthKeyID { if authInfo, authOK := r.authInfo[authKeyID]; authOK { info = mergeClientSessionInfo(info, authInfo) ok = true } } + if authInfo, authOK := r.authInfo[rawAuthKeyID]; authOK { + info = mergeClientSessionInfo(info, authInfo) + ok = true + } if !ok { return info, false, false } @@ -1132,7 +1546,7 @@ func (r *Router) clientSessionInfoFromAuthKey(ctx context.Context, authKeyID [8] if !found { return clientSessionInfo{authKeyInfoChecked: true}, nil } - return clientSessionInfoFromAuthKeyClientInfo(info, current), nil + return clientSessionInfoFromAuthKeyClientInfo(info), nil }) if err != nil { return clientSessionInfo{}, false @@ -1145,7 +1559,13 @@ func (r *Router) clientSessionInfoFromAuthKey(ctx context.Context, authKeyID [8] } func mergeClientSessionInfo(base, fallback clientSessionInfo) clientSessionInfo { - if base.layer == 0 { + switch { + case fallback.layerObservationID > base.layerObservationID: + base.layer = fallback.layer + base.layerObservationID = fallback.layerObservationID + base.layerBlocked = fallback.layerBlocked + base.layerBlockedByAuthKey = fallback.layerBlockedByAuthKey + case fallback.layerObservationID == base.layerObservationID && base.layer == 0: base.layer = fallback.layer } if !base.hasClientInfo && fallback.hasClientInfo { @@ -1158,13 +1578,26 @@ func mergeClientSessionInfo(base, fallback clientSessionInfo) clientSessionInfo if fallback.authKeyInfoChecked { base.authKeyInfoChecked = true } + if fallback.layerBlocked && base.layer == 0 { + base.layerBlocked = true + } + if fallback.layerBlockedByAuthKey && base.layer == 0 { + base.layerBlockedByAuthKey = true + } + if base.layer != 0 { + base.layerBlocked = false + base.layerBlockedByAuthKey = false + } + if fallback.wrapperMsgID > base.wrapperMsgID { + base.wrapperMsgID = fallback.wrapperMsgID + } return base } -func clientSessionInfoFromAuthKeyClientInfo(item domain.AuthKeyClientInfo, current clientSessionInfo) clientSessionInfo { +func clientSessionInfoFromAuthKeyClientInfo(item domain.AuthKeyClientInfo) clientSessionInfo { info := clientSessionInfo{ - layer: item.Layer, authKeyInfoChecked: true, + layerObservationID: item.LayerObservationID, clientInfo: ClientInfo{ APIID: item.APIID, DeviceModel: item.DeviceModel, @@ -1173,15 +1606,22 @@ func clientSessionInfoFromAuthKeyClientInfo(item domain.AuthKeyClientInfo, curre Type: ClientType(item.Platform), }, } + if isSupportedLayer(item.Layer) { + info.layer = item.Layer + } else if item.Layer != 0 { + // A non-zero auth_keys.layer is primary even when this binary has not + // generated it. Mark the mirror checked so an older authorization.layer + // cannot silently downgrade the future value. + info.authorizationChecked = true + info.layerBlocked = true + info.layerBlockedByAuthKey = true + } info.clientInfo = restoreClientInfo(info.clientInfo) info.hasClientInfo = info.clientInfo.ClientType() != ClientTypeUnknown || info.clientInfo.DeviceModel != "" || info.clientInfo.SystemVersion != "" || info.clientInfo.AppVersion != "" || info.clientInfo.APIID != 0 - if info.layer == 0 && current.layer != 0 { - info.layer = current.layer - } return info } @@ -1212,7 +1652,7 @@ func (r *Router) clientSessionInfoFromAuthorization(ctx context.Context, userID if !found || item.UserID != userID || item.PasswordPending { return clientSessionInfo{authorizationChecked: true}, nil } - return clientSessionInfoFromAuthorizationRecord(item, current), nil + return clientSessionInfoFromAuthorizationRecord(item), nil }) if err != nil { return clientSessionInfo{}, false @@ -1220,9 +1660,8 @@ func (r *Router) clientSessionInfoFromAuthorization(ctx context.Context, userID return v.(clientSessionInfo), true } -func clientSessionInfoFromAuthorizationRecord(item domain.Authorization, current clientSessionInfo) clientSessionInfo { +func clientSessionInfoFromAuthorizationRecord(item domain.Authorization) clientSessionInfo { info := clientSessionInfo{ - layer: item.Layer, authorizationChecked: true, clientInfo: ClientInfo{ APIID: item.APIID, @@ -1232,17 +1671,16 @@ func clientSessionInfoFromAuthorizationRecord(item domain.Authorization, current Type: ClientType(item.Platform), }, } + // authorizations.layer is only a materialized device-list projection. + // Protocol inheritance is exclusively sourced from auth_keys.layer with its + // observation watermark; promoting this mirror would fabricate provenance + // when the primary is zero or has been repaired independently. info.clientInfo = restoreClientInfo(info.clientInfo) info.hasClientInfo = info.clientInfo.ClientType() != ClientTypeUnknown || info.clientInfo.DeviceModel != "" || info.clientInfo.SystemVersion != "" || info.clientInfo.AppVersion != "" || info.clientInfo.APIID != 0 - if info.layer == 0 { - if current.layer != 0 { - info.layer = current.layer - } - } return info } @@ -1263,11 +1701,6 @@ func clientSessionInfoNeedsAuthKeyInfo(info clientSessionInfo) bool { // fallback 处理未注册的 RPC:记录到 compatibility trace(落兼容矩阵), // 返回 NOT_IMPLEMENTED rpc_error 让客户端继续运行而非断连。 func (r *Router) fallback(ctx context.Context, b *bin.Buffer) (bin.Encoder, error) { - // DrKLO 12.8.1 的 theme 方法构造器比 gotd schema 新,dispatcher 匹配不上; - // 在落到「未实现」前先按 DrKLO 字段序手动解码处理。 - if enc, handled, err := r.tryLegacyThemeRPC(ctx, b); handled { - return enc, err - } id, _ := b.PeekID() fields := append([]zap.Field{ zap.String("method", tlTypeName(id)), diff --git a/internal/rpc/router_auth_cache_test.go b/internal/rpc/router_auth_cache_test.go index 3e0321fe..c8e527e7 100644 --- a/internal/rpc/router_auth_cache_test.go +++ b/internal/rpc/router_auth_cache_test.go @@ -4,11 +4,11 @@ import ( "context" "encoding/binary" - "github.com/gotd/td/bin" - "github.com/gotd/td/clock" - "github.com/gotd/td/proto" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/bin" + "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" "testing" "time" @@ -26,7 +26,7 @@ func newAuthBindingCaptureSessions() *authBindingCaptureSessions { return &authBindingCaptureSessions{captureSessions: &captureSessions{}} } -func (s *authBindingCaptureSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, _ [8]byte, _ int64, t proto.MessageType, msg bin.Encoder) (int, error) { +func (s *authBindingCaptureSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, _ [8]byte, _ int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) { s.mu.Lock() defer s.mu.Unlock() s.messageType = t diff --git a/internal/rpc/router_dispatch_test.go b/internal/rpc/router_dispatch_test.go index 5613cc71..19f5ef05 100644 --- a/internal/rpc/router_dispatch_test.go +++ b/internal/rpc/router_dispatch_test.go @@ -3,10 +3,11 @@ package rpc import ( "context" "encoding/binary" - "github.com/gotd/td/bin" - "github.com/gotd/td/clock" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "fmt" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/clock" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" "go.uber.org/zap" "go.uber.org/zap/zaptest" "go.uber.org/zap/zaptest/observer" @@ -182,7 +183,7 @@ func TestDispatchRemembersLayerAndClientTypeForSession(t *testing.T) { entries = logs.FilterMessage("RPC inner handled").All() fields = entries[len(entries)-1].ContextMap() if got := intLogField(fields["layer"]); got != layer { - t.Fatalf("new session logged layer = %d fields=%v, want %d", got, fields, layer) + t.Fatalf("new session logged layer = %d fields=%v, want inherited %d", got, fields, layer) } if got := fields["client_type"]; got != string(ClientTypeTDesktop) { t.Fatalf("new session logged client_type = %v, want %s", got, ClientTypeTDesktop) @@ -331,7 +332,7 @@ func TestSendCodeAPIIDDoesNotOverwriteStrongTWebIdentity(t *testing.T) { } } -func TestDispatchRestoresPreLoginAndroidMetadataFromAuthKey(t *testing.T) { +func TestDispatchRestoresPreLoginAndroidDescriptionWithoutLayer(t *testing.T) { core, logs := observer.New(zap.DebugLevel) authKeyID := [8]byte{0x22, 0xdb, 0xcf, 0xc8, 0x0d, 0x4c, 0x77, 0x97} auth := &captureAuthService{ @@ -365,7 +366,7 @@ func TestDispatchRestoresPreLoginAndroidMetadataFromAuthKey(t *testing.T) { } fields := entries[len(entries)-1].ContextMap() if got := intLogField(fields["layer"]); got != currentClientLayer { - t.Fatalf("logged layer = %d fields=%v, want %d", got, fields, currentClientLayer) + t.Fatalf("logged layer = %d fields=%v, want restored %d", got, fields, currentClientLayer) } if got := fields["client_type"]; got != string(ClientTypeAndroid) { t.Fatalf("logged client_type = %v, want %s", got, ClientTypeAndroid) @@ -373,8 +374,8 @@ func TestDispatchRestoresPreLoginAndroidMetadataFromAuthKey(t *testing.T) { if got := fields["app_version"]; got != "12.8.1 (69169) pbeta" { t.Fatalf("logged app_version = %v, want 12.8.1 (69169) pbeta", got) } - if got, ok := r.NegotiatedLayer(authKeyID, sessionID+1); !ok || got != currentClientLayer { - t.Fatalf("auth-key fallback layer = (%d,%v), want (%d,true)", got, ok, currentClientLayer) + if got, ok := r.NegotiatedLayer(authKeyID, sessionID); ok || got != currentClientLayer { + t.Fatalf("metadata-only negotiated layer = (%d,%v), want (%d,false)", got, ok, currentClientLayer) } } @@ -400,7 +401,7 @@ func TestAndroidLegacyCompatLogsClientMetadataWithoutInit(t *testing.T) { t.Fatalf("dispatch legacy updates.getDifference: %v", err) } - // The legacy Android constructor is upgraded by layerwire and dispatched + // The legacy Android constructor is upgraded by the gotdgen client overlay and dispatched // normally; client metadata is still applied only because IsClientDrift // positively identified a DrKLO constructor, now surfaced on the standard // "RPC inner handled" log. @@ -420,11 +421,10 @@ func TestAndroidLegacyCompatLogsClientMetadataWithoutInit(t *testing.T) { } } -// TestNegotiatedLayerStickyContract pins the (layer, ok) contract that keeps the -// edge from clobbering a live connection's layer: unknown ⇒ ok=false (edge keeps -// last-known), a recorded layer ⇒ ok=true, and a reconnect with a NEW session_id -// still inherits the layer via the stable auth_key fallback. -func TestNegotiatedLayerStickyContract(t *testing.T) { +// TestNegotiatedLayerExactSessionContract pins the protocol-only boundary: +// unknown ⇒ ok=false, invokeWithLayer evidence is sticky for the same logical +// session, and another session on the same auth key remains unknown. +func TestNegotiatedLayerExactSessionContract(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) authKey := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} const session = int64(42) @@ -434,14 +434,20 @@ func TestNegotiatedLayerStickyContract(t *testing.T) { } ctx := WithSessionID(WithRawAuthKeyID(context.Background(), authKey), session) - r.rememberClientLayer(ctx, 220) + r.rememberClientLayer(ctx, 225) - if l, ok := r.NegotiatedLayer(authKey, session); !ok || l != 220 { - t.Fatalf("recorded = (%d,%v), want (220,true)", l, ok) + if l, ok := r.NegotiatedLayer(authKey, session); !ok || l != 225 { + t.Fatalf("recorded = (%d,%v), want (225,true)", l, ok) } - // Reconnect: new session_id, same auth_key → inherits 220 (no re-invokeWithLayer). - if l, ok := r.NegotiatedLayer(authKey, 999); !ok || l != 220 { - t.Fatalf("reconnect new session = (%d,%v), want (220,true)", l, ok) + if l, ok := r.NegotiatedSessionLayer(authKey, session); !ok || l != 225 { + t.Fatalf("exact session seed = (%d,%v), want (225,true)", l, ok) + } + // A different logical session must provide its own protocol evidence. + if l, ok := r.NegotiatedLayer(authKey, 999); ok || l != currentClientLayer { + t.Fatalf("new session = (%d,%v), want (%d,false)", l, ok, currentClientLayer) + } + if l, ok := r.NegotiatedSessionLayer(authKey, 999); ok || l != 0 { + t.Fatalf("new-session exact seed = (%d,%v), want (0,false)", l, ok) } // Unrelated auth_key stays unknown. if _, ok := r.NegotiatedLayer([8]byte{9, 9}, session); ok { @@ -449,7 +455,7 @@ func TestNegotiatedLayerStickyContract(t *testing.T) { } } -func TestObservedClientLayerOverridesStaleAuthFallback(t *testing.T) { +func TestObservedClientLayerNeverLeaksAcrossAuthKeySessions(t *testing.T) { r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{}, zaptest.NewLogger(t), clock.System) rawAuthKey := [8]byte{0x68, 0x25, 0x7a, 0x01} effectiveAuthKey := [8]byte{0x8b, 0x6f, 0x26, 0x17} @@ -464,11 +470,11 @@ func TestObservedClientLayerOverridesStaleAuthFallback(t *testing.T) { if got, ok := r.NegotiatedLayer(rawAuthKey, 100); !ok || got != 225 { t.Fatalf("exact session layer = (%d,%v), want (225,true)", got, ok) } - if got, ok := r.NegotiatedLayer(rawAuthKey, 101); !ok || got != 225 { - t.Fatalf("raw auth fallback layer = (%d,%v), want (225,true)", got, ok) + if got, ok := r.NegotiatedLayer(rawAuthKey, 101); ok || got != currentClientLayer { + t.Fatalf("raw auth new-session layer = (%d,%v), want (%d,false)", got, ok, currentClientLayer) } - if got, ok := r.NegotiatedLayer(effectiveAuthKey, 101); !ok || got != 225 { - t.Fatalf("effective auth fallback layer = (%d,%v), want (225,true)", got, ok) + if got, ok := r.NegotiatedLayer(effectiveAuthKey, 101); ok || got != currentClientLayer { + t.Fatalf("effective auth metadata layer = (%d,%v), want (%d,false)", got, ok, currentClientLayer) } } @@ -499,14 +505,17 @@ func TestInvokeWithLayerPersistsClientLayerUpgrade(t *testing.T) { t.Fatalf("dispatch invokeWithLayer: %v", err) } - if auth.layerUpdates != 1 { - t.Fatalf("layer update calls = %d, want 1", auth.layerUpdates) + if got := auth.authKeyClientInfos[authKeyID].Layer; got != currentClientLayer { + t.Fatalf("persisted auth-key layer = %d, want %d", got, currentClientLayer) } - if got := auth.authorizations[0].Layer; got != currentClientLayer { - t.Fatalf("persisted layer = %d, want %d", got, currentClientLayer) + if got := auth.authorizations[0].Layer; got != 225 { + t.Fatalf("unordered authorization mirror changed to %d, want 225", got) } - if got, ok := r.NegotiatedLayer(authKeyID, 101); !ok || got != currentClientLayer { - t.Fatalf("new session negotiated layer = (%d,%v), want (%d,true)", got, ok, currentClientLayer) + if got, ok := r.NegotiatedLayer(authKeyID, 100); !ok || got != currentClientLayer { + t.Fatalf("same session negotiated layer = (%d,%v), want (%d,true)", got, ok, currentClientLayer) + } + if got, ok := r.NegotiatedLayer(authKeyID, 101); ok || got != currentClientLayer { + t.Fatalf("new session negotiated layer = (%d,%v), want (%d,false)", got, ok, currentClientLayer) } } @@ -637,8 +646,8 @@ func TestDispatchRestoresClientMetadataFromAuthorization(t *testing.T) { t.Fatalf("RPC inner handled log missing") } fields := entries[len(entries)-1].ContextMap() - if got := intLogField(fields["layer"]); got != currentClientLayer { - t.Fatalf("logged layer = %d fields=%v, want %d", got, fields, currentClientLayer) + if got := intLogField(fields["layer"]); got != 0 { + t.Fatalf("logged layer = %d fields=%v, want unknown without auth_keys evidence", got, fields) } if got := fields["client_type"]; got != string(ClientTypeAndroid) { t.Fatalf("logged client_type = %v, want %s", got, ClientTypeAndroid) @@ -659,7 +668,7 @@ func TestDispatchRestoresClientMetadataFromAuthorization(t *testing.T) { } } -func TestDispatchCopiesEffectiveAuthLayerToRawTempSession(t *testing.T) { +func TestDispatchCopiesPermanentAuthorizationMetadataWithoutLayerEvidence(t *testing.T) { rawAuthKeyID := [8]byte{0x1a, 0x2d, 0x2d, 0x3d, 0x4b, 0x38, 0x62, 0xc0} permAuthKeyID := [8]byte{0x5b, 0x1c, 0x12, 0x24, 0x98, 0x85, 0x60, 0xc1} userID := int64(1780243218) @@ -688,8 +697,8 @@ func TestDispatchCopiesEffectiveAuthLayerToRawTempSession(t *testing.T) { if _, err := r.Dispatch(context.Background(), permAuthKeyID, 11, &warm); err != nil { t.Fatalf("dispatch warm perm request: %v", err) } - if got, ok := r.NegotiatedLayer(permAuthKeyID, 12); !ok || got != 225 { - t.Fatalf("perm auth fallback layer = (%d,%v), want (225,true)", got, ok) + if got, ok := r.NegotiatedLayer(permAuthKeyID, 11); ok || got != currentClientLayer { + t.Fatalf("perm metadata layer = (%d,%v), want (%d,false)", got, ok, currentClientLayer) } var firstTempRequest bin.Buffer @@ -700,19 +709,19 @@ func TestDispatchCopiesEffectiveAuthLayerToRawTempSession(t *testing.T) { if _, err := r.Dispatch(context.Background(), rawAuthKeyID, tempSessionID, &firstTempRequest); err != nil { t.Fatalf("dispatch first temp request: %v", err) } - if got, ok := r.NegotiatedLayer(rawAuthKeyID, tempSessionID); !ok || got != 225 { - t.Fatalf("raw temp exact session layer = (%d,%v), want (225,true)", got, ok) + if got, ok := r.NegotiatedLayer(rawAuthKeyID, tempSessionID); ok || got != currentClientLayer { + t.Fatalf("raw temp metadata layer = (%d,%v), want (%d,false)", got, ok, currentClientLayer) } - if got, ok := r.NegotiatedLayer(rawAuthKeyID, tempSessionID+1); !ok || got != 225 { - t.Fatalf("raw temp auth fallback layer = (%d,%v), want (225,true)", got, ok) + if got, ok := r.NegotiatedLayer(rawAuthKeyID, tempSessionID+1); ok || got != currentClientLayer { + t.Fatalf("raw temp new-session layer = (%d,%v), want (%d,false)", got, ok, currentClientLayer) } hotCtx := WithAuthKeyID( WithSessionID(WithRawAuthKeyID(context.Background(), rawAuthKeyID), tempSessionID), permAuthKeyID, ) info, ok, stored := r.clientSessionInfo(hotCtx) - if !ok || info.layer != 225 { - t.Fatalf("cached temp session info = (%+v,%v), want layer 225", info, ok) + if !ok || info.layer != 0 || !info.hasClientInfo || info.clientInfo.ClientType() != ClientTypeAndroid { + t.Fatalf("cached temp session info = (%+v,%v), want Android metadata with unknown Layer", info, ok) } if !stored { t.Fatalf("cached temp session metadata is not fully materialized for hot path") @@ -1200,7 +1209,7 @@ func TestTDesktopStartupRPCsEncode(t *testing.T) { tests := []struct { name string - req bin.Encoder + req bin.Object }{ {name: "auth.bindTempAuthKey", req: &tg.AuthBindTempAuthKeyRequest{PermAuthKeyID: 1, Nonce: 2, ExpiresAt: 3, EncryptedMessage: []byte("binding")}}, {name: "auth.exportLoginToken", req: &tg.AuthExportLoginTokenRequest{APIID: 1, APIHash: "hash"}}, @@ -1324,17 +1333,13 @@ func TestTDesktopStartupRPCsEncode(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var in bin.Buffer - if err := tt.req.Encode(&in); err != nil { - t.Fatalf("encode request: %v", err) - } ctx := WithUserID(context.Background(), 1000000001) - enc, err := r.Dispatch(ctx, [8]byte{}, 0, &in) - if err != nil { - t.Fatalf("dispatch: %v", err) + result, method := dispatchExactLayerRPCTest(t, r, ctx, tg.LayerProfileCanonical, tt.req) + if method != tt.name { + t.Fatalf("dispatched method = %q, want %q", method, tt.name) } var out bin.Buffer - if err := enc.Encode(&out); err != nil { + if err := result.Encode(&out); err != nil { t.Fatalf("encode response: %v", err) } if out.Len() == 0 { @@ -1344,6 +1349,120 @@ func TestTDesktopStartupRPCsEncode(t *testing.T) { } } +func dispatchExactLayerRPCTest( + t *testing.T, + r *Router, + ctx context.Context, + profile tg.LayerProfile, + request bin.Object, +) (tg.LayerRPCResult, string) { + t.Helper() + body := encodeExactLayerRPC(t, profile, request) + admitted, err := r.AdmitLayer(profile, &body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatalf("admit exact Layer %d request: %v", profile, err) + } + if body.Len() != 0 { + t.Fatalf("exact Layer %d admission left %d bytes", profile, body.Len()) + } + result, method, err := r.DispatchAdmitted(ctx, [8]byte{}, 0, 0, 0, admitted) + if err != nil { + t.Fatalf("dispatch exact Layer %d request: %v", profile, err) + } + if result == nil { + t.Fatalf("dispatch exact Layer %d request returned nil result", profile) + } + return result, method +} + +func TestMessagesSearchGlobalExactLayerProfiles(t *testing.T) { + r := New(Config{}, Deps{}, zaptest.NewLogger(t), clock.System) + ctx := WithUserID(context.Background(), 1000000001) + for _, tc := range []struct { + profile tg.LayerProfile + wireID uint32 + }{ + {profile: tg.LayerProfile227, wireID: 0x4bc6589a}, + {profile: tg.LayerProfile228, wireID: 0x6126a43c}, + } { + t.Run(fmt.Sprintf("layer_%d", tc.profile), func(t *testing.T) { + request := &tg.MessagesSearchGlobalRequest{ + Q: "login", + Filter: &tg.InputMessagesFilterEmpty{}, + OffsetPeer: &tg.InputPeerEmpty{}, + Limit: 20, + } + body := encodeExactLayerRPC(t, tc.profile, request) + if got := binary.LittleEndian.Uint32(body.Raw()); got != tc.wireID { + t.Fatalf("Layer %d wire id = %#x, want %#x", tc.profile, got, tc.wireID) + } + admitted, err := r.AdmitLayer(tc.profile, &body, tg.LayerDecodeLimits{}) + if err != nil { + t.Fatalf("admit Layer %d searchGlobal: %v", tc.profile, err) + } + if body.Len() != 0 { + t.Fatalf("Layer %d admission left %d bytes", tc.profile, body.Len()) + } + call := admitted.Call() + if call.Profile() != tc.profile || call.WireID() != tc.wireID || call.Method() != tg.LayerSemanticMethodMessagesSearchGlobal { + t.Fatalf("Layer %d call = profile:%d wire:%#x semantic:%#x", tc.profile, call.Profile(), call.WireID(), call.Method()) + } + result, method, err := r.DispatchAdmitted(ctx, [8]byte{}, 0, 0, 0, admitted) + if err != nil { + t.Fatalf("dispatch Layer %d searchGlobal: %v", tc.profile, err) + } + if method != "messages.searchGlobal" || result == nil { + t.Fatalf("Layer %d result = method:%q value:%T", tc.profile, method, result) + } + bound := result.Prepared().Call() + if bound.Identity() != call.Identity() || bound.Profile() != tc.profile || bound.WireID() != tc.wireID { + t.Fatalf("Layer %d result binding = profile:%d wire:%#x identity:%#v, want request-bound %#v", tc.profile, bound.Profile(), bound.WireID(), bound.Identity(), call.Identity()) + } + var encoded bin.Buffer + if err := result.Encode(&encoded); err != nil { + t.Fatalf("encode Layer %d result: %v", tc.profile, err) + } + if encoded.Len() == 0 { + t.Fatalf("Layer %d result encoded empty", tc.profile) + } + }) + } +} + +func TestMessagesSearchGlobalCommunityProjectionFailsClosedForLayer227(t *testing.T) { + request := &tg.MessagesSearchGlobalRequest{ + Q: "scoped", + Filter: &tg.InputMessagesFilterEmpty{}, + OffsetPeer: &tg.InputPeerEmpty{}, + Limit: 20, + } + request.SetCommunity(&tg.InputChannel{ChannelID: 42, AccessHash: 84}) + + // The Layer 228 shape is valid and carries the new field. + body228 := encodeExactLayerRPC(t, tg.LayerProfile228, request) + if got := binary.LittleEndian.Uint32(body228.Raw()); got != 0x6126a43c { + t.Fatalf("Layer 228 wire id = %#x, want %#x", got, uint32(0x6126a43c)) + } + if _, err := New(Config{}, Deps{}, zaptest.NewLogger(t), clock.System).AdmitLayer(tg.LayerProfile228, &body228, tg.LayerDecodeLimits{}); err != nil { + t.Fatalf("admit Layer 228 community search: %v", err) + } + if body228.Len() != 0 { + t.Fatalf("Layer 228 community admission left %d bytes", body228.Len()) + } + + outbound227, err := tg.PrepareLayerOutboundCall(tg.LayerProfile227, request) + if err != nil { + t.Fatalf("prepare Layer 227 searchGlobal projection: %v", err) + } + var body227 bin.Buffer + if err := outbound227.Encode(&body227); err == nil { + t.Fatal("Layer 227 projection accepted a Layer 228-only community scope") + } + if body227.Len() != 0 { + t.Fatalf("failed Layer 227 projection emitted %d partial bytes", body227.Len()) + } +} + // TestHelpGetDeepLinkInfoReturnsEmpty 回归:help.getDeepLinkInfo 此前未注册 handler, // 落 fallback 返回 500 NOT_IMPLEMENTED。客户端遇到无法识别的 tg:// 深链就会发该请求 // (DrKLO LaunchActivity unsupportedUrl 分支),应返回规范的 deepLinkInfoEmpty 而非报错。 diff --git a/internal/rpc/router_layer_binder_test.go b/internal/rpc/router_layer_binder_test.go index 4f036582..b526b3dd 100644 --- a/internal/rpc/router_layer_binder_test.go +++ b/internal/rpc/router_layer_binder_test.go @@ -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" ) type layerBinderCall struct { @@ -37,10 +37,11 @@ func (s *layerCaptureSessions) layerCallsSnapshot() []layerBinderCall { return append([]layerBinderCall(nil), s.layerCalls...) } -// TestDispatchInvokeWithLayerPushesLayerToSessionBinder 验证 invokeWithLayer 在 -// Dispatch 入口把新观测的 layer 即时下推到连接层(ClientLayerBinder),且仅在 -// 首次观测或 layer 变化时下推——每条请求都带 wrapper 的客户端不会造成逐 RPC 下推。 -func TestDispatchInvokeWithLayerPushesLayerToSessionBinder(t *testing.T) { +// TestLegacyDispatchInvokeWithLayerAppliesOrderedSessionCorrection verifies the +// legacy facade follows the same explicit correction semantics as generated +// admission. A repeated selector is idempotent; a new selector updates exactly +// this session and notifies the connection once. +func TestLegacyDispatchInvokeWithLayerAppliesOrderedSessionCorrection(t *testing.T) { sessions := &layerCaptureSessions{} r := New(Config{DC: 2, IP: "127.0.0.1", Port: 2398}, Deps{Sessions: sessions}, zaptest.NewLogger(t), clock.System) rawAuthKeyID := [8]byte{1, 2, 3, 4, 5, 6, 7, 8} @@ -73,10 +74,13 @@ func TestDispatchInvokeWithLayerPushesLayerToSessionBinder(t *testing.T) { t.Fatalf("layer binder calls after repeat = %d, want 1", len(calls)) } - // layer 变化:再次下推。 + // A later explicit selector is a valid ordered correction. dispatchWithLayer(226) calls = sessions.layerCallsSnapshot() - if len(calls) != 2 || calls[1].layer != 226 { - t.Fatalf("layer binder calls after change = %+v, want second call with layer 226", calls) + if len(calls) != 2 || calls[1] != (layerBinderCall{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID, layer: 226}) { + t.Fatalf("layer binder calls after correction = %+v", calls) + } + if layer, ok := r.NegotiatedSessionLayer(rawAuthKeyID, sessionID); !ok || layer != 226 { + t.Fatalf("corrected exact session profile = (%d,%v), want (226,true)", layer, ok) } } diff --git a/internal/rpc/router_tempkey_cache_test.go b/internal/rpc/router_tempkey_cache_test.go index 0f70f8ff..e47ececa 100644 --- a/internal/rpc/router_tempkey_cache_test.go +++ b/internal/rpc/router_tempkey_cache_test.go @@ -5,9 +5,9 @@ import ( "testing" "time" - "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" ) diff --git a/internal/rpc/rpc_projection_cache.go b/internal/rpc/rpc_projection_cache.go index e1b70de2..f81a6ad5 100644 --- a/internal/rpc/rpc_projection_cache.go +++ b/internal/rpc/rpc_projection_cache.go @@ -3,7 +3,7 @@ package rpc import ( "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/rpc_testkit_auth_test.go b/internal/rpc/rpc_testkit_auth_test.go index b208c328..af6996f1 100644 --- a/internal/rpc/rpc_testkit_auth_test.go +++ b/internal/rpc/rpc_testkit_auth_test.go @@ -7,6 +7,9 @@ import ( ) type captureAuthService struct { + bindTempCalls int + bindTempLayer int + bindTempHook func(domain.TempAuthKeyBinding) error resolvedAuthKeyID [8]byte hasResolved bool resolveCount int @@ -24,7 +27,6 @@ type captureAuthService struct { authorizations []domain.Authorization authorizationLookups int authorizationLists int - layerUpdates int authKeyClientInfos map[[8]byte]domain.AuthKeyClientInfo authKeyInfoLookups int loggedOutAuthKeyID [8]byte @@ -120,10 +122,6 @@ func (s *blockingUserAuthService) Authorization(context.Context, [8]byte) (domai return domain.Authorization{}, false, nil } -func (s *blockingUserAuthService) UpdateAuthorizationLayer(context.Context, [8]byte, int) error { - return nil -} - func (s *blockingUserAuthService) AuthKeyClientInfo(context.Context, [8]byte) (domain.AuthKeyClientInfo, bool, error) { return domain.AuthKeyClientInfo{}, false, nil } @@ -152,7 +150,12 @@ func (s *blockingUserAuthService) CompletePasswordSignIn(context.Context, [8]byt return nil } -func (s *captureAuthService) BindTempAuthKey(context.Context, int64, domain.TempAuthKeyBinding) error { +func (s *captureAuthService) BindTempAuthKey(ctx context.Context, _ int64, binding domain.TempAuthKeyBinding) error { + s.bindTempCalls++ + s.bindTempLayer = LayerFrom(ctx) + if s.bindTempHook != nil { + return s.bindTempHook(binding) + } return nil } @@ -251,17 +254,6 @@ func (s *captureAuthService) Authorization(_ context.Context, authKeyID [8]byte) return domain.Authorization{}, false, nil } -func (s *captureAuthService) UpdateAuthorizationLayer(_ context.Context, authKeyID [8]byte, layer int) error { - s.layerUpdates++ - for i := range s.authorizations { - if s.authorizations[i].AuthKeyID == authKeyID { - s.authorizations[i].Layer = layer - return nil - } - } - return nil -} - func (s *captureAuthService) AuthKeyClientInfo(_ context.Context, authKeyID [8]byte) (domain.AuthKeyClientInfo, bool, error) { s.authKeyInfoLookups++ info, ok := s.authKeyClientInfos[authKeyID] @@ -292,6 +284,26 @@ func (s *captureAuthService) UpdateAuthKeyClientInfo(_ context.Context, authKeyI current.AppVersion = info.AppVersion } s.authKeyClientInfos[authKeyID] = current + for i := range s.authorizations { + if s.authorizations[i].AuthKeyID != authKeyID { + continue + } + if info.DeviceModel != "" { + s.authorizations[i].DeviceModel = info.DeviceModel + } + if info.Platform != "" { + s.authorizations[i].Platform = info.Platform + } + if info.SystemVersion != "" { + s.authorizations[i].SystemVersion = info.SystemVersion + } + if info.APIID != 0 { + s.authorizations[i].APIID = info.APIID + } + if info.AppVersion != "" { + s.authorizations[i].AppVersion = info.AppVersion + } + } return nil } diff --git a/internal/rpc/rpc_testkit_clock_test.go b/internal/rpc/rpc_testkit_clock_test.go index 39a52bc2..f5a4a7bc 100644 --- a/internal/rpc/rpc_testkit_clock_test.go +++ b/internal/rpc/rpc_testkit_clock_test.go @@ -1,7 +1,7 @@ package rpc import ( - "github.com/gotd/td/clock" + "github.com/iamxvbaba/td/clock" "time" ) diff --git a/internal/rpc/rpc_testkit_helpers_test.go b/internal/rpc/rpc_testkit_helpers_test.go index 72a47376..5592c241 100644 --- a/internal/rpc/rpc_testkit_helpers_test.go +++ b/internal/rpc/rpc_testkit_helpers_test.go @@ -4,9 +4,9 @@ import ( "context" "time" - "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" diff --git a/internal/rpc/rpc_testkit_sessions_test.go b/internal/rpc/rpc_testkit_sessions_test.go index 134d9fee..df973112 100644 --- a/internal/rpc/rpc_testkit_sessions_test.go +++ b/internal/rpc/rpc_testkit_sessions_test.go @@ -2,9 +2,11 @@ package rpc import ( "context" - "github.com/gotd/td/bin" - "github.com/gotd/td/proto" "sync" + + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/proto" + "github.com/iamxvbaba/td/tg" ) type captureSessions struct { @@ -16,6 +18,7 @@ type captureSessions struct { authKeyID [8]byte authKeyResolved bool receives bool + receivesCalls int messageType proto.MessageType message bin.Encoder userMessage bin.Encoder // 最近一次 PushToUser* 的消息(与 message 区分:message 也被 PushToSession 覆盖) @@ -34,6 +37,7 @@ type captureSessionsSnapshot struct { authKeyID [8]byte authKeyResolved bool receives bool + receivesCalls int messageType proto.MessageType message bin.Encoder } @@ -48,6 +52,7 @@ func (s *captureSessions) snapshot() captureSessionsSnapshot { authKeyID: s.authKeyID, authKeyResolved: s.authKeyResolved, receives: s.receives, + receivesCalls: s.receivesCalls, messageType: s.messageType, message: s.message, } @@ -139,9 +144,10 @@ func (s *captureSessions) SetReceivesUpdatesForAuthKey(rawAuthKeyID [8]byte, ses s.rawAuthKeyID = rawAuthKeyID s.sessionID = sessionID s.receives = receives + s.receivesCalls++ } -func (s *captureSessions) PushToSessionForAuthKey(_ context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg bin.Encoder) error { +func (s *captureSessions) PushToSessionForAuthKey(_ context.Context, rawAuthKeyID [8]byte, sessionID int64, t proto.MessageType, msg tg.UpdatesClass) error { s.mu.Lock() defer s.mu.Unlock() s.rawAuthKeyID = rawAuthKeyID @@ -151,7 +157,7 @@ func (s *captureSessions) PushToSessionForAuthKey(_ context.Context, rawAuthKeyI return nil } -func (s *captureSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg bin.Encoder) (int, error) { +func (s *captureSessions) PushToUserExceptAuthKeySession(_ context.Context, userID int64, excludeAuthKeyID [8]byte, excludeSessionID int64, t proto.MessageType, msg tg.UpdatesClass) (int, error) { s.mu.Lock() defer s.mu.Unlock() s.userID = userID diff --git a/internal/rpc/rpc_testkit_updates_test.go b/internal/rpc/rpc_testkit_updates_test.go index e3a363a8..0477236a 100644 --- a/internal/rpc/rpc_testkit_updates_test.go +++ b/internal/rpc/rpc_testkit_updates_test.go @@ -19,6 +19,11 @@ type captureUpdates struct { excludeSessionID int64 reliableDispatch bool difference *domain.UpdateDifference + observedRequest domain.UpdateState + observedCalls int + committedState domain.UpdateState + commitMode domain.UpdateStateCommitMode + commitCalls int } func (s *captureUpdates) UsesReliableDispatch() bool { @@ -45,17 +50,22 @@ func (s *captureUpdates) ConfirmedState(_ context.Context, authKeyID [8]byte, us return s.state, s.state.Pts != 0 || s.state.Date != 0, nil } -func (s *captureUpdates) AcknowledgeCurrentState(_ context.Context, authKeyID [8]byte, userID int64) (domain.UpdateState, error) { +func (s *captureUpdates) ObserveDifferenceRequest(_ context.Context, authKeyID [8]byte, userID int64, from domain.UpdateState) (domain.UpdateState, error) { s.authKeyID = authKeyID s.userID = userID - st := s.state + current := s.state if s.currentState != nil { - st = *s.currentState + current = *s.currentState } - // 模拟真实 service:确认水位推进到账号最新。 - s.state = st - s.acknowledged = true - return st, nil + if from.Pts < 0 { + from.Pts = 0 + } + if from.Pts > current.Pts { + from.Pts = current.Pts + } + s.observedRequest = from + s.observedCalls++ + return from, nil } func (s *captureUpdates) GetDifference(_ context.Context, authKeyID [8]byte, userID int64, _ domain.UpdateState) (domain.UpdateDifference, error) { @@ -67,6 +77,17 @@ func (s *captureUpdates) GetDifference(_ context.Context, authKeyID [8]byte, use return domain.UpdateDifference{State: s.state}, nil } +func (s *captureUpdates) CommitDeliveredState(_ context.Context, authKeyID [8]byte, userID int64, state domain.UpdateState, mode domain.UpdateStateCommitMode) error { + s.authKeyID = authKeyID + s.userID = userID + s.committedState = state + s.commitMode = mode + s.commitCalls++ + s.state = state + s.acknowledged = true + return nil +} + func (s *captureUpdates) ClearAuthKey(_ context.Context, authKeyID [8]byte) error { s.clearedAuthKeyID = authKeyID s.cleared = true diff --git a/internal/rpc/self_flag_emission_test.go b/internal/rpc/self_flag_emission_test.go index 4b402d86..9030db38 100644 --- a/internal/rpc/self_flag_emission_test.go +++ b/internal/rpc/self_flag_emission_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/send_media.go b/internal/rpc/send_media.go index a6837af0..19bf3090 100644 --- a/internal/rpc/send_media.go +++ b/internal/rpc/send_media.go @@ -9,7 +9,7 @@ import ( "strings" "unicode/utf8" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/send_media_geo_test.go b/internal/rpc/send_media_geo_test.go index 036e2096..4938cfce 100644 --- a/internal/rpc/send_media_geo_test.go +++ b/internal/rpc/send_media_geo_test.go @@ -5,8 +5,8 @@ import ( "context" "testing" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" ) func TestSendMediaPrivateGeoPoint(t *testing.T) { diff --git a/internal/rpc/send_media_test.go b/internal/rpc/send_media_test.go index 0e94b85a..720ecb89 100644 --- a/internal/rpc/send_media_test.go +++ b/internal/rpc/send_media_test.go @@ -7,9 +7,9 @@ import ( "strings" "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" appmessages "telesrv/internal/app/messages" @@ -538,7 +538,7 @@ func (f *fakeFiles) CreatePhotoFromBytes(_ context.Context, data []byte) (domain return f.putPhoto(photo), nil } func (f *fakeFiles) CreateAvatarFromUpload(_ context.Context, _ domain.UploadedFileRef) (domain.Photo, error) { - photo := domain.Photo{ID: 778, AccessHash: 7, DCID: 2, Sizes: []domain.PhotoSize{{Kind: domain.PhotoSizeKindDefault, Type: "a", W: 160, H: 160}, {Kind: domain.PhotoSizeKindDefault, Type: "c", W: 640, H: 640}}} + photo := domain.Photo{ID: 778, AccessHash: 7, DCID: 2, Sizes: fakeAvatarStaticSizes()} return f.putPhoto(photo), nil } func (f *fakeFiles) CreateAvatarVideoFromUpload(_ context.Context, _ domain.UploadedFileRef, videoStartTs float64) (domain.Photo, error) { @@ -558,6 +558,7 @@ func (f *fakeFiles) CreateAvatarMarkup(_ context.Context, size domain.PhotoSize) func fakeAvatarStaticSizes() []domain.PhotoSize { return []domain.PhotoSize{ + {Kind: domain.PhotoSizeKindDefault, Type: "s", W: 150, H: 150, Size: 900}, {Kind: domain.PhotoSizeKindDefault, Type: "a", W: 160, H: 160, Size: 1024}, {Kind: domain.PhotoSizeKindDefault, Type: "c", W: 640, H: 640, Size: 1024}, } diff --git a/internal/rpc/send_replay.go b/internal/rpc/send_replay.go index fc220bbe..9b68db84 100644 --- a/internal/rpc/send_replay.go +++ b/internal/rpc/send_replay.go @@ -4,7 +4,7 @@ import ( "context" "crypto/sha256" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/stats.go b/internal/rpc/stats.go index 3f8adb6c..49a094fe 100644 --- a/internal/rpc/stats.go +++ b/internal/rpc/stats.go @@ -4,7 +4,7 @@ import ( "context" "fmt" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/sticker_link_smoke_test.go b/internal/rpc/sticker_link_smoke_test.go index 4c51b172..8fa64ac8 100644 --- a/internal/rpc/sticker_link_smoke_test.go +++ b/internal/rpc/sticker_link_smoke_test.go @@ -8,9 +8,9 @@ import ( "testing" "time" - "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" appaccount "telesrv/internal/app/account" diff --git a/internal/rpc/stickers.go b/internal/rpc/stickers.go index 80a52519..d2ced196 100644 --- a/internal/rpc/stickers.go +++ b/internal/rpc/stickers.go @@ -5,7 +5,7 @@ import ( "encoding/json" "hash/fnv" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/compat/tdesktop" diff --git a/internal/rpc/stickers_creator.go b/internal/rpc/stickers_creator.go index 9a25ffb4..2530330c 100644 --- a/internal/rpc/stickers_creator.go +++ b/internal/rpc/stickers_creator.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/stickers_creator_rpc_test.go b/internal/rpc/stickers_creator_rpc_test.go index 1eb271d5..5dc5eaf6 100644 --- a/internal/rpc/stickers_creator_rpc_test.go +++ b/internal/rpc/stickers_creator_rpc_test.go @@ -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" diff --git a/internal/rpc/stickers_emoji_index.go b/internal/rpc/stickers_emoji_index.go index b58cd4d6..3daa4efe 100644 --- a/internal/rpc/stickers_emoji_index.go +++ b/internal/rpc/stickers_emoji_index.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/stickers_emoji_index_test.go b/internal/rpc/stickers_emoji_index_test.go index b10f5550..cf852fd6 100644 --- a/internal/rpc/stickers_emoji_index_test.go +++ b/internal/rpc/stickers_emoji_index_test.go @@ -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" diff --git a/internal/rpc/stickers_test.go b/internal/rpc/stickers_test.go index cd8442e2..be66a173 100644 --- a/internal/rpc/stickers_test.go +++ b/internal/rpc/stickers_test.go @@ -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" diff --git a/internal/rpc/stories.go b/internal/rpc/stories.go index 15516892..7424d515 100644 --- a/internal/rpc/stories.go +++ b/internal/rpc/stories.go @@ -10,7 +10,7 @@ import ( "strings" "unicode/utf8" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" diff --git a/internal/rpc/stories_rpc_test.go b/internal/rpc/stories_rpc_test.go index 08387ab5..63a9c658 100644 --- a/internal/rpc/stories_rpc_test.go +++ b/internal/rpc/stories_rpc_test.go @@ -8,8 +8,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" diff --git a/internal/rpc/story_peer_projection.go b/internal/rpc/story_peer_projection.go index 8f3cfab2..83a59ea6 100644 --- a/internal/rpc/story_peer_projection.go +++ b/internal/rpc/story_peer_projection.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/story_peer_projection_rpc_test.go b/internal/rpc/story_peer_projection_rpc_test.go index 5dec1e6c..f7faf087 100644 --- a/internal/rpc/story_peer_projection_rpc_test.go +++ b/internal/rpc/story_peer_projection_rpc_test.go @@ -6,8 +6,8 @@ import ( "testing" "time" - "github.com/gotd/td/bin" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/bin" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap/zaptest" appchannels "telesrv/internal/app/channels" diff --git a/internal/rpc/story_projection_cache.go b/internal/rpc/story_projection_cache.go index 2de4c6ba..4a601464 100644 --- a/internal/rpc/story_projection_cache.go +++ b/internal/rpc/story_projection_cache.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "golang.org/x/sync/singleflight" "telesrv/internal/domain" diff --git a/internal/rpc/translation_projection.go b/internal/rpc/translation_projection.go index fd30d53c..61bc0db3 100644 --- a/internal/rpc/translation_projection.go +++ b/internal/rpc/translation_projection.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/updates.go b/internal/rpc/updates.go index 90e48621..9c6f7218 100644 --- a/internal/rpc/updates.go +++ b/internal/rpc/updates.go @@ -3,7 +3,7 @@ package rpc import ( "context" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) @@ -15,38 +15,35 @@ func (r *Router) registerUpdates(d *tg.ServerDispatcher) { } // onUpdatesGetState 处理 updates.getState。TDesktop 与 DrKLO 的启动路径把它当作 -// 「从当前快照开始同步」的显式 baseline:返回账号当前连续水位并推进该设备 observed。 -// 对尚未审计 baseline 语义的客户端仍返回同一 current state,但不把尚未被客户端带回 -// 的服务端快照记成 observed;这保留 durable difference tail,避免把 TDesktop/DrKLO -// 的兼容例外扩散成所有客户端都能跨过未实际确认事件的 retention 后门。 +// 「从当前快照开始同步」的显式 baseline:返回账号当前连续水位,并且只在 rpc_result +// 物理交付后原子推进该设备 confirmed + observed。对尚未审计 baseline 语义的客户端 +// 仍返回同一 current state,但交付后只推进 confirmed;这保留 observed/durable +// difference tail,避免把 TDesktop/DrKLO 的兼容例外扩散成所有客户端都能跨过未实际 +// 确认事件的 retention 后门。 func (r *Router) onUpdatesGetState(ctx context.Context) (*tg.UpdatesState, error) { - id, _ := AuthKeyIDFrom(ctx) userID, _, err := r.currentUserID(ctx) if err != nil { return nil, internalErr() } if r.deps.Updates == nil { - r.markSessionReceivesUpdates(ctx, userID) + r.stageUpdatesBaselineAfterDelivery(ctx, userID, nil, 0, nil, false) return &tg.UpdatesState{Date: int(r.clock.Now().Unix()), Qts: r.deviceEncryptedQts(ctx)}, nil } - var st domain.UpdateState + st, err := r.deps.Updates.CurrentState(ctx, userID) + mode := domain.UpdateStateCommitDeliveredOnly if getStateEstablishesObservedBaseline(ctx) { - st, err = r.deps.Updates.AcknowledgeCurrentState(ctx, id, userID) - } else { - st, err = r.deps.Updates.CurrentState(ctx, userID) - if err == nil { - r.log.Warn("updates.getState returned current snapshot without advancing observed baseline for client without audited baseline policy", - r.contextLogFields(ctx)...) - } + mode = domain.UpdateStateCommitDeliveredAndObservedBaseline + } else if err == nil { + r.log.Warn("updates.getState returned current snapshot without advancing observed baseline for client without audited baseline policy", + r.contextLogFields(ctx)...) } if err != nil { return nil, internalErr() } - r.markSessionReceivesUpdates(ctx, userID) - r.registerBootstrapAfterBaseline(ctx, userID) // 密聊 qts 是设备级、独立于账号级 pts 引擎:注入当前设备已分配的 qts(无密聊设备为 0)。 + st.Qts = r.deviceEncryptedQts(ctx) + r.stageUpdatesBaselineAfterDelivery(ctx, userID, &st, mode, nil, true) out := tgUpdateState(st) - out.Qts = r.deviceEncryptedQts(ctx) return ptr(out), nil } @@ -67,20 +64,10 @@ func (r *Router) onUpdatesGetDifference(ctx context.Context, req *tg.UpdatesGetD } if r.deps.Updates == nil { now := int(r.clock.Now().Unix()) - r.markSessionReceivesUpdates(ctx, userID) + r.stageUpdatesBaselineAfterDelivery(ctx, userID, nil, 0, nil, false) return &tg.UpdatesDifferenceEmpty{Date: now}, nil } - // pts_total_limit 是客户端显式请求的 fast-skip:差距超限时返回 - // differenceTooLong{pts},客户端据此整体重置会话列表而不是串行翻 - // 上千页 slice。不传该参数的客户端(TDesktop)永远不会收到 tooLong。 - if limit, ok := req.GetPtsTotalLimit(); ok && limit > 0 && req.Pts > 0 { - current, err := r.deps.Updates.CurrentState(ctx, userID) - if err == nil && current.Pts-req.Pts > limit { - r.markSessionReceivesUpdates(ctx, userID) - return &tg.UpdatesDifferenceTooLong{Pts: current.Pts}, nil - } - } - st, err := r.deps.Updates.GetDifference(ctx, id, userID, domain.UpdateState{ + from, err := r.deps.Updates.ObserveDifferenceRequest(ctx, id, userID, domain.UpdateState{ Pts: req.Pts, Qts: req.Qts, Date: req.Date, @@ -88,26 +75,44 @@ func (r *Router) onUpdatesGetDifference(ctx context.Context, req *tg.UpdatesGetD if err != nil { return nil, internalErr() } - r.markSessionReceivesUpdates(ctx, userID) + // pts_total_limit 是客户端显式请求的 fast-skip:差距超限时返回 + // differenceTooLong{pts},客户端据此整体重置会话列表而不是串行翻 + // 上千页 slice。不传该参数的客户端(TDesktop)永远不会收到 tooLong。 + if limit, ok := req.GetPtsTotalLimit(); ok && limit > 0 && req.Pts > 0 { + current, err := r.deps.Updates.CurrentState(ctx, userID) + if err == nil && current.Pts-from.Pts > limit { + // differenceTooLong carries only the replacement pts. Preserve the + // request-proven qts/date instead of over-confirming fields that were + // not present on wire. + returnedCursor := from + returnedCursor.Pts = current.Pts + r.stageUpdatesBaselineAfterDelivery(ctx, userID, &returnedCursor, domain.UpdateStateCommitDeliveredOnly, nil, false) + return &tg.UpdatesDifferenceTooLong{Pts: current.Pts}, nil + } + } + st, err := r.deps.Updates.GetDifference(ctx, id, userID, from) + if err != nil { + return nil, internalErr() + } st.ChannelNudges = r.accountChannelDifferenceNudges(ctx, userID, req.Date) // 密聊设备级 qts 消息(独立于账号级 pts 事件):按当前设备 req.Qts 补回。 encMsgs, newQts := r.encryptedDifference(ctx, req.Qts) // 密聊握手/已读状态事件(无 qts):按未投递标记补回 OtherUpdates。 stateUpdates, statePeerUserIDs, stateEventIDs := r.encryptedStateUpdates(ctx, userID) if !st.Partial && len(st.Events) == 0 && len(st.ChannelNudges) == 0 && len(encMsgs) == 0 && len(stateUpdates) == 0 { - r.registerBootstrapAfterBaseline(ctx, userID) + // differenceEmpty carries no pts/qts. Both audited clients retain their + // request cursor, so only that normalized cursor is proven delivered. + emptyCursor := domain.UpdateState{Pts: from.Pts, Qts: from.Qts, Date: st.State.Date, Seq: st.State.Seq} + r.stageUpdatesBaselineAfterDelivery(ctx, userID, &emptyCursor, domain.UpdateStateCommitDeliveredOnly, nil, true) return &tg.UpdatesDifferenceEmpty{Date: st.State.Date, Seq: st.State.Seq}, nil } st.Events = r.enrichUpdateEvents(ctx, userID, st.Events) diff := r.tgUpdatesDifference(ctx, userID, st) diff = injectEncryptedMessages(diff, encMsgs, newQts) diff = r.injectEncryptedOtherUpdates(ctx, userID, diff, stateUpdates, statePeerUserIDs) - if len(stateEventIDs) > 0 { - if deviceKey, ok := businessAuthKeyIDFrom(ctx); ok { - _ = r.deps.SecretChats.MarkStateEventsDelivered(ctx, deviceKey, stateEventIDs) - } - } - r.registerBootstrapAfterBaseline(ctx, userID) + returnedCursor := st.State + returnedCursor.Qts = newQts + r.stageUpdatesBaselineAfterDelivery(ctx, userID, &returnedCursor, domain.UpdateStateCommitDeliveredOnly, stateEventIDs, true) return diff, nil } @@ -163,8 +168,9 @@ func (r *Router) accountChannelDifferenceNudges(ctx context.Context, userID int6 // maybeMarkSessionReceivesUpdates 把已登录连接发出的裸 RPC(未包 invokeWithoutUpdates) // 视为该 session 的 updates 接收声明,对齐官方语义:客户端只在主连接上发裸请求, -// media/temp 连接一律带 invokeWithoutUpdates 包装。已在接收的 session 直接短路, -// 避免每条 RPC 重复同步 channel membership。 +// media/temp 连接一律带 invokeWithoutUpdates 包装。这里只登记交付计划;membership +// sync、SetReceivesUpdates 与 pending flush 必须等成功 rpc_result 物理交付后才执行。 +// 已在接收的 session 直接短路,避免每条 RPC 重复同步 channel membership。 func (r *Router) maybeMarkSessionReceivesUpdates(ctx context.Context) { if invokeWithoutUpdatesFrom(ctx) { return @@ -180,10 +186,10 @@ func (r *Router) maybeMarkSessionReceivesUpdates(ctx context.Context) { return } } - r.markSessionReceivesUpdates(ctx, userID) + r.stageSessionUpdatesReadyAfterDelivery(ctx, userID) } -func (r *Router) markSessionReceivesUpdates(ctx context.Context, userID int64) { +func (r *Router) markSessionReceivesUpdatesNow(ctx context.Context, userID int64) { if r.deps.Sessions == nil { return } diff --git a/internal/rpc/updates_delivery.go b/internal/rpc/updates_delivery.go new file mode 100644 index 00000000..3458213a --- /dev/null +++ b/internal/rpc/updates_delivery.go @@ -0,0 +1,245 @@ +package rpc + +import ( + "context" + "time" + + "go.uber.org/zap" + + "telesrv/internal/domain" + "telesrv/internal/postresponse" +) + +const updatesDeliveryPhaseTimeout = 5 * time.Second + +type updatesDeliveryPlanKey struct{} + +// updatesDeliveryPlan collects every state transition that is justified by one +// successful RPC result. Dispatch owns the plan and registers exactly one +// post-response callback after the typed handler has succeeded. This keeps the +// baseline result ahead of pending updates on the physical MTProto stream and +// gives secret-chat delivery, session readiness and bootstrap publication one +// explicit order. +type updatesDeliveryPlan struct { + baseCtx context.Context + + commitCursor bool + cursorAuthKey [8]byte + cursorUserID int64 + cursorState domain.UpdateState + cursorMode domain.UpdateStateCommitMode + + markSecretDelivered bool + secretDeviceKey int64 + secretEventIDs []int64 + + markSessionReady bool + readyUserID int64 + + publishBootstrap bool + bootstrapUserID int64 +} + +func withUpdatesDeliveryPlan(ctx context.Context) (context.Context, *updatesDeliveryPlan) { + if ctx == nil { + ctx = context.Background() + } + plan := &updatesDeliveryPlan{baseCtx: context.WithoutCancel(ctx)} + return context.WithValue(ctx, updatesDeliveryPlanKey{}, plan), plan +} + +func updatesDeliveryPlanFrom(ctx context.Context) (*updatesDeliveryPlan, bool) { + if ctx == nil { + return nil, false + } + plan, ok := ctx.Value(updatesDeliveryPlanKey{}).(*updatesDeliveryPlan) + return plan, ok && plan != nil +} + +func (p *updatesDeliveryPlan) hasWork() bool { + return p != nil && (p.commitCursor || p.markSecretDelivered || p.markSessionReady || p.publishBootstrap) +} + +func (p *updatesDeliveryPlan) stageCursor(authKeyID [8]byte, userID int64, state domain.UpdateState, mode domain.UpdateStateCommitMode) { + if p == nil || userID == 0 { + return + } + p.commitCursor = true + p.cursorAuthKey = authKeyID + p.cursorUserID = userID + p.cursorState = state + p.cursorMode = mode +} + +func (p *updatesDeliveryPlan) stageSessionReady(userID int64) { + if p == nil { + return + } + p.markSessionReady = true + p.readyUserID = userID +} + +// suppressSessionActivation removes only effects which would make the current +// physical session eligible for proactive updates. Delivery-gated cursor and +// secret-event facts remain valid for a generated wire-invariant RPC result. +// This is used when exact admission has no authoritative profile evidence. +func (p *updatesDeliveryPlan) suppressSessionActivation() { + if p == nil { + return + } + p.markSessionReady = false + p.readyUserID = 0 + p.publishBootstrap = false + p.bootstrapUserID = 0 +} + +func (p *updatesDeliveryPlan) stageBaseline(userID, secretDeviceKey int64, secretEventIDs []int64, subscribe, bootstrap bool) { + if p == nil { + return + } + if secretDeviceKey != 0 && len(secretEventIDs) != 0 { + p.markSecretDelivered = true + p.secretDeviceKey = secretDeviceKey + p.secretEventIDs = appendUniqueInt64s(p.secretEventIDs, secretEventIDs...) + } + if !subscribe { + return + } + p.stageSessionReady(userID) + if bootstrap && userID != 0 { + p.publishBootstrap = true + p.bootstrapUserID = userID + } +} + +func appendUniqueInt64s(dst []int64, values ...int64) []int64 { + for _, value := range values { + if value == 0 { + continue + } + seen := false + for _, existing := range dst { + if existing == value { + seen = true + break + } + } + if !seen { + dst = append(dst, value) + } + } + return dst +} + +func (p *updatesDeliveryPlan) snapshot() updatesDeliveryPlan { + if p == nil { + return updatesDeliveryPlan{} + } + out := *p + out.secretEventIDs = append([]int64(nil), p.secretEventIDs...) + return out +} + +// stageSessionUpdatesReadyAfterDelivery is used by ordinary bare RPCs. During +// Router.Dispatch it only mutates the request-owned plan; direct handler tests +// with a postresponse registry still get the same delivery-gated behavior. +func (r *Router) stageSessionUpdatesReadyAfterDelivery(ctx context.Context, userID int64) { + if userID == 0 || r.deps.Sessions == nil { + return + } + if plan, ok := updatesDeliveryPlanFrom(ctx); ok { + plan.stageSessionReady(userID) + return + } + plan := updatesDeliveryPlan{baseCtx: context.WithoutCancel(ctx)} + plan.stageSessionReady(userID) + r.registerUpdatesDeliveryPlan(ctx, &plan) +} + +// stageUpdatesBaselineAfterDelivery adds the extra actions justified by a +// successful getState/getDifference result. A single plan also deduplicates the +// ordinary bare-RPC readiness declaration made by the common router path. +func (r *Router) stageUpdatesBaselineAfterDelivery( + ctx context.Context, + userID int64, + cursor *domain.UpdateState, + mode domain.UpdateStateCommitMode, + secretEventIDs []int64, + bootstrap bool, +) { + var secretDeviceKey int64 + if len(secretEventIDs) != 0 { + secretDeviceKey, _ = businessAuthKeyIDFrom(ctx) + } + subscribe := !invokeWithoutUpdatesFrom(ctx) + stage := func(plan *updatesDeliveryPlan) { + if cursor != nil && r.deps.Updates != nil { + authKeyID, _ := AuthKeyIDFrom(ctx) + plan.stageCursor(authKeyID, userID, *cursor, mode) + } + plan.stageBaseline(userID, secretDeviceKey, secretEventIDs, subscribe, bootstrap) + } + if plan, ok := updatesDeliveryPlanFrom(ctx); ok { + stage(plan) + return + } + plan := updatesDeliveryPlan{baseCtx: context.WithoutCancel(ctx)} + stage(&plan) + r.registerUpdatesDeliveryPlan(ctx, &plan) +} + +func (r *Router) registerUpdatesDeliveryPlan(ctx context.Context, plan *updatesDeliveryPlan) { + if plan == nil || !plan.hasWork() { + return + } + snapshot := plan.snapshot() + postresponse.Register(ctx, func() { + r.runUpdatesDeliveryPlan(snapshot) + }) +} + +// runUpdatesDeliveryPlan is ordered deliberately: +// 1. commit the exact account cursor carried by the delivered result; +// 2. the just-delivered difference may retire its projected secret-chat events; +// 3. membership routing is rebuilt before SetReceivesUpdates starts FIFO flush; +// 4. bootstrap jobs are published last, so they queue behind older pending updates. +// +// Each phase gets an independent timeout so one failed side effect cannot starve +// the remaining delivery-safe transitions. +func (r *Router) runUpdatesDeliveryPlan(plan updatesDeliveryPlan) { + baseCtx := plan.baseCtx + if baseCtx == nil { + baseCtx = context.Background() + } + if plan.commitCursor && r.deps.Updates != nil && plan.cursorUserID != 0 { + ctx, cancel := context.WithTimeout(baseCtx, updatesDeliveryPhaseTimeout) + err := r.deps.Updates.CommitDeliveredState(ctx, plan.cursorAuthKey, plan.cursorUserID, plan.cursorState, plan.cursorMode) + cancel() + if err != nil { + r.log.Warn("commit delivered update state after rpc_result", + zap.Int64("user_id", plan.cursorUserID), + zap.Int("pts", plan.cursorState.Pts), + zap.Uint8("mode", uint8(plan.cursorMode)), + zap.Error(err)) + } + } + if plan.markSecretDelivered && r.deps.SecretChats != nil && plan.secretDeviceKey != 0 && len(plan.secretEventIDs) != 0 { + ctx, cancel := context.WithTimeout(baseCtx, updatesDeliveryPhaseTimeout) + err := r.deps.SecretChats.MarkStateEventsDelivered(ctx, plan.secretDeviceKey, plan.secretEventIDs) + cancel() + if err != nil { + r.log.Warn("mark encrypted state events delivered after rpc_result", + zap.Int64("device_auth_key_id", plan.secretDeviceKey), + zap.Int("event_count", len(plan.secretEventIDs)), + zap.Error(err)) + } + } + if plan.markSessionReady { + ctx, cancel := context.WithTimeout(baseCtx, updatesDeliveryPhaseTimeout) + r.markSessionReceivesUpdatesNow(ctx, plan.readyUserID) + cancel() + } + if plan.publishBootstrap { + r.publishBootstrapAfterBaseline(baseCtx, plan.bootstrapUserID) + } +} diff --git a/internal/rpc/updates_rpc_test.go b/internal/rpc/updates_rpc_test.go index 2df43805..fb9e6da3 100644 --- a/internal/rpc/updates_rpc_test.go +++ b/internal/rpc/updates_rpc_test.go @@ -6,8 +6,9 @@ import ( "testing" "time" - "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" @@ -17,6 +18,17 @@ import ( "telesrv/internal/store/memory" ) +type bootstrapOrderUpdates struct { + *captureUpdates + sessions *captureSessions + publishedAfterReady bool +} + +func (s *bootstrapOrderUpdates) PublishNewMessage(ctx context.Context, userID int64, msg domain.Message) (domain.UpdateEvent, domain.UpdateState, error) { + s.publishedAfterReady = s.sessions.snapshot().receives + return s.captureUpdates.PublishNewMessage(ctx, userID, msg) +} + func TestSignUpBootstrapLoginMessagePublishesNewMessageAfterReady(t *testing.T) { bootstrap := memory.NewBootstrapUpdateJobStore() updates := &captureUpdates{state: domain.UpdateState{Pts: 3, Date: 1700000000}} @@ -109,7 +121,11 @@ func TestSignUpBootstrapPendingJobFollowsSameAuthKeyReconnect(t *testing.T) { func TestUpdatesGetStatePublishesSignUpBootstrapAfterRPCResult(t *testing.T) { bootstrap := memory.NewBootstrapUpdateJobStore() - updates := &captureUpdates{state: domain.UpdateState{Pts: 0, Date: 1700000000}} + sessions := &captureSessions{} + updates := &bootstrapOrderUpdates{ + captureUpdates: &captureUpdates{state: domain.UpdateState{Pts: 0, Date: 1700000000}}, + sessions: sessions, + } msg := domain.Message{ ID: 1, OwnerUserID: 1780243001, @@ -119,7 +135,7 @@ func TestUpdatesGetStatePublishesSignUpBootstrapAfterRPCResult(t *testing.T) { Body: "Login code: 12345", } messages := &captureMessages{list: domain.MessageList{Messages: []domain.Message{msg}}} - r := New(Config{}, Deps{BootstrapUpdates: bootstrap, Updates: updates, Messages: messages}, zaptest.NewLogger(t), clock.System) + r := New(Config{}, Deps{BootstrapUpdates: bootstrap, Updates: updates, Messages: messages, Sessions: sessions}, zaptest.NewLogger(t), clock.System) authKeyID := [8]byte{9, 8, 7} sessionID := int64(5723482677041206318) ctx := postresponse.WithCallbacks( @@ -133,10 +149,18 @@ func TestUpdatesGetStatePublishesSignUpBootstrapAfterRPCResult(t *testing.T) { ) r.enqueueLoginMessageBootstrap(ctx, msg) - state, err := r.onUpdatesGetState(ctx) + var request bin.Buffer + if err := (&tg.UpdatesGetStateRequest{}).Encode(&request); err != nil { + t.Fatalf("encode updates.getState: %v", err) + } + encoded, err := r.Dispatch(ctx, authKeyID, sessionID, &request) if err != nil { t.Fatalf("getState: %v", err) } + state, ok := encoded.(*tg.UpdatesState) + if !ok { + t.Fatalf("getState response = %T, want *tg.UpdatesState", encoded) + } if state.Pts != 0 { t.Fatalf("state pts = %d, want 0 before bootstrap publish", state.Pts) } @@ -146,6 +170,9 @@ func TestUpdatesGetStatePublishesSignUpBootstrapAfterRPCResult(t *testing.T) { if len(updates.events) != 0 { t.Fatalf("events before post-response = %d, want 0", len(updates.events)) } + if got := sessions.snapshot(); got.receives || got.receivesCalls != 0 { + t.Fatalf("session readiness before post-response = receives:%v calls:%d, want false/0", got.receives, got.receivesCalls) + } postresponse.Run(ctx) if len(updates.events) != 1 { @@ -154,6 +181,12 @@ func TestUpdatesGetStatePublishesSignUpBootstrapAfterRPCResult(t *testing.T) { if got := updates.events[0]; got.Type != domain.UpdateEventNewMessage || got.Message.ID != msg.ID { t.Fatalf("event after post-response = %+v, want login message", got) } + if !updates.publishedAfterReady { + t.Fatal("bootstrap update published before session readiness/FIFO flush barrier") + } + if got := sessions.snapshot(); !got.receives || got.receivesCalls != 1 { + t.Fatalf("merged baseline callback readiness = receives:%v calls:%d, want true/1", got.receives, got.receivesCalls) + } } func TestSignInServiceNotificationMatchesEnterpriseShape(t *testing.T) { @@ -253,7 +286,7 @@ func TestUpdatesGetStateMarksSessionReadyForPush(t *testing.T) { Updates: &captureUpdates{state: domain.UpdateState{Pts: 3, Date: 1700000000, Seq: 2}}, }, zaptest.NewLogger(t), clock.System) - ctx := WithClientInfo(WithSessionID(context.Background(), 77), ClientInfo{Type: ClientTypeTDesktop}) + ctx := postresponse.WithCallbacks(WithClientInfo(WithUserID(WithSessionID(context.Background(), 77), 1000000001), ClientInfo{Type: ClientTypeTDesktop})) got, err := r.onUpdatesGetState(ctx) if err != nil { t.Fatalf("updates.getState: %v", err) @@ -261,12 +294,94 @@ func TestUpdatesGetStateMarksSessionReadyForPush(t *testing.T) { if got.Pts != 3 || got.Seq != 2 { t.Fatalf("state = %+v, want pts=3 seq=2", got) } + if gotSession := sessions.snapshot(); gotSession.receives { + t.Fatal("session became ready before getState rpc_result delivery") + } + postresponse.Run(ctx) gotSession := sessions.snapshot() if gotSession.sessionID != 77 || !gotSession.receives { t.Fatalf("session ready = id %d receives %v, want 77/true", gotSession.sessionID, gotSession.receives) } } +func TestUpdatesGetDifferenceMarksSessionReadyOnlyAfterRPCResult(t *testing.T) { + sessions := &captureSessions{} + r := New(Config{}, Deps{ + Sessions: sessions, + Updates: &captureUpdates{state: domain.UpdateState{Pts: 7, Date: 1700000007}}, + }, zaptest.NewLogger(t), clock.System) + + ctx := postresponse.WithCallbacks( + WithSessionID( + WithAuthKeyID(WithUserID(context.Background(), 1000000001), [8]byte{7}), + 79, + ), + ) + diff, err := r.onUpdatesGetDifference(ctx, &tg.UpdatesGetDifferenceRequest{Pts: 7, Date: 1700000007}) + if err != nil { + t.Fatalf("updates.getDifference: %v", err) + } + if _, ok := diff.(*tg.UpdatesDifferenceEmpty); !ok { + t.Fatalf("difference = %T, want UpdatesDifferenceEmpty", diff) + } + if sessions.snapshot().receives { + t.Fatal("session became ready before getDifference rpc_result delivery") + } + updates := r.deps.Updates.(*captureUpdates) + if updates.observedCalls != 1 || updates.observedRequest.Pts != 7 || updates.commitCalls != 0 { + t.Fatalf("pre-delivery cursors = observed_calls:%d observed:%+v commits:%d", updates.observedCalls, updates.observedRequest, updates.commitCalls) + } + + postresponse.Run(ctx) + gotSession := sessions.snapshot() + if gotSession.sessionID != 79 || !gotSession.receives { + t.Fatalf("session ready = id %d receives %v, want 79/true", gotSession.sessionID, gotSession.receives) + } + if updates.commitCalls != 1 || updates.committedState.Pts != 7 || updates.commitMode != domain.UpdateStateCommitDeliveredOnly { + t.Fatalf("delivered difference commit = calls:%d state:%+v mode:%d", updates.commitCalls, updates.committedState, updates.commitMode) + } +} + +func TestUpdatesDifferenceTooLongObservesRequestAndCommitsReturnedCursorAfterDelivery(t *testing.T) { + updates := &captureUpdates{currentState: &domain.UpdateState{Pts: 10, Date: 1700000010}} + r := New(Config{}, Deps{Updates: updates, Sessions: &captureSessions{}}, zaptest.NewLogger(t), clock.System) + ctx := postresponse.WithCallbacks(WithAuthKeyID(WithUserID(context.Background(), 1000000001), [8]byte{10})) + req := &tg.UpdatesGetDifferenceRequest{Pts: 1, Qts: 3, Date: 1700000001} + req.SetPtsTotalLimit(2) + got, err := r.onUpdatesGetDifference(ctx, req) + if err != nil { + t.Fatalf("getDifference tooLong: %v", err) + } + tooLong, ok := got.(*tg.UpdatesDifferenceTooLong) + if !ok || tooLong.Pts != 10 { + t.Fatalf("tooLong result = %T %+v", got, got) + } + if updates.observedCalls != 1 || updates.observedRequest.Pts != 1 || updates.commitCalls != 0 { + t.Fatalf("pre-delivery cursors = observed:%+v calls:%d commits:%d", updates.observedRequest, updates.observedCalls, updates.commitCalls) + } + postresponse.Run(ctx) + if updates.commitCalls != 1 || updates.committedState.Pts != 10 || updates.committedState.Qts != req.Qts || updates.committedState.Date != req.Date || updates.commitMode != domain.UpdateStateCommitDeliveredOnly { + t.Fatalf("delivered tooLong commit = calls:%d state:%+v mode:%d", updates.commitCalls, updates.committedState, updates.commitMode) + } +} + +func TestUpdatesDifferenceEmptyCommitsRequestCursorNotInternalCandidate(t *testing.T) { + updates := &captureUpdates{state: domain.UpdateState{Pts: 100, Date: 1700000100}} + r := New(Config{}, Deps{Updates: updates, Sessions: &captureSessions{}}, zaptest.NewLogger(t), clock.System) + ctx := postresponse.WithCallbacks(WithAuthKeyID(WithUserID(context.Background(), 1000000002), [8]byte{11})) + got, err := r.onUpdatesGetDifference(ctx, &tg.UpdatesGetDifferenceRequest{Pts: 5, Qts: 6, Date: 1700000005}) + if err != nil { + t.Fatalf("getDifference empty: %v", err) + } + if _, ok := got.(*tg.UpdatesDifferenceEmpty); !ok { + t.Fatalf("difference = %T, want empty", got) + } + postresponse.Run(ctx) + if updates.committedState.Pts != 5 || updates.committedState.Qts != 6 { + t.Fatalf("empty delivered cursor = %+v, want request pts/qts 5/6 (wire has neither)", updates.committedState) + } +} + // TestUpdatesGetStateReturnsAccountCurrentState 复现 TDesktop 冷启动未读重复: // getState 必须返回账号当前最新状态(而非设备旧确认水位),且不得再推 // updatesTooLong 诱导差分——TDesktop 不持久化 pts,启动期离线数据由 @@ -284,7 +399,10 @@ func TestUpdatesGetStateReturnsAccountCurrentState(t *testing.T) { Updates: updates, }, zaptest.NewLogger(t), clock.System) - ctx := WithClientInfo(WithSessionID(context.Background(), 77), ClientInfo{Type: ClientTypeTDesktop}) + ctx := postresponse.WithCallbacks(WithClientInfo( + WithUserID(WithSessionID(context.Background(), 77), 1000000001), + ClientInfo{Type: ClientTypeTDesktop}, + )) got, err := r.onUpdatesGetState(ctx) if err != nil { t.Fatalf("updates.getState: %v", err) @@ -292,8 +410,12 @@ func TestUpdatesGetStateReturnsAccountCurrentState(t *testing.T) { if got.Pts != 4 { t.Fatalf("state pts = %d, want account current 4 (per-key stale=3 会触发客户端重放)", got.Pts) } - if !updates.acknowledged { - t.Fatal("getState 未推进设备确认水位") + if updates.acknowledged { + t.Fatal("getState 在 rpc_result 物理交付前推进了设备确认水位") + } + postresponse.Run(ctx) + if !updates.acknowledged || updates.commitMode != domain.UpdateStateCommitDeliveredAndObservedBaseline || updates.committedState.Pts != 4 { + t.Fatalf("delivered getState commit = acknowledged:%v mode:%d state:%+v", updates.acknowledged, updates.commitMode, updates.committedState) } time.Sleep(500 * time.Millisecond) if msg := sessions.snapshot().message; msg != nil { @@ -312,7 +434,8 @@ func TestUpdatesGetStateUnknownClientDoesNotAdvanceObservedBaseline(t *testing.T } r := New(Config{}, Deps{Sessions: sessions, Updates: updates}, zaptest.NewLogger(t), clock.System) - got, err := r.onUpdatesGetState(WithSessionID(context.Background(), 78)) + ctx := postresponse.WithCallbacks(WithUserID(WithSessionID(context.Background(), 78), 1000000001)) + got, err := r.onUpdatesGetState(ctx) if err != nil { t.Fatalf("updates.getState unknown client: %v", err) } @@ -322,21 +445,32 @@ func TestUpdatesGetStateUnknownClientDoesNotAdvanceObservedBaseline(t *testing.T if updates.acknowledged { t.Fatal("unknown client advanced the observed getState baseline") } + if sessions.snapshot().receives { + t.Fatal("unknown client was enabled before getState rpc_result delivery") + } + postresponse.Run(ctx) if !sessions.snapshot().receives { t.Fatal("unknown client was not enabled for subsequent updates") } + if updates.commitMode != domain.UpdateStateCommitDeliveredOnly || updates.committedState.Pts != current.Pts { + t.Fatalf("unknown client delivered commit = mode:%d state:%+v", updates.commitMode, updates.committedState) + } } func TestUpdatesGetStateDrKLOEstablishesObservedBaseline(t *testing.T) { updates := &captureUpdates{currentState: &domain.UpdateState{Pts: 6, Date: 1700000006}} r := New(Config{}, Deps{Sessions: &captureSessions{}, Updates: updates}, zaptest.NewLogger(t), clock.System) - ctx := WithClientInfo(context.Background(), ClientInfo{Type: ClientTypeAndroid, AppVersion: "12.8.1"}) + ctx := postresponse.WithCallbacks(WithClientInfo(WithUserID(context.Background(), 1000000001), ClientInfo{Type: ClientTypeAndroid, AppVersion: "12.8.1"})) if _, err := r.onUpdatesGetState(ctx); err != nil { t.Fatalf("updates.getState DrKLO: %v", err) } - if !updates.acknowledged { - t.Fatal("DrKLO getState did not establish its explicit current-snapshot baseline") + if updates.acknowledged { + t.Fatal("DrKLO getState established baseline before rpc_result delivery") + } + postresponse.Run(ctx) + if !updates.acknowledged || updates.commitMode != domain.UpdateStateCommitDeliveredAndObservedBaseline { + t.Fatalf("DrKLO delivered baseline = acknowledged:%v mode:%d", updates.acknowledged, updates.commitMode) } } diff --git a/internal/rpc/upload.go b/internal/rpc/upload.go index 4185072b..1bf0b813 100644 --- a/internal/rpc/upload.go +++ b/internal/rpc/upload.go @@ -6,7 +6,7 @@ import ( "fmt" "strings" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "go.uber.org/zap" "telesrv/internal/domain" diff --git a/internal/rpc/upload_test.go b/internal/rpc/upload_test.go index 3d3fa171..27a9aa49 100644 --- a/internal/rpc/upload_test.go +++ b/internal/rpc/upload_test.go @@ -4,8 +4,8 @@ import ( "context" "testing" - "github.com/gotd/td/tg" - "github.com/gotd/td/tgerr" + "github.com/iamxvbaba/td/tg" + "github.com/iamxvbaba/td/tgerr" ) func TestStorageFileTypePrefersMagicOverMime(t *testing.T) { @@ -73,6 +73,11 @@ func TestFileLocationKeyMapsLegacyAndroidPhotoLocations(t *testing.T) { location: &tg.InputFileLocation{VolumeID: -3999, LocalID: int('a')}, want: "photo:3999:a", }, + { + name: "plain transient response avatar", + location: &tg.InputFileLocation{VolumeID: -3999, LocalID: int('s')}, + want: "photo:3999:s", + }, { name: "plain big avatar", location: &tg.InputFileLocation{VolumeID: -3999, LocalID: int('c')}, @@ -93,6 +98,16 @@ func TestFileLocationKeyMapsLegacyAndroidPhotoLocations(t *testing.T) { location: &tg.InputPeerPhotoFileLocationLegacy{VolumeID: -4002, LocalID: int('a'), Big: true, Peer: &tg.InputPeerSelf{}}, want: "photo:4002:c", }, + { + name: "modern response transient size", + location: &tg.InputPhotoFileLocation{ID: 4003, ThumbSize: "s"}, + want: "photo:4003:s", + }, + { + name: "modern peer small remains canonical a", + location: &tg.InputPeerPhotoFileLocation{PhotoID: 4004, Peer: &tg.InputPeerSelf{}}, + want: "photo:4004:a", + }, { name: "document thumb", location: &tg.InputFileLocation{VolumeID: -1129957402753368786, LocalID: 1000 + int('m')}, diff --git a/internal/rpc/upload_webfile.go b/internal/rpc/upload_webfile.go index 2f252548..6b7f4995 100644 --- a/internal/rpc/upload_webfile.go +++ b/internal/rpc/upload_webfile.go @@ -11,7 +11,7 @@ import ( "strings" "time" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/users.go b/internal/rpc/users.go index bc710711..2df0f6da 100644 --- a/internal/rpc/users.go +++ b/internal/rpc/users.go @@ -4,7 +4,7 @@ import ( "context" "errors" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/app/users" "telesrv/internal/compat/tdesktop" diff --git a/internal/rpc/users_rpc_test.go b/internal/rpc/users_rpc_test.go index 8b54eaf8..c8cb9286 100644 --- a/internal/rpc/users_rpc_test.go +++ b/internal/rpc/users_rpc_test.go @@ -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" diff --git a/internal/rpc/wallpaper.go b/internal/rpc/wallpaper.go index 3bd999ee..250c2536 100644 --- a/internal/rpc/wallpaper.go +++ b/internal/rpc/wallpaper.go @@ -1,7 +1,7 @@ package rpc import ( - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/compat/tdesktop" "telesrv/internal/domain" diff --git a/internal/rpc/webpage_resolver_test.go b/internal/rpc/webpage_resolver_test.go index 8ccdb2ae..cea371eb 100644 --- a/internal/rpc/webpage_resolver_test.go +++ b/internal/rpc/webpage_resolver_test.go @@ -4,7 +4,7 @@ import ( "context" "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/webpage_url_extract.go b/internal/rpc/webpage_url_extract.go index 28a7a8bd..a778c89a 100644 --- a/internal/rpc/webpage_url_extract.go +++ b/internal/rpc/webpage_url_extract.go @@ -6,7 +6,7 @@ import ( "strings" "unicode/utf16" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" "telesrv/internal/domain" ) diff --git a/internal/rpc/webpage_url_extract_test.go b/internal/rpc/webpage_url_extract_test.go index e71c8b59..990d99f2 100644 --- a/internal/rpc/webpage_url_extract_test.go +++ b/internal/rpc/webpage_url_extract_test.go @@ -3,7 +3,7 @@ package rpc import ( "testing" - "github.com/gotd/td/tg" + "github.com/iamxvbaba/td/tg" ) func TestFirstPreviewableURL(t *testing.T) { diff --git a/internal/store/authkey.go b/internal/store/authkey.go index b2bcb8b6..c37ab88f 100644 --- a/internal/store/authkey.go +++ b/internal/store/authkey.go @@ -13,6 +13,11 @@ var ( // ErrAuthKeyProtocolMetadataConflict 表示同一 cryptographic auth_key_id // 被尝试改写为另一 key body 或另一 permanent/temp 类型/寿命。 ErrAuthKeyProtocolMetadataConflict = errors.New("auth key protocol metadata conflict") + // ErrAuthKeyNotFound prevents client metadata writes from silently succeeding + // after the protocol key row has already disappeared. auth_keys is the + // authoritative Layer source; an authorization mirror must never advance on + // its own when that primary write did not happen. + ErrAuthKeyNotFound = errors.New("auth key not found") // ErrAuthKeyNotPermanent 防止 authorization 落到 temporary/legacy-unknown key。 ErrAuthKeyNotPermanent = errors.New("auth key is not permanent") // ErrAuthKeyBindingInvalid 表示 temp/perm 引用缺失、类型错误,或 binding @@ -38,17 +43,25 @@ type AuthKeyData struct { // 0 只允许表示 permanent key;-1 仅表示 migration 0086 无法证明类型的历史 key, // edge 必须用 -404 拒绝并迫使客户端重握手。key 类型是握手事实,不能由 // authorization 是否存在推断。 - ExpiresAt int - Layer int - DeviceModel string - Platform string - SystemVersion string - APIID int - AppVersion string + ExpiresAt int + Layer int + // LayerObservationID globally orders durable explicit Layer observations + // across sessions, processes and restarts. Zero means legacy/no ordered + // evidence; it is still a usable inherited default but cannot outrank a + // positive observation during temp-to-perm identity merge. + LayerObservationID int64 + DeviceModel string + Platform string + SystemVersion string + APIID int + AppVersion string // 用户绑定不在此处:auth_key 是协议产物,授权(auth_key↔user + 设备信息)由 authorization 承载(P2)。 } type AuthKeyClientInfo struct { + // Layer is the durable last-known default. The RPC boundary validates it + // against the generated profile set before use; stores must preserve the + // exact value and must never clamp a future unsupported Layer. Layer int DeviceModel string Platform string @@ -57,13 +70,44 @@ type AuthKeyClientInfo struct { AppVersion string } +// MergeAuthKeyLayerObservations resolves the inherited default when a raw +// temporary key is bound to its permanent identity. Positive observation IDs +// are globally ordered durable evidence. Equal positive IDs must describe the +// same Layer; zero is legacy/unordered and therefore defers to the permanent +// identity. Both rows must be written to the returned tuple atomically. +func MergeAuthKeyLayerObservations( + tempLayer int, + tempObservationID int64, + permLayer int, + permObservationID int64, +) (layer int, observationID int64, err error) { + if tempLayer < 0 || permLayer < 0 || tempObservationID < 0 || permObservationID < 0 || + (tempObservationID > 0 && tempLayer == 0) || + (permObservationID > 0 && permLayer == 0) { + return 0, 0, ErrAuthKeySessionLayerInvalid + } + switch { + case tempObservationID > permObservationID: + return tempLayer, tempObservationID, nil + case permObservationID > tempObservationID: + return permLayer, permObservationID, nil + case tempObservationID > 0 && tempLayer != permLayer: + return 0, 0, ErrAuthKeySessionLayerConflict + case tempObservationID > 0: + return tempLayer, tempObservationID, nil + default: + return permLayer, 0, nil + } +} + // AuthKeyStore 持久化 auth key。实现见 store/memory(测试替身)、store/postgres。 type AuthKeyStore interface { // Save 保存一条 auth key 记录;同 ID 重试只能保持 key body 与协议类型/寿命不变。 Save(ctx context.Context, k AuthKeyData) error // Get 按 auth_key_id 查询;不存在时 found=false。 Get(ctx context.Context, id [8]byte) (data AuthKeyData, found bool, err error) - // UpdateClientInfo 合并更新 auth key 的客户端协商元数据。 + // UpdateClientInfo 合并更新 auth key 的客户端协商元数据。目标 key 不存在时 + // 必须返回 ErrAuthKeyNotFound,禁止把缺失 primary 当成成功后继续更新 mirror。 // 空字段不覆盖已有值,layer/api_id 为 0 时不覆盖。 UpdateClientInfo(ctx context.Context, id [8]byte, info AuthKeyClientInfo) error // Delete 删除一条 auth key 记录(destroy_auth_key)。不存在时静默成功。 diff --git a/internal/store/authkey_session_layer.go b/internal/store/authkey_session_layer.go new file mode 100644 index 00000000..77fd382f --- /dev/null +++ b/internal/store/authkey_session_layer.go @@ -0,0 +1,85 @@ +package store + +import ( + "context" + "errors" + "time" +) + +var ( + // ErrAuthKeySessionLayerInvalid rejects malformed protocol evidence before it + // can enter the durable same-session ordering boundary. + ErrAuthKeySessionLayerInvalid = errors.New("invalid auth key session layer evidence") + // ErrAuthKeySessionLayerConflict means one client msg_id selected two + // different Layers for the same raw auth key and logical MTProto session. + ErrAuthKeySessionLayerConflict = errors.New("conflicting auth key session layer evidence") +) + +// AuthKeySessionLayer is the short-lived durable high-water mark for explicit +// invokeWithLayer evidence on one logical MTProto session. It is deliberately +// keyed by the raw (wire) auth key rather than the canonical permanent key: +// two PFS temporary keys may reuse a session_id without becoming one session. +// +// ExpiresAt bounds storage and is not a protocol permission. Once this proof +// expires, a new/naked session uses the auth-key-wide last-known Layer default; +// old client msg_ids outside the MTProto freshness window remain request-local +// and cannot recreate shared state. +type AuthKeySessionLayer struct { + Layer int + MessageID int64 + ObservationID int64 + ExpiresAt time.Time + // SharedDefault is populated by AdvanceSessionLayer. It is true when this + // session observation is still the current auth-key-wide default after the + // transaction. A duplicate may safely refresh local caches only in that + // case; an older session must not overwrite a newer session's default. + SharedDefault bool +} + +// AuthKeySessionLayerStore linearizes explicit Layer evidence across server +// processes and restarts. AdvanceSessionLayer never replaces a live row with a +// lower msg_id. applied is true only for an insert, a strictly newer msg_id, or +// replacement of an expired row; duplicate/older evidence returns the current +// row with applied=false. A successful advance and the auth-key-wide default +// update share one store transaction and one globally ordered ObservationID; +// callers must not persist the default in a second best-effort write. +// AdvanceSessionLayer derives ExpiresAt from a fresh client msg_id at the store +// boundary; no caller-controlled retention duration is accepted. +type AuthKeySessionLayerStore interface { + GetSessionLayer(ctx context.Context, rawAuthKeyID [8]byte, sessionID int64) (value AuthKeySessionLayer, found bool, err error) + AdvanceSessionLayer(ctx context.Context, rawAuthKeyID [8]byte, sessionID int64, layer int, msgID int64) (current AuthKeySessionLayer, applied bool, err error) + DeleteSessionLayer(ctx context.Context, rawAuthKeyID [8]byte, sessionID int64) (deleted bool, err error) + DeleteExpiredSessionLayers(ctx context.Context, limit int) (deleted int, err error) +} + +// AuthKeySessionLayerExpiry derives the complete mutable lifetime of explicit +// Layer evidence from the client MTProto msg_id which carried it. The caller +// cannot choose a longer retention window: that would let stale selectors keep +// rewriting the auth-key-wide default after their replay-admission authority +// expired. The calculation intentionally mirrors proto.MessageID.Time without +// importing the protocol package into the store boundary. +func AuthKeySessionLayerExpiry(msgID int64) (time.Time, bool) { + if msgID <= 0 || msgID%4 != 0 || uint32(msgID) == 0 { + // MTProto client message ids are 0 modulo 4 and must carry a + // non-empty lower-32-bit fractional component. + return time.Time{}, false + } + createdAt := time.Unix(msgID>>32, int64(int32(msgID))).UTC() + return createdAt.Add(301 * time.Second), true +} + +// AuthKeySessionLayerEvidenceFresh applies the MTProto freshness envelope at +// the durable write boundary. Edge admission normally rejects stale/future +// messages first; the store repeats the invariant so an alternate caller can +// neither publish an already-expired selector nor manufacture future state. +func AuthKeySessionLayerEvidenceFresh(now time.Time, msgID int64) (time.Time, bool) { + expiresAt, ok := AuthKeySessionLayerExpiry(msgID) + if !ok || !now.Before(expiresAt) { + return time.Time{}, false + } + createdAt := expiresAt.Add(-301 * time.Second) + if createdAt.After(now.Add(30 * time.Second)) { + return time.Time{}, false + } + return expiresAt, true +} diff --git a/internal/store/authkey_test.go b/internal/store/authkey_test.go new file mode 100644 index 00000000..f94bc868 --- /dev/null +++ b/internal/store/authkey_test.go @@ -0,0 +1,72 @@ +package store + +import ( + "errors" + "testing" + "time" +) + +func TestMergeAuthKeyLayerObservations(t *testing.T) { + tests := []struct { + name string + tempLayer int + tempID int64 + permLayer int + permID int64 + wantLayer int + wantID int64 + wantErr error + }{ + {name: "temporary newer", tempLayer: 227, tempID: 20, permLayer: 220, permID: 10, wantLayer: 227, wantID: 20}, + {name: "permanent newer", tempLayer: 220, tempID: 10, permLayer: 227, permID: 20, wantLayer: 227, wantID: 20}, + {name: "equal ordered observation", tempLayer: 225, tempID: 30, permLayer: 225, permID: 30, wantLayer: 225, wantID: 30}, + {name: "equal ordered conflict", tempLayer: 220, tempID: 30, permLayer: 227, permID: 30, wantErr: ErrAuthKeySessionLayerConflict}, + {name: "legacy permanent wins", tempLayer: 220, permLayer: 227, wantLayer: 227}, + {name: "legacy permanent zero wins", tempLayer: 220, wantLayer: 0}, + {name: "negative observation", tempLayer: 220, tempID: -1, permLayer: 227, wantErr: ErrAuthKeySessionLayerInvalid}, + {name: "ordered zero layer", tempLayer: 0, tempID: 1, permLayer: 227, wantErr: ErrAuthKeySessionLayerInvalid}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotLayer, gotID, err := MergeAuthKeyLayerObservations(tt.tempLayer, tt.tempID, tt.permLayer, tt.permID) + if tt.wantErr != nil { + if !errors.Is(err, tt.wantErr) { + t.Fatalf("merge error = %v, want %v", err, tt.wantErr) + } + return + } + if err != nil || gotLayer != tt.wantLayer || gotID != tt.wantID { + t.Fatalf("merge = (%d,%d,%v), want (%d,%d,nil)", gotLayer, gotID, err, tt.wantLayer, tt.wantID) + } + }) + } +} + +func TestAuthKeySessionLayerExpiryIsOwnedByClientMessageID(t *testing.T) { + const ( + seconds = int64(2_000_000_000) + fractional = int64(123_456_788) // non-zero and client-owned (mod 4 == 0) + ) + msgID := (seconds << 32) | fractional + got, ok := AuthKeySessionLayerExpiry(msgID) + want := time.Unix(seconds, int64(int32(msgID))).UTC().Add(301 * time.Second) + if !ok || !got.Equal(want) { + t.Fatalf("expiry = (%v,%v), want (%v,true)", got, ok, want) + } + for _, invalid := range []int64{0, -4, seconds << 32, msgID + 1, msgID + 3} { + if expiry, ok := AuthKeySessionLayerExpiry(invalid); ok || !expiry.IsZero() { + t.Fatalf("invalid msg_id %d expiry = (%v,%v)", invalid, expiry, ok) + } + } + now := time.Unix(seconds, 0).UTC() + if expiry, ok := AuthKeySessionLayerEvidenceFresh(now, msgID); !ok || !expiry.Equal(want) { + t.Fatalf("fresh evidence = (%v,%v), want (%v,true)", expiry, ok, want) + } + stale := (now.Add(-302*time.Second).Unix() << 32) | 4 + tooFuture := (now.Add(31*time.Second).Unix() << 32) | 4 + for _, invalid := range []int64{stale, tooFuture} { + if expiry, ok := AuthKeySessionLayerEvidenceFresh(now, invalid); ok || !expiry.IsZero() { + t.Fatalf("out-of-window msg_id %d evidence = (%v,%v)", invalid, expiry, ok) + } + } +} diff --git a/internal/store/authorization.go b/internal/store/authorization.go index 4bf6a552..bed176a7 100644 --- a/internal/store/authorization.go +++ b/internal/store/authorization.go @@ -10,7 +10,6 @@ import ( type AuthorizationStore interface { Bind(ctx context.Context, a domain.Authorization) error ByAuthKey(ctx context.Context, authKeyID [8]byte) (domain.Authorization, bool, error) - UpdateLayer(ctx context.Context, authKeyID [8]byte, layer int) error // UpdateClientInfo 合并更新已绑定授权的客户端元数据,使设备列表与 auth key 协商事实一致。 UpdateClientInfo(ctx context.Context, authKeyID [8]byte, info domain.AuthKeyClientInfo) error ListByUser(ctx context.Context, userID int64) ([]domain.Authorization, error) @@ -20,3 +19,12 @@ type AuthorizationStore interface { // MarkPasswordPassed 清除 auth_key 的 password_pending 标记,使其转为完全授权(两步验证通过后调用)。 MarkPasswordPassed(ctx context.Context, authKeyID [8]byte) error } + +// AuthKeyAuthorityLinker is an optional in-process store-composition boundary. +// Implementations whose auth_keys primary and authorization projection live in +// separate in-memory objects can attach them here so Layer writes update both +// under one state transition. Durable stores normally enforce this inside one +// database transaction and do not implement the hook. +type AuthKeyAuthorityLinker interface { + LinkAuthKeyAuthority(AuthKeyStore) +} diff --git a/internal/store/memory/auth.go b/internal/store/memory/auth.go index edfa2e40..7a28693a 100644 --- a/internal/store/memory/auth.go +++ b/internal/store/memory/auth.go @@ -11,9 +11,12 @@ import ( ) type authKeyState struct { - mu sync.RWMutex - keys map[[8]byte]store.AuthKeyData - bindings map[[8]byte]domain.TempAuthKeyBinding + mu sync.RWMutex + keys map[[8]byte]store.AuthKeyData + bindings map[[8]byte]domain.TempAuthKeyBinding + sessionLayers map[authKeySessionLayerKey]store.AuthKeySessionLayer + authorizationMirrors map[*AuthorizationStore]struct{} + nextLayerObservation int64 } // AuthKeyStore 是 store.AuthKeyStore 的内存实现。 @@ -24,8 +27,10 @@ type AuthKeyStore struct { // NewAuthKeyStore 创建内存 AuthKeyStore。 func NewAuthKeyStore() *AuthKeyStore { return &AuthKeyStore{state: &authKeyState{ - keys: make(map[[8]byte]store.AuthKeyData), - bindings: make(map[[8]byte]domain.TempAuthKeyBinding), + keys: make(map[[8]byte]store.AuthKeyData), + bindings: make(map[[8]byte]domain.TempAuthKeyBinding), + sessionLayers: make(map[authKeySessionLayerKey]store.AuthKeySessionLayer), + authorizationMirrors: make(map[*AuthorizationStore]struct{}), }} } @@ -34,11 +39,35 @@ func (s *AuthKeyStore) Save(_ context.Context, k store.AuthKeyData) error { return store.ErrInvalidAuthKeyProtocolExpiry } s.state.mu.Lock() - if current, ok := s.state.keys[k.ID]; ok && (current.Value != k.Value || current.ExpiresAt != k.ExpiresAt) { - s.state.mu.Unlock() - return store.ErrAuthKeyProtocolMetadataConflict + if current, ok := s.state.keys[k.ID]; ok { + if current.Value != k.Value || current.ExpiresAt != k.ExpiresAt { + s.state.mu.Unlock() + return store.ErrAuthKeyProtocolMetadataConflict + } + // Save is the idempotent protocol-key upsert. Match PostgreSQL's + // ON CONFLICT behavior: a repeated handshake may refresh server_salt, + // but must never erase Layer/client metadata recorded after the first + // insert merely because the protocol write carries zero-value metadata. + if k.CreatedAt == 0 { + k.CreatedAt = current.CreatedAt + } + k.Layer = current.Layer + k.LayerObservationID = current.LayerObservationID + k.DeviceModel = current.DeviceModel + k.Platform = current.Platform + k.SystemVersion = current.SystemVersion + k.APIID = current.APIID + k.AppVersion = current.AppVersion } s.state.keys[k.ID] = k + s.state.mirrorAuthorizationLayersLocked([][8]byte{k.ID}, k.Layer) + // Tests may restore a store snapshot carrying an already-issued durable + // observation. Keep the in-memory sequence above that watermark so the next + // AdvanceSessionLayer has the same monotonic ordering as PostgreSQL's + // sequence after a restart/fixture restore. + if k.LayerObservationID > s.state.nextLayerObservation { + s.state.nextLayerObservation = k.LayerObservationID + } s.state.mu.Unlock() return nil } @@ -53,10 +82,17 @@ func (s *AuthKeyStore) Get(_ context.Context, id [8]byte) (store.AuthKeyData, bo func (s *AuthKeyStore) UpdateClientInfo(_ context.Context, id [8]byte, info store.AuthKeyClientInfo) error { s.state.mu.Lock() k, ok := s.state.keys[id] - if ok { - mergeAuthKeyClientInfo(&k, info) - s.state.keys[id] = k + if !ok { + s.state.mu.Unlock() + return store.ErrAuthKeyNotFound } + if info.Layer > 0 && k.LayerObservationID > 0 && info.Layer != k.Layer { + s.state.mu.Unlock() + return store.ErrAuthKeySessionLayerConflict + } + mergeAuthKeyClientInfo(&k, info) + s.state.keys[id] = k + s.state.mirrorAuthorizationLayersLocked([][8]byte{id}, k.Layer) s.state.mu.Unlock() return nil } @@ -82,28 +118,71 @@ func mergeAuthKeyClientInfo(k *store.AuthKeyData, info store.AuthKeyClientInfo) } } +// mirrorAuthorizationLayersLocked updates the materialized authorization view +// at the same write boundary as auth_keys. authKeyState.mu must be held; the +// only cross-object lock order is auth-key state -> authorization mirror. +func (s *authKeyState) mirrorAuthorizationLayersLocked(ids [][8]byte, layer int) { + for mirror := range s.authorizationMirrors { + mirror.mu.Lock() + for _, id := range ids { + if a, found := mirror.m[id]; found { + a.Layer = layer + mirror.m[id] = a + } + } + mirror.mu.Unlock() + } +} + +func (s *authKeyState) deleteAuthorizationMirrorsLocked(ids [][8]byte) { + s.deleteAuthorizationMirrorsWithHeldLocked(ids, nil) +} + +func (s *authKeyState) deleteAuthorizationMirrorsWithHeldLocked(ids [][8]byte, held *AuthorizationStore) { + for mirror := range s.authorizationMirrors { + if mirror != held { + mirror.mu.Lock() + } + for _, id := range ids { + delete(mirror.m, id) + } + if mirror != held { + mirror.mu.Unlock() + } + } +} + func (s *AuthKeyStore) Delete(_ context.Context, id [8]byte) error { s.state.mu.Lock() - deleting, exists := s.state.keys[id] + deleted := s.state.deleteProtocolAuthKeyLocked(id) + s.state.deleteAuthorizationMirrorsLocked(deleted) + s.state.mu.Unlock() + return nil +} + +func (s *authKeyState) deleteProtocolAuthKeyLocked(id [8]byte) [][8]byte { + deleting, exists := s.keys[id] if !exists { - s.state.mu.Unlock() return nil } + deleted := make([][8]byte, 0, 2) if deleting.ExpiresAt > 0 { - delete(s.state.bindings, id) + delete(s.bindings, id) } else { permID := int64(binary.LittleEndian.Uint64(id[:])) - for tempID, binding := range s.state.bindings { + for tempID, binding := range s.bindings { if binding.PermAuthKeyID != permID { continue } - delete(s.state.bindings, tempID) - delete(s.state.keys, tempID) + delete(s.bindings, tempID) + delete(s.keys, tempID) + s.deleteSessionLayersLocked(tempID) + deleted = append(deleted, tempID) } } - delete(s.state.keys, id) - s.state.mu.Unlock() - return nil + delete(s.keys, id) + s.deleteSessionLayersLocked(id) + return append(deleted, id) } // TempAuthKeyBindingStore 是 store.TempAuthKeyBindingStore 的内存实现。 @@ -133,7 +212,22 @@ func (s *TempAuthKeyBindingStore) Save(_ context.Context, b domain.TempAuthKeyBi if !tempFound || !permFound || temp.ExpiresAt <= 0 || perm.ExpiresAt != 0 || b.ExpiresAt != temp.ExpiresAt { return store.ErrAuthKeyBindingInvalid } + // Binding and Layer-default normalization are one state transition. Exact + // session evidence remains keyed by the raw temp key; only the inherited + // default follows the globally ordered observation. + layer, observationID, err := store.MergeAuthKeyLayerObservations( + temp.Layer, temp.LayerObservationID, + perm.Layer, perm.LayerObservationID, + ) + if err != nil { + return err + } + temp.Layer, temp.LayerObservationID = layer, observationID + perm.Layer, perm.LayerObservationID = layer, observationID + s.state.keys[b.TempAuthKeyID] = temp + s.state.keys[permID] = perm s.state.bindings[b.TempAuthKeyID] = b + s.state.mirrorAuthorizationLayersLocked([][8]byte{b.TempAuthKeyID, permID}, layer) return nil } @@ -164,6 +258,8 @@ func (s *TempAuthKeyBindingStore) DeleteExpired(_ context.Context, expiredBefore } delete(s.state.bindings, id) delete(s.state.keys, id) + s.state.deleteSessionLayersLocked(id) + s.state.deleteAuthorizationMirrorsLocked([][8]byte{id}) deleted++ } return deleted, nil @@ -171,8 +267,10 @@ func (s *TempAuthKeyBindingStore) DeleteExpired(_ context.Context, expiredBefore // AuthorizationStore 是 store.AuthorizationStore 的内存实现。 type AuthorizationStore struct { - mu sync.RWMutex - m map[[8]byte]domain.Authorization + linkMu sync.RWMutex + authKeys *authKeyState + mu sync.RWMutex + m map[[8]byte]domain.Authorization } // NewAuthorizationStore 创建内存 AuthorizationStore。 @@ -180,6 +278,42 @@ func NewAuthorizationStore() *AuthorizationStore { return &AuthorizationStore{m: make(map[[8]byte]domain.Authorization)} } +// LinkAuthKeyAuthority connects the test/dev in-memory projection to the same +// auth-key state. PostgreSQL performs the equivalent projection updates inside +// its write transactions. Existing standalone AuthorizationStore construction +// remains valid for tests that intentionally omit protocol keys. +func (s *AuthorizationStore) LinkAuthKeyAuthority(keys store.AuthKeyStore) { + authKeys, ok := keys.(*AuthKeyStore) + if !ok || authKeys == nil || authKeys.state == nil { + return + } + s.linkMu.Lock() + defer s.linkMu.Unlock() + if s.authKeys == authKeys.state { + return + } + if s.authKeys != nil { + // A projection has one authoritative primary. Constructors do not + // return errors, so preserve the first explicit composition. + return + } + authKeys.state.mu.Lock() + s.mu.Lock() + for id, a := range s.m { + if key, found := authKeys.state.keys[id]; found { + a.Layer = key.Layer + s.m[id] = a + } + } + if authKeys.state.authorizationMirrors == nil { + authKeys.state.authorizationMirrors = make(map[*AuthorizationStore]struct{}) + } + authKeys.state.authorizationMirrors[s] = struct{}{} + s.authKeys = authKeys.state + s.mu.Unlock() + authKeys.state.mu.Unlock() +} + func (s *AuthorizationStore) Bind(_ context.Context, a domain.Authorization) error { now := time.Now() if a.Hash == 0 { @@ -189,13 +323,40 @@ func (s *AuthorizationStore) Bind(_ context.Context, a domain.Authorization) err a.CreatedAt = now } a.ActiveAt = now + s.linkMu.RLock() + if s.authKeys != nil { + s.authKeys.mu.RLock() + key, found := s.authKeys.keys[a.AuthKeyID] + if !found { + s.authKeys.mu.RUnlock() + s.linkMu.RUnlock() + return store.ErrAuthKeyNotFound + } + if key.ExpiresAt != 0 { + s.authKeys.mu.RUnlock() + s.linkMu.RUnlock() + return store.ErrAuthKeyNotPermanent + } + a.Layer = key.Layer + s.mu.Lock() + s.bindLocked(a) + s.mu.Unlock() + s.authKeys.mu.RUnlock() + s.linkMu.RUnlock() + return nil + } + s.linkMu.RUnlock() s.mu.Lock() + s.bindLocked(a) + s.mu.Unlock() + return nil +} + +func (s *AuthorizationStore) bindLocked(a domain.Authorization) { if existing, ok := s.m[a.AuthKeyID]; ok && !existing.CreatedAt.IsZero() { a.CreatedAt = existing.CreatedAt } s.m[a.AuthKeyID] = a - s.mu.Unlock() - return nil } func (s *AuthorizationStore) ByAuthKey(_ context.Context, id [8]byte) (domain.Authorization, bool, error) { @@ -205,46 +366,57 @@ func (s *AuthorizationStore) ByAuthKey(_ context.Context, id [8]byte) (domain.Au return a, ok, nil } -func (s *AuthorizationStore) UpdateLayer(_ context.Context, id [8]byte, layer int) error { - if layer <= 0 { +func (s *AuthorizationStore) UpdateClientInfo(_ context.Context, id [8]byte, info domain.AuthKeyClientInfo) error { + s.linkMu.RLock() + if s.authKeys != nil { + s.authKeys.mu.RLock() + key, found := s.authKeys.keys[id] + if !found { + s.authKeys.mu.RUnlock() + s.linkMu.RUnlock() + return store.ErrAuthKeyNotFound + } + s.mu.Lock() + if a, ok := s.m[id]; ok { + mergeAuthorizationClientInfo(&a, info) + a.Layer = key.Layer + s.m[id] = a + } + s.mu.Unlock() + s.authKeys.mu.RUnlock() + s.linkMu.RUnlock() return nil } + s.linkMu.RUnlock() s.mu.Lock() if a, ok := s.m[id]; ok { - a.Layer = layer - a.ActiveAt = time.Now() + mergeAuthorizationClientInfo(&a, info) s.m[id] = a } s.mu.Unlock() return nil } -func (s *AuthorizationStore) UpdateClientInfo(_ context.Context, id [8]byte, info domain.AuthKeyClientInfo) error { - s.mu.Lock() - if a, ok := s.m[id]; ok { - if info.Layer > 0 { - a.Layer = info.Layer - } - if info.DeviceModel != "" { - a.DeviceModel = info.DeviceModel - } - if info.Platform != "" { - a.Platform = info.Platform - } - if info.SystemVersion != "" { - a.SystemVersion = info.SystemVersion - } - if info.APIID != 0 { - a.APIID = info.APIID - } - if info.AppVersion != "" { - a.AppVersion = info.AppVersion - } - a.ActiveAt = time.Now() - s.m[id] = a +func mergeAuthorizationClientInfo(a *domain.Authorization, info domain.AuthKeyClientInfo) { + if info.Layer > 0 { + a.Layer = info.Layer } - s.mu.Unlock() - return nil + if info.DeviceModel != "" { + a.DeviceModel = info.DeviceModel + } + if info.Platform != "" { + a.Platform = info.Platform + } + if info.SystemVersion != "" { + a.SystemVersion = info.SystemVersion + } + if info.APIID != 0 { + a.APIID = info.APIID + } + if info.AppVersion != "" { + a.AppVersion = info.AppVersion + } + a.ActiveAt = time.Now() } func (s *AuthorizationStore) MarkPasswordPassed(_ context.Context, id [8]byte) error { @@ -289,6 +461,39 @@ func (s *AuthorizationStore) DeleteByHash(_ context.Context, userID, hash int64) return domain.Authorization{}, false, nil } +// RevokeByHash mirrors PostgreSQL's protocol-key revocation boundary when this +// authorization projection is linked to an in-memory auth-key authority. +func (s *AuthorizationStore) RevokeByHash(ctx context.Context, userID, hash int64) (domain.Authorization, bool, error) { + s.linkMu.RLock() + defer s.linkMu.RUnlock() + if s.authKeys == nil { + return s.DeleteByHash(ctx, userID, hash) + } + s.authKeys.mu.Lock() + s.mu.Lock() + var ( + targetID [8]byte + target domain.Authorization + found bool + ) + for id, a := range s.m { + if a.UserID == userID && a.Hash == hash { + targetID, target, found = id, a, true + break + } + } + if !found { + s.mu.Unlock() + s.authKeys.mu.Unlock() + return domain.Authorization{}, false, nil + } + deletedIDs := s.authKeys.deleteProtocolAuthKeyLocked(targetID) + s.authKeys.deleteAuthorizationMirrorsWithHeldLocked(deletedIDs, s) + s.mu.Unlock() + s.authKeys.mu.Unlock() + return target, true, nil +} + func (s *AuthorizationStore) DeleteByUserExcept(_ context.Context, userID int64, keepAuthKeyID [8]byte) ([]domain.Authorization, error) { s.mu.Lock() defer s.mu.Unlock() @@ -303,6 +508,32 @@ func (s *AuthorizationStore) DeleteByUserExcept(_ context.Context, userID int64, return out, nil } +func (s *AuthorizationStore) RevokeByUserExcept(ctx context.Context, userID int64, keepAuthKeyID [8]byte) ([]domain.Authorization, error) { + s.linkMu.RLock() + defer s.linkMu.RUnlock() + if s.authKeys == nil { + return s.DeleteByUserExcept(ctx, userID, keepAuthKeyID) + } + s.authKeys.mu.Lock() + s.mu.Lock() + out := make([]domain.Authorization, 0) + targets := make([][8]byte, 0) + for id, a := range s.m { + if a.UserID == userID && id != keepAuthKeyID { + out = append(out, a) + targets = append(targets, id) + } + } + deletedIDs := make([][8]byte, 0, len(targets)) + for _, id := range targets { + deletedIDs = append(deletedIDs, s.authKeys.deleteProtocolAuthKeyLocked(id)...) + } + s.authKeys.deleteAuthorizationMirrorsWithHeldLocked(deletedIDs, s) + s.mu.Unlock() + s.authKeys.mu.Unlock() + return out, nil +} + // CodeStore 是 store.CodeStore 的内存实现(带 TTL)。 type CodeStore struct { mu sync.Mutex diff --git a/internal/store/memory/auth_test.go b/internal/store/memory/auth_test.go index 3a300e57..aa6594d6 100644 --- a/internal/store/memory/auth_test.go +++ b/internal/store/memory/auth_test.go @@ -44,6 +44,178 @@ func TestAuthKeyStorePreservesProtocolExpiry(t *testing.T) { } } +func TestAuthKeyStoreProtocolRetryPreservesClientLayerMetadata(t *testing.T) { + ctx := context.Background() + keys := NewAuthKeyStore() + id := memoryAuthKeyID(17) + key := store.AuthKeyData{ID: id, ServerSalt: 10, CreatedAt: 11} + key.Value[0] = 1 + if err := keys.Save(ctx, key); err != nil { + t.Fatalf("save auth key: %v", err) + } + if err := keys.UpdateClientInfo(ctx, id, store.AuthKeyClientInfo{ + Layer: 227, DeviceModel: "Desktop", Platform: "tdesktop", + SystemVersion: "Windows", APIID: 2040, AppVersion: "6.2", + }); err != nil { + t.Fatalf("update client info: %v", err) + } + + retry := key + retry.ServerSalt = 20 + retry.CreatedAt = 0 + if err := keys.Save(ctx, retry); err != nil { + t.Fatalf("retry protocol save: %v", err) + } + got, found, err := keys.Get(ctx, id) + if err != nil || !found { + t.Fatalf("get auth key: found=%v err=%v", found, err) + } + if got.ServerSalt != 20 || got.CreatedAt != 11 { + t.Fatalf("protocol fields = salt:%d created:%d, want 20/11", got.ServerSalt, got.CreatedAt) + } + if got.Layer != 227 || got.DeviceModel != "Desktop" || got.Platform != "tdesktop" || + got.SystemVersion != "Windows" || got.APIID != 2040 || got.AppVersion != "6.2" { + t.Fatalf("client metadata was erased by protocol retry: %+v", got) + } +} + +func TestAuthKeyStoreUpdateClientInfoRejectsMissingPrimary(t *testing.T) { + keys := NewAuthKeyStore() + err := keys.UpdateClientInfo(context.Background(), memoryAuthKeyID(18), store.AuthKeyClientInfo{Layer: 227}) + if !errors.Is(err, store.ErrAuthKeyNotFound) { + t.Fatalf("missing primary update error = %v, want %v", err, store.ErrAuthKeyNotFound) + } +} + +func TestAuthKeyStoreUpdateClientInfoProtectsObservedLayer(t *testing.T) { + ctx := context.Background() + keys := NewAuthKeyStore() + id := memoryAuthKeyID(19) + want := store.AuthKeyData{ + ID: id, Layer: 227, LayerObservationID: 91, + DeviceModel: "before", Platform: "tdesktop", + } + if err := keys.Save(ctx, want); err != nil { + t.Fatalf("save observed auth key: %v", err) + } + + err := keys.UpdateClientInfo(ctx, id, store.AuthKeyClientInfo{ + Layer: 220, DeviceModel: "must-not-merge", AppVersion: "must-not-merge", + }) + if !errors.Is(err, store.ErrAuthKeySessionLayerConflict) { + t.Fatalf("conflicting layer update error = %v, want %v", err, store.ErrAuthKeySessionLayerConflict) + } + got, found, err := keys.Get(ctx, id) + if err != nil || !found || got != want { + t.Fatalf("auth key changed after layer conflict: got=%+v found=%v err=%v, want=%+v", got, found, err, want) + } + + if err := keys.UpdateClientInfo(ctx, id, store.AuthKeyClientInfo{ + Layer: 227, DeviceModel: "same-layer", AppVersion: "1.0", + }); err != nil { + t.Fatalf("same observed layer metadata merge: %v", err) + } + if err := keys.UpdateClientInfo(ctx, id, store.AuthKeyClientInfo{ + Layer: 0, Platform: "windows", SystemVersion: "11", + }); err != nil { + t.Fatalf("layerless metadata merge: %v", err) + } + got, found, err = keys.Get(ctx, id) + if err != nil || !found { + t.Fatalf("get merged auth key: found=%v err=%v", found, err) + } + if got.Layer != 227 || got.LayerObservationID != 91 || got.DeviceModel != "same-layer" || + got.Platform != "windows" || got.SystemVersion != "11" || got.AppVersion != "1.0" { + t.Fatalf("guarded metadata merge = %+v", got) + } +} + +func TestTempAuthKeyBindingStoreMergesLayerObservations(t *testing.T) { + const handshakeExpiry = 1_800_000_000 + tests := []struct { + name string + tempLayer int + tempObs int64 + permLayer int + permObs int64 + wantLayer int + wantObs int64 + wantErr error + }{ + {name: "temporary newer", tempLayer: 227, tempObs: 20, permLayer: 220, permObs: 10, wantLayer: 227, wantObs: 20}, + {name: "permanent newer", tempLayer: 220, tempObs: 10, permLayer: 227, permObs: 20, wantLayer: 227, wantObs: 20}, + {name: "equal ordered same layer", tempLayer: 225, tempObs: 30, permLayer: 225, permObs: 30, wantLayer: 225, wantObs: 30}, + {name: "equal ordered conflict", tempLayer: 220, tempObs: 30, permLayer: 227, permObs: 30, wantErr: store.ErrAuthKeySessionLayerConflict}, + {name: "legacy permanent wins", tempLayer: 220, permLayer: 227, wantLayer: 227}, + } + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + keys := NewAuthKeyStore() + bindings := NewTempAuthKeyBindingStore(keys) + tempID := memoryAuthKeyID(int64(1_000 + i*2)) + permID := memoryAuthKeyID(int64(1_001 + i*2)) + tempBefore := store.AuthKeyData{ + ID: tempID, ExpiresAt: handshakeExpiry, + Layer: tt.tempLayer, LayerObservationID: tt.tempObs, DeviceModel: "temp", + } + permBefore := store.AuthKeyData{ + ID: permID, Layer: tt.permLayer, LayerObservationID: tt.permObs, DeviceModel: "perm", + } + if err := keys.Save(ctx, tempBefore); err != nil { + t.Fatalf("save temporary auth key: %v", err) + } + if err := keys.Save(ctx, permBefore); err != nil { + t.Fatalf("save permanent auth key: %v", err) + } + binding := domain.TempAuthKeyBinding{ + TempAuthKeyID: tempID, + PermAuthKeyID: int64(binary.LittleEndian.Uint64(permID[:])), + ExpiresAt: handshakeExpiry, + } + err := bindings.Save(ctx, binding) + if tt.wantErr != nil { + if !errors.Is(err, tt.wantErr) { + t.Fatalf("bind error = %v, want %v", err, tt.wantErr) + } + tempAfter, _, _ := keys.Get(ctx, tempID) + permAfter, _, _ := keys.Get(ctx, permID) + if tempAfter != tempBefore || permAfter != permBefore { + t.Fatalf("conflicting bind changed keys: temp=%+v perm=%+v", tempAfter, permAfter) + } + if _, found, getErr := bindings.GetByTemp(ctx, tempID); getErr != nil || found { + t.Fatalf("conflicting binding found=%v err=%v, want absent", found, getErr) + } + return + } + if err != nil { + t.Fatalf("bind: %v", err) + } + tempAfter, tempFound, getErr := keys.Get(ctx, tempID) + if getErr != nil || !tempFound { + t.Fatalf("get temporary after bind: found=%v err=%v", tempFound, getErr) + } + permAfter, permFound, getErr := keys.Get(ctx, permID) + if getErr != nil || !permFound { + t.Fatalf("get permanent after bind: found=%v err=%v", permFound, getErr) + } + if tempAfter.Layer != tt.wantLayer || tempAfter.LayerObservationID != tt.wantObs || + permAfter.Layer != tt.wantLayer || permAfter.LayerObservationID != tt.wantObs { + t.Fatalf("merged defaults: temp=(%d,%d) perm=(%d,%d), want=(%d,%d)", + tempAfter.Layer, tempAfter.LayerObservationID, + permAfter.Layer, permAfter.LayerObservationID, + tt.wantLayer, tt.wantObs) + } + if tempAfter.DeviceModel != "temp" || permAfter.DeviceModel != "perm" { + t.Fatalf("bind erased client metadata: temp=%+v perm=%+v", tempAfter, permAfter) + } + if _, found, getErr := bindings.GetByTemp(ctx, tempID); getErr != nil || !found { + t.Fatalf("merged binding found=%v err=%v, want present", found, getErr) + } + }) + } +} + func TestTempAuthKeyBindingStoreIsIdempotentAndRejectsCrossPermanentRebind(t *testing.T) { ctx := context.Background() keys := NewAuthKeyStore() diff --git a/internal/store/memory/authkey_session_layer.go b/internal/store/memory/authkey_session_layer.go new file mode 100644 index 00000000..a4594855 --- /dev/null +++ b/internal/store/memory/authkey_session_layer.go @@ -0,0 +1,163 @@ +package memory + +import ( + "context" + "encoding/binary" + "math" + "time" + + "telesrv/internal/store" +) + +type authKeySessionLayerKey struct { + rawAuthKeyID [8]byte + sessionID int64 +} + +func (s *AuthKeyStore) GetSessionLayer( + _ context.Context, + rawAuthKeyID [8]byte, + sessionID int64, +) (store.AuthKeySessionLayer, bool, error) { + now := time.Now() + key := authKeySessionLayerKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} + s.state.mu.Lock() + value, found := s.state.sessionLayers[key] + if found && !now.Before(value.ExpiresAt) { + delete(s.state.sessionLayers, key) + found = false + value = store.AuthKeySessionLayer{} + } else if found { + value.SharedDefault = s.state.sessionLayerIsSharedDefaultLocked(rawAuthKeyID, value) + } + s.state.mu.Unlock() + return value, found, nil +} + +func (s *AuthKeyStore) AdvanceSessionLayer( + _ context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + layer int, + msgID int64, +) (store.AuthKeySessionLayer, bool, error) { + now := time.Now() + expiresAt, freshEvidence := store.AuthKeySessionLayerEvidenceFresh(now, msgID) + if layer <= 0 || !freshEvidence { + return store.AuthKeySessionLayer{}, false, store.ErrAuthKeySessionLayerInvalid + } + key := authKeySessionLayerKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} + s.state.mu.Lock() + defer s.state.mu.Unlock() + if _, found := s.state.keys[rawAuthKeyID]; !found { + return store.AuthKeySessionLayer{}, false, store.ErrAuthKeyNotFound + } + current, found := s.state.sessionLayers[key] + if found && now.Before(current.ExpiresAt) { + switch { + case msgID < current.MessageID: + current.SharedDefault = s.state.sessionLayerIsSharedDefaultLocked(rawAuthKeyID, current) + return current, false, nil + case msgID == current.MessageID: + if layer != current.Layer { + return current, false, store.ErrAuthKeySessionLayerConflict + } + current.SharedDefault = s.state.sessionLayerIsSharedDefaultLocked(rawAuthKeyID, current) + return current, false, nil + } + } + var ( + permID [8]byte + perm store.AuthKeyData + bound bool + ) + if binding, ok := s.state.bindings[rawAuthKeyID]; ok { + bound = true + binary.LittleEndian.PutUint64(permID[:], uint64(binding.PermAuthKeyID)) + var permFound bool + perm, permFound = s.state.keys[permID] + if !permFound { + return store.AuthKeySessionLayer{}, false, store.ErrAuthKeyBindingInvalid + } + } + if s.state.nextLayerObservation == math.MaxInt64 { + return store.AuthKeySessionLayer{}, false, store.ErrAuthKeySessionLayerInvalid + } + s.state.nextLayerObservation++ + current = store.AuthKeySessionLayer{ + Layer: layer, + MessageID: msgID, + ObservationID: s.state.nextLayerObservation, + ExpiresAt: expiresAt, + } + stored := current + stored.SharedDefault = false + s.state.sessionLayers[key] = stored + raw := s.state.keys[rawAuthKeyID] + raw.Layer = layer + raw.LayerObservationID = current.ObservationID + s.state.keys[rawAuthKeyID] = raw + if bound { + perm.Layer = layer + perm.LayerObservationID = current.ObservationID + s.state.keys[permID] = perm + s.state.mirrorAuthorizationLayersLocked([][8]byte{rawAuthKeyID, permID}, layer) + } else { + s.state.mirrorAuthorizationLayersLocked([][8]byte{rawAuthKeyID}, layer) + } + current.SharedDefault = true + return current, true, nil +} + +func (s *AuthKeyStore) DeleteSessionLayer( + _ context.Context, + rawAuthKeyID [8]byte, + sessionID int64, +) (bool, error) { + key := authKeySessionLayerKey{rawAuthKeyID: rawAuthKeyID, sessionID: sessionID} + s.state.mu.Lock() + _, deleted := s.state.sessionLayers[key] + delete(s.state.sessionLayers, key) + s.state.mu.Unlock() + return deleted, nil +} + +func (s *AuthKeyStore) DeleteExpiredSessionLayers(_ context.Context, limit int) (int, error) { + if limit <= 0 { + return 0, nil + } + now := time.Now() + s.state.mu.Lock() + deleted := 0 + for key, value := range s.state.sessionLayers { + if deleted >= limit { + break + } + if now.Before(value.ExpiresAt) { + continue + } + delete(s.state.sessionLayers, key) + deleted++ + } + s.state.mu.Unlock() + return deleted, nil +} + +func (s *authKeyState) deleteSessionLayersLocked(rawAuthKeyID [8]byte) { + for key := range s.sessionLayers { + if key.rawAuthKeyID == rawAuthKeyID { + delete(s.sessionLayers, key) + } + } +} + +func (s *authKeyState) sessionLayerIsSharedDefaultLocked(rawAuthKeyID [8]byte, value store.AuthKeySessionLayer) bool { + defaultKeyID := rawAuthKeyID + if binding, ok := s.bindings[rawAuthKeyID]; ok { + binary.LittleEndian.PutUint64(defaultKeyID[:], uint64(binding.PermAuthKeyID)) + } + key, found := s.keys[defaultKeyID] + return found && + key.Layer == value.Layer && + key.LayerObservationID == value.ObservationID +} diff --git a/internal/store/memory/authkey_session_layer_test.go b/internal/store/memory/authkey_session_layer_test.go new file mode 100644 index 00000000..74195bf1 --- /dev/null +++ b/internal/store/memory/authkey_session_layer_test.go @@ -0,0 +1,235 @@ +package memory + +import ( + "context" + "encoding/binary" + "errors" + "testing" + "time" + + "telesrv/internal/domain" + "telesrv/internal/store" +) + +func TestAuthKeySessionLayerOrdersRestartEvidenceAndBindingDefaults(t *testing.T) { + ctx := context.Background() + keys := NewAuthKeyStore() + bindings := NewTempAuthKeyBindingStore(keys) + temp := [8]byte{1} + perm := [8]byte{2} + const tempExpiry = 2_000_000_000 + if err := keys.Save(ctx, store.AuthKeyData{ID: temp, ExpiresAt: tempExpiry}); err != nil { + t.Fatal(err) + } + if err := keys.Save(ctx, store.AuthKeyData{ID: perm, ExpiresAt: 0}); err != nil { + t.Fatal(err) + } + now := time.Now().UTC() + firstMsgID := authKeySessionLayerTestMsgID(now, 1) + newerMsgID := authKeySessionLayerTestMsgID(now, 2) + otherMsgID := authKeySessionLayerTestMsgID(now, 3) + + first, applied, err := keys.AdvanceSessionLayer(ctx, temp, 10, 220, firstMsgID) + if err != nil || !applied || !first.SharedDefault || first.ObservationID <= 0 { + t.Fatalf("first advance = (%+v,%v,%v)", first, applied, err) + } + var permInt [8]byte + copy(permInt[:], perm[:]) + if err := bindings.Save(ctx, domain.TempAuthKeyBinding{ + TempAuthKeyID: temp, + PermAuthKeyID: int64(binary.LittleEndian.Uint64(permInt[:])), + ExpiresAt: tempExpiry, + }); err != nil { + t.Fatal(err) + } + for _, id := range [][8]byte{temp, perm} { + got, found, err := keys.Get(ctx, id) + if err != nil || !found || got.Layer != 220 || got.LayerObservationID != first.ObservationID { + t.Fatalf("bound default %x = (%+v,%v,%v)", id, got, found, err) + } + } + + newer, applied, err := keys.AdvanceSessionLayer(ctx, temp, 10, 227, newerMsgID) + if err != nil || !applied || !newer.SharedDefault || newer.ObservationID <= first.ObservationID { + t.Fatalf("newer advance = (%+v,%v,%v)", newer, applied, err) + } + older, applied, err := keys.AdvanceSessionLayer(ctx, temp, 10, 220, firstMsgID) + if err != nil || applied || older.Layer != 227 || older.MessageID != newerMsgID || !older.SharedDefault { + t.Fatalf("older replay = (%+v,%v,%v)", older, applied, err) + } + if _, _, err := keys.AdvanceSessionLayer(ctx, temp, 10, 220, newerMsgID); !errors.Is(err, store.ErrAuthKeySessionLayerConflict) { + t.Fatalf("same-msg conflict = %v", err) + } + + other, applied, err := keys.AdvanceSessionLayer(ctx, temp, 11, 225, otherMsgID) + if err != nil || !applied || !other.SharedDefault || other.ObservationID <= newer.ObservationID { + t.Fatalf("other-session advance = (%+v,%v,%v)", other, applied, err) + } + oldSession, found, err := keys.GetSessionLayer(ctx, temp, 10) + if err != nil || !found || oldSession.Layer != 227 || oldSession.SharedDefault { + t.Fatalf("old exact session after other default = (%+v,%v,%v)", oldSession, found, err) + } + for _, id := range [][8]byte{temp, perm} { + got, _, _ := keys.Get(ctx, id) + if got.Layer != 225 || got.LayerObservationID != other.ObservationID { + t.Fatalf("shared default %x = layer %d observation %d", id, got.Layer, got.LayerObservationID) + } + } +} + +func TestAuthKeySessionLayerExpiryDeleteAndAuthKeyCascade(t *testing.T) { + ctx := context.Background() + keys := NewAuthKeyStore() + id := [8]byte{3} + if err := keys.Save(ctx, store.AuthKeyData{ID: id}); err != nil { + t.Fatal(err) + } + now := time.Now().UTC() + seedMsgID := authKeySessionLayerTestMsgID(now, 1) + replacementMsgID := authKeySessionLayerTestMsgID(now.Add(time.Second), 1) + otherMsgID := authKeySessionLayerTestMsgID(now.Add(time.Second), 2) + if _, _, err := keys.AdvanceSessionLayer( + ctx, id, 20, 227, authKeySessionLayerTestMsgID(now.Add(-302*time.Second), 1), + ); !errors.Is(err, store.ErrAuthKeySessionLayerInvalid) { + t.Fatalf("stale evidence err = %v", err) + } + if _, applied, err := keys.AdvanceSessionLayer(ctx, id, 20, 227, seedMsgID); err != nil || !applied { + t.Fatalf("seed = applied %v err %v", applied, err) + } + // Model the same once-valid row after wall-clock retention elapsed. Tests do + // not pass an arbitrary expiry through the production write API. + key := authKeySessionLayerKey{rawAuthKeyID: id, sessionID: 20} + keys.state.mu.Lock() + expired := keys.state.sessionLayers[key] + expired.ExpiresAt = time.Now().Add(-time.Second) + keys.state.sessionLayers[key] = expired + keys.state.mu.Unlock() + if _, found, err := keys.GetSessionLayer(ctx, id, 20); err != nil || found { + t.Fatalf("expired lookup = found %v err %v", found, err) + } + current, applied, err := keys.AdvanceSessionLayer(ctx, id, 20, 220, replacementMsgID) + if err != nil || !applied || current.Layer != 220 { + t.Fatalf("expired replacement = (%+v,%v,%v)", current, applied, err) + } + if deleted, err := keys.DeleteSessionLayer(ctx, id, 20); err != nil || !deleted { + t.Fatalf("delete session layer = (%v,%v)", deleted, err) + } + if _, applied, err := keys.AdvanceSessionLayer(ctx, id, 21, 227, otherMsgID); err != nil || !applied { + t.Fatalf("cascade seed = applied %v err %v", applied, err) + } + if err := keys.Delete(ctx, id); err != nil { + t.Fatal(err) + } + if _, found, err := keys.GetSessionLayer(ctx, id, 21); err != nil || found { + t.Fatalf("auth key cascade = found %v err %v", found, err) + } +} + +func TestAuthKeySessionLayerObservationContinuesAfterRestoredAuthKeyWatermark(t *testing.T) { + ctx := context.Background() + keys := NewAuthKeyStore() + id := [8]byte{4} + if err := keys.Save(ctx, store.AuthKeyData{ + ID: id, Layer: 225, LayerObservationID: 91, + }); err != nil { + t.Fatal(err) + } + + current, applied, err := keys.AdvanceSessionLayer( + ctx, id, 30, 227, authKeySessionLayerTestMsgID(time.Now().UTC(), 1), + ) + if err != nil || !applied { + t.Fatalf("advance restored watermark = (%+v,%v,%v)", current, applied, err) + } + if current.ObservationID <= 91 { + t.Fatalf("new observation = %d, want > 91", current.ObservationID) + } +} + +func TestAuthKeyLayerAuthorityKeepsAuthorizationProjectionInParity(t *testing.T) { + ctx := context.Background() + t.Run("advance before stale bind", func(t *testing.T) { + keys := NewAuthKeyStore() + auths := NewAuthorizationStore() + auths.LinkAuthKeyAuthority(keys) + perm := memoryAuthKeyID(8_701) + if err := keys.Save(ctx, store.AuthKeyData{ID: perm}); err != nil { + t.Fatal(err) + } + advanced, applied, err := keys.AdvanceSessionLayer( + ctx, perm, 1, 227, authKeySessionLayerTestMsgID(time.Now().UTC(), 1), + ) + if err != nil || !applied { + t.Fatalf("advance = (%+v,%v,%v)", advanced, applied, err) + } + if err := auths.Bind(ctx, domain.Authorization{ + AuthKeyID: perm, UserID: 1, Layer: 220, + }); err != nil { + t.Fatal(err) + } + got, found, err := auths.ByAuthKey(ctx, perm) + if err != nil || !found || got.Layer != 227 { + t.Fatalf("authorization after stale bind = (%+v,%v,%v)", got, found, err) + } + }) + + t.Run("bind before advance", func(t *testing.T) { + keys := NewAuthKeyStore() + auths := NewAuthorizationStore() + auths.LinkAuthKeyAuthority(keys) + perm := memoryAuthKeyID(8_702) + if err := keys.Save(ctx, store.AuthKeyData{ID: perm, Layer: 220}); err != nil { + t.Fatal(err) + } + if err := auths.Bind(ctx, domain.Authorization{AuthKeyID: perm, UserID: 2, Layer: 225}); err != nil { + t.Fatal(err) + } + if _, _, err := keys.AdvanceSessionLayer( + ctx, perm, 2, 227, authKeySessionLayerTestMsgID(time.Now().UTC(), 2), + ); err != nil { + t.Fatal(err) + } + got, found, err := auths.ByAuthKey(ctx, perm) + if err != nil || !found || got.Layer != 227 { + t.Fatalf("authorization after advance = (%+v,%v,%v)", got, found, err) + } + }) + + t.Run("temp merge", func(t *testing.T) { + keys := NewAuthKeyStore() + auths := NewAuthorizationStore() + auths.LinkAuthKeyAuthority(keys) + bindings := NewTempAuthKeyBindingStore(keys) + temp := memoryAuthKeyID(8_703) + perm := memoryAuthKeyID(8_704) + const expiresAt = 2_000_000_000 + if err := keys.Save(ctx, store.AuthKeyData{ + ID: temp, ExpiresAt: expiresAt, Layer: 225, LayerObservationID: 20, + }); err != nil { + t.Fatal(err) + } + if err := keys.Save(ctx, store.AuthKeyData{ + ID: perm, Layer: 220, LayerObservationID: 10, + }); err != nil { + t.Fatal(err) + } + if err := auths.Bind(ctx, domain.Authorization{AuthKeyID: perm, UserID: 3, Layer: 227}); err != nil { + t.Fatal(err) + } + if err := bindings.Save(ctx, domain.TempAuthKeyBinding{ + TempAuthKeyID: temp, + PermAuthKeyID: int64(binary.LittleEndian.Uint64(perm[:])), + ExpiresAt: expiresAt, + }); err != nil { + t.Fatal(err) + } + got, found, err := auths.ByAuthKey(ctx, perm) + if err != nil || !found || got.Layer != 225 { + t.Fatalf("authorization after temp merge = (%+v,%v,%v)", got, found, err) + } + }) +} + +func authKeySessionLayerTestMsgID(at time.Time, order uint32) int64 { + return int64((uint64(at.Unix()) << 32) | uint64(order)<<2) +} diff --git a/internal/store/memory/update_state_delivery_test.go b/internal/store/memory/update_state_delivery_test.go new file mode 100644 index 00000000..377debfe --- /dev/null +++ b/internal/store/memory/update_state_delivery_test.go @@ -0,0 +1,65 @@ +package memory + +import ( + "context" + "testing" + + "telesrv/internal/domain" +) + +func TestUpdateStateDeliveredCommitSeparatesConfirmedAndObserved(t *testing.T) { + ctx := context.Background() + store := NewUpdateStateStore() + authKeyID := [8]byte{1} + const userID int64 = 1001 + if err := store.ObserveClientState(ctx, authKeyID, userID, domain.UpdateState{Pts: 2, Date: 20}); err != nil { + t.Fatalf("observe request: %v", err) + } + if _, found, err := store.Get(ctx, authKeyID, userID); err != nil || found { + t.Fatalf("observed request fabricated confirmed state: found=%v err=%v", found, err) + } + if err := store.CommitDeliveredState(ctx, authKeyID, userID, domain.UpdateState{Pts: 5, Date: 50}, domain.UpdateStateCommitDeliveredOnly); err != nil { + t.Fatalf("commit delivered: %v", err) + } + confirmed, found, err := store.Get(ctx, authKeyID, userID) + if err != nil || !found || confirmed.Pts != 5 { + t.Fatalf("confirmed = %+v/%v err=%v, want pts=5", confirmed, found, err) + } + observed, found := store.ObservedClientState(authKeyID, userID) + if !found || observed.Pts != 2 { + t.Fatalf("observed = %+v/%v, want pts=2", observed, found) + } +} + +func TestUpdateStateBaselineCommitIsAtomicAndMonotonic(t *testing.T) { + ctx := context.Background() + store := NewUpdateStateStore() + authKeyID := [8]byte{2} + const userID int64 = 1002 + if err := store.CommitDeliveredState(ctx, authKeyID, userID, domain.UpdateState{Pts: 8, Date: 80}, domain.UpdateStateCommitDeliveredAndObservedBaseline); err != nil { + t.Fatalf("commit baseline: %v", err) + } + if err := store.CommitDeliveredState(ctx, authKeyID, userID, domain.UpdateState{Pts: 3, Date: 30}, domain.UpdateStateCommitDeliveredAndObservedBaseline); err != nil { + t.Fatalf("commit stale baseline: %v", err) + } + confirmed, _, _ := store.Get(ctx, authKeyID, userID) + observed, _ := store.ObservedClientState(authKeyID, userID) + if confirmed.Pts != 8 || observed.Pts != 8 { + t.Fatalf("out-of-order baseline regressed state: confirmed=%+v observed=%+v", confirmed, observed) + } +} + +func TestUpdateStateDeleteAuthKeyRemovesObservedOnlyRows(t *testing.T) { + ctx := context.Background() + store := NewUpdateStateStore() + authKeyID := [8]byte{3} + if err := store.ObserveClientState(ctx, authKeyID, 1003, domain.UpdateState{Pts: 4}); err != nil { + t.Fatalf("observe: %v", err) + } + if err := store.DeleteAuthKey(ctx, authKeyID); err != nil { + t.Fatalf("delete auth key: %v", err) + } + if _, found := store.ObservedClientState(authKeyID, 1003); found { + t.Fatal("observed-only row survived auth-key deletion") + } +} diff --git a/internal/store/memory/updates.go b/internal/store/memory/updates.go index 68d253c9..7124744a 100644 --- a/internal/store/memory/updates.go +++ b/internal/store/memory/updates.go @@ -2,6 +2,7 @@ package memory import ( "context" + "fmt" "sync" "telesrv/internal/domain" ) @@ -195,27 +196,44 @@ func (s *UpdateStateStore) Save(_ context.Context, id [8]byte, userID int64, st return nil } +func (s *UpdateStateStore) CommitDeliveredState(_ context.Context, id [8]byte, userID int64, st domain.UpdateState, mode domain.UpdateStateCommitMode) error { + if mode != domain.UpdateStateCommitDeliveredOnly && mode != domain.UpdateStateCommitDeliveredAndObservedBaseline { + return fmt.Errorf("commit delivered update state: invalid mode %d", mode) + } + s.mu.Lock() + defer s.mu.Unlock() + key := updateStateKey{authKeyID: id, userID: userID} + s.states[key] = monotonicUpdateState(s.states[key], st) + if mode == domain.UpdateStateCommitDeliveredAndObservedBaseline { + s.observed[key] = monotonicUpdateState(s.observed[key], st) + } + return nil +} + func (s *UpdateStateStore) ObserveClientState(_ context.Context, id [8]byte, userID int64, st domain.UpdateState) error { s.mu.Lock() key := updateStateKey{authKeyID: id, userID: userID} - prev := s.observed[key] - if st.Pts < prev.Pts { - st.Pts = prev.Pts - } - if st.Qts < prev.Qts { - st.Qts = prev.Qts - } - if st.Date < prev.Date { - st.Date = prev.Date - } - if st.Seq < prev.Seq { - st.Seq = prev.Seq - } - s.observed[key] = st + s.observed[key] = monotonicUpdateState(s.observed[key], st) s.mu.Unlock() return nil } +func monotonicUpdateState(prev, next domain.UpdateState) domain.UpdateState { + if next.Pts < prev.Pts { + next.Pts = prev.Pts + } + if next.Qts < prev.Qts { + next.Qts = prev.Qts + } + if next.Date < prev.Date { + next.Date = prev.Date + } + if next.Seq < prev.Seq { + next.Seq = prev.Seq + } + return next +} + // ObservedClientState 暴露给同包/服务测试验证 retention 安全水位;业务读路径仍用 Get。 func (s *UpdateStateStore) ObservedClientState(id [8]byte, userID int64) (domain.UpdateState, bool) { s.mu.RLock() @@ -240,6 +258,11 @@ func (s *UpdateStateStore) DeleteAuthKey(_ context.Context, id [8]byte) error { delete(s.observed, k) } } + for k := range s.observed { + if k.authKeyID == id { + delete(s.observed, k) + } + } s.mu.Unlock() return nil } diff --git a/internal/store/postgres/auth_identity_lock.go b/internal/store/postgres/auth_identity_lock.go new file mode 100644 index 00000000..cb4c9e65 --- /dev/null +++ b/internal/store/postgres/auth_identity_lock.go @@ -0,0 +1,222 @@ +package postgres + +import ( + "context" + "errors" + "fmt" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" + + "telesrv/internal/store" + "telesrv/internal/store/postgres/sqlcgen" +) + +const ( + // authIdentityAdvisoryNamespace is deliberately a two-int advisory-lock + // namespace. PostgreSQL keeps it disjoint from the one-bigint advisory locks + // used elsewhere in the store. AUTH in ASCII is stable and recognizable in + // pg_locks diagnostics. + authIdentityAdvisoryNamespace int32 = 0x41555448 + authIdentityTxMaxAttempts = 3 +) + +var errAuthIdentityChanged = errors.New("auth key permanent identity changed while acquiring locks") + +type authKeyIdentityHint struct { + found bool + expiresAt int + bound bool + permID int64 + identityID int64 + hasIdentity bool +} + +// withAuthIdentityTx gives identity-sensitive stores an explicit transaction +// boundary. Application-level identity visibility changes are retried after a +// savepoint/transaction rollback. PostgreSQL deadlock/serialization retries are +// only safe when this store owns the top-level transaction; an injected pgx.Tx +// is never silently replayed after 40P01/40001. +func withAuthIdentityTx( + ctx context.Context, + db sqlcgen.DBTX, + op string, + fn func(pgx.Tx) error, +) error { + _, embedded := db.(pgx.Tx) + var lastErr error + for attempt := 0; attempt < authIdentityTxMaxAttempts; attempt++ { + err := withTx(ctx, db, op, fn) + if err == nil { + return nil + } + lastErr = err + switch { + case errors.Is(err, errAuthIdentityChanged): + // The attempt owns a nested savepoint even for an injected pgx.Tx, + // so all row/advisory locks from the stale hint have been released + // before the next READ COMMITTED statement snapshot is taken. + continue + case !embedded && isAuthIdentityRetryableDatabaseError(err): + // Defensive retry only. The identity gate is the deadlock fix; this + // does not substitute for the global lock order. + continue + default: + return err + } + } + return fmt.Errorf("%s did not stabilize after %d attempts: %w", op, authIdentityTxMaxAttempts, lastErr) +} + +func isAuthIdentityRetryableDatabaseError(err error) bool { + var pgErr *pgconn.PgError + return errors.As(err, &pgErr) && (pgErr.Code == "40P01" || pgErr.Code == "40001") +} + +// lockPermanentAuthIdentities acquires the complete batch before any auth-key, +// binding, authorization, or update-state row lock. Ordering is by the final +// int32 hashint8 key, not by the source bigint identity: hash collisions are +// intentionally one lock and cannot create an opposite acquisition order. +func lockPermanentAuthIdentities(ctx context.Context, tx pgx.Tx, permIDs []int64) error { + if len(permIDs) == 0 { + return nil + } + rows, err := tx.Query(ctx, ` +SELECT DISTINCT hashint8(identity_id)::integer AS lock_key +FROM unnest($1::bigint[]) AS identities(identity_id) +ORDER BY lock_key`, permIDs) + if err != nil { + return fmt.Errorf("derive permanent auth identity lock keys: %w", err) + } + lockKeys := make([]int32, 0, len(permIDs)) + for rows.Next() { + var key int32 + if err := rows.Scan(&key); err != nil { + rows.Close() + return fmt.Errorf("scan permanent auth identity lock key: %w", err) + } + lockKeys = append(lockKeys, key) + } + if err := rows.Err(); err != nil { + rows.Close() + return fmt.Errorf("iterate permanent auth identity lock keys: %w", err) + } + rows.Close() + for _, key := range lockKeys { + if _, err := tx.Exec(ctx, `SELECT pg_advisory_xact_lock($1::integer, $2::integer)`, authIdentityAdvisoryNamespace, key); err != nil { + return fmt.Errorf("lock permanent auth identity %d: %w", key, err) + } + } + return nil +} + +// lookupAuthKeyIdentityHint is intentionally lock-free. A positive-expiry raw +// key has no permanent identity until a binding is committed; a permanent raw +// key is its own identity. Callers must re-read after the raw row is locked. +func lookupAuthKeyIdentityHint(ctx context.Context, tx pgx.Tx, rawID int64) (authKeyIdentityHint, error) { + var hint authKeyIdentityHint + err := tx.QueryRow(ctx, ` +/* auth_identity_hint */ +SELECT key.expires_at, + binding.temp_auth_key_id IS NOT NULL, + COALESCE(binding.perm_auth_key_id, 0) +FROM auth_keys AS key +LEFT JOIN temp_auth_key_bindings AS binding + ON binding.temp_auth_key_id = key.auth_key_id +WHERE key.auth_key_id = $1`, rawID).Scan(&hint.expiresAt, &hint.bound, &hint.permID) + if errors.Is(err, pgx.ErrNoRows) { + return authKeyIdentityHint{}, nil + } + if err != nil { + return authKeyIdentityHint{}, fmt.Errorf("resolve auth key identity hint: %w", err) + } + hint.found = true + switch { + case hint.bound: + hint.identityID = hint.permID + hint.hasIdentity = true + case hint.expiresAt == 0: + hint.identityID = rawID + hint.hasIdentity = true + } + return hint, nil +} + +// lockRawAuthKeyInIdentityOrder establishes the only cross-identity row-lock +// order used by bind, selector advance and direct key deletion: +// +// permanent identity advisory gate -> raw auth-key row -> permanent row +// +// If an initially-unbound temp key becomes bound before the raw lock is +// acquired, taking its newly discovered identity advisory lock at that point +// would recreate raw->identity inversion. The caller must roll back and retry. +func lockRawAuthKeyInIdentityOrder( + ctx context.Context, + tx pgx.Tx, + rawID int64, +) (rawExpiry int, permID int64, bound bool, err error) { + hint, err := lookupAuthKeyIdentityHint(ctx, tx, rawID) + if err != nil || !hint.found { + if err != nil { + return 0, 0, false, err + } + return 0, 0, false, store.ErrAuthKeyNotFound + } + if hint.hasIdentity { + if err := lockPermanentAuthIdentities(ctx, tx, []int64{hint.identityID}); err != nil { + return 0, 0, false, err + } + } + if err := tx.QueryRow(ctx, ` +SELECT expires_at +FROM auth_keys +WHERE auth_key_id = $1 +FOR UPDATE`, rawID).Scan(&rawExpiry); err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return 0, 0, false, store.ErrAuthKeyNotFound + } + return 0, 0, false, fmt.Errorf("lock raw auth key: %w", err) + } + + var actualPermID int64 + err = tx.QueryRow(ctx, ` +SELECT perm_auth_key_id +FROM temp_auth_key_bindings +WHERE temp_auth_key_id = $1`, rawID).Scan(&actualPermID) + switch { + case err == nil: + bound = true + permID = actualPermID + case errors.Is(err, pgx.ErrNoRows): + permID = rawID + default: + return 0, 0, false, fmt.Errorf("revalidate auth key permanent identity: %w", err) + } + + actualHasIdentity := bound || rawExpiry == 0 + actualIdentityID := permID + if actualHasIdentity != hint.hasIdentity || + (actualHasIdentity && actualIdentityID != hint.identityID) || + bound != hint.bound || rawExpiry != hint.expiresAt { + return 0, 0, false, errAuthIdentityChanged + } + if !bound { + return rawExpiry, permID, false, nil + } + + var permExpiry int + if err := tx.QueryRow(ctx, ` +SELECT expires_at +FROM auth_keys +WHERE auth_key_id = $1 +FOR UPDATE`, permID).Scan(&permExpiry); err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return 0, 0, false, store.ErrAuthKeyBindingInvalid + } + return 0, 0, false, fmt.Errorf("lock permanent auth key: %w", err) + } + if rawExpiry <= 0 || permExpiry != 0 { + return 0, 0, false, store.ErrAuthKeyBindingInvalid + } + return rawExpiry, permID, true, nil +} diff --git a/internal/store/postgres/auth_identity_lock_integration_test.go b/internal/store/postgres/auth_identity_lock_integration_test.go new file mode 100644 index 00000000..89122ad8 --- /dev/null +++ b/internal/store/postgres/auth_identity_lock_integration_test.go @@ -0,0 +1,429 @@ +package postgres + +import ( + "context" + "errors" + "strings" + "sync" + "testing" + "time" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgxpool" + + "telesrv/internal/domain" + "telesrv/internal/store" +) + +func TestAuthIdentitySelectorRetriesUncommittedFirstBindSnapshotPostgres(t *testing.T) { + pool := testPool(t) + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + t.Cleanup(cancel) + keys := NewAuthKeyStore(pool) + bindings := NewTempAuthKeyBindingStore(pool) + expiresAt := int(time.Now().Add(time.Hour).Unix()) + temp := saveTempIdentityTestAuthKey(t, ctx, pool, keys, expiresAt) + perm := saveTempIdentityTestAuthKey(t, ctx, pool, keys, 0) + binding := domain.TempAuthKeyBinding{ + TempAuthKeyID: temp, PermAuthKeyID: authKeyIDToInt64(perm), + Nonce: 8701, TempSessionID: 8702, ExpiresAt: expiresAt, + EncryptedMessage: []byte("first bind snapshot"), + } + + advanceConn, err := pool.Acquire(ctx) + if err != nil { + t.Fatal(err) + } + defer advanceConn.Release() + var advancePID int + if err := advanceConn.QueryRow(ctx, `SELECT pg_backend_pid()`).Scan(&advancePID); err != nil { + t.Fatal(err) + } + barrier := newAuthStoreQueryBarrier(advanceConn, "auth_identity_hint", "") + msgID := authKeySessionLayerTestMsgID(time.Now().UTC(), 1) + type advanceResult struct { + value store.AuthKeySessionLayer + applied bool + err error + } + result := make(chan advanceResult, 1) + go func() { + value, applied, err := NewAuthKeyStore(barrier).AdvanceSessionLayer(ctx, temp, 8703, 227, msgID) + result <- advanceResult{value: value, applied: applied, err: err} + }() + <-barrier.observed + + // The selector already read "unbound". Stage a committed binding behind + // its statement snapshot while retaining P/raw row locks in the outer tx. + bindTx, err := pool.Begin(ctx) + if err != nil { + t.Fatal(err) + } + defer func() { _ = bindTx.Rollback(context.Background()) }() + if err := NewTempAuthKeyBindingStore(bindTx).Save(ctx, binding); err != nil { + t.Fatalf("stage first bind: %v", err) + } + close(barrier.release) + waitForPostgresBackendLockWait(t, ctx, pool, advancePID) + if err := bindTx.Commit(ctx); err != nil { + t.Fatalf("commit first bind: %v", err) + } + + got := <-result + if got.err != nil || !got.applied || got.value.Layer != 227 || !got.value.SharedDefault { + t.Fatalf("advance after identity retry = (%+v,%v,%v)", got.value, got.applied, got.err) + } + assertTempIdentityBinding(t, ctx, bindings, binding) + for _, id := range [][8]byte{temp, perm} { + stored, found, err := keys.Get(ctx, id) + if err != nil || !found || stored.Layer != 227 || stored.LayerObservationID != got.value.ObservationID { + t.Fatalf("shared tuple %x = (%+v,%v,%v)", id, stored, found, err) + } + } +} + +func TestAuthIdentitySelectorSerializesWithPermanentRevocationAndDeletePostgres(t *testing.T) { + for _, op := range []string{"revoke", "delete"} { + t.Run(op, func(t *testing.T) { + pool := testPool(t) + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + t.Cleanup(cancel) + keys := NewAuthKeyStore(pool) + auths := NewAuthorizationStore(pool) + bindings := NewTempAuthKeyBindingStore(pool) + expiresAt := int(time.Now().Add(time.Hour).Unix()) + temp := saveTempIdentityTestAuthKey(t, ctx, pool, keys, expiresAt) + perm := saveTempIdentityTestAuthKey(t, ctx, pool, keys, 0) + userID := createRevokeTestUser(t, ctx, pool, "selector-"+op) + hash := int64(8800) + if err := auths.Bind(ctx, domain.Authorization{AuthKeyID: perm, UserID: userID, Hash: hash}); err != nil { + t.Fatal(err) + } + if err := bindings.Save(ctx, domain.TempAuthKeyBinding{ + TempAuthKeyID: temp, PermAuthKeyID: authKeyIDToInt64(perm), ExpiresAt: expiresAt, + EncryptedMessage: []byte("identity serialization"), + }); err != nil { + t.Fatal(err) + } + + blocker, err := pool.Begin(ctx) + if err != nil { + t.Fatal(err) + } + defer func() { _ = blocker.Rollback(context.Background()) }() + if err := lockPermanentAuthIdentities(ctx, blocker, []int64{authKeyIDToInt64(perm)}); err != nil { + t.Fatal(err) + } + + selectorConn, err := pool.Acquire(ctx) + if err != nil { + t.Fatal(err) + } + defer selectorConn.Release() + opConn, err := pool.Acquire(ctx) + if err != nil { + t.Fatal(err) + } + defer opConn.Release() + var selectorPID, opPID int + if err := selectorConn.QueryRow(ctx, `SELECT pg_backend_pid()`).Scan(&selectorPID); err != nil { + t.Fatal(err) + } + if err := opConn.QueryRow(ctx, `SELECT pg_backend_pid()`).Scan(&opPID); err != nil { + t.Fatal(err) + } + + selectorResult := make(chan error, 1) + go func() { + _, _, err := NewAuthKeyStore(selectorConn).AdvanceSessionLayer( + ctx, temp, 8801, 227, authKeySessionLayerTestMsgID(time.Now().UTC(), 1), + ) + selectorResult <- err + }() + waitForPostgresBackendLockWait(t, ctx, pool, selectorPID) + opResult := make(chan error, 1) + go func() { + if op == "revoke" { + _, found, err := NewAuthorizationStore(opConn).RevokeByHash(ctx, userID, hash) + if err == nil && !found { + err = errors.New("revoke target disappeared") + } + opResult <- err + return + } + opResult <- NewAuthKeyStore(opConn).Delete(ctx, perm) + }() + waitForPostgresBackendLockWait(t, ctx, pool, opPID) + if err := blocker.Commit(ctx); err != nil { + t.Fatal(err) + } + selectorErr := <-selectorResult + if selectorErr != nil && + !errors.Is(selectorErr, store.ErrAuthKeyNotFound) && + !errors.Is(selectorErr, store.ErrAuthKeyBindingInvalid) { + t.Fatalf("selector error = %v", selectorErr) + } + if err := <-opResult; err != nil { + t.Fatalf("%s error = %v", op, err) + } + assertTempIdentityAuthKeyMissing(t, ctx, keys, temp) + assertTempIdentityAuthKeyMissing(t, ctx, keys, perm) + assertRevokeTestNoAuthorization(t, ctx, auths, perm) + if _, found, err := bindings.GetByTemp(ctx, temp); err != nil || found { + t.Fatalf("binding after %s found=%v err=%v", op, found, err) + } + }) + } +} + +func TestAuthIdentityAuthorizationMirrorUsesLockedPrimaryLayerPostgres(t *testing.T) { + pool := testPool(t) + ctx := context.Background() + keys := NewAuthKeyStore(pool) + auths := NewAuthorizationStore(pool) + + t.Run("advance before stale bind", func(t *testing.T) { + perm := saveTempIdentityTestAuthKey(t, ctx, pool, keys, 0) + userID := createRevokeTestUser(t, ctx, pool, "layer-advance-before-bind") + if _, _, err := keys.AdvanceSessionLayer( + ctx, perm, 8901, 227, authKeySessionLayerTestMsgID(time.Now().UTC(), 1), + ); err != nil { + t.Fatal(err) + } + if err := auths.Bind(ctx, domain.Authorization{ + AuthKeyID: perm, UserID: userID, Hash: 8902, Layer: 220, + }); err != nil { + t.Fatal(err) + } + got, found, err := auths.ByAuthKey(ctx, perm) + if err != nil || !found || got.Layer != 227 { + t.Fatalf("stale bind mirror = (%+v,%v,%v)", got, found, err) + } + }) + + t.Run("bind before advance", func(t *testing.T) { + perm := saveTempIdentityTestAuthKey(t, ctx, pool, keys, 0) + userID := createRevokeTestUser(t, ctx, pool, "layer-bind-before-advance") + if err := auths.Bind(ctx, domain.Authorization{ + AuthKeyID: perm, UserID: userID, Hash: 8903, Layer: 220, + }); err != nil { + t.Fatal(err) + } + if _, _, err := keys.AdvanceSessionLayer( + ctx, perm, 8904, 227, authKeySessionLayerTestMsgID(time.Now().UTC(), 2), + ); err != nil { + t.Fatal(err) + } + got, found, err := auths.ByAuthKey(ctx, perm) + if err != nil || !found || got.Layer != 227 { + t.Fatalf("advanced mirror = (%+v,%v,%v)", got, found, err) + } + }) +} + +func TestDeleteOrphanedRevalidatesUncommittedAuthorizationAndTempBindPostgres(t *testing.T) { + t.Run("authorization bind", func(t *testing.T) { + pool := testPool(t) + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + t.Cleanup(cancel) + keys := NewAuthKeyStore(pool) + auths := NewAuthorizationStore(pool) + perm := saveTempIdentityTestAuthKey(t, ctx, pool, keys, 0) + if _, err := pool.Exec(ctx, `UPDATE auth_keys SET last_used_at = now() - interval '72 hours' WHERE auth_key_id = $1`, authKeyIDToInt64(perm)); err != nil { + t.Fatal(err) + } + userID := createRevokeTestUser(t, ctx, pool, "orphan-auth-bind") + + gcConn, err := pool.Acquire(ctx) + if err != nil { + t.Fatal(err) + } + defer gcConn.Release() + var gcPID int + if err := gcConn.QueryRow(ctx, `SELECT pg_backend_pid()`).Scan(&gcPID); err != nil { + t.Fatal(err) + } + barrier := newAuthStoreQueryBarrier(gcConn, "", "orphan_identity_candidates") + gcResult := make(chan struct { + deleted int + err error + }, 1) + go func() { + deleted, err := NewAuthKeyStore(barrier).DeleteOrphaned(ctx, 24*time.Hour, 1, nil) + gcResult <- struct { + deleted int + err error + }{deleted: deleted, err: err} + }() + <-barrier.observed + + bindTx, err := pool.Begin(ctx) + if err != nil { + t.Fatal(err) + } + defer func() { _ = bindTx.Rollback(context.Background()) }() + if err := NewAuthorizationStore(bindTx).Bind(ctx, domain.Authorization{ + AuthKeyID: perm, UserID: userID, Hash: 9001, + }); err != nil { + t.Fatal(err) + } + close(barrier.release) + waitForPostgresBackendLockWait(t, ctx, pool, gcPID) + if err := bindTx.Commit(ctx); err != nil { + t.Fatal(err) + } + got := <-gcResult + if got.err != nil || got.deleted != 0 { + t.Fatalf("orphan GC after authorization bind = (%d,%v)", got.deleted, got.err) + } + assertRevokeTestPresentAuthKey(t, ctx, keys, perm) + assertRevokeTestPresentAuthorization(t, ctx, auths, perm) + }) + + t.Run("temporary bind", func(t *testing.T) { + pool := testPool(t) + ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) + t.Cleanup(cancel) + keys := NewAuthKeyStore(pool) + bindings := NewTempAuthKeyBindingStore(pool) + expiresAt := int(time.Now().Add(time.Hour).Unix()) + temp := saveTempIdentityTestAuthKey(t, ctx, pool, keys, expiresAt) + perm := saveTempIdentityTestAuthKey(t, ctx, pool, keys, 0) + if _, err := pool.Exec(ctx, `UPDATE auth_keys SET last_used_at = now() - interval '72 hours' WHERE auth_key_id = $1`, authKeyIDToInt64(temp)); err != nil { + t.Fatal(err) + } + binding := domain.TempAuthKeyBinding{ + TempAuthKeyID: temp, PermAuthKeyID: authKeyIDToInt64(perm), + Nonce: 9002, TempSessionID: 9003, ExpiresAt: expiresAt, + EncryptedMessage: []byte("orphan bind revalidation"), + } + + gcConn, err := pool.Acquire(ctx) + if err != nil { + t.Fatal(err) + } + defer gcConn.Release() + barrier := newAuthStoreQueryBarrier(gcConn, "", "orphan_identity_candidates") + gcResult := make(chan struct { + deleted int + err error + }, 1) + go func() { + deleted, err := NewAuthKeyStore(barrier).DeleteOrphaned(ctx, 24*time.Hour, 1, nil) + gcResult <- struct { + deleted int + err error + }{deleted: deleted, err: err} + }() + <-barrier.observed + + bindTx, err := pool.Begin(ctx) + if err != nil { + t.Fatal(err) + } + defer func() { _ = bindTx.Rollback(context.Background()) }() + if err := NewTempAuthKeyBindingStore(bindTx).Save(ctx, binding); err != nil { + t.Fatal(err) + } + close(barrier.release) + var gc struct { + deleted int + err error + } + select { + case gc = <-gcResult: + case <-time.After(2 * time.Second): + _ = bindTx.Commit(context.Background()) + t.Fatal("orphan GC blocked on an uncommitted temp bind despite SKIP LOCKED") + } + if gc.err != nil || gc.deleted != 0 { + t.Fatalf("orphan GC during temp bind = (%d,%v)", gc.deleted, gc.err) + } + if err := bindTx.Commit(ctx); err != nil { + t.Fatal(err) + } + assertTempIdentityBinding(t, ctx, bindings, binding) + assertRevokeTestPresentAuthKey(t, ctx, keys, temp) + assertRevokeTestPresentAuthKey(t, ctx, keys, perm) + }) +} + +type authStoreQueryBarrier struct { + *pgxpool.Conn + queryRowMarker string + queryMarker string + observed chan struct{} + release chan struct{} + once sync.Once +} + +func newAuthStoreQueryBarrier(conn *pgxpool.Conn, queryRowMarker, queryMarker string) *authStoreQueryBarrier { + return &authStoreQueryBarrier{ + Conn: conn, queryRowMarker: queryRowMarker, queryMarker: queryMarker, + observed: make(chan struct{}), release: make(chan struct{}), + } +} + +func (db *authStoreQueryBarrier) Begin(ctx context.Context) (pgx.Tx, error) { + tx, err := db.Conn.Begin(ctx) + if err != nil { + return nil, err + } + return &authStoreBarrierTx{Tx: tx, owner: db}, nil +} + +type authStoreBarrierTx struct { + pgx.Tx + owner *authStoreQueryBarrier +} + +func (tx *authStoreBarrierTx) QueryRow(ctx context.Context, sql string, args ...any) pgx.Row { + row := tx.Tx.QueryRow(ctx, sql, args...) + if tx.owner.queryRowMarker != "" && strings.Contains(sql, tx.owner.queryRowMarker) { + return &authStoreBarrierRow{Row: row, owner: tx.owner} + } + return row +} + +func (tx *authStoreBarrierTx) Query(ctx context.Context, sql string, args ...any) (pgx.Rows, error) { + rows, err := tx.Tx.Query(ctx, sql, args...) + if err != nil { + return nil, err + } + if tx.owner.queryMarker != "" && strings.Contains(sql, tx.owner.queryMarker) { + return &authStoreBarrierRows{Rows: rows, owner: tx.owner}, nil + } + return rows, nil +} + +type authStoreBarrierRow struct { + pgx.Row + owner *authStoreQueryBarrier +} + +func (row *authStoreBarrierRow) Scan(dest ...any) error { + err := row.Row.Scan(dest...) + if err == nil { + row.owner.once.Do(func() { + close(row.owner.observed) + <-row.owner.release + }) + } + return err +} + +type authStoreBarrierRows struct { + pgx.Rows + owner *authStoreQueryBarrier +} + +func (rows *authStoreBarrierRows) Next() bool { + next := rows.Rows.Next() + if !next { + rows.owner.once.Do(func() { + close(rows.owner.observed) + <-rows.owner.release + }) + } + return next +} diff --git a/internal/store/postgres/authkey.go b/internal/store/postgres/authkey.go index 4c871d31..834decca 100644 --- a/internal/store/postgres/authkey.go +++ b/internal/store/postgres/authkey.go @@ -8,7 +8,6 @@ import ( "time" "github.com/jackc/pgx/v5" - "github.com/jackc/pgx/v5/pgconn" "github.com/jackc/pgx/v5/pgtype" "telesrv/internal/store" @@ -56,24 +55,26 @@ WHERE auth_keys.body = EXCLUDED.body // 注册进 SessionManager”的窗口被后台清理。 func (s *AuthKeyStore) Get(ctx context.Context, id [8]byte) (store.AuthKeyData, bool, error) { var ( - body []byte - serverSalt int64 - expiresAt int - createdAt pgtype.Timestamptz - layer int - deviceModel string - platform string - systemVersion string - apiID int - appVersion string + body []byte + serverSalt int64 + expiresAt int + createdAt pgtype.Timestamptz + layer int + layerObservationID int64 + deviceModel string + platform string + systemVersion string + apiID int + appVersion string ) err := s.db.QueryRow(ctx, ` UPDATE auth_keys SET last_used_at = now() WHERE auth_key_id = $1 RETURNING auth_key_id, body, server_salt, created_at, - expires_at, layer, device_model, platform, system_version, api_id, app_version -`, authKeyIDToInt64(id)).Scan(new(int64), &body, &serverSalt, &createdAt, &expiresAt, &layer, &deviceModel, &platform, &systemVersion, &apiID, &appVersion) + expires_at, layer, layer_observation_id, + device_model, platform, system_version, api_id, app_version +`, authKeyIDToInt64(id)).Scan(new(int64), &body, &serverSalt, &createdAt, &expiresAt, &layer, &layerObservationID, &deviceModel, &platform, &systemVersion, &apiID, &appVersion) if err != nil { if errors.Is(err, pgx.ErrNoRows) { return store.AuthKeyData{}, false, nil @@ -84,15 +85,16 @@ RETURNING auth_key_id, body, server_salt, created_at, return store.AuthKeyData{}, false, fmt.Errorf("auth key body length = %d, want 256", len(body)) } data := store.AuthKeyData{ - ID: id, - ServerSalt: serverSalt, - ExpiresAt: expiresAt, - Layer: layer, - DeviceModel: deviceModel, - Platform: platform, - SystemVersion: systemVersion, - APIID: apiID, - AppVersion: appVersion, + ID: id, + ServerSalt: serverSalt, + ExpiresAt: expiresAt, + Layer: layer, + LayerObservationID: layerObservationID, + DeviceModel: deviceModel, + Platform: platform, + SystemVersion: systemVersion, + APIID: apiID, + AppVersion: appVersion, } copy(data.Value[:], body) if createdAt.Valid { @@ -148,7 +150,8 @@ WHERE auth_key_id = ANY($1::bigint[])`, batch) } func (s *AuthKeyStore) UpdateClientInfo(ctx context.Context, id [8]byte, info store.AuthKeyClientInfo) error { - if _, err := s.db.Exec(ctx, ` + var updated int + err := s.db.QueryRow(ctx, ` UPDATE auth_keys SET layer = CASE WHEN $2::integer > 0 THEN $2 ELSE layer END, device_model = CASE WHEN $3::text <> '' THEN $3 ELSE device_model END, @@ -157,7 +160,31 @@ SET layer = CASE WHEN $2::integer > 0 THEN $2 ELSE layer END, api_id = CASE WHEN $6::integer <> 0 THEN $6 ELSE api_id END, app_version = CASE WHEN $7::text <> '' THEN $7 ELSE app_version END WHERE auth_key_id = $1 -`, authKeyIDToInt64(id), info.Layer, info.DeviceModel, info.Platform, info.SystemVersion, info.APIID, info.AppVersion); err != nil { + AND ($2::integer <= 0 OR layer_observation_id = 0 OR layer = $2::integer) +RETURNING 1 +`, authKeyIDToInt64(id), info.Layer, info.DeviceModel, info.Platform, info.SystemVersion, info.APIID, info.AppVersion).Scan(&updated) + if err != nil { + if errors.Is(err, pgx.ErrNoRows) { + var ( + currentLayer int + observation int64 + ) + lookupErr := s.db.QueryRow(ctx, ` +SELECT layer, layer_observation_id +FROM auth_keys +WHERE auth_key_id = $1 +`, authKeyIDToInt64(id)).Scan(¤tLayer, &observation) + switch { + case errors.Is(lookupErr, pgx.ErrNoRows): + return store.ErrAuthKeyNotFound + case lookupErr != nil: + return fmt.Errorf("classify auth key client info update: %w", lookupErr) + case info.Layer > 0 && observation > 0 && currentLayer != info.Layer: + return store.ErrAuthKeySessionLayerConflict + default: + return fmt.Errorf("update auth key client info: guarded update affected no row") + } + } return fmt.Errorf("update auth key client info: %w", err) } return nil @@ -171,25 +198,20 @@ WHERE auth_key_id = $1 // RESTRICT FK 防止悬空,因此被踢/销毁 perm key 时必须先把关联 temp key 一并删掉。否则 Web/上传连接用 // raw temp key 重连时仍能进入 RPC 层,只得到 AUTH_KEY_UNREGISTERED,而不是连接层 404。 func (s *AuthKeyStore) Delete(ctx context.Context, id [8]byte) error { - for attempt := 0; attempt < 3; attempt++ { - err := s.deleteAuthKeyOnce(ctx, id) - if err == nil { - return nil - } - if !isPermAuthKeyDeleteRace(err) { - return err - } - if _, inTx := s.db.(pgx.Tx); inTx { - return err - } - } - return fmt.Errorf("delete auth key: permanent-key binding changed during all retries") + return withAuthIdentityTx(ctx, s.db, "delete auth key", func(tx pgx.Tx) error { + return deleteAuthKeyTx(ctx, tx, authKeyIDToInt64(id)) + }) } -func (s *AuthKeyStore) deleteAuthKeyOnce(ctx context.Context, id [8]byte) error { - keyID := authKeyIDToInt64(id) +func deleteAuthKeyTx(ctx context.Context, tx pgx.Tx, keyID int64) error { + if _, _, _, err := lockRawAuthKeyInIdentityOrder(ctx, tx, keyID); err != nil { + if errors.Is(err, store.ErrAuthKeyNotFound) { + return nil + } + return err + } var touched int - if err := s.db.QueryRow(ctx, ` + if err := tx.QueryRow(ctx, ` WITH doomed_temp AS MATERIALIZED ( SELECT temp_auth_key_id FROM temp_auth_key_bindings @@ -225,13 +247,6 @@ SELECT const tempAuthKeyPermFKConstraint = "temp_auth_key_bindings_perm_auth_key_id_fkey" -func isPermAuthKeyDeleteRace(err error) bool { - var pgErr *pgconn.PgError - return errors.As(err, &pgErr) && - pgErr.Code == "23503" && - pgErr.ConstraintName == tempAuthKeyPermFKConstraint -} - // DeleteOrphaned 回收握手已落库、但从未形成 authorization/temp binding 且当前没有 // 活跃物理连接的旧 auth key。last_used_at 与 Get 的 UPDATE ... RETURNING 行锁配对,封住 // active-key 快照之后新连接开始使用旧 key 的竞态;所有引用条件仍在最终 DELETE 中复核。 @@ -248,51 +263,140 @@ func (s *AuthKeyStore) DeleteOrphaned(ctx context.Context, olderThan time.Durati protectedIDs = append(protectedIDs, authKeyIDToInt64(id)) } var deleted int - err := s.db.QueryRow(ctx, ` -WITH candidates AS MATERIALIZED ( + err := withAuthIdentityTx(ctx, s.db, "delete orphaned auth keys", func(tx pgx.Tx) error { + var err error + deleted, err = deleteOrphanedAuthKeysTx(ctx, tx, olderThan, limit, protectedIDs) + return err + }) + if err != nil { + return 0, fmt.Errorf("delete orphaned auth keys: %w", err) + } + return deleted, nil +} + +func deleteOrphanedAuthKeysTx( + ctx context.Context, + tx pgx.Tx, + olderThan time.Duration, + limit int, + protectedIDs []int64, +) (int, error) { + // Phase 1 is only a bounded hint. It must not lock rows before the complete + // permanent-identity advisory set has been derived and acquired. + rows, err := tx.Query(ctx, ` +/* orphan_identity_candidates */ +SELECT k.auth_key_id, k.expires_at +FROM auth_keys AS k +WHERE k.last_used_at < now() - make_interval(secs => $1::double precision) + AND NOT (k.auth_key_id = ANY($2::bigint[])) + AND NOT EXISTS ( + SELECT 1 FROM authorizations AS a WHERE a.auth_key_id = k.auth_key_id + ) + AND NOT EXISTS ( + SELECT 1 + FROM temp_auth_key_bindings AS b + WHERE b.temp_auth_key_id = k.auth_key_id OR b.perm_auth_key_id = k.auth_key_id + ) +ORDER BY k.last_used_at, k.auth_key_id +LIMIT $3`, olderThan.Seconds(), protectedIDs, limit) + if err != nil { + return 0, fmt.Errorf("select orphan auth key candidates: %w", err) + } + candidates := make([]int64, 0, limit) + permanentCandidates := make([]int64, 0, limit) + for rows.Next() { + var ( + id int64 + expiresAt int + ) + if err := rows.Scan(&id, &expiresAt); err != nil { + rows.Close() + return 0, fmt.Errorf("scan orphan auth key candidate: %w", err) + } + candidates = append(candidates, id) + if expiresAt == 0 { + permanentCandidates = append(permanentCandidates, id) + } + } + if err := rows.Err(); err != nil { + rows.Close() + return 0, fmt.Errorf("iterate orphan auth key candidates: %w", err) + } + rows.Close() + if len(candidates) == 0 { + return 0, nil + } + if err := lockPermanentAuthIdentities(ctx, tx, permanentCandidates); err != nil { + return 0, err + } + + // Phase 2 locks only the hinted raw rows, in real-ID order, after every P + // gate is held. A temp bind already holding its raw row is skipped; if it + // committed immediately before this lock, phase 3's new READ COMMITTED + // statement sees the binding and excludes it. + lockRows, err := tx.Query(ctx, ` +SELECT auth_key_id +FROM auth_keys +WHERE auth_key_id = ANY($1::bigint[]) +ORDER BY auth_key_id +FOR UPDATE SKIP LOCKED`, candidates) + if err != nil { + return 0, fmt.Errorf("lock orphan auth key candidates: %w", err) + } + lockedIDs := make([]int64, 0, len(candidates)) + for lockRows.Next() { + var id int64 + if err := lockRows.Scan(&id); err != nil { + lockRows.Close() + return 0, fmt.Errorf("scan locked orphan auth key: %w", err) + } + lockedIDs = append(lockedIDs, id) + } + if err := lockRows.Err(); err != nil { + lockRows.Close() + return 0, fmt.Errorf("iterate locked orphan auth keys: %w", err) + } + lockRows.Close() + if len(lockedIDs) == 0 { + return 0, nil + } + + // Phase 3 is a separate statement snapshot and repeats every ownership, + // activity and protection predicate. Never delete from the phase-1 hint. + var deleted int + err = tx.QueryRow(ctx, ` +WITH still_orphaned AS MATERIALIZED ( SELECT k.auth_key_id - FROM auth_keys k - WHERE k.last_used_at < now() - make_interval(secs => $1::double precision) - AND NOT (k.auth_key_id = ANY($2::bigint[])) - AND NOT EXISTS ( - SELECT 1 FROM authorizations a WHERE a.auth_key_id = k.auth_key_id - ) - AND NOT EXISTS ( - SELECT 1 - FROM temp_auth_key_bindings b - WHERE b.temp_auth_key_id = k.auth_key_id OR b.perm_auth_key_id = k.auth_key_id - ) - ORDER BY k.last_used_at ASC, k.auth_key_id ASC - LIMIT $3 - FOR UPDATE OF k SKIP LOCKED -), deleted_update_states AS ( - -- Historical authorization-only deletion could leave a cursor without an - -- auth_keys FK. GC owns that stale row once the raw key is proven orphaned. - DELETE FROM update_states s - USING candidates c - WHERE s.auth_key_id = c.auth_key_id - RETURNING s.auth_key_id -), deleted_keys AS ( - DELETE FROM auth_keys k - USING candidates c - WHERE k.auth_key_id = c.auth_key_id + FROM auth_keys AS k + WHERE k.auth_key_id = ANY($3::bigint[]) AND k.last_used_at < now() - make_interval(secs => $1::double precision) AND NOT (k.auth_key_id = ANY($2::bigint[])) AND NOT EXISTS ( - SELECT 1 FROM authorizations a WHERE a.auth_key_id = k.auth_key_id + SELECT 1 FROM authorizations AS a WHERE a.auth_key_id = k.auth_key_id ) AND NOT EXISTS ( SELECT 1 - FROM temp_auth_key_bindings b + FROM temp_auth_key_bindings AS b WHERE b.temp_auth_key_id = k.auth_key_id OR b.perm_auth_key_id = k.auth_key_id ) - RETURNING k.auth_key_id +), deleted_update_states AS ( + DELETE FROM update_states AS state + USING still_orphaned AS orphan + WHERE state.auth_key_id = orphan.auth_key_id + RETURNING state.auth_key_id +), deleted_keys AS ( + DELETE FROM auth_keys AS key + USING still_orphaned AS orphan + WHERE key.auth_key_id = orphan.auth_key_id + RETURNING key.auth_key_id ) -SELECT count(*)::int +SELECT count(*)::integer FROM deleted_keys -CROSS JOIN LATERAL (SELECT count(*) FROM deleted_update_states) AS touched`, olderThan.Seconds(), protectedIDs, limit).Scan(&deleted) +CROSS JOIN LATERAL (SELECT count(*) FROM deleted_update_states) AS touched`, + olderThan.Seconds(), protectedIDs, lockedIDs, + ).Scan(&deleted) if err != nil { - return 0, fmt.Errorf("delete orphaned auth keys: %w", err) + return 0, fmt.Errorf("delete revalidated orphan auth keys: %w", err) } return deleted, nil } diff --git a/internal/store/postgres/authkey_integration_test.go b/internal/store/postgres/authkey_integration_test.go index 15599ee3..f3c7b86b 100644 --- a/internal/store/postgres/authkey_integration_test.go +++ b/internal/store/postgres/authkey_integration_test.go @@ -144,3 +144,69 @@ func TestAuthKeyStoreClientInfoRoundTrip(t *testing.T) { t.Fatalf("partial client info merge mismatch: %+v", got) } } + +func TestAuthKeyStoreUpdateClientInfoProtectsObservedLayerPostgres(t *testing.T) { + pool := testPool(t) + ctx := context.Background() + keys := NewAuthKeyStore(pool) + + var id [8]byte + var value [256]byte + if _, err := rand.Read(id[:]); err != nil { + t.Fatal(err) + } + if _, err := rand.Read(value[:]); err != nil { + t.Fatal(err) + } + t.Cleanup(func() { _ = keys.Delete(ctx, id) }) + if err := keys.Save(ctx, store.AuthKeyData{ID: id, Value: value}); err != nil { + t.Fatalf("save auth key: %v", err) + } + if _, err := pool.Exec(ctx, ` +UPDATE auth_keys +SET layer = 227, layer_observation_id = 91, + device_model = 'before', platform = 'tdesktop' +WHERE auth_key_id = $1`, authKeyIDToInt64(id)); err != nil { + t.Fatalf("seed ordered layer: %v", err) + } + + err := keys.UpdateClientInfo(ctx, id, store.AuthKeyClientInfo{ + Layer: 220, DeviceModel: "must-not-merge", AppVersion: "must-not-merge", + }) + if !errors.Is(err, store.ErrAuthKeySessionLayerConflict) { + t.Fatalf("conflicting layer update error = %v, want %v", err, store.ErrAuthKeySessionLayerConflict) + } + got, found, err := keys.Get(ctx, id) + if err != nil || !found { + t.Fatalf("get after conflict: found=%v err=%v", found, err) + } + if got.Layer != 227 || got.LayerObservationID != 91 || got.DeviceModel != "before" || + got.Platform != "tdesktop" || got.AppVersion != "" { + t.Fatalf("conflicting update changed row: %+v", got) + } + + if err := keys.UpdateClientInfo(ctx, id, store.AuthKeyClientInfo{ + Layer: 227, DeviceModel: "same-layer", AppVersion: "1.0", + }); err != nil { + t.Fatalf("same observed layer metadata merge: %v", err) + } + if err := keys.UpdateClientInfo(ctx, id, store.AuthKeyClientInfo{ + Platform: "windows", SystemVersion: "11", + }); err != nil { + t.Fatalf("layerless metadata merge: %v", err) + } + got, found, err = keys.Get(ctx, id) + if err != nil || !found { + t.Fatalf("get guarded metadata merge: found=%v err=%v", found, err) + } + if got.Layer != 227 || got.LayerObservationID != 91 || got.DeviceModel != "same-layer" || + got.Platform != "windows" || got.SystemVersion != "11" || got.AppVersion != "1.0" { + t.Fatalf("guarded metadata merge = %+v", got) + } + + missing := id + missing[0] ^= 0xff + if err := keys.UpdateClientInfo(ctx, missing, store.AuthKeyClientInfo{Layer: 227}); !errors.Is(err, store.ErrAuthKeyNotFound) { + t.Fatalf("missing primary update error = %v, want %v", err, store.ErrAuthKeyNotFound) + } +} diff --git a/internal/store/postgres/authkey_session_layer.go b/internal/store/postgres/authkey_session_layer.go new file mode 100644 index 00000000..c45b2567 --- /dev/null +++ b/internal/store/postgres/authkey_session_layer.go @@ -0,0 +1,245 @@ +package postgres + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/jackc/pgx/v5" + + "telesrv/internal/store" +) + +const maxAuthKeySessionLayerDeleteBatch = 100000 + +func (s *AuthKeyStore) GetSessionLayer( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, +) (store.AuthKeySessionLayer, bool, error) { + var value store.AuthKeySessionLayer + err := s.db.QueryRow(ctx, ` +SELECT evidence.layer, + evidence.msg_id, + evidence.observation_id, + evidence.expires_at, + defaults.layer = evidence.layer + AND defaults.layer_observation_id = evidence.observation_id +FROM auth_key_session_layers AS evidence +LEFT JOIN temp_auth_key_bindings AS binding + ON binding.temp_auth_key_id = evidence.raw_auth_key_id +JOIN auth_keys AS defaults + ON defaults.auth_key_id = COALESCE(binding.perm_auth_key_id, evidence.raw_auth_key_id) +WHERE evidence.raw_auth_key_id = $1 + AND evidence.session_id = $2 + AND evidence.expires_at > now() +`, authKeyIDToInt64(rawAuthKeyID), sessionID).Scan( + &value.Layer, + &value.MessageID, + &value.ObservationID, + &value.ExpiresAt, + &value.SharedDefault, + ) + if errors.Is(err, pgx.ErrNoRows) { + return store.AuthKeySessionLayer{}, false, nil + } + if err != nil { + return store.AuthKeySessionLayer{}, false, fmt.Errorf("get auth key session layer: %w", err) + } + return value, true, nil +} + +// AdvanceSessionLayer enters the permanent identity advisory gate before any +// row lock when rawAuthKeyID is permanent or already-bound temporary. An +// initially-unbound temp key that becomes bound while the raw row is acquired +// rolls the attempt back and retries in the new identity. The session watermark +// and every currently bound shared default then commit in one transaction. +func (s *AuthKeyStore) AdvanceSessionLayer( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, + layer int, + msgID int64, +) (store.AuthKeySessionLayer, bool, error) { + expiresAt, validMessageID := store.AuthKeySessionLayerExpiry(msgID) + if layer <= 0 || !validMessageID { + return store.AuthKeySessionLayer{}, false, store.ErrAuthKeySessionLayerInvalid + } + var ( + current store.AuthKeySessionLayer + applied bool + ) + err := withAuthIdentityTx(ctx, s.db, "advance auth key session layer", func(tx pgx.Tx) error { + var err error + current, applied, err = advanceSessionLayerTx( + ctx, tx, authKeyIDToInt64(rawAuthKeyID), sessionID, layer, msgID, expiresAt, + ) + return err + }) + if err != nil { + return current, false, err + } + return current, applied, nil +} + +func advanceSessionLayerTx( + ctx context.Context, + tx pgx.Tx, + rawID int64, + sessionID int64, + layer int, + msgID int64, + expiresAt time.Time, +) (store.AuthKeySessionLayer, bool, error) { + _, permID, _, err := lockRawAuthKeyInIdentityOrder(ctx, tx, rawID) + if err != nil { + return store.AuthKeySessionLayer{}, false, err + } + var ( + current store.AuthKeySessionLayer + now time.Time + ) + err = tx.QueryRow(ctx, ` +SELECT layer, msg_id, observation_id, expires_at, now() +FROM auth_key_session_layers +WHERE raw_auth_key_id = $1 AND session_id = $2 +FOR UPDATE +`, rawID, sessionID).Scan( + ¤t.Layer, + ¤t.MessageID, + ¤t.ObservationID, + ¤t.ExpiresAt, + &now, + ) + if errors.Is(err, pgx.ErrNoRows) { + if err := tx.QueryRow(ctx, `SELECT now()`).Scan(&now); err != nil { + return store.AuthKeySessionLayer{}, false, fmt.Errorf("read session layer database time: %w", err) + } + current = store.AuthKeySessionLayer{} + } else if err != nil { + return store.AuthKeySessionLayer{}, false, fmt.Errorf("lock auth key session layer: %w", err) + } + if _, fresh := store.AuthKeySessionLayerEvidenceFresh(now, msgID); !fresh { + return store.AuthKeySessionLayer{}, false, store.ErrAuthKeySessionLayerInvalid + } + if current.MessageID != 0 && now.Before(current.ExpiresAt) { + switch { + case msgID < current.MessageID: + if err := tx.QueryRow(ctx, ` +SELECT layer = $2 AND layer_observation_id = $3 +FROM auth_keys WHERE auth_key_id = $1 +`, permID, current.Layer, current.ObservationID).Scan(¤t.SharedDefault); err != nil { + return store.AuthKeySessionLayer{}, false, fmt.Errorf("compare older session layer with shared default: %w", err) + } + return current, false, nil + case msgID == current.MessageID: + if layer != current.Layer { + return current, false, store.ErrAuthKeySessionLayerConflict + } + if err := tx.QueryRow(ctx, ` +SELECT layer = $2 AND layer_observation_id = $3 +FROM auth_keys WHERE auth_key_id = $1 +`, permID, current.Layer, current.ObservationID).Scan(¤t.SharedDefault); err != nil { + return store.AuthKeySessionLayer{}, false, fmt.Errorf("compare duplicate session layer with shared default: %w", err) + } + return current, false, nil + } + } + + var observationID int64 + if err := tx.QueryRow(ctx, `SELECT nextval('auth_key_layer_observation_seq')`).Scan(&observationID); err != nil { + return store.AuthKeySessionLayer{}, false, fmt.Errorf("allocate auth key layer observation: %w", err) + } + err = tx.QueryRow(ctx, ` +INSERT INTO auth_key_session_layers ( + raw_auth_key_id, session_id, layer, msg_id, observation_id, expires_at +) VALUES ($1, $2, $3, $4, $5, $6) +ON CONFLICT (raw_auth_key_id, session_id) DO UPDATE SET + layer = EXCLUDED.layer, + msg_id = EXCLUDED.msg_id, + observation_id = EXCLUDED.observation_id, + expires_at = EXCLUDED.expires_at +RETURNING layer, msg_id, observation_id, expires_at +`, rawID, sessionID, layer, msgID, observationID, expiresAt).Scan( + ¤t.Layer, + ¤t.MessageID, + ¤t.ObservationID, + ¤t.ExpiresAt, + ) + if err != nil { + return store.AuthKeySessionLayer{}, false, fmt.Errorf("upsert auth key session layer: %w", err) + } + keyIDs := []int64{rawID} + if permID != rawID { + keyIDs = append(keyIDs, permID) + } + tag, err := tx.Exec(ctx, ` +UPDATE auth_keys +SET layer = $2, layer_observation_id = $3 +WHERE auth_key_id = ANY($1::bigint[]) + AND layer_observation_id < $3 +`, keyIDs, layer, observationID) + if err != nil { + return store.AuthKeySessionLayer{}, false, fmt.Errorf("publish auth key session layer defaults: %w", err) + } + if tag.RowsAffected() != int64(len(keyIDs)) { + return store.AuthKeySessionLayer{}, false, fmt.Errorf("publish auth key session layer defaults: updated %d of %d locked keys", tag.RowsAffected(), len(keyIDs)) + } + if _, err := tx.Exec(ctx, ` +UPDATE authorizations +SET layer = $2 +WHERE auth_key_id = ANY($1::bigint[]) +`, keyIDs, layer); err != nil { + return store.AuthKeySessionLayer{}, false, fmt.Errorf("mirror auth key session layer defaults: %w", err) + } + current.SharedDefault = true + return current, true, nil +} + +func (s *AuthKeyStore) DeleteSessionLayer( + ctx context.Context, + rawAuthKeyID [8]byte, + sessionID int64, +) (bool, error) { + tag, err := s.db.Exec(ctx, ` +DELETE FROM auth_key_session_layers +WHERE raw_auth_key_id = $1 AND session_id = $2 +`, authKeyIDToInt64(rawAuthKeyID), sessionID) + if err != nil { + return false, fmt.Errorf("delete auth key session layer: %w", err) + } + return tag.RowsAffected() > 0, nil +} + +func (s *AuthKeyStore) DeleteExpiredSessionLayers(ctx context.Context, limit int) (int, error) { + if limit <= 0 { + return 0, nil + } + if limit > maxAuthKeySessionLayerDeleteBatch { + limit = maxAuthKeySessionLayerDeleteBatch + } + var deleted int + err := s.db.QueryRow(ctx, ` +WITH candidates AS MATERIALIZED ( + SELECT raw_auth_key_id, session_id + FROM auth_key_session_layers + WHERE expires_at <= now() + ORDER BY expires_at, raw_auth_key_id, session_id + LIMIT $1 + FOR UPDATE SKIP LOCKED +), removed AS ( + DELETE FROM auth_key_session_layers AS evidence + USING candidates + WHERE evidence.raw_auth_key_id = candidates.raw_auth_key_id + AND evidence.session_id = candidates.session_id + AND evidence.expires_at <= now() + RETURNING 1 +) +SELECT count(*)::integer FROM removed +`, limit).Scan(&deleted) + if err != nil { + return 0, fmt.Errorf("delete expired auth key session layers: %w", err) + } + return deleted, nil +} diff --git a/internal/store/postgres/authkey_session_layer_integration_test.go b/internal/store/postgres/authkey_session_layer_integration_test.go new file mode 100644 index 00000000..55d89bda --- /dev/null +++ b/internal/store/postgres/authkey_session_layer_integration_test.go @@ -0,0 +1,140 @@ +package postgres + +import ( + "context" + "crypto/rand" + "encoding/binary" + "errors" + "sync" + "testing" + "time" + + "telesrv/internal/domain" + "telesrv/internal/store" +) + +func TestAuthKeySessionLayerTransactionAndRestartPostgres(t *testing.T) { + pool := testPool(t) + ctx := context.Background() + temp := randomLayerTestAuthKeyID(t) + perm := randomLayerTestAuthKeyID(t) + for perm == temp { + perm = randomLayerTestAuthKeyID(t) + } + const sessionID = int64(87001) + t.Cleanup(func() { + _ = NewAuthKeyStore(pool).Delete(ctx, perm) + _ = NewAuthKeyStore(pool).Delete(ctx, temp) + }) + + keys := NewAuthKeyStore(pool) + expiresAt := int(time.Now().Add(time.Hour).Unix()) + if err := keys.Save(ctx, store.AuthKeyData{ID: temp, ExpiresAt: expiresAt}); err != nil { + t.Fatal(err) + } + if err := keys.Save(ctx, store.AuthKeyData{ID: perm, ExpiresAt: 0}); err != nil { + t.Fatal(err) + } + now := time.Now().UTC() + firstMsgID := authKeySessionLayerTestMsgID(now, 1) + newerMsgID := authKeySessionLayerTestMsgID(now, 2) + concurrentLowMsgID := authKeySessionLayerTestMsgID(now, 3) + concurrentHighMsgID := authKeySessionLayerTestMsgID(now, 4) + for _, invalidMsgID := range []int64{ + authKeySessionLayerTestMsgID(now.Add(-302*time.Second), 1), + authKeySessionLayerTestMsgID(now.Add(31*time.Second), 1), + firstMsgID + 1, + } { + if _, _, err := keys.AdvanceSessionLayer(ctx, temp, sessionID, 220, invalidMsgID); !errors.Is(err, store.ErrAuthKeySessionLayerInvalid) { + t.Fatalf("invalid msg_id %d advance err = %v", invalidMsgID, err) + } + } + if _, found, err := keys.GetSessionLayer(ctx, temp, sessionID); err != nil || found { + t.Fatalf("rejected evidence created session row: found=%v err=%v", found, err) + } + first, applied, err := keys.AdvanceSessionLayer(ctx, temp, sessionID, 220, firstMsgID) + if err != nil || !applied || !first.SharedDefault || first.ObservationID <= 0 { + t.Fatalf("first advance = (%+v,%v,%v)", first, applied, err) + } + if err := NewTempAuthKeyBindingStore(pool).Save(ctx, domain.TempAuthKeyBinding{ + TempAuthKeyID: temp, + PermAuthKeyID: int64(binary.LittleEndian.Uint64(perm[:])), + Nonce: 87, + TempSessionID: sessionID, + ExpiresAt: expiresAt, + EncryptedMessage: []byte{8, 7}, + }); err != nil { + t.Fatal(err) + } + for _, id := range [][8]byte{temp, perm} { + got, found, err := NewAuthKeyStore(pool).Get(ctx, id) + if err != nil || !found || got.Layer != 220 || got.LayerObservationID != first.ObservationID { + t.Fatalf("bound default %x = (%+v,%v,%v)", id, got, found, err) + } + } + + newer, applied, err := NewAuthKeyStore(pool).AdvanceSessionLayer(ctx, temp, sessionID, 227, newerMsgID) + if err != nil || !applied || !newer.SharedDefault || newer.ObservationID <= first.ObservationID { + t.Fatalf("newer advance = (%+v,%v,%v)", newer, applied, err) + } + old, applied, err := NewAuthKeyStore(pool).AdvanceSessionLayer(ctx, temp, sessionID, 220, firstMsgID) + if err != nil || applied || old.Layer != 227 || old.MessageID != newerMsgID || !old.SharedDefault { + t.Fatalf("old replay = (%+v,%v,%v)", old, applied, err) + } + if _, _, err := NewAuthKeyStore(pool).AdvanceSessionLayer(ctx, temp, sessionID, 220, newerMsgID); !errors.Is(err, store.ErrAuthKeySessionLayerConflict) { + t.Fatalf("same-msg conflict = %v", err) + } + + // Two independent store instances model two server processes. The raw-key + // row lock and session CAS must converge on the greater selector msg_id. + type candidate struct { + layer int + msgID int64 + } + candidates := []candidate{{layer: 225, msgID: concurrentLowMsgID}, {layer: 227, msgID: concurrentHighMsgID}} + start := make(chan struct{}) + errs := make(chan error, len(candidates)) + var wg sync.WaitGroup + for _, item := range candidates { + item := item + wg.Add(1) + go func() { + defer wg.Done() + <-start + _, _, err := NewAuthKeyStore(pool).AdvanceSessionLayer(ctx, temp, sessionID, item.layer, item.msgID) + errs <- err + }() + } + close(start) + wg.Wait() + close(errs) + for err := range errs { + if err != nil { + t.Fatal(err) + } + } + restarted := NewAuthKeyStore(pool) + current, found, err := restarted.GetSessionLayer(ctx, temp, sessionID) + if err != nil || !found || current.Layer != 227 || current.MessageID != concurrentHighMsgID || !current.SharedDefault { + t.Fatalf("restart authoritative row = (%+v,%v,%v)", current, found, err) + } + for _, id := range [][8]byte{temp, perm} { + got, found, err := restarted.Get(ctx, id) + if err != nil || !found || got.Layer != 227 || got.LayerObservationID != current.ObservationID { + t.Fatalf("transactional shared default %x = (%+v,%v,%v)", id, got, found, err) + } + } +} + +func authKeySessionLayerTestMsgID(at time.Time, order uint32) int64 { + return int64((uint64(at.Unix()) << 32) | uint64(order)<<2) +} + +func randomLayerTestAuthKeyID(t *testing.T) [8]byte { + t.Helper() + var id [8]byte + if _, err := rand.Read(id[:]); err != nil { + t.Fatal(err) + } + return id +} diff --git a/internal/store/postgres/authorization.go b/internal/store/postgres/authorization.go index f3adee28..c0000d6c 100644 --- a/internal/store/postgres/authorization.go +++ b/internal/store/postgres/authorization.go @@ -29,17 +29,9 @@ func (s *AuthorizationStore) Bind(ctx context.Context, a domain.Authorization) e if a.Hash == 0 { a.Hash = authorizationHash(a.AuthKeyID) } - bind := func(db sqlcgen.DBTX) error { - return bindAuthorization(ctx, db, a) - } - var err error - if tx, ok := s.db.(pgx.Tx); ok { - err = bind(tx) - } else { - err = withTx(ctx, s.db, "bind authorization", func(tx pgx.Tx) error { - return bind(tx) - }) - } + err := withAuthIdentityTx(ctx, s.db, "bind authorization", func(tx pgx.Tx) error { + return bindAuthorization(ctx, tx, a) + }) if err != nil { return fmt.Errorf("upsert authorization: %w", err) } @@ -55,20 +47,35 @@ func (s *AuthorizationStore) Bind(ctx context.Context, a domain.Authorization) e // raw auth key 的并发登录/换号。 func bindAuthorization(ctx context.Context, db sqlcgen.DBTX, a domain.Authorization) error { keyID := authKeyIDToInt64(a.AuthKeyID) + tx, ok := db.(pgx.Tx) + if !ok { + return fmt.Errorf("bind authorization requires a transaction") + } + if err := lockPermanentAuthIdentities(ctx, tx, []int64{keyID}); err != nil { + return err + } var ( - lockedKeyID int64 - expiresAt int + lockedKeyID int64 + expiresAt int + authLayer int + layerObservationID int64 ) if err := db.QueryRow(ctx, ` -SELECT auth_key_id, expires_at +SELECT auth_key_id, expires_at, layer, layer_observation_id FROM auth_keys WHERE auth_key_id = $1 -FOR UPDATE`, keyID).Scan(&lockedKeyID, &expiresAt); err != nil { +FOR UPDATE`, keyID).Scan(&lockedKeyID, &expiresAt, &authLayer, &layerObservationID); err != nil { return fmt.Errorf("lock auth key for authorization: %w", err) } if expiresAt != 0 { return store.ErrAuthKeyNotPermanent } + if authLayer < 0 || layerObservationID < 0 || (layerObservationID > 0 && authLayer == 0) { + return fmt.Errorf( + "authorization auth-key layer invariant violation: auth key %x has layer %d observation %d", + a.AuthKeyID, authLayer, layerObservationID, + ) + } if _, err := db.Exec(ctx, ` INSERT INTO user_update_watermarks (user_id, contiguous_pts) @@ -154,7 +161,7 @@ ON CONFLICT (auth_key_id) DO UPDATE SET ip = EXCLUDED.ip, password_pending = EXCLUDED.password_pending, active_at = now()`, - keyID, a.UserID, a.Hash, int32(a.Layer), a.DeviceModel, a.Platform, a.SystemVersion, int32(a.APIID), a.AppVersion, a.IP, a.PasswordPending, + keyID, a.UserID, a.Hash, int32(authLayer), a.DeviceModel, a.Platform, a.SystemVersion, int32(a.APIID), a.AppVersion, a.IP, a.PasswordPending, ); err != nil { return fmt.Errorf("write authorization: %w", err) } @@ -178,18 +185,6 @@ FROM authorizations WHERE auth_key_id = $1`, authKeyIDToInt64(id)) return a, true, nil } -func (s *AuthorizationStore) UpdateLayer(ctx context.Context, id [8]byte, layer int) error { - if layer <= 0 { - return nil - } - if _, err := s.db.Exec(ctx, ` -UPDATE authorizations SET layer = $2, active_at = now() WHERE auth_key_id = $1`, - authKeyIDToInt64(id), int32(layer)); err != nil { - return fmt.Errorf("update authorization layer: %w", err) - } - return nil -} - func (s *AuthorizationStore) UpdateClientInfo(ctx context.Context, id [8]byte, info domain.AuthKeyClientInfo) error { if _, err := s.db.Exec(ctx, ` UPDATE authorizations SET @@ -261,34 +256,19 @@ RETURNING auth_key_id, user_id, hash, layer, device_model, platform, system_vers // authorizations 通过 FK cascade 删除;update_states 没有 auth_keys FK,必须显式清理; // 关联 temp auth key 也显式删除,避免 raw temp key 重连。 func (s *AuthorizationStore) RevokeByHash(ctx context.Context, userID, hash int64) (domain.Authorization, bool, error) { - for attempt := 0; attempt < 3; attempt++ { - var ( - a domain.Authorization - found bool - ) - err := s.withRevocationTx(ctx, "revoke authorization by hash", func(tx pgx.Tx) error { - var err error - a, found, err = revokeByHashTx(ctx, tx, userID, hash) - return err - }) - if err == nil { - return a, found, nil - } - if !isPermAuthKeyDeleteRace(err) { - return domain.Authorization{}, false, err - } - if _, inTx := s.db.(pgx.Tx); inTx { - return domain.Authorization{}, false, err - } + var ( + a domain.Authorization + found bool + ) + err := withAuthIdentityTx(ctx, s.db, "revoke authorization by hash", func(tx pgx.Tx) error { + var err error + a, found, err = revokeByHashTx(ctx, tx, userID, hash) + return err + }) + if err != nil { + return domain.Authorization{}, false, err } - return domain.Authorization{}, false, fmt.Errorf("revoke authorization by hash: permanent-key binding changed during all retries") -} - -func (s *AuthorizationStore) withRevocationTx(ctx context.Context, op string, fn func(pgx.Tx) error) error { - if tx, ok := s.db.(pgx.Tx); ok { - return fn(tx) - } - return withTx(ctx, s.db, op, fn) + return a, found, nil } // revokeByHashTx deliberately uses separate READ COMMITTED statements. The first @@ -307,6 +287,9 @@ WHERE user_id = $1 AND hash = $2`, userID, hash).Scan(&candidate); err != nil { } return domain.Authorization{}, false, fmt.Errorf("select revoke candidate by hash: %w", err) } + if err := lockPermanentAuthIdentities(ctx, tx, []int64{candidate}); err != nil { + return domain.Authorization{}, false, err + } var locked int64 if err := tx.QueryRow(ctx, ` @@ -368,24 +351,13 @@ RETURNING auth_key_id, user_id, hash, layer, device_model, platform, system_vers // RevokeByUserExcept 批量删除协议 auth_key,保留 keepAuthKeyID 对应的当前设备。 func (s *AuthorizationStore) RevokeByUserExcept(ctx context.Context, userID int64, keepAuthKeyID [8]byte) ([]domain.Authorization, error) { - for attempt := 0; attempt < 3; attempt++ { - var out []domain.Authorization - err := s.withRevocationTx(ctx, "revoke authorizations by user", func(tx pgx.Tx) error { - var err error - out, err = revokeByUserExceptTx(ctx, tx, userID, authKeyIDToInt64(keepAuthKeyID)) - return err - }) - if err == nil { - return out, nil - } - if !isPermAuthKeyDeleteRace(err) { - return nil, err - } - if _, inTx := s.db.(pgx.Tx); inTx { - return nil, err - } - } - return nil, fmt.Errorf("revoke authorizations by user: permanent-key binding changed during all retries") + var out []domain.Authorization + err := withAuthIdentityTx(ctx, s.db, "revoke authorizations by user", func(tx pgx.Tx) error { + var err error + out, err = revokeByUserExceptTx(ctx, tx, userID, authKeyIDToInt64(keepAuthKeyID)) + return err + }) + return out, err } func revokeByUserExceptTx(ctx context.Context, tx pgx.Tx, userID, keepAuthKeyID int64) ([]domain.Authorization, error) { @@ -414,9 +386,12 @@ ORDER BY auth_key_id`, userID, keepAuthKeyID) if len(candidates) == 0 { return []domain.Authorization{}, nil } + if err := lockPermanentAuthIdentities(ctx, tx, candidates); err != nil { + return nil, err + } - // Stable parent-row lock order matches every concurrent batch revocation and - // serializes each candidate with Bind's auth_keys-first ownership change. + // Advisory keys are already all held in final int32-hash order. Parent rows + // are then locked by their real bigint IDs for deterministic batch behavior. lockRows, err := tx.Query(ctx, ` SELECT auth_key_id FROM auth_keys diff --git a/internal/store/postgres/temp_auth_key.go b/internal/store/postgres/temp_auth_key.go index 75ace452..48cbdb92 100644 --- a/internal/store/postgres/temp_auth_key.go +++ b/internal/store/postgres/temp_auth_key.go @@ -16,19 +16,99 @@ import ( // TempAuthKeyBindingStore 用 PostgreSQL 实现 store.TempAuthKeyBindingStore。 type TempAuthKeyBindingStore struct { - q *sqlcgen.Queries + db sqlcgen.DBTX + q *sqlcgen.Queries } // NewTempAuthKeyBindingStore 基于 pgx 连接池(或事务)创建 TempAuthKeyBindingStore。 func NewTempAuthKeyBindingStore(db sqlcgen.DBTX) *TempAuthKeyBindingStore { - return &TempAuthKeyBindingStore{q: sqlcgen.New(db)} + return &TempAuthKeyBindingStore{db: db, q: sqlcgen.New(db)} } func (s *TempAuthKeyBindingStore) Save(ctx context.Context, b domain.TempAuthKeyBinding) error { if b.ExpiresAt <= 0 || int64(b.ExpiresAt) > math.MaxInt32 { return store.ErrAuthKeyBindingInvalid } - n, err := s.q.UpsertTempAuthKeyBinding(ctx, sqlcgen.UpsertTempAuthKeyBindingParams{ + return withAuthIdentityTx(ctx, s.db, "save temp auth key binding", func(tx pgx.Tx) error { + return s.saveTx(ctx, tx, b) + }) +} + +func (s *TempAuthKeyBindingStore) saveTx(ctx context.Context, tx pgx.Tx, b domain.TempAuthKeyBinding) error { + rawID := authKeyIDToInt64(b.TempAuthKeyID) + permID := b.PermAuthKeyID + // Every operation that may bridge temp and permanent rows enters the + // permanent identity gate before taking the raw-key row lock. This is the + // same gate/order used by selector advance and permanent revocation. + if err := lockPermanentAuthIdentities(ctx, tx, []int64{permID}); err != nil { + return err + } + var ( + tempExpiry int + tempLayer int + tempObservationID int64 + ) + if err := tx.QueryRow(ctx, ` +SELECT expires_at, layer, layer_observation_id +FROM auth_keys +WHERE auth_key_id = $1 +FOR UPDATE +`, rawID).Scan(&tempExpiry, &tempLayer, &tempObservationID); err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return store.ErrAuthKeyBindingInvalid + } + return fmt.Errorf("lock temporary auth key for binding: %w", err) + } + if tempExpiry <= 0 || tempExpiry != b.ExpiresAt || rawID == permID { + return store.ErrAuthKeyBindingInvalid + } + + // The raw row serializes first bind and rebind attempts. Read the binding + // only after taking that lock, so a concurrent winner is either visible or + // still waiting behind us. A different permanent identity is immutable. + var currentPermID int64 + err := tx.QueryRow(ctx, ` +SELECT perm_auth_key_id +FROM temp_auth_key_bindings +WHERE temp_auth_key_id = $1 +`, rawID).Scan(¤tPermID) + switch { + case err == nil && currentPermID != permID: + return store.ErrTempAuthKeyAlreadyBound + case err != nil && !errors.Is(err, pgx.ErrNoRows): + return fmt.Errorf("read existing temporary auth key binding: %w", err) + } + + var ( + permExpiry int + permLayer int + permObservationID int64 + ) + if err := tx.QueryRow(ctx, ` +SELECT expires_at, layer, layer_observation_id +FROM auth_keys +WHERE auth_key_id = $1 +FOR UPDATE +`, permID).Scan(&permExpiry, &permLayer, &permObservationID); err != nil { + if errors.Is(err, pgx.ErrNoRows) { + return store.ErrAuthKeyBindingInvalid + } + return fmt.Errorf("lock permanent auth key for binding: %w", err) + } + if permExpiry != 0 { + return store.ErrAuthKeyBindingInvalid + } + + mergedLayer, mergedObservationID, err := store.MergeAuthKeyLayerObservations( + tempLayer, tempObservationID, + permLayer, permObservationID, + ) + if err != nil { + return err + } + + q := s.q.WithTx(tx) + n, err := q.UpsertTempAuthKeyBinding(ctx, sqlcgen.UpsertTempAuthKeyBindingParams{ TempAuthKeyID: authKeyIDToInt64(b.TempAuthKeyID), PermAuthKeyID: b.PermAuthKeyID, Nonce: b.Nonce, @@ -44,13 +124,28 @@ func (s *TempAuthKeyBindingStore) Save(ctx context.Context, b domain.TempAuthKey return fmt.Errorf("upsert temp auth key binding: %w", err) } if n == 0 { - if current, found, getErr := s.GetByTemp(ctx, b.TempAuthKeyID); getErr != nil { - return getErr - } else if found && current.PermAuthKeyID != b.PermAuthKeyID { - return store.ErrTempAuthKeyAlreadyBound - } return store.ErrAuthKeyBindingInvalid } + keyIDs := []int64{rawID, permID} + tag, err := tx.Exec(ctx, ` +UPDATE auth_keys +SET layer = $2, + layer_observation_id = $3 +WHERE auth_key_id = ANY($1::bigint[]) +`, keyIDs, mergedLayer, mergedObservationID) + if err != nil { + return fmt.Errorf("merge bound auth key layer defaults: %w", err) + } + if tag.RowsAffected() != int64(len(keyIDs)) { + return fmt.Errorf("merge bound auth key layer defaults: updated %d of %d locked keys", tag.RowsAffected(), len(keyIDs)) + } + if _, err := tx.Exec(ctx, ` +UPDATE authorizations +SET layer = $2 +WHERE auth_key_id = ANY($1::bigint[]) +`, keyIDs, mergedLayer); err != nil { + return fmt.Errorf("mirror bound auth key layer default: %w", err) + } return nil } diff --git a/internal/store/postgres/temp_auth_key_identity_integration_test.go b/internal/store/postgres/temp_auth_key_identity_integration_test.go index 79605a87..7c23b795 100644 --- a/internal/store/postgres/temp_auth_key_identity_integration_test.go +++ b/internal/store/postgres/temp_auth_key_identity_integration_test.go @@ -11,7 +11,6 @@ import ( "testing" "time" - "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgconn" "github.com/jackc/pgx/v5/pgxpool" @@ -133,6 +132,90 @@ func TestTempAuthKeyBindingStorePreservesHandshakeExpiryAndRejectsRebindPostgres assertTempIdentityAuthKeyExpiry(t, ctx, keys, temp, handshakeExpiry) } +func TestTempAuthKeyBindingStoreAtomicallyMergesLayerObservationsPostgres(t *testing.T) { + pool := testPool(t) + ctx := context.Background() + tests := []struct { + name string + tempLayer int + tempObs int64 + permLayer int + permObs int64 + wantLayer int + wantObs int64 + wantErr error + }{ + {name: "temporary newer", tempLayer: 227, tempObs: 20, permLayer: 220, permObs: 10, wantLayer: 227, wantObs: 20}, + {name: "permanent newer", tempLayer: 220, tempObs: 10, permLayer: 227, permObs: 20, wantLayer: 227, wantObs: 20}, + {name: "equal ordered same layer", tempLayer: 225, tempObs: 30, permLayer: 225, permObs: 30, wantLayer: 225, wantObs: 30}, + {name: "equal ordered conflict", tempLayer: 220, tempObs: 30, permLayer: 227, permObs: 30, wantErr: store.ErrAuthKeySessionLayerConflict}, + {name: "legacy permanent wins", tempLayer: 220, permLayer: 227, wantLayer: 227}, + } + for i, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + userID := createRevokeTestUser(t, ctx, pool, fmt.Sprintf("layer-merge-%d", i)) + keys := NewAuthKeyStore(pool) + bindings := NewTempAuthKeyBindingStore(pool) + auths := NewAuthorizationStore(pool) + handshakeExpiry := int(time.Now().Add(time.Hour).Unix()) + i + tempID := saveTempIdentityTestAuthKey(t, ctx, pool, keys, handshakeExpiry) + permID := saveTempIdentityTestAuthKey(t, ctx, pool, keys, 0) + if err := auths.Bind(ctx, domain.Authorization{ + AuthKeyID: permID, UserID: userID, Layer: tt.permLayer, + }); err != nil { + t.Fatalf("bind permanent authorization: %v", err) + } + if _, err := pool.Exec(ctx, ` +UPDATE auth_keys SET layer = $2, layer_observation_id = $3 +WHERE auth_key_id = $1`, authKeyIDToInt64(tempID), tt.tempLayer, tt.tempObs); err != nil { + t.Fatalf("seed temporary layer observation: %v", err) + } + if _, err := pool.Exec(ctx, ` +UPDATE auth_keys SET layer = $2, layer_observation_id = $3 +WHERE auth_key_id = $1`, authKeyIDToInt64(permID), tt.permLayer, tt.permObs); err != nil { + t.Fatalf("seed permanent layer observation: %v", err) + } + if _, err := pool.Exec(ctx, ` +UPDATE authorizations SET layer = $2 WHERE auth_key_id = $1`, authKeyIDToInt64(permID), tt.permLayer); err != nil { + t.Fatalf("seed authorization layer mirror: %v", err) + } + + binding := domain.TempAuthKeyBinding{ + TempAuthKeyID: tempID, + PermAuthKeyID: authKeyIDToInt64(permID), + Nonce: int64(1_000 + i), + TempSessionID: int64(2_000 + i), + ExpiresAt: handshakeExpiry, + EncryptedMessage: []byte("layer merge proof"), + } + err := bindings.Save(ctx, binding) + if tt.wantErr != nil { + if !errors.Is(err, tt.wantErr) { + t.Fatalf("bind error = %v, want %v", err, tt.wantErr) + } + if _, found, getErr := bindings.GetByTemp(ctx, tempID); getErr != nil || found { + t.Fatalf("conflicting binding found=%v err=%v, want absent", found, getErr) + } + assertTempIdentityLayerTuple(t, ctx, pool, tempID, tt.tempLayer, tt.tempObs) + assertTempIdentityLayerTuple(t, ctx, pool, permID, tt.permLayer, tt.permObs) + assertTempIdentityAuthorizationLayer(t, ctx, pool, permID, tt.permLayer) + return + } + if err != nil { + t.Fatalf("bind: %v", err) + } + // A normalized proof replay is idempotent and repeats the same merge. + binding.Nonce++ + if err := bindings.Save(ctx, binding); err != nil { + t.Fatalf("replay merged binding: %v", err) + } + assertTempIdentityLayerTuple(t, ctx, pool, tempID, tt.wantLayer, tt.wantObs) + assertTempIdentityLayerTuple(t, ctx, pool, permID, tt.wantLayer, tt.wantObs) + assertTempIdentityAuthorizationLayer(t, ctx, pool, permID, tt.wantLayer) + }) + } +} + func TestTempAuthKeyBindingStoreConcurrentFirstBindKeepsHandshakeExpiryPostgres(t *testing.T) { pool := testPool(t) ctx := context.Background() @@ -303,131 +386,6 @@ func TestTempAuthKeyBindingConcurrentWithPermanentDeleteLeavesNoDanglingStatePos } } -func TestAuthKeyStoreDeleteRetriesDeterministicPermanentBindingFKRacePostgres(t *testing.T) { - pool := testPool(t) - testCtx, cancel := context.WithTimeout(context.Background(), 15*time.Second) - t.Cleanup(cancel) - keys := NewAuthKeyStore(pool) - bindings := NewTempAuthKeyBindingStore(pool) - auths := NewAuthorizationStore(pool) - - handshakeExpiry := int(time.Now().Add(time.Hour).Unix()) - temp := saveTempIdentityTestAuthKey(t, testCtx, pool, keys, handshakeExpiry) - perm := saveTempIdentityTestAuthKey(t, testCtx, pool, keys, 0) - userID := createRevokeTestUser(t, testCtx, pool, "deterministic-bind-delete-race") - if err := auths.Bind(testCtx, domain.Authorization{ - AuthKeyID: perm, - UserID: userID, - Hash: 9401, - }); err != nil { - t.Fatalf("bind permanent authorization: %v", err) - } - candidate := domain.TempAuthKeyBinding{ - TempAuthKeyID: temp, - PermAuthKeyID: authKeyIDToInt64(perm), - Nonce: 901, - TempSessionID: 902, - ExpiresAt: handshakeExpiry, - EncryptedMessage: []byte("deterministic FK retry barrier"), - } - - deleteConn, err := pool.Acquire(testCtx) - if err != nil { - t.Fatalf("acquire dedicated delete connection: %v", err) - } - defer deleteConn.Release() - var deletePID int - if err := deleteConn.QueryRow(testCtx, "SELECT pg_backend_pid()").Scan(&deletePID); err != nil { - t.Fatalf("get delete backend pid: %v", err) - } - - blocker, err := pool.Begin(testCtx) - if err != nil { - t.Fatalf("begin key-share blocker: %v", err) - } - defer func() { _ = blocker.Rollback(context.Background()) }() - var lockedPermID int64 - if err := blocker.QueryRow(testCtx, ` -SELECT auth_key_id -FROM auth_keys -WHERE auth_key_id = $1 -FOR KEY SHARE`, authKeyIDToInt64(perm)).Scan(&lockedPermID); err != nil { - t.Fatalf("lock permanent key FOR KEY SHARE: %v", err) - } - if lockedPermID != authKeyIDToInt64(perm) { - t.Fatalf("locked permanent key = %d, want %d", lockedPermID, authKeyIDToInt64(perm)) - } - - observedDeleteDB := &permanentKeyFKRetryObservingDB{Conn: deleteConn} - deleteResult := make(chan error, 1) - go func() { - deleteResult <- NewAuthKeyStore(observedDeleteDB).Delete(testCtx, perm) - }() - waitForPostgresBackendLockWait(t, testCtx, pool, deletePID) - - // This transaction already owns the compatible KEY SHARE lock needed by the - // FK check, so it can commit a new binding while the first DELETE statement - // remains blocked with a snapshot that cannot see that binding. - if err := NewTempAuthKeyBindingStore(blocker).Save(testCtx, candidate); err != nil { - t.Fatalf("save binding behind delete snapshot barrier: %v", err) - } - if err := blocker.Commit(testCtx); err != nil { - t.Fatalf("commit binding and release delete blocker: %v", err) - } - - select { - case err := <-deleteResult: - if err != nil { - t.Fatalf("delete after deterministic FK retry: %v", err) - } - case <-testCtx.Done(): - t.Fatalf("delete did not finish after releasing FK barrier: %v", testCtx.Err()) - } - if observedDeleteDB.attempts != 2 || observedDeleteDB.fkViolations != 1 { - t.Fatalf( - "delete attempts/FK violations = %d/%d, want 2/1", - observedDeleteDB.attempts, - observedDeleteDB.fkViolations, - ) - } - - if _, found, err := bindings.GetByTemp(testCtx, temp); err != nil || found { - t.Fatalf("binding after deterministic retry found=%v err=%v, want absent", found, err) - } - assertTempIdentityAuthKeyMissing(t, testCtx, keys, temp) - assertTempIdentityAuthKeyMissing(t, testCtx, keys, perm) - assertRevokeTestNoAuthorization(t, testCtx, auths, perm) -} - -type permanentKeyFKRetryObservingDB struct { - *pgxpool.Conn - attempts int - fkViolations int -} - -func (db *permanentKeyFKRetryObservingDB) QueryRow(ctx context.Context, sql string, args ...interface{}) pgx.Row { - db.attempts++ - return &permanentKeyFKRetryObservingRow{Row: db.Conn.QueryRow(ctx, sql, args...), db: db} -} - -func (db *permanentKeyFKRetryObservingDB) observeFKViolation(err error) { - var pgErr *pgconn.PgError - if errors.As(err, &pgErr) && pgErr.Code == "23503" && pgErr.ConstraintName == tempAuthKeyPermFKConstraint { - db.fkViolations++ - } -} - -type permanentKeyFKRetryObservingRow struct { - pgx.Row - db *permanentKeyFKRetryObservingDB -} - -func (row *permanentKeyFKRetryObservingRow) Scan(dest ...any) error { - err := row.Row.Scan(dest...) - row.db.observeFKViolation(err) - return err -} - func waitForPostgresBackendLockWait( t *testing.T, ctx context.Context, @@ -552,3 +510,47 @@ func assertTempIdentityAuthKeyMissing( t.Fatalf("auth key %x found=%v err=%v, want absent", id, found, err) } } + +func assertTempIdentityLayerTuple( + t *testing.T, + ctx context.Context, + pool *pgxpool.Pool, + authKeyID [8]byte, + wantLayer int, + wantObservationID int64, +) { + t.Helper() + var ( + layer int + observationID int64 + ) + if err := pool.QueryRow(ctx, ` +SELECT layer, layer_observation_id +FROM auth_keys +WHERE auth_key_id = $1`, authKeyIDToInt64(authKeyID)).Scan(&layer, &observationID); err != nil { + t.Fatalf("read auth-key layer tuple: %v", err) + } + if layer != wantLayer || observationID != wantObservationID { + t.Fatalf("auth-key layer tuple = (%d,%d), want (%d,%d)", layer, observationID, wantLayer, wantObservationID) + } +} + +func assertTempIdentityAuthorizationLayer( + t *testing.T, + ctx context.Context, + pool *pgxpool.Pool, + authKeyID [8]byte, + wantLayer int, +) { + t.Helper() + var layer int + if err := pool.QueryRow(ctx, ` +SELECT layer +FROM authorizations +WHERE auth_key_id = $1`, authKeyIDToInt64(authKeyID)).Scan(&layer); err != nil { + t.Fatalf("read authorization layer mirror: %v", err) + } + if layer != wantLayer { + t.Fatalf("authorization layer mirror = %d, want %d", layer, wantLayer) + } +} diff --git a/internal/store/postgres/updatestate.go b/internal/store/postgres/updatestate.go index 2d486fd1..343c0102 100644 --- a/internal/store/postgres/updatestate.go +++ b/internal/store/postgres/updatestate.go @@ -55,16 +55,39 @@ func (s *UpdateStateStore) Save(ctx context.Context, id [8]byte, userID int64, s return nil } +func (s *UpdateStateStore) CommitDeliveredState(ctx context.Context, id [8]byte, userID int64, st domain.UpdateState, mode domain.UpdateStateCommitMode) error { + establishObserved := mode == domain.UpdateStateCommitDeliveredAndObservedBaseline + if mode != domain.UpdateStateCommitDeliveredOnly && !establishObserved { + return fmt.Errorf("commit delivered update state: invalid mode %d", mode) + } + if _, err := s.db.Exec(ctx, ` +INSERT INTO update_states (auth_key_id, user_id, pts, qts, date, seq, observed_pts) +VALUES ($1, $2, $3, $4, $5, $6, CASE WHEN $7 THEN $3 ELSE 0 END) +ON CONFLICT (auth_key_id, user_id) DO UPDATE SET + pts = GREATEST(update_states.pts, EXCLUDED.pts), + qts = GREATEST(update_states.qts, EXCLUDED.qts), + date = GREATEST(update_states.date, EXCLUDED.date), + seq = GREATEST(update_states.seq, EXCLUDED.seq), + observed_pts = CASE + WHEN $7 THEN GREATEST(update_states.observed_pts, EXCLUDED.observed_pts) + ELSE update_states.observed_pts + END, + updated_at = now()`, authKeyIDToInt64(id), userID, st.Pts, st.Qts, st.Date, st.Seq, establishObserved); err != nil { + return fmt.Errorf("commit delivered update state: %w", err) + } + return nil +} + func (s *UpdateStateStore) ObserveClientState(ctx context.Context, id [8]byte, userID int64, st domain.UpdateState) error { if st.Pts < 0 { st.Pts = 0 } if _, err := s.db.Exec(ctx, ` INSERT INTO update_states (auth_key_id, user_id, pts, qts, date, seq, observed_pts) -VALUES ($1, $2, $3, $4, $5, $6, $3) +VALUES ($1, $2, 0, 0, 0, 0, $3) ON CONFLICT (auth_key_id, user_id) DO UPDATE SET observed_pts = GREATEST(update_states.observed_pts, EXCLUDED.observed_pts), - updated_at = now()`, authKeyIDToInt64(id), userID, st.Pts, st.Qts, st.Date, st.Seq); err != nil { + updated_at = now()`, authKeyIDToInt64(id), userID, st.Pts); err != nil { return fmt.Errorf("observe client update state: %w", err) } return nil diff --git a/internal/store/postgres/updatestate_delivery_test.go b/internal/store/postgres/updatestate_delivery_test.go new file mode 100644 index 00000000..f775397c --- /dev/null +++ b/internal/store/postgres/updatestate_delivery_test.go @@ -0,0 +1,79 @@ +package postgres + +import ( + "context" + "strings" + "testing" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" + + "telesrv/internal/domain" +) + +type captureUpdateStateDB struct { + sql string + args []any +} + +func (d *captureUpdateStateDB) Exec(_ context.Context, sql string, args ...any) (pgconn.CommandTag, error) { + d.sql = sql + d.args = append([]any(nil), args...) + return pgconn.NewCommandTag("INSERT 0 1"), nil +} + +func (*captureUpdateStateDB) Query(context.Context, string, ...any) (pgx.Rows, error) { + panic("unexpected Query") +} + +func (*captureUpdateStateDB) QueryRow(context.Context, string, ...any) pgx.Row { + panic("unexpected QueryRow") +} + +func TestCommitDeliveredStateUsesOneAtomicBaselineUpsert(t *testing.T) { + db := &captureUpdateStateDB{} + store := NewUpdateStateStore(db) + state := domain.UpdateState{Pts: 9, Qts: 2, Date: 90, Seq: 3} + if err := store.CommitDeliveredState(context.Background(), [8]byte{4}, 1004, state, domain.UpdateStateCommitDeliveredAndObservedBaseline); err != nil { + t.Fatalf("commit baseline: %v", err) + } + if len(db.args) != 7 || db.args[6] != true { + t.Fatalf("baseline args = %#v, want final true mode", db.args) + } + for _, fragment := range []string{ + "pts = GREATEST(update_states.pts, EXCLUDED.pts)", + "WHEN $7 THEN GREATEST(update_states.observed_pts, EXCLUDED.observed_pts)", + } { + if !strings.Contains(db.sql, fragment) { + t.Fatalf("atomic commit SQL missing %q:\n%s", fragment, db.sql) + } + } +} + +func TestCommitDeliveredOnlyLeavesObservedUntouched(t *testing.T) { + db := &captureUpdateStateDB{} + store := NewUpdateStateStore(db) + if err := store.CommitDeliveredState(context.Background(), [8]byte{5}, 1005, domain.UpdateState{Pts: 7}, domain.UpdateStateCommitDeliveredOnly); err != nil { + t.Fatalf("commit delivered-only: %v", err) + } + if len(db.args) != 7 || db.args[6] != false { + t.Fatalf("delivered-only args = %#v, want final false mode", db.args) + } + if !strings.Contains(db.sql, "ELSE update_states.observed_pts") { + t.Fatalf("delivered-only SQL can overwrite observed:\n%s", db.sql) + } +} + +func TestObserveClientStateDoesNotFabricateConfirmedCursor(t *testing.T) { + db := &captureUpdateStateDB{} + store := NewUpdateStateStore(db) + if err := store.ObserveClientState(context.Background(), [8]byte{6}, 1006, domain.UpdateState{Pts: 11, Qts: 4, Date: 110, Seq: 2}); err != nil { + t.Fatalf("observe request: %v", err) + } + if !strings.Contains(db.sql, "VALUES ($1, $2, 0, 0, 0, 0, $3)") { + t.Fatalf("observed-only insert fabricated confirmed values:\n%s", db.sql) + } + if len(db.args) != 3 || db.args[2] != 11 { + t.Fatalf("observed-only args = %#v, want auth/user/pts", db.args) + } +} diff --git a/internal/store/updatestate.go b/internal/store/updatestate.go index 32b820ac..902ba250 100644 --- a/internal/store/updatestate.go +++ b/internal/store/updatestate.go @@ -10,9 +10,14 @@ import ( type UpdateStateStore interface { Get(ctx context.Context, authKeyID [8]byte, userID int64) (domain.UpdateState, bool, error) Save(ctx context.Context, authKeyID [8]byte, userID int64, state domain.UpdateState) error + // CommitDeliveredState atomically advances the cursor proven by one physically + // delivered response. Baseline mode advances confirmed and observed together; + // delivered-only mode must leave observed untouched. + CommitDeliveredState(ctx context.Context, authKeyID [8]byte, userID int64, state domain.UpdateState, mode domain.UpdateStateCommitMode) error // ObserveClientState advances only the state that the client has proved it already owns by - // carrying it in a request (or by explicitly establishing a getState snapshot baseline). - // Durable-log retention must use this watermark, never a response state merely sent by server. + // carrying it in a request. An audited getState baseline advances the same watermark only via + // the atomic CommitDeliveredState baseline mode after physical delivery. Durable-log retention + // must use this watermark, never a response state merely sent by server. ObserveClientState(ctx context.Context, authKeyID [8]byte, userID int64, state domain.UpdateState) error Delete(ctx context.Context, authKeyID [8]byte, userID int64) error DeleteAuthKey(ctx context.Context, authKeyID [8]byte) error